I created a local Apache server using the official php:7.2-apache docker image. I installed mod_fcgid and included the cgi, includes, and fcgid mod packages. I made the necessary changes to the httpd.conf file and ran the server with a compiled go cgi program in the /cgi-bin folder. It works when hitting the file directly from the /cgi-bin folder, but does not work when being used included with Apache SSI both through <!--#include virtual="/cgi-bin/<bianary-name>.cgi"--> and <!--#exec cgi="/cgi-bin/<bianary-name>.cgi"-->.
After much digging I found that the issue can very simply be replicated on go.dev/play. See reproduced bug
What did you see happen?
When running both CGI and FCGI compiled programs the following error is logged when being included as server side includes:
cgi: invalid SERVER_PROTOCOL version
What did you expect to see?
FCGI implements CGI so fixing this piece in net/http/cgi will solve the issue for both CGI and FCGI.
Section 4.1.16 of the CGI Spec, RFC 3875, states the following:
A well-known value for SERVER_PROTOCOL which the server MAY use is
"INCLUDED", which signals that the current document is being included
as part of a composite document, rather than being the direct target
of the client request. The script should treat this as an HTTP/1.0
request.
The following piece of the cgi package does not properly implement this spec.
Since this relies entirely on the http.ParseHttpVersion function to validate the server protocol, the INCLUDED value for SERVER_PROTOCOL is not handled.
The fix could be implemented directly in the CGI child.go script since this only applies to CGI/FCGI only and will not cause problems by modifying http.ParseHttpVersion.
Example of one possible fix, in place of the above referenced code block:
r.Proto = params["SERVER_PROTOCOL"]
var ok bool
if r.Proto == "INCLUDED" {
// Handles SSI (Server Side Include) use case per the CGI RFC 3875 spec as specified in section 4.1.16
r.ProtoMajor, r.ProtoMinor, ok = http.ParseHTTPVersion("HTTP/1.0")
} else {
r.ProtoMajor, r.ProtoMinor, ok = http.ParseHTTPVersion(r.Proto)
}
if !ok {
return nil, errors.New("cgi: invalid SERVER_PROTOCOL version")
}
Go version
go version go1.23.1 darwin/arm64
Output of
go env
in your module/workspace:What did you do?
I created a local Apache server using the official
php:7.2-apache
docker image. I installed mod_fcgid and included the cgi, includes, and fcgid mod packages. I made the necessary changes to the httpd.conf file and ran the server with a compiled go cgi program in the /cgi-bin folder. It works when hitting the file directly from the /cgi-bin folder, but does not work when being used included with Apache SSI both through<!--#include virtual="/cgi-bin/<bianary-name>.cgi"-->
and<!--#exec cgi="/cgi-bin/<bianary-name>.cgi"-->
.After much digging I found that the issue can very simply be replicated on go.dev/play. See reproduced bug
What did you see happen?
When running both CGI and FCGI compiled programs the following error is logged when being included as server side includes:
cgi: invalid SERVER_PROTOCOL version
What did you expect to see?
FCGI implements CGI so fixing this piece in net/http/cgi will solve the issue for both CGI and FCGI.
Section 4.1.16 of the CGI Spec, RFC 3875, states the following:
The following piece of the cgi package does not properly implement this spec.
https://github.com/golang/go/blob/3ca78afb3bf4f28af1ca76875c0a15d6b87a5c50/src/net/http/cgi/child.go#L58-L63
Since this relies entirely on the
http.ParseHttpVersion
function to validate the server protocol, theINCLUDED
value for SERVER_PROTOCOL is not handled.The fix could be implemented directly in the CGI child.go script since this only applies to CGI/FCGI only and will not cause problems by modifying
http.ParseHttpVersion
.Example of one possible fix, in place of the above referenced code block: