Skip to content

Commit 94f7a7e

Browse files
Merge branch 'release/mod_wsgi-6.0.2'
2 parents 5d7e460 + db7fbc1 commit 94f7a7e

25 files changed

Lines changed: 671 additions & 89 deletions

docs/configuration-directives/WSGIDaemonProcess.rst

Lines changed: 58 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -769,20 +769,69 @@ Options which can be supplied to the ``WSGIDaemonProcess`` directive are:
769769
.. _response-buffer-size:
770770

771771
**response-buffer-size=nnn**
772-
Defines the maximum number of bytes that will be buffered for a
773-
response in the Apache child processes when proxying the response body
774-
from the WSGI application. The default size is 65536 bytes. Be careful
775-
increasing this to provide extra buffering of responses as it
776-
contributes to the runtime memory size of the Apache child processes.
772+
Acts as a coarse upper bound, in bytes, on how much response content is
773+
passed down the output filter chain without a flush when proxying a
774+
response body from the WSGI application. If this many bytes are passed
775+
without a flush occurring for another reason, a flush is forced. The
776+
default is 8388608 bytes (8 MB), and if specified the value must be at
777+
least 65536 bytes.
778+
779+
Its only purpose is to bound a downstream output filter that buffers
780+
response data without draining it, capping such buffering to roughly
781+
this many bytes per request. The Apache core output filter already
782+
bounds normal in-memory buffering of the response in the Apache child
783+
processes, so the default is set high and the guard does not affect
784+
normal operation. Setting it low forces frequent flushes that can
785+
interfere with a downstream pacing or batching output filter such as
786+
``mod_ratelimit`` (see ``response-flush-delay``), so it should only be
787+
reduced if you specifically need to cap such a filter.
777788

778789
.. _response-socket-timeout:
779790

780791
**response-socket-timeout=nnn**
781792
Defines the maximum number of seconds allowed to pass before timing out
782-
on a write operation back to the HTTP client when the response buffer
783-
has filled and data is being forcibly flushed. Defaults to 0 seconds
784-
indicating that it will default to the value of the ``socket-timeout``
785-
option.
793+
on a write operation back to the HTTP client when transferring the
794+
response body. Defaults to 0 seconds indicating that it will default to
795+
the value of the ``socket-timeout`` option.
796+
797+
.. _response-flush-delay:
798+
799+
**response-flush-delay=nnn**
800+
Defines, in **milliseconds**, how long mod_wsgi will wait for further
801+
response data to arrive from the daemon process before flushing the
802+
data already read out to the HTTP client. Defaults to 5 milliseconds.
803+
804+
When proxying a response back from a daemon process, mod_wsgi reads the
805+
data as it becomes available and would otherwise flush to the client
806+
every time the daemon socket momentarily ran dry. During a bulk
807+
transfer that emptying is usually just an artefact of timing, and
808+
flushing on it defeats a downstream output filter that paces or batches
809+
data, most notably ``mod_ratelimit`` (whose ``RATE_LIMIT`` filter is
810+
forced to emit a short write on every flush and so throttles the
811+
response far below the configured rate). Waiting a brief period for
812+
more data lets mod_wsgi coalesce it into larger writes so such a filter
813+
can do its job, while a genuinely idle application still has its partial
814+
output flushed within the delay so streaming responses remain
815+
responsive.
816+
817+
The default of 5 milliseconds is comfortably longer than the time it
818+
takes the local daemon process to produce more data during an active
819+
transfer, so it does not affect throughput, while bounding any extra
820+
latency added to a paused streaming response to that same small value.
821+
822+
Setting the value to 0 disables the wait, so data is flushed on any
823+
momentary stall. This is generally not recommended. In particular, do
824+
not set it to 0 when a downstream pacing or batching output filter such
825+
as ``mod_ratelimit`` is in use: doing so reintroduces a flush on every
826+
momentary stall, which prevents such a filter from accumulating
827+
full-size writes and can throttle responses far below the configured
828+
rate. A value of 0 is only appropriate for latency-sensitive streaming
829+
where no such filter is present and even a few milliseconds of flush
830+
delay must be avoided.
831+
832+
Note that, unlike the various ``*-timeout`` options which are expressed
833+
in seconds, this option is expressed in milliseconds because the useful
834+
values are far smaller than one second.
786835

787836
.. _server-metrics:
788837

docs/configuration-directives/WSGISlowRequests.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@ Setting ``WSGISlowRequests`` without ``WSGITelemetryService`` is
2727
not treated as a configuration error: the per-request bookkeeping
2828
runs and the records are constructed, but nothing reads them.
2929

30+
Note that, like the telemetry reporter it feeds, this directive is
31+
not available on Windows. See :doc:`WSGITelemetryService` for
32+
details.
33+
3034
Each slow-request record carries:
3135

3236
* The originating process PID and worker thread ID.

docs/configuration-directives/WSGITelemetryOptions.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ This is a server-wide directive: it may only appear at the top
1616
level of the Apache configuration, outside any ``<VirtualHost>``
1717
block.
1818

19+
Note that, like the telemetry reporter it configures, this directive
20+
is not available on Windows. See :doc:`WSGITelemetryService` for
21+
details.
22+
1923
Syntax follows the Apache ``Options`` directive convention. Two
2024
argument forms are supported, and may not be mixed within one
2125
line:

docs/configuration-directives/WSGITelemetryService.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,14 @@ configuration line enables the reporter for the entire Apache
3939
instance, covering every daemon process group and every
4040
embedded-mode Apache child.
4141

42+
Note that the telemetry reporter, and so the ``WSGITelemetryService``,
43+
:doc:`WSGISlowRequests` and :doc:`WSGITelemetryOptions` directives, are
44+
not available on Windows. The reporter delivers its datagrams over a
45+
UNIX ``SOCK_DGRAM`` socket, which Windows does not provide, so the
46+
feature is not built there and these directives are not registered.
47+
Using one of them on Windows is reported by Apache as an unknown
48+
directive.
49+
4250
Arguments
4351
---------
4452

docs/error-reference.rst

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5413,3 +5413,36 @@ WSGI0209 — Unable to publish 'process_signal' event for interpreter
54135413
subscribers should be defensive about missed signals (idempotent
54145414
reload, polling-based fallback) since signals are not
54155415
refcounted and a dropped delivery is not redelivered.
5416+
5417+
.. _WSGI0210:
5418+
5419+
WSGI0210 — Embedded mode of mod_wsgi cannot be used as Python was not initialised
5420+
---------------------------------------------------------------------------------
5421+
5422+
:Severity: ERR
5423+
:Source: ``src/server/mod_wsgi.c``
5424+
5425+
:Logged message:
5426+
``Embedded mode of mod_wsgi cannot be used as Python was not
5427+
initialised in this process.``
5428+
5429+
:Cause:
5430+
A request reached the embedded-mode code path and embedded mode
5431+
was permitted, but no Python interpreter is available in this
5432+
Apache child process, so the per-thread state needed to run the
5433+
handler does not exist. This normally means the child was never
5434+
asked to initialise Python (for example a daemon-only
5435+
configuration), or initialisation was attempted but failed (see
5436+
:ref:`WSGI0001`).
5437+
5438+
:Outcome:
5439+
The request returns ``500 Internal Server Error``. The check
5440+
exists so this condition is reported rather than crashing the
5441+
process by dereferencing the uninitialised per-thread state.
5442+
5443+
:Operator action:
5444+
Route the request to a ``WSGIDaemonProcess`` via
5445+
``WSGIProcessGroup``, or ensure embedded mode is configured so
5446+
Python is initialised in the Apache child processes. If
5447+
:ref:`WSGI0001` was logged at child start up, resolve that
5448+
initialisation failure first.

docs/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ Where to start
8686
:maxdepth: 1
8787

8888
troubleshooting
89+
known-issues
8990
finding-help
9091
reporting-bugs
9192
contributing

docs/known-issues.rst

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
============
2+
Known Issues
3+
============
4+
5+
This page lists known issues in mod_wsgi itself: confirmed defects and
6+
accepted limitations in the module, as opposed to problems in your
7+
Apache configuration or your WSGI application. If you are still working
8+
out *where* a problem lives, start with :doc:`troubleshooting`; the
9+
guides it links to cover installation, configuration, and application
10+
problems, which are far more common than bugs in mod_wsgi.
11+
12+
An issue is listed here when the behaviour is understood, there is
13+
nothing a user can do to make mod_wsgi behave differently beyond the
14+
noted workaround, and a full fix is either not yet available or not
15+
considered worthwhile. Each entry records the symptom, which mode of
16+
operation is affected, the underlying cause, any workaround, and the
17+
current status with a link to the tracking issue.
18+
19+
If you are hitting something that is not listed here and not explained
20+
by :doc:`troubleshooting`, see :doc:`reporting-bugs`.
21+
22+
.. _known-issue-chunked-truncation:
23+
24+
Truncated chunked responses are not signalled to the client in daemon mode
25+
--------------------------------------------------------------------------
26+
27+
**Symptom**
28+
29+
A WSGI application streams a response with no ``Content-Length`` header,
30+
so it is sent to the client using ``Transfer-Encoding: chunked``. If the
31+
response is then cut short partway through, the client still receives a
32+
syntactically complete chunked response, terminated with the final
33+
``0`` chunk, and cannot tell that the body was truncated. The response
34+
is cut short when either:
35+
36+
* the application raises an unhandled exception while iterating the
37+
response, or
38+
* the daemon process handling the request dies mid-response (for
39+
example, it is killed, crashes, or hits a resource limit).
40+
41+
**Affected mode**
42+
43+
Daemon mode only. In embedded mode this was addressed in version 4.4.0:
44+
when a chunked response is interrupted by an application exception,
45+
mod_wsgi suppresses the terminating ``0`` chunk so the client sees an
46+
unterminated response and can detect the truncation. Responses that do
47+
carry a ``Content-Length`` are not affected in either mode, because a
48+
client can already detect a short read against the declared length.
49+
50+
**Cause**
51+
52+
In daemon mode the response is produced in the daemon process and
53+
proxied back to the Apache child process over a socket, with the chunked
54+
framing toward the client applied by the Apache child. The response leg
55+
between daemon and child is an unframed byte stream whose end is
56+
signalled only by the socket closing, so a clean completion, an
57+
application exception, and an outright crash all look identical to the
58+
Apache child. The child then terminates the chunked response toward the
59+
client normally. The embedded-mode fix does not carry over because it
60+
acts in the daemon process, on a different request, from where the
61+
client-facing chunked framing is applied.
62+
63+
**Workaround**
64+
65+
Where it matters that a client can detect a truncated response, have the
66+
application set a ``Content-Length`` header so the response is not sent
67+
chunked; a client can then detect a short read against the declared
68+
length. This is only possible when the response length is known in
69+
advance.
70+
71+
**Status**
72+
73+
Open. A fix would require framing the daemon-to-child response leg so the
74+
Apache child can distinguish a truncated response from a clean one and
75+
withhold the terminating ``0`` chunk. The value of such a fix is limited
76+
in any case: chunked transfer encoding is hop by hop, so an intermediary
77+
proxy may dechunk and re-chunk the response and append its own
78+
terminating chunk, which would erase the truncation signal before it
79+
reaches the client. Tracked as
80+
`issue #42 <https://github.com/GrahamDumpleton/mod_wsgi/issues/42>`__.

docs/release-notes.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ mod_wsgi. See :doc:`project-status` for the version support policy.
88
.. toctree::
99
:maxdepth: 2
1010

11+
release-notes/version-6.0.2
1112
release-notes/version-6.0.1
1213
release-notes/version-6.0.0
1314

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
=============
2+
Version 6.0.2
3+
=============
4+
5+
Features Changed
6+
----------------
7+
8+
* The way mod_wsgi proxies a response body back from a daemon process to
9+
the HTTP client has been reworked so that it no longer interferes with
10+
downstream output filters that pace or batch data, most notably
11+
``mod_ratelimit``. Previously mod_wsgi forced a flush both every time the
12+
daemon socket momentarily ran dry and after each ``response-buffer-size``
13+
worth of data had been passed on. Both kinds of flush forced the
14+
``mod_ratelimit`` ``RATE_LIMIT`` filter to emit a short write and so
15+
throttled daemon mode responses far below the configured rate. As
16+
mod_wsgi requires Apache 2.4, whose core output filter already bounds how
17+
much response data is buffered in the Apache child processes, these
18+
forced flushes are no longer needed to limit memory use and have been
19+
removed. mod_wsgi now passes response data straight on, so a pacing
20+
filter receives full-size writes and works correctly, while a genuinely
21+
idle application still has its partial output flushed promptly so
22+
streaming responses remain responsive.
23+
24+
The visible effect of the previous behaviour varied with the version of
25+
Apache in use. With some versions of mod_ratelimit the forced flushes
26+
effectively let the response through at close to full speed, so a
27+
configured rate limit had little effect; with others they caused the
28+
rate limit to be applied far too aggressively, throttling the response
29+
well below the configured rate. In neither case could the rate limit be
30+
honoured accurately for a daemon mode response, which it now is.
31+
32+
Two options on the :doc:`../configuration-directives/WSGIDaemonProcess`
33+
directive control this behaviour:
34+
35+
- The new ``response-flush-delay`` option (default 5 milliseconds) sets
36+
how long mod_wsgi waits for more response data before flushing when the
37+
daemon socket runs dry, so a transient stall during an active transfer
38+
does not trigger a flush while a genuinely paused application still has
39+
its output flushed within that delay. Setting it to 0 flushes on any
40+
stall and is not recommended when a pacing filter such as
41+
``mod_ratelimit`` is in use, as it can throttle responses far below the
42+
configured rate.
43+
44+
- The ``response-buffer-size`` option has changed meaning. It is now a
45+
coarse runaway guard that forces a flush only once this many bytes have
46+
been passed downstream without one, in order to bound a downstream
47+
filter that buffers without draining. Its default has been raised from
48+
65536 bytes to 8388608 bytes (8 MB) accordingly; normal bounding of
49+
response memory use is handled by the Apache core output filter.
50+
51+
Bugs Fixed
52+
----------
53+
54+
* Building the Windows ``mod_wsgi`` extension failed at the link stage with
55+
a ``LNK2005`` multiply defined symbol error for ``PyInit_mod_wsgi``, and a
56+
fatal ``LNK1169``. When the single ``mod_wsgi.c`` source file was split
57+
into the separate ``wsgi_*.c`` files in version 6.0.0, the real
58+
``PyInit_mod_wsgi`` module init function moved into ``wsgi_module.c`` as
59+
an unconditional definition, but an older Windows-only stub of the same
60+
function was left behind in ``mod_wsgi.c``. On non-Windows builds the stub
61+
was excluded by ``#if defined(_WIN32)`` so only one definition was
62+
compiled, but on Windows both were compiled and the linker rejected the
63+
duplicate. The obsolete stub has been removed so ``wsgi_module.c`` is the
64+
sole provider of ``PyInit_mod_wsgi`` on all platforms.
65+
66+
* Setting ``WSGIRestrictEmbedded Off`` after it had previously been set
67+
to ``On`` could crash the Apache child process when an embedded mode
68+
request was subsequently received. ``WSGIRestrictEmbedded On`` not only
69+
blocks embedded mode requests but, as an optimisation, also suppresses
70+
initialisation of Python in the Apache child processes when nothing
71+
else requires it. Switching it back ``Off`` re-enabled embedded mode
72+
request handling but did not undo that suppression, so the request
73+
reached the embedded mode code path in a child where Python, and the
74+
per-thread state it depends on, had never been initialised, causing a
75+
crash. ``WSGIRestrictEmbedded Off`` now marks Python as required in the
76+
Apache child processes, consistent with the other directives that need
77+
it, so embedded mode works as expected. As an additional safeguard, an
78+
embedded mode request that reaches a child with no initialised Python
79+
interpreter is now rejected with a ``500 Internal Server Error`` and
80+
logged as :ref:`WSGI0210` rather than crashing the process.

docs/reporting-bugs.rst

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@ the GitHub issue tracker:
1010
A substantial fraction of bug reports against mod_wsgi turn out to
1111
be misconfiguration, application errors, or problems in third-party
1212
packages rather than mod_wsgi bugs. Before filing a bug report,
13-
work through :doc:`troubleshooting`.
13+
work through :doc:`troubleshooting`. If the behaviour does look like
14+
a defect or limitation in mod_wsgi itself, check :doc:`known-issues`
15+
first, as it may already be recorded there along with any workaround.
1416

1517
For general questions, or if you want to discuss whether something
1618
is actually a bug before filing it, see :doc:`finding-help`.

0 commit comments

Comments
 (0)