]> Sergey Matveev's repositories - godlighty.git/commitdiff
FastCGI running example
authorSergey Matveev <stargrave@stargrave.org>
Fri, 15 Oct 2021 09:37:11 +0000 (12:37 +0300)
committerSergey Matveev <stargrave@stargrave.org>
Fri, 15 Oct 2021 11:12:30 +0000 (14:12 +0300)
cmd/godlighty/main.go
doc/index.texi
godlighty.go
handler.go
rc/fcgi/fcgi.go [new file with mode: 0644]

index 1344aaa40ca51d29ea5fc709a658bee4634c8615..04b7db57b471b8a2c72bc54b67857c53fdc3d651 100644 (file)
@@ -104,6 +104,7 @@ func main() {
                }
        }()
 
+       godlighty.BindAddr = *bind
        srv := http.Server{
                Handler:           godlighty.MainHandler,
                ReadHeaderTimeout: RWTimeout,
index 2b865846b680e7548b668ba9fdf2848819bfa489..4be54c80cd9b52126b205102ed5e9651aaa026d2 100644 (file)
@@ -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{
index 8acad7f97f2ef703b8d06a69b69388d13f87492e..4a5c458a41c30f52dcaf1c3dfb7aad0abf809bc7 100644 (file)
@@ -2,3 +2,5 @@
 package godlighty
 
 const Version = "godlighty/0.1.0"
+
+var BindAddr string
index 8953a8060713f04cb3dbdd14df575afcb9ff5a02..6fa1d35bbeb0e1a6290900f55ecaaf9a8b91f998 100644 (file)
@@ -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 (file)
index 0000000..0551d2e
--- /dev/null
@@ -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"),
+       )
+}