summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGraham Dumpleton <Graham.Dumpleton@gmail.com>2015-02-21 21:53:15 +1100
committerGraham Dumpleton <Graham.Dumpleton@gmail.com>2015-02-21 21:53:15 +1100
commit61572d5706182d9d2ecf2ff7711be29de49240e9 (patch)
tree242e428d6ac0ddf8f4b61010bc4590ab67d92717
parent3cc8bba0658bb448ac197cd5517b363ec3dbc400 (diff)
parent683acabbb3acd7d60015a1b84878e24f8d9a6278 (diff)
downloadmod_wsgi-4.4.9.tar.gz
Merge branch 'release/4.4.9'4.4.9
-rw-r--r--.mailmap1
-rw-r--r--configure.ac2
-rw-r--r--docs/conf.py2
-rw-r--r--docs/index.rst6
-rw-r--r--docs/release-notes/index.rst1
-rw-r--r--docs/release-notes/version-4.4.9.rst107
-rw-r--r--src/server/__init__.py101
-rw-r--r--src/server/mod_wsgi.c373
-rw-r--r--src/server/wsgi_apache.c2
-rw-r--r--src/server/wsgi_apache.h2
-rw-r--r--src/server/wsgi_buckets.c2
-rw-r--r--src/server/wsgi_buckets.h2
-rw-r--r--src/server/wsgi_convert.c2
-rw-r--r--src/server/wsgi_convert.h2
-rw-r--r--src/server/wsgi_daemon.c2
-rw-r--r--src/server/wsgi_daemon.h2
-rw-r--r--src/server/wsgi_interp.c97
-rw-r--r--src/server/wsgi_interp.h9
-rw-r--r--src/server/wsgi_logger.c2
-rw-r--r--src/server/wsgi_logger.h2
-rw-r--r--src/server/wsgi_metrics.c2
-rw-r--r--src/server/wsgi_metrics.h2
-rw-r--r--src/server/wsgi_python.h2
-rw-r--r--src/server/wsgi_restrict.c2
-rw-r--r--src/server/wsgi_restrict.h2
-rw-r--r--src/server/wsgi_server.c4
-rw-r--r--src/server/wsgi_server.h6
-rw-r--r--src/server/wsgi_stream.c2
-rw-r--r--src/server/wsgi_stream.h2
-rw-r--r--src/server/wsgi_validate.c2
-rw-r--r--src/server/wsgi_validate.h2
-rw-r--r--src/server/wsgi_version.h6
32 files changed, 678 insertions, 75 deletions
diff --git a/.mailmap b/.mailmap
new file mode 100644
index 0000000..e268341
--- /dev/null
+++ b/.mailmap
@@ -0,0 +1 @@
+Graham Dumpleton <Graham.Dumpleton@gmail.com> Graham.Dumpleton <devnull@localhost>
diff --git a/configure.ac b/configure.ac
index f3f1d09..ab6145d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,6 +1,6 @@
dnl vim: set sw=4 expandtab :
dnl
-dnl Copyright 2007-2014 GRAHAM DUMPLETON
+dnl Copyright 2007-2015 GRAHAM DUMPLETON
dnl
dnl Licensed under the Apache License, Version 2.0 (the "License");
dnl you may not use this file except in compliance with the License.
diff --git a/docs/conf.py b/docs/conf.py
index 36cbae5..402a603 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -41,7 +41,7 @@ master_doc = 'index'
# General information about the project.
project = u'mod_wsgi'
-copyright = u'2014, Graham Dumpleton'
+copyright = u'2007-2015, Graham Dumpleton'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
diff --git a/docs/index.rst b/docs/index.rst
index b826a23..ac08d10 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -19,7 +19,7 @@ host any Python application which supports the Python WSGI_ interface.
Status
======
-No mod_wsgi is not dead, it's just been resting.
+No mod_wsgi is not dead, it was just resting.
Renewed development on mod_wsgi began early 2014, with a considerable
amount of new development work and fixes being performed. This included the
@@ -27,7 +27,9 @@ ability to install mod_wsgi using 'pip', along with an admin command
called ``mod_wsgi-express`` which provides a really simple way of starting
up Apache/mod_wsgi with an automatically generated configuration.
-Completely revised documentation will progressively be incorporated here.
+Completely revised documentation will eventually be incorporated here.
+Right now though I am having too much fun working on all the new features.
+
In the mean time keep referring to the older documentation at:
http://www.modwsgi.org/
diff --git a/docs/release-notes/index.rst b/docs/release-notes/index.rst
index 9b7b42b..0321696 100644
--- a/docs/release-notes/index.rst
+++ b/docs/release-notes/index.rst
@@ -5,6 +5,7 @@ Release Notes
.. toctree::
:maxdepth: 2
+ version-4.4.9.rst
version-4.4.8.rst
version-4.4.7.rst
version-4.4.6.rst
diff --git a/docs/release-notes/version-4.4.9.rst b/docs/release-notes/version-4.4.9.rst
new file mode 100644
index 0000000..a4828c3
--- /dev/null
+++ b/docs/release-notes/version-4.4.9.rst
@@ -0,0 +1,107 @@
+=============
+Version 4.4.9
+=============
+
+Version 4.4.9 of mod_wsgi can be obtained from:
+
+ https://codeload.github.com/GrahamDumpleton/mod_wsgi/tar.gz/4.4.9
+
+For details on the availability of Windows binaries see:
+
+ https://github.com/GrahamDumpleton/mod_wsgi/tree/master/win32
+
+Features Changed
+----------------
+
+1. The ``--proxy-url-alias`` option of ``mod_wsgi-express`` has been
+superseded by the ``--proxy-mount-point`` option. This option now should
+only be used to proxy to a whole site or sub site and not individual file
+resources. If the mount point URL for what should be proxied doesn't have a
+trailing slash, the trailing slash redirection will first be performed on
+the proxy for the mount point rather than simply passing it through to
+the backend.
+
+2. The signal handler intercept will now be removed automatically from a
+Python child process forked from either an Apache child process or a daemon
+process. This avoids the requirement of setting ``WSGIRestrictSignal`` to
+``Off`` if wanting to setup new signal handlers from a forked child process.
+
+3. The signal handler registrations setup in daemon processes to manage
+process shutdown, will now revert to exiting the process when invoked from
+a Python process forked from a daemon process. This avoids the need to set
+new signal handlers in forked processes to override what was inherited.
+
+Note that this only applies to processes forked from daemon mode processes.
+If you are forking processes when your WSGI application is running in
+embedded mode, it is still a good idea to set signal handles for ``SIGINT``,
+``SIGTERM`` and ``SIGUSR1`` back to ``SIG_DFL`` using ``signal.signal()``
+if you want to avoid the possibility of strange behaviour due to the
+inherited Apache child worker process signal registrations.
+
+New Features
+------------
+
+1. Added ``--hsts-policy`` option to ``mod_wsgi-express`` to allow a HSTS
+(``Strict-Transport-Security``) policy response header to be specified which
+should be included when the ``--https-only`` option is used to ensure that
+the site only accepts HTTPS connections.
+
+2. Added ``WSGITrustedProxyHeaders`` directive. This allows you to specify
+a space separated list of inbound HTTP headers used to transfer client
+connection information from a proxy to a backend server, that are trusted.
+When the specified headers are seen in a request, the values passed via
+them will be used to fix up the values in the WSGI ``environ`` dictionary
+to reflect client information as was seen by the proxy.
+
+Only the specific headers you are expecting and which is guaranteed to have
+only been set by the proxy should be listed. Whether it exists or not, all
+other headers in a category will be removed so as to avoid an issue with
+a forged header getting through to a WSGI middleware which is looking for a
+different header and subsequently overriding whatever the trusted header
+specified. This applies to the following as well when more than one
+convention is used for the header name.
+
+The header names which are accepted for specifying the HTTP scheme used are
+``X-Forwarded-Proto``, ``X-Forwarded-Scheme`` and ``X-Scheme``. It is
+expected that the value these supply will be ``http`` or ``https``. When it
+is ``https``, the ``wsgi.url_scheme`` value in the WSGI ``environ``
+dictionary will be overridden to be ``https``.
+
+Alternate headers accepted are ``X-Forwarded-HTTPS``, ``X-Forwarded-SSL``
+and ``X-HTTPS``. If these are passed, the value needs to be ``On``,
+``true`` or ``1``. A case insensitive match is performed. When matched, the
+``wsgi.url_scheme`` value in the WSGI ``environ`` dictionary will be
+overridden to be ``https``.
+
+The header names which are accepted for specifying the target host are
+``X-Forwarded-Host`` and ``X-Host``. When found, the value will be used
+to override the ``HTTP_HOST`` value in the WSGI ``environ`` dictionary.
+
+The sole header name accepted for specifying the front end proxy server
+name is ``X-Fowarded-Server``. When found, the value will be used to
+override the ``SERVER_NAME`` value in the WSGI ``environ`` dictionary.
+
+The sole header name accepted for specifying the front end proxy server
+port is ``X-Fowarded-Port``. When found, the value will be used to
+override the ``SERVER_PORT`` value in the WSGI ``environ`` dictionary.
+
+The header names accepted for specifying the client IP address are
+``X-Forwarded-For`` and ``X-Real-IP``. When ``X-Forwarded-For`` is used
+then the first IP address listed in the header value will be used. For
+``X-Real-IP`` only one IP address should be given. When found, the value
+will be used to override the ``REMOTE_ADDR`` value in the WSGI ``environ``
+dictionary.
+
+Note that at present there is no facility for specifying a list of trusted
+IP addresses to be specified for front end proxies. This will be a feature
+added in a future version. When that is available and ``X-Forwarded-For``
+is used, then the IP address preceding the furthest away trusted proxy IP
+address will instead be used, even if not the first in the list.
+
+The header names accepted for specifying the application mount point are
+``X-Script-Name`` and ``X-Forwarded-Script-Name``. When found, the value
+will override the ``SCRIPT_NAME`` value in the ``WSGI`` environ dictionary.
+
+When using ``mod_wsgi-express`` the equivalent command line option is
+``--trust-proxy-header``. The option can be used multiple times to specify
+more than one header.
diff --git a/src/server/__init__.py b/src/server/__init__.py
index 2e06db4..ea2eaac 100644
--- a/src/server/__init__.py
+++ b/src/server/__init__.py
@@ -169,6 +169,9 @@ LoadModule dir_module '${HTTPD_MODULES_DIRECTORY}/mod_dir.so'
<IfModule !env_module>
LoadModule env_module '${HTTPD_MODULES_DIRECTORY}/mod_env.so'
</IfModule>
+<IfModule !headers_module>
+LoadModule headers_module '${HTTPD_MODULES_DIRECTORY}/mod_headers.so'
+</IfModule>
<IfVersion >= 2.2.15>
<IfModule !reqtimeout_module>
@@ -369,6 +372,10 @@ CustomLog "%(access_log_file)s" %(log_format_nickname)s
WSGIChunkedRequest On
</IfDefine>
+<IfDefine WSGI_WITH_PROXY_HEADERS>
+WSGITrustedProxyHeaders %(trusted_proxy_headers)s
+</IfDefine>
+
<IfDefine WSGI_WITH_HTTPS>
<IfModule !ssl_module>
LoadModule ssl_module ${HTTPD_MODULES_DIRECTORY}/mod_ssl.so
@@ -530,6 +537,11 @@ ServerAlias %(server_aliases)s
SSLEngine On
SSLCertificateFile %(ssl_certificate)s.crt
SSLCertificateKeyFile %(ssl_certificate)s.key
+<IfDefine WSGI_HTTPS_ONLY>
+<IfDefine WSGI_HSTS_POLICY>
+Header set Strict-Transport-Security %(hsts_policy)s
+</IfDefine>
+</IfDefine>
</VirtualHost>
<IfDefine WSGI_REDIRECT_WWW>
<VirtualHost *:%(https_port)s>
@@ -623,14 +635,25 @@ WSGIImportScript '%(server_root)s/handler.wsgi' \\
</IfDefine>
"""
-APACHE_PROXY_PASS_CONFIG = """
+APACHE_PROXY_PASS_MOUNT_POINT_CONFIG = """
ProxyPass '%(mount_point)s' '%(url)s'
+ProxyPassReverse '%(mount_point)s' '%(url)s'
+"""
+
+APACHE_PROXY_PASS_MOUNT_POINT_SLASH_CONFIG = """
+ProxyPass '%(mount_point)s/' '%(url)s/'
+ProxyPassReverse '%(mount_point)s/' '%(url)s/'
+<LocationMatch '^%(mount_point)s$'>
+RewriteEngine On
+RewriteRule - http://%%{HTTP_HOST}%%{REQUEST_URI}/ [R=302,L]
+</LocationMatch>
"""
APACHE_PROXY_PASS_HOST_CONFIG = """
<VirtualHost *:%(port)s>
ServerName %(host)s
ProxyPass / '%(url)s'
+ProxyPassReverse / '%(url)s'
</VirtualHost>
"""
@@ -715,10 +738,14 @@ def generate_apache_config(options):
with open(options['httpd_conf'], 'w') as fp:
print(APACHE_GENERAL_CONFIG % options, file=fp)
- if options['proxy_url_aliases']:
- for mount_point, url in options['proxy_url_aliases']:
- print(APACHE_PROXY_PASS_CONFIG % dict(
- mount_point=mount_point, url=url), file=fp)
+ if options['proxy_mount_points']:
+ for mount_point, url in options['proxy_mount_points']:
+ if mount_point.endswith('/'):
+ print(APACHE_PROXY_PASS_MOUNT_POINT_CONFIG % dict(
+ mount_point=mount_point, url=url), file=fp)
+ else:
+ print(APACHE_PROXY_PASS_MOUNT_POINT_SLASH_CONFIG % dict(
+ mount_point=mount_point, url=url), file=fp)
if options['proxy_virtual_hosts']:
for host, url in options['proxy_virtual_hosts']:
@@ -1138,16 +1165,35 @@ class ApplicationHandler(object):
# Strip out the leading component due to internal redirect in
# Apache when using web application as fallback resource.
+ mount_point = environ.get('mod_wsgi.mount_point')
+
script_name = environ.get('SCRIPT_NAME')
path_info = environ.get('PATH_INFO')
- environ['SCRIPT_NAME'] = ''
- environ['PATH_INFO'] = script_name + path_info
+ if mount_point is not None:
+ # If this is set then it means that SCRIPT_NAME was
+ # overridden by a trusted proxy header. In this case
+ # we want to ignore any local mount point, simply
+ # stripping it from the path.
+
+ script_name = environ['mod_wsgi.script_name']
- if self.mount_point != '/':
- if environ['PATH_INFO'].startswith(self.mount_point):
- environ['SCRIPT_NAME'] = self.mount_point
- environ['PATH_INFO'] = environ['PATH_INFO'][len(self.mount_point):]
+ environ['PATH_INFO'] = script_name + path_info
+
+ if self.mount_point != '/':
+ if environ['PATH_INFO'].startswith(self.mount_point):
+ environ['PATH_INFO'] = environ['PATH_INFO'][len(
+ self.mount_point):]
+
+ else:
+ environ['SCRIPT_NAME'] = ''
+ environ['PATH_INFO'] = script_name + path_info
+
+ if self.mount_point != '/':
+ if environ['PATH_INFO'].startswith(self.mount_point):
+ environ['SCRIPT_NAME'] = self.mount_point
+ environ['PATH_INFO'] = environ['PATH_INFO'][len(
+ self.mount_point):]
return self.application(environ, start_response)
@@ -1535,9 +1581,12 @@ option_list = (
'the extension.'),
optparse.make_option('--https-only', action='store_true',
default=False, help='Flag indicating whether any requests '
- 'made using a HTTP request over the non connection connection '
+ 'made using a HTTP request over the non secure connection '
'should be redirected automatically to use a HTTPS request '
'over the secure connection.'),
+ optparse.make_option('--hsts-policy', default=None, metavar='PARAMS',
+ help='Specify the HTST policy that should be applied when '
+ 'HTTPS only connections are being enforced.'),
optparse.make_option('--server-name', default=None, metavar='HOSTNAME',
help='The primary host name of the web server. If this name '
@@ -1782,15 +1831,25 @@ option_list = (
default=False, help='Flag indicating whether Apache error '
'documents will override application error responses.'),
- optparse.make_option('--proxy-url-alias', action='append', nargs=2,
- dest='proxy_url_aliases', metavar='URL-PATH URL',
+ optparse.make_option('--proxy-mount-point', action='append', nargs=2,
+ dest='proxy_mount_points', metavar='URL-PATH URL',
help='Map a sub URL such that any requests against it will be '
- 'proxied to the specified URL.'),
+ 'proxied to the specified URL. This is only for proxying to a '
+ 'site as a whole, or a sub site, not individual resources.'),
+ optparse.make_option('--proxy-url-alias', action='append', nargs=2,
+ dest='proxy_mount_points', metavar='URL-PATH URL',
+ help=optparse.SUPPRESS_HELP),
+
optparse.make_option('--proxy-virtual-host', action='append', nargs=2,
dest='proxy_virtual_hosts', metavar='HOSTNAME URL',
help='Proxy any requests for the specified host name to the '
'remote URL.'),
+ optparse.make_option('--trust-proxy-header', action='append', default=[],
+ dest='trusted_proxy_headers', metavar='HEADER-NAME',
+ help='The name of any trusted HTTP header providing details '
+ 'of the front end client request when proxying.'),
+
optparse.make_option('--keep-alive-timeout', type='int', default=0,
metavar='SECONDS', help='The number of seconds which a client '
'connection will be kept alive to allow subsequent requests '
@@ -2191,6 +2250,9 @@ def _cmd_setup_server(command, args, options):
if not options['mount_point'].startswith('/'):
options['mount_point'] = os.path.normpath('/' + options['mount_point'])
+ # Create subdirectories for mount points in document directory
+ # so that fallback resource rewrite rule will work.
+
if options['mount_point'] != '/':
parts = options['mount_point'].rstrip('/').split('/')[1:]
subdir = options['document_root']
@@ -2463,6 +2525,9 @@ def _cmd_setup_server(command, args, options):
options['httpd_arguments_list'] = []
+ options['trusted_proxy_headers'] = ' '.join(
+ options['trusted_proxy_headers'])
+
if options['startup_log']:
if not options['log_to_terminal']:
options['startup_log_file'] = os.path.join(
@@ -2558,6 +2623,8 @@ def _cmd_setup_server(command, args, options):
options['httpd_arguments_list'].append('-DWSGI_WITH_HTTPS')
if options['https_only']:
options['httpd_arguments_list'].append('-DWSGI_HTTPS_ONLY')
+ if options['hsts_policy']:
+ options['httpd_arguments_list'].append('-DWSGI_HSTS_POLICY')
if options['server_aliases']:
options['httpd_arguments_list'].append('-DWSGI_SERVER_ALIAS')
@@ -2600,8 +2667,10 @@ def _cmd_setup_server(command, args, options):
options['httpd_arguments_list'].append('-DWSGI_CHUNKED_REQUEST')
if options['with_php5']:
options['httpd_arguments_list'].append('-DWSGI_WITH_PHP5')
- if options['proxy_url_aliases'] or options['proxy_virtual_hosts']:
+ if options['proxy_mount_points'] or options['proxy_virtual_hosts']:
options['httpd_arguments_list'].append('-DWSGI_WITH_PROXY')
+ if options['trusted_proxy_headers']:
+ options['httpd_arguments_list'].append('-DWSGI_WITH_PROXY_HEADERS')
options['httpd_arguments_list'].extend(
_mpm_module_defines(options['modules_directory'],
diff --git a/src/server/mod_wsgi.c b/src/server/mod_wsgi.c
index c60f422..ff2a51d 100644
--- a/src/server/mod_wsgi.c
+++ b/src/server/mod_wsgi.c
@@ -1,7 +1,7 @@
/* ------------------------------------------------------------------------- */
/*
- * Copyright 2007-2014 GRAHAM DUMPLETON
+ * Copyright 2007-2015 GRAHAM DUMPLETON
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -184,6 +184,11 @@ static void *wsgi_merge_server_config(apr_pool_t *p, void *base_conf,
else
config->map_head_to_get = parent->map_head_to_get;
+ if (child->trusted_proxy_headers)
+ config->trusted_proxy_headers = child->trusted_proxy_headers;
+ else
+ config->trusted_proxy_headers = parent->trusted_proxy_headers;
+
if (child->enable_sendfile != -1)
config->enable_sendfile = child->enable_sendfile;
else
@@ -219,6 +224,8 @@ typedef struct {
int chunked_request;
int map_head_to_get;
+ apr_array_header_t *trusted_proxy_headers;
+
int enable_sendfile;
WSGIScriptFile *access_script;
@@ -251,6 +258,8 @@ static WSGIDirectoryConfig *newWSGIDirectoryConfig(apr_pool_t *p)
object->chunked_request = -1;
object->map_head_to_get = -1;
+ object->trusted_proxy_headers = NULL;
+
object->enable_sendfile = -1;
object->access_script = NULL;
@@ -338,6 +347,11 @@ static void *wsgi_merge_dir_config(apr_pool_t *p, void *base_conf,
else
config->map_head_to_get = parent->map_head_to_get;
+ if (child->trusted_proxy_headers)
+ config->trusted_proxy_headers = child->trusted_proxy_headers;
+ else
+ config->trusted_proxy_headers = parent->trusted_proxy_headers;
+
if (child->enable_sendfile != -1)
config->enable_sendfile = child->enable_sendfile;
else
@@ -398,6 +412,8 @@ typedef struct {
int chunked_request;
int map_head_to_get;
+ apr_array_header_t *trusted_proxy_headers;
+
int enable_sendfile;
WSGIScriptFile *access_script;
@@ -833,6 +849,11 @@ static WSGIRequestConfig *wsgi_create_req_config(apr_pool_t *p, request_rec *r)
config->map_head_to_get = 2;
}
+ config->trusted_proxy_headers = dconfig->trusted_proxy_headers;
+
+ if (!config->trusted_proxy_headers)
+ config->trusted_proxy_headers = sconfig->trusted_proxy_headers;
+
config->enable_sendfile = dconfig->enable_sendfile;
if (config->enable_sendfile < 0) {
@@ -3869,6 +3890,8 @@ static void wsgi_python_child_init(apr_pool_t *p)
PyType_Ready(&Dispatch_Type);
PyType_Ready(&Auth_Type);
+ PyType_Ready(&SignalIntercept_Type);
+
#if PY_MAJOR_VERSION > 3 || (PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION >= 4)
PyType_Ready(&ShutdownInterpreter_Type);
#endif
@@ -4971,6 +4994,40 @@ static const char *wsgi_set_map_head_to_get(cmd_parms *cmd, void *mconfig,
return NULL;
}
+static char *wsgi_http2env(apr_pool_t *a, const char *w);
+
+static const char *wsgi_set_trusted_proxy_headers(cmd_parms *cmd,
+ void *mconfig,
+ const char *args)
+{
+ apr_array_header_t *headers = NULL;
+
+ if (cmd->path) {
+ WSGIDirectoryConfig *dconfig = NULL;
+ dconfig = (WSGIDirectoryConfig *)mconfig;
+
+ headers = apr_array_make(cmd->pool, 3, sizeof(char*));
+ dconfig->trusted_proxy_headers = headers;
+ }
+ else {
+ WSGIServerConfig *sconfig = NULL;
+ sconfig = ap_get_module_config(cmd->server->module_config,
+ &wsgi_module);
+
+ headers = apr_array_make(cmd->pool, 3, sizeof(char*));
+ sconfig->trusted_proxy_headers = headers;
+ }
+
+ while (*args) {
+ const char **entry = NULL;
+
+ entry = (const char **)apr_array_push(headers);
+ *entry = wsgi_http2env(cmd->pool, ap_getword_conf(cmd->pool, &args));
+ }
+
+ return NULL;
+}
+
static const char *wsgi_set_enable_sendfile(cmd_parms *cmd, void *mconfig,
const char *f)
{
@@ -5424,6 +5481,7 @@ static int wsgi_hook_intercept(request_rec *r)
/* Handler for the response handler phase. */
static void wsgi_drop_invalid_headers(request_rec *r);
+static void wsgi_process_proxy_headers(request_rec *r);
static void wsgi_build_environment(request_rec *r)
{
@@ -5441,21 +5499,22 @@ static void wsgi_build_environment(request_rec *r)
&wsgi_module);
/*
- * Populate environment with standard CGI variables. Before
- * we do this though, we ensure that we delete any headers
- * which use invalid characters. This is necessary to ensure
- * that someone doesn't try and take advantage of header
- * spoofing. This can come about where characters other than
- * alphanumerics or '-' are used as the conversion of non
- * alphanumerics to '_' means one can get collisions. This
- * is technically only an issue with Apache 2.2 as Apache
- * 2.4 addresses the problem and drops them anyway. Still go
- * through and drop them even for Apache 2.4 as not sure
- * which version of Apache 2.4 introduces the change.
+ * Remove any invalid headers which use invalid characters.
+ * This is necessary to ensure that someone doesn't try and
+ * take advantage of header spoofing. This can come about
+ * where characters other than alphanumerics or '-' are used
+ * as the conversion of non alphanumerics to '_' means one
+ * can get collisions. This is technically only an issue
+ * with Apache 2.2 as Apache 2.4 addresses the problem and
+ * drops them anyway. Still go through and drop them even
+ * for Apache 2.4 as not sure which version of Apache 2.4
+ * introduces the change.
*/
wsgi_drop_invalid_headers(r);
+ /* Populate environment with standard CGI variables. */
+
ap_add_cgi_vars(r);
ap_add_common_vars(r);
@@ -5492,14 +5551,6 @@ static void wsgi_build_environment(request_rec *r)
apr_table_setn(r->subprocess_env, "REQUEST_METHOD", "GET");
}
- /* Determine whether connection uses HTTPS protocol. */
-
- if (!wsgi_is_https)
- wsgi_is_https = APR_RETRIEVE_OPTIONAL_FN(ssl_is_https);
-
- if (wsgi_is_https && wsgi_is_https(r->connection))
- apr_table_set(r->subprocess_env, "HTTPS", "1");
-
/*
* If enabled, pass along authorisation headers which Apache
* leaves out of CGI environment. WSGI still needs to see
@@ -5538,7 +5589,7 @@ static void wsgi_build_environment(request_rec *r)
script_name = apr_table_get(r->subprocess_env, "SCRIPT_NAME");
- if (*script_name) {
+ if (*script_name == '/') {
while (*script_name && (*(script_name+1) == '/'))
script_name++;
script_name = apr_pstrdup(r->pool, script_name);
@@ -5548,7 +5599,7 @@ static void wsgi_build_environment(request_rec *r)
path_info = apr_table_get(r->subprocess_env, "PATH_INFO");
- if (*path_info) {
+ if (*path_info == '/') {
while (*path_info && (*(path_info+1) == '/'))
path_info++;
path_info = apr_pstrdup(r->pool, path_info);
@@ -5557,6 +5608,34 @@ static void wsgi_build_environment(request_rec *r)
}
/*
+ * Save away the SCRIPT_NAME and PATH_INFO values at this point
+ * so we have a way of determining if they are rewritten somehow.
+ * This can be important when dealing with rewrite rules and
+ * a trusted header was being handled for SCRIPT_NAME.
+ */
+
+ apr_table_setn(r->subprocess_env, "mod_wsgi.script_name", script_name);
+ apr_table_setn(r->subprocess_env, "mod_wsgi.path_info", path_info);
+
+ /*
+ * Perform fixups on environment based on trusted proxy headers
+ * sent through from a front end proxy.
+ */
+
+ wsgi_process_proxy_headers(r);
+
+ /*
+ * Determine whether connection uses HTTPS protocol. This has
+ * to be done after and fixups due to trusted proxy headers.
+ */
+
+ if (!wsgi_is_https)
+ wsgi_is_https = APR_RETRIEVE_OPTIONAL_FN(ssl_is_https);
+
+ if (wsgi_is_https && wsgi_is_https(r->connection))
+ apr_table_set(r->subprocess_env, "HTTPS", "1");
+
+ /*
* Set values specific to mod_wsgi configuration. These control
* aspects of how a request is managed but don't strictly need
* to be passed through to the application itself. It is though
@@ -7225,6 +7304,9 @@ static void wsgi_signal_handler(int signum)
{
apr_size_t nbytes = 1;
+ if (wsgi_daemon_pid != 0 && wsgi_daemon_pid != getpid())
+ exit(-1);
+
if (signum == AP_SIG_GRACEFUL) {
apr_file_write(wsgi_signal_pipe_out, "G", &nbytes);
apr_file_flush(wsgi_signal_pipe_out);
@@ -9116,6 +9198,8 @@ static int wsgi_start_process(apr_pool_t *p, WSGIDaemonProcess *daemon)
wsgi_daemon_shutdown = 0;
+ wsgi_daemon_pid = getpid();
+
apr_signal(SIGINT, wsgi_signal_handler);
apr_signal(SIGTERM, wsgi_signal_handler);
@@ -12180,6 +12264,10 @@ static void wsgi_hook_child_init(apr_pool_t *p, server_rec *s)
}
#endif
+ /* Remember worker process ID. */
+
+ wsgi_worker_pid = getpid();
+
/* Create lock for request monitoring. */
apr_thread_mutex_create(&wsgi_monitor_lock,
@@ -12297,6 +12385,244 @@ static void wsgi_drop_invalid_headers(request_rec *r)
}
}
+static const char *wsgi_proxy_scheme_headers[] = {
+ "HTTP_X_FORWARDED_HTTPS",
+ "HTTP_X_FORWARDED_PROTO",
+ "HTTP_X_FORWARDED_SCHEME",
+ "HTTP_X_FORWARDED_SSL",
+ "HTTP_X_HTTPS",
+ "HTTP_X_SCHEME",
+ NULL,
+};
+
+static const char *wsgi_proxy_host_headers[] = {
+ "HTTP_X_FORWARDED_HOST",
+ "HTTP_X_HOST",
+ NULL,
+};
+
+static const char *wsgi_proxy_script_name_headers[] = {
+ "HTTP_X_SCRIPT_NAME",
+ "HTTP_X_FORWARDED_SCRIPT_NAME",
+ NULL,
+};
+
+static void wsgi_process_proxy_headers(request_rec *r)
+{
+ WSGIRequestConfig *config = NULL;
+
+ apr_array_header_t *trusted_proxy_headers = NULL;
+
+ int match_scheme_header = 0;
+ int match_host_header = 0;
+ int match_script_name_header = 0;
+
+ const char *trusted_scheme_header = NULL;
+ const char *trusted_host_header = NULL;
+ const char *trusted_script_name_header = NULL;
+
+ int i = 0;
+
+ config = (WSGIRequestConfig *)ap_get_module_config(r->request_config,
+ &wsgi_module);
+
+ trusted_proxy_headers = config->trusted_proxy_headers;
+
+ /* Nothing to do if no trusted headers have been specified. */
+
+ if (!trusted_proxy_headers)
+ return;
+
+ /*
+ * Check for any special processing required for each trusted
+ * header which has been specified.
+ */
+
+ for (i=0; i<trusted_proxy_headers->nelts; i++) {
+ const char *name = NULL;
+ const char *value = NULL;
+
+ name = ((const char**)trusted_proxy_headers->elts)[i];
+ value = apr_table_get(r->subprocess_env, name);
+
+ if (!strcmp(name, "HTTP_X_FORWARDED_FOR")) {
+ if (value) {
+ /*
+ * A potentially comma separated list where client
+ * we are interested in will be listed first.
+ */
+
+ const char *end = NULL;
+
+ while (*value != '\0' && apr_isspace(*value))
+ value++;
+
+ if (*value != '\0') {
+ end = value;
+
+ while (*end != '\0' && *end != ',')
+ end++;
+
+ /* Need to deal with trailing whitespace. */
+
+ while (end != value) {
+ if (!apr_isspace(*(end-1)))
+ break;
+
+ end--;
+ }
+
+ apr_table_setn(r->subprocess_env, "REMOTE_ADDR",
+ apr_pstrndup(r->pool, value, (end-value)));
+ }
+ }
+ }
+ else if (!strcmp(name, "HTTP_X_REAL_IP")) {
+ if (value) {
+ /* Use the value as is. */
+
+ apr_table_setn(r->subprocess_env, "REMOTE_ADDR", value);
+ }
+ }
+ else if (!strcmp(name, "HTTP_X_FORWARDED_HOST") ||
+ !strcmp(name, "HTTP_X_HOST")) {
+
+ match_host_header = 1;
+
+ if (value) {
+ /* Use the value as is. May include a port. */
+
+ trusted_host_header = name;
+
+ apr_table_setn(r->subprocess_env, "HTTP_HOST", value);
+ }
+ }
+ else if (!strcmp(name, "HTTP_X_FORWARDED_SERVER")) {
+ if (value) {
+ /* Use the value as is. */
+
+ apr_table_setn(r->subprocess_env, "SERVER_NAME", value);
+ }
+ }
+ else if (!strcmp(name, "HTTP_X_FORWARDED_PORT")) {
+ if (value) {
+ /* Use the value as is. */
+
+ apr_table_setn(r->subprocess_env, "SERVER_PORT", value);
+ }
+ }
+ else if (!strcmp(name, "HTTP_X_SCRIPT_NAME") ||
+ !strcmp(name, "HTTP_X_FORWARDED_SCRIPT_NAME")) {
+
+ match_script_name_header = 1;
+
+ if (value) {
+ /*
+ * Use the value as is. We want to remember what the
+ * original value for SCRIPT_NAME was though.
+ */
+
+ apr_table_setn(r->subprocess_env, "mod_wsgi.mount_point",
+ value);
+
+ trusted_script_name_header = name;
+
+ apr_table_setn(r->subprocess_env, "SCRIPT_NAME", value);
+ }
+ }
+ else if (!strcmp(name, "HTTP_X_FORWARDED_PROTO") ||
+ !strcmp(name, "HTTP_X_FORWARDED_SCHEME") ||
+ !strcmp(name, "HTTP_X_SCHEME")) {
+
+ match_scheme_header = 1;
+
+ if (value) {
+ trusted_scheme_header = name;
+
+ /* Value can be either 'http' or 'https'. */
+
+ if (!strcasecmp(value, "https"))
+ apr_table_setn(r->subprocess_env, "HTTPS", "1");
+ else if (!strcasecmp(value, "http"))
+ apr_table_unset(r->subprocess_env, "HTTPS");
+ }
+ }
+ else if (!strcmp(name, "HTTP_X_FORWARDED_HTTPS") ||
+ !strcmp(name, "HTTP_X_FORWARDED_SSL") ||
+ !strcmp(name, "HTTP_X_HTTPS")) {
+
+ match_scheme_header = 1;
+
+ if (value) {
+ trusted_scheme_header = name;
+
+ /*
+ * Value can be a boolean like flag such as 'On',
+ * 'Off', 'true', 'false', '1' or '0'.
+ */
+
+ if (!strcasecmp(value, "On") ||
+ !strcasecmp(value, "true") ||
+ !strcasecmp(value, "1")) {
+
+ apr_table_setn(r->subprocess_env, "HTTPS", "1");
+ }
+ else if (!strcasecmp(value, "Off") ||
+ !strcasecmp(value, "false") ||
+ !strcasecmp(value, "0")) {
+
+ apr_table_unset(r->subprocess_env, "HTTPS");
+ }
+ }
+ }
+ }
+
+ /*
+ * Remove all proxy scheme headers from request environment
+ * which weren't matched as being trusted.
+ */
+
+ if (match_scheme_header) {
+ const char *name = NULL;
+
+ for (i=0; (name=wsgi_proxy_scheme_headers[i]); i++) {
+ if (!trusted_scheme_header || strcmp(name, trusted_scheme_header)) {
+ apr_table_unset(r->subprocess_env, name);
+ }
+ }
+ }
+
+ /*
+ * Remove all proxy host from request environment which weren't
+ * matched as being trusted.
+ */
+
+ if (match_host_header) {
+ const char *name = NULL;
+
+ for (i=0; (name=wsgi_proxy_host_headers[i]); i++) {
+ if (!trusted_host_header || strcmp(name, trusted_host_header))
+ apr_table_unset(r->subprocess_env, name);
+ }
+ }
+
+ /*
+ * Remove all proxy script name headers from request environment
+ * which weren't matched as being trusted.
+ */
+
+ if (match_script_name_header) {
+ const char *name = NULL;
+
+ for (i=0; (name=wsgi_proxy_script_name_headers[i]); i++) {
+ if (!trusted_script_name_header ||
+ strcmp(name, trusted_script_name_header)) {
+ apr_table_unset(r->subprocess_env, name);
+ }
+ }
+ }
+}
+
static char *wsgi_http2env(apr_pool_t *a, const char *w)
{
char *res = (char *)apr_palloc(a, sizeof("HTTP_") + strlen(w));
@@ -14428,6 +14754,9 @@ static const command_rec wsgi_commands[] =
AP_INIT_TAKE1("WSGIMapHEADToGET", wsgi_set_map_head_to_get,
NULL, OR_FILEINFO, "Enable/Disable mapping of HEAD to GET."),
+ AP_INIT_RAW_ARGS("WSGITrustedProxyHeaders", wsgi_set_trusted_proxy_headers,
+ NULL, OR_FILEINFO, "Specify a list of trusted proxy headers."),
+
#ifndef WIN32
AP_INIT_TAKE1("WSGIEnableSendfile", wsgi_set_enable_sendfile,
NULL, OR_FILEINFO, "Enable/Disable support for kernel sendfile."),
diff --git a/src/server/wsgi_apache.c b/src/server/wsgi_apache.c
index afa9162..504cbc3 100644
--- a/src/server/wsgi_apache.c
+++ b/src/server/wsgi_apache.c
@@ -1,7 +1,7 @@
/* ------------------------------------------------------------------------- */
/*
- * Copyright 2007-2014 GRAHAM DUMPLETON
+ * Copyright 2007-2015 GRAHAM DUMPLETON
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/src/server/wsgi_apache.h b/src/server/wsgi_apache.h
index aa54c0f..bd2f2b9 100644
--- a/src/server/wsgi_apache.h
+++ b/src/server/wsgi_apache.h
@@ -4,7 +4,7 @@
/* ------------------------------------------------------------------------- */
/*
- * Copyright 2007-2014 GRAHAM DUMPLETON
+ * Copyright 2007-2015 GRAHAM DUMPLETON
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/src/server/wsgi_buckets.c b/src/server/wsgi_buckets.c
index 94573a9..a1c9c1f 100644
--- a/src/server/wsgi_buckets.c
+++ b/src/server/wsgi_buckets.c
@@ -1,7 +1,7 @@
/* ------------------------------------------------------------------------- */
/*
- * Copyright 2007-2014 GRAHAM DUMPLETON
+ * Copyright 2007-2015 GRAHAM DUMPLETON
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/src/server/wsgi_buckets.h b/src/server/wsgi_buckets.h
index c0f6c37..4a34da6 100644
--- a/src/server/wsgi_buckets.h
+++ b/src/server/wsgi_buckets.h
@@ -4,7 +4,7 @@
/* ------------------------------------------------------------------------- */
/*
- * Copyright 2007-2014 GRAHAM DUMPLETON
+ * Copyright 2007-2015 GRAHAM DUMPLETON
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/src/server/wsgi_convert.c b/src/server/wsgi_convert.c
index c344cf2..d55bec9 100644
--- a/src/server/wsgi_convert.c
+++ b/src/server/wsgi_convert.c
@@ -1,7 +1,7 @@
/* ------------------------------------------------------------------------- */
/*
- * Copyright 2007-2014 GRAHAM DUMPLETON
+ * Copyright 2007-2015 GRAHAM DUMPLETON
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/src/server/wsgi_convert.h b/src/server/wsgi_convert.h
index c14966b..b1f5d6e 100644
--- a/src/server/wsgi_convert.h
+++ b/src/server/wsgi_convert.h
@@ -4,7 +4,7 @@
/* ------------------------------------------------------------------------- */
/*
- * Copyright 2007-2014 GRAHAM DUMPLETON
+ * Copyright 2007-2015 GRAHAM DUMPLETON
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/src/server/wsgi_daemon.c b/src/server/wsgi_daemon.c
index d1392ae..5a4bd25 100644
--- a/src/server/wsgi_daemon.c
+++ b/src/server/wsgi_daemon.c
@@ -1,7 +1,7 @@
/* ------------------------------------------------------------------------- */
/*
- * Copyright 2007-2014 GRAHAM DUMPLETON
+ * Copyright 2007-2015 GRAHAM DUMPLETON
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/src/server/wsgi_daemon.h b/src/server/wsgi_daemon.h
index 999fca2..3b83de5 100644
--- a/src/server/wsgi_daemon.h
+++ b/src/server/wsgi_daemon.h
@@ -4,7 +4,7 @@
/* ------------------------------------------------------------------------- */
/*
- * Copyright 2007-2014 GRAHAM DUMPLETON
+ * Copyright 2007-2015 GRAHAM DUMPLETON
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/src/server/wsgi_interp.c b/src/server/wsgi_interp.c
index 60851d0..5ac9296 100644
--- a/src/server/wsgi_interp.c
+++ b/src/server/wsgi_interp.c
@@ -1,7 +1,7 @@
/* ------------------------------------------------------------------------- */
/*
- * Copyright 2007-2014 GRAHAM DUMPLETON
+ * Copyright 2007-2015 GRAHAM DUMPLETON
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -42,13 +42,39 @@
/* Function to restrict access to use of signal(). */
-static PyObject *wsgi_signal_intercept(PyObject *self, PyObject *args)
+static void SignalIntercept_dealloc(SignalInterceptObject *self)
+{
+ Py_DECREF(self->wrapped);
+}
+
+static SignalInterceptObject *newSignalInterceptObject(PyObject *wrapped)
+{
+ SignalInterceptObject *self = NULL;
+
+ self = PyObject_New(SignalInterceptObject, &SignalIntercept_Type);
+ if (self == NULL)
+ return NULL;
+
+ Py_INCREF(wrapped);
+ self->wrapped = wrapped;
+
+ return self;
+}
+
+static PyObject *SignalIntercept_call(
+ SignalInterceptObject *self, PyObject *args, PyObject *kwds)
{
PyObject *h = NULL;
int n = 0;
PyObject *m = NULL;
+ if (wsgi_daemon_pid != 0 && wsgi_daemon_pid != getpid())
+ return PyObject_Call(self->wrapped, args, kwds);
+
+ if (wsgi_worker_pid != 0 && wsgi_worker_pid != getpid())
+ return PyObject_Call(self->wrapped, args, kwds);
+
if (!PyArg_ParseTuple(args, "iO:signal", &n, &h))
return NULL;
@@ -87,9 +113,48 @@ static PyObject *wsgi_signal_intercept(PyObject *self, PyObject *args)
return h;
}
-static PyMethodDef wsgi_signal_method[] = {
- { "signal", (PyCFunction)wsgi_signal_intercept, METH_VARARGS, 0 },
- { NULL, NULL }
+PyTypeObject SignalIntercept_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "mod_wsgi.SignalIntercept", /*tp_name*/
+ sizeof(SignalInterceptObject), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ /* methods */
+ (destructor)SignalIntercept_dealloc, /*tp_dealloc*/
+ 0, /*tp_print*/
+ 0, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ 0, /*tp_repr*/
+ 0, /*tp_as_number*/
+ 0, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ 0, /*tp_hash*/
+ (ternaryfunc)SignalIntercept_call, /*tp_call*/
+ 0, /*tp_str*/
+ 0, /*tp_getattro*/
+ 0, /*tp_setattro*/
+ 0, /*tp_as_buffer*/
+ Py_TPFLAGS_DEFAULT, /*tp_flags*/
+ 0, /*tp_doc*/
+ 0, /*tp_traverse*/
+ 0, /*tp_clear*/
+ 0, /*tp_richcompare*/
+ 0, /*tp_weaklistoffset*/
+ 0, /*tp_iter*/
+ 0, /*tp_iternext*/
+ 0, /*tp_methods*/
+ 0, /*tp_members*/
+ 0, /*tp_getset*/
+ 0, /*tp_base*/
+ 0, /*tp_dict*/
+ 0, /*tp_descr_get*/
+ 0, /*tp_descr_set*/
+ 0, /*tp_dictoffset*/
+ 0, /*tp_init*/
+ 0, /*tp_alloc*/
+ 0, /*tp_new*/
+ 0, /*tp_free*/
+ 0, /*tp_is_gc*/
};
/* Wrapper around Python interpreter instances. */
@@ -504,10 +569,26 @@ InterpreterObject *newInterpreterObject(const char *name)
*/
if (wsgi_server_config->restrict_signal != 0) {
+
module = PyImport_ImportModule("signal");
- PyModule_AddObject(module, "signal", PyCFunction_New(
- &wsgi_signal_method[0], NULL));
- Py_DECREF(module);
+
+ if (module) {
+ PyObject *dict = NULL;
+ PyObject *func = NULL;
+
+ dict = PyModule_GetDict(module);
+ func = PyDict_GetItemString(dict, "signal");
+
+ if (func) {
+ PyObject *wrapper = NULL;
+
+ wrapper = (PyObject *)newSignalInterceptObject(func);
+ PyDict_SetItemString(dict, "signal", wrapper);
+ Py_DECREF(wrapper);
+ }
+ }
+
+ Py_XDECREF(module);
}
/*
diff --git a/src/server/wsgi_interp.h b/src/server/wsgi_interp.h
index c788173..7da1e09 100644
--- a/src/server/wsgi_interp.h
+++ b/src/server/wsgi_interp.h
@@ -4,7 +4,7 @@
/* ------------------------------------------------------------------------- */
/*
- * Copyright 2007-2014 GRAHAM DUMPLETON
+ * Copyright 2007-2015 GRAHAM DUMPLETON
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -29,6 +29,13 @@
typedef struct {
PyObject_HEAD
PyObject *wrapped;
+} SignalInterceptObject;
+
+extern PyTypeObject SignalIntercept_Type;
+
+typedef struct {
+ PyObject_HEAD
+ PyObject *wrapped;
} ShutdownInterpreterObject;
extern PyTypeObject ShutdownInterpreter_Type;
diff --git a/src/server/wsgi_logger.c b/src/server/wsgi_logger.c
index 5f29704..28f0728 100644
--- a/src/server/wsgi_logger.c
+++ b/src/server/wsgi_logger.c
@@ -1,7 +1,7 @@
/* ------------------------------------------------------------------------- */
/*
- * Copyright 2007-2014 GRAHAM DUMPLETON
+ * Copyright 2007-2015 GRAHAM DUMPLETON
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/src/server/wsgi_logger.h b/src/server/wsgi_logger.h
index 33b2247..319a295 100644
--- a/src/server/wsgi_logger.h
+++ b/src/server/wsgi_logger.h
@@ -4,7 +4,7 @@
/* ------------------------------------------------------------------------- */
/*
- * Copyright 2007-2014 GRAHAM DUMPLETON
+ * Copyright 2007-2015 GRAHAM DUMPLETON
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/src/server/wsgi_metrics.c b/src/server/wsgi_metrics.c
index 4b0ccb0..e888fcf 100644
--- a/src/server/wsgi_metrics.c
+++ b/src/server/wsgi_metrics.c
@@ -1,7 +1,7 @@
/* ------------------------------------------------------------------------- */
/*
- * Copyright 2007-2014 GRAHAM DUMPLETON
+ * Copyright 2007-2015 GRAHAM DUMPLETON
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/src/server/wsgi_metrics.h b/src/server/wsgi_metrics.h
index 2143806..06c5079 100644
--- a/src/server/wsgi_metrics.h
+++ b/src/server/wsgi_metrics.h
@@ -4,7 +4,7 @@
/* ------------------------------------------------------------------------- */
/*
- * Copyright 2007-2014 GRAHAM DUMPLETON
+ * Copyright 2007-2015 GRAHAM DUMPLETON
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/src/server/wsgi_python.h b/src/server/wsgi_python.h
index 8c3841a..0137eab 100644
--- a/src/server/wsgi_python.h
+++ b/src/server/wsgi_python.h
@@ -4,7 +4,7 @@
/* ------------------------------------------------------------------------- */
/*
- * Copyright 2007-2014 GRAHAM DUMPLETON
+ * Copyright 2007-2015 GRAHAM DUMPLETON
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/src/server/wsgi_restrict.c b/src/server/wsgi_restrict.c
index 8267abc..630ced3 100644
--- a/src/server/wsgi_restrict.c
+++ b/src/server/wsgi_restrict.c
@@ -1,7 +1,7 @@
/* ------------------------------------------------------------------------- */
/*
- * Copyright 2007-2014 GRAHAM DUMPLETON
+ * Copyright 2007-2015 GRAHAM DUMPLETON
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/src/server/wsgi_restrict.h b/src/server/wsgi_restrict.h
index a5c8a59..33def94 100644
--- a/src/server/wsgi_restrict.h
+++ b/src/server/wsgi_restrict.h
@@ -4,7 +4,7 @@
/* ------------------------------------------------------------------------- */
/*
- * Copyright 2007-2014 GRAHAM DUMPLETON
+ * Copyright 2007-2015 GRAHAM DUMPLETON
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/src/server/wsgi_server.c b/src/server/wsgi_server.c
index 0d602ca..b6bdf82 100644
--- a/src/server/wsgi_server.c
+++ b/src/server/wsgi_server.c
@@ -1,7 +1,7 @@
/* ------------------------------------------------------------------------- */
/*
- * Copyright 2007-2014 GRAHAM DUMPLETON
+ * Copyright 2007-2015 GRAHAM DUMPLETON
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -34,6 +34,8 @@ const char *wsgi_daemon_group = "";
/* Process information. */
pid_t wsgi_parent_pid = 0;
+pid_t wsgi_worker_pid = 0;
+pid_t wsgi_daemon_pid = 0;
/* New Relic monitoring agent. */
diff --git a/src/server/wsgi_server.h b/src/server/wsgi_server.h
index a9fd74d..d7a27b1 100644
--- a/src/server/wsgi_server.h
+++ b/src/server/wsgi_server.h
@@ -4,7 +4,7 @@
/* ------------------------------------------------------------------------- */
/*
- * Copyright 2007-2014 GRAHAM DUMPLETON
+ * Copyright 2007-2015 GRAHAM DUMPLETON
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -28,6 +28,8 @@
extern server_rec *wsgi_server;
extern pid_t wsgi_parent_pid;
+extern pid_t wsgi_worker_pid;
+extern pid_t wsgi_daemon_pid;
extern const char *wsgi_daemon_group;
/* New Relic monitoring agent. */
@@ -104,6 +106,8 @@ typedef struct {
int chunked_request;
int map_head_to_get;
+ apr_array_header_t *trusted_proxy_headers;
+
int enable_sendfile;
apr_hash_t *handler_scripts;
diff --git a/src/server/wsgi_stream.c b/src/server/wsgi_stream.c
index 3513745..5be4757 100644
--- a/src/server/wsgi_stream.c
+++ b/src/server/wsgi_stream.c
@@ -1,7 +1,7 @@
/* ------------------------------------------------------------------------- */
/*
- * Copyright 2007-2014 GRAHAM DUMPLETON
+ * Copyright 2007-2015 GRAHAM DUMPLETON
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/src/server/wsgi_stream.h b/src/server/wsgi_stream.h
index 2c306fe..ea083e1 100644
--- a/src/server/wsgi_stream.h
+++ b/src/server/wsgi_stream.h
@@ -4,7 +4,7 @@
/* ------------------------------------------------------------------------- */
/*
- * Copyright 2007-2014 GRAHAM DUMPLETON
+ * Copyright 2007-2015 GRAHAM DUMPLETON
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/src/server/wsgi_validate.c b/src/server/wsgi_validate.c
index c72728a..df74b57 100644
--- a/src/server/wsgi_validate.c
+++ b/src/server/wsgi_validate.c
@@ -1,7 +1,7 @@
/* ------------------------------------------------------------------------- */
/*
- * Copyright 2007-2014 GRAHAM DUMPLETON
+ * Copyright 2007-2015 GRAHAM DUMPLETON
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/src/server/wsgi_validate.h b/src/server/wsgi_validate.h
index 33b6922..67fe2cb 100644
--- a/src/server/wsgi_validate.h
+++ b/src/server/wsgi_validate.h
@@ -4,7 +4,7 @@
/* ------------------------------------------------------------------------- */
/*
- * Copyright 2007-2014 GRAHAM DUMPLETON
+ * Copyright 2007-2015 GRAHAM DUMPLETON
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/src/server/wsgi_version.h b/src/server/wsgi_version.h
index 5f1e2ce..08a5cbc 100644
--- a/src/server/wsgi_version.h
+++ b/src/server/wsgi_version.h
@@ -4,7 +4,7 @@
/* ------------------------------------------------------------------------- */
/*
- * Copyright 2007-2014 GRAHAM DUMPLETON
+ * Copyright 2007-2015 GRAHAM DUMPLETON
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -25,8 +25,8 @@
#define MOD_WSGI_MAJORVERSION_NUMBER 4
#define MOD_WSGI_MINORVERSION_NUMBER 4
-#define MOD_WSGI_MICROVERSION_NUMBER 8
-#define MOD_WSGI_VERSION_STRING "4.4.8"
+#define MOD_WSGI_MICROVERSION_NUMBER 9
+#define MOD_WSGI_VERSION_STRING "4.4.9"
/* ------------------------------------------------------------------------- */