mod-wsgi 6.0.1__tar.gz → 6.0.3.dev1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {mod_wsgi-6.0.1 → mod_wsgi-6.0.3.dev1}/PKG-INFO +1 -1
- {mod_wsgi-6.0.1 → mod_wsgi-6.0.3.dev1}/mod_wsgi.egg-info/PKG-INFO +1 -1
- {mod_wsgi-6.0.1 → mod_wsgi-6.0.3.dev1}/setup.py +1 -1
- {mod_wsgi-6.0.1 → mod_wsgi-6.0.3.dev1}/src/express/apache.py +2 -0
- {mod_wsgi-6.0.1 → mod_wsgi-6.0.3.dev1}/src/express/cli.py +27 -5
- {mod_wsgi-6.0.1 → mod_wsgi-6.0.3.dev1}/src/express/options.py +22 -8
- {mod_wsgi-6.0.1 → mod_wsgi-6.0.3.dev1}/src/express/platform.py +1 -1
- {mod_wsgi-6.0.1 → mod_wsgi-6.0.3.dev1}/src/express/reloader.py +11 -0
- {mod_wsgi-6.0.1 → mod_wsgi-6.0.3.dev1}/src/express/server.py +10 -7
- {mod_wsgi-6.0.1 → mod_wsgi-6.0.3.dev1}/src/server/mod_wsgi.c +14 -23
- {mod_wsgi-6.0.1 → mod_wsgi-6.0.3.dev1}/src/server/wsgi_config.c +6 -0
- {mod_wsgi-6.0.1 → mod_wsgi-6.0.3.dev1}/src/server/wsgi_daemon.c +20 -0
- {mod_wsgi-6.0.1 → mod_wsgi-6.0.3.dev1}/src/server/wsgi_daemon.h +1 -0
- {mod_wsgi-6.0.1 → mod_wsgi-6.0.3.dev1}/src/server/wsgi_remote.c +101 -45
- {mod_wsgi-6.0.1 → mod_wsgi-6.0.3.dev1}/src/server/wsgi_version.h +2 -2
- {mod_wsgi-6.0.1 → mod_wsgi-6.0.3.dev1}/CREDITS.rst +0 -0
- {mod_wsgi-6.0.1 → mod_wsgi-6.0.3.dev1}/LICENSE +0 -0
- {mod_wsgi-6.0.1 → mod_wsgi-6.0.3.dev1}/MANIFEST.in +0 -0
- {mod_wsgi-6.0.1 → mod_wsgi-6.0.3.dev1}/Makefile.in +0 -0
- {mod_wsgi-6.0.1 → mod_wsgi-6.0.3.dev1}/README-express.rst +0 -0
- {mod_wsgi-6.0.1 → mod_wsgi-6.0.3.dev1}/README-standalone.rst +0 -0
- {mod_wsgi-6.0.1 → mod_wsgi-6.0.3.dev1}/README.rst +0 -0
- {mod_wsgi-6.0.1 → mod_wsgi-6.0.3.dev1}/configure +0 -0
- {mod_wsgi-6.0.1 → mod_wsgi-6.0.3.dev1}/configure.ac +0 -0
- {mod_wsgi-6.0.1 → mod_wsgi-6.0.3.dev1}/images/__init__.py +0 -0
- {mod_wsgi-6.0.1 → mod_wsgi-6.0.3.dev1}/images/snake-whiskey.jpg +0 -0
- {mod_wsgi-6.0.1 → mod_wsgi-6.0.3.dev1}/mod_wsgi.egg-info/SOURCES.txt +0 -0
- {mod_wsgi-6.0.1 → mod_wsgi-6.0.3.dev1}/mod_wsgi.egg-info/dependency_links.txt +0 -0
- {mod_wsgi-6.0.1 → mod_wsgi-6.0.3.dev1}/mod_wsgi.egg-info/entry_points.txt +0 -0
- {mod_wsgi-6.0.1 → mod_wsgi-6.0.3.dev1}/mod_wsgi.egg-info/not-zip-safe +0 -0
- {mod_wsgi-6.0.1 → mod_wsgi-6.0.3.dev1}/mod_wsgi.egg-info/top_level.txt +0 -0
- {mod_wsgi-6.0.1 → mod_wsgi-6.0.3.dev1}/setup.cfg +0 -0
- {mod_wsgi-6.0.1 → mod_wsgi-6.0.3.dev1}/src/__init__.py +0 -0
- {mod_wsgi-6.0.1 → mod_wsgi-6.0.3.dev1}/src/diagnostics/__init__.py +0 -0
- {mod_wsgi-6.0.1 → mod_wsgi-6.0.3.dev1}/src/diagnostics/environ.py +0 -0
- {mod_wsgi-6.0.1 → mod_wsgi-6.0.3.dev1}/src/diagnostics/hello.py +0 -0
- {mod_wsgi-6.0.1 → mod_wsgi-6.0.3.dev1}/src/express/__init__.py +0 -0
- {mod_wsgi-6.0.1 → mod_wsgi-6.0.3.dev1}/src/express/management/__init__.py +0 -0
- {mod_wsgi-6.0.1 → mod_wsgi-6.0.3.dev1}/src/express/management/commands/__init__.py +0 -0
- {mod_wsgi-6.0.1 → mod_wsgi-6.0.3.dev1}/src/express/management/commands/runmodwsgi.py +0 -0
- {mod_wsgi-6.0.1 → mod_wsgi-6.0.3.dev1}/src/express/runtime.py +0 -0
- {mod_wsgi-6.0.1 → mod_wsgi-6.0.3.dev1}/src/express/scripts.py +0 -0
- {mod_wsgi-6.0.1 → mod_wsgi-6.0.3.dev1}/src/server/__init__.py +0 -0
- {mod_wsgi-6.0.1 → mod_wsgi-6.0.3.dev1}/src/server/management/__init__.py +0 -0
- {mod_wsgi-6.0.1 → mod_wsgi-6.0.3.dev1}/src/server/management/commands/__init__.py +0 -0
- {mod_wsgi-6.0.1 → mod_wsgi-6.0.3.dev1}/src/server/management/commands/runmodwsgi.py +0 -0
- {mod_wsgi-6.0.1 → mod_wsgi-6.0.3.dev1}/src/server/wsgi_adapter.c +0 -0
- {mod_wsgi-6.0.1 → mod_wsgi-6.0.3.dev1}/src/server/wsgi_adapter.h +0 -0
- {mod_wsgi-6.0.1 → mod_wsgi-6.0.3.dev1}/src/server/wsgi_apache.c +0 -0
- {mod_wsgi-6.0.1 → mod_wsgi-6.0.3.dev1}/src/server/wsgi_apache.h +0 -0
- {mod_wsgi-6.0.1 → mod_wsgi-6.0.3.dev1}/src/server/wsgi_auth.c +0 -0
- {mod_wsgi-6.0.1 → mod_wsgi-6.0.3.dev1}/src/server/wsgi_auth.h +0 -0
- {mod_wsgi-6.0.1 → mod_wsgi-6.0.3.dev1}/src/server/wsgi_buckets.c +0 -0
- {mod_wsgi-6.0.1 → mod_wsgi-6.0.3.dev1}/src/server/wsgi_buckets.h +0 -0
- {mod_wsgi-6.0.1 → mod_wsgi-6.0.3.dev1}/src/server/wsgi_config.h +0 -0
- {mod_wsgi-6.0.1 → mod_wsgi-6.0.3.dev1}/src/server/wsgi_convert.c +0 -0
- {mod_wsgi-6.0.1 → mod_wsgi-6.0.3.dev1}/src/server/wsgi_convert.h +0 -0
- {mod_wsgi-6.0.1 → mod_wsgi-6.0.3.dev1}/src/server/wsgi_dispatch.c +0 -0
- {mod_wsgi-6.0.1 → mod_wsgi-6.0.3.dev1}/src/server/wsgi_dispatch.h +0 -0
- {mod_wsgi-6.0.1 → mod_wsgi-6.0.3.dev1}/src/server/wsgi_environ.c +0 -0
- {mod_wsgi-6.0.1 → mod_wsgi-6.0.3.dev1}/src/server/wsgi_environ.h +0 -0
- {mod_wsgi-6.0.1 → mod_wsgi-6.0.3.dev1}/src/server/wsgi_execute.c +0 -0
- {mod_wsgi-6.0.1 → mod_wsgi-6.0.3.dev1}/src/server/wsgi_execute.h +0 -0
- {mod_wsgi-6.0.1 → mod_wsgi-6.0.3.dev1}/src/server/wsgi_gc.c +0 -0
- {mod_wsgi-6.0.1 → mod_wsgi-6.0.3.dev1}/src/server/wsgi_gc.h +0 -0
- {mod_wsgi-6.0.1 → mod_wsgi-6.0.3.dev1}/src/server/wsgi_input.c +0 -0
- {mod_wsgi-6.0.1 → mod_wsgi-6.0.3.dev1}/src/server/wsgi_input.h +0 -0
- {mod_wsgi-6.0.1 → mod_wsgi-6.0.3.dev1}/src/server/wsgi_interp.c +0 -0
- {mod_wsgi-6.0.1 → mod_wsgi-6.0.3.dev1}/src/server/wsgi_interp.h +0 -0
- {mod_wsgi-6.0.1 → mod_wsgi-6.0.3.dev1}/src/server/wsgi_logger.c +0 -0
- {mod_wsgi-6.0.1 → mod_wsgi-6.0.3.dev1}/src/server/wsgi_logger.h +0 -0
- {mod_wsgi-6.0.1 → mod_wsgi-6.0.3.dev1}/src/server/wsgi_memory.c +0 -0
- {mod_wsgi-6.0.1 → mod_wsgi-6.0.3.dev1}/src/server/wsgi_memory.h +0 -0
- {mod_wsgi-6.0.1 → mod_wsgi-6.0.3.dev1}/src/server/wsgi_metrics.c +0 -0
- {mod_wsgi-6.0.1 → mod_wsgi-6.0.3.dev1}/src/server/wsgi_metrics.h +0 -0
- {mod_wsgi-6.0.1 → mod_wsgi-6.0.3.dev1}/src/server/wsgi_module.c +0 -0
- {mod_wsgi-6.0.1 → mod_wsgi-6.0.3.dev1}/src/server/wsgi_module.h +0 -0
- {mod_wsgi-6.0.1 → mod_wsgi-6.0.3.dev1}/src/server/wsgi_python.h +0 -0
- {mod_wsgi-6.0.1 → mod_wsgi-6.0.3.dev1}/src/server/wsgi_remote.h +0 -0
- {mod_wsgi-6.0.1 → mod_wsgi-6.0.3.dev1}/src/server/wsgi_restrict.c +0 -0
- {mod_wsgi-6.0.1 → mod_wsgi-6.0.3.dev1}/src/server/wsgi_restrict.h +0 -0
- {mod_wsgi-6.0.1 → mod_wsgi-6.0.3.dev1}/src/server/wsgi_server.c +0 -0
- {mod_wsgi-6.0.1 → mod_wsgi-6.0.3.dev1}/src/server/wsgi_server.h +0 -0
- {mod_wsgi-6.0.1 → mod_wsgi-6.0.3.dev1}/src/server/wsgi_shutdown.c +0 -0
- {mod_wsgi-6.0.1 → mod_wsgi-6.0.3.dev1}/src/server/wsgi_shutdown.h +0 -0
- {mod_wsgi-6.0.1 → mod_wsgi-6.0.3.dev1}/src/server/wsgi_signal.c +0 -0
- {mod_wsgi-6.0.1 → mod_wsgi-6.0.3.dev1}/src/server/wsgi_signal.h +0 -0
- {mod_wsgi-6.0.1 → mod_wsgi-6.0.3.dev1}/src/server/wsgi_stream.c +0 -0
- {mod_wsgi-6.0.1 → mod_wsgi-6.0.3.dev1}/src/server/wsgi_stream.h +0 -0
- {mod_wsgi-6.0.1 → mod_wsgi-6.0.3.dev1}/src/server/wsgi_telemetry.c +0 -0
- {mod_wsgi-6.0.1 → mod_wsgi-6.0.3.dev1}/src/server/wsgi_telemetry.h +0 -0
- {mod_wsgi-6.0.1 → mod_wsgi-6.0.3.dev1}/src/server/wsgi_thread.c +0 -0
- {mod_wsgi-6.0.1 → mod_wsgi-6.0.3.dev1}/src/server/wsgi_thread.h +0 -0
- {mod_wsgi-6.0.1 → mod_wsgi-6.0.3.dev1}/src/server/wsgi_validate.c +0 -0
- {mod_wsgi-6.0.1 → mod_wsgi-6.0.3.dev1}/src/server/wsgi_validate.h +0 -0
|
@@ -456,6 +456,6 @@ setup(name = package_name,
|
|
|
456
456
|
entry_points = { 'console_scripts':
|
|
457
457
|
['mod_wsgi-express = mod_wsgi.express.cli:main'],},
|
|
458
458
|
zip_safe = False,
|
|
459
|
-
install_requires = standalone and ['mod_wsgi-httpd==2.4.
|
|
459
|
+
install_requires = standalone and ['mod_wsgi-httpd==2.4.68.1'] or [],
|
|
460
460
|
python_requires='>=3.10',
|
|
461
461
|
)
|
|
@@ -243,6 +243,7 @@ WSGIDaemonProcess %(process_group)s \\
|
|
|
243
243
|
header-buffer-size=%(header_buffer_size)s \\
|
|
244
244
|
response-buffer-size=%(response_buffer_size)s \\
|
|
245
245
|
response-socket-timeout=%(response_socket_timeout)s \\
|
|
246
|
+
response-flush-delay=%(response_flush_delay)s \\
|
|
246
247
|
server-metrics=%(server_metrics_flag)s%(daemon_switch_interval_option)s
|
|
247
248
|
</IfDefine>
|
|
248
249
|
<IfDefine !MOD_WSGI_MULTIPROCESS>
|
|
@@ -273,6 +274,7 @@ WSGIDaemonProcess %(process_group)s \\
|
|
|
273
274
|
receive-buffer-size=%(receive_buffer_size)s \\
|
|
274
275
|
response-buffer-size=%(response_buffer_size)s \\
|
|
275
276
|
response-socket-timeout=%(response_socket_timeout)s \\
|
|
277
|
+
response-flush-delay=%(response_flush_delay)s \\
|
|
276
278
|
server-metrics=%(server_metrics_flag)s%(daemon_switch_interval_option)s
|
|
277
279
|
</IfDefine>
|
|
278
280
|
</IfDefine>
|
|
@@ -67,11 +67,33 @@ def cmd_start_server(params):
|
|
|
67
67
|
httpd_arguments.extend(['-f', config['httpd_conf']])
|
|
68
68
|
httpd_arguments.extend(['-DONE_PROCESS'])
|
|
69
69
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
70
|
+
# On Windows httpd shares our console, so a Ctrl-C delivers a
|
|
71
|
+
# CTRL_C_EVENT to the whole console process group and httpd runs
|
|
72
|
+
# its own graceful shutdown. We must not let the same Ctrl-C kill
|
|
73
|
+
# this launcher first, or it returns to the shell while httpd is
|
|
74
|
+
# still tearing down (and dumps a KeyboardInterrupt traceback). So
|
|
75
|
+
# absorb our own interrupt and keep waiting until httpd exits.
|
|
76
|
+
#
|
|
77
|
+
# A first Ctrl-C is treated as "you should have received the
|
|
78
|
+
# console event, shutting down gracefully, I will wait". If httpd
|
|
79
|
+
# did not actually receive the event (for example a git-bash pty
|
|
80
|
+
# bridge that does not forward it to the child), a second Ctrl-C
|
|
81
|
+
# escalates to terminating it so we cannot hang indefinitely.
|
|
82
|
+
|
|
83
|
+
process = subprocess.Popen([executable]+httpd_arguments, env=environ)
|
|
84
|
+
|
|
85
|
+
interrupts = 0
|
|
86
|
+
|
|
87
|
+
while True:
|
|
88
|
+
try:
|
|
89
|
+
process.wait()
|
|
90
|
+
break
|
|
91
|
+
except KeyboardInterrupt:
|
|
92
|
+
interrupts += 1
|
|
93
|
+
if interrupts >= 2:
|
|
94
|
+
process.terminate()
|
|
95
|
+
|
|
96
|
+
sys.exit(process.returncode)
|
|
75
97
|
|
|
76
98
|
else:
|
|
77
99
|
executable = posixpath.join(config['server_root'], 'apachectl')
|
|
@@ -395,18 +395,32 @@ add_option('unix', '--header-buffer-size', type='int', default=0,
|
|
|
395
395
|
'indicating internal default of 32768 bytes is used.')
|
|
396
396
|
|
|
397
397
|
add_option('unix', '--response-buffer-size', type='int', default=0,
|
|
398
|
-
metavar='NUMBER', help='
|
|
399
|
-
'
|
|
400
|
-
'
|
|
401
|
-
'process.
|
|
402
|
-
'
|
|
398
|
+
metavar='NUMBER', help='Coarse upper bound, in bytes, on how '
|
|
399
|
+
'much response content is passed down the output filter chain '
|
|
400
|
+
'without a flush when proxying the response from a daemon '
|
|
401
|
+
'process. Only bounds a downstream filter that buffers without '
|
|
402
|
+
'draining; the Apache core output filter handles normal memory '
|
|
403
|
+
'bounding. Defaults to 0, indicating the internal default of '
|
|
404
|
+
'8388608 bytes (8 MB) is used. Setting it low can interfere with '
|
|
405
|
+
'a downstream pacing filter such as mod_ratelimit.')
|
|
403
406
|
|
|
404
407
|
add_option('unix', '--response-socket-timeout', type='int', default=0,
|
|
405
408
|
metavar='SECONDS', help='Maximum number of seconds allowed '
|
|
406
409
|
'to pass before timing out on a write operation back to the '
|
|
407
|
-
'HTTP client when the response
|
|
408
|
-
'
|
|
409
|
-
'
|
|
410
|
+
'HTTP client when transferring the response body. Defaults to 0 '
|
|
411
|
+
'seconds indicating that it will default to the value of the '
|
|
412
|
+
'\'socket-timeout\' option.')
|
|
413
|
+
|
|
414
|
+
add_option('unix', '--response-flush-delay', type='int', default=5,
|
|
415
|
+
metavar='MILLISECONDS', help='Number of milliseconds mod_wsgi '
|
|
416
|
+
'will wait for further response data from a daemon process before '
|
|
417
|
+
'flushing what it has to the HTTP client. Waiting briefly lets a '
|
|
418
|
+
'downstream output filter such as mod_ratelimit pace or batch the '
|
|
419
|
+
'response correctly instead of being forced to emit a short write '
|
|
420
|
+
'on every momentary stall. Defaults to 5 milliseconds. Setting it '
|
|
421
|
+
'to 0 flushes on any stall and is not recommended when a pacing '
|
|
422
|
+
'filter such as mod_ratelimit is in use, as it can throttle '
|
|
423
|
+
'responses far below the configured rate.')
|
|
410
424
|
|
|
411
425
|
add_option('all', '--enable-sendfile', action='store_true',
|
|
412
426
|
default=False, help='Flag indicating whether sendfile() support '
|
|
@@ -82,7 +82,7 @@ def default_run_group():
|
|
|
82
82
|
|
|
83
83
|
def find_program(names, default=None, paths=[]):
|
|
84
84
|
for name in names:
|
|
85
|
-
for path in os.environ['PATH'].split(
|
|
85
|
+
for path in os.environ['PATH'].split(os.pathsep) + paths:
|
|
86
86
|
program = posixpath.join(path, name)
|
|
87
87
|
if os.path.exists(program):
|
|
88
88
|
return program
|
|
@@ -97,6 +97,17 @@ def track_changes(path):
|
|
|
97
97
|
_files.append(path)
|
|
98
98
|
|
|
99
99
|
def start_reloader(interval=1.0):
|
|
100
|
+
# The reloader triggers a restart by sending SIGINT to this process. On
|
|
101
|
+
# Windows os.kill() cannot deliver SIGINT to ourselves: any signal other
|
|
102
|
+
# than CTRL_C_EVENT/CTRL_BREAK_EVENT is implemented as an unconditional
|
|
103
|
+
# TerminateProcess, so the reloader would hard kill the server rather than
|
|
104
|
+
# trigger a graceful restart. Disable it on Windows.
|
|
105
|
+
if os.name == 'nt':
|
|
106
|
+
prefix = 'monitor (pid=%d):' % os.getpid()
|
|
107
|
+
print('%s Source code reloading is not supported on Windows.' % prefix,
|
|
108
|
+
file=sys.stderr)
|
|
109
|
+
return
|
|
110
|
+
|
|
100
111
|
global _interval
|
|
101
112
|
if interval < _interval:
|
|
102
113
|
_interval = interval
|
|
@@ -255,14 +255,17 @@ def setup_server(command, args, options):
|
|
|
255
255
|
options['access_log_file'] = posixpath.join(
|
|
256
256
|
options['log_directory'], options['access_log_name'])
|
|
257
257
|
else:
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
pass
|
|
261
|
-
except IOError:
|
|
262
|
-
options['access_log_file'] = '|%s' % find_program(
|
|
263
|
-
['tee'], default='tee')
|
|
258
|
+
if os.name == 'nt':
|
|
259
|
+
options['access_log_file'] = 'CON'
|
|
264
260
|
else:
|
|
265
|
-
|
|
261
|
+
try:
|
|
262
|
+
with open('/dev/stdout', 'w'):
|
|
263
|
+
pass
|
|
264
|
+
except IOError:
|
|
265
|
+
options['access_log_file'] = '|%s' % find_program(
|
|
266
|
+
['tee'], default='tee')
|
|
267
|
+
else:
|
|
268
|
+
options['access_log_file'] = '/dev/stdout'
|
|
266
269
|
|
|
267
270
|
if options['access_log_format']:
|
|
268
271
|
if options['access_log_format'] in ('common', 'combined'):
|
|
@@ -793,6 +793,20 @@ static int wsgi_hook_handler(request_rec *r)
|
|
|
793
793
|
return HTTP_INTERNAL_SERVER_ERROR;
|
|
794
794
|
}
|
|
795
795
|
|
|
796
|
+
/*
|
|
797
|
+
* Embedded execution needs a Python interpreter in this child. If
|
|
798
|
+
* one was never initialised (or initialisation failed), the
|
|
799
|
+
* per-thread state used by wsgi_execute_script() does not exist and
|
|
800
|
+
* running it would crash the process, so refuse the request.
|
|
801
|
+
*/
|
|
802
|
+
|
|
803
|
+
if (!wsgi_python_initialized)
|
|
804
|
+
{
|
|
805
|
+
wsgi_log_rerror(APLOG_ERR, 0, r, WSGI_APLOGNO(0210) "Embedded mode of mod_wsgi cannot be used as Python "
|
|
806
|
+
"was not initialised in this process.");
|
|
807
|
+
return HTTP_INTERNAL_SERVER_ERROR;
|
|
808
|
+
}
|
|
809
|
+
|
|
796
810
|
return wsgi_execute_script(r);
|
|
797
811
|
}
|
|
798
812
|
|
|
@@ -1262,27 +1276,4 @@ module AP_MODULE_DECLARE_DATA wsgi_module = {
|
|
|
1262
1276
|
|
|
1263
1277
|
/* ------------------------------------------------------------------------- */
|
|
1264
1278
|
|
|
1265
|
-
#if defined(_WIN32)
|
|
1266
|
-
PyMODINIT_FUNC PyInit_mod_wsgi(void)
|
|
1267
|
-
{
|
|
1268
|
-
/* The 'mod_wsgi' Python module is created at runtime by the Apache
|
|
1269
|
-
* module when it sets up each interpreter; it is not a regular
|
|
1270
|
-
* Python extension and cannot be imported from a standalone Python
|
|
1271
|
-
* process. This stub exists only to satisfy the Windows linker and
|
|
1272
|
-
* is not expected to be reached. Set an explicit ImportError so the
|
|
1273
|
-
* importer reports the actual situation instead of the generic
|
|
1274
|
-
* "initialization of mod_wsgi failed without raising an exception"
|
|
1275
|
-
* SystemError. */
|
|
1276
|
-
|
|
1277
|
-
PyErr_SetString(PyExc_ImportError,
|
|
1278
|
-
"mod_wsgi cannot be imported as a regular Python "
|
|
1279
|
-
"module; it is provided by the Apache mod_wsgi "
|
|
1280
|
-
"module and is only available inside an Apache "
|
|
1281
|
-
"process running mod_wsgi.");
|
|
1282
|
-
return NULL;
|
|
1283
|
-
}
|
|
1284
|
-
#endif
|
|
1285
|
-
|
|
1286
|
-
/* ------------------------------------------------------------------------- */
|
|
1287
|
-
|
|
1288
1279
|
/* vi: set sw=4 expandtab : */
|
|
@@ -778,6 +778,12 @@ const char *wsgi_set_restrict_embedded(cmd_parms *cmd, void *mconfig,
|
|
|
778
778
|
if (wsgi_python_required == -1)
|
|
779
779
|
wsgi_python_required = 0;
|
|
780
780
|
}
|
|
781
|
+
else
|
|
782
|
+
{
|
|
783
|
+
/* Embedded mode enabled, so Python is needed in the child. */
|
|
784
|
+
|
|
785
|
+
wsgi_python_required = 1;
|
|
786
|
+
}
|
|
781
787
|
|
|
782
788
|
return NULL;
|
|
783
789
|
}
|
|
@@ -149,6 +149,8 @@ const char *wsgi_add_daemon_process(cmd_parms *cmd, void *mconfig,
|
|
|
149
149
|
|
|
150
150
|
int response_socket_timeout = 0;
|
|
151
151
|
|
|
152
|
+
int response_flush_delay = -1;
|
|
153
|
+
|
|
152
154
|
const char *script_user = NULL;
|
|
153
155
|
const char *script_group = NULL;
|
|
154
156
|
|
|
@@ -510,6 +512,17 @@ const char *wsgi_add_daemon_process(cmd_parms *cmd, void *mconfig,
|
|
|
510
512
|
if (response_socket_timeout < 0)
|
|
511
513
|
return "Invalid response socket timeout for WSGI daemon process.";
|
|
512
514
|
}
|
|
515
|
+
else if (!strcmp(option, "response-flush-delay"))
|
|
516
|
+
{
|
|
517
|
+
if (!*value)
|
|
518
|
+
return "Invalid response flush delay for WSGI daemon process.";
|
|
519
|
+
|
|
520
|
+
/* Value is in milliseconds; 0 disables the delay. */
|
|
521
|
+
|
|
522
|
+
response_flush_delay = atoi(value);
|
|
523
|
+
if (response_flush_delay < 0)
|
|
524
|
+
return "Invalid response flush delay for WSGI daemon process.";
|
|
525
|
+
}
|
|
513
526
|
else if (!strcmp(option, "socket-user"))
|
|
514
527
|
{
|
|
515
528
|
uid_t socket_uid;
|
|
@@ -741,6 +754,13 @@ const char *wsgi_add_daemon_process(cmd_parms *cmd, void *mconfig,
|
|
|
741
754
|
|
|
742
755
|
entry->response_socket_timeout = apr_time_from_sec(response_socket_timeout);
|
|
743
756
|
|
|
757
|
+
/* Default the response flush delay to 5 milliseconds. */
|
|
758
|
+
|
|
759
|
+
if (response_flush_delay < 0)
|
|
760
|
+
response_flush_delay = 5;
|
|
761
|
+
|
|
762
|
+
entry->response_flush_delay = apr_time_from_msec(response_flush_delay);
|
|
763
|
+
|
|
744
764
|
entry->script_user = script_user;
|
|
745
765
|
entry->script_group = script_group;
|
|
746
766
|
|
|
@@ -803,7 +803,9 @@ static int wsgi_scan_headers_brigade(request_rec *r, apr_bucket_brigade *bb,
|
|
|
803
803
|
}
|
|
804
804
|
|
|
805
805
|
static int wsgi_transfer_response(request_rec *r, apr_bucket_brigade *bb,
|
|
806
|
-
apr_size_t buffer_size, apr_time_t timeout
|
|
806
|
+
apr_size_t buffer_size, apr_time_t timeout,
|
|
807
|
+
apr_socket_t *daemon_socket,
|
|
808
|
+
apr_time_t flush_delay)
|
|
807
809
|
{
|
|
808
810
|
apr_bucket *e;
|
|
809
811
|
apr_read_type_e mode = APR_NONBLOCK_READ;
|
|
@@ -815,15 +817,24 @@ static int wsgi_transfer_response(request_rec *r, apr_bucket_brigade *bb,
|
|
|
815
817
|
|
|
816
818
|
apr_size_t bytes_transfered = 0;
|
|
817
819
|
|
|
818
|
-
int bucket_count = 0;
|
|
819
|
-
|
|
820
820
|
apr_status_t rv;
|
|
821
821
|
|
|
822
822
|
apr_socket_t *sock;
|
|
823
823
|
apr_interval_time_t existing_timeout = 0;
|
|
824
824
|
|
|
825
|
+
apr_interval_time_t daemon_timeout = 0;
|
|
826
|
+
int lingering = 0;
|
|
827
|
+
|
|
828
|
+
/*
|
|
829
|
+
* response-buffer-size bounds how many bytes of response content
|
|
830
|
+
* may be passed downstream without a flush, acting as a coarse
|
|
831
|
+
* runaway guard (see where it is applied below). Zero selects the
|
|
832
|
+
* default, which is high enough that the guard does not affect
|
|
833
|
+
* normal operation.
|
|
834
|
+
*/
|
|
835
|
+
|
|
825
836
|
if (buffer_size == 0)
|
|
826
|
-
buffer_size =
|
|
837
|
+
buffer_size = 8 * 1024 * 1024;
|
|
827
838
|
|
|
828
839
|
/*
|
|
829
840
|
* Override the socket timeout for writing back data to the
|
|
@@ -851,15 +862,22 @@ static int wsgi_transfer_response(request_rec *r, apr_bucket_brigade *bb,
|
|
|
851
862
|
}
|
|
852
863
|
|
|
853
864
|
/*
|
|
854
|
-
*
|
|
855
|
-
*
|
|
856
|
-
*
|
|
857
|
-
*
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
865
|
+
* When a response flush delay is configured, remember the daemon
|
|
866
|
+
* socket's current read timeout. While lingering for more data we
|
|
867
|
+
* lower it to the flush delay and restore it afterwards. Guard
|
|
868
|
+
* against a NULL daemon socket by disabling the linger.
|
|
869
|
+
*/
|
|
870
|
+
|
|
871
|
+
if (!daemon_socket)
|
|
872
|
+
flush_delay = 0;
|
|
873
|
+
|
|
874
|
+
if (flush_delay)
|
|
875
|
+
apr_socket_timeout_get(daemon_socket, &daemon_timeout);
|
|
876
|
+
|
|
877
|
+
/*
|
|
878
|
+
* Transfer the response content back to the client, reading it
|
|
879
|
+
* from the daemon a block at a time and passing each block down
|
|
880
|
+
* the output filter chain.
|
|
863
881
|
*/
|
|
864
882
|
|
|
865
883
|
tmpbb = apr_brigade_create(r->pool, r->connection->bucket_alloc);
|
|
@@ -923,13 +941,46 @@ static int wsgi_transfer_response(request_rec *r, apr_bucket_brigade *bb,
|
|
|
923
941
|
rv = apr_bucket_read(e, &data, &length, mode);
|
|
924
942
|
|
|
925
943
|
/*
|
|
926
|
-
*
|
|
927
|
-
*
|
|
928
|
-
*
|
|
944
|
+
* A non-blocking read returned no data. Rather than flushing
|
|
945
|
+
* immediately, which would force any downstream pacing filter
|
|
946
|
+
* such as mod_ratelimit to emit a short write and so defeat
|
|
947
|
+
* its rate calculation, first wait a bounded flush delay for
|
|
948
|
+
* more data using a blocking read with a short timeout on the
|
|
949
|
+
* daemon socket. If data arrives within that window the
|
|
950
|
+
* transfer is still active and we keep accumulating without a
|
|
951
|
+
* flush. Only if the producer stays idle for the whole delay
|
|
952
|
+
* do we flush, so streaming responses still reach the client
|
|
953
|
+
* promptly. When the flush delay is zero this step is skipped
|
|
954
|
+
* and the data is flushed on any would-block.
|
|
955
|
+
*/
|
|
956
|
+
|
|
957
|
+
if (rv == APR_EAGAIN && mode == APR_NONBLOCK_READ && flush_delay)
|
|
958
|
+
{
|
|
959
|
+
apr_socket_timeout_set(daemon_socket, flush_delay);
|
|
960
|
+
|
|
961
|
+
mode = APR_BLOCK_READ;
|
|
962
|
+
lingering = 1;
|
|
963
|
+
|
|
964
|
+
continue;
|
|
965
|
+
}
|
|
966
|
+
|
|
967
|
+
/*
|
|
968
|
+
* If we would have blocked, or the producer stayed idle for
|
|
969
|
+
* the whole flush delay, we send a flush bucket to ensure that
|
|
970
|
+
* all buffered data is sent out before we block waiting for
|
|
971
|
+
* more.
|
|
929
972
|
*/
|
|
930
973
|
|
|
931
|
-
if (rv == APR_EAGAIN && mode == APR_NONBLOCK_READ)
|
|
974
|
+
if ((rv == APR_EAGAIN && mode == APR_NONBLOCK_READ) ||
|
|
975
|
+
(rv == APR_TIMEUP && lingering))
|
|
932
976
|
{
|
|
977
|
+
if (lingering)
|
|
978
|
+
{
|
|
979
|
+
apr_socket_timeout_set(daemon_socket, daemon_timeout);
|
|
980
|
+
|
|
981
|
+
lingering = 0;
|
|
982
|
+
}
|
|
983
|
+
|
|
933
984
|
APR_BRIGADE_INSERT_TAIL(tmpbb, apr_bucket_flush_create(
|
|
934
985
|
r->connection->bucket_alloc));
|
|
935
986
|
|
|
@@ -961,8 +1012,6 @@ static int wsgi_transfer_response(request_rec *r, apr_bucket_brigade *bb,
|
|
|
961
1012
|
|
|
962
1013
|
bytes_transfered = 0;
|
|
963
1014
|
|
|
964
|
-
bucket_count = 0;
|
|
965
|
-
|
|
966
1015
|
/*
|
|
967
1016
|
* Retry read from daemon using a blocking read. We do
|
|
968
1017
|
* not delete the bucket as we want to operate on the
|
|
@@ -991,9 +1040,18 @@ static int wsgi_transfer_response(request_rec *r, apr_bucket_brigade *bb,
|
|
|
991
1040
|
|
|
992
1041
|
/*
|
|
993
1042
|
* We had some data to transfer. Next time round we need to
|
|
994
|
-
* always be try a non-blocking read first.
|
|
1043
|
+
* always be try a non-blocking read first. If we got here from
|
|
1044
|
+
* a lingering blocking read, restore the daemon socket timeout
|
|
1045
|
+
* that we lowered to the flush delay.
|
|
995
1046
|
*/
|
|
996
1047
|
|
|
1048
|
+
if (lingering)
|
|
1049
|
+
{
|
|
1050
|
+
apr_socket_timeout_set(daemon_socket, daemon_timeout);
|
|
1051
|
+
|
|
1052
|
+
lingering = 0;
|
|
1053
|
+
}
|
|
1054
|
+
|
|
997
1055
|
mode = APR_NONBLOCK_READ;
|
|
998
1056
|
|
|
999
1057
|
/*
|
|
@@ -1010,41 +1068,38 @@ static int wsgi_transfer_response(request_rec *r, apr_bucket_brigade *bb,
|
|
|
1010
1068
|
APR_BRIGADE_INSERT_TAIL(tmpbb, e);
|
|
1011
1069
|
|
|
1012
1070
|
/*
|
|
1013
|
-
*
|
|
1014
|
-
*
|
|
1015
|
-
*
|
|
1016
|
-
*
|
|
1017
|
-
*
|
|
1018
|
-
*
|
|
1019
|
-
*
|
|
1020
|
-
*
|
|
1021
|
-
*
|
|
1022
|
-
*
|
|
1023
|
-
*
|
|
1071
|
+
* Each block is passed straight on without a forced flush. The
|
|
1072
|
+
* Apache 2.4 core output filter bounds how much response data
|
|
1073
|
+
* is buffered in the child process: it switches to blocking
|
|
1074
|
+
* writes once its own threshold is reached, which backpressures
|
|
1075
|
+
* through ap_pass_brigade and on to the daemon, and it batches
|
|
1076
|
+
* its own writev() calls. Passing whole blocks on keeps writes
|
|
1077
|
+
* large enough for a downstream pacing filter such as
|
|
1078
|
+
* mod_ratelimit to pace correctly. Pending data is otherwise
|
|
1079
|
+
* flushed when the producer goes idle (above) and at end of
|
|
1080
|
+
* stream.
|
|
1081
|
+
*
|
|
1082
|
+
* As a coarse runaway guard, force a flush if more than
|
|
1083
|
+
* buffer_size bytes have been passed downstream since the last
|
|
1084
|
+
* flush. This bounds a downstream filter that buffers without
|
|
1085
|
+
* draining to roughly buffer_size per request. It counts bytes
|
|
1086
|
+
* transferred, not bytes currently buffered, so on a healthy
|
|
1087
|
+
* connection it just emits an otherwise harmless flush every
|
|
1088
|
+
* buffer_size bytes; buffer_size is high by default so it does
|
|
1089
|
+
* not fire in normal operation.
|
|
1024
1090
|
*/
|
|
1025
1091
|
|
|
1026
1092
|
bytes_transfered += length;
|
|
1027
1093
|
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
if (bytes_transfered > buffer_size || bucket_count >= 16)
|
|
1094
|
+
if (bytes_transfered > buffer_size)
|
|
1031
1095
|
{
|
|
1032
1096
|
APR_BRIGADE_INSERT_TAIL(tmpbb, apr_bucket_flush_create(
|
|
1033
1097
|
r->connection->bucket_alloc));
|
|
1034
1098
|
|
|
1035
1099
|
bytes_transfered = 0;
|
|
1036
|
-
|
|
1037
|
-
bucket_count = 0;
|
|
1038
|
-
|
|
1039
|
-
/*
|
|
1040
|
-
* Since we flushed the data out to the client, it is
|
|
1041
|
-
* okay to go back and do a blocking read the next time.
|
|
1042
|
-
*/
|
|
1043
|
-
|
|
1044
|
-
mode = APR_BLOCK_READ;
|
|
1045
1100
|
}
|
|
1046
1101
|
|
|
1047
|
-
/* Pass the heap bucket and any flush
|
|
1102
|
+
/* Pass the heap bucket and any runaway-guard flush on. */
|
|
1048
1103
|
|
|
1049
1104
|
rv = ap_pass_brigade(r->output_filters, tmpbb);
|
|
1050
1105
|
|
|
@@ -1835,7 +1890,8 @@ int wsgi_execute_remote(request_rec *r)
|
|
|
1835
1890
|
/* Transfer any response content. */
|
|
1836
1891
|
|
|
1837
1892
|
return wsgi_transfer_response(r, bbin, group->response_buffer_size,
|
|
1838
|
-
group->response_socket_timeout
|
|
1893
|
+
group->response_socket_timeout,
|
|
1894
|
+
daemon->socket, group->response_flush_delay);
|
|
1839
1895
|
}
|
|
1840
1896
|
|
|
1841
1897
|
static apr_status_t wsgi_socket_read(apr_socket_t *sock, void *vbuf,
|
|
@@ -25,8 +25,8 @@
|
|
|
25
25
|
|
|
26
26
|
#define MOD_WSGI_MAJORVERSION_NUMBER 6
|
|
27
27
|
#define MOD_WSGI_MINORVERSION_NUMBER 0
|
|
28
|
-
#define MOD_WSGI_MICROVERSION_NUMBER
|
|
29
|
-
#define MOD_WSGI_VERSION_STRING "6.0.
|
|
28
|
+
#define MOD_WSGI_MICROVERSION_NUMBER 3
|
|
29
|
+
#define MOD_WSGI_VERSION_STRING "6.0.3.dev1"
|
|
30
30
|
|
|
31
31
|
/* ------------------------------------------------------------------------- */
|
|
32
32
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|