github.com/mackerelio/mackerel-agent-plugins@v0.89.3/mackerel-plugin-php-fpm/lib/fcgi.go (about) 1 //go:build linux 2 3 package mpphpfpm 4 5 import ( 6 "bytes" 7 "io" 8 "net/http" 9 "strconv" 10 "time" 11 12 "github.com/tomasen/fcgi_client" 13 ) 14 15 // FastCGITransport is an implementation of RoundTripper that supports FastCGI. 16 type FastCGITransport struct { 17 Network string 18 Address string 19 } 20 21 func (*FastCGITransport) timeout(req *http.Request) time.Duration { 22 t, ok := req.Context().Deadline() 23 if !ok { 24 return 0 // no timeout 25 } 26 return time.Until(t) 27 } 28 29 // RoundTrip implements the RoundTripper interface. 30 func (t *FastCGITransport) RoundTrip(req *http.Request) (*http.Response, error) { 31 c, err := fcgiclient.DialTimeout(t.Network, t.Address, t.timeout(req)) 32 if err != nil { 33 return nil, err 34 } 35 defer c.Close() 36 37 params := make(map[string]string) 38 params["REQUEST_METHOD"] = req.Method 39 if req.ContentLength >= 0 { 40 params["CONTENT_LENGTH"] = strconv.FormatInt(req.ContentLength, 10) 41 } 42 43 // https://github.com/dreamcat4/php-fpm/blob/master/cgi/cgi_main.c#L781 44 params["PATH_INFO"] = req.URL.Path // TODO(lufia): correct? 45 params["SCRIPT_NAME"] = req.URL.Path // TODO(lufia): correct? 46 params["SCRIPT_FILENAME"] = req.URL.Path // TODO(lufia): correct? 47 params["REQUEST_URI"] = req.URL.RequestURI() 48 params["QUERY_STRING"] = req.URL.RawQuery 49 params["SERVER_NAME"] = req.URL.Hostname() 50 params["SERVER_ADDR"] = req.URL.Port() 51 if req.URL.Scheme == "https" { 52 params["HTTPS"] = "on" 53 } 54 params["SERVER_PROTOCOL"] = req.Proto 55 if ctype := req.Header.Get("Content-Type"); ctype != "" { 56 params["CONTENT_TYPE"] = ctype 57 } 58 if ua := req.Header.Get("User-Agent"); ua != "" { 59 params["USER_AGENT"] = ua 60 } 61 resp, err := c.Request(params, req.Body) 62 if err != nil { 63 return nil, err 64 } 65 body := resp.Body 66 defer body.Close() 67 68 // Var c can disconnect before end of reading of resp.Body. 69 // So contents of resp.Body should copy in memory. 70 var buf bytes.Buffer 71 if _, err := buf.ReadFrom(body); err != nil { 72 return nil, err 73 } 74 resp.Body = io.NopCloser(&buf) 75 return resp, nil 76 }