1

I am writing spec for testing RESTful api. The module I use to make http request is standard http module in nodejs.

If I don't specify the 'Content-Length' in header, then the request is made successfully, but I specify the length by

options.headers['Content-Length'] = post_data.length;

, then it is a bad request with 400 error code. I searched stackoverflow for Content-Length related question, but got no inspiration so far. I tried length +1, and just 100, all ending with same bad request.

Below is my code. Can you tell me what is the problem?

var options = {
  hostname: hostname,
  port: port,
  headers: {
        'Content-Type': 'application/json',
        'Cache-Control': 'no-cache'
        // 'Content-Length': post_data.length
    }
};

describe('API Testing Function', function () {

    db.bind('user');

    describe('POST /api/user', function () {
        it('should return 400 when password is not present', function (done) {

            options.method = 'POST';
            options.path = '/api/user';
            var post_data = JSON.stringify({email:'111@email.com'});
            options.headers['Content-Length'] = post_data.length; // error here
            // if I delete above line, then it is totally good request. 

            var req = http.request(options, function(res){

                res.on('data', function(chunk){
                    // console.log('BODY:' + chunk);
                    var result = JSON.parse(chunk);
                    assert.equal(400, result.code);
                    done();
                });
            });
            req.write(post_data, 'utf8');
            req.end();
        });
    });
});
Nicolas S.Xu
  • 13,794
  • 31
  • 84
  • 129
  • Doesn't this depend a lot on the API you're calling? How is it validating the content length? – Joe Jul 06 '14 at 14:54
  • I don't think content-length depends on the API that I am calling, since I am making a POST request and the length is in the header of request, not in that of response from API. What else do you think could be the problem? – Nicolas S.Xu Jul 07 '14 at 02:41

1 Answers1

0

Came across your post while studying the same problem and thought I might as well post an answer from my findings even though it's roughly 2.5yrs since you posted this. Might as well contribute for future reference. :)

Here are some points:

Firstly, it is advisable to use Buffer.byteLength(post_data) rather than the variable's string length to account for different encoding types.

I've simplified your code on my local machine and tried shooting it against a local job site I was planning on mining. Removing the Content-Length gave me a 411 (Length Required). However, leaving most of your code intact I managed to pull some results with the Content-Length as is. My issue is more of the opposite, I tried to use a GET method along with the Content-Length. This didn't work on the target server. My guesses are it's a server thing or an RFC thing. This is okay since most implementations I've seen only use it when doing POST not as GET.

Finally, I recommend reading the RFC for Content-Length as well as the GET method for a basic understanding. There are some nuances to its specifications but some are worth remembering.

Notable items say this when I understood what my problem was:

For the GET method:

A payload within a GET request message has no defined semantics; sending a payload body on a GET request might cause some existing implementations to reject the request.

And under the Content-Length documentation I came across this:

..a Content-Length header field is normally sent in a POST request even when the value is 0 (indicating an empty payload body). A user agent SHOULD NOT send a Content-Length header field when the request message does not contain a payload body and the method semantics do not anticipate such a body. ... A sender MUST NOT send a Content-Length header field in any message that contains a Transfer-Encoding header field.

Also, this site helped me get some information from my browser and what it would probably look like from the server's point of view. You can also use it to debug the target server if it's visible on the internet.

A simple check if the server accepts Content-Length in a GET method is to set its value to zero. The same is also true when testing the POST.

Worth noting is that HTTP/1.1 uses Transfer-Encoding to take the guesswork out of Content-Length and they also SHOULD NOT be used at the same time. Node.js HTTP docs mentions this at the bottom:

Sending a 'Content-Length' header will disable the default chunked encoding.

I recommend you leave it as is without using Content-Length. It's supposed to be there so you won't have to worry about it.

Community
  • 1
  • 1
Chad
  • 738
  • 2
  • 8
  • 21
  • Another notable reference is this: http://stackoverflow.com/questions/8540931/what-is-the-correct-content-length-to-set-for-a-get-request – Chad Feb 22 '17 at 15:39