home *** CD-ROM | disk | FTP | other *** search
/ PC Professionell 1998 October / PCpro_1998_10.ISO / internet / layout / xitami.exe / addons / LRWP / LRWPLIB.PY < prev    next >
Encoding:
Python Source  |  1998-01-26  |  8.8 KB  |  273 lines

  1. #!/bin/env python
  2. #------------------------------------------------------------------------
  3. #               Copyright (c) 1997 by Total Control Software
  4. #                         All Rights Reserved
  5. #------------------------------------------------------------------------
  6. #
  7. # Module Name:  lrwplib.py
  8. #
  9. # Description:  Class LRWP handles the connection to the LRWP agent in
  10. #               Xitami.  This class can be used standalone or derived
  11. #               from to override behavior.
  12. #
  13. # Creation Date:    11/11/97 8:36:21PM
  14. #
  15. # License:      This is free software.  You may use this software for any
  16. #               purpose including modification/redistribution, so long as
  17. #               this header remains intact and that you do not claim any
  18. #               rights of ownership or authorship of this software.  This
  19. #               software has been tested, but no warranty is expressed or
  20. #               implied.
  21. #
  22. #------------------------------------------------------------------------
  23.  
  24. import  sys, socket, string
  25. from    cStringIO import StringIO
  26.  
  27.  
  28. __version__ = '1.0'
  29.  
  30. LENGTHSIZE  = 9
  31. LENGTHFMT   = '%09d'
  32.  
  33. #---------------------------------------------------------------------------
  34. # Exception objects
  35.  
  36. ConnectError        = 'lrwp.ConnectError'
  37. ConnectionClosed    = 'lrwp.ConnectionClosed'
  38. SocketError         = 'lrwp.SocketError'
  39.  
  40. #---------------------------------------------------------------------------
  41.  
  42. class Request:
  43.     '''
  44.     Encapsulates the request/response IO objects and CGI-Environment.
  45.     An instance of this class is returned
  46.     '''
  47.     def __init__(self, lrwp):
  48.         self.inp = lrwp.inp
  49.         self.out = lrwp.out
  50.         self.err = lrwp.out
  51.         self.env = lrwp.env
  52.         self.lrwp = lrwp
  53.  
  54.     def finish(self):
  55.         self.lrwp.finish()
  56.  
  57.     def getFieldStorage(self):
  58.         method = 'POST'
  59.         if self.env.has_key('REQUEST_METHOD'):
  60.             method = string.upper(self.env['REQUEST_METHOD'])
  61.         if method == 'GET':
  62.             return cgi.FieldStorage(environ=self.env, keep_blank_values=1)
  63.         else:
  64.             return cgi.FieldStorage(fp=self.inp, environ=self.env, keep_blank_values=1)
  65.  
  66.  
  67. #---------------------------------------------------------------------------
  68.  
  69. class LRWP:
  70.     def __init__(self, name, host, port, vhost='', filter='', useStdio=0):
  71.         '''
  72.         Construct an LRWP object.
  73.             name        The name or alias of this request handler.  Requests
  74.                         matching http://host/name will be directed to this
  75.                         LRWP object.
  76.             host        Hostname or IP address to connect to.
  77.             port        Port number to connect on.
  78.             vhost       If this handler is to only be available to a specific
  79.                         virtual host, name it here.
  80.             filter      A space separated list of file extenstions that should
  81.                         be directed to this handler in filter mode.  (Not yet
  82.                         supported.)
  83.         '''
  84.         self.name = name
  85.         self.host = host
  86.         self.port = port
  87.         self.vhost = vhost
  88.         self.filter = filter
  89.         self.useStdio = useStdio
  90.         self.sock = None
  91.         self.env = None
  92.         self.inp = None
  93.         self.out = None
  94.  
  95.     #----------------------------------------
  96.     def connect(self):
  97.         '''
  98.         Establishes the connection to the web server, using the parameters given
  99.         at construction.
  100.         '''
  101.         try:
  102.             self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  103.             self.sock.connect(self.host, self.port)
  104.             self.sock.send("%s\xFF%s\xFF%s" % (self.name, self.vhost, self.filter) )
  105.             buf = self.sock.recv(1024)
  106.             if buf != 'OK':
  107.                 raise ConnectError, buf
  108.         except socket.error, val:
  109.             raise SocketError, val
  110.  
  111.     #----------------------------------------
  112.     def acceptRequest(self):
  113.         '''
  114.         Wait for, and accept a new request from the Web Server.  Reads the
  115.         name=value pairs that comprise the CGI environment, followed by the
  116.         post data, if any.  Constructs and returns a Request object.
  117.         '''
  118.         if self.out:
  119.             self.finish()
  120.         try:
  121.             # get the length of the environment data
  122.             data = self.recvBlock(LENGTHSIZE)
  123.             if not data:        # server closed down
  124.                 raise ConnectionClosed
  125.             length = string.atoi(data)
  126.  
  127.             # and then the environment data
  128.             data = self.recvBlock(length)
  129.             if not data:        # server closed down
  130.                 raise ConnectionClosed
  131.             data = string.split(data, '\000')
  132.             self.env = {}
  133.             for x in data:
  134.                 x = string.split(x, '=')
  135.                 if len(x) > 1:
  136.                     self.env[x[0]] = string.join(x[1:], '=')
  137.  
  138.             # now get the size of the POST data
  139.             data = self.recvBlock(LENGTHSIZE)
  140.             if not data:        # server closed down
  141.                 raise ConnectionClosed
  142.             length = string.atoi(data)
  143.  
  144.             # and the POST data...
  145.             if length:
  146.                 data = self.recvBlock(length)
  147.                 if not data:        # server closed down
  148.                     raise ConnectionClosed
  149.                 self.inp = StringIO(data)
  150.             else:
  151.                 self.inp = StringIO()
  152.  
  153.             self.out = StringIO()
  154.  
  155.             # do the switcheroo on the sys IO objects, etc.
  156.             if self.useStdio:
  157.                 self.saveStdio = sys.stdin, sys.stdout, sys.stderr, os.environ
  158.                 sys.stdin, sys.stdout, sys.stderr, os.environ = \
  159.                     self.inp, self.out, self.out, self.env
  160.  
  161.             return Request(self)
  162.  
  163.         except socket.error, val:
  164.             raise SocketError, val
  165.  
  166.  
  167.     #----------------------------------------
  168.     def recvBlock(self, size):
  169.         '''
  170.         Pull an exact number of bytes from the socket, taking into
  171.         account the possibility of multiple packets...
  172.         '''
  173.         numRead = 0
  174.         data = []
  175.         while numRead < size:
  176.             buf = self.sock.recv(size - numRead);
  177.             if not buf:
  178.                 return ''
  179.             data.append(buf)
  180.             numRead = numRead + len(buf)
  181.  
  182.         return string.join(data, '')
  183.  
  184.     #----------------------------------------
  185.     def finish(self):
  186.         '''
  187.         Complete the request and send the output back to the webserver.
  188.         '''
  189.         doc = self.out.getvalue()
  190.         size = LENGTHFMT % (len(doc), )
  191.         try:
  192.             self.sock.send(size)
  193.             self.sock.send(doc)
  194.         except socket.error, val:
  195.             raise SocketError, val
  196.  
  197.         if self.useStdio:
  198.             sys.stdin, sys.stdout, sys.stderr, os.environ = self.saveStdio
  199.  
  200.         self.env = None
  201.         self.inp = None
  202.         self.out = None
  203.  
  204.     #----------------------------------------
  205.     def close(self):
  206.         '''
  207.         Close the LRWP connection to the web server.
  208.         '''
  209.         self.sock.close()
  210.         self.sock = None
  211.         self.env = None
  212.         self.inp = None
  213.         self.out = None
  214.  
  215. #---------------------------------------------------------------------------
  216.  
  217.  
  218. def _test():
  219.     import os, time
  220.  
  221.     eol = '\r\n'
  222.     appname = 'testapp1'
  223.     vhost = ''
  224.     host = 'localhost'
  225.     port = 5081
  226.     if len(sys.argv) > 1:
  227.         appname = sys.argv[1]
  228.     if len(sys.argv) > 2:
  229.         host = sys.argv[2]
  230.     if len(sys.argv) > 3:
  231.         port = string.atoi(sys.argv[3])
  232.     if len(sys.argv) > 4:
  233.         vhost = sys.argv[4]
  234.  
  235.     lrwp = LRWP(appname, host, port, vhost)
  236.     lrwp.connect()
  237.  
  238.     count = 0
  239.     while count < 5:        # exit after servicing 5 requests
  240.         req = lrwp.acceptRequest()
  241.  
  242.         doc = ['<HTML><HEAD><TITLE>LRWP TestApp ('+appname+')</TITLE></HEAD>\n<BODY>\n']
  243.         count = count + 1
  244.         doc.append('<H2>LRWP test app ('+appname+')</H2><P>')
  245.         doc.append('<b>request count</b> = %d<br>' % (count, ))
  246.         if hasattr(os, 'getpid'):
  247.             doc.append('<b>pid</b> = %s<br>' % (os.getpid(), ))
  248.         doc.append('<br><b>post data:</b> ' + req.inp.read() + '<br>')
  249.  
  250.         doc.append('<P><HR><P><pre>')
  251.         keys = req.env.keys()
  252.         keys.sort()
  253.         for k in keys:
  254.             doc.append('<b>%-20s :</b>  %s\n' % (k, req.env[k]))
  255.         doc.append('\n</pre><P><HR>\n')
  256.         doc.append('</BODY></HTML>\n')
  257.  
  258.  
  259.         req.out.write('Content-type: text/html' + eol)
  260.         req.out.write(eol)
  261.         req.out.write(string.join(doc, ''))
  262.  
  263.         req.finish()
  264.  
  265.     lrwp.close()
  266.  
  267.  
  268. if __name__ == '__main__':
  269.     #import pdb
  270.     #pdb.run('_test()')
  271.     _test()
  272.  
  273.