From 129d0cb543e1e15cdea706dd7230ee90c8d54446 Mon Sep 17 00:00:00 2001 From: Peter Beard Date: Tue, 28 Oct 2025 10:26:26 -0600 Subject: [PATCH] net/http/cgi: accept INCLUDED as protocol for server side includes The existing protocol check for fcgi/cgi requests did not properly account for Apache SSI (Server-Side Includes) SERVER_PROTOCOL value of INCLUDED. Added check for well-known INCLUDED value for proper implementation of the CGI Spec as specified in RFC 3875 - section 4.1.16. The SERVER_PROTOCOL section of the specification is outlined at https://www.rfc-editor.org/rfc/rfc3875.html#section-4.1.16 Fixes #70416 Change-Id: I129e606147e16d1daefb49ed6c13a561a88ddeb6 Reviewed-on: https://go-review.googlesource.com/c/go/+/715680 Reviewed-by: Damien Neil LUCI-TryBot-Result: Go LUCI Reviewed-by: Junyang Shao Reviewed-by: Sean Liao Auto-Submit: Sean Liao --- src/net/http/cgi/child.go | 7 +++++-- src/net/http/cgi/child_test.go | 22 ++++++++++++++++++++++ 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/src/net/http/cgi/child.go b/src/net/http/cgi/child.go index e29fe20d7d5..466d42c08e9 100644 --- a/src/net/http/cgi/child.go +++ b/src/net/http/cgi/child.go @@ -57,8 +57,11 @@ func RequestFromMap(params map[string]string) (*http.Request, error) { r.Proto = params["SERVER_PROTOCOL"] var ok bool - r.ProtoMajor, r.ProtoMinor, ok = http.ParseHTTPVersion(r.Proto) - if !ok { + if r.Proto == "INCLUDED" { + // SSI (Server Side Include) use case + // CGI Specification RFC 3875 - section 4.1.16 + r.ProtoMajor, r.ProtoMinor = 1, 0 + } else if r.ProtoMajor, r.ProtoMinor, ok = http.ParseHTTPVersion(r.Proto); !ok { return nil, errors.New("cgi: invalid SERVER_PROTOCOL version") } diff --git a/src/net/http/cgi/child_test.go b/src/net/http/cgi/child_test.go index 18cf789bd59..f901bec1a84 100644 --- a/src/net/http/cgi/child_test.go +++ b/src/net/http/cgi/child_test.go @@ -154,6 +154,28 @@ func TestRequestWithoutRemotePort(t *testing.T) { } } +// CGI Specification RFC 3875 - section 4.1.16 +// INCLUDED value for SERVER_PROTOCOL must be treated as an HTTP/1.0 request +func TestIncludedServerProtocol(t *testing.T) { + env := map[string]string{ + "REQUEST_METHOD": "GET", + "SERVER_PROTOCOL": "INCLUDED", + } + req, err := RequestFromMap(env) + if req.Proto != "INCLUDED" { + t.Errorf("unexpected change to SERVER_PROTOCOL") + } + if major := req.ProtoMajor; major != 1 { + t.Errorf("ProtoMajor: got %d, want %d", major, 1) + } + if minor := req.ProtoMinor; minor != 0 { + t.Errorf("ProtoMinor: got %d, want %d", minor, 0) + } + if err != nil { + t.Fatalf("expected INCLUDED to be treated as HTTP/1.0 request") + } +} + func TestResponse(t *testing.T) { var tests = []struct { name string