| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,325 @@ | ||
| 2011-04-04 Allan Saddi <allan@saddi.com> | ||
|
|
||
| * Add threadpool options to Paste factories. | ||
|
|
||
| 2011-02-19 Allan Saddi <allan@saddi.com> | ||
|
|
||
| * When deriving PATH_INFO from REQUEST_URI, take SCRIPT_NAME into account. | ||
|
|
||
| 2011-01-11 Allan Saddi <allan@saddi.com> | ||
|
|
||
| * Use HTTP status code 500 for error pages. Thanks to | ||
| Yohann Gabory for pointing out this issue and providing a patch. | ||
|
|
||
| 2010-10-14 Allan Saddi <allan@saddi.com> | ||
|
|
||
| * Don't try to restore signal handlers if they weren't installed in | ||
| the first place. | ||
|
|
||
| 2010-10-05 Allan Saddi <allan@saddi.com> | ||
|
|
||
| * Improvements to *_app._getConnection methods suggested by | ||
| Andrej A Antonov. Thanks! | ||
|
|
||
| 2009-10-27 Allan Saddi <allan@saddi.com> | ||
|
|
||
| * Exit gracefully if a thread cannot be started when adding a new | ||
| job. | ||
|
|
||
| 2009-10-21 Allan Saddi <allan@saddi.com> | ||
|
|
||
| * Add configurable timeout (default: no timeout) to be used when the | ||
| WSGI application is called. Only applies to forked servers! | ||
|
|
||
| 2009-06-05 Allan Saddi <allan@saddi.com> | ||
|
|
||
| * Fix bug in scgi servers that occurs when SCRIPT_NAME is missing. | ||
| Thanks to Jon Nelson for finding the problem! | ||
|
|
||
| 2009-05-29 Allan Saddi <allan@saddi.com> | ||
|
|
||
| * Let all the active requests to finish before quitting. Thanks | ||
| to Anand Chitipothu for the patch! | ||
|
|
||
| 2009-05-26 Allan Saddi <allan@saddi.com> | ||
|
|
||
| * Release 1.0.2 | ||
|
|
||
| 2009-05-18 Allan Saddi <allan@saddi.com> | ||
|
|
||
| * Import Paste factories (and dependencies...) from PasteScript | ||
|
|
||
| 2009-05-04 Allan Saddi <allan@saddi.com> | ||
|
|
||
| * Be tolerant of EAGAIN when sending messages to parent process. | ||
|
|
||
| 2009-02-02 Allan Saddi <allan@saddi.com> | ||
|
|
||
| * Add forceCGI keyword argument to FastCGI servers to | ||
| programmatically force CGI behavior. | ||
|
|
||
| * Merge Tommi Virtanen's "single server" (sequential server) | ||
| patch. | ||
|
|
||
| 2008-12-03 Allan Saddi <allan@saddi.com> | ||
|
|
||
| * Update ez_setup.py. | ||
|
|
||
| 2008-09-26 Allan Saddi <allan@saddi.com> | ||
|
|
||
| * Re-seed random module after each fork. | ||
|
|
||
| 2008-09-11 Allan Saddi <allan@saddi.com> | ||
|
|
||
| * Add an indication as to which header fails assertion when | ||
| passing in non-string header names and/or values. | ||
|
|
||
| 2008-08-20 Allan Saddi <allan@saddi.com> | ||
|
|
||
| * Add support for setting umask for UNIX domain sockets from | ||
| paste.server_factory implementations. Thanks to Michal Suszko | ||
| for the patch. | ||
|
|
||
| 2008-07-23 Allan Saddi <allan@saddi.com> | ||
|
|
||
| * Add support for configuring UNIX domain sockets (for servers that | ||
| support them) in the paste.server_factory implementations. Thanks | ||
| to Dan Roberts for the code. | ||
|
|
||
| 2008-07-22 Allan Saddi <allan@saddi.com> | ||
|
|
||
| * Release 1.0.1 | ||
|
|
||
| * Attempt to deduce missing PATH_INFO and/or QUERY_STRING from | ||
| REQUEST_URI, if present. Patch provided by Richard Davies. | ||
|
|
||
| 2007-09-10 Allan Saddi <allan@saddi.com> | ||
|
|
||
| * Fix readline implementations so size argument is checked | ||
| earlier. | ||
|
|
||
| 2007-07-14 Allan Saddi <allan@saddi.com> | ||
|
|
||
| * Prevent ThreadPool inconsistences if an exception is | ||
| actually raised. Thanks to Tim Chen for the patch. | ||
|
|
||
| 2007-06-05 Allan Saddi <allan@saddi.com> | ||
|
|
||
| * Remove publisher and middleware packages. | ||
| * Add cgi server for completeness. | ||
|
|
||
| 2007-05-17 Allan Saddi <allan@saddi.com> | ||
|
|
||
| * Fix fcgi_fork so it can run on Solaris. Thanks to | ||
| Basil Crow for the patch. | ||
|
|
||
| 2007-01-22 Allan Saddi <allan@saddi.com> | ||
|
|
||
| * Fix eunuchs import issue. | ||
|
|
||
| 2007-01-10 Allan Saddi <allan@saddi.com> | ||
|
|
||
| * Support gzip compression of XHTML pages using the | ||
| correct MIME type. | ||
|
|
||
| 2006-12-29 Allan Saddi <allan@saddi.com> | ||
|
|
||
| * Deprecate WSGI_SCRIPT_NAME and scriptName in scgi_base. | ||
| Modern versions of mod_scgi correctly set SCRIPT_NAME & | ||
| PATH_INFO. | ||
|
|
||
| 2006-12-13 Allan Saddi <allan@saddi.com> | ||
|
|
||
| * Fix problem in session.py seen when optimization is on. | ||
|
|
||
| 2006-12-05 Allan Saddi <allan@saddi.com> | ||
|
|
||
| * Update servers to default to an empty QUERY_STRING if | ||
| not present in the environ. | ||
| * Update gzip.py: compresslevel -> compress_level | ||
| * Update gzip.py by updating docstrings and renaming | ||
| classes/methods/functions to better follow Python naming | ||
| conventions. NB: mimeTypes keyword parameter is now | ||
| mime_types. | ||
|
|
||
| 2006-12-02 Allan Saddi <allan@saddi.com> | ||
|
|
||
| * Change intra-package imports into absolute imports. | ||
|
|
||
| 2006-12-02 Allan Saddi <allan@saddi.com> | ||
|
|
||
| * Add forceCookieOutput attribute to SessionService to | ||
| force Set-Cookie output for the current request. | ||
|
|
||
| 2006-12-01 Allan Saddi <allan@saddi.com> | ||
|
|
||
| * Update setup script. | ||
|
|
||
| 2006-11-26 Allan Saddi <allan@saddi.com> | ||
|
|
||
| * Don't attempt to install signal handlers under Windows | ||
| to improve compatibility. | ||
|
|
||
| 2006-11-24 Allan Saddi <allan@saddi.com> | ||
|
|
||
| * Add *_thread egg entry-point aliases. | ||
| * Add UNIX domain socket support to scgi, scgi_fork, | ||
| scgi_app. | ||
| * Add flup.client package which contains various | ||
| WSGI -> connector client implentations. (So far: FastCGI, | ||
| and SCGI.) | ||
|
|
||
| 2006-11-19 Allan Saddi <allan@saddi.com> | ||
|
|
||
| * Change mime-type matching algorithm in GzipMiddleware. | ||
| Strip parameters (e.g. "encoding") and accept a list of | ||
| regexps. By default, compress 'text/.*' mime-types. | ||
|
|
||
| 2006-11-10 Allan Saddi <allan@saddi.com> | ||
|
|
||
| * Add cookieAttributes to SessionService to make it easier | ||
| to customize the generated cookie's attributes. | ||
|
|
||
| 2006-08-28 Allan Saddi <allan@saddi.com> | ||
|
|
||
| * Add support for FastCGI roles other than FCGI_RESPONDER. | ||
| Patch provided by Seairth Jacobs. | ||
|
|
||
| 2006-08-02 Allan Saddi <allan@saddi.com> | ||
|
|
||
| * Add cookieExpiration keyword to SessionService / | ||
| SessionMiddleware to adjust the session cookie's expiration. | ||
| Thanks to Blaise Laflamme for the suggestion. | ||
|
|
||
| 2006-06-27 Allan Saddi <allan@saddi.com> | ||
|
|
||
| * Set close-on-exec flag on all server sockets. Thanks to | ||
| Ralf Schmitt for reporting the problem. | ||
|
|
||
| 2006-06-18 Allan Saddi <allan@saddi.com> | ||
|
|
||
| * Stop ignoring EPIPE exceptions, as this is probably the | ||
| wrong thing to do. (Application is unaware of disconnected | ||
| clients and the CPU spins when sending large files to a | ||
| disconnected client.) Thanks to Ivan Sagalaev for bringing | ||
| this to my attention. | ||
|
|
||
| NB: Existing applications that use the flup servers may begin | ||
| seeing socket.error exceptions... | ||
|
|
||
| 2006-05-18 Allan Saddi <allan@saddi.com> | ||
|
|
||
| * Added umask keyword parameter to fcgi and fcgi_fork, | ||
| for use when binding to a UNIX socket. | ||
|
|
||
| 2006-05-03 Allan Saddi <allan@saddi.com> | ||
|
|
||
| * Fix illusive problem with AJP implementation. Thanks to | ||
| Moshe Van der Sterre for explaining the problem and | ||
| providing a fix. | ||
|
|
||
| 2006-04-06 Allan Saddi <allan@saddi.com> | ||
|
|
||
| * Catch a strange FieldStorage case. Seen in production. | ||
| Not quite sure what causes it. | ||
|
|
||
| 2006-03-21 Allan Saddi <allan@saddi.com> | ||
|
|
||
| * Add maxRequests option to PreforkServer. Patch provided by | ||
| Wojtek Sobczuk. | ||
|
|
||
| 2006-02-23 Allan Saddi <allan@saddi.com> | ||
|
|
||
| * Add paste.server_factory-compliant factories and respective | ||
| egg entry points. Thanks to Luis Bruno for the code. | ||
|
|
||
| Add debug option to servers, which is True by default. | ||
| Currently, only server-level error handling is affected. | ||
|
|
||
| 2006-01-15 Allan Saddi <allan@saddi.com> | ||
|
|
||
| * Change the behavior of ImportingModuleResolver when dealing | ||
| with ImportErrors. Previously, it would act as if the module | ||
| did not exist. Now, it propagates the exception to another | ||
| level (outer middleware or WSGI). Reported by Scot Doyle. | ||
|
|
||
| 2006-01-05 Allan Saddi <allan@saddi.com> | ||
|
|
||
| * Improve Windows compatibility by conditionally installing | ||
| SIGHUP handler. Thanks to Brad Miller for pointing out the | ||
| problem and providing a fix. | ||
|
|
||
| 2005-12-19 Allan Saddi <allan@saddi.com> | ||
|
|
||
| * Fix socket leak in eunuchs socketpair() wrapper. Thanks to | ||
| Georg Bauer for pointing this out. | ||
|
|
||
| 2005-12-16 Allan Saddi <allan@saddi.com> | ||
|
|
||
| * Switch to setuptools for egg support. | ||
| * Add higher-level 404 error page support. Thanks to Scot Doyle | ||
| for suggesting the idea and providing code. If you previously | ||
| subclassed Publisher to provide a custom 404 error page, this | ||
| is now broken. It will have to be massaged to fit the new | ||
| calling convention. | ||
|
|
||
| 2005-11-28 Allan Saddi <allan@saddi.com> | ||
|
|
||
| * Fix issue with FCGI_GET_VALUES handling. Thanks to | ||
| Timothy Wright for pointing this out. | ||
|
|
||
| 2005-11-18 Allan Saddi <allan@saddi.com> | ||
|
|
||
| * When running under Python < 2.4, attempt to use socketpair() | ||
| from eunuchs module. | ||
|
|
||
| 2005-09-07 Allan Saddi <allan@saddi.com> | ||
|
|
||
| * Python 2.3 doesn't define socket.SHUT_WR, which affected | ||
| the closing of the FastCGI socket with the server. This would | ||
| cause output to hang. Thanks to Eugene Lazutkin for bringing | ||
| the problem to my attention and going out of his way to help | ||
| me debug it! | ||
|
|
||
| 2005-07-03 Allan Saddi <allan@saddi.com> | ||
|
|
||
| * Ensure session identifiers only contain ASCII characters when | ||
| using a non-ASCII locale. Thanks to Ksenia Marasanova for the | ||
| the fix. | ||
|
|
||
| 2005-06-12 Allan Saddi <allan@saddi.com> | ||
|
|
||
| * Cleanly close connection socket to avoid sending a TCP RST to | ||
| the web server. (fcgi_base) Fix suggested by Dima Barsky. | ||
|
|
||
| 2005-05-31 Allan Saddi <allan@saddi.com> | ||
|
|
||
| * Take scriptName from the WSGI_SCRIPT_NAME environment variable | ||
| passed from the web server, if present. | ||
| * Check if scriptName is None, and if so, don't modify SCRIPT_NAME | ||
| & PATH_INFO. For better compatibility with cgi2scgi. (scgi_base) | ||
|
|
||
| 2005-05-18 Allan Saddi <allan@saddi.com> | ||
|
|
||
| * Change default allowedServers for ajp and scgi to ['127.0.0.1']. | ||
| * Accept PATH_INFO from environment for scgi servers, in case | ||
| cgi2scgi is being used. Submitted by Ian Bicking. | ||
| * Change threaded servers so wsgi.multiprocess is False by default. | ||
| Allow it to be changed by keyword argument. | ||
| * Fix wsgi.multiprocess for scgi_fork. (Set to True.) | ||
|
|
||
| 2005-05-15 Allan Saddi <allan@saddi.com> | ||
|
|
||
| * Prevent possible deadlock related to DiskSessionStore locking. | ||
| * Add logic to SessionStore so that it will block if attempting to | ||
| check out a Session that's already been checked out. | ||
|
|
||
| 2005-05-14 Allan Saddi <allan@saddi.com> | ||
|
|
||
| * Convert the use of decorators in session.py to something | ||
| compatible with Python <2.4. | ||
|
|
||
| 2005-04-23 Allan Saddi <allan@saddi.com> | ||
|
|
||
| * Ensure that SessionStore.checkOutSession() never returns an | ||
| invalidated Session. Reported by Rene Dudfield. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| Metadata-Version: 1.0 | ||
| Name: flup | ||
| Version: 1.0.3.dev-20110405 | ||
| Summary: Random assortment of WSGI servers | ||
| Home-page: http://www.saddi.com/software/flup/ | ||
| Author: Allan Saddi | ||
| Author-email: allan@saddi.com | ||
| License: BSD | ||
| Description: UNKNOWN | ||
| Platform: UNKNOWN | ||
| Classifier: Development Status :: 5 - Production/Stable | ||
| Classifier: Environment :: Web Environment | ||
| Classifier: Intended Audience :: Developers | ||
| Classifier: License :: OSI Approved :: BSD License | ||
| Classifier: Operating System :: OS Independent | ||
| Classifier: Programming Language :: Python | ||
| Classifier: Topic :: Internet :: WWW/HTTP :: WSGI :: Server | ||
| Classifier: Topic :: Software Development :: Libraries :: Python Modules |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| 2013-09-01, Larry Shaffer <larrys@dakotacarto.com> | ||
|
|
||
| This is a stripped-down source of flup-1.0.3.dev-20110405, specifically to act | ||
| only as a client to a locally spawned QGIS Server fcgi process, for unit tests. | ||
|
|
||
| flup available at http://trac.saddi.com/flup under a BSD-style license |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| # |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| # | ||
| class NoDefault(object): | ||
| pass | ||
|
|
||
| __all__ = [ 'NoDefault', ] |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,207 @@ | ||
| """ | ||
| .. highlight:: python | ||
| :linenothreshold: 5 | ||
| .. highlight:: bash | ||
| :linenothreshold: 5 | ||
| ajp - an AJP 1.3/WSGI gateway. | ||
| :copyright: Copyright (c) 2005, 2006 Allan Saddi <allan@saddi.com> | ||
| All rights reserved. | ||
| :license: | ||
| Redistribution and use in source and binary forms, with or without | ||
| modification, are permitted provided that the following conditions | ||
| are met: | ||
| 1. Redistributions of 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. | ||
| THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS **AS IS** AND | ||
| ANY EXPRESS 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 THE AUTHOR OR 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. | ||
| For more information about AJP and AJP connectors for your web server, see | ||
| http://jakarta.apache.org/tomcat/connectors-doc/. | ||
| For more information about the Web Server Gateway Interface, see | ||
| http://www.python.org/peps/pep-0333.html. | ||
| Example usage:: | ||
| #!/usr/bin/env python | ||
| import sys | ||
| from myapplication import app # Assume app is your WSGI application object | ||
| from ajp import WSGIServer | ||
| ret = WSGIServer(app).run() | ||
| sys.exit(ret and 42 or 0) | ||
| See the documentation for WSGIServer for more information. | ||
| About the bit of logic at the end: | ||
| Upon receiving SIGHUP, the python script will exit with status code 42. This | ||
| can be used by a wrapper script to determine if the python script should be | ||
| re-run. When a SIGINT or SIGTERM is received, the script exits with status | ||
| code 0, possibly indicating a normal exit. | ||
| Example wrapper script:: | ||
| #!/bin/sh | ||
| STATUS=42 | ||
| while test $STATUS -eq 42; do | ||
| python "$@" that_script_above.py | ||
| STATUS=$? | ||
| done | ||
| Example workers.properties (for mod_jk):: | ||
| worker.list=foo | ||
| worker.foo.port=8009 | ||
| worker.foo.host=localhost | ||
| worker.foo.type=ajp13 | ||
| Example httpd.conf (for mod_jk):: | ||
| JkWorkersFile /path/to/workers.properties | ||
| JkMount /* foo | ||
| Note that if you mount your ajp application anywhere but the root ("/"), you | ||
| SHOULD specifiy scriptName to the WSGIServer constructor. This will ensure | ||
| that SCRIPT_NAME/PATH_INFO are correctly deduced. | ||
| """ | ||
|
|
||
| __author__ = 'Allan Saddi <allan@saddi.com>' | ||
| __version__ = '$Revision$' | ||
|
|
||
| import socket | ||
| import logging | ||
|
|
||
| from flup.server.ajp_base import BaseAJPServer, Connection | ||
| from flup.server.threadedserver import ThreadedServer | ||
|
|
||
| __all__ = ['WSGIServer'] | ||
|
|
||
| class WSGIServer(BaseAJPServer, ThreadedServer): | ||
| """ | ||
| AJP1.3/WSGI server. Runs your WSGI application as a persistant program | ||
| that understands AJP1.3. Opens up a TCP socket, binds it, and then | ||
| waits for forwarded requests from your webserver. | ||
| Why AJP? Two good reasons are that AJP provides load-balancing and | ||
| fail-over support. Personally, I just wanted something new to | ||
| implement. :) | ||
| Of course you will need an AJP1.3 connector for your webserver (e.g. | ||
| mod_jk) - see http://jakarta.apache.org/tomcat/connectors-doc/. | ||
| """ | ||
| def __init__(self, application, scriptName='', environ=None, | ||
| multithreaded=True, multiprocess=False, | ||
| bindAddress=('localhost', 8009), allowedServers=None, | ||
| loggingLevel=logging.INFO, debug=False, **kw): | ||
| """ | ||
| scriptName is the initial portion of the URL path that "belongs" | ||
| to your application. It is used to determine PATH_INFO (which doesn't | ||
| seem to be passed in). An empty scriptName means your application | ||
| is mounted at the root of your virtual host. | ||
| environ, which must be a dictionary, can contain any additional | ||
| environment variables you want to pass to your application. | ||
| bindAddress is the address to bind to, which must be a tuple of | ||
| length 2. The first element is a string, which is the host name | ||
| or IPv4 address of a local interface. The 2nd element is the port | ||
| number. | ||
| allowedServers must be None or a list of strings representing the | ||
| IPv4 addresses of servers allowed to connect. None means accept | ||
| connections from anywhere. | ||
| loggingLevel sets the logging level of the module-level logger. | ||
| """ | ||
| BaseAJPServer.__init__(self, application, | ||
| scriptName=scriptName, | ||
| environ=environ, | ||
| multithreaded=multithreaded, | ||
| multiprocess=multiprocess, | ||
| bindAddress=bindAddress, | ||
| allowedServers=allowedServers, | ||
| loggingLevel=loggingLevel, | ||
| debug=debug) | ||
| for key in ('jobClass', 'jobArgs'): | ||
| if kw.has_key(key): | ||
| del kw[key] | ||
| ThreadedServer.__init__(self, jobClass=Connection, | ||
| jobArgs=(self, None), **kw) | ||
|
|
||
| def run(self): | ||
| """ | ||
| Main loop. Call this after instantiating WSGIServer. SIGHUP, SIGINT, | ||
| SIGQUIT, SIGTERM cause it to cleanup and return. (If a SIGHUP | ||
| is caught, this method returns True. Returns False otherwise.) | ||
| """ | ||
| self.logger.info('%s starting up', self.__class__.__name__) | ||
|
|
||
| try: | ||
| sock = self._setupSocket() | ||
| except socket.error, e: | ||
| self.logger.error('Failed to bind socket (%s), exiting', e[1]) | ||
| return False | ||
|
|
||
| ret = ThreadedServer.run(self, sock) | ||
|
|
||
| self._cleanupSocket(sock) | ||
| # AJP connections are more or less persistent. .shutdown() will | ||
| # not return until the web server lets go. So don't bother calling | ||
| # it... | ||
| #self.shutdown() | ||
|
|
||
| self.logger.info('%s shutting down%s', self.__class__.__name__, | ||
| self._hupReceived and ' (reload requested)' or '') | ||
|
|
||
| return ret | ||
|
|
||
| if __name__ == '__main__': | ||
| def test_app(environ, start_response): | ||
| """Probably not the most efficient example.""" | ||
| import cgi | ||
| start_response('200 OK', [('Content-Type', 'text/html')]) | ||
| yield '<html><head><title>Hello World!</title></head>\n' \ | ||
| '<body>\n' \ | ||
| '<p>Hello World!</p>\n' \ | ||
| '<table border="1">' | ||
| names = environ.keys() | ||
| names.sort() | ||
| for name in names: | ||
| yield '<tr><td>%s</td><td>%s</td></tr>\n' % ( | ||
| name, cgi.escape(`environ[name]`)) | ||
|
|
||
| form = cgi.FieldStorage(fp=environ['wsgi.input'], environ=environ, | ||
| keep_blank_values=1) | ||
| if form.list: | ||
| yield '<tr><th colspan="2">Form data</th></tr>' | ||
|
|
||
| for field in form.list: | ||
| yield '<tr><td>%s</td><td>%s</td></tr>\n' % ( | ||
| field.name, field.value) | ||
|
|
||
| yield '</table>\n' \ | ||
| '</body></html>\n' | ||
|
|
||
| from wsgiref import validate | ||
| test_app = validate.validator(test_app) | ||
| # Explicitly set bindAddress to *:8009 for testing. | ||
| WSGIServer(test_app, | ||
| bindAddress=('', 8009), allowedServers=None, | ||
| loggingLevel=logging.DEBUG).run() |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,180 @@ | ||
| # Copyright (c) 2005 Allan Saddi <allan@saddi.com> | ||
| # 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 of 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. | ||
| # | ||
| # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND | ||
| # ANY EXPRESS 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 THE AUTHOR OR 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. | ||
| # | ||
| # $Id$ | ||
|
|
||
| __author__ = 'Allan Saddi <allan@saddi.com>' | ||
| __version__ = '$Revision$' | ||
|
|
||
| import sys | ||
| import socket | ||
| import select | ||
| import signal | ||
| import errno | ||
|
|
||
| try: | ||
| import fcntl | ||
| except ImportError: | ||
| def setCloseOnExec(sock): | ||
| pass | ||
| else: | ||
| def setCloseOnExec(sock): | ||
| fcntl.fcntl(sock.fileno(), fcntl.F_SETFD, fcntl.FD_CLOEXEC) | ||
|
|
||
| from flup.server.threadpool import ThreadPool | ||
|
|
||
| __all__ = ['ThreadedServer'] | ||
|
|
||
| class ThreadedServer(object): | ||
| def __init__(self, jobClass=None, jobArgs=(), **kw): | ||
| self._jobClass = jobClass | ||
| self._jobArgs = jobArgs | ||
|
|
||
| self._threadPool = ThreadPool(**kw) | ||
|
|
||
| def run(self, sock, timeout=1.0): | ||
| """ | ||
| The main loop. Pass a socket that is ready to accept() client | ||
| connections. Return value will be True or False indiciating whether | ||
| or not the loop was exited due to SIGHUP. | ||
| """ | ||
| # Set up signal handlers. | ||
| self._keepGoing = True | ||
| self._hupReceived = False | ||
|
|
||
| # Might need to revisit this? | ||
| if not sys.platform.startswith('win'): | ||
| self._installSignalHandlers() | ||
|
|
||
| # Set close-on-exec | ||
| setCloseOnExec(sock) | ||
|
|
||
| # Main loop. | ||
| while self._keepGoing: | ||
| try: | ||
| r, w, e = select.select([sock], [], [], timeout) | ||
| except select.error, e: | ||
| if e[0] == errno.EINTR: | ||
| continue | ||
| raise | ||
|
|
||
| if r: | ||
| try: | ||
| clientSock, addr = sock.accept() | ||
| except socket.error, e: | ||
| if e[0] in (errno.EINTR, errno.EAGAIN): | ||
| continue | ||
| raise | ||
|
|
||
| setCloseOnExec(clientSock) | ||
|
|
||
| if not self._isClientAllowed(addr): | ||
| clientSock.close() | ||
| continue | ||
|
|
||
| # Hand off to Connection. | ||
| conn = self._jobClass(clientSock, addr, *self._jobArgs) | ||
| if not self._threadPool.addJob(conn, allowQueuing=False): | ||
| # No thread left, immediately close the socket to hopefully | ||
| # indicate to the web server that we're at our limit... | ||
| # and to prevent having too many opened (and useless) | ||
| # files. | ||
| clientSock.close() | ||
|
|
||
| self._mainloopPeriodic() | ||
|
|
||
| # Restore signal handlers. | ||
| if not sys.platform.startswith('win'): | ||
| self._restoreSignalHandlers() | ||
|
|
||
| # Return bool based on whether or not SIGHUP was received. | ||
| return self._hupReceived | ||
|
|
||
| def shutdown(self): | ||
| """Wait for running threads to finish.""" | ||
| self._threadPool.shutdown() | ||
|
|
||
| def _mainloopPeriodic(self): | ||
| """ | ||
| Called with just about each iteration of the main loop. Meant to | ||
| be overridden. | ||
| """ | ||
| pass | ||
|
|
||
| def _exit(self, reload=False): | ||
| """ | ||
| Protected convenience method for subclasses to force an exit. Not | ||
| really thread-safe, which is why it isn't public. | ||
| """ | ||
| if self._keepGoing: | ||
| self._keepGoing = False | ||
| self._hupReceived = reload | ||
|
|
||
| def _isClientAllowed(self, addr): | ||
| """Override to provide access control.""" | ||
| return True | ||
|
|
||
| # Signal handlers | ||
|
|
||
| def _hupHandler(self, signum, frame): | ||
| self._hupReceived = True | ||
| self._keepGoing = False | ||
|
|
||
| def _intHandler(self, signum, frame): | ||
| self._keepGoing = False | ||
|
|
||
| def _installSignalHandlers(self): | ||
| supportedSignals = [signal.SIGINT, signal.SIGTERM] | ||
| if hasattr(signal, 'SIGHUP'): | ||
| supportedSignals.append(signal.SIGHUP) | ||
|
|
||
| self._oldSIGs = [(x,signal.getsignal(x)) for x in supportedSignals] | ||
|
|
||
| for sig in supportedSignals: | ||
| if hasattr(signal, 'SIGHUP') and sig == signal.SIGHUP: | ||
| signal.signal(sig, self._hupHandler) | ||
| else: | ||
| signal.signal(sig, self._intHandler) | ||
|
|
||
| def _restoreSignalHandlers(self): | ||
| for signum,handler in self._oldSIGs: | ||
| signal.signal(signum, handler) | ||
|
|
||
| if __name__ == '__main__': | ||
| class TestJob(object): | ||
| def __init__(self, sock, addr): | ||
| self._sock = sock | ||
| self._addr = addr | ||
| def run(self): | ||
| print "Client connection opened from %s:%d" % self._addr | ||
| self._sock.send('Hello World!\n') | ||
| self._sock.setblocking(1) | ||
| self._sock.recv(1) | ||
| self._sock.close() | ||
| print "Client connection closed from %s:%d" % self._addr | ||
| sock = socket.socket() | ||
| sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) | ||
| sock.bind(('', 8080)) | ||
| sock.listen(socket.SOMAXCONN) | ||
| ThreadedServer(maxThreads=10, jobClass=TestJob).run(sock) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,150 @@ | ||
| # Copyright (c) 2005 Allan Saddi <allan@saddi.com> | ||
| # 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 of 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. | ||
| # | ||
| # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND | ||
| # ANY EXPRESS 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 THE AUTHOR OR 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. | ||
| # | ||
| # $Id$ | ||
|
|
||
| __author__ = 'Allan Saddi <allan@saddi.com>' | ||
| __version__ = '$Revision$' | ||
|
|
||
| import sys | ||
| import thread | ||
| import threading | ||
|
|
||
| class ThreadPool(object): | ||
| """ | ||
| Thread pool that maintains the number of idle threads between | ||
| minSpare and maxSpare inclusive. By default, there is no limit on | ||
| the number of threads that can be started, but this can be controlled | ||
| by maxThreads. | ||
| """ | ||
| def __init__(self, minSpare=1, maxSpare=5, maxThreads=sys.maxint): | ||
| self._minSpare = minSpare | ||
| self._maxSpare = maxSpare | ||
| self._maxThreads = max(minSpare, maxThreads) | ||
|
|
||
| self._lock = threading.Condition() | ||
| self._workQueue = [] | ||
| self._idleCount = self._workerCount = maxSpare | ||
|
|
||
| self._threads = [] | ||
| self._stop = False | ||
|
|
||
| # Start the minimum number of worker threads. | ||
| for i in range(maxSpare): | ||
| self._start_new_thread() | ||
|
|
||
| def _start_new_thread(self): | ||
| t = threading.Thread(target=self._worker) | ||
| self._threads.append(t) | ||
| t.setDaemon(True) | ||
| t.start() | ||
| return t | ||
|
|
||
| def shutdown(self): | ||
| """shutdown all workers.""" | ||
| self._lock.acquire() | ||
| self._stop = True | ||
| self._lock.notifyAll() | ||
| self._lock.release() | ||
|
|
||
| # wait for all threads to finish | ||
| for t in self._threads[:]: | ||
| t.join() | ||
|
|
||
| def addJob(self, job, allowQueuing=True): | ||
| """ | ||
| Adds a job to the work queue. The job object should have a run() | ||
| method. If allowQueuing is True (the default), the job will be | ||
| added to the work queue regardless if there are any idle threads | ||
| ready. (The only way for there to be no idle threads is if maxThreads | ||
| is some reasonable, finite limit.) | ||
| Otherwise, if allowQueuing is False, and there are no more idle | ||
| threads, the job will not be queued. | ||
| Returns True if the job was queued, False otherwise. | ||
| """ | ||
| self._lock.acquire() | ||
| try: | ||
| # Maintain minimum number of spares. | ||
| while self._idleCount < self._minSpare and \ | ||
| self._workerCount < self._maxThreads: | ||
| try: | ||
| self._start_new_thread() | ||
| except thread.error: | ||
| return False | ||
| self._workerCount += 1 | ||
| self._idleCount += 1 | ||
|
|
||
| # Hand off the job. | ||
| if self._idleCount or allowQueuing: | ||
| self._workQueue.append(job) | ||
| self._lock.notify() | ||
| return True | ||
| else: | ||
| return False | ||
| finally: | ||
| self._lock.release() | ||
|
|
||
| def _worker(self): | ||
| """ | ||
| Worker thread routine. Waits for a job, executes it, repeat. | ||
| """ | ||
| self._lock.acquire() | ||
| try: | ||
| while True: | ||
| while not self._workQueue and not self._stop: | ||
| self._lock.wait() | ||
|
|
||
| if self._stop: | ||
| return | ||
|
|
||
| # We have a job to do... | ||
| job = self._workQueue.pop(0) | ||
|
|
||
| assert self._idleCount > 0 | ||
| self._idleCount -= 1 | ||
|
|
||
| self._lock.release() | ||
|
|
||
| try: | ||
| job.run() | ||
| except: | ||
| # FIXME: This should really be reported somewhere. | ||
| # But we can't simply report it to stderr because of fcgi | ||
| pass | ||
|
|
||
| self._lock.acquire() | ||
|
|
||
| if self._idleCount == self._maxSpare: | ||
| break # NB: lock still held | ||
| self._idleCount += 1 | ||
| assert self._idleCount <= self._maxSpare | ||
|
|
||
| # Die off... | ||
| assert self._workerCount > self._maxSpare | ||
| self._threads.remove(threading.currentThread()) | ||
| self._workerCount -= 1 | ||
| finally: | ||
| self._lock.release() |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,54 @@ | ||
| #!/usr/bin/env python | ||
| """ | ||
| ################################################################################ | ||
| # 2013-09-01 Larry Shaffer <larrys@dakotacarto.com> | ||
| # | ||
| # NOTE: THIS IS ONLY A DEVELOPMENT TESTING SCRIPT. TO BE REMOVED AT LATER DATE. | ||
| ################################################################################ | ||
| <description> | ||
| This file is part of ZTC and distributed under the same license. | ||
| http://bitbucket.org/rvs/ztc/ | ||
| Copyright (c) 2011 Vladimir Rusinov <vladimir@greenmice.info> | ||
| """ | ||
|
|
||
| import flup_fcgi_client as fcgi_client | ||
| # from flup.client.fcgi_app import FCGIApp as fcgi_client | ||
|
|
||
| def load_page(fcgi_host,fcgi_port, script, query): | ||
| """ load fastcgi page """ | ||
| try: | ||
| fcgi = fcgi_client.FCGIApp(host = fcgi_host, | ||
| port = fcgi_port) | ||
| env = { | ||
| 'SCRIPT_FILENAME': script, | ||
| 'QUERY_STRING': query, | ||
| 'REQUEST_METHOD': 'GET', | ||
| 'SCRIPT_NAME': script, | ||
| 'REQUEST_URI': script + '?' + query, | ||
| 'GATEWAY_INTERFACE': 'CGI/1.1', | ||
| 'SERVER_SOFTWARE': '', | ||
| 'REDIRECT_STATUS': '200', | ||
| 'CONTENT_TYPE': '', | ||
| 'CONTENT_LENGTH': '0', | ||
| 'DOCUMENT_ROOT': '/qgisserver/', | ||
| 'SERVER_ADDR': fcgi_host, | ||
| 'SERVER_PORT': str(fcgi_port), | ||
| 'SERVER_PROTOCOL': 'HTTP/1.0', | ||
| 'SERVER_NAME': fcgi_host | ||
| } | ||
| ret = fcgi(env) | ||
| return ret | ||
| except: | ||
| print 'fastcgi load failed' | ||
| return '500', [], '', '' | ||
|
|
||
|
|
||
| if __name__ == "__main__": | ||
| fcgi_host = '127.0.0.1' | ||
| fcgi_port = '8448' | ||
| script = 'qgis_mapserv.fcgi' | ||
| query = 'SERVICE=WMS&VERSION=1.3.0&REQUEST=GetCapabilities&MAP=/test-projects/tests/pal_test.qgs' | ||
| print load_page(fcgi_host,fcgi_port, script, query)[2] |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| jan kneschke <jan@kneschke.de> | ||
| stefan bühler <lighttpd@stbuehler.de> |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| CMAKE_MINIMUM_REQUIRED(VERSION 2.6.0 FATAL_ERROR) | ||
|
|
||
| cmake_policy(VERSION 2.6.0) | ||
|
|
||
| PROJECT(spawn-fcgi) | ||
| SET(PACKAGE_NAME ${CMAKE_PROJECT_NAME}) | ||
| SET(PACKAGE_VERSION 1.6.4) | ||
|
|
||
| SET(CMAKE_MAN_DIR "share/man" CACHE STRING | ||
| "Install location for man pages (relative to prefix).") | ||
| MARK_AS_ADVANCED(CMAKE_MAN_DIR) | ||
|
|
||
| # Set Default build type to RelWithDebInfo | ||
| IF("${CMAKE_BUILD_TYPE}" STREQUAL "") | ||
| SET(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING "Choose the type of build, options are: None(CMAKE_CXX_FLAGS or CMAKE_C_FLAGS used) Debug Release RelWithDebInfo MinSizeRel." FORCE) | ||
| ENDIF("${CMAKE_BUILD_TYPE}" STREQUAL "") | ||
|
|
||
| ADD_SUBDIRECTORY(src) | ||
|
|
||
| INSTALL(FILES spawn-fcgi.1 DESTINATION ${CMAKE_MAN_DIR}/man1) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,31 @@ | ||
|
|
||
|
|
||
| Copyright (c) 2004, Jan Kneschke, incremental | ||
| All rights reserved. | ||
|
|
||
| Redistribution and use in source and binary forms, with or without | ||
| modification, are permitted provided that the following conditions are met: | ||
|
|
||
| - Redistributions of source code must retain the above copyright notice, this | ||
| list of conditions and the following disclaimer. | ||
|
|
||
| - 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. | ||
|
|
||
| - Neither the name of the 'incremental' nor the names of its contributors may | ||
| be used to endorse or promote products derived from this software without | ||
| specific prior written permission. | ||
|
|
||
| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||
| AND ANY EXPRESS 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 THE COPYRIGHT OWNER OR 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. | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| SUBDIRS=src doc | ||
|
|
||
| EXTRA_DIST=autogen.sh spawn-fcgi.1 CMakeLists.txt | ||
| man1_MANS=spawn-fcgi.1 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,44 @@ | ||
|
|
||
| ==== | ||
| NEWS | ||
| ==== | ||
|
|
||
| - 1.6.4 - | ||
| * Use octal mode for -M (patch by dfjoerg) | ||
| * Add -b backlog option (fixes #2422, patch by aschmitz) | ||
|
|
||
| - 1.6.3 - 2009-09-23 | ||
| * Fix unix socket mode change to work without specifying user/group for socket | ||
| * Add some ./run script examples for use with daemontools or runit | ||
| * Fix Invalid Argument in chmod if mode=-1 (fixes #2033) | ||
| * Add deprecated and /bin/sh info for -f option; wrap syntax output (fixes #2044) | ||
| * Add run script examples in automake dist build | ||
|
|
||
| - 1.6.2 - 2009-04-18 | ||
| * Add homepage to README | ||
| * Add IPv6 support | ||
| * Fix problems with usernames starting with a digit and non-existent uids; add warning if only user privs are dropped. (fixes #1959) | ||
| * Add check to link against socket/nsl if needed (fixes #1960) | ||
| * List IPv6 as feature after the version if it is supported | ||
|
|
||
| - 1.6.1 - 2009-03-29 | ||
|
|
||
| * Add build date to show-version | ||
| * Added options to chown/chmod the socket and to create the socket before chroot() (fixes #1906) | ||
| * Updated man page | ||
| * Add proper SUID bit detection | ||
| * Added option to change the directory before spawning (fixes #1847) | ||
|
|
||
| - 1.6.0 - 2009-02-28 | ||
|
|
||
| * Separated spawn-fcgi from lighttpd | ||
| * Remove limits for php children; per default the PHP_FCGI_CHILDREN var is not changed (php defaults to no children, one worker) | ||
| * Modified the log messages format (more details on errors, no source line) | ||
| * Only try to connect to unix socket (not tcp) before spawning (fixes again #1575) | ||
| * Only disconnect from terminal in fork mode (keep stderr/stdout open in nofork mode) | ||
| * Allow numerical user and group ids for -u/-g (fixes #1141) | ||
| * Ignore pid-file option in no-fork mode (instead of producing empty file) | ||
| * Fix error handling for unix-socket-connect test | ||
| * Man page update | ||
| * Use header include order from 1.4.x | ||
| * Fix segfault due to uninitialized var |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,41 @@ | ||
|
|
||
| ========== | ||
| spawn-fcgi | ||
| ========== | ||
|
|
||
| :authors: Jan Kneschke, Stefan Bühler | ||
|
|
||
| :homepage: | ||
| http://redmine.lighttpd.net/projects/spawn-fcgi | ||
|
|
||
| :abstract: | ||
| spawn-fcgi is used to spawn FastCGI applications | ||
|
|
||
| Features | ||
| -------- | ||
| - binds to IPv4/IPv6 and Unix domain sockets | ||
| - supports privilege separation: chmod/chown socket, drop to uid/gid | ||
| - supports chroot | ||
| - supports daemontools supervise | ||
|
|
||
| Build | ||
| ===== | ||
|
|
||
| If ./configure is missing, run ./autogen.sh. | ||
|
|
||
| ./configure | ||
| make | ||
| make install | ||
|
|
||
| Alternatively you can use the cmake build system (may not work | ||
| on every platform): | ||
|
|
||
| cmake . | ||
| make | ||
| make install | ||
|
|
||
|
|
||
| Usage | ||
| ===== | ||
|
|
||
| See man page. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,24 @@ | ||
| #!/bin/sh | ||
| # Run this to generate all the initial makefiles, etc. | ||
|
|
||
| ACLOCAL=${ACLOCAL:-aclocal} | ||
| AUTOHEADER=${AUTOHEADER:-autoheader} | ||
| AUTOMAKE=${AUTOMAKE:-automake} | ||
| AUTOMAKE_FLAGS="--add-missing --copy" | ||
| AUTOCONF=${AUTOCONF:-autoconf} | ||
|
|
||
| ARGV0=$0 | ||
|
|
||
| set -e | ||
|
|
||
|
|
||
| run() { | ||
| echo "$ARGV0: running \`$@'" | ||
| $@ | ||
| } | ||
|
|
||
| run $ACLOCAL $ACLOCAL_FLAGS | ||
| run $AUTOHEADER | ||
| run $AUTOMAKE $AUTOMAKE_FLAGS | ||
| run $AUTOCONF | ||
| echo "Now type './configure ...' and 'make' to compile." |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,88 @@ | ||
| # -*- Autoconf -*- | ||
| # Process this file with autoconf to produce a configure script. | ||
|
|
||
| AC_PREREQ(2.61) | ||
| AC_INIT([spawn-fcgi],[1.6.4]) | ||
| AC_CONFIG_SRCDIR([src/spawn-fcgi.c]) | ||
| AC_CONFIG_HEADER([config.h]) | ||
|
|
||
| AM_INIT_AUTOMAKE([-Wall -Werror foreign]) | ||
|
|
||
| # Checks for programs. | ||
| AC_PROG_CC | ||
| AC_PROG_MAKE_SET | ||
|
|
||
| # Checks for libraries. | ||
|
|
||
| # Checks for header files. | ||
| AC_HEADER_STDC | ||
| AC_HEADER_SYS_WAIT | ||
| AC_CHECK_HEADERS([arpa/inet.h errno.h fcntl.h getopt.h grp.h netdb.h \ | ||
| netinet/in.h netinet/tcp.h pwd.h stdio.h stdlib.h \ | ||
| string.h sys/ioctl.h sys/socket.h sys/stat.h sys/time.h \ | ||
| sys/types.h sys/un.h sys/wait.h unistd.h]) | ||
|
|
||
|
|
||
| # Checks for typedefs, structures, and compiler characteristics. | ||
| AC_C_CONST | ||
| AC_TYPE_UID_T | ||
| AC_TYPE_PID_T | ||
| AC_HEADER_TIME | ||
| AC_CHECK_TYPES(socklen_t,,,[#include <sys/types.h> | ||
| #include <sys/socket.h>]) | ||
|
|
||
| ## solaris needs -lsocket -lnsl | ||
| AC_SEARCH_LIBS([socket],[socket]) | ||
| AC_SEARCH_LIBS([inet_addr],[nsl socket]) | ||
|
|
||
| # Checks for library functions. | ||
| AC_FUNC_CHOWN | ||
| AC_FUNC_FORK | ||
| AC_FUNC_MALLOC | ||
| AC_FUNC_SELECT_ARGTYPES | ||
| AC_FUNC_STAT | ||
| AC_CHECK_FUNCS([dup2 memset putenv select socket strerror strtol issetugid inet_pton]) | ||
|
|
||
|
|
||
| # Check for IPv6 support | ||
|
|
||
| AC_ARG_ENABLE(ipv6, | ||
| AC_HELP_STRING([--disable-ipv6],[disable IPv6 support]), | ||
| [case "${enableval}" in | ||
| yes) ipv6=true ;; | ||
| no) ipv6=false ;; | ||
| *) AC_MSG_ERROR(bad value ${enableval} for --enable-ipv6) ;; | ||
| esac],[ipv6=true]) | ||
|
|
||
| if test x$ipv6 = xtrue; then | ||
| AC_CACHE_CHECK([for IPv6 support], ac_cv_ipv6_support, | ||
| [AC_TRY_LINK([ #include <sys/types.h> | ||
| #include <sys/socket.h> | ||
| #include <netinet/in.h>], [struct sockaddr_in6 s; struct in6_addr t=in6addr_any; int i=AF_INET6; s; t.s6_addr[0] = 0; ], | ||
| [ac_cv_ipv6_support=yes], [ac_cv_ipv6_support=no])]) | ||
|
|
||
| if test "$ac_cv_ipv6_support" = yes; then | ||
| AC_DEFINE(HAVE_IPV6,1,[Whether to enable IPv6 support]) | ||
| fi | ||
| fi | ||
|
|
||
|
|
||
| # check for extra compiler options (warning options) | ||
| if test "${GCC}" = "yes"; then | ||
| CFLAGS="${CFLAGS} -Wall -W -Wshadow -pedantic -std=gnu99" | ||
| fi | ||
|
|
||
| AC_ARG_ENABLE(extra-warnings, | ||
| AC_HELP_STRING([--enable-extra-warnings],[enable extra warnings (gcc specific)]), | ||
| [case "${enableval}" in | ||
| yes) extrawarnings=true ;; | ||
| no) extrawarnings=false ;; | ||
| *) AC_MSG_ERROR(bad value ${enableval} for --enable-extra-warnings) ;; | ||
| esac],[extrawarnings=false]) | ||
|
|
||
| if test x$extrawarnings = xtrue; then | ||
| CFLAGS="${CFLAGS} -g -O2 -g2 -Wall -Wmissing-declarations -Wdeclaration-after-statement -Wcast-align -Winline -Wsign-compare -Wnested-externs -Wpointer-arith -Wl,--as-needed -Wformat-security" | ||
| fi | ||
|
|
||
| AC_CONFIG_FILES([Makefile src/Makefile doc/Makefile]) | ||
| AC_OUTPUT |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| EXTRA_DIST=run-generic run-php run-rails |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,49 @@ | ||
| #!/bin/bash | ||
| # Use this as a run script with daemontools or runit | ||
|
|
||
| ## ABSOLUTE path to the spawn-fcgi binary | ||
| SPAWNFCGI="/usr/bin/spawn-fcgi" | ||
|
|
||
| ## ABSOLUTE path to the FastCGI application (php-cgi, dispatch.fcgi, ...) | ||
| FCGIPROGRAM="/usr/bin/php5-cgi" | ||
|
|
||
| ## bind to unix socket | ||
| FCGISOCKET="/var/run/lighttpd/your-fcgi-app.sock" | ||
|
|
||
| # allowed environment variables separated by spaces | ||
| ALLOWED_ENV="PATH USER" | ||
|
|
||
| ## if this script is run as root switch to the following user | ||
| USERID=xxx | ||
| SOCKUSERID=www-data | ||
| #CHROOT=/home/www/ | ||
|
|
||
| #RAILS_ENV="production" | ||
| #export RAILS_ENV | ||
|
|
||
|
|
||
| ################## no config below this line | ||
|
|
||
| exec 2>&1 | ||
|
|
||
| if test x$PHP_FCGI_CHILDREN = x; then | ||
| PHP_FCGI_CHILDREN=4 | ||
| fi | ||
|
|
||
| ALLOWED_ENV="$ALLOWED_ENV RAILS_ENV" | ||
|
|
||
| if test x$UID = x0; then | ||
| EX="$SPAWNFCGI -n -s $FCGISOCKET -u $USERID -U $SOCKUSERID -C $PHP_FCGI_CHILDREN -- $FCGIPROGRAM" | ||
| else | ||
| EX="$SPAWNFCGI -n -s $FCGISOCKET -C $PHP_FCGI_CHILDREN -- $FCGIPROGRAM" | ||
| fi | ||
|
|
||
| # copy the allowed environment variables | ||
| E= | ||
|
|
||
| for i in $ALLOWED_ENV; do | ||
| E="$E $i=${!i}" | ||
| done | ||
|
|
||
| # clean environment and set up a new one | ||
| exec env - $E $EX |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| #!/bin/sh | ||
| # Use this as a ./run script with daemontools or runit | ||
| # You should replace xxx with the user you want php to run as (and www-data with the user lighty runs as) | ||
|
|
||
| exec 2>&1 | ||
| PHP_FCGI_CHILDREN=2 \ | ||
| PHP_FCGI_MAX_REQUESTS=1000 \ | ||
| exec /usr/bin/spawn-fcgi -n -s /var/run/lighttpd/php-xxx.sock -n -u xxx -U www-data -- /usr/bin/php5-cgi |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| #!/bin/sh | ||
| # Use this as a ./run script with daemontools or runit | ||
| # You should replace xxx with the user you want rails to run as (and www-data with the user lighty runs as) | ||
| # /path-to-rails should be replaced with the correct path too :) | ||
|
|
||
| exec 2>&1 | ||
| RAILS_ENV="production" \ | ||
| exec /usr/bin/spawn-fcgi -n -s /var/run/lighttpd/rails-xxx.sock -u xxx -U www-data -- /path-to-rails/public/dispatch.fcgi |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,122 @@ | ||
| .TH spawn-fcgi 1 "21 November 2012" | ||
| . | ||
| .SH NAME | ||
| . | ||
| spawn-fcgi \- Spawns FastCGI processes | ||
| . | ||
| .SH SYNOPSIS | ||
| . | ||
| .B spawn-fcgi | ||
| [options] [ -- <fcgiapp> [fcgi app arguments]] | ||
| .P | ||
| .B spawn-fcgi | ||
| \-v | ||
| .P | ||
| .B spawn-fcgi | ||
| \-h | ||
| . | ||
| .SH DESCRIPTION | ||
| . | ||
| \fIspawn-fcgi\fP is used to spawn remote and local FastCGI processes. | ||
| .P | ||
| While it is obviously needed to spawn remote FastCGI backends (the web server | ||
| can only spawn local ones), it is recommended to spawn local backends | ||
| with spawn-fcgi, too. | ||
| .P | ||
| Reasons why you may want to use spawn-fcgi instead of something else: | ||
| .IP * 3 | ||
| Privilege separation without needing a suid-binary or running a server as root. | ||
| .IP * 3 | ||
| You can restart your web server and the FastCGI applications without restarting the others. | ||
| .IP * 3 | ||
| You can run them in different chroot()s. | ||
| .IP * 3 | ||
| Running your FastCGI applications doesn't depend on the web server you are running, | ||
| which allows for easier testing of other web servers. | ||
| . | ||
| .SH OPTIONS | ||
| . | ||
| \fIspawn-fcgi\fP accepts the following options: | ||
| .TP 8 | ||
| .B \-f <path> | ||
| Filename of the FastCGI application to spawn. This option is deprecated and it | ||
| is recommend to always specify the application (absolute path) and its parameters after "--"; | ||
| the fcgiapp parameter is directly used for the exec() call, while for starting the binary given | ||
| with \-f /bin/sh is needed (which may not be available in a chroot). | ||
| .IP | ||
| This option is ignored if fcgiapp is given. | ||
| .TP 8 | ||
| .B \-d <path> | ||
| Change the current directory before spawning the application. | ||
| .TP 8 | ||
| .B \-a <address> | ||
| IPv4/IPv6 address to bind to; only used if \-p is given too. Defaults to "0.0.0.0" (IPv4). | ||
| .TP 8 | ||
| .B \-p <port> | ||
| TCP port to bind to; you cannot combine this with the \-s option. | ||
| .TP 8 | ||
| .B \-s <path> | ||
| Path to the Unix domain socket to bind to; you cannot combine this with the \-p option. | ||
| .TP 8 | ||
| .B \-C <children> | ||
| (PHP only) Number of children to spawn by setting the PHP_FCGI_CHILDREN | ||
| environment variable. Default is not to overwrite the environment variable; | ||
| php will spawn no children if the variable is not set (same as setting it to 0). | ||
| .TP 8 | ||
| .B \-F <children> | ||
| Number of children to fork, defaults to 1. This option doesn't work with \-n, | ||
| have a look at | ||
| .BR multiwatch(1) | ||
| if you want to supervise multiple forks on the same socket. | ||
| .TP 8 | ||
| .B \-b <backlog> | ||
| backlog to allow on the socket (default 1024). This is usually limited by the kernel too, | ||
| check sysctl net.core.somaxconn (default 128) for linux. | ||
| .IP | ||
| backlog is the queue of connections that the kernel accepts before the userspace application sees them. | ||
| .TP 8 | ||
| .B \-P <path> | ||
| Name of the PID file for spawned processes (ignored in no-fork mode) | ||
| .TP 8 | ||
| .B \-n | ||
| No forking should take place (for daemontools) | ||
| .TP 8 | ||
| .B \-M <mode> | ||
| Change file mode of the Unix domain socket; only used if \-s is given too. | ||
| .TP 8 | ||
| .B \-?, \-h | ||
| General usage instructions | ||
| .TP 8 | ||
| .B \-v | ||
| Shows version information and exits | ||
| .P | ||
| . | ||
| The following options are only available if you invoke spawn-fcgi as root: | ||
| .TP 8 | ||
| .B \-c <directory> | ||
| Chroot to specified directory; the Unix domain socket is created inside the chroot unless \-S is given. | ||
| .TP 8 | ||
| .B \-S | ||
| Create Unix domain socket before chroot(). | ||
| .TP 8 | ||
| .B \-u | ||
| User ID to change to. | ||
| .TP 8 | ||
| .B \-g | ||
| Group ID to change to. Defaults to primary group of the user given for \-u. | ||
| .TP 8 | ||
| .B \-U | ||
| Change user of the Unix domain socket, defaults to the value of \-u. (only used if \-s is given) | ||
| .TP 8 | ||
| .B \-G | ||
| Change group of the Unix domain socket, defaults to the primary group of the user given for \-U; | ||
| if \-U wasn't given, defaults to the value of \-g. (only used if \-s is given) | ||
| . | ||
| .SH "SEE ALSO" | ||
| . | ||
| .BR svc(8), | ||
| .BR supervise(8), | ||
| see http://cr.yp.to/daemontools.html | ||
| .P | ||
| .BR multiwatch(1), | ||
| see http://cgit.stbuehler.de/gitosis/multiwatch/about/ |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,72 @@ | ||
| INCLUDE(CheckCSourceCompiles) | ||
| INCLUDE(CheckIncludeFiles) | ||
| INCLUDE(CheckFunctionExists) | ||
| INCLUDE(CheckVariableExists) | ||
| INCLUDE(CheckTypeSize) | ||
| INCLUDE(CMakeDetermineCCompiler) | ||
|
|
||
| IF(CMAKE_COMPILER_IS_GNUCC) | ||
| OPTION(BUILD_EXTRA_WARNINGS "extra warnings") | ||
|
|
||
| IF(BUILD_EXTRA_WARNINGS) | ||
| SET(WARN_FLAGS "-g -O2 -g2 -Wall -Wmissing-declarations -Wdeclaration-after-statement -Wcast-align -Winline -Wsign-compare -Wnested-externs -Wpointer-arith -Wl,--as-needed -Wformat-security") | ||
| # -Wno-pointer-sign -Werror -Wbad-function-cast -Wmissing-prototypes | ||
| ELSE(BUILD_EXTRA_WARNINGS) | ||
| SET(WARN_FLAGS "") | ||
| ENDIF(BUILD_EXTRA_WARNINGS) | ||
| ENDIF(CMAKE_COMPILER_IS_GNUCC) | ||
|
|
||
| # awk '/#include <(.*)>/ { h = substr($2,2,length($2)-2); h2=toupper(h); gsub("\\.|\\/", "_", h2); printf "%s%s%s%s%s", "CHECK_INCLUDE_FILES(", h, " HAVE_", h2, ")\n" }' spawn-fcgi.c | sort | ||
| CHECK_INCLUDE_FILES(arpa/inet.h HAVE_ARPA_INET_H) | ||
| CHECK_INCLUDE_FILES(errno.h HAVE_ERRNO_H) | ||
| CHECK_INCLUDE_FILES(fcntl.h HAVE_FCNTL_H) | ||
| CHECK_INCLUDE_FILES(getopt.h HAVE_GETOPT_H) | ||
| CHECK_INCLUDE_FILES(grp.h HAVE_GRP_H) | ||
| CHECK_INCLUDE_FILES(netdb.h HAVE_NETDB_H) | ||
| CHECK_INCLUDE_FILES(netinet/in.h HAVE_NETINET_IN_H) | ||
| CHECK_INCLUDE_FILES(netinet/tcp.h HAVE_NETINET_TCP_H) | ||
| CHECK_INCLUDE_FILES(pwd.h HAVE_PWD_H) | ||
| CHECK_INCLUDE_FILES(stdio.h HAVE_STDIO_H) | ||
| CHECK_INCLUDE_FILES(stdlib.h HAVE_STDLIB_H) | ||
| CHECK_INCLUDE_FILES(string.h HAVE_STRING_H) | ||
| CHECK_INCLUDE_FILES(sys/ioctl.h HAVE_SYS_IOCTL_H) | ||
| CHECK_INCLUDE_FILES(sys/socket.h HAVE_SYS_SOCKET_H) | ||
| CHECK_INCLUDE_FILES(sys/stat.h HAVE_SYS_STAT_H) | ||
| CHECK_INCLUDE_FILES(sys/time.h HAVE_SYS_TIME_H) | ||
| CHECK_INCLUDE_FILES(sys/types.h HAVE_SYS_TYPES_H) | ||
| CHECK_INCLUDE_FILES(sys/un.h HAVE_SYS_UN_H) | ||
| CHECK_INCLUDE_FILES(sys/wait.h HAVE_SYS_WAIT_H) | ||
| CHECK_INCLUDE_FILES(unistd.h HAVE_UNISTD_H) | ||
| CHECK_INCLUDE_FILES(winsock2.h HAVE_WINSOCK2_H) | ||
|
|
||
| CHECK_FUNCTION_EXISTS(issetugid HAVE_ISSETUGID) | ||
| CHECK_FUNCTION_EXISTS(inet_pton HAVE_INET_PTON) | ||
|
|
||
| CHECK_C_SOURCE_COMPILES(" | ||
| #include <sys/types.h> | ||
| #include <sys/socket.h> | ||
| #include <netinet/in.h> | ||
| int main() { | ||
| struct sockaddr_in6 s; struct in6_addr t=in6addr_any; int i=AF_INET6; s; t.s6_addr[0] = 0; | ||
| return 0; | ||
| }" HAVE_IPV6) | ||
|
|
||
| SET(CMAKE_EXTRA_INCLUDE_FILES sys/socket.h) | ||
| CHECK_TYPE_SIZE(socklen_t HAVE_SOCKLEN_T) | ||
| SET(CMAKE_EXTRA_INCLUDE_FILES) | ||
|
|
||
| ## Write out config.h | ||
| CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config.h) | ||
|
|
||
| ADD_DEFINITIONS(-DHAVE_CONFIG_H) | ||
|
|
||
| INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}) | ||
|
|
||
| ADD_EXECUTABLE(spawn-fcgi spawn-fcgi.c) | ||
|
|
||
| IF(CMAKE_COMPILER_IS_GNUCC) | ||
| SET_TARGET_PROPERTIES(spawn-fcgi PROPERTIES COMPILE_FLAGS "-std=gnu99 -Wall -g -Wshadow -W -pedantic -fPIC -D_GNU_SOURCE ${WARN_FLAGS}") | ||
| ENDIF(CMAKE_COMPILER_IS_GNUCC) | ||
|
|
||
| INSTALL(TARGETS spawn-fcgi DESTINATION bin) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
|
|
||
| bin_PROGRAMS=spawn-fcgi | ||
| spawn_fcgi_SOURCES=spawn-fcgi.c | ||
|
|
||
| EXTRA_DIST=CMakeLists.txt config.h.cmake |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,37 @@ | ||
|
|
||
| /* generated by cmake, do not modify. modify config.h.cmake instead */ | ||
|
|
||
| /* Package data */ | ||
|
|
||
| #define PACKAGE_NAME "${PACKAGE_NAME}" | ||
| #define PACKAGE_VERSION "${PACKAGE_VERSION}" | ||
|
|
||
| /* grep HAVE_ CMakeLists.txt | sed -e 's/.*\(HAVE_[A-Z_]*\).*/#cmakedefine \1/' */ | ||
|
|
||
| #cmakedefine HAVE_ARPA_INET_H | ||
| #cmakedefine HAVE_ERRNO_H | ||
| #cmakedefine HAVE_FCNTL_H | ||
| #cmakedefine HAVE_GETOPT_H | ||
| #cmakedefine HAVE_GRP_H | ||
| #cmakedefine HAVE_NETDB_H | ||
| #cmakedefine HAVE_NETINET_IN_H | ||
| #cmakedefine HAVE_NETINET_TCP_H | ||
| #cmakedefine HAVE_PWD_H | ||
| #cmakedefine HAVE_STDIO_H | ||
| #cmakedefine HAVE_STDLIB_H | ||
| #cmakedefine HAVE_STRING_H | ||
| #cmakedefine HAVE_SYS_IOCTL_H | ||
| #cmakedefine HAVE_SYS_SOCKET_H | ||
| #cmakedefine HAVE_SYS_STAT_H | ||
| #cmakedefine HAVE_SYS_TIME_H | ||
| #cmakedefine HAVE_SYS_TYPES_H | ||
| #cmakedefine HAVE_SYS_UN_H | ||
| #cmakedefine HAVE_SYS_WAIT_H | ||
| #cmakedefine HAVE_UNISTD_H | ||
| #cmakedefine HAVE_WINSOCK | ||
| #cmakedefine HAVE_SOCKLEN_T | ||
|
|
||
| #cmakedefine HAVE_ISSETUGID | ||
| #cmakedefine HAVE_INET_PTON | ||
|
|
||
| #cmakedefine HAVE_IPV6 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| #!/bin/bash | ||
|
|
||
| ################################################################################ | ||
| # 2013-09-01 Larry Shaffer <larrys@dakotacarto.com> | ||
| # | ||
| # NOTE: THIS IS ONLY A DEVELOPMENT TESTING SCRIPT. TO BE REMOVED AT LATER DATE. | ||
| ################################################################################ | ||
|
|
||
| /usr/local/bin/spawn-fcgi -p 8448 -u $UID -- /qgisserver/qgis_mapserv.fcgi | ||
|
|
||
|
|