summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGraham Dumpleton <Graham.Dumpleton@gmail.com>2022-05-02 11:52:15 +1000
committerGraham Dumpleton <Graham.Dumpleton@gmail.com>2022-05-02 11:52:15 +1000
commit0497f0c29e8dd06608378e6fc814a6037e8c6906 (patch)
treeb1ecfbe7b8ba7ea13bef90abb7b56ba6cf4429e7
parent6eeec45ef8cec1768e5e79368bd04198150cf1f4 (diff)
parent520d94aa701a52bd98efe697ff04a43ad0975739 (diff)
downloadmod_wsgi-0497f0c29e8dd06608378e6fc814a6037e8c6906.tar.gz
Merge branch 'release/4.9.1'4.9.1
-rw-r--r--.github/workflows/main.yml2
-rw-r--r--configure.ac2
-rw-r--r--docs/conf.py2
-rw-r--r--docs/release-notes.rst1
-rw-r--r--docs/release-notes/version-4.4.9.rst4
-rw-r--r--docs/release-notes/version-4.9.1.rst99
-rw-r--r--setup.py3
-rw-r--r--src/server/__init__.py16
-rw-r--r--src/server/management/commands/runmodwsgi.py2
-rw-r--r--src/server/mod_wsgi.c51
-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.c7
-rw-r--r--src/server/wsgi_interp.h2
-rw-r--r--src/server/wsgi_logger.c2
-rw-r--r--src/server/wsgi_logger.h2
-rw-r--r--src/server/wsgi_memory.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.c3
-rw-r--r--src/server/wsgi_server.h3
-rw-r--r--src/server/wsgi_stream.c2
-rw-r--r--src/server/wsgi_stream.h2
-rw-r--r--src/server/wsgi_thread.c2
-rw-r--r--src/server/wsgi_thread.h2
-rw-r--r--src/server/wsgi_validate.c2
-rw-r--r--src/server/wsgi_validate.h2
-rwxr-xr-xsrc/server/wsgi_version.h6
-rw-r--r--tests/events.wsgi22
-rw-r--r--tox.ini3
39 files changed, 230 insertions, 42 deletions
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index e28d76d..c38e733 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -34,7 +34,7 @@ jobs:
strategy:
fail-fast: false
matrix:
- python-version: ["2.7", "3.5", "3.6", "3.7", "3.8", "3.9", "3.10-dev"]
+ python-version: ["2.7", "3.5", "3.6", "3.7", "3.8", "3.9", "3.10", "3.11-dev"]
steps:
- uses: "actions/checkout@v2"
- uses: "actions/setup-python@v2"
diff --git a/configure.ac b/configure.ac
index 37a0f86..25962bc 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,6 +1,6 @@
dnl vim: set sw=4 expandtab :
dnl
-dnl Copyright 2007-2021 GRAHAM DUMPLETON
+dnl Copyright 2007-2022 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 f65d6e3..f0ca969 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'2007-2021, Graham Dumpleton'
+copyright = u'2007-2022, 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/release-notes.rst b/docs/release-notes.rst
index 3df2288..fa6d30c 100644
--- a/docs/release-notes.rst
+++ b/docs/release-notes.rst
@@ -5,6 +5,7 @@ Release Notes
.. toctree::
:maxdepth: 2
+ release-notes/version-4.9.1
release-notes/version-4.9.0
release-notes/version-4.8.0
diff --git a/docs/release-notes/version-4.4.9.rst b/docs/release-notes/version-4.4.9.rst
index a4828c3..b64d626 100644
--- a/docs/release-notes/version-4.4.9.rst
+++ b/docs/release-notes/version-4.4.9.rst
@@ -78,11 +78,11 @@ The header names which are accepted for specifying the target host are
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
+name is ``X-Forwarded-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
+port is ``X-Forwarded-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
diff --git a/docs/release-notes/version-4.9.1.rst b/docs/release-notes/version-4.9.1.rst
new file mode 100644
index 0000000..b6731ff
--- /dev/null
+++ b/docs/release-notes/version-4.9.1.rst
@@ -0,0 +1,99 @@
+=============
+Version 4.9.1
+=============
+
+Version 4.9.1 of mod_wsgi can be obtained from:
+
+ https://codeload.github.com/GrahamDumpleton/mod_wsgi/tar.gz/4.9.1
+
+Bugs Fixed
+----------
+
+* When using ``--enable-debugger`` of mod_wsgi-express to enable Pdb, it was
+ failing due to prior changes to run Apache in a sub processes to avoid Apache
+ being shutdown when the window size changed. This was because standard input
+ was being detached from Apache and so it was not possible to interact with
+ Pdb. Now when ``--enable-debugger`` is used, or any feature which uses
+ ``--debug-mode``, Apache will not be run in a sub process so that you can
+ still use standard input to interact with the process if needed. This does
+ mean that a window size change event will again cause Apache to shutdown in
+ these cases though.
+
+* Update code so compiles on Python 3.11. Python 3.11 makes structures for
+ Python frame objects opaque and requires functions to access struct members.
+
+Features Changed
+----------------
+
+* Historically when a process was being shutdown, mod_wsgi would do its best to
+ destroy any Python sub interpreters as well as the main Python interpreter.
+ This was done in case applications attempted to run any actions on process
+ shutdown via ``atexit`` registered callbacks or other means.
+
+ Because of changes in Python 3.9, and possibly because mod_wsgi makes use of
+ externally created C threads to handle requests, and not Python native
+ threads, there is now a suspiscion that attempting to delete Python sub
+ interpreters can hang. It is believed this may relate to Python core now
+ expecting all Python thread state objects to have been deleted before the
+ Python sub interpreter can be destroyed. If they aren't then Python core
+ code can block indefinitely. If the issue isn't the externally created C
+ threads that mod_wsgi uses, it might instead be arising as a problem when a
+ hosted WSGI application creates its own background threads but they are
+ still running when the attempt is made to destroy the sub interpreter.
+
+ In the case of using daemon mode the result is that processes can hang on
+ shutdown, but will still at least be deleted after 5 seconds due to how
+ Apache process management will forcibly kill managed processes after 5
+ seconds if they do not exit cleanly themselves. In other words the issue
+ may not be noticed.
+
+ For embedded mode however, the Apache child process can hang around
+ indefinitely, possibly only being deleted if some higher level system
+ application manager such as systemd is able to detect the problem and
+ forcibly deleted the hung process.
+
+ Although mod_wsgi always attempts to ensure that the externally created C
+ threads are not still handling HTTP requests and thus not active prior to
+ destroying the Python interpreter, it is impossible to guarantee this.
+ Similarly, there is no way to guarantee that background threads created by a
+ WSGI application aren't still running. As such, it isn't possible to safely
+ attempt to delete the Python thread state objects before deleting the Python
+ sub interpreter.
+
+ Because of this uncertainty mod_wsgi now provides a way to disable the attempt
+ to destroy the Python sub interpreters or the main Python interpreter when the
+ process is being shutdown. This will though mean that ``atexit`` registered
+ callbacks will not be called if this option is enabled. It is therefore
+ important that you use mod_wsgi's own mechanism of being notified when a
+ process is being shutdown to perform any special actions.
+
+ ::
+
+ import mod_wsgi
+
+ def shutdown_handler(event, **kwargs):
+ print('SHUTDOWN-HANDLER', event, kwargs)
+
+ mod_wsgi.subscribe_shutdown(shutdown_handler)
+
+ Use of this shutdown notification was necessary anyway to reliably attempt
+ to stop background threads created by the WSGI application since ``atexit``
+ registered callbacks are not called by Python core until after it thinks all
+ threads have been stopped. In other words, ``atexit`` register callbacks
+ couldn't be used to reliably stop background threads. Thus use of the
+ mod_wsgi mechanism for performing actions on process shutdown is the
+ preferred way.
+
+ Overall it is expected that the majority of users will not notice this
+ change as it is very rare to see WSGI applications want to perform special
+ actions on process shutdown. If you are affected, you should use mod_wsgi's
+ mechanism to perform special actions on process shutdown.
+
+ If you need to enable this mode whereby no attempt is made to destroy the
+ Python interpreter (including sub interpreters) on process shutdown, you can
+ add at global scope in the Apache configuration::
+
+ WSGIDestroyInterpreter Off
+
+ If you are using mod_wsgi-express, you can instead supply the command line
+ option ``--orphan-interpreter``.
diff --git a/setup.py b/setup.py
index 3abcb42..9878047 100644
--- a/setup.py
+++ b/setup.py
@@ -448,6 +448,9 @@ setup(name = package_name,
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
+ 'Programming Language :: Python :: 3.9',
+ 'Programming Language :: Python :: 3.10',
+ 'Programming Language :: Python :: 3.11',
'Topic :: Internet :: WWW/HTTP :: WSGI',
'Topic :: Internet :: WWW/HTTP :: WSGI :: Server'
],
diff --git a/src/server/__init__.py b/src/server/__init__.py
index 5702801..fc632cf 100644
--- a/src/server/__init__.py
+++ b/src/server/__init__.py
@@ -353,6 +353,13 @@ WSGISocketRotation Off
MaxConnectionsPerChild %(maximum_requests)s
</IfDefine>
+<IfDefine ORPHAN_INTERPRETER>
+WSGIDestroyInterpreter Off
+</IfDefine>
+<IfDefine !ORPHAN_INTERPRETER>
+WSGIDestroyInterpreter On
+</IfDefine>
+
<IfDefine !ONE_PROCESS>
<IfDefine !EMBEDDED_MODE>
WSGIRestrictEmbedded On
@@ -2692,6 +2699,10 @@ add_option('unix', '--service-log-file', action='append', nargs=2,
help='Specify the name of a separate log file to be used for '
'the managed service.')
+add_option('all', '--orphan-interpreter', action='store_true',
+ default=False, help='Flag indicating whether should skip over '
+ 'destroying the Python interpreter on process shutdown.')
+
add_option('unix', '--embedded-mode', action='store_true', default=False,
help='Flag indicating whether to run in embedded mode rather '
'than the default daemon mode. Numerous daemon mode specific '
@@ -3348,6 +3359,9 @@ def _cmd_setup_server(command, args, options):
else:
options['https_url'] = None
+ if options['orphan_interpreter']:
+ options['httpd_arguments_list'].append('-DORPHAN_INTERPRETER')
+
if options['embedded_mode']:
options['httpd_arguments_list'].append('-DEMBEDDED_MODE')
options['disable_reloading'] = True
@@ -3662,7 +3676,7 @@ def cmd_start_server(params):
else:
executable = posixpath.join(config['server_root'], 'apachectl')
- if sys.stdout.isatty():
+ if sys.stdout.isatty() and not config['debug_mode']:
process = None
def handler(signum, frame):
diff --git a/src/server/management/commands/runmodwsgi.py b/src/server/management/commands/runmodwsgi.py
index f6d1392..b010dd2 100644
--- a/src/server/management/commands/runmodwsgi.py
+++ b/src/server/management/commands/runmodwsgi.py
@@ -140,7 +140,7 @@ class Command(BaseCommand):
executable = os.path.join(options['server_root'], 'apachectl')
name = executable.ljust(len(options['process_name']))
- if sys.stdout.isatty():
+ if sys.stdout.isatty() and not options['debug_mode']:
process = None
def handler(signum, frame):
diff --git a/src/server/mod_wsgi.c b/src/server/mod_wsgi.c
index 9bef2bd..59aad90 100644
--- a/src/server/mod_wsgi.c
+++ b/src/server/mod_wsgi.c
@@ -1,7 +1,7 @@
/* ------------------------------------------------------------------------- */
/*
- * Copyright 2007-2021 GRAHAM DUMPLETON
+ * Copyright 2007-2022 GRAHAM DUMPLETON
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -4306,6 +4306,11 @@ static apr_status_t wsgi_python_child_cleanup(void *data)
wsgi_publish_process_stopping(wsgi_shutdown_reason);
#endif
+ /* Skip destruction of Python interpreter. */
+
+ if (wsgi_server_config->destroy_interpreter == 0)
+ return APR_SUCCESS;
+
/* In a multithreaded MPM must protect table. */
#if APR_HAS_THREADS
@@ -5043,6 +5048,28 @@ static const char *wsgi_set_python_hash_seed(cmd_parms *cmd, void *mconfig,
return NULL;
}
+static const char *wsgi_set_destroy_interpreter(cmd_parms *cmd, void *mconfig,
+ const char *f)
+{
+ const char *error = NULL;
+ WSGIServerConfig *sconfig = NULL;
+
+ error = ap_check_cmd_context(cmd, GLOBAL_ONLY);
+ if (error != NULL)
+ return error;
+
+ sconfig = ap_get_module_config(cmd->server->module_config, &wsgi_module);
+
+ if (strcasecmp(f, "Off") == 0)
+ sconfig->destroy_interpreter = 0;
+ else if (strcasecmp(f, "On") == 0)
+ sconfig->destroy_interpreter = 1;
+ else
+ return "WSGIDestroyInterpreter must be one of: Off | On";
+
+ return NULL;
+}
+
static const char *wsgi_set_restrict_embedded(cmd_parms *cmd, void *mconfig,
const char *f)
{
@@ -9521,6 +9548,9 @@ static void wsgi_log_stack_traces(void)
const char *filename = NULL;
const char *name = NULL;
+#if PY_MAJOR_VERSION > 3 || (PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION >= 9)
+ lineno = PyFrame_GetLineNumber(current);
+#else
if (current->f_trace) {
lineno = current->f_lineno;
}
@@ -9528,10 +9558,16 @@ static void wsgi_log_stack_traces(void)
lineno = PyCode_Addr2Line(current->f_code,
current->f_lasti);
}
+#endif
#if PY_MAJOR_VERSION >= 3
+#if PY_MAJOR_VERSION > 3 || (PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION >= 9)
+ filename = PyUnicode_AsUTF8(PyFrame_GetCode(current)->co_filename);
+ name = PyUnicode_AsUTF8(PyFrame_GetCode(current)->co_name);
+#else
filename = PyUnicode_AsUTF8(current->f_code->co_filename);
name = PyUnicode_AsUTF8(current->f_code->co_name);
+#endif
#else
filename = PyString_AsString(current->f_code->co_filename);
name = PyString_AsString(current->f_code->co_name);
@@ -9544,7 +9580,11 @@ static void wsgi_log_stack_traces(void)
getpid(), thread_id, filename, lineno, name);
}
else {
+#if PY_MAJOR_VERSION > 3 || (PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION >= 9)
+ if (PyFrame_GetBack(current)) {
+#else
if (current->f_back) {
+#endif
ap_log_error(APLOG_MARK, APLOG_INFO, 0, wsgi_server,
"mod_wsgi (pid=%d): called from file "
"\"%s\", line %d, in %s,", getpid(),
@@ -9558,7 +9598,11 @@ static void wsgi_log_stack_traces(void)
}
}
+#if PY_MAJOR_VERSION > 3 || (PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION >= 9)
+ current = PyFrame_GetBack(current);
+#else
current = current->f_back;
+#endif
}
}
}
@@ -10011,7 +10055,7 @@ static int wsgi_start_process(apr_pool_t *p, WSGIDaemonProcess *daemon)
if (status != APR_SUCCESS) {
ap_log_error(APLOG_MARK, APLOG_CRIT, 0, wsgi_server,
- "mod_wsgi (pid=%d): Couldn't intialise accept "
+ "mod_wsgi (pid=%d): Couldn't initialise accept "
"mutex in daemon process '%s'.",
getpid(), daemon->group->mutex_path);
@@ -16224,6 +16268,9 @@ static const command_rec wsgi_commands[] =
AP_INIT_TAKE1("WSGIPythonHashSeed", wsgi_set_python_hash_seed,
NULL, RSRC_CONF, "Python hash seed."),
+ AP_INIT_TAKE1("WSGIDestroyInterpreter", wsgi_set_destroy_interpreter,
+ NULL, RSRC_CONF, "Enable/Disable destruction of Python interpreter."),
+
#if defined(MOD_WSGI_WITH_DAEMONS)
AP_INIT_TAKE1("WSGIRestrictEmbedded", wsgi_set_restrict_embedded,
NULL, RSRC_CONF, "Enable/Disable use of embedded mode."),
diff --git a/src/server/wsgi_apache.c b/src/server/wsgi_apache.c
index c16d701..955ed41 100644
--- a/src/server/wsgi_apache.c
+++ b/src/server/wsgi_apache.c
@@ -1,7 +1,7 @@
/* ------------------------------------------------------------------------- */
/*
- * Copyright 2007-2021 GRAHAM DUMPLETON
+ * Copyright 2007-2022 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 dca7a0c..4b518f4 100644
--- a/src/server/wsgi_apache.h
+++ b/src/server/wsgi_apache.h
@@ -4,7 +4,7 @@
/* ------------------------------------------------------------------------- */
/*
- * Copyright 2007-2021 GRAHAM DUMPLETON
+ * Copyright 2007-2022 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 85852d1..3f1537e 100644
--- a/src/server/wsgi_buckets.c
+++ b/src/server/wsgi_buckets.c
@@ -1,7 +1,7 @@
/* ------------------------------------------------------------------------- */
/*
- * Copyright 2007-2021 GRAHAM DUMPLETON
+ * Copyright 2007-2022 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 66d7f0b..785ac0e 100644
--- a/src/server/wsgi_buckets.h
+++ b/src/server/wsgi_buckets.h
@@ -4,7 +4,7 @@
/* ------------------------------------------------------------------------- */
/*
- * Copyright 2007-2021 GRAHAM DUMPLETON
+ * Copyright 2007-2022 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 e45ccf5..d41b58c 100644
--- a/src/server/wsgi_convert.c
+++ b/src/server/wsgi_convert.c
@@ -1,7 +1,7 @@
/* ------------------------------------------------------------------------- */
/*
- * Copyright 2007-2021 GRAHAM DUMPLETON
+ * Copyright 2007-2022 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 64824ab..30d2715 100644
--- a/src/server/wsgi_convert.h
+++ b/src/server/wsgi_convert.h
@@ -4,7 +4,7 @@
/* ------------------------------------------------------------------------- */
/*
- * Copyright 2007-2021 GRAHAM DUMPLETON
+ * Copyright 2007-2022 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 d8b262f..3a9f17d 100644
--- a/src/server/wsgi_daemon.c
+++ b/src/server/wsgi_daemon.c
@@ -1,7 +1,7 @@
/* ------------------------------------------------------------------------- */
/*
- * Copyright 2007-2021 GRAHAM DUMPLETON
+ * Copyright 2007-2022 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 d84338a..15bef55 100644
--- a/src/server/wsgi_daemon.h
+++ b/src/server/wsgi_daemon.h
@@ -4,7 +4,7 @@
/* ------------------------------------------------------------------------- */
/*
- * Copyright 2007-2021 GRAHAM DUMPLETON
+ * Copyright 2007-2022 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 027325f..5209040 100644
--- a/src/server/wsgi_interp.c
+++ b/src/server/wsgi_interp.c
@@ -1,7 +1,7 @@
/* ------------------------------------------------------------------------- */
/*
- * Copyright 2007-2021 GRAHAM DUMPLETON
+ * Copyright 2007-2022 GRAHAM DUMPLETON
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -2069,6 +2069,11 @@ apr_status_t wsgi_python_term(void)
{
PyObject *module = NULL;
+ /* Skip destruction of Python interpreter. */
+
+ if (wsgi_server_config->destroy_interpreter == 0)
+ return APR_SUCCESS;
+
ap_log_error(APLOG_MARK, APLOG_INFO, 0, wsgi_server,
"mod_wsgi (pid=%d): Terminating Python.", getpid());
diff --git a/src/server/wsgi_interp.h b/src/server/wsgi_interp.h
index 0a45807..3abb834 100644
--- a/src/server/wsgi_interp.h
+++ b/src/server/wsgi_interp.h
@@ -4,7 +4,7 @@
/* ------------------------------------------------------------------------- */
/*
- * Copyright 2007-2021 GRAHAM DUMPLETON
+ * Copyright 2007-2022 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.c b/src/server/wsgi_logger.c
index c7470a5..d4d4233 100644
--- a/src/server/wsgi_logger.c
+++ b/src/server/wsgi_logger.c
@@ -1,7 +1,7 @@
/* ------------------------------------------------------------------------- */
/*
- * Copyright 2007-2021 GRAHAM DUMPLETON
+ * Copyright 2007-2022 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 1dc937b..7e845ff 100644
--- a/src/server/wsgi_logger.h
+++ b/src/server/wsgi_logger.h
@@ -4,7 +4,7 @@
/* ------------------------------------------------------------------------- */
/*
- * Copyright 2007-2021 GRAHAM DUMPLETON
+ * Copyright 2007-2022 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_memory.h b/src/server/wsgi_memory.h
index 77657e1..c2f2365 100644
--- a/src/server/wsgi_memory.h
+++ b/src/server/wsgi_memory.h
@@ -4,7 +4,7 @@
/* ------------------------------------------------------------------------- */
/*
- * Copyright 2007-2021 GRAHAM DUMPLETON
+ * Copyright 2007-2022 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 5c6d876..7150ef9 100644
--- a/src/server/wsgi_metrics.c
+++ b/src/server/wsgi_metrics.c
@@ -1,7 +1,7 @@
/* ------------------------------------------------------------------------- */
/*
- * Copyright 2007-2021 GRAHAM DUMPLETON
+ * Copyright 2007-2022 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 6e7e915..a136fc5 100644
--- a/src/server/wsgi_metrics.h
+++ b/src/server/wsgi_metrics.h
@@ -4,7 +4,7 @@
/* ------------------------------------------------------------------------- */
/*
- * Copyright 2007-2021 GRAHAM DUMPLETON
+ * Copyright 2007-2022 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 3b34b73..6976ffd 100644
--- a/src/server/wsgi_python.h
+++ b/src/server/wsgi_python.h
@@ -4,7 +4,7 @@
/* ------------------------------------------------------------------------- */
/*
- * Copyright 2007-2021 GRAHAM DUMPLETON
+ * Copyright 2007-2022 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 1a129ea..2bde771 100644
--- a/src/server/wsgi_restrict.c
+++ b/src/server/wsgi_restrict.c
@@ -1,7 +1,7 @@
/* ------------------------------------------------------------------------- */
/*
- * Copyright 2007-2021 GRAHAM DUMPLETON
+ * Copyright 2007-2022 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 a7400fb..c4d86e9 100644
--- a/src/server/wsgi_restrict.h
+++ b/src/server/wsgi_restrict.h
@@ -4,7 +4,7 @@
/* ------------------------------------------------------------------------- */
/*
- * Copyright 2007-2021 GRAHAM DUMPLETON
+ * Copyright 2007-2022 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 2954d4c..8506c2a 100644
--- a/src/server/wsgi_server.c
+++ b/src/server/wsgi_server.c
@@ -1,7 +1,7 @@
/* ------------------------------------------------------------------------- */
/*
- * Copyright 2007-2021 GRAHAM DUMPLETON
+ * Copyright 2007-2022 GRAHAM DUMPLETON
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -101,6 +101,7 @@ WSGIServerConfig *newWSGIServerConfig(apr_pool_t *p)
object->python_hash_seed = NULL;
+ object->destroy_interpreter = -1;
object->restrict_embedded = -1;
object->restrict_stdin = -1;
object->restrict_stdout = -1;
diff --git a/src/server/wsgi_server.h b/src/server/wsgi_server.h
index c433959..0bc842c 100644
--- a/src/server/wsgi_server.h
+++ b/src/server/wsgi_server.h
@@ -4,7 +4,7 @@
/* ------------------------------------------------------------------------- */
/*
- * Copyright 2007-2021 GRAHAM DUMPLETON
+ * Copyright 2007-2022 GRAHAM DUMPLETON
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -87,6 +87,7 @@ typedef struct {
const char *python_hash_seed;
+ int destroy_interpreter;
int restrict_embedded;
int restrict_stdin;
int restrict_stdout;
diff --git a/src/server/wsgi_stream.c b/src/server/wsgi_stream.c
index 39d5842..763bcf5 100644
--- a/src/server/wsgi_stream.c
+++ b/src/server/wsgi_stream.c
@@ -1,7 +1,7 @@
/* ------------------------------------------------------------------------- */
/*
- * Copyright 2007-2021 GRAHAM DUMPLETON
+ * Copyright 2007-2022 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 9ac6582..861e7af 100644
--- a/src/server/wsgi_stream.h
+++ b/src/server/wsgi_stream.h
@@ -4,7 +4,7 @@
/* ------------------------------------------------------------------------- */
/*
- * Copyright 2007-2021 GRAHAM DUMPLETON
+ * Copyright 2007-2022 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_thread.c b/src/server/wsgi_thread.c
index 800cfab..c742e85 100644
--- a/src/server/wsgi_thread.c
+++ b/src/server/wsgi_thread.c
@@ -1,7 +1,7 @@
/* ------------------------------------------------------------------------- */
/*
- * Copyright 2007-2021 GRAHAM DUMPLETON
+ * Copyright 2007-2022 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_thread.h b/src/server/wsgi_thread.h
index eaadf29..eeab38c 100644
--- a/src/server/wsgi_thread.h
+++ b/src/server/wsgi_thread.h
@@ -4,7 +4,7 @@
/* ------------------------------------------------------------------------- */
/*
- * Copyright 2007-2021 GRAHAM DUMPLETON
+ * Copyright 2007-2022 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 d4df896..a37528c 100644
--- a/src/server/wsgi_validate.c
+++ b/src/server/wsgi_validate.c
@@ -1,7 +1,7 @@
/* ------------------------------------------------------------------------- */
/*
- * Copyright 2007-2021 GRAHAM DUMPLETON
+ * Copyright 2007-2022 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 bd1d8cd..90cf082 100644
--- a/src/server/wsgi_validate.h
+++ b/src/server/wsgi_validate.h
@@ -4,7 +4,7 @@
/* ------------------------------------------------------------------------- */
/*
- * Copyright 2007-2021 GRAHAM DUMPLETON
+ * Copyright 2007-2022 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 3cd6a62..793ee81 100755
--- a/src/server/wsgi_version.h
+++ b/src/server/wsgi_version.h
@@ -4,7 +4,7 @@
/* ------------------------------------------------------------------------- */
/*
- * Copyright 2007-2021 GRAHAM DUMPLETON
+ * Copyright 2007-2022 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 9
-#define MOD_WSGI_MICROVERSION_NUMBER 0
-#define MOD_WSGI_VERSION_STRING "4.9.0"
+#define MOD_WSGI_MICROVERSION_NUMBER 1
+#define MOD_WSGI_VERSION_STRING "4.9.1"
/* ------------------------------------------------------------------------- */
diff --git a/tests/events.wsgi b/tests/events.wsgi
index 50b9246..0f7e778 100644
--- a/tests/events.wsgi
+++ b/tests/events.wsgi
@@ -5,6 +5,7 @@ import traceback
import time
import os
import threading
+import atexit
try:
mod_wsgi.request_data()
@@ -18,7 +19,7 @@ def wrapper(application):
return _application
def event_handler(name, **kwargs):
- print('EVENT', name, kwargs, os.getpid(), mod_wsgi.application_group)
+ print('EVENT-HANDLER', name, kwargs, os.getpid(), mod_wsgi.application_group)
if name == 'request_started':
thread = threading.current_thread()
request_data = kwargs['request_data']
@@ -35,12 +36,27 @@ def event_handler(name, **kwargs):
elif name == 'process_stopping':
print('SHUTDOWN', mod_wsgi.active_requests)
-print('EVENTS', mod_wsgi.event_callbacks)
+print('EVENTS#ALL', mod_wsgi.event_callbacks)
mod_wsgi.subscribe_events(event_handler)
+def shutdown_handler(event, **kwargs):
+ print('SHUTDOWN-HANDLER', event, kwargs)
+
+print('EVENTS#SHUTDOWN', mod_wsgi.event_callbacks)
+
+mod_wsgi.subscribe_shutdown(shutdown_handler)
+
print('CALLBACKS', mod_wsgi.event_callbacks)
+def atexit_handler():
+ print('ATEXIT-HANDLER')
+
+atexit.register(atexit_handler)
+
+def do_sleep(duration):
+ time.sleep(duration)
+
def application(environ, start_response):
failure_mode = environ.get('HTTP_X_FAILURE_MODE', '')
failure_mode = failure_mode.split()
@@ -61,7 +77,7 @@ def application(environ, start_response):
environ['wsgi.input'].read()
if sleep_duration:
- time.sleep(sleep_duration)
+ do_sleep(sleep_duration)
try:
yield output
diff --git a/tox.ini b/tox.ini
index b215c1e..acdfe7e 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,5 +1,5 @@
[tox]
-envlist = py26,py27,py33,py34,py35,py36,py37,py38,py39,py310
+envlist = py26,py27,py33,py34,py35,py36,py37,py38,py39,py310,py311
[gh-actions]
python =
@@ -10,3 +10,4 @@ python =
3.8: py38
3.9: py39
3.10: py310
+ 3.11: py311