caddyhttp: add {http.request.proto_name} placeholder for spec-compliant protocol names (#7782)
* caddyhttp: add {http.request.proto_name} placeholder for spec-compliant protocol names
{http.request.proto} exposes Go's raw http.Request.Proto field which
returns HTTP/2.0 and HTTP/3.0 for HTTP/2 and HTTP/3 respectively.
These strings are non-standard since the specs define them as HTTP/2
and HTTP/3.
To preserve backward compat (especially CGI/FastCGI expectations),
{http.request.proto} is kept as-is. A new {http.request.proto_name}
placeholder is introduced that normalises the version string to the
spec-defined form:
HTTP/2.0 -> HTTP/2
HTTP/3.0 -> HTTP/3
all others returned unchanged
Closes #7734
* caddyhttp: Use ProtoMajor for proto_name normalization and update docs
---------
Co-authored-by: jalikajalika5 <105954036+jalikajalika5@users.noreply.github.com>
pull/7799/head^2
parent
fcc7860d03
commit
915793f6e0
|
|
@ -70,7 +70,8 @@ func init() {
|
|||
// `{http.request.orig_uri.query}` | The request's original query string (without `?`)
|
||||
// `{http.request.orig_uri.prefixed_query}` | The request's original query string with a `?` prefix, if non-empty
|
||||
// `{http.request.port}` | The port part of the request's Host header
|
||||
// `{http.request.proto}` | The protocol of the request
|
||||
// `{http.request.proto}` | The raw protocol of the request as returned by Go (e.g., HTTP/2.0 or HTTP/3.0)
|
||||
// `{http.request.proto_name}` | The spec-defined protocol of the request (e.g., HTTP/2 or HTTP/3)
|
||||
// `{http.request.local.host}` | The host (IP) part of the local address the connection arrived on
|
||||
// `{http.request.local.port}` | The port part of the local address the connection arrived on
|
||||
// `{http.request.local}` | The local address the connection arrived on
|
||||
|
|
|
|||
|
|
@ -105,6 +105,14 @@ func addHTTPVarsToReplacer(repl *caddy.Replacer, req *http.Request, w http.Respo
|
|||
return "http", true
|
||||
case "http.request.proto":
|
||||
return req.Proto, true
|
||||
case "http.request.proto_name":
|
||||
if req.ProtoMajor == 2 {
|
||||
return "HTTP/2", true
|
||||
}
|
||||
if req.ProtoMajor == 3 {
|
||||
return "HTTP/3", true
|
||||
}
|
||||
return req.Proto, true
|
||||
case "http.request.host":
|
||||
host, _, err := net.SplitHostPort(req.Host)
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -266,3 +266,33 @@ eqp31wM9il1n+guTNyxJd+FzVAH+hCZE5K+tCgVDdVFUlDEHHbS/wqb2PSIoouLV
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestHTTPProtoNameNormalization(t *testing.T) {
|
||||
for _, tc := range []struct {
|
||||
proto string
|
||||
major int
|
||||
expectRaw string
|
||||
expectName string
|
||||
}{
|
||||
{proto: "HTTP/1.0", major: 1, expectRaw: "HTTP/1.0", expectName: "HTTP/1.0"},
|
||||
{proto: "HTTP/1.1", major: 1, expectRaw: "HTTP/1.1", expectName: "HTTP/1.1"},
|
||||
{proto: "HTTP/2.0", major: 2, expectRaw: "HTTP/2.0", expectName: "HTTP/2"},
|
||||
{proto: "HTTP/3.0", major: 3, expectRaw: "HTTP/3.0", expectName: "HTTP/3"},
|
||||
} {
|
||||
req := httptest.NewRequest(http.MethodGet, "/", nil)
|
||||
req.Proto = tc.proto
|
||||
req.ProtoMajor = tc.major
|
||||
repl := caddy.NewReplacer()
|
||||
addHTTPVarsToReplacer(repl, req, nil)
|
||||
|
||||
gotRaw, okRaw := repl.GetString("http.request.proto")
|
||||
if !okRaw || gotRaw != tc.expectRaw {
|
||||
t.Errorf("proto=%s: expected http.request.proto to be %q, got %q (ok=%t)", tc.proto, tc.expectRaw, gotRaw, okRaw)
|
||||
}
|
||||
|
||||
gotName, okName := repl.GetString("http.request.proto_name")
|
||||
if !okName || gotName != tc.expectName {
|
||||
t.Errorf("proto=%s: expected http.request.proto_name to be %q, got %q (ok=%t)", tc.proto, tc.expectName, gotName, okName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue