Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: benoitc/gunicorn
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 22.0.0
Choose a base ref
...
head repository: benoitc/gunicorn
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 23.0.0
Choose a head ref
Loading
Showing with 815 additions and 426 deletions.
  1. +25 −2 .github/workflows/lint.yml
  2. +23 −1 .github/workflows/tox.yml
  3. +1 −0 .gitignore
  4. +1 −1 LICENSE
  5. +2 −0 MANIFEST.in
  6. +1 −1 NOTICE
  7. +11 −3 SECURITY.md
  8. +2 −0 docs/Makefile
  9. +2 −2 docs/README.rst
  10. +1 −1 docs/site/index.html
  11. +5 −0 docs/source/2023-news.rst
  12. +61 −0 docs/source/2024-news.rst
  13. +0 −1 docs/source/conf.py
  14. +19 −0 docs/source/custom.rst
  15. +11 −7 docs/source/deploy.rst
  16. +1 −4 docs/source/design.rst
  17. +7 −1 docs/source/faq.rst
  18. +28 −37 docs/source/news.rst
  19. +168 −20 docs/source/settings.rst
  20. +0 −1 examples/alt_spec.py
  21. +0 −1 examples/boot_fail.py
  22. +0 −1 examples/deep/test.py
  23. +0 −1 examples/echo.py
  24. +1 −1 examples/example_config.py
  25. +1 −1 examples/frameworks/cherryapp.py
  26. +1 −1 examples/frameworks/django/testing/testing/apps/someapp/middleware.py
  27. +16 −25 examples/frameworks/tornadoapp.py
  28. +1 −2 examples/longpoll.py
  29. +1 −2 examples/multiapp.py
  30. +0 −1 examples/multidomainapp.py
  31. +0 −1 examples/readline_app.py
  32. +0 −1 examples/sendfile.py
  33. +0 −1 examples/slowclient.py
  34. +0 −1 examples/standalone_app.py
  35. +0 −1 examples/test.py
  36. +0 −1 examples/timeout.py
  37. +2 −3 examples/websocket/gevent_websocket.py
  38. +2 −3 examples/websocket/websocket.py
  39. +1 −1 examples/when_ready.conf.py
  40. +1 −2 gunicorn/__init__.py
  41. +0 −1 gunicorn/__main__.py
  42. +0 −1 gunicorn/app/__init__.py
  43. +1 −2 gunicorn/app/base.py
  44. +0 −1 gunicorn/app/pasterapp.py
  45. +0 −1 gunicorn/app/wsgiapp.py
  46. +4 −5 gunicorn/arbiter.py
  47. +109 −51 gunicorn/config.py
  48. +2 −3 gunicorn/debug.py
  49. +0 −1 gunicorn/errors.py
  50. +1 −2 gunicorn/glogging.py
  51. +0 −1 gunicorn/http/__init__.py
  52. +10 −6 gunicorn/http/body.py
  53. +9 −2 gunicorn/http/errors.py
  54. +52 −39 gunicorn/http/message.py
  55. +1 −2 gunicorn/http/parser.py
  56. +1 −2 gunicorn/http/unreader.py
  57. +2 −3 gunicorn/http/wsgi.py
  58. +2 −1 gunicorn/instrument/statsd.py
  59. +4 −5 gunicorn/pidfile.py
  60. +1 −2 gunicorn/reloader.py
  61. +7 −8 gunicorn/sock.py
  62. +0 −1 gunicorn/systemd.py
  63. +4 −5 gunicorn/util.py
  64. +0 −1 gunicorn/workers/__init__.py
  65. +13 −3 gunicorn/workers/base.py
  66. +4 −5 gunicorn/workers/base_async.py
  67. +0 −1 gunicorn/workers/geventlet.py
  68. +6 −3 gunicorn/workers/ggevent.py
  69. +6 −7 gunicorn/workers/gthread.py
  70. +1 −2 gunicorn/workers/gtornado.py
  71. +6 −7 gunicorn/workers/sync.py
  72. +1 −2 gunicorn/workers/workertmp.py
  73. +4 −0 tests/requests/invalid/013.py
  74. +2 −2 tests/requests/invalid/chunked_03.py
  75. +2 −2 tests/requests/invalid/chunked_06.py
  76. +7 −0 tests/requests/invalid/chunked_12.http
  77. +2 −0 tests/requests/invalid/chunked_12.py
  78. +7 −0 tests/requests/invalid/chunked_13.http
  79. +2 −0 tests/requests/invalid/chunked_13.py
  80. +7 −0 tests/requests/invalid/invalid_field_value_01.http
  81. +5 −0 tests/requests/invalid/invalid_field_value_01.py
  82. +5 −0 tests/requests/invalid/obs_fold_01.http
  83. +3 −0 tests/requests/invalid/obs_fold_01.py
  84. +4 −18 tests/requests/valid/025.http
  85. +4 −21 tests/requests/valid/025.py
  86. +9 −0 tests/requests/valid/025_line.http
  87. +10 −0 tests/requests/valid/025_line.py
  88. +0 −18 tests/requests/valid/025compat.http
  89. +0 −27 tests/requests/valid/025compat.py
  90. +5 −0 tests/requests/valid/compat_obs_fold.http
  91. +16 −0 tests/requests/valid/compat_obs_fold.py
  92. 0 tests/requests/valid/{016.http → compat_obs_fold_huge.http}
  93. +5 −0 tests/requests/valid/{016.py → compat_obs_fold_huge.py}
  94. +4 −0 tests/requests/valid/padding_01.http
  95. +11 −0 tests/requests/valid/padding_01.py
  96. +2 −3 tests/t.py
  97. +0 −1 tests/test_arbiter.py
  98. +40 −7 tests/test_config.py
  99. +6 −3 tests/test_http.py
  100. +0 −1 tests/test_invalid_requests.py
  101. +0 −1 tests/test_pidfile.py
  102. +0 −1 tests/test_sock.py
  103. +0 −2 tests/test_ssl.py
  104. +1 −1 tests/test_statsd.py
  105. +0 −1 tests/test_systemd.py
  106. +0 −1 tests/test_util.py
  107. +0 −1 tests/test_valid_requests.py
  108. +1 −1 tests/treq.py
  109. +0 −1 tests/workers/test_geventlet.py
  110. +0 −1 tests/workers/test_ggevent.py
  111. +8 −3 tox.ini
27 changes: 25 additions & 2 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
@@ -7,22 +7,45 @@ env:
FORCE_COLOR: 1
jobs:
lint:
name: tox-${{ matrix.toxenv }}
name: ${{ matrix.python-version }} / tox-${{ matrix.toxenv || '(other)' }}
timeout-minutes: 10
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
toxenv: [lint, docs-lint, pycodestyle]
python-version: [ "3.10" ]
include:
# for actions that want git env, not tox env
- toxenv: null
python-version: "3.10"
steps:
- uses: actions/checkout@v4
- name: Using Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
cache: pip
- name: Install Dependencies
- name: Install Dependencies (tox)
if: ${{ matrix.toxenv }}
run: |
python -m pip install --upgrade pip
python -m pip install tox
- run: tox -e ${{ matrix.toxenv }}
if: ${{ matrix.toxenv }}
- name: Install Dependencies (non-toxic)
if: ${{ ! matrix.toxenv }}
run: |
python -m pip install sphinx
- name: "Update docs"
if: ${{ ! matrix.toxenv }}
run: |
# this will update docs/source/settings.rst - but will not create html output
(cd docs && sphinx-build -b "dummy" -d _build/doctrees source "_build/dummy")
if unclean=$(git status --untracked-files=no --porcelain) && [ -z "$unclean" ]; then
echo "no uncommitted changes in working tree (as it should be)"
else
echo "did you forget to run `make -C docs html`?"
echo "$unclean"
exit 2
fi
24 changes: 23 additions & 1 deletion .github/workflows/tox.yml
Original file line number Diff line number Diff line change
@@ -14,7 +14,12 @@ jobs:
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest] # All OSes pass except Windows because tests need Unix-only fcntl, grp, pwd, etc.
unsupported: [false]
os:
- ubuntu-latest
# not defaulting to macos-latest: Python <= 3.9 was missing from macos-14 @ arm64
- macos-13
# Not testing Windows, because tests need Unix-only fcntl, grp, pwd, etc.
python-version:
# CPython <= 3.7 is EoL since 2023-06-27
- "3.7"
@@ -26,6 +31,19 @@ jobs:
# PyPy <= 3.8 is EoL since 2023-06-16
- "pypy-3.9"
- "pypy-3.10"
include:
# Note: potentially "universal2" release
# https://github.com/actions/runner-images/issues/9741
- os: macos-latest
python-version: "3.12"
unsupported: false
# will run these without showing red CI results should they fail
- os: macos-latest
python-version: "3.13"
unsupported: true
- os: ubuntu-latest
python-version: "3.13"
unsupported: true
steps:
- uses: actions/checkout@v4
- name: Using Python ${{ matrix.python-version }}
@@ -35,10 +53,14 @@ jobs:
cache: pip
cache-dependency-path: requirements_test.txt
check-latest: true
allow-prereleases: ${{ matrix.unsupported }}
- name: Install Dependencies
run: |
python -m pip install --upgrade pip
python -m pip install tox
- run: tox -e run-module
continue-on-error: ${{ matrix.unsupported }}
- run: tox -e run-entrypoint
continue-on-error: ${{ matrix.unsupported }}
- run: tox -e py
continue-on-error: ${{ matrix.unsupported }}
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -7,6 +7,7 @@
.tox
__pycache__
build
docs/_build
coverage.xml
dist
examples/frameworks/django/testing/testdb.sql
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
2009-2023 (c) Benoît Chesneau <benoitc@gunicorn.org>
2009-2024 (c) Benoît Chesneau <benoitc@gunicorn.org>
2009-2015 (c) Paul J. Davis <paul.joseph.davis@gmail.com>

Permission is hereby granted, free of charge, to any person
2 changes: 2 additions & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
@@ -10,4 +10,6 @@ recursive-include examples *
recursive-include docs *
recursive-include examples/frameworks *
recursive-exclude * __pycache__
recursive-exclude docs/build *
recursive-exclude docs/_build *
recursive-exclude * *.py[co]
2 changes: 1 addition & 1 deletion NOTICE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Gunicorn

2009-2023 (c) Benoît Chesneau <benoitc@gunicorn.org>
2009-2024 (c) Benoît Chesneau <benoitc@gunicorn.org>
2009-2015 (c) Paul J. Davis <paul.joseph.davis@gmail.com>

Gunicorn is released under the MIT license. See the LICENSE
14 changes: 11 additions & 3 deletions SECURITY.md
Original file line number Diff line number Diff line change
@@ -4,19 +4,27 @@

**Please note that public Github issues are open for everyone to see!**

If you believe you are found a problem in Gunicorn software, examples or documentation, we encourage you to send your report privately via [email](mailto:security@gunicorn.org?subject=Security%20issue%20in%20Gunicorn), or via Github using the *Report a vulnerability* button in the [Security](https://github.com/benoitc/gunicorn/security) section.
If you believe you are found a problem in Gunicorn software, examples or documentation, we encourage you to send your
report privately via [email](mailto:security@gunicorn.org?subject=Security%20issue%20in%20Gunicorn), or via Github
using the *Report a vulnerability* button in the [Security](https://github.com/benoitc/gunicorn/security) section.

## Supported Releases

At this time, **only the latest release** receives any security attention whatsoever.

Please target reports against :white_check_mark: or current master. Please understand that :x: will
not receive further security attention.

| Version | Status |
| ------- | ------------------ |
| latest release | :white_check_mark: |
| 23.0.0 | :white_check_mark: |
| 22.0.0 | :x: |
| 21.2.0 | :x: |
| 20.0.0 | :x: |
| < 20.0 | :x: |

## Python Versions

Gunicorn runs on Python 3.7+, we *highly recommend* the latest release of a [supported series](https://devguide.python.org/versions/) and will not prioritize issues exclusively affecting in EoL environments.
Gunicorn runs on Python 3.7+, we *highly recommend* the latest release of a
[supported series](https://devguide.python.org/versions/) and will not prioritize issues exclusively
affecting in EoL environments.
2 changes: 2 additions & 0 deletions docs/Makefile
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# Makefile for Sphinx documentation
#
# if you want to compare this file to current sphinx defaults, recreate it:
# BUILDDIR=build sphinx-quickstart --sep --extensions=gunicorn_ext --templatedir=_templates --makefile --batchfile --no-use-make-mode --master=index

# You can set these variables from the command line.
PYTHON = python
4 changes: 2 additions & 2 deletions docs/README.rst
Original file line number Diff line number Diff line change
@@ -6,8 +6,8 @@ Requirements

To generate documentation you need to install:

- Python >= 3.4
- Sphinx (http://sphinx-doc.org/)
- Python >= 3.7
- Sphinx (https://www.sphinx-doc.org/)


Generate html
2 changes: 1 addition & 1 deletion docs/site/index.html
Original file line number Diff line number Diff line change
@@ -16,7 +16,7 @@
<div class="logo-div">
<div class="latest">
Latest version: <strong><a
href="https://docs.gunicorn.org/en/stable/">22.0.0</a></strong>
href="https://docs.gunicorn.org/en/stable/">23.0.0</a></strong>
</div>

<div class="logo"><img src="images/logo.jpg" ></div>
5 changes: 5 additions & 0 deletions docs/source/2023-news.rst
Original file line number Diff line number Diff line change
@@ -11,6 +11,11 @@ Changelog - 2023

This is fixing the bad file description error.

21.1.0 - 2023-07-18
===================

- fix thread worker: fix socket removal from the queue

21.0.1 - 2023-07-17
===================

61 changes: 61 additions & 0 deletions docs/source/2024-news.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
================
Changelog - 2024
================

23.0.0 - 2024-08-10
===================

- minor docs fixes (:pr:`3217`, :pr:`3089`, :pr:`3167`)
- worker_class parameter accepts a class (:pr:`3079`)
- fix deadlock if request terminated during chunked parsing (:pr:`2688`)
- permit receiving Transfer-Encodings: compress, deflate, gzip (:pr:`3261`)
- permit Transfer-Encoding headers specifying multiple encodings. note: no parameters, still (:pr:`3261`)
- sdist generation now explicitly excludes sphinx build folder (:pr:`3257`)
- decode bytes-typed status (as can be passed by gevent) as utf-8 instead of raising `TypeError` (:pr:`2336`)
- raise correct Exception when encounting invalid chunked requests (:pr:`3258`)
- the SCRIPT_NAME and PATH_INFO headers, when received from allowed forwarders, are no longer restricted for containing an underscore (:pr:`3192`)
- include IPv6 loopback address ``[::1]`` in default for :ref:`forwarded-allow-ips` and :ref:`proxy-allow-ips` (:pr:`3192`)

** NOTE **

- The SCRIPT_NAME change mitigates a regression that appeared first in the 22.0.0 release
- Review your :ref:`forwarded-allow-ips` setting if you are still not seeing the SCRIPT_NAME transmitted
- Review your :ref:`forwarder-headers` setting if you are missing headers after upgrading from a version prior to 22.0.0

** Breaking changes **

- refuse requests where the uri field is empty (:pr:`3255`)
- refuse requests with invalid CR/LR/NUL in heade field values (:pr:`3253`)
- remove temporary ``--tolerate-dangerous-framing`` switch from 22.0 (:pr:`3260`)
- If any of the breaking changes affect you, be aware that now refused requests can post a security problem, especially so in setups involving request pipe-lining and/or proxies.

22.0.0 - 2024-04-17
===================

- use `utime` to notify workers liveness
- migrate setup to pyproject.toml
- fix numerous security vulnerabilities in HTTP parser (closing some request smuggling vectors)
- parsing additional requests is no longer attempted past unsupported request framing
- on HTTP versions < 1.1 support for chunked transfer is refused (only used in exploits)
- requests conflicting configured or passed SCRIPT_NAME now produce a verbose error
- Trailer fields are no longer inspected for headers indicating secure scheme
- support Python 3.12

** Breaking changes **

- minimum version is Python 3.7
- the limitations on valid characters in the HTTP method have been bounded to Internet Standards
- requests specifying unsupported transfer coding (order) are refused by default (rare)
- HTTP methods are no longer casefolded by default (IANA method registry contains none affected)
- HTTP methods containing the number sign (#) are no longer accepted by default (rare)
- HTTP versions < 1.0 or >= 2.0 are no longer accepted by default (rare, only HTTP/1.1 is supported)
- HTTP versions consisting of multiple digits or containing a prefix/suffix are no longer accepted
- HTTP header field names Gunicorn cannot safely map to variables are silently dropped, as in other software
- HTTP headers with empty field name are refused by default (no legitimate use cases, used in exploits)
- requests with both Transfer-Encoding and Content-Length are refused by default (such a message might indicate an attempt to perform request smuggling)
- empty transfer codings are no longer permitted (reportedly seen with really old & broken proxies)


** SECURITY **

- fix CVE-2024-1135
1 change: 0 additions & 1 deletion docs/source/conf.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
#
# Gunicorn documentation build configuration file
#
19 changes: 19 additions & 0 deletions docs/source/custom.rst
Original file line number Diff line number Diff line change
@@ -16,6 +16,25 @@ a custom Application:
:start-after: # See the NOTICE for more information
:lines: 2-

Using server hooks
------------------

If you wish to include server hooks in your custom application, you can specify a function in the config options. Here is an example with the `pre_fork` hook:

.. code-block:: python
def pre_fork(server, worker):
print(f"pre-fork server {server} worker {worker}", file=sys.stderr)
# ...
if __name__ == '__main__':
options = {
'bind': '%s:%s' % ('127.0.0.1', '8080'),
'workers': number_of_workers(),
'pre_fork': pre_fork,
}
Direct Usage of Existing WSGI Apps
----------------------------------

18 changes: 11 additions & 7 deletions docs/source/deploy.rst
Original file line number Diff line number Diff line change
@@ -246,20 +246,23 @@ to the newly created unix socket:
After=network.target

[Service]
# gunicorn can let systemd know when it is ready
Type=notify
NotifyAccess=main
# the specific user that our service will run as
User=someuser
Group=someuser
# another option for an even more restricted service is
# DynamicUser=yes
# see http://0pointer.net/blog/dynamic-users-with-systemd.html
# this user can be transiently created by systemd
# DynamicUser=true
RuntimeDirectory=gunicorn
WorkingDirectory=/home/someuser/applicationroot
ExecStart=/usr/bin/gunicorn applicationname.wsgi
ExecReload=/bin/kill -s HUP $MAINPID
KillMode=mixed
TimeoutStopSec=5
PrivateTmp=true
# if your app does not need administrative capabilities, let systemd know
# ProtectSystem=strict

[Install]
WantedBy=multi-user.target
@@ -272,11 +275,12 @@ to the newly created unix socket:
[Socket]
ListenStream=/run/gunicorn.sock
# Our service won't need permissions for the socket, since it
# inherits the file descriptor by socket activation
# only the nginx daemon will need access to the socket
# inherits the file descriptor by socket activation.
# Only the nginx daemon will need access to the socket:
SocketUser=www-data
# Optionally restrict the socket permissions even more.
# SocketMode=600
SocketGroup=www-data
# Once the user/group is correct, restrict the permissions:
SocketMode=0660

[Install]
WantedBy=sockets.target
5 changes: 1 addition & 4 deletions docs/source/design.rst
Original file line number Diff line number Diff line change
@@ -75,10 +75,7 @@ WSGI application, this is not a recommended configuration.
AsyncIO Workers
---------------

These workers are compatible with Python 3.

You can port also your application to use aiohttp_'s ``web.Application`` API and use the
``aiohttp.worker.GunicornWebWorker`` worker.
Third-party workers can be usedd to use Gunicorn with asyncio frameworks.

Choosing a Worker Type
======================
8 changes: 7 additions & 1 deletion docs/source/faq.rst
Original file line number Diff line number Diff line change
@@ -11,8 +11,14 @@ How do I set SCRIPT_NAME?
-------------------------

By default ``SCRIPT_NAME`` is an empty string. The value could be set by
setting ``SCRIPT_NAME`` in the environment or as an HTTP header.
setting ``SCRIPT_NAME`` in the environment or as an HTTP header. Note that
this headers contains and underscore, so it is only accepted from trusted
forwarders listed in the :ref:`forwarded-allow-ips` setting.

.. note::

If your application should appear in a subfolder, your ``SCRIPT_NAME``
would typically start with single slash but contain no trailing slash.

Server Stuff
============
Loading