Keith Walton
Keith Walton

Reputation: 5364

HTTP request from javascript using raw message including headers

I know how to make an HTTP request to my REST api from javascript using jQuery or XMLHttpRequest. What I want to do now is make the request without setting properties for the header values. An HTTP request message consists of:

  • Request line, such as GET /images/logo.png HTTP/1.1, which requests a resource called /images/logo.png from server
  • Headers, such as Accept-Language: en
  • An empty line
  • An optional message body

A request to my api should look something like this:

GET /myapi/myresource/1234 HTTP/1.1
Host: localhost:51127
Content-Type: application/x-www-form-urlencoded
Accept: application/json, text/csv
Authorization: Basic <base64 encoded credentials>

I would like to open a connection to localhost:51127, send the above text, and get the response. Is this possible in javascript?

Update: I know how to set headers. I just want to do it a different way. There are lots of ways to "build" a request including headers and send it. I just want to build it manually.

Upvotes: 2

Views: 4357

Answers (4)

To build on lonesomeday's answer, here's how to actually do it.

function rawRequest(txt,cb) {
  let x = new XMLHttpRequest(),
      lines = txt.split("\n"),
      methods = [
        "GET",
        "POST",
        "PATCH",
        "PUT",
        "DELETE",
        "HEAD",
        "OPTIONS"
      ],
      host, path, method, version, body = "", headers = {}
  lines.forEach((x, i) => {
    if(!x.includes(":")) {
      let ind;
      methods.forEach(m => {
        let tmpIndex = x.indexOf(m);
        
        if(tmpIndex > -1) {
          if(!method) {
            ind = tmpIndex;
            let words = x.split(" ");
            method = x.substring(
              tmpIndex,
              tmpIndex + 
              m.length
            );
            method = method && method.trim();
            path = words.find((y, k) => 
              y[0] === "/"
            )
            path = path && path.trim();
            version = (
              x
              .replace(method, "")
              .replace(path, "")
            ).trim();
          }
          
        }
      });
    } else {
      let indexOfSemiColon = x.indexOf(":");
      if(
        indexOfSemiColon > 0 &&
        indexOfSemiColon < x.length - 1
      ) {
      
        let key = x.substring(
          0,
          indexOfSemiColon
        ).trim(),
            value = x.substring(
              indexOfSemiColon + 1
            ).trim();
         headers[key] = value;
         if(key.toLowerCase() == "host") {
          host = value
         }
   	 }
    }
  });
  let inds = []
  txt.split(/\r?\n/).forEach((x,i)=>
    x === "" 
    && inds.push(i)
  )
  let afterTwoLineBreaksIndex;
  inds.forEach((x,i) => {
    if(
      i < inds.length - 2 &&
      inds[i] === "" &&
      inds[i + 1] === ""
    ) {
      afterTwoLineBreaksIndex = i + 1;
    }
  });
  if(afterTwoLineBreaksIndex) {
    body = txt.substring(
      afterTwoLineBreaksIndex
    )
  }
  x.onreadystatechange = () => {
    if(x.readyState == 4 && x.status == 200) {
      if(cb) cb(x.response);
    } 
  }
  if(host && path && method) {
    x.open(
      method, 
      "http://" //don't know how to differentiate between http & https, if some1 could help out would be greate
      + host 
      + path
    );
    
    for(let k in headers) {
      x.setRequestHeader(k, headers[k]);
    }
    
    x.send(body);
  }
  return {
    headers,
    body,
    method,
    host,
    path,
    version
  } //for testing just return all the values we found
}

console.log(
  rawRequest(`
    GET /search?q=test HTTP/2
    Host: www.bing.com
    User-Agent: curl/7.54.0
    Accept: */*`
  ),
  rawRequest(`
    GET /foo/bar HTTP/1.1
    Host: example.org
    User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; fr; rv:1.9.2.8) Gecko/20100722 Firefox/3.6.8
    Accept: */*
    Accept-Language: fr,fr-fr;q=0.8,en-us;q=0.5,en;q=0.3
    Accept-Encoding: gzip,deflate
    Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
    Keep-Alive: 115
    Connection: keep-alive
    Content-Type: application/x-www-form-urlencoded
    X-Requested-With: XMLHttpRequest
    Referer: http://example.org/test
    Cookie: foo=bar; lorem=ipsum;
  `),
   rawRequest(`
      GET /myapi/myresource/1234 HTTP/1.1
      Host: localhost:51127
      Content-Type: application/x-www-form-urlencoded
      Accept: application/json, text/csv
      Authorization: Basic <base64 encoded credentials>
   `)
  
 )

Upvotes: 1

Shumii
Shumii

Reputation: 4581

Came here looking for same thing. I think it would be possible to build something which takes a raw request text and parses that to an xmlHttpRequest object putting the headers etc in the correct properties. Pls comment a link if something like this already exists. Basically if jQuery has a function to BuildRequestFromRaw(text) that would be awesome.

Upvotes: 0

lonesomeday
lonesomeday

Reputation: 237865

There is no socket support in Javascript. You can only build HTTP queries by using the XMLHTTPRequest wrapper, or optionally wrappers for that such as jQuery.ajax. This is for all kinds of good reasons, principally security.

Upvotes: 2

Derrick
Derrick

Reputation: 2021

You can possibly get an instance of the HmlHttpRequest object and use the setRequestHeader.

jQuery has a beforeSend handler you can set to get the actual hxr object.

  $.ajax({
      beforeSend: function(xhr){
          xhr.setRequestHeader("name","value");
       }
  ...
  })

Upvotes: 2

Related Questions