Missing environment vars with nginx + golang and fcgi

467 views
Skip to first unread message

Rob Alfonso

unread,
Jun 4, 2015, 3:26:47 PM6/4/15
to golan...@googlegroups.com


I'm using nginx and fcgi with golang, the nginx and golang code is below.  I'm not getting any of the "fastcgi_params" set in the go code.  My understanding is the variables are made available to the environment but os.Environ doesn't print anything out, however, normal enviroment data is printed, just nothing appended for the request.

Nginx Config

   location ~* ^/(.+)$ {

    fastcgi_param TEST $1;
    fastcgi_param FOO "bar";
    fastcgi_param REMOTE_ADDR $http_x_real_ip;
    fastcgi_param HTTP_CLIENT_IP $http_x_real_ip;
    fastcgi_split_path_info ^(.+.php)(.*)$;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    fastcgi_param SCRIPT_NAME $fastcgi_script_name;
    fastcgi_param PATH_INFO $fastcgi_path_info;
    fastcgi_pass 127.0.0.1:9150;
    include fastcgi_params;
  }



Fcgi server


package main

import (

    "log"
    "net"
    "os"
    "net/http"
    "net/http/fcgi"
)



type FastCGIServer struct{}

func (s FastCGIServer) ServeHTTP(resp http.ResponseWriter, req *http.Request) {

headers := resp.Header()
        headers.Add("Content-Type", "text/html")
log.Println(req.Body)
log.Println(os.Environ());
log.Println(os.Getenv("FOO"))
        resp.Write([]byte("Hello World"))
}

func main() {
 listener, _ := net.Listen("tcp", "127.0.0.1:9000")
 srv := new(FastCGIServer)
 fcgi.Serve(listener, srv)

}




Any help is appreciated, I went through net/http/cgi and accessed the environment the same way so I'm pulling my hair out a bit.

Thanks,

Rob








Tamás Gulácsi

unread,
Jun 4, 2015, 4:41:21 PM6/4/15
to golan...@googlegroups.com
Are you sure that fastcgi works that way? That was the plain old cgi way.

Rob Alfonso

unread,
Jun 4, 2015, 4:57:08 PM6/4/15
to golan...@googlegroups.com
I don't know for sure, but I know using php-fpm you can load the environment with nginx fastcgi_params. It also appears using cgi you can do it, so it seems reasonable to be able to do it here as well. Obviously its not working but there must be some kind of way.  Whats unclear at the moment is if the environment is loaded by nginx or the variables are passed to the fcgi handler to do so, however, if thats the case I can't see to figure out where they are coming from.

Kiki Sugiaman

unread,
Jun 4, 2015, 5:24:44 PM6/4/15
to golan...@googlegroups.com
I think only params with "HTTP_" prefix get parsed into the
http.Request. In other words, change FOO to HTTP_FOO, then retrieve
using req.Header.Get("FOO").
The OS environment thing only works for cgi.
I could be wrong.

Brad Fitzpatrick

unread,
Jun 4, 2015, 11:08:09 PM6/4/15
to Rob Alfonso, golang-nuts
It appears that Go's CGI and FCGI server only support passing through params if they start with "HTTP_", and then they show up in req.Header.  For instance, param "HTTP_FOO_BAR" will show up in req.Header.Get("Foo-Bar").

Them showing up in os.Environ() doesn't make sense: that's a global resource, and many HTTP requests can be going on at once.


--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Rob Alfonso

unread,
Jun 5, 2015, 10:26:21 AM6/5/15
to golan...@googlegroups.com, ralf...@dnc.io
Thanks Brad,

I can confirm for anyone reading this later that 

req.Header.Get("Foo")
req.Header.Get("FOO")

Work for someone passing HTTP_FOO in a fastcgi param in nginx

Regarding os.Environ I understand what you are saying (and thought that myself), though I think something else is going on as its used in net/http/cgi

 r, err := RequestFromMap(envMap(os.Environ())) 

And is accessing things like REQUEST_URI that appear to be part of the environment in that scope.

Rob

Brad Fitzpatrick

unread,
Jun 5, 2015, 10:30:25 AM6/5/15
to Rob Alfonso, golang-nuts
On Fri, Jun 5, 2015 at 7:26 AM, Rob Alfonso <ralf...@dnc.io> wrote:
Thanks Brad,

I can confirm for anyone reading this later that 

req.Header.Get("Foo")
req.Header.Get("FOO")

Work for someone passing HTTP_FOO in a fastcgi param in nginx

Regarding os.Environ I understand what you are saying (and thought that myself), though I think something else is going on as its used in net/http/cgi

 r, err := RequestFromMap(envMap(os.Environ())) 

And is accessing things like REQUEST_URI that appear to be part of the environment in that scope.

No, those aren't passed via the environment. That's not how the FCGI protocol works.

Back in the day when there were only processes for concurrency it made sense to use environment variables so things were mashed together both to & from environment variables on both sides (server host & child worker) but REQUEST_URI isn't an environment variable on either side, even though that's how it appeared in CGI back in the day.  (and FCGI when you had a process-per-request)




Kiki Sugiaman

unread,
Jun 5, 2015, 11:00:16 AM6/5/15
to golan...@googlegroups.com


On 06/06/15 00:26, Rob Alfonso wrote:
Thanks Brad,

I can confirm for anyone reading this later that 

req.Header.Get("Foo")
req.Header.Get("FOO")

Work for someone passing HTTP_FOO in a fastcgi param in nginx

Regarding os.Environ I understand what you are saying (and thought that myself), though I think something else is going on as its used in net/http/cgi

 r, err := RequestFromMap(envMap(os.Environ()))

That's snippet from cgi. The fcgi equivalent is:
   250		httpReq, err := cgi.RequestFromMap(req.params)
So, nothing is read from the environment.
Also, some params without "HTTP_" prefix like "REQUEST_METHOD" are parsed into req. Other than those few predefined ones, the prefix is needed.
Reply all
Reply to author
Forward
0 new messages