PUT should always send Content-Length header

I'm attempting to PUT with a zero-length content body. My target HTTP server is (rightly) rejecting the request because requests is not sending a Content-Length header, and the server is interpreting the request as having no body.

By my reading of the RFC, requests should always send a Content-Length header with PUT methods, even if it is 0, as in this case.

http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html

Even if requests does not always send a Content-Length header with PUT, it should send one if the content being sent is a zero-length string. I suspect instead of checking for None, or whatever the default body value is, it's checking for "truthy".


https://github.com/kennethreitz/requests/blob/master/requests/models.py#L309

``` python
import requests

r = requests.put('http://httpbin.org/put', data='')
r.json['headers']['Content-Length']
```

That prints `u'0'` for me. What version of requests are you using?


Easier yet:

``` pycon
>>>import requests
>>>req = requests.Request('PUT', 'http://httpbin.org/put', data='').prepare()
>>>req.headers['Content-Length']
'0'
```


Hmm... maybe my issue is that I'm manually specifying one header, and was expecting the Content-Length header to be automatically set.


Shouldn't interfere. What version of requests are you using?


14.2


@kennethreitz I love this refactor more and more.

@PaulMcMillan can you post the call you're making or an example of it? This fix was introduced ~0.14.1

And by example, I mean: fake header and fake URI


My call looks like this:

```
requests.request(method='PUT', url='https://myserver/myendpoint', headers={'Content-Type': 'application/json'}, data='', verify=False)
```

and the relevant nginx debug log looks like this:

```
2012/12/19 22:04:39 [debug] 21390#0: *38 http request line: "PUT /myendpoint HTTP/1.1"
2012/12/19 22:04:39 [debug] 21390#0: *38 http uri: "/myendpoint"
2012/12/19 22:04:39 [debug] 21390#0: *38 http args: ""
2012/12/19 22:04:39 [debug] 21390#0: *38 http exten: ""
2012/12/19 22:04:39 [debug] 21390#0: *38 http process request header line
2012/12/19 22:04:39 [debug] 21390#0: *38 http header: "Host: myserver"
2012/12/19 22:04:39 [debug] 21390#0: *38 http header: "Content-Type: application/json"
2012/12/19 22:04:39 [debug] 21390#0: *38 http header: "Accept-Encoding: gzip, deflate, compress"
2012/12/19 22:04:39 [debug] 21390#0: *38 http header: "Accept: */*"
2012/12/19 22:04:39 [debug] 21390#0: *38 http header: "User-Agent: python-requests/0.14.2 CPython/2.7.3 Linux/3.2.0-31-generic"
2012/12/19 22:04:39 [debug] 21390#0: *38 http header done
2012/12/19 22:04:39 [info] 21390#0: *38 client sent PUT method without "Content-Length" header while reading client request headers, client: myserver, server: _, request: "PUT /myendpoint HTTP/1.1", host: "myserver"
2012/12/19 22:04:39 [debug] 21390#0: *38 http finalize request: 411, "/myendpoint?" a:1, c:1
2012/12/19 22:04:39 [debug] 21390#0: *38 event timer del: 18: 1355954739281
2012/12/19 22:04:39 [debug] 21390#0: *38 http special response: 411, "/myendpoint?"
2012/12/19 22:04:39 [debug] 21390#0: *38 http set discard body
2012/12/19 22:04:39 [debug] 21390#0: *38 xslt filter header
2012/12/19 22:04:39 [debug] 21390#0: *38 HTTP/1.1 411 Length Required
Server: nginx/1.2.3
Date: Wed, 19 Dec 2012 22:04:39 GMT
Content-Type: text/html
Content-Length: 180
Connection: close
```

Is something automatically generating that header when you look for it?


Definitely not.


I officially cannot reproduce this behaviour on v1.0.4:

``` python
>>> import requests
>>> requests.__version__
'1.0.4'
>>> r = requests.request(method='PUT', url='http://httpbin.org/put', data='', headers={'Content-Type': 'application/json'})
>>> r.json()['headers']['Content-Length']
u'0'
```

Want to try updating to v1.0.4?


I agree looking at the (much cleaner and nicer) 1.0.4 code, that this is unlikely to be an issue in that codebase. I'm just concerned about breaking existing usage throughout the rest of my application since so much changed (and last I looked) the docs weren't updated. It's not heartening to see so many revs so quickly, especially without an alpha period. 14.2 worked other than this issue, I'm not sure about upgrading to code that is clearly not in any kind of final state. 

Is there any kind of promise about support for 1.0.X api compatibility beyond "upgrade to the latest and greatest and fix your code because the API changed"? Are the docs updated? I can see about updating my application, but it would sure be nice to know that the code I was updating to was well tested, reliable, and not going to break everything again... It sucks be debugging framework problems.


The docs have been updated. There are no plans to change the API in any way until 2.0.


I'm closing this as resolved by v1.0.4. =) @PaulMcMillan, I understand your worries about the maturity of v1, but there's not much I can do about it other than to say that any bugs that are in v0.14 will never be fixed. Bugs in v1 will be. =) Thanks for raising this issue!


I'm working on the conditional addition of the header for the other related issue