mirror of
https://github.com/caddyserver/caddy.git
synced 2025-01-06 02:48:48 +03:00
persistent fastcgi connections (#1087)
* keep fastcgi connection open * poor mans serialisation to make up for the lack of demuxing * pointing includes to echse's repo * Revert "pointing includes to echse's repo" This reverts commit281daad8d4
. * switch for persistent fcgi connections on/off added * fixing ineffectual assignments * camel case instead of _ * only activate persistent sockets on windows (and some naming conventions/cleanup) * gitfm import sorting * Revert "fixing ineffectual assignments" This reverts commit79760344e7
. # Conflicts: # caddyhttp/staticfiles/fileserver.go * added another mutex and deleting map entries. thx to mholts QA comments! * thinking about it, this RW lock was not a good idea here * thread safety * I keep learning about mutexs in go * some cosmetics
This commit is contained in:
parent
8e54d5cecb
commit
09a1f02971
2 changed files with 51 additions and 8 deletions
|
@ -12,10 +12,29 @@ import (
|
|||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/mholt/caddy/caddyhttp/httpserver"
|
||||
)
|
||||
|
||||
// persistent fastcgi connections
|
||||
|
||||
type serialClient struct {
|
||||
// for read/write serialisation
|
||||
sync.Mutex
|
||||
backend *FCGIClient
|
||||
}
|
||||
type concurrentPersistentConnectionsMap struct {
|
||||
// for thread safe acces to the map
|
||||
sync.Mutex
|
||||
clientMap map[string]*serialClient
|
||||
}
|
||||
|
||||
var persistentConnections = &(concurrentPersistentConnectionsMap{clientMap: make(map[string]*serialClient)})
|
||||
|
||||
// UsePersistentFcgiConnections TODO: add an option in Caddyfile and pass it down to here
|
||||
var UsePersistentFcgiConnections = true
|
||||
|
||||
// Handler is a middleware type that can handle requests as a FastCGI client.
|
||||
type Handler struct {
|
||||
Next httpserver.Handler
|
||||
|
@ -73,9 +92,25 @@ func (h Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error)
|
|||
|
||||
// Connect to FastCGI gateway
|
||||
network, address := rule.parseAddress()
|
||||
fcgiBackend, err := Dial(network, address)
|
||||
if err != nil {
|
||||
return http.StatusBadGateway, err
|
||||
|
||||
var fcgiBackend *FCGIClient
|
||||
var client *serialClient
|
||||
reuse := false
|
||||
if UsePersistentFcgiConnections {
|
||||
persistentConnections.Lock()
|
||||
client, reuse = persistentConnections.clientMap[network+address]
|
||||
persistentConnections.Unlock()
|
||||
}
|
||||
|
||||
if reuse {
|
||||
client.Lock()
|
||||
defer client.Unlock()
|
||||
fcgiBackend = client.backend
|
||||
} else {
|
||||
fcgiBackend, err = Dial(network, address)
|
||||
if err != nil {
|
||||
return http.StatusBadGateway, err
|
||||
}
|
||||
}
|
||||
|
||||
var resp *http.Response
|
||||
|
@ -91,14 +126,18 @@ func (h Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error)
|
|||
resp, err = fcgiBackend.Post(env, r.Method, r.Header.Get("Content-Type"), r.Body, contentLength)
|
||||
}
|
||||
|
||||
if resp.Body != nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
|
||||
if err != nil && err != io.EOF {
|
||||
return http.StatusBadGateway, err
|
||||
}
|
||||
|
||||
if UsePersistentFcgiConnections {
|
||||
persistentConnections.Lock()
|
||||
persistentConnections.clientMap[network+address] = &(serialClient{backend: fcgiBackend})
|
||||
persistentConnections.Unlock()
|
||||
} else {
|
||||
defer fcgiBackend.Close()
|
||||
}
|
||||
|
||||
// Write response header
|
||||
writeHeader(w, resp)
|
||||
|
||||
|
@ -112,6 +151,10 @@ func (h Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error)
|
|||
if fcgiBackend.stderr.Len() != 0 {
|
||||
// Remove trailing newline, error logger already does this.
|
||||
err = LogError(strings.TrimSuffix(fcgiBackend.stderr.String(), "\n"))
|
||||
persistentConnections.Lock()
|
||||
delete(persistentConnections.clientMap, network+address)
|
||||
persistentConnections.Unlock()
|
||||
fcgiBackend.Close()
|
||||
}
|
||||
|
||||
// Normally we would return the status code if it is an error status (>= 400),
|
||||
|
|
|
@ -385,7 +385,7 @@ func (w *streamReader) Read(p []byte) (n int, err error) {
|
|||
// Do made the request and returns a io.Reader that translates the data read
|
||||
// from fcgi responder out of fcgi packet before returning it.
|
||||
func (c *FCGIClient) Do(p map[string]string, req io.Reader) (r io.Reader, err error) {
|
||||
err = c.writeBeginRequest(uint16(Responder), 0)
|
||||
err = c.writeBeginRequest(uint16(Responder), FCGIKeepConn)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue