Arjan Groen Arjan Groen - 2 months ago 31
HTTP Question

HTTP/1.1 400 Bad Request. Bad number of command parts

Im trying to execute the following code from Chapter 12 of the book "Python for Informatics".

import socket
mysock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
mysock.connect(('www.py4inf.com', 80))
mysock.send('GET http://www.py4inf.com/code/romeo.txt HTTP/1.0\n\n')
while True:
data = mysock.recv(512)
if ( len(data) < 1 ) :
break
print data
mysock.close()


According to the book, the script should print the following:


HTTP/1.1 200 OK
Date: Sun, 14 Mar 2010 23:52:41 GMT
Server: Apache
Last-Modified: Tue, 29 Dec 2009 01:31:22 GMT
ETag: "143c1b33-a7-4b395bea"
Accept-Ranges: bytes
Content-Length: 167
Connection: close
Content-Type: text/plain
But soft what light through yonder window breaks
It is the east and Juliet is the sun
Arise fair sun and kill the envious moon
Who is already sick and pale with grief


Unfortunately the variable data is filled with the following string:


'HTTP/1.1 400 Bad Request. Bad number of command parts ['GET', 'http://www.py4inf.com/code/romeo.txt', 'HTTP/1.0', 'X-WS-Ver:', '1.0']'


I cannot find any good explanation for this error. I hope someone can help!

Answer

On your Python installation, machine, or your network, something is rewriting requests and injecting its own code. Prime suspects are

  • Anything marked as "Anti-Virus"
  • Anything marked as "Network Security Solution"
  • Malware on your computer or router
  • A network-wide (transparent) proxy
  • A library in your Python program or installation
  • Your ISP or network administrator

This service wants, in your case, to inject a totally useless header X-WS-Ver. However, this service's interpretation of HTTP is more strict than yours and the py4inf.com server; HTTP lines are supposed to end with \r\n, but you use \n only. This service modifies the data you sent to

GET http://www.py4inf.com/code/romeo.txt HTTP/1.0\n\nX-WS-Ver: 1.0\r\n\r\n

or something similar. This is of course a very buggy behavior by this service. Since the new request is not valid HTTP anymore, py4inf.com will return an error message, correctly indicating that the request it received is malformed (400 Bad request).

To make your program work, you can take any of these options:

  • If it's on your local machine, disable the offending service (if it uselessly and incorrectly modifies connections, it's not likely to provide much, if any, security anyways), or use another machine
  • Get unrestricted network access, maybe with the help of a VPN provider
  • Send proper HTTP, i.e.
mysock.send('GET http://www.py4inf.com/code/romeo.txt HTTP/1.0\r\n\r\n')
#                                                             ^^  ^^
  • Use an encrypted connection (with Python's ssl module), i.e. URLs under the https:// scheme.
Comments