/
fastcgi.go
91 lines (75 loc) · 2.2 KB
/
fastcgi.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
package fastcgi
import (
"bytes"
"fmt"
"io"
"net/http"
"net/http/httptest"
"strings"
"github.com/yookoala/gofast"
"github.com/zalando/skipper/logging"
)
type RoundTripper struct {
log logging.Logger
client gofast.Client
handler gofast.SessionHandler
}
func NewRoundTripper(log logging.Logger, addr, filename string) (*RoundTripper, error) {
connFactory := gofast.SimpleConnFactory("tcp", addr)
client, err := gofast.SimpleClientFactory(connFactory)()
if err != nil {
return nil, fmt.Errorf("gofast: failed creating client: %w", err)
}
chain := gofast.Chain(
gofast.BasicParamsMap,
gofast.MapHeader,
gofast.MapEndpoint(filename),
func(handler gofast.SessionHandler) gofast.SessionHandler {
return func(client gofast.Client, req *gofast.Request) (*gofast.ResponsePipe, error) {
req.Params["HTTP_HOST"] = req.Params["SERVER_NAME"]
req.Params["SERVER_SOFTWARE"] = "Skipper"
// Gofast sets this param to `fastcgi` which is not what the backend will expect.
delete(req.Params, "REQUEST_SCHEME")
return handler(client, req)
}
},
)
return &RoundTripper{
log: log,
client: client,
handler: chain(gofast.BasicSession),
}, nil
}
func (rt *RoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
defer func() {
if rt.client == nil {
return
}
if err := rt.client.Close(); err != nil {
rt.log.Errorf("gofast: error closing client: %s", err.Error())
}
}()
resp, err := rt.handler(rt.client, gofast.NewRequest(req))
if err != nil {
return nil, fmt.Errorf("gofast: failed to process request: %w", err)
}
rr := httptest.NewRecorder()
errBuffer := new(bytes.Buffer)
resp.WriteTo(rr, errBuffer)
if errBuffer.Len() > 0 {
if strings.Contains(errBuffer.String(), "Primary script unknown") {
body := http.StatusText(http.StatusNotFound)
return &http.Response{
Status: body,
StatusCode: http.StatusNotFound,
Body: io.NopCloser(bytes.NewBufferString(body)),
ContentLength: int64(len(body)),
Request: req,
Header: make(http.Header),
}, nil
} else {
return nil, fmt.Errorf("gofast: error stream from application process %s", errBuffer.String())
}
}
return rr.Result(), nil
}