classification
Title: Empty body {} in POST requests leads to 405 Method not allowed error
Type: behavior Stage:
Components: Library (Lib), Windows Versions: Python 3.9
process
Status: open Resolution:
Dependencies: Superseder:
Assigned To: Nosy List: bhushan.shelke, paul.moore, ronaldoussoren, steve.dower, tim.golden, zach.ware
Priority: normal Keywords:

Created on 2020-11-20 09:20 by bhushan.shelke, last changed 2020-11-20 10:06 by bhushan.shelke.

Files
File name Uploaded Description Edit
sample_flask.py bhushan.shelke, 2020-11-20 09:20
Messages (5)
msg381470 - (view) Author: Bhushan Shelke (bhushan.shelke) Date: 2020-11-20 09:20
I have a Tomcat+Java based server exposing REST APIs. I am writing a client in python to consume those APIs. Everything is fine until I send empty body in POST request. It is a valid use case for us. If I send empty body I get 400 bad request error - Invalid character found in method name [{}POST]. HTTP method names must be tokens. If I send empty request from POSTMAN or Java or CURL it works fine, problem is only when I used python as a client. 

If I use python based server (attached a simple server program for same) then I get 405 Method not allowed instead of 400 that I get using java based server.

Server code is Following is python snippet -

json_object={}
header = {'alias': 'A', 'Content-Type' : 'application/json', 'Content-Length' : '0'} 
resp = requests.post(url, auth=(username, password), headers=header, json=json_object) 
I tried using data as well instead of json param to send payload with not much of success.

I captured the wireshark dumps to undertand it further and found that, the request tomcat received is not as per RFC2616 (https://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html). Especially the part - Request-Line = Method SP Request-URI SP HTTP-Version CRLF Because I could see in from wireshark dumps it looked like - {}POST MY-APP-URI HTTP/1.1

As we can see the empty body is getting prefixed with http-method, hence tomcat reports that as an error. I then looked at python http library code -client.py. Following are relevant details -

File - client.py

Method - _send_output (starting at line # 1001) - It first sends the header at line #1010 and then the body somewhere down in the code. I thought(I could be wrong here) perhaps in this case header is way longer 310 bytes than body 2 bytes, so by the time complete header is sent on wire body is pushed and hence TCP frames are order in such a way that body appears first. To corroborate this I added a delay of 1 second just after sending header line#1011 and bingo, the error disappeared and it started working fine. Not sure if this is completely correct analysis, but can someone in the know can confirm or let me know how to fix this.
msg381471 - (view) Author: Ronald Oussoren (ronaldoussoren) * (Python committer) Date: 2020-11-20 09:27
Are you using the requests library (https://requests.readthedocs.io/en/master/)?
msg381472 - (view) Author: Bhushan Shelke (bhushan.shelke) Date: 2020-11-20 09:33
Yes Ronald I am using requests library however I tried HTTPSConnection class from http.client package as well getting same error, may be because cause is in the core http library itself
msg381473 - (view) Author: Ronald Oussoren (ronaldoussoren) * (Python committer) Date: 2020-11-20 09:43
Please check with the requests project as well, I'm not sure how much of the stdlib HTTP client is used by requests.

This issue can stay open because the issue is reproducible using the stdlib.
msg381474 - (view) Author: Bhushan Shelke (bhushan.shelke) Date: 2020-11-20 10:06
I have looked at requests lib code. As far as I could understand following is the flow of packages used in this case -

request "uses->" urllib3 "uses->" http
History
Date User Action Args
2020-11-20 10:06:17bhushan.shelkesetmessages: + msg381474
2020-11-20 09:43:19ronaldoussorensetmessages: + msg381473
2020-11-20 09:33:15bhushan.shelkesetmessages: + msg381472
2020-11-20 09:27:20ronaldoussorensetnosy: + ronaldoussoren
messages: + msg381471
2020-11-20 09:26:35bhushan.shelkesetcomponents: + Library (Lib)
2020-11-20 09:20:23bhushan.shelkecreate