From 38295878a4b22d3f2d53c0f5f6270842a5b1fc9e Mon Sep 17 00:00:00 2001 From: Sergey Matveev Date: Fri, 15 Oct 2021 12:37:11 +0300 Subject: [PATCH] FastCGI running example --- cmd/godlighty/main.go | 1 + doc/index.texi | 3 +- godlighty.go | 2 + handler.go | 6 ++- rc/fcgi/fcgi.go | 92 +++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 102 insertions(+), 2 deletions(-) create mode 100644 rc/fcgi/fcgi.go diff --git a/cmd/godlighty/main.go b/cmd/godlighty/main.go index 1344aaa..04b7db5 100644 --- a/cmd/godlighty/main.go +++ b/cmd/godlighty/main.go @@ -104,6 +104,7 @@ func main() { } }() + godlighty.BindAddr = *bind srv := http.Server{ Handler: godlighty.MainHandler, ReadHeaderTimeout: RWTimeout, diff --git a/doc/index.texi b/doc/index.texi index 2b86584..4be54c8 100644 --- a/doc/index.texi +++ b/doc/index.texi @@ -103,7 +103,8 @@ func newTLSCfg(host string) *godlighty.TLSCfg { @end verbatim But there are hooks that can do anything more. For example if you want -to run CGI script or make a redirection: +to run CGI script or make a redirection (FastCGI handler example is in +@file{rc/fcgi}): @verbatim HostCfg{ diff --git a/godlighty.go b/godlighty.go index 8acad7f..4a5c458 100644 --- a/godlighty.go +++ b/godlighty.go @@ -2,3 +2,5 @@ package godlighty const Version = "godlighty/0.1.0" + +var BindAddr string diff --git a/handler.go b/handler.go index 8953a80..6fa1d35 100644 --- a/handler.go +++ b/handler.go @@ -24,6 +24,7 @@ import ( "fmt" "io/ioutil" "log" + "net" "net/http" "net/url" "os" @@ -313,6 +314,9 @@ func (h Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { http.Error(w, "invalid URL path", http.StatusBadRequest) return } - host := strings.SplitN(r.Host, ":", 2)[0] + host, _, err := net.SplitHostPort(r.Host) + if err != nil { + host = r.Host + } h.Handle(w, r, host, Hosts[host]) } diff --git a/rc/fcgi/fcgi.go b/rc/fcgi/fcgi.go new file mode 100644 index 0000000..0551d2e --- /dev/null +++ b/rc/fcgi/fcgi.go @@ -0,0 +1,92 @@ +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"), + ) +} -- 2.44.0