Standalone http server, cgi software?
Thomas Fuchs
tgfuchs at my-deja.com
Thu Jun 15 02:10:02 EDT 2000
In article <39479D02.42B5AD06 at erols.com>,
"Edward C. Jones" <edcjones at erols.com> wrote:
> I am looking for a system that resides entirely on one PC. The idea is
> to pass arguments to a Python program via a HTML form. The program
> would look things up in a database, process them, etc. and return to
> the browser a page of html containing the answers.
>
This is also my preferred method for a simple GUI.
Here is a minimal sample program:
"""
simple http server
it executes a system command and returns stdout of command
or return code as plain text
arguments: -port portnumber
default port: 8000
accepted urls:
/command?cmd=command # perform command
/command/form/get # send form for get
/command/form/post # send form for post
usage: start the program and in the browser type the address
http://localhost:8000/command/form/get
This server is intended to be a starting point for writing any simple
http server.
Modify the part between -- edit begin -- and -- edit end --
supported methods are GET, HEAD and POST,
where POST content-type must be application/x-www-form-urlencoded
Two functions must be provided:
analyse(pathlist, d, headOnly = None)
pathlist is the path part as list splitted by '/'
d is the query string as dictionary
headOnly is set, if method is HEAD
the function must return value a triple:
typ content-type, if not set, the http return code is 404
size optional
info forwarded to do function
do(info, fout)
info is the result of analyse
fout the output stream
the function must write the content to fout
"""
import os
import sys
import string
import SocketServer
import BaseHTTPServer
import urllib
import socket
class RequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
def do_GET(self):
info = self.send_head()
do(info, self.wfile)
def do_HEAD(self):
self.send_head(headOnly = 1)
def do_POST(self):
ctyp = self.headers.getheader('content-type')
if ctyp != 'application/x-www-form-urlencoded':
print 'POST ERROR: unexpected content-tpye:', ctyp
return
clen = self.headers.getheader('content-length')
if clen:
clen = string.atoi(clen)
else:
print 'POST ERROR: missing content-length'
return
data = self.rfile.read(clen)
dummy = self.rfile.read(2)
self.path = '%s?%s' % (self.path, data)
self.do_GET()
def send_head(self, headOnly = None):
pathlist, d = urlParse(self.path)
typ, size, info = analyse(pathlist, d, headOnly)
if typ:
self.send_response(200) # http return code: ok
self.send_header('Content-type', typ)
if size:
self.send_header('Content-length', size)
else:
self.send_response(404) # http return code: not found
self.end_headers()
return info
# url handling
def urlParse(url):
""" return path as list and query string dictionary
strip / from path
ignore empty values in query string
for example:
if url is: /xyz?a1=&a2=0%3A1
then result is: (['xyz'], { 'a2' : '0:1' } )
if url is: /a/b/c/
then result is: (['a', 'b', 'c'], None )
if url is: /?
then result is: ([], {} )
"""
x = string.split(url, '?')
pathlist = filter(None, string.split(x[0], '/'))
d = {}
if len(x) > 1:
q = x[-1] # eval query string
x = string.split(q, '&')
for kv in x:
y = string.split(kv, '=')
k = y[0]
try:
v = urllib.unquote_plus(y[1])
if v: # ignore empty values
d[k] = v
except:
pass
return (pathlist, d)
# -------------- edit begin ----------------------------
defaultPort = 8000 # set default port for server
def analyse(pathlist, d, headOnly = None):
size = None
info = ''
typ = None
#print pathlist, d # test only
if pathlist == ['command'] and d.keys() == ['cmd']:
typ = 'text/plain'
if not headOnly:
info = syscmd(d['cmd'])
size = len(info)
elif pathlist[:2] == ['command', 'form'] and d == {} and \
pathlist[2:] in [['get'], ['post']]:
typ = 'text/html'
if not headOnly:
info = buildform(pathlist[2])
size = len(info)
return (typ, size, info)
def do(info, fout):
fout.write(info)
# task specific helper functions
def syscmd(cmd):
f = os.popen(cmd, 'rb')
rsp = f.read()
rc = f.close()
return rsp or 'RC: %s' % rc
def buildform(method):
# get hostname of server
try:
host = socket.gethostname()
except:
host = "???"
doc = '''\
<TITLE>command %(host)s</TITLE>
<H1>command %(host)s</H1>
<P>
<FORM ACTION="/command" METHOD="%(method)s">
command: <INPUT TYPE=TEXT NAME="cmd" SIZE=80>
<BR>
<INPUT TYPE=SUBMIT>
</FORM>
''' % locals()
return doc
# -------------- edit end ----------------------------
if __name__ == '__main__':
# argument handling
try:
i = sys.argv.index('-port')
port = string.atoi(sys.argv[i+1])
del sys.argv[i:i+1]
except:
port = defaultPort
# start server
print 'Serving on port', port
server = SocketServer.TCPServer(('', port), RequestHandler)
server.serve_forever()
Sent via Deja.com http://www.deja.com/
Before you buy.
More information about the Python-list
mailing list