Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cannot get POST values with cgi.FieldStorage

Tags:

python

http

I`m trying to send simple html page with form data to user with GET, and then receive variables from form with POST. HTML file looks like:

<HTML>
<title> My Title</title>
<body>
<form  method="post" action="http.py">
<input name="Name" type="text"/>
<input name="Submit" type="submit" value="Submit" />
</form>
</body>
</HTML>

Here is python script:

import os
import cgi
import sys
from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler



class customHTTPServer(BaseHTTPRequestHandler):
        def do_GET(self):
                self.send_response(200)
                self.send_header('Content-type', 'text/html')
                self.end_headers()
                fh=open('index.html','r')
                self.wfile.write(fh.read())
                return

        def do_POST(self):
            form = cgi.FieldStorage()
            self.send_response(200)
            self.end_headers()
            self.wfile.write(form['Name'].value)


def main():
       try:
            server = HTTPServer(('',9111),customHTTPServer)
            print 'server started at port 8080'
            server.serve_forever()
       except KeyboardInterrupt:
            server.socket.close()

if __name__=='__main__':
       sys.exit(main())

But FieldStorage remains empty all the time. I already tried to check what is in self.rfile, and found that if i try to do self.rfile.readlines() , browser stuck and looks like script is waiting for the end of data stream. From where i should take Name variable that i`m submitting with POST?

like image 902
Danylo Gurianov Avatar asked Jul 04 '12 17:07

Danylo Gurianov


2 Answers

In the original code, I just changed the line

form = cgi.FieldStorage()

to

form = cgi.FieldStorage(
    fp=self.rfile,
    headers=self.headers,
    environ={'REQUEST_METHOD':'POST'})

and it seems to work as you intended.

Hat-tip to http://pymotw.com/2/BaseHTTPServer/ for the critical 'environ' setting. (By default, cgi.FieldStorage thinks it's dealing with a GET request.)

like image 115
Michael Dyck Avatar answered Nov 09 '22 23:11

Michael Dyck


I think you might be mixing some concepts here. You have both the idea of a server and also a cgi script. No matter what your POST action is (http.py or whatever), your server is just going to take in a request. No CGI processing is actually happening. So you can first adjust your html template to this for simplicity:

<form  method="post" action="">

Then, you should reference this other question about how to read from the request, as opposed to trying to use the cgi fieldstorage:

import urlparse

...

    def do_POST(self):
        length = int(self.headers.getheader('content-length'))
        postvars = urlparse.parse_qs(self.rfile.read(length), keep_blank_values=1)
        self.send_response(200)
        self.end_headers()
        self.wfile.write(postvars)

The issue you were having, and because this is a very low level way to create a web server app, if you read indefinitely from the input stream, it will keep going and block. You check the header for the content length and only read that many bytes. You don't have any need for the cgi module at all, because this is not a cgi script.

A cgi script works by the server seeing the request is for a file of a matching type and location, and executing it in a subprocess like a normal program. It feeds the process the args and then gets back a response to ship back to the client. If this were a cgi script, the server would be in one module, running forever, and the cgi code would be in another with much simpler code to check the request.

like image 43
jdi Avatar answered Nov 09 '22 22:11

jdi