Open-Source Wikis

/

nginx

/

Systems

/

HTTP server

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

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_filter

Filters 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_t machinery. 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 != NULL on the connection. Reads/writes go through ngx_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 and ngx_http_request_t.
  • Configuration — every HTTP directive is an ngx_command_t with NGX_HTTP_*_CONF context bits. Configs are merged top-down: main → server → location.
  • Variables — set up via ngx_http_add_variable() at preconfiguration time. Read via ngx_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.

HTTP server – nginx wiki | Factory