BoboMailHTTPD.py :  » Email » BoboMail » bobomail » Python Open Source

Home
Python Open Source
1.3.1.2 Python
2.Ajax
3.Aspect Oriented
4.Blog
5.Build
6.Business Application
7.Chart Report
8.Content Management Systems
9.Cryptographic
10.Database
11.Development
12.Editor
13.Email
14.ERP
15.Game 2D 3D
16.GIS
17.GUI
18.IDE
19.Installer
20.IRC
21.Issue Tracker
22.Language Interface
23.Log
24.Math
25.Media Sound Audio
26.Mobile
27.Network
28.Parser
29.PDF
30.Project Management
31.RSS
32.Search
33.Security
34.Template Engines
35.Test
36.UML
37.USB Serial
38.Web Frameworks
39.Web Server
40.Web Services
41.Web Unit
42.Wiki
43.Windows
44.XML
Python Open Source » Email » BoboMail 
BoboMail » bobomail » BoboMailHTTPD.py
#!/usr/bin/env python
##############################################################################
# 
# Zope Public License (ZPL) Version 0.9.5
# ---------------------------------------
# 
# Copyright (c) Digital Creations.  All rights reserved.
# 
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
# 
# 1. Redistributions in source code must retain the above copyright
#    notice, this list of conditions, and the following disclaimer.
# 
# 2. Redistributions in binary form must reproduce the above copyright
#    notice, this list of conditions, and the following disclaimer in
#    the documentation and/or other materials provided with the
#    distribution.
# 
# 3. Any use, including use of the Zope software to operate a website,
#    must either comply with the terms described below under
#    "Attribution" or alternatively secure a separate license from
#    Digital Creations.  Digital Creations will not unreasonably
#    deny such a separate license in the event that the request
#    explains in detail a valid reason for withholding attribution.
# 
# 4. All advertising materials and documentation mentioning
#    features derived from or use of this software must display
#    the following acknowledgement:
# 
#      "This product includes software developed by Digital Creations
#      for use in the Z Object Publishing Environment
#      (http://www.zope.org/)."
# 
#    In the event that the product being advertised includes an
#    intact Zope distribution (with copyright and license included)
#    then this clause is waived.
# 
# 5. Names associated with Zope or Digital Creations must not be used to
#    endorse or promote products derived from this software without
#    prior written permission from Digital Creations.
# 
# 6. Modified redistributions of any form whatsoever must retain
#    the following acknowledgment:
# 
#      "This product includes software developed by Digital Creations
#      for use in the Z Object Publishing Environment
#      (http://www.zope.org/)."
# 
#    Intact (re-)distributions of any official Zope release do not
#    require an external acknowledgement.
# 
# 7. Modifications are encouraged but must be packaged separately as
#    patches to official Zope releases.  Distributions that do not
#    clearly separate the patches from the original work must be clearly
#    labeled as unofficial distributions.  Modifications which do not
#    carry the name Zope may be packaged in any form, as long as they
#    conform to all of the clauses above.
# 
# 
# Disclaimer
# 
#   THIS SOFTWARE IS PROVIDED BY DIGITAL CREATIONS ``AS IS'' AND ANY
#   EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
#   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
#   PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL DIGITAL CREATIONS OR ITS
#   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
#   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
#   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
#   USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
#   ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
#   OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
#   OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
#   SUCH DAMAGE.
# 
# Attribution
# 
#   Individuals or organizations using this software as a web site must
#   provide attribution by placing the accompanying "button" and a link
#   to the accompanying "credits page" on the website's main entry
#   point.  In cases where this placement of attribution is not
#   feasible, a separate arrangment must be concluded with Digital
#   Creations.  Those using the software for purposes other than web
#   sites must provide a corresponding attribution in locations that
#   include a copyright using a manner best suited to the application
#   environment.  Where attribution is not possible, or is considered
#   to be onerous for some other reason, a request should be made to
#   Digital Creations to waive this requirement in writing.  As stated
#   above, for valid requests, Digital Creations will not unreasonably
#   deny such requests.
# 
# This software consists of contributions made by Digital Creations and
# many individuals on behalf of Digital Creations.  Specific
# attributions are listed in the accompanying credits file.
# 
##############################################################################
"""Simple Bobo HTTP Server (based on CGIHTTPServer.py)

What's Bobo?

  An open source collection of tools for developing
  world-wide web applications in Python. Find out more at
  http://www.digicool.com/releases/bobo/

What's Zope?

  Zope is the result of the merging of Bobo and Principia.
  For more info visit the Zope web site at
  http://www.zope.org/

What does ZopeHTTPServer.py do?

  It is a very simple web server that published a module 
  with Bobo. ZopeHTTPServer.py is probably the easiest way
  to publish a module with Bobo. It does not require anything
  besides Python and Bobo to be installed. It is fast because
  it publishes a module as a long running process.

Why not use CGI or PCGI or Medusa?

  ZopeHTTPServer is much simpler to use than other Bobo publishers.
  ZopeHTTPServer does not require any configuration. It has a 
  friendly license. It also offers excellent performance, threaded
  publishing, and streaming response, not to mention all the Bobo
  basics like authenication, control of response content-type,
  file uploads, etc.

Features:

  -Only publishes one module at a time
  -Cannot reload a module
  -Does not serve files or CGI programs, only Bobo
  -Single-threaded or multi-threaded publishing
  -Unbuffered output so response can stream
  -Works under Python 1.5 and Python 1.4 (mostly) 
  -At least it's easy to use

Basic Useage:

  ZopeHTTPServer.py <path to module>

  This publishes your module on the web.

Usage:

  ZopeHTTPServer.py [-p <port>] [-t] [-h <host address>] <path to module> [var=value,]

  Starts a web server which publishes the specified module.

  -p <port>: Run the server on the specified port. The default
  port is 9673.

  -t: Use a multi-threaded HTTP server. The default is a
  single-threaded server. Note, your platform must support
  threads to use the multi-threaded server.

  -h: Specifies the host address. Python normally supplies this by default. 

  -P <pid file>: Specifies a file in which the server will write its PID

  -s <script_name>: Specify a virtual script name.

  Specifying additional arguments of the form var=value sets environment
  variables. You can use this facility to set things like BOBO_DEBUG_MODE=1
  and the like. These setting override default environment settings, so you
  can do things like change the SCRIPT_NAME or other weird stuff. NOTE:
  var=value settings can come before or after the path to module.

  You can also use the server from Python like this::

    import ZopeHTTPServer
    ZopeHTTPServer.main(<args>)

  The form the args take is exactly the same as the command line arguments.
  For example::

    ZopeHTTPServer.main("-t","-p 80","/home/amos/Test.py","BOBO_DEBUG_MODE=1")

Using ZopeHTTPServer behind Apache 

  ZopeHTTPServer doesn't have many fancy features, but it's easy to 
  use. Andreas Kostyrka suggests using ZopeHTTPServer with an Apache
  proxy to get some of Apache's cool features like SSL.
  
  Run ZopeHTTPServer on a high port and an IP address which is behind
  a firewall. For example 127.0.0.2, port 5000::
  
    ZopeHTTPServer -p 5000 -h 127.0.0.2 /home/amos/MyModule.py SCRIPT_NAME=/intern
  
  Then use Apache's proxy module to map requests to ZopeHTTPServer::
  
    RewriteEngine on
    RewriteRule ^/intern/(.*) http://127.0.0.2:5000/$1 [P]

  This rule maps request beginning with '/intern/' to ZopeHTTPServer.
  Notice that we set the ZopeHTTPServer SCRIPT_NAME to '/intern' so that
  it knows how it's being accessed. You can change other aspects of
  ZopeHTTPServer's environment to match the proxying environment. For example
  if you are using SSL, you should set HTTPS=on.

Known bugs:

  PUT doesn't work very well at all.
  
  REQUEST.write never closes the connection under Python 1.4

  There is a problem with mutipart/form-data POST requests
  under win32 and python 1.5.2a2. I think the problem is
  with cgi.py

  Under win32 interupted HTTP requests can raise exceptions,
  but they don't seem to cause any problems.
"""

__version__='$Revision: 1.1.1.1 $'[11:-2]

import SocketServer
import SimpleHTTPServer
import BaseHTTPServer
import os
import sys
import urllib
import string
import tempfile
import socket
try: from cStringIO import StringIO
except ImportError: from StringIO import StringIO


class ResponseWriter:
    """Logs response and reorders it so status header is
    first. After status header has been written, the rest
    of the response can stream."""
    
    def __init__(self,handler):
        self.handler=handler
        self.data=""
        self.latch=None
        
    def write(self,data):
        if self.latch:
            self.handler.wfile.write(data)
        else:
            self.data=self.data+data
            start=string.find(self.data,"Status: ")
            if start != -1:
                end=string.find(self.data,"\n",start)
                status=self.data[start+8:end]
                code, message=tuple(string.split(status," ",1))
                self.handler.send_response(string.atoi(code),message)
                self.handler.wfile.write(self.data[:start]+
                    self.data[end+1:])
                self.latch=1

    def flush(self):
        pass
    

class BoboRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
    """Handler for GET, HEAD and POST. Only publishes one
    Bobo module at a time. All URLs go to the published module.
    Does not serve files or CGI programs.
    """
    
    server_version = "ZopeHTTP/" + __version__
    buffer_size = 8192
    env_override={}
    script=''

    def setup(self):
        """overrides defaults to set larger buffer for rfile
        otherwise large POST requests seem to take forever."""
        self.connection = self.request
        self.rfile = self.connection.makefile('rb', self.buffer_size)
        self.wfile = self.connection.makefile('wb', 0)

    def hack_si(self):
        #cgi.py doesn't like to parse file uploads unless we do this
        si_len=string.atoi(self.headers.getheader('content-length'))
        if si_len < 1048576:
            si=StringIO()
            si.write(self.rfile.read(si_len))
        else:
            bufsize=self.buffer_size
            si=tempfile.TemporaryFile()
            while si_len > 0:
                if si_len < bufsize:
                    bufsize=si_len
                data=self.rfile.read(bufsize)
                si_len=si_len - len(data)
                si.write(data)
        si.seek(0)
        self.rfile=si

    def do_POST(self):
        if string.find(self.headers.getheader('content-type'),
            'multipart/form-data') != -1:
            self.hack_si()
        self.publish_module()

    def do_GET(self):
        self.publish_module()

    def do_HEAD(self):
        #is this necessary?
        self.publish_module()
    
    def do_PUT(self):
        #doesn't work very well yet
        self.env_override['REQUEST_METHOD']='PUT'
        self.env_override['CONTENT_TYPE']='application/data'
        self.hack_si()
        self.publish_module()

    def publish_module(self):
        publish_module(
            self.module_name,
            stdin=self.rfile,
            stdout=ResponseWriter(self),
            stderr=sys.stderr,
            environ=self.get_environment())

    def get_environment(self):
        #Partially derived from CGIHTTPServer
        env={}
        env['SERVER_SOFTWARE'] = self.version_string()
        env['SERVER_NAME'] = self.server.server_name
        env['SERVER_PORT'] = str(self.server.server_port)
        env['SERVER_PROTOCOL'] = self.protocol_version
        env['GATEWAY_INTERFACE'] = 'CGI/1.1'
        rest = self.path
        i = string.rfind(rest, '?')
        if i >= 0:
            rest, query = rest[:i], rest[i+1:]
        else:
            query = ''
        uqrest = urllib.unquote(rest)
  script=self.script
  if script:
      env['SCRIPT_NAME'] = script[:-1]
      if uqrest[:len(script)]==script:
    uqrest=uqrest[len(script)-1:]
  else: env['SCRIPT_NAME'] = ''
        env['PATH_INFO'] = uqrest
        env['REQUEST_METHOD'] = self.command
        env['PATH_TRANSLATED'] = self.translate_path(uqrest)
        if query:
            env['QUERY_STRING'] = query
        host = self.address_string()
        if host != self.client_address[0]:
            env['REMOTE_HOST'] = host
        env['REMOTE_ADDR'] = self.client_address[0]
        env['CONTENT_TYPE'] = self.headers.getheader('content-type')
        length = self.headers.getheader('content-length')
        if length:
            env['CONTENT_LENGTH'] = length
        # handle the rest of the environment
        for k,v in self.headers.items():
            k=string.upper(string.join(string.split(k,"-"),"_"))
            if not env.has_key(k) and v:
                env['HTTP_'+k]=v
        if self.env_override:
            for k,v in self.env_override.items():
                env[k]=v
        return env


class NonThreadingHTTPServer(BaseHTTPServer.HTTPServer):
    "The normal HTTPServer with some socket tweaks"
    
    def server_bind(self):
        # Modified version of server_bind that allows unconnected
        # win32 boxes to run the server without errors.
        self.socket.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
        SocketServer.TCPServer.server_bind(self)
        host, port = self.socket.getsockname()
        hostname=host
        if not host or host == '0.0.0.0':
            host = socket.gethostname()
        try:
            hostname, hostnames, hostaddrs = socket.gethostbyaddr(host)
            if '.' not in hostname:
                for host in hostnames:
                    if '.' in host:
                        hostname = host
                        break
        except:
            pass
        self.server_name = hostname
        self.server_port = port

    def handle_request(self):
        """Handle one request, possibly blocking."""
        request, client_address = self.get_request()
        if self.verify_request(request, client_address):
            try:
                self.process_request(request, client_address)
            except SystemExit:
                self.handle_error(request, client_address)
                sys.exit(0)
            except:
                self.handle_error(request, client_address)

                
class ThreadingHTTPServer(SocketServer.ThreadingMixIn,
    NonThreadingHTTPServer):
    "A threading HTTPServer with some socket tweaks"
    pass


def try_to_become_nobody():
    # from CGIHTTPServer
    try: import pwd
    except: return
    try:
        nobody = pwd.getpwnam('nobody')[2]
    except pwd.error:
        nobody = 1 + max(map(lambda x: x[2], pwd.getpwall()))
    try: os.setuid(nobody)
    except os.error: pass    

def set_published_module(file,klass,env=None):
    dir,file=os.path.split(file)
    name,ext=os.path.splitext(file)
    klass.module_name=name
    klass.module_dir=dir
    cdir=os.path.join(dir,'Components')
    sys.path[0:0]=[dir,cdir,os.path.join(cdir,sys.platform)]
    
    if env is not None:
        klass.env_override=env
    
    global publish_module
    try:
        import ZPublisher
        publish_module=ZPublisher.publish_module
    except:
        import cgi_module_publisher
        publish_module=cgi_module_publisher.publish_module
        
    __import__(name) # to catch problem modules right away
    print "Publishing module %s" % name

def start(module_file, host='', port=8080, threading=None,env=None):
    set_published_module(module_file,BoboRequestHandler,env)
    server_address = (host, port)
    if threading:
        try:
            import thread
            httpd = ThreadingHTTPServer(server_address,
                BoboRequestHandler)
            print "Using threading server"
        except ImportError:
            httpd = NonThreadingHTTPServer(server_address,
                BoboRequestHandler)
    else:
        httpd = NonThreadingHTTPServer(server_address,
            BoboRequestHandler)
    print "Serving HTTP on port", port, "..."
    try_to_become_nobody()
    try:
        httpd.serve_forever()
    except:
        httpd.socket.close()
        sys.exit(1)

def die(message=''):
    if message: print '\nError: %s\n' % message
    print __doc__
    sys.exit(1)

def main(args=None):
    args=args or sys.argv[1:]
    import getopt
    optlist, args=getopt.getopt(args,"tp:h:P:s:")
    if len(args) < 1: die()

    env={}
    module_file=''
    for a in args:
        a=string.split(a,'=')
        if len(a)==1:
            if module_file: die('Unrecognized argument: %s' % a[0])
            module_file=a[0]
        elif len(a)==0: continue
        else:
            k, v = a[0], string.join(a[1:],'=')
            os.environ[k]=v
            env[k]=v

    port=9673
    threading=None
    host=''
    for k,v in optlist:
        if k=="-p":
            port=string.atoi(v)
        elif k=="-t":
            threading=1
        elif k=="-h":
            host=v
        elif k=="-P":
            open(v,'w').write(str(os.getpid()))
  elif k=='-s':
      while v[:1]=='/': v=v[1:]
      while v[-1:]=='/': v=v[:-1]
      BoboRequestHandler.script="/%s/" % v
    start(module_file,host,port,threading,env)


if __name__=="__main__": 
    if os.environ.has_key("QUERY_STRING"):
    print "Content-type: text/plain\n"

    sys.path.insert(0, os.path.dirname(sys.argv[0]))
    import bobomailrc
    sys.path.insert(0, bobomailrc.app_dir)
    
    bobomailrc.image_dir = "GetFile?images"

    if "-d" in sys.argv:
  sys.stdout = sys.stderr = open(bobomailrc.access_log, "a")
  sys.argv.remove("-d")
    
    #remove "-t" if your Python-interpreter doesn't support threads
    main(["-p", str(bobomailrc.httpd_port), "main"])
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.