Davin Boling
davin at wordpainter.net
Wed Mar 16 23:18:42 EST 2005
Found it, and damn was it ever an obsure one. Basicly, Apache+mod_python gets confused when you try to do a POST to a URI which corresponds to a real directory on the filesystem. I understand that's a bit hard to follow, so I'll provide the following example: 1) DocumentRoot is /home/foobar/public_html/python 2) In this directory, you have a folder named "htdocs". 3) Inside this directory, you have a number of HTML templates which are combined to form the full document. 4) The handler is written so that when a client requests foobar.com/htdocs, they aren't served a real file on the filesystem, but a dynamic document generated from the templates in the corresponding filesystem directory. 5) THE PROBLEM: User attempts to post action="http://foobar.com/htdocs". 6) Unexplainable GET->POST calamity rears its ugly head. 7) SOLUTION: Add a trailing slash. It's the proper syntax anyway! action="http://foobar.com/htdocs/" 8) BETTER SOLUTION: Don't be a halfass, store your templates somewhere on the filesystem that isn't accessible by the web. Even if the templates don't contain any secure information, it's good to get in the practice. Graham Dumpleton wrote: > Are you going direct to the server, or via a web proxy? Just a thought. > I have never heard of web proxies change POST requests to GET, but > I have had problems with web proxy caches before. This is why I > tend to explicitly use: > > req.headers_out['Pragma'] = 'no-cache' > req.headers_out['Cache-Control'] = 'no-cache' > req.headers_out['Expires'] = '-1' > > When a handler is processing forms, whether it be GET or POST. > > Graham > > Davin Boling wrote .. > >>I had already established that the method type is somehow getting >>switched in the non-working handler. As much as it's hell-bent to force >>me to use a GET for my form, I'd much rather figure out why it's forcing >>a GET when I'm telling it to use a POST. >> >> >>1) I can make a script from scratch that accepts a POST operation just >>fine. That's the one that I provided a moment ago. >>2) req.read() isn't working on the bad handler, even if I put it at the >>top of the bad handler. That was my first hint that something was >>strange, and by logging req.method I was able to find out that Apache >>wants to use GET instead of POST with my non-working handler. It doesn't >>make sense, since I'm using the exact same form that worked with the >>smaller (working) handler. >>3) Before anyone asks, I'm manually killing my browser cache between >>submissions just to be safe. The strange behavior is exhibited in both >>Mozilla and IE. >> >> >>Graham Dumpleton wrote: >> >> >>>The content length will not be set for a GET, thus I had in mine: >>> >>> if req.method == "POST": >>> length = int(req.headers_in["content-length"]) >>> template.req_read.content = req.read(length) >>> >>>I believe that for a POST, content length must be provided by the >>>client, certainly for the content types that FieldStorage is designed >>>to work with. >>> >>>Davin Boling wrote .. >>> >>> >>>>(forgive the double-mail Graham, replied direct and didn't hit the list >>>>by accident) >>>> >>>> >>>>I took your suggestion involving time.sleep, but it made no difference. >>>>As for grabbing the content-length in the method you described...the >>>>plot thickens! >>>> >>>>Using your code at the very beginning of the handler(req):, I get the >>>>following exception: >>>> >>>> >>>>Mod_python error: "PythonHandler handler" >>>> >>>>Traceback (most recent call last): >>>> >>>> File "/usr/lib/python2.3/site-packages/mod_python/apache.py", line >>>>299, in HandlerDispatch >>>> result = object(req) >>>> >>>> File "/home/davin/public_html/demo/handler/__init__.py", line 83, >> >>in >> >>>>handler >>>> length = int(req.headers_in["content-length"]) >>>> >>>>KeyError: 'content-length' >>>> >>>> >>>>Graham Dumpleton wrote: >>>> >>>> >>>> >>>>>Davin Boling wrote .. >>>>> >>>>> >>>>> >>>>>>I've got an example that works correctly already. The problem is that >>>> >>>>in >>>> >>>> >>>>>>the larger handler that I've written, SOMETHING is breaking. I can't >>>>>>understand at all why req.read() returns nothing on a POST when it's >>>> >>>>the >>>> >>>> >>>>>>very first thing I assign to a variable. I'm about to go on a commenting >>>>>>crusade to narrow down where the problem is. >>>>>> >>>>>>This is my "from scratch" handler, which works correctly...just to >> >>show >> >>>>>>that I know how to handle a POST: >>>>>> >>>>>> >>>>> >>>>>>from mod_python import apache >>>>> >>>>> >>>>>>def handler(req): >>>>>> head = """ >>>>>> <?xml version="1.0" encoding="utf-8"?> >>>>>> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" >>>>>> "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> >>>>>> <html> >>>>>> <head> >>>>>> <title>Debug</title> >>>>>> </head> >>>>>> <body> >>>>>> """ >>>>>> data = req.read() >>>>>> method = req.method >>>>>> req.content_type = "text/html" >>>>>> req.write(head + data + method + '</body></html>') >>>>>> return apache.OK >>>>> >>>>> >>>>>Get the content length out of the headers and supply it to req.read() >>>>>and see if that makes a difference. Ie., >>>>> >>>>> length = int(req.headers_in["content-length"]) >>>>> data = req.read(length) >>>>> >>>>>Also note what documentation says about timeouts. >>>>> >>>>> read([len]) >>>>> >>>>> Reads at most len bytes directly from the client, returning a string >>>>> with the data read. If the len argument is negative or omitted, >> >>reads >> >>>>> all data given by the client. >>>>> >>>>> This function is affected by the Timeout Apache configuration directive. >>>>> The read will be aborted and an IOError raised if the Timeout is >>>> >>>>reached >>>> >>>> >>>>> while reading client data. >>>>> >>>>> This function relies on the client providing the Content-length >>>> >>>>header. >>>> >>>> >>>>> Absence of the Content-length header will be treated as if >>>>> Content-length: 0 was supplied. >>>>> >>>>> Incorrect Content-length may cause the function to try to read >> >>more >> >>>>> data than available, which will make the function block until a >>>> >>>>Timeout >>>> >>>> >>>>> is reached. >>>>> >>>>>One would expect an IOError according to this if a timeout occured, >> >>but >> >>>>>maybe it isn't being generated for some reason. >>>>> >>>>>You might also add: >>>>> >>>>> time.sleep(10) >>>>> >>>>>at the start of your handler and see if it makes a difference. Ie., >> >>try >> >>>>and >>>> >>>> >>>>>determine if it is the time the client takes to send the post data. >>>>> >>>>>Graham >>>>>
|