package cfg import ( "fmt" "io" "log" "net" "net/http" "path" "strconv" "strings" "time" fcgiclient "github.com/alash3al/go-fastcgi-client" "go.stargrave.org/godlighty" ) func ServeFCGI( w http.ResponseWriter, r *http.Request, host, docRoot, scriptName, sockProto, sockPath string, timeout time.Duration, ) { defer r.Body.Close() serverHost, serverPort, err := net.SplitHostPort(godlighty.BindAddr) if err != nil { panic(err) } remoteAddr, remotePort, _ := net.SplitHostPort(r.RemoteAddr) params := map[string]string{ "GATEWAY_INTERFACE": "CGI/1.1", "PATH_INFO": r.URL.Path, "QUERY_STRING": r.URL.RawQuery, "REMOTE_ADDR": remoteAddr, "REMOTE_PORT": remotePort, "SERVER_NAME": serverHost, "SERVER_PORT": serverPort, "SERVER_PROTOCOL": r.Proto, "SERVER_SOFTWARE": godlighty.Version, "REQUEST_METHOD": r.Method, "DOCUMENT_ROOT": docRoot, "SCRIPT_NAME": scriptName, "SCRIPT_FILENAME": path.Join(docRoot, scriptName), } for k, vs := range r.Header { if len(vs) < 1 { continue } k = "HTTP_" + strings.ToUpper(strings.Replace(k, "-", "_", -1)) params[k] = strings.Join(vs, ";") } c, err := fcgiclient.Dial(sockProto, sockPath) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) log.Println("can not FCGI:", err) return } defer c.Close() c.SetReadTimeout(timeout) c.SetSendTimeout(timeout) resp, err := c.Request(params, r.Body) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) log.Println("can not FCGI:", err) return } defer resp.Body.Close() for k, vs := range resp.Header { for _, v := range vs { w.Header().Add(k, v) } } if resp.ContentLength > 0 { w.Header().Set("Content-Length", strconv.FormatInt(resp.ContentLength, 10)) } w.WriteHeader(resp.StatusCode) written, err := io.Copy(w, resp.Body) if err != nil { stderr := c.Stderr() log.Println("can not copy FCGI:", string(stderr.Bytes())) return } fmt.Printf("%s %s \"%s %+q %s\" %d %d \"%s\"\n", r.RemoteAddr, host, r.Method, godlighty.PathWithQuery(r.URL), r.Proto, resp.StatusCode, written, r.Header.Get("User-Agent"), ) }