Skip to content

mod_http3: Run the post_read_request hooks for HTTP/3 requests - #944

Open
mbeijen wants to merge 2 commits into
apache:trunkfrom
mbeijen:h3-post-read-request
Open

mbeijen wants to merge 2 commits into
apache:trunkfrom
mbeijen:h3-post-read-request

Conversation

@mbeijen

@mbeijen mbeijen commented Nov 4, 2026

Copy link
Copy Markdown
Contributor

mod_http3 went straight from building the request_rec to ap_process_request(), skipping the ap_check_request_header() and ap_post_read_request() steps that HTTP/1.1 and HTTP/2 run on every request. So StrictHostCheck, the missing-Host and Expect checks and every post_read_request hook (SetEnvIf, RemoteIPHeader, RequestHeader early, …) were ignored over HTTP/3. With SetEnvIf User-Agent ^evilbot bad_bot and Require not env bad_bot, a request got 403 over HTTP/1.1 but 200 over HTTP/3.

This builds on #943 for the test package; only the last commit is new here.

  • This PR does not report or address a security vulnerability (see SECURITY.md and https://www.apache.org/security/#reporting-a-vulnerability).
  • Code follows the httpd style guide.
  • New log messages (level debug or higher) use an empty APLOGNO() tag; numbers are assigned by a committer at merge time (see docs/log-message-tags/README).
  • If the change is user-visible, a changes-entries/*.txt file is included, following the template in README.CHANGES (not needed otherwise).
  • Test cases based on pyhttpd are included where appropriate, in the test/modules/xxx directory matching the modules/xxx module source, or test/modules/core for core server changes. On Unix, verify these pass locally with e.g. make check-pytest PYTEST_DIRS=test/modules/xxx.

test/modules/http3 runs requests over HTTP/3 with curl --http3-only
against a QUIC listener on the https port number. It covers static
files, HEAD, 404, a 1 MB response, several requests on one connection,
virtual host selection by Host, POST content to CGI up to 1 MB and the
CGI environment.

The package is skipped when mod_http3, mod_ssl or curl's HTTP3 feature
is missing.

Generated-by: Claude Code (Claude Opus 5.5)
stream_worker() built the request_rec and went straight to
ap_process_request(), with only ap_update_vhost_from_headers() in
between.  It skipped the two steps that HTTP/1.1 (ap_read_request()) and
HTTP/2 (h2_create_request_rec()) run on every request:

* ap_check_request_header(): vhost selection with StrictHostCheck, the
  missing Host check and Expect handling.
* ap_post_read_request(): the post_read_request hooks of mod_setenvif,
  mod_remoteip, mod_headers ("early"), mod_proxy (forward proxy
  detection), mod_md, mod_unique_id and others, plus the core checks on
  the complete request.  mod_http3's own h3_hook_post_read_request never
  ran for its own requests either.

So configuration behaved differently over HTTP/3, including access
control: with "SetEnvIf User-Agent ^evilbot bad_bot" and
"Require not env bad_bot", a request was denied with 403 over HTTP/1.1
but served with 200 over HTTP/3.  Both now give 403.

Add test_003_access.py to the mod_http3 tests for this.

Generated-by: Claude Code (Claude Opus 5.5)
@mbeijen mbeijen mentioned this pull request Nov 4, 2026
5 tasks done
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant