web/lib/django/core/servers/fastcgi.py
changeset 0 0d40e90630ef
equal deleted inserted replaced
-1:000000000000 0:0d40e90630ef
       
     1 """
       
     2 FastCGI (or SCGI, or AJP1.3 ...) server that implements the WSGI protocol.
       
     3 
       
     4 Uses the flup python package: http://www.saddi.com/software/flup/
       
     5 
       
     6 This is a adaptation of the flup package to add FastCGI server support
       
     7 to run Django apps from Web servers that support the FastCGI protocol.
       
     8 This module can be run standalone or from the django-admin / manage.py
       
     9 scripts using the "runfcgi" directive.
       
    10 
       
    11 Run with the extra option "help" for a list of additional options you can
       
    12 pass to this server.
       
    13 """
       
    14 
       
    15 from django.utils import importlib
       
    16 import sys, os
       
    17 
       
    18 __version__ = "0.1"
       
    19 __all__ = ["runfastcgi"]
       
    20 
       
    21 FASTCGI_HELP = r"""
       
    22   Run this project as a fastcgi (or some other protocol supported
       
    23   by flup) application. To do this, the flup package from
       
    24   http://www.saddi.com/software/flup/ is required.
       
    25 
       
    26    runfcgi [options] [fcgi settings]
       
    27 
       
    28 Optional Fcgi settings: (setting=value)
       
    29   protocol=PROTOCOL    fcgi, scgi, ajp, ... (default fcgi)
       
    30   host=HOSTNAME        hostname to listen on..
       
    31   port=PORTNUM         port to listen on.
       
    32   socket=FILE          UNIX socket to listen on.
       
    33   method=IMPL          prefork or threaded (default prefork)
       
    34   maxrequests=NUMBER   number of requests a child handles before it is 
       
    35                        killed and a new child is forked (0 = no limit).
       
    36   maxspare=NUMBER      max number of spare processes / threads
       
    37   minspare=NUMBER      min number of spare processes / threads.
       
    38   maxchildren=NUMBER   hard limit number of processes / threads
       
    39   daemonize=BOOL       whether to detach from terminal.
       
    40   pidfile=FILE         write the spawned process-id to this file.
       
    41   workdir=DIRECTORY    change to this directory when daemonizing.
       
    42   debug=BOOL           set to true to enable flup tracebacks
       
    43   outlog=FILE          write stdout to this file.
       
    44   errlog=FILE          write stderr to this file.
       
    45   umask=UMASK          umask to use when daemonizing (default 022).
       
    46 
       
    47 Examples:
       
    48   Run a "standard" fastcgi process on a file-descriptor
       
    49   (for webservers which spawn your processes for you)
       
    50     $ manage.py runfcgi method=threaded
       
    51 
       
    52   Run a scgi server on a TCP host/port
       
    53     $ manage.py runfcgi protocol=scgi method=prefork host=127.0.0.1 port=8025
       
    54 
       
    55   Run a fastcgi server on a UNIX domain socket (posix platforms only)
       
    56     $ manage.py runfcgi method=prefork socket=/tmp/fcgi.sock
       
    57 
       
    58   Run a fastCGI as a daemon and write the spawned PID in a file
       
    59     $ manage.py runfcgi socket=/tmp/fcgi.sock method=prefork \
       
    60         daemonize=true pidfile=/var/run/django-fcgi.pid
       
    61 
       
    62 """
       
    63 
       
    64 FASTCGI_OPTIONS = {
       
    65     'protocol': 'fcgi',
       
    66     'host': None,
       
    67     'port': None,
       
    68     'socket': None,
       
    69     'method': 'fork',
       
    70     'daemonize': None,
       
    71     'workdir': '/',
       
    72     'pidfile': None,
       
    73     'maxspare': 5,
       
    74     'minspare': 2,
       
    75     'maxchildren': 50,
       
    76     'maxrequests': 0,
       
    77     'debug': None,
       
    78     'outlog': None,
       
    79     'errlog': None,
       
    80     'umask': None,
       
    81 }
       
    82 
       
    83 def fastcgi_help(message=None):
       
    84     print FASTCGI_HELP
       
    85     if message:
       
    86         print message
       
    87     return False
       
    88 
       
    89 def runfastcgi(argset=[], **kwargs):
       
    90     options = FASTCGI_OPTIONS.copy()
       
    91     options.update(kwargs)
       
    92     for x in argset:
       
    93         if "=" in x:
       
    94             k, v = x.split('=', 1)
       
    95         else:
       
    96             k, v = x, True
       
    97         options[k.lower()] = v
       
    98 
       
    99     if "help" in options:
       
   100         return fastcgi_help()
       
   101 
       
   102     try:
       
   103         import flup
       
   104     except ImportError, e:
       
   105         print >> sys.stderr, "ERROR: %s" % e
       
   106         print >> sys.stderr, "  Unable to load the flup package.  In order to run django"
       
   107         print >> sys.stderr, "  as a FastCGI application, you will need to get flup from"
       
   108         print >> sys.stderr, "  http://www.saddi.com/software/flup/   If you've already"
       
   109         print >> sys.stderr, "  installed flup, then make sure you have it in your PYTHONPATH."
       
   110         return False
       
   111 
       
   112     flup_module = 'server.' + options['protocol']
       
   113 
       
   114     if options['method'] in ('prefork', 'fork'):
       
   115         wsgi_opts = {
       
   116             'maxSpare': int(options["maxspare"]),
       
   117             'minSpare': int(options["minspare"]),
       
   118             'maxChildren': int(options["maxchildren"]),
       
   119             'maxRequests': int(options["maxrequests"]),
       
   120         }
       
   121         flup_module += '_fork'
       
   122     elif options['method'] in ('thread', 'threaded'):
       
   123         wsgi_opts = {
       
   124             'maxSpare': int(options["maxspare"]),
       
   125             'minSpare': int(options["minspare"]),
       
   126             'maxThreads': int(options["maxchildren"]),
       
   127         }
       
   128     else:
       
   129         return fastcgi_help("ERROR: Implementation must be one of prefork or thread.")
       
   130 
       
   131     wsgi_opts['debug'] = options['debug'] is not None
       
   132 
       
   133     try:
       
   134         module = importlib.import_module('.%s' % flup_module, 'flup')
       
   135         WSGIServer = module.WSGIServer
       
   136     except:
       
   137         print "Can't import flup." + flup_module
       
   138         return False
       
   139 
       
   140     # Prep up and go
       
   141     from django.core.handlers.wsgi import WSGIHandler
       
   142 
       
   143     if options["host"] and options["port"] and not options["socket"]:
       
   144         wsgi_opts['bindAddress'] = (options["host"], int(options["port"]))
       
   145     elif options["socket"] and not options["host"] and not options["port"]:
       
   146         wsgi_opts['bindAddress'] = options["socket"]
       
   147     elif not options["socket"] and not options["host"] and not options["port"]:
       
   148         wsgi_opts['bindAddress'] = None
       
   149     else:
       
   150         return fastcgi_help("Invalid combination of host, port, socket.")
       
   151 
       
   152     if options["daemonize"] is None:
       
   153         # Default to daemonizing if we're running on a socket/named pipe.
       
   154         daemonize = (wsgi_opts['bindAddress'] is not None)
       
   155     else:
       
   156         if options["daemonize"].lower() in ('true', 'yes', 't'):
       
   157             daemonize = True
       
   158         elif options["daemonize"].lower() in ('false', 'no', 'f'):
       
   159             daemonize = False
       
   160         else:
       
   161             return fastcgi_help("ERROR: Invalid option for daemonize parameter.")
       
   162 
       
   163     daemon_kwargs = {}
       
   164     if options['outlog']:
       
   165         daemon_kwargs['out_log'] = options['outlog']
       
   166     if options['errlog']:
       
   167         daemon_kwargs['err_log'] = options['errlog']
       
   168     if options['umask']:
       
   169         daemon_kwargs['umask'] = int(options['umask'])
       
   170 
       
   171     if daemonize:
       
   172         from django.utils.daemonize import become_daemon
       
   173         become_daemon(our_home_dir=options["workdir"], **daemon_kwargs)
       
   174 
       
   175     if options["pidfile"]:
       
   176         fp = open(options["pidfile"], "w")
       
   177         fp.write("%d\n" % os.getpid())
       
   178         fp.close()
       
   179 
       
   180     WSGIServer(WSGIHandler(), **wsgi_opts).run()
       
   181 
       
   182 if __name__ == '__main__':
       
   183     runfastcgi(sys.argv[1:])