https://bz.apache.org/bugzilla/show_bug.cgi?id=70195

            Bug ID: 70195
           Summary: mod_http2 rejects asterisk-form "OPTIONS *" with 400
                    since 2.4.55
           Product: Apache httpd-2
           Version: 2.4.68
          Hardware: Other
                OS: Linux
            Status: NEW
          Severity: normal
          Priority: P2
         Component: mod_http2
          Assignee: [email protected]
          Reporter: [email protected]
  Target Milestone: ---

Symptom:

The server answers 400 to "OPTIONS *" over HTTP/2, but succeeds over HTTP/1.1.
The problem occurs both with default tls h2 and with h2c.

This violates RFC 9113 for HTTP/2, ยง8.3.1, fourth bullet point: " A request in
asterisk form (for OPTIONS) includes the value '*' for the ":path"
pseudo-header field."

The server correctly replies 200 from 2.4.23 (at least) to 2.4.54 included, and
started failing with 2.4.55 including 58, 66, 67, 68. The same versions all
pass over HTTP/1.1

 On a related version note, Ubuntu 22.04's apache2 2.4.52-1ubuntu4.23 carries
the version number of a working release but backports the change: a stock
container of it, with only "Protocols h2c http/1.1" added, answers 200 over
HTTP/1.1 and 400 over h2.

Diagnosis - created by Claude Opus 5, verified manually by me

tl;dr: Root cause is
https://github.com/apache/httpd/commit/b90220157d4ef25d2ecbbb96ee8b2e99b661f8d5#diff-560c73821ce0f1f56db0567922f8c3227a929f646c1cd4e1abf1bf0f83ae2fd6R780-R852

-----
Introduced by r1897940 (trunk, 2022-02-10), first released in 2.4.55.
Its log message reads "Checks on combinations of pseudo-headers
values/absence have been added as described in RFC 7540", fixing
https://github.com/icing/mod_h2/issues/230. It added to
modules/http2/h2_stream.c:

    if (req->scheme && (req->path && req->path[0] != '/')) {
        ... APLOGNO(10379) ...
        set_error_response(stream, HTTP_BAD_REQUEST);
        goto cleanup;
    }

For "OPTIONS *" the path is "*", so path[0] != '/' holds and the stream is
failed. The same check is present unchanged in trunk.

The same commit documents the rule this breaks, roughly twenty lines
above the check, quoting RFC 7540 section 8.1.2.3:

    This [:path] pseudo-header field MUST NOT be empty for "http" or
    "https" URIs; "http" or "https" URIs that do not contain a path
    component MUST include a value of '/'. The exception to this rule is
    an OPTIONS request for an "http" or "https" URI that does not include
    a path component; these MUST include a ":path" pseudo-header field
    with a value of '*'

So the asterisk exception appears to have been documented but not
implemented.

Suggested fix
-------------
Exempt a path of exactly "*" when the method is OPTIONS, before the
absolute-URL check, mirroring what ap_parse_request_line() already does
for HTTP/1.1:

    r->method_number != M_OPTIONS || strcmp(r->parsed_uri.path, "*") != 0

References
----------
r1897940            https://svn.apache.org/r1897940
git mirror         
https://github.com/apache/httpd/commit/b90220157d4ef25d2ecbbb96ee8b2e99b661f8d5
issue it fixed      https://github.com/icing/mod_h2/issues/230

Related
-------
bz 66499 reports a different regression from the same commit (":scheme"
mismatch behind a TLS-terminating proxy) and is currently REOPENED.
icing/mod_h2 #271 reported another (REQUEST_URI carrying an absolute URL)
and was fixed in 2.4.58. This report concerns ":path" rather than
":scheme", and I found no existing report of it.

-- 
You are receiving this mail because:
You are the assignee for the bug.
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to