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 <dneil@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Junyang Shao <shaojunyang@google.com>
Reviewed-by: Sean Liao <sean@liao.dev>
Auto-Submit: Sean Liao <sean@liao.dev>
This commit is contained in:
Peter Beard 2025-10-28 10:26:26 -06:00 committed by Gopher Robot
parent 77c5130100
commit 129d0cb543
2 changed files with 27 additions and 2 deletions

View file

@ -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")
}

View file

@ -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