1 # -*- coding: iso-8859-1 -*-
3 MoinMoin - Flup based WSGI adapters
5 This module provides adapters between popular gateway interfaces
6 like CGI, FastCGI, SCGI and AJP to the MoinMoin WSGI application.
7 They are based on the adapters in the flup package and upon the
8 MoinMoin.frontend.ServerFrontEnd to provide configuration via
11 Typically they are simply run from the CGI-scripts like this:
13 > from MoinMoin.web.flup_frontend import CGIFrontEnd
16 They automatically parse the options given on the commandline and
17 behave accordingly. Flup makes it possible to serve FCGI, SCGI and
18 AJP from a bound network or unix socket, in different flavours of
19 multiprocessing/multithreading.
23 @license: GNU GPL, see COPYING for details.
29 import flup.server.fcgi
32 import flup.server.fcgi_single
33 have_singlepatch = True
35 have_singlepatch = False
39 from MoinMoin.web.frontend import ServerFrontEnd, FrontEnd, FrontEndNotAvailable
41 from MoinMoin import log
42 logging = log.getLogger(__name__)
45 class FlupFrontEnd(ServerFrontEnd):
46 def add_options(self):
47 super(FlupFrontEnd, self).add_options()
49 parser.add_option("--min-spare", dest="min_spare", type="int", metavar='MIN',
50 help=("Minimum spare threads/processes (when "
51 "using threaded or forking servers)."))
52 parser.add_option("--max-spare", dest="max_spare", type="int", metavar='MAX',
53 help=("Maximum spare threads/processes (when "
54 "using threaded or forking servers)."))
55 parser.add_option("--max-childs", dest="max_childs", type="int", metavar='CHILDS',
56 help=("Hard upper limit on threads/processes "
57 "(when using threaded or forking servers)."))
58 parser.add_option("-t", "--type", dest="server_type", metavar='TYPE',
59 help=("Type of server to use, e.g. single/threaded"
60 "/forking. Defaults to 'single' when not "
61 "bound to a socket and to 'threaded' when it is"))
63 def run_server(self, application, options):
64 server_type = options.server_type
67 if 'single' in self.server_types:
68 server_type = (options.port and 'threaded') or 'single'
70 server_type = 'threaded'
72 if server_type not in self.server_types:
73 raise TypeError("Unknown server type '%s'" % options.server_type)
75 multi = server_type in ('threaded', 'forking')
77 mod = self.server_types[server_type]
78 mod = __import__(mod, globals(), locals(), ['WSGIServer'])
79 WSGIServerWrapped = mod.WSGIServer
81 class WSGIServer(WSGIServerWrapped):
82 # note: base class uses debug=False as default. as we use string values,
83 # better explicitely pass in "off", "web" or "external".
85 """ Override the default handler, so it implements debug=web/external/off. """
86 if self.debug == 'external':
88 elif self.debug == 'web':
90 req.stdout.write('Content-Type: text/html\r\n\r\n' +
91 cgitb.html(sys.exc_info()))
93 errorpage = """<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
95 <title>Unhandled Exception</title>
97 <h1>Unhandled Exception</h1>
98 <p>An unhandled exception was thrown by the application.</p>
101 req.stdout.write('Content-Type: text/html\r\n\r\n' + errorpage)
106 kwargs['debug'] = options.debug or os.environ.get('MOIN_DEBUGGER', 'off')
109 kwargs['bindAddress'] = (options.interface, options.port)
110 elif options.interface and (
111 options.interface.startswith('/') or options.interface.startswith('./')):
112 kwargs['bindAddress'] = options.interface
114 if options.min_spare and multi:
115 kwargs['minSpare'] = options.min_spare
116 if options.max_spare and multi:
117 kwargs['maxSpare'] = options.max_spare
118 if options.max_childs and multi:
119 if server_type == 'threaded':
120 kwargs['maxThreads'] = options.max_childs
122 kwargs['maxChildren'] = options.max_childs
123 logging.debug("WSGIServer(%r, %r)" % (application, kwargs))
124 return WSGIServer(application, **kwargs).run()
126 class CGIFrontEnd(FlupFrontEnd):
127 server_types = {'threaded': 'flup.server.fcgi',
128 'forking': 'flup.server.fcgi_fork'}
130 server_types['single'] = 'flup.server.fcgi_single'
132 def run(self, args=None):
133 if 'GATEWAY_INTERFACE' in os.environ:
135 super(CGIFrontEnd, self).run(args)
137 class SCGIFrontEnd(FlupFrontEnd):
138 server_types = {'threaded': 'flup.server.scgi',
139 'forking': 'flup.server.scgi_fork'}
141 class AJPFrontEnd(FlupFrontEnd):
142 server_types = {'threaded': 'flup.server.ajp',
143 'forking': 'flup.server.ajp_fork'}
145 class CGIFrontEnd(FrontEnd):
146 """ Simple WSGI CGI Adapter for fallback if flup is not installed. """
148 logging.warning("No flup-package installed, only basic CGI "
149 "support is available.")
150 super(CGIFrontEnd, self).__init__()
152 def run(self, args=None):
153 if 'GATEWAY_INTERFACE' in os.environ:
155 super(CGIFrontEnd, self).run(args)
157 def run_server(self, application, options):
158 from MoinMoin.web._fallback_cgi import WSGIServer
159 return WSGIServer(application).run()
162 The flup package is not installed on your system. To make use of FCGI,
163 SCGI or AJP adapters, you have to install it first. The MoinMoin source
164 distribution provides a flup package in the contrib/flup-server
165 directory. It is also patched to support non-threaded & non-forking
166 behaviour. See contrib/flup-server/NOTES.moin for more information.
169 raise FrontEndNotAvailable(_ERROR)
171 raise FrontEndNotAvailable(_ERROR)