Calculating Content-Length with Python

Question:

I’m trying to make a post, however each time I did it, I would get a 411 response error. I’m using the requests library in python.

In [1]: r.post(url)
Out[1]: <Response [411]>

So then I specified the content length h = {'content-length' : '0'} and try again.

In [2]: r.post(url,h)
Out[2]: <Response [200]>

So great, I get a success, however none of the information is posted in.

I think I need to calculate the content-length, which makes sense as it could be “cutting-off” the post.

So my question is, given a url www.example.com/import.php?key=value&key=value how can I calculate the content-length? (in python if possible)

Asked By: tshauck

||

Answers:

It looks strange that you use post method without the data argument (but put data in url).

Look at the example from the official requests documentation :

>>> payload = {'key1': 'value1', 'key2': 'value2'}
>>> r = requests.post("http://httpbin.org/post", data=payload)
>>> print r.text
{
  "origin": "179.13.100.4",
  "files": {},
  "form": {
    "key2": "value2",
    "key1": "value1"
  },
  "url": "http://httpbin.org/post",
  "args": {},
  "headers": {
    "Content-Length": "23",
    "Accept-Encoding": "identity, deflate, compress, gzip",
    "Accept": "*/*",
    "User-Agent": "python-requests/0.8.0",
    "Host": "127.0.0.1:7077",
    "Content-Type": "application/x-www-form-urlencoded"
  },
  "data": ""
}
Answered By: Leonid Shvechikov

Sending POST request with empty body is perfectly legal as long as the Content-Length header is being sent and set to 0. Requests normally calculate the value for Content-Length header. The behavior you observe is probably due to issue 223 – Content-Length is missing.
Although the bug is not closed it looks like the issue was fixed:

C:>python
Python 2.7.3 (default, Apr 10 2012, 23:24:47) [MSC v.1500 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import requests
>>> requests.__version__
'0.11.1'
>>> r = requests.post('http://httpbin.org/post?key1=valueA&key2=valueB')
>>> print r.content
{
  "origin": "77.255.249.138",
  "files": {},
  "form": {},
  "url": "http://httpbin.org/post?key1=valueA&key2=valueB",
  "args": {
    "key2": "valueB",
    "key1": "valueA"
  },
  "headers": {
    "Content-Length": "0",
    "Accept-Encoding": "identity, deflate, compress, gzip",
    "Connection": "keep-alive",
    "Accept": "*/*",
    "User-Agent": "python-requests/0.11.1",
    "Host": "httpbin.org",
    "Content-Type": ""
  },
  "json": null,
  "data": ""
}
Answered By: Piotr Dobrogost

If you hit the same API from postman it will work.
The reason is because postman automatically includes content-length in the header while calling an API. If you try unchecking content-length in postman then it doesn’t work.

This issue is something that happens intermittently.
You will still get 200 RESPONSE if you hit without content-length(at times) and 400 or someother whichever it throws when body is not present.

So the hack here is, The API host which you’re trying to hit will sometimes try to figure the content length on it’s own and sometimes when heavy traffic it is actually configured to not utilise it’s power/time to calculate the content-length hence it believes there is no body when content-length is not given. So if you give content-length : 0 then it will actually calculate the content-length every time because during the transportation of data it can compress and uncompress.

Also

while(times--):
    requests.post(url,headers)

The above didn’t work
but the below has worked.

while(times--):
    requests.post(url,headers)
    time.sleep(2.5)
Answered By: Kamarthapu Nikhil