twins/serve_fcgi.go

111 lines
2.9 KiB
Go
Raw Normal View History

2020-11-04 20:48:55 +00:00
package main
import (
"bytes"
"crypto/sha1"
"crypto/tls"
"fmt"
2020-11-04 20:48:55 +00:00
"io"
"io/ioutil"
2020-12-07 06:09:41 +00:00
"log"
2020-11-04 20:48:55 +00:00
"net/http"
"net/url"
2020-12-07 06:09:41 +00:00
"path/filepath"
"strings"
2020-11-04 20:48:55 +00:00
"github.com/yookoala/gofast"
)
2020-12-03 19:12:13 +00:00
type fakeResponseWriter struct {
2020-11-04 20:48:55 +00:00
io.WriteCloser
header http.Header
}
2020-12-03 19:12:13 +00:00
func newFakeResponseWriter(out io.WriteCloser) *fakeResponseWriter {
return &fakeResponseWriter{
2020-11-04 20:48:55 +00:00
WriteCloser: out,
header: make(http.Header),
}
}
2020-12-03 19:12:13 +00:00
func (w *fakeResponseWriter) Header() http.Header {
2020-11-04 20:48:55 +00:00
return w.header
}
2020-12-03 19:12:13 +00:00
func (w *fakeResponseWriter) WriteHeader(statusCode int) {
2020-11-04 20:48:55 +00:00
// Do nothing
}
func serveFastCGI(c *tls.Conn, connFactory gofast.ConnFactory, u *url.URL, filePath string) {
2020-11-04 21:07:06 +00:00
header := map[string][]string{
"Accept": {"*/*"},
"Host": {u.Hostname()},
}
2020-11-04 20:48:55 +00:00
r := &http.Request{
Method: "GET",
2020-11-04 21:07:06 +00:00
URL: u,
2020-11-04 20:48:55 +00:00
Proto: "HTTP/1.1",
ProtoMajor: 1,
ProtoMinor: 1,
2020-11-04 21:07:06 +00:00
Header: header,
2020-11-04 20:48:55 +00:00
Body: ioutil.NopCloser(bytes.NewReader(nil)),
2020-11-04 21:07:06 +00:00
Host: u.Host,
2020-12-07 06:09:41 +00:00
RemoteAddr: c.RemoteAddr().String(),
2020-11-04 20:48:55 +00:00
}
2020-12-07 06:09:41 +00:00
req := gofast.NewRequest(r)
req.Params["CONTENT_TYPE"] = r.Header.Get("Content-Type")
req.Params["CONTENT_LENGTH"] = r.Header.Get("Content-Length")
req.Params["HTTP_HOST"] = r.Host
req.Params["HTTPS"] = "on"
req.Params["GATEWAY_INTERFACE"] = "CGI/1.1"
req.Params["REMOTE_ADDR"] = strings.SplitN(c.RemoteAddr().String(), ":", 2)[0]
req.Params["REMOTE_PORT"] = "1965"
req.Params["SERVER_PORT"] = "1965"
req.Params["SERVER_NAME"] = r.Host
req.Params["SERVER_PROTOCOL"] = r.Proto
req.Params["SERVER_SOFTWARE"] = "twins"
req.Params["REDIRECT_STATUS"] = "200"
req.Params["REQUEST_METHOD"] = r.Method
req.Params["REQUEST_URI"] = r.RequestURI
req.Params["QUERY_STRING"] = r.URL.RawQuery
req.Params["DOCUMENT_ROOT"] = filepath.Dir(filePath)
req.Params["DOCUMENT_URI"] = r.URL.Path
req.Params["SCRIPT_FILENAME"] = filePath
req.Params["SCRIPT_NAME"] = filepath.Base(filePath)
certLabel := 'A'
clientCerts := c.ConnectionState().PeerCertificates
for i := 0; i < len(clientCerts) && i < 26; i++ {
req.Params["CLIENT_CERT_"+string(certLabel+rune(i))] = fmt.Sprintf("%x", sha1.Sum(clientCerts[i].Raw))
}
2020-12-07 06:09:41 +00:00
w := newFakeResponseWriter(c)
client, err := gofast.SimpleClientFactory(connFactory, 0)()
if err != nil {
log.Printf("FastCGI Error: %s", err)
http.Error(w, "Failed to connect to FastCGI server", http.StatusInternalServerError)
return
}
resp, err := client.Do(req)
if err != nil {
log.Printf("FastCGI Error: %s", err)
http.Error(w, "Failed to connect to FastCGI server", http.StatusInternalServerError)
return
}
errBuffer := new(bytes.Buffer)
err = resp.WriteTo(w, errBuffer)
if err != nil {
log.Printf("FastCGI Error: %s", err)
http.Error(w, "Failed to connect to FastCGI server", http.StatusInternalServerError)
return
} else if errBuffer.Len() > 0 {
log.Printf("FastCGI Error: %s", errBuffer.String())
http.Error(w, "Failed to connect to FastCGI server", http.StatusInternalServerError)
}
2020-11-04 20:48:55 +00:00
}