nginx/nginx
HTTP server
Active contributors: Sergey Kandaurov, Roman Arutyunyan, Maxim Dounin, Roman Semenov
Purpose
The largest subsystem in the codebase. The HTTP server implements RFC 7230/7231 (HTTP/1.1), RFC 7540 (HTTP/2), RFC 9114 (HTTP/3 over QUIC), the upstream-proxying machinery for HTTP/FastCGI/uwsgi/SCGI/gRPC, the file cache, the variable + script engine, and 50+ bundled modules that hook into a 11-phase request engine.
Sub-pages
- Request lifecycle — the 11 phases, headers, body, finalize
- Upstream — proxying to backends
- File cache —
proxy_cache,fastcgi_cache, etc. - Variables and scripts —
$variable, complex values, the script bytecode - HTTP/2 — frame parser, HPACK, the v2 filter
- HTTP/3 — over QUIC, QPACK
- Modules — the 60+ bundled http modules and how they hook in
Directory layout
src/http/
├── ngx_http.{c,h} # the http { } module + bootstrap
├── ngx_http_config.h # ngx_http_module_t hook table
├── ngx_http_core_module.{c,h} # core directives, phase engine, locations
├── ngx_http_request.{c,h} # ngx_http_request_t + lifecycle
├── ngx_http_request_body.c # request body reading + chunked decoder
├── ngx_http_parse.c # raw header / request-line parser
├── ngx_http_header_filter_module.c # the canonical response header writer
├── ngx_http_write_filter_module.c # the bottom of the body filter chain
├── ngx_http_postpone_filter_module.c # subrequest output ordering
├── ngx_http_copy_filter_module.c # async file → output
├── ngx_http_special_response.c # default error pages
├── ngx_http_variables.{c,h} # $variables + the variable hash
├── ngx_http_script.{c,h} # complex value bytecode engine
├── ngx_http_upstream.{c,h} # upstream subsystem (see upstream.md)
├── ngx_http_upstream_round_robin.{c,h} # default load balancer
├── ngx_http_file_cache.c # file cache + cache index
├── ngx_http_huff_decode.c # static Huffman decode (HPACK)
├── ngx_http_huff_encode.c # static Huffman encode (HPACK)
├── ngx_http_cache.h # cache types
├── modules/ # ~60 bundled HTTP modules
├── v2/ # HTTP/2 (see http2.md)
└── v3/ # HTTP/3 (see http3.md)How an HTTP request flows
graph TD
Acc[ngx_event_accept] --> Init[ngx_http_init_connection]
Init --> Wait[wait for first byte:<br/>read handler = ngx_http_wait_request_handler]
Wait --> Read[read + parse request line<br/>ngx_http_process_request_line]
Read --> Hdrs[read + parse headers<br/>ngx_http_process_request_headers]
Hdrs --> Process[ngx_http_process_request]
Process --> Phases[11-phase engine]
Phases --> Handler[content handler]
Handler --> Filter[output filter chain]
Filter --> Final[ngx_http_finalize_request]
Final --> KA{keepalive?}
KA -->|yes| Wait
KA -->|no| Close[ngx_http_close_connection]The big states are: connection accept → request parse → 11-phase processing → content handler → output filters → finalize → either start over (HTTP keep-alive) or close.
For HTTP/2 and HTTP/3 there's an extra layer on top: the framing parser (ngx_http_v2.c or ngx_http_v3_request.c) creates one ngx_http_request_t per stream and runs the same engine for each. The phase engine is protocol-agnostic — that's the whole reason it exists.
See request-lifecycle for the full 11-phase walkthrough.
Phases at a glance
| Phase | What's in it | Typical modules attached |
|---|---|---|
POST_READ |
Earliest hook after headers parsed | realip |
SERVER_REWRITE |
rewrite directives at server scope |
rewrite |
FIND_CONFIG |
Choose a location block (special — implicit) |
(core) |
REWRITE |
rewrite at location scope |
rewrite |
POST_REWRITE |
After rewrite, may re-do FIND_CONFIG |
(core) |
PREACCESS |
Before access checks | limit_conn, limit_req, degradation |
ACCESS |
Authorization | access, auth_basic, auth_request |
POST_ACCESS |
If satisfy any; — mediate between access modules |
(core) |
PRECONTENT |
Before content (used by try_files, mirror) |
try_files, mirror |
CONTENT |
The handler that produces the body | static, proxy, fastcgi, uwsgi, dav, autoindex, ... |
LOG |
Per-request bookkeeping | log (access log) |
Filter chain
After the content handler produces buffers, output flows through two ordered filter chains:
header filter chain ─▶ body filter chain ─▶ ngx_http_write_filterFilters chain by capturing the ngx_http_top_header_filter / ngx_http_top_body_filter global function pointers at module init and writing themselves on top. When invoked, each filter does its work and then calls the previous top via ngx_http_next_*_filter.
Common filters in order (innermost first as you read down):
ngx_http_postpone_filter (handle subrequests)
ngx_http_ssi_filter
ngx_http_charset_filter
ngx_http_addition_filter (add_after_body, add_before_body)
ngx_http_image_filter
ngx_http_xslt_filter
ngx_http_sub_filter
ngx_http_gunzip_filter
ngx_http_userid_filter (Set-Cookie)
ngx_http_headers_filter (Cache-Control, Expires, ...)
ngx_http_not_modified_filter (304)
ngx_http_range_filter
ngx_http_slice_filter
ngx_http_chunked_filter
ngx_http_v2_filter / ngx_http_v3_filter (only on H2/H3)
ngx_http_gzip_filter
ngx_http_header_filter (writes the status line + headers)
ngx_http_write_filter (sends out via socket / SSL)Each one is its own module under src/http/modules/ or src/http/. See modules.
Subrequests
A subrequest is an internally-generated request running on the parent's connection. Used by:
- SSI —
<!--# include -->triggers a subrequest. add_after_body— append the body of another location.auth_request— query an auth endpoint before serving content.mirror— copy a request to a side endpoint.
Subrequests get their own ngx_http_request_t and pool but share r->connection. Output ordering is handled by the postpone filter, which ensures the parent's bytes interleave correctly with subrequest output.
Integration points
- Event loop — every read/write goes through the standard
ngx_event_tmachinery. HTTP modules typically don't call into the event loop directly; they set handlers and return. - OpenSSL integration — TLS-protected HTTP just sees
c->ssl != NULLon the connection. Reads/writes go throughngx_ssl_recv/ngx_ssl_send(see openssl). - QUIC — for HTTP/3, the connection is a QUIC stream and reads/writes go through
ngx_quic_*(see quic). The HTTP/3 layer (src/http/v3/) translates between QUIC frames andngx_http_request_t. - Configuration — every HTTP directive is an
ngx_command_twithNGX_HTTP_*_CONFcontext bits. Configs are merged top-down: main → server → location. - Variables — set up via
ngx_http_add_variable()at preconfiguration time. Read viangx_http_get_indexed_variable(r, idx).
Entry points for modification
If you're adding new behavior, the question is "which phase, which filter, or which content handler?" — that determines which file gets the new code. Adding a new HTTP module is a self-contained job: see primitives/module for the skeleton. Touching the request engine itself is rare and warrants careful review; most "I want X to happen during request processing" cases are handled by attaching a phase handler.
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.