Mikey 0
Mikey 0

Reputation: 51

Python BadStatusLine error on certain DELETE requests

I am trying to use the python-rest-client ( http://code.google.com/p/python-rest-client/wiki/Using_Connection ) to perform testing of some RESTful webservices. Since I'm just learning, I've been pointing my tests at the sample services provided at http://www.predic8.com/rest-demo.htm.

I have no problems with creating entries, updating entries, or retrieving entries (POST and GET requests). When I try make a DELETE request, it fails. I can use the Firefox REST Client to perform DELETE requests and they work. I can also make DELETE requests on other services, but I've been driving myself crazy trying to figure out why it doesn't work in this case. I'm using Python 3 with updated Httplib2, but I also tried Python 2.5 so that I could use the python-rest-client with the included version of Httplib2. I see the same problem in either case.

The code is simple, matching the documented use:

from restful_lib import Connection        
self.base_url = "http://www.thomas-bayer.com"
self.conn = Connection(self.base_url)
response = self.conn.request_delete('/sqlrest/CUSTOMER/85')

I've looked at the resulting HTTP requests from the browser tool and from my code and I can't see why one works and the other doesn't. This is the trace I receive:

Traceback (most recent call last):
 File "/home/fmk/python/rest-client/src/TestExampleService.py", line 68, in test_CRUD
  self.Delete()
 File "/home/fmk/python/rest-client/src/TestExampleService.py", line 55, in Delete
  response = self.conn.request_delete('/sqlrest/CUSTOMER/85')
 File "/home/fmk/python/rest-client/src/restful_lib.py", line 64, in request_delete
  return self.request(resource, "delete", args, headers=headers)
 File "/home/fmk/python/rest-client/src/restful_lib.py", line 138, in request
  resp, content = self.h.request("%s://%s%s" % (self.scheme, self.host,     '/'.join(request_path)), method.upper(), body=body, headers=headers )
 File "/home/fmk/python/rest-client/src/httplib2/__init__.py", line 1175, in request
 (response, content) = self._request(conn, authority, uri, request_uri, method, body, headers, redirections, cachekey)
 File "/home/fmk/python/rest-client/src/httplib2/__init__.py", line 931, in _request
 (response, content) = self._conn_request(conn, request_uri, method, body, headers)
 File "/home/fmk/python/rest-client/src/httplib2/__init__.py", line 897, in _conn_request
  response = conn.getresponse()
 File "/usr/lib/python3.2/http/client.py", line 1046, in getresponse
  response.begin()
 File "/usr/lib/python3.2/http/client.py", line 346, in begin
  version, status, reason = self._read_status()
 File "/usr/lib/python3.2/http/client.py", line 316, in _read_status
  raise BadStatusLine(line)
 http.client.BadStatusLine: ''

What's breaking? What do I do about it? Actually, I'd settle for advice on debugging it. I've changed the domain in my script and pointed it at my own machine so I could view the request. I've viewed/modified the Firefox requests in BurpProxy to make them match my script requests. The modified Burp requests still work and the Python requests still don't.

Upvotes: 1

Views: 1367

Answers (2)

jfs
jfs

Reputation: 414715

The following script correctly produces 404 response from the server:

#!/usr/bin/env python3
import http.client 

h = http.client.HTTPConnection('www.thomas-bayer.com', timeout=10)
h.request('DELETE', '/sqlrest/CUSTOMER/85', headers={'Content-Length': 0})
response = h.getresponse()
print(response.status, response.version)
print(response.info())
print(response.read()[:77])

python -V => 3.2


curl -X DELETE http://www.thomas-bayer.com/sqlrest/CUSTOMER/85
curl: (52) Empty reply from server

Status-Line is not optional; HTTP server must return it. Or at least send 411 Length Required response.

curl -H 'Content-length: 0' -X DELETE \
  http://www.thomas-bayer.com/sqlrest/CUSTOMER/85

Returns correctly 404.

Upvotes: 1

Mikey 0
Mikey 0

Reputation: 51

Apparently the issue is that the server expects there to be some message body for DELETE requests. That's an unusual expectation for a DELETE, but by specifying Content-Length:0 in the headers, I'm able to successfully perform DELETEs.

Somewhere along the way (in python-rest-client or httplib2), the Content-Length header is wiped out if I try to do:

from restful_lib import Connection        
self.base_url = "http://www.thomas-bayer.com"
self.conn = Connection(self.base_url)
response = self.conn.request_delete('/sqlrest/CUSTOMER/85', headers={'Content-Length':'0'})

Just to prove the concept, I went to the point in the stack trace where the request was happening:

File "/home/fmk/python/rest-client/src/httplib2/__init__.py", line 897, in _conn_request
response = conn.getresponse()

I printed the headers parameter there to confirm that the content length wasn't there, then I added:

if(method == 'DELETE'):
     headers['Content-Length'] = '0'

before the request.

I think the real answer is that the service is wonky, but at least I got to know httplib2 a little better. I've seen some other confused people looking for help with REST and Python, so hopefully I'm not the only one who got something out of this.

Upvotes: 4

Related Questions