与fastcgi的golang如何阅读REMOTE_USER

Short: How can I read the CGI var REMOTE_USER on golang using fastcgi?

Long: I'm trying to write a program in go to work behind a httpd using fcgi over a socket. The httpd does the ssl termination and provides basic auth. I need to read $REMOTE_USER, but I cannot in golang, while I can in perl.

My code is based on this fcgi example. I try

func homeView(w http.ResponseWriter, r *http.Request) {     
    user, pass, authok := r.BasicAuth()

But authok is always false, user and pass remain empty, although I know for sure that the authorization (done by httpd) was OK. To eliminate other errors, I have done it in perl:

my $socket = FCGI::OpenSocket("/run/fcgi-check.sock", 5);
my $q = FCGI::Request(\*STDIN, \*STDOUT, \*STDERR, \%ENV, $socket);

while ($q->Accept() >= 0) {
    my $c = CGI::Simple->new;
    my $user_id      = $c->remote_user(); 

and it works fine in perl.

To debug, I printed the output of r.Header and I got:

map[Authorization:[]

Am I right that the header that go sees does no hold any information about any authorization? But it does in perl.

Here is a full but minimal golang code example that demonstrates the problem (on OpenBSD 5.8 with go version go1.4.2 openbsd/amd64 and OpenBSDs httpd with 'authenticate "/" with restricted_users' in httpd.conf.

package main

import (
        "github.com/gorilla/mux"
        "io"
        "log"
        "fmt"
        "net"
        "net/http"
        "net/http/fcgi"
)


func homeView(w http.ResponseWriter, r *http.Request) {
        headers := w.Header()
        headers.Add("Content-Type", "text/html")
        headers.Add("Cache-Control", "no-cache, no-store, must-revalidate")
        headers.Add("Pragma", "no-cache")
        headers.Add("Expires", "0")
        r.ParseForm()

        user, pass, authok := r.BasicAuth()

        if authok {
                io.WriteString(w, fmt.Sprintln("Auth OK"))
                io.WriteString(w, fmt.Sprintln("user is: "+user+", pass is: "+pass))
        } else {
                io.WriteString(w, fmt.Sprintln("Auth NOT OK"))
        }
}

func main() {

        r := mux.NewRouter()
        r.HandleFunc("/check/", homeView)

    var err error
        listener, err := net.Listen("unix", "/run/fcgi-check.sock")
        if err != nil {
                log.Fatal(err)
        }
        defer listener.Close()

        err = fcgi.Serve(listener, r)
        if err != nil { log.Fatal(err)}
}

Help will be appreciated!

Thanks in advance! T.

The simple answer (as of go version 1.4.2) is that go currently does not support the transfer of CGI variable REMOTE_USER.

While @JimB is correct on that you're wrong in your approach, I'll answer the question as stated.

The net/http/fcgi package uses the machinery of net/http/cgi to populate an instance of http.Request—which is passed to your handler—with "parameters" (key/value pairs) submitted by the webserver during the FastCGI session (call). This is done here.

Now if you'll inspect the relevant bit of the net/http/cgi code, you'll see that the variables which are not mapped to specific dedicated fields of http.Request get converted to HTTP "headers".

This means, your code should be able to access the variable you need using something like

ruser := r.Header.Get("Remote-User")

Update 2015-12-02: the reseach performed by @JimB and the OP showed that there's apparently no way to read the REMOTE_USER variable under FastCGI. Sorry for the noise.

This core change to the fcgi package is in review and is close to being merged. If it's no longer relevant to you, hopefully it will be useful to others.

Go 1.9 will expose cgi environment variables. As seen in this closed ticket:

https://go-review.googlesource.com/c/40012