]> Sergey Matveev's repositories - godlighty.git/blob - rc/fcgi/fcgi.go
0551d2e12dad79cf37472f4afeba6d08f619e3d8
[godlighty.git] / rc / fcgi / fcgi.go
1 package cfg
2
3 import (
4         "fmt"
5         "io"
6         "log"
7         "net"
8         "net/http"
9         "path"
10         "strconv"
11         "strings"
12         "time"
13
14         fcgiclient "github.com/alash3al/go-fastcgi-client"
15         "go.stargrave.org/godlighty"
16 )
17
18 func ServeFCGI(
19         w http.ResponseWriter,
20         r *http.Request,
21         host, docRoot, scriptName, sockProto, sockPath string,
22         timeout time.Duration,
23 ) {
24         defer r.Body.Close()
25         serverHost, serverPort, err := net.SplitHostPort(godlighty.BindAddr)
26         if err != nil {
27                 panic(err)
28         }
29         remoteAddr, remotePort, _ := net.SplitHostPort(r.RemoteAddr)
30         params := map[string]string{
31                 "GATEWAY_INTERFACE": "CGI/1.1",
32
33                 "PATH_INFO":    r.URL.Path,
34                 "QUERY_STRING": r.URL.RawQuery,
35
36                 "REMOTE_ADDR": remoteAddr,
37                 "REMOTE_PORT": remotePort,
38
39                 "SERVER_NAME":     serverHost,
40                 "SERVER_PORT":     serverPort,
41                 "SERVER_PROTOCOL": r.Proto,
42                 "SERVER_SOFTWARE": godlighty.Version,
43
44                 "REQUEST_METHOD":  r.Method,
45                 "DOCUMENT_ROOT":   docRoot,
46                 "SCRIPT_NAME":     scriptName,
47                 "SCRIPT_FILENAME": path.Join(docRoot, scriptName),
48         }
49         for k, vs := range r.Header {
50                 if len(vs) < 1 {
51                         continue
52                 }
53                 k = "HTTP_" + strings.ToUpper(strings.Replace(k, "-", "_", -1))
54                 params[k] = strings.Join(vs, ";")
55         }
56         c, err := fcgiclient.Dial(sockProto, sockPath)
57         if err != nil {
58                 http.Error(w, err.Error(), http.StatusInternalServerError)
59                 log.Println("can not FCGI:", err)
60                 return
61         }
62         defer c.Close()
63         c.SetReadTimeout(timeout)
64         c.SetSendTimeout(timeout)
65         resp, err := c.Request(params, r.Body)
66         if err != nil {
67                 http.Error(w, err.Error(), http.StatusInternalServerError)
68                 log.Println("can not FCGI:", err)
69                 return
70         }
71         defer resp.Body.Close()
72         for k, vs := range resp.Header {
73                 for _, v := range vs {
74                         w.Header().Add(k, v)
75                 }
76         }
77         if resp.ContentLength > 0 {
78                 w.Header().Set("Content-Length", strconv.FormatInt(resp.ContentLength, 10))
79         }
80         w.WriteHeader(resp.StatusCode)
81         written, err := io.Copy(w, resp.Body)
82         if err != nil {
83                 stderr := c.Stderr()
84                 log.Println("can not copy FCGI:", string(stderr.Bytes()))
85                 return
86         }
87         fmt.Printf("%s %s \"%s %+q %s\" %d %d \"%s\"\n",
88                 r.RemoteAddr, host, r.Method, godlighty.PathWithQuery(r.URL), r.Proto,
89                 resp.StatusCode, written,
90                 r.Header.Get("User-Agent"),
91         )
92 }