From 27f9fe52bc3c0845a545c9caa5d69d1b0b8d24f5 Mon Sep 17 00:00:00 2001 From: Allan Saddi Date: Sat, 25 Nov 2006 02:00:02 +0000 Subject: Experimental support for SCGI over UNIX domain sockets. --- flup/client/scgi_app.py | 5 ++++- flup/server/scgi.py | 20 ++++++++++++++------ flup/server/scgi_base.py | 48 +++++++++++++++++++++++++++++++++++++++--------- flup/server/scgi_fork.py | 20 ++++++++++++++------ 4 files changed, 71 insertions(+), 22 deletions(-) diff --git a/flup/client/scgi_app.py b/flup/client/scgi_app.py index dc08743..c26cd58 100644 --- a/flup/client/scgi_app.py +++ b/flup/client/scgi_app.py @@ -136,7 +136,10 @@ class SCGIApp(object): return [result] def _getConnection(self): - sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + if type(self._connect) is str: + sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) + else: + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect(self._connect) return sock diff --git a/flup/server/scgi.py b/flup/server/scgi.py index 10b0226..d966798 100644 --- a/flup/server/scgi.py +++ b/flup/server/scgi.py @@ -89,7 +89,8 @@ class WSGIServer(BaseSCGIServer, ThreadedServer): """ def __init__(self, application, scriptName='', environ=None, multithreaded=True, multiprocess=False, - bindAddress=('localhost', 4000), allowedServers=None, + bindAddress=('localhost', 4000), umask=None, + allowedServers=None, loggingLevel=logging.INFO, debug=True, **kw): """ scriptName is the initial portion of the URL path that "belongs" @@ -100,11 +101,17 @@ class WSGIServer(BaseSCGIServer, ThreadedServer): 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. - + bindAddress is the address to bind to, which must be a string or + a tuple of length 2. If a tuple, the first element must be a string, + which is the host name or IPv4 address of a local interface. The + 2nd element of the tuple is the port number. If a string, it will + be interpreted as a filename and a UNIX socket will be opened. + + If binding to a UNIX socket, umask may be set to specify what + the umask is to be changed to before the socket is created in the + filesystem. After the socket is created, the previous umask is + restored. + allowedServers must be None or a list of strings representing the IPv4 addresses of servers allowed to connect. None means accept connections from anywhere. @@ -117,6 +124,7 @@ class WSGIServer(BaseSCGIServer, ThreadedServer): multithreaded=multithreaded, multiprocess=multiprocess, bindAddress=bindAddress, + umask=umask, allowedServers=allowedServers, loggingLevel=loggingLevel, debug=debug) diff --git a/flup/server/scgi_base.py b/flup/server/scgi_base.py index b57b401..d874e07 100644 --- a/flup/server/scgi_base.py +++ b/flup/server/scgi_base.py @@ -35,6 +35,7 @@ import errno import cStringIO as StringIO import signal import datetime +import os # Threads are required. If you want a non-threaded (forking) version, look at # SWAP . @@ -272,7 +273,8 @@ class BaseSCGIServer(object): def __init__(self, application, scriptName='', environ=None, multithreaded=True, multiprocess=False, - bindAddress=('localhost', 4000), allowedServers=NoDefault, + bindAddress=('localhost', 4000), umask=None, + allowedServers=NoDefault, loggingLevel=logging.INFO, debug=True): """ scriptName is the initial portion of the URL path that "belongs" @@ -288,11 +290,17 @@ class BaseSCGIServer(object): Set multiprocess to True to explicitly set wsgi.multiprocess to True. (Only makes sense with threaded servers.) - 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. - + bindAddress is the address to bind to, which must be a string or + a tuple of length 2. If a tuple, the first element must be a string, + which is the host name or IPv4 address of a local interface. The + 2nd element of the tuple is the port number. If a string, it will + be interpreted as a filename and a UNIX socket will be opened. + + If binding to a UNIX socket, umask may be set to specify what + the umask is to be changed to before the socket is created in the + filesystem. After the socket is created, the previous umask is + restored. + allowedServers must be None or a list of strings representing the IPv4 addresses of servers allowed to connect. None means accept connections from anywhere. By default, it is a list containing @@ -310,6 +318,7 @@ class BaseSCGIServer(object): self.multiprocess = multiprocess self.debug = debug self._bindAddress = bindAddress + self._umask = umask if allowedServers is NoDefault: allowedServers = ['127.0.0.1'] self._allowedServers = allowedServers @@ -322,10 +331,29 @@ class BaseSCGIServer(object): def _setupSocket(self): """Creates and binds the socket for communication with the server.""" - sock = socket.socket() - sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + oldUmask = None + if type(self._bindAddress) is str: + # Unix socket + sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) + try: + os.unlink(self._bindAddress) + except OSError: + pass + if self._umask is not None: + oldUmask = os.umask(self._umask) + else: + # INET socket + assert type(self._bindAddress) is tuple + assert len(self._bindAddress) == 2 + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + sock.bind(self._bindAddress) sock.listen(socket.SOMAXCONN) + + if oldUmask is not None: + os.umask(oldUmask) + return sock def _cleanupSocket(self, sock): @@ -333,7 +361,9 @@ class BaseSCGIServer(object): sock.close() def _isClientAllowed(self, addr): - ret = self._allowedServers is None or addr[0] in self._allowedServers + ret = self._allowedServers is None or \ + len(addr) != 2 or \ + (len(addr) == 2 and addr[0] in self._allowedServers) if not ret: self.logger.warning('Server connection from %s disallowed', addr[0]) diff --git a/flup/server/scgi_fork.py b/flup/server/scgi_fork.py index 0ca81f6..cc63338 100644 --- a/flup/server/scgi_fork.py +++ b/flup/server/scgi_fork.py @@ -88,7 +88,8 @@ class WSGIServer(BaseSCGIServer, PreforkServer): mind running in multiple processes, go use SWAP. ;) """ def __init__(self, application, scriptName='', environ=None, - bindAddress=('localhost', 4000), allowedServers=None, + bindAddress=('localhost', 4000), umask=None, + allowedServers=None, loggingLevel=logging.INFO, debug=True, **kw): """ scriptName is the initial portion of the URL path that "belongs" @@ -99,11 +100,17 @@ class WSGIServer(BaseSCGIServer, PreforkServer): 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. - + bindAddress is the address to bind to, which must be a string or + a tuple of length 2. If a tuple, the first element must be a string, + which is the host name or IPv4 address of a local interface. The + 2nd element of the tuple is the port number. If a string, it will + be interpreted as a filename and a UNIX socket will be opened. + + If binding to a UNIX socket, umask may be set to specify what + the umask is to be changed to before the socket is created in the + filesystem. After the socket is created, the previous umask is + restored. + allowedServers must be None or a list of strings representing the IPv4 addresses of servers allowed to connect. None means accept connections from anywhere. @@ -116,6 +123,7 @@ class WSGIServer(BaseSCGIServer, PreforkServer): multithreaded=False, multiprocess=True, bindAddress=bindAddress, + umask=umask, allowedServers=allowedServers, loggingLevel=loggingLevel, debug=debug) -- cgit v1.2.1