Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions docs/content/reference/settings.md
Original file line number Diff line number Diff line change
Expand Up @@ -1218,6 +1218,7 @@ The protocol for incoming connections.

* ``http`` - Standard HTTP/1.x (default)
* ``uwsgi`` - uWSGI binary protocol (for nginx uwsgi_pass)
* ``fastcgi`` - FastCGI binary protocol (for nginx fastcgi_pass)

When using the uWSGI protocol, Gunicorn can receive requests from
nginx using the uwsgi_pass directive::
Expand All @@ -1230,6 +1231,17 @@ nginx using the uwsgi_pass directive::
include uwsgi_params;
}

When using the FastCGI protocol, Gunicorn can receive requests from
nginx using the fastcgi_pass directive::

upstream gunicorn {
server 127.0.0.1:8000;
}
location / {
fastcgi_pass gunicorn;
include fastcgi_params;
}

### `uwsgi_allow_ips`

**Command line:** `--uwsgi-allow-from`
Expand All @@ -1243,6 +1255,23 @@ don't know in advance the IP address of front-end, but instead have
ensured via other means that only your authorized front-ends can
access Gunicorn.

!!! note
This option does not affect UNIX socket connections. Connections not associated with
an IP address are treated as allowed, unconditionally.

### `fastcgi_allow_ips`

**Command line:** `--fastcgi-allow-from`

**Default:** `'127.0.0.1,::1'`

IPs allowed to send FastCGI protocol requests (comma separated).

Set to ``*`` to allow all IPs. This is useful for setups where you
don't know in advance the IP address of front-end, but instead have
ensured via other means that only your authorized front-ends can
access Gunicorn.

!!! note
This option does not affect UNIX socket connections. Connections not associated with
an IP address are treated as allowed, unconditionally.
Expand Down
33 changes: 33 additions & 0 deletions gunicorn/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -2212,6 +2212,7 @@ class Protocol(Setting):

* ``http`` - Standard HTTP/1.x (default)
* ``uwsgi`` - uWSGI binary protocol (for nginx uwsgi_pass)
* ``fastcgi`` - FastCGI binary protocol (for nginx fastcgi_pass)

When using the uWSGI protocol, Gunicorn can receive requests from
nginx using the uwsgi_pass directive::
Expand All @@ -2223,6 +2224,17 @@ class Protocol(Setting):
uwsgi_pass gunicorn;
include uwsgi_params;
}

When using the FastCGI protocol, Gunicorn can receive requests from
nginx using the fastcgi_pass directive::

upstream gunicorn {
server 127.0.0.1:8000;
}
location / {
fastcgi_pass gunicorn;
include fastcgi_params;
}
"""


Expand All @@ -2247,6 +2259,27 @@ class UWSGIAllowFrom(Setting):
"""


class FastCGIAllowFrom(Setting):
name = "fastcgi_allow_ips"
section = "Server Mechanics"
cli = ["--fastcgi-allow-from"]
validator = validate_string_to_addr_list
default = "127.0.0.1,::1"
desc = """\
IPs allowed to send FastCGI protocol requests (comma separated).

Set to ``*`` to allow all IPs. This is useful for setups where you
don't know in advance the IP address of front-end, but instead have
ensured via other means that only your authorized front-ends can
access Gunicorn.

.. note::

This option does not affect UNIX socket connections. Connections not associated with
an IP address are treated as allowed, unconditionally.
"""


class KeyFile(Setting):
name = "keyfile"
section = "SSL"
Expand Down
31 changes: 31 additions & 0 deletions gunicorn/fastcgi/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#
# This file is part of gunicorn released under the MIT license.
# See the NOTICE for more information.

from gunicorn.fastcgi.message import (
FastCGIRequest,
FastCGIConnectionState,
FastCGIRequestFromState,
RequestState,
)
from gunicorn.fastcgi.parser import FastCGIParser
from gunicorn.fastcgi.response import FastCGIResponse
from gunicorn.fastcgi.errors import (
FastCGIParseException,
InvalidFastCGIRecord,
UnsupportedRole,
ForbiddenFastCGIRequest,
)

__all__ = [
'FastCGIRequest',
'FastCGIConnectionState',
'FastCGIRequestFromState',
'RequestState',
'FastCGIParser',
'FastCGIResponse',
'FastCGIParseException',
'InvalidFastCGIRecord',
'UnsupportedRole',
'ForbiddenFastCGIRequest',
]
66 changes: 66 additions & 0 deletions gunicorn/fastcgi/constants.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
#
# This file is part of gunicorn released under the MIT license.
# See the NOTICE for more information.

"""FastCGI protocol constants.

Based on the FastCGI Specification:
https://fastcgi-archives.github.io/FastCGI_Specification.html
"""

# Protocol version
FCGI_VERSION_1 = 1

# Record types
FCGI_BEGIN_REQUEST = 1
FCGI_ABORT_REQUEST = 2
FCGI_END_REQUEST = 3
FCGI_PARAMS = 4
FCGI_STDIN = 5
FCGI_STDOUT = 6
FCGI_STDERR = 7
FCGI_DATA = 8
FCGI_GET_VALUES = 9
FCGI_GET_VALUES_RESULT = 10
FCGI_UNKNOWN_TYPE = 11

# Roles (in BEGIN_REQUEST)
FCGI_RESPONDER = 1
FCGI_AUTHORIZER = 2
FCGI_FILTER = 3

# Flags (in BEGIN_REQUEST)
FCGI_KEEP_CONN = 1

# Protocol status (in END_REQUEST)
FCGI_REQUEST_COMPLETE = 0
FCGI_CANT_MPX_CONN = 1
FCGI_OVERLOADED = 2
FCGI_UNKNOWN_ROLE = 3

# Header size (8 bytes fixed)
FCGI_HEADER_LEN = 8

# Maximum content length per record (64KB - 1)
FCGI_MAX_CONTENT_LEN = 65535

# Maximum number of parameters to prevent DoS
MAX_FCGI_PARAMS = 1000

# Null request ID (for management records)
FCGI_NULL_REQUEST_ID = 0

# Record type names for debugging
FCGI_RECORD_TYPES = {
FCGI_BEGIN_REQUEST: 'BEGIN_REQUEST',
FCGI_ABORT_REQUEST: 'ABORT_REQUEST',
FCGI_END_REQUEST: 'END_REQUEST',
FCGI_PARAMS: 'PARAMS',
FCGI_STDIN: 'STDIN',
FCGI_STDOUT: 'STDOUT',
FCGI_STDERR: 'STDERR',
FCGI_DATA: 'DATA',
FCGI_GET_VALUES: 'GET_VALUES',
FCGI_GET_VALUES_RESULT: 'GET_VALUES_RESULT',
FCGI_UNKNOWN_TYPE: 'UNKNOWN_TYPE',
}
46 changes: 46 additions & 0 deletions gunicorn/fastcgi/errors.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#
# This file is part of gunicorn released under the MIT license.
# See the NOTICE for more information.

# We don't need to call super() in __init__ methods of our
# BaseException and Exception classes because we also define
# our own __str__ methods so there is no need to pass 'message'
# to the base class to get a meaningful output from 'str(exc)'.
# pylint: disable=super-init-not-called


class FastCGIParseException(Exception):
"""Base exception for FastCGI protocol parsing errors."""


class InvalidFastCGIRecord(FastCGIParseException):
"""Raised when a FastCGI record is malformed."""

def __init__(self, msg=""):
self.msg = msg
self.code = 400

def __str__(self):
return "Invalid FastCGI record: %s" % self.msg


class UnsupportedRole(FastCGIParseException):
"""Raised when the FastCGI role is not RESPONDER."""

def __init__(self, role):
self.role = role
self.code = 501

def __str__(self):
return "Unsupported FastCGI role: %d" % self.role


class ForbiddenFastCGIRequest(FastCGIParseException):
"""Raised when source IP is not in the allow list."""

def __init__(self, host):
self.host = host
self.code = 403

def __str__(self):
return "FastCGI request from %r not allowed" % self.host
Loading
Loading