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?
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.)
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With