non-file-based web server?

tgfuchs at my-deja.com tgfuchs at my-deja.com
Fri Oct 15 06:06:17 EDT 1999


In article <87hfjuwngo.fsf at ethereal.dhis.org>,
  Nolan Darilek <nolan at ethereal.dhis.org> wrote:
> Wow, nice technical terminology in the subject line, no? :)
>
> Out of curiousity, is there an HTTP server written in Python which
> doesn't depend on files? Instead, what I'd like to do is to use
> HTMLgen to generate dynamic content within the program, and serve
> that via the web server.
>
> My goal, in a nutshell, is to implement a simple package installer
> which uses a web interface. Basically, the installer launches a web
> server and either gives the user the URL to connect to, or launches a
> specific web browser to view the page and start the
> installation. Though I'm sure I could provide HTML with the package,
> it'd be great if the pages could all originate within the install
> script.
>
It is easy to write your own http server derived from BaseHTTPServer.py.
This is my preferred method for a simple GUI.
See the following code as an example.

"""
simple http server
it executes a system command and returns stdout or return code of command
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

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 as 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