I have been experimenting with mod_python to evaluate it for some
upcoming projects, and I recently came across what appeared to be a bug
in mod_python. (After three days of scratching my head over this, the
solution came to me as I was writing this message, but I'm sending it
anyway in case someone else comes across this problem. -- Should this
sort of thing go into the FAQ?)
The problem was essentially that whenever I performed a GET request on
a URL immediately following a POST request to that same URL, Apache
would seem to confuse the two requests, and after the GET, I would
receive an error message like this:
HTTP/1.1 501 Method Not Implemented
key=valueGET to /pytest not supported
Invalid method in request key=valueGET /pytest
Running tcpdump on the communication between the browser and server
showed that the requests were all well-formed, and there was nothing
unusual in the headers to suggest that anything but Apache/mod_python
was at fault.
The simplest script I could produce to replicate the problem was this:
# -------------------------------------------------------------------
import sys
from mod_python import apache
def handler(req):
if req.method == 'GET':
req.content_type = "text/html"
req.send_http_header()
req.write("""<html>
<head>
<title>python test</title>
</head>
<body>
<form method=\"post\" action=\"/pytest\">
<input name=\"key\" value=\"value\"> <input type=\"submit\">
</form>
</body>
</html>
""")
return apache.OK
elif req.method == 'POST':
req.content_type = "text/html"
req.send_http_header()
req.write("""<html>
<head>
<title>python test part 2</title>
</head>
<body>
<p>POST successful. <a href=\"/pytest\">Click here</a></p>
</body>
</html>
""")
return apache.OK
else:
return apache.DECLINED
# -------------------------------------------------------------------
It was supported by these Apache configuration directives:
<Location "/pytest">
SetHandler python-program
PythonPath "sys.path+['/home/ian/src/pytest']"
PythonHandler python_test
</Location>
The script is accessable from the virtual URL /pytest, which runs the
python_test.py module from a non-web-accessable directory. Going to the
URL /pytest in Mozilla, hitting the submit button, then clicking on the
'Click here' link brings up the error message.
The problem with this code (as it became apparent to me while writing
this message) is that the POST handler never actually reads the POST
data, and so it stays on stdin, and Apache treats it as the beginning
of the next request. Simply inserting the line 'postdata = req.read()'
gets rid of the error.
Questions:
Is this the correct behaviour for mod_python? Is it the python module
writer's responsibility to read all POST data in all situations? What
if the data is very large (say, a 5MB file when I expected a small text
field) and I just want to discard it?
Ian
<ian at veryfresh.com>