mirror of
https://github.com/caddyserver/caddy.git
synced 2025-01-23 18:55:49 +03:00
Merge pull request #1284 from mholt/fastcgi-send-timeout
Add send_timeout property to fastcgi directive
This commit is contained in:
commit
e363491a28
7 changed files with 222 additions and 81 deletions
|
@ -19,7 +19,10 @@ type basicDialer struct {
|
||||||
timeout time.Duration
|
timeout time.Duration
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b basicDialer) Dial() (Client, error) { return Dial(b.network, b.address, b.timeout) }
|
func (b basicDialer) Dial() (Client, error) {
|
||||||
|
return DialTimeout(b.network, b.address, b.timeout)
|
||||||
|
}
|
||||||
|
|
||||||
func (b basicDialer) Close(c Client) error { return c.Close() }
|
func (b basicDialer) Close(c Client) error { return c.Close() }
|
||||||
|
|
||||||
// persistentDialer keeps a pool of fcgi connections.
|
// persistentDialer keeps a pool of fcgi connections.
|
||||||
|
@ -47,7 +50,7 @@ func (p *persistentDialer) Dial() (Client, error) {
|
||||||
p.Unlock()
|
p.Unlock()
|
||||||
|
|
||||||
// no connection available, create new one
|
// no connection available, create new one
|
||||||
return Dial(p.network, p.address, p.timeout)
|
return DialTimeout(p.network, p.address, p.timeout)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *persistentDialer) Close(client Client) error {
|
func (p *persistentDialer) Close(client Client) error {
|
||||||
|
|
|
@ -6,6 +6,7 @@ package fastcgi
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"io"
|
"io"
|
||||||
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
|
@ -80,9 +81,14 @@ func (h Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error)
|
||||||
// Connect to FastCGI gateway
|
// Connect to FastCGI gateway
|
||||||
fcgiBackend, err := rule.dialer.Dial()
|
fcgiBackend, err := rule.dialer.Dial()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if err, ok := err.(net.Error); ok && err.Timeout() {
|
||||||
|
return http.StatusGatewayTimeout, err
|
||||||
|
}
|
||||||
return http.StatusBadGateway, err
|
return http.StatusBadGateway, err
|
||||||
}
|
}
|
||||||
|
defer fcgiBackend.Close()
|
||||||
fcgiBackend.SetReadTimeout(rule.ReadTimeout)
|
fcgiBackend.SetReadTimeout(rule.ReadTimeout)
|
||||||
|
fcgiBackend.SetSendTimeout(rule.SendTimeout)
|
||||||
|
|
||||||
var resp *http.Response
|
var resp *http.Response
|
||||||
contentLength, _ := strconv.Atoi(r.Header.Get("Content-Length"))
|
contentLength, _ := strconv.Atoi(r.Header.Get("Content-Length"))
|
||||||
|
@ -97,9 +103,13 @@ 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)
|
resp, err = fcgiBackend.Post(env, r.Method, r.Header.Get("Content-Type"), r.Body, contentLength)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil && err != io.EOF {
|
if err != nil {
|
||||||
|
if err, ok := err.(net.Error); ok && err.Timeout() {
|
||||||
|
return http.StatusGatewayTimeout, err
|
||||||
|
} else if err != io.EOF {
|
||||||
return http.StatusBadGateway, err
|
return http.StatusBadGateway, err
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Write response header
|
// Write response header
|
||||||
writeHeader(w, resp)
|
writeHeader(w, resp)
|
||||||
|
@ -110,8 +120,6 @@ func (h Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error)
|
||||||
return http.StatusBadGateway, err
|
return http.StatusBadGateway, err
|
||||||
}
|
}
|
||||||
|
|
||||||
defer rule.dialer.Close(fcgiBackend)
|
|
||||||
|
|
||||||
// Log any stderr output from upstream
|
// Log any stderr output from upstream
|
||||||
if stderr := fcgiBackend.StdErr(); stderr.Len() != 0 {
|
if stderr := fcgiBackend.StdErr(); stderr.Len() != 0 {
|
||||||
// Remove trailing newline, error logger already does this.
|
// Remove trailing newline, error logger already does this.
|
||||||
|
@ -306,6 +314,9 @@ type Rule struct {
|
||||||
// The duration used to set a deadline when reading from the FastCGI server.
|
// The duration used to set a deadline when reading from the FastCGI server.
|
||||||
ReadTimeout time.Duration
|
ReadTimeout time.Duration
|
||||||
|
|
||||||
|
// The duration used to set a deadline when sending to the FastCGI server.
|
||||||
|
SendTimeout time.Duration
|
||||||
|
|
||||||
// FCGI dialer
|
// FCGI dialer
|
||||||
dialer dialer
|
dialer dialer
|
||||||
}
|
}
|
||||||
|
|
|
@ -327,9 +327,22 @@ func TestBuildEnv(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestReadTimeout(t *testing.T) {
|
func TestReadTimeout(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
sleep time.Duration
|
||||||
|
readTimeout time.Duration
|
||||||
|
shouldErr bool
|
||||||
|
}{
|
||||||
|
{75 * time.Millisecond, 50 * time.Millisecond, true},
|
||||||
|
{0, -1 * time.Second, true},
|
||||||
|
{0, time.Minute, false},
|
||||||
|
}
|
||||||
|
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
|
||||||
|
for i, test := range tests {
|
||||||
listener, err := net.Listen("tcp", "127.0.0.1:0")
|
listener, err := net.Listen("tcp", "127.0.0.1:0")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Unable to create listener for test: %v", err)
|
t.Fatalf("Test %d: Unable to create listener for test: %v", i, err)
|
||||||
}
|
}
|
||||||
defer listener.Close()
|
defer listener.Close()
|
||||||
|
|
||||||
|
@ -341,24 +354,97 @@ func TestReadTimeout(t *testing.T) {
|
||||||
Path: "/",
|
Path: "/",
|
||||||
Address: listener.Addr().String(),
|
Address: listener.Addr().String(),
|
||||||
dialer: basicDialer{network: network, address: address},
|
dialer: basicDialer{network: network, address: address},
|
||||||
ReadTimeout: time.Millisecond * 100,
|
ReadTimeout: test.readTimeout,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
r, err := http.NewRequest("GET", "/", nil)
|
r, err := http.NewRequest("GET", "/", nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Unable to create request: %v", err)
|
t.Fatalf("Test %d: Unable to create request: %v", i, err)
|
||||||
|
}
|
||||||
|
w := httptest.NewRecorder()
|
||||||
|
|
||||||
|
wg.Add(1)
|
||||||
|
go fcgi.Serve(listener, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
time.Sleep(test.sleep)
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
wg.Done()
|
||||||
|
}))
|
||||||
|
|
||||||
|
got, err := handler.ServeHTTP(w, r)
|
||||||
|
if test.shouldErr {
|
||||||
|
if err == nil {
|
||||||
|
t.Errorf("Test %d: Expected i/o timeout error but had none", i)
|
||||||
|
} else if err, ok := err.(net.Error); !ok || !err.Timeout() {
|
||||||
|
t.Errorf("Test %d: Expected i/o timeout error, got: '%s'", i, err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
want := http.StatusGatewayTimeout
|
||||||
|
if got != want {
|
||||||
|
t.Errorf("Test %d: Expected returned status code to be %d, got: %d",
|
||||||
|
i, want, got)
|
||||||
|
}
|
||||||
|
} else if err != nil {
|
||||||
|
t.Errorf("Test %d: Expected nil error, got: %v", i, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
wg.Wait()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSendTimeout(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
sendTimeout time.Duration
|
||||||
|
shouldErr bool
|
||||||
|
}{
|
||||||
|
{-1 * time.Second, true},
|
||||||
|
{time.Minute, false},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, test := range tests {
|
||||||
|
listener, err := net.Listen("tcp", "127.0.0.1:0")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Test %d: Unable to create listener for test: %v", i, err)
|
||||||
|
}
|
||||||
|
defer listener.Close()
|
||||||
|
|
||||||
|
network, address := parseAddress(listener.Addr().String())
|
||||||
|
handler := Handler{
|
||||||
|
Next: nil,
|
||||||
|
Rules: []Rule{
|
||||||
|
{
|
||||||
|
Path: "/",
|
||||||
|
Address: listener.Addr().String(),
|
||||||
|
dialer: basicDialer{network: network, address: address},
|
||||||
|
SendTimeout: test.sendTimeout,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
r, err := http.NewRequest("GET", "/", nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Test %d: Unable to create request: %v", i, err)
|
||||||
}
|
}
|
||||||
w := httptest.NewRecorder()
|
w := httptest.NewRecorder()
|
||||||
|
|
||||||
go fcgi.Serve(listener, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
go fcgi.Serve(listener, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
time.Sleep(time.Millisecond * 130)
|
w.WriteHeader(http.StatusOK)
|
||||||
}))
|
}))
|
||||||
|
|
||||||
_, err = handler.ServeHTTP(w, r)
|
got, err := handler.ServeHTTP(w, r)
|
||||||
|
if test.shouldErr {
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Error("Expected i/o timeout error but had none")
|
t.Errorf("Test %d: Expected i/o timeout error but had none", i)
|
||||||
} else if err, ok := err.(net.Error); !ok || !err.Timeout() {
|
} else if err, ok := err.(net.Error); !ok || !err.Timeout() {
|
||||||
t.Errorf("Expected i/o timeout error, got: '%s'", err.Error())
|
t.Errorf("Test %d: Expected i/o timeout error, got: '%s'", i, err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
want := http.StatusGatewayTimeout
|
||||||
|
if got != want {
|
||||||
|
t.Errorf("Test %d: Expected returned status code to be %d, got: %d",
|
||||||
|
i, want, got)
|
||||||
|
}
|
||||||
|
} else if err != nil {
|
||||||
|
t.Errorf("Test %d: Expected nil error, got: %v", i, err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,6 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"mime/multipart"
|
"mime/multipart"
|
||||||
|
@ -116,8 +115,8 @@ type Client interface {
|
||||||
Post(pairs map[string]string, method string, bodyType string, body io.Reader, contentLength int) (response *http.Response, err error)
|
Post(pairs map[string]string, method string, bodyType string, body io.Reader, contentLength int) (response *http.Response, err error)
|
||||||
Close() error
|
Close() error
|
||||||
StdErr() bytes.Buffer
|
StdErr() bytes.Buffer
|
||||||
ReadTimeout() time.Duration
|
|
||||||
SetReadTimeout(time.Duration) error
|
SetReadTimeout(time.Duration) error
|
||||||
|
SetSendTimeout(time.Duration) error
|
||||||
}
|
}
|
||||||
|
|
||||||
type header struct {
|
type header struct {
|
||||||
|
@ -174,57 +173,32 @@ func (rec *record) read(r io.Reader) (buf []byte, err error) {
|
||||||
// interfacing external applications with Web servers.
|
// interfacing external applications with Web servers.
|
||||||
type FCGIClient struct {
|
type FCGIClient struct {
|
||||||
mutex sync.Mutex
|
mutex sync.Mutex
|
||||||
rwc io.ReadWriteCloser
|
conn net.Conn
|
||||||
h header
|
h header
|
||||||
buf bytes.Buffer
|
buf bytes.Buffer
|
||||||
stderr bytes.Buffer
|
stderr bytes.Buffer
|
||||||
keepAlive bool
|
keepAlive bool
|
||||||
reqID uint16
|
reqID uint16
|
||||||
readTimeout time.Duration
|
readTimeout time.Duration
|
||||||
|
sendTimeout time.Duration
|
||||||
}
|
}
|
||||||
|
|
||||||
// DialWithDialer connects to the fcgi responder at the specified network address, using custom net.Dialer.
|
// DialTimeout connects to the fcgi responder at the specified network address, using default net.Dialer.
|
||||||
// See func net.Dial for a description of the network and address parameters.
|
// See func net.Dial for a description of the network and address parameters.
|
||||||
func DialWithDialer(network, address string, dialer net.Dialer) (fcgi *FCGIClient, err error) {
|
func DialTimeout(network string, address string, timeout time.Duration) (fcgi *FCGIClient, err error) {
|
||||||
var conn net.Conn
|
conn, err := net.DialTimeout(network, address, timeout)
|
||||||
conn, err = dialer.Dial(network, address)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
fcgi = &FCGIClient{
|
fcgi = &FCGIClient{conn: conn, keepAlive: false, reqID: 1}
|
||||||
rwc: conn,
|
|
||||||
keepAlive: false,
|
|
||||||
reqID: 1,
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
return fcgi, nil
|
||||||
}
|
|
||||||
|
|
||||||
// Dial connects to the fcgi responder at the specified network address, using default net.Dialer.
|
|
||||||
// See func net.Dial for a description of the network and address parameters.
|
|
||||||
func Dial(network string, address string, timeout time.Duration) (fcgi *FCGIClient, err error) {
|
|
||||||
return DialWithDialer(network, address, net.Dialer{Timeout: timeout})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close closes fcgi connnection.
|
// Close closes fcgi connnection.
|
||||||
func (c *FCGIClient) Close() error {
|
func (c *FCGIClient) Close() error {
|
||||||
return c.rwc.Close()
|
return c.conn.Close()
|
||||||
}
|
|
||||||
|
|
||||||
// setReadDeadline sets a read deadline on FCGIClient based on the configured
|
|
||||||
// readTimeout. A zero value for readTimeout means no deadline will be set.
|
|
||||||
func (c *FCGIClient) setReadDeadline() error {
|
|
||||||
if c.readTimeout > 0 {
|
|
||||||
conn, ok := c.rwc.(net.Conn)
|
|
||||||
if ok {
|
|
||||||
conn.SetReadDeadline(time.Now().Add(c.readTimeout))
|
|
||||||
} else {
|
|
||||||
return fmt.Errorf("Could not set Client ReadTimeout")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *FCGIClient) writeRecord(recType uint8, content []byte) error {
|
func (c *FCGIClient) writeRecord(recType uint8, content []byte) error {
|
||||||
|
@ -245,7 +219,13 @@ func (c *FCGIClient) writeRecord(recType uint8, content []byte) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := c.rwc.Write(c.buf.Bytes()); err != nil {
|
if c.sendTimeout != 0 {
|
||||||
|
if err := c.conn.SetWriteDeadline(time.Now().Add(c.sendTimeout)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := c.conn.Write(c.buf.Bytes()); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -369,7 +349,7 @@ func (w *streamReader) Read(p []byte) (n int, err error) {
|
||||||
for {
|
for {
|
||||||
rec := &record{}
|
rec := &record{}
|
||||||
var buf []byte
|
var buf []byte
|
||||||
buf, err = rec.read(w.c.rwc)
|
buf, err = rec.read(w.c.conn)
|
||||||
if err == errInvalidHeaderVersion {
|
if err == errInvalidHeaderVersion {
|
||||||
continue
|
continue
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
|
@ -436,7 +416,6 @@ func (c clientCloser) Close() error { return c.f.Close() }
|
||||||
// Request returns a HTTP Response with Header and Body
|
// Request returns a HTTP Response with Header and Body
|
||||||
// from fcgi responder
|
// from fcgi responder
|
||||||
func (c *FCGIClient) Request(p map[string]string, req io.Reader) (resp *http.Response, err error) {
|
func (c *FCGIClient) Request(p map[string]string, req io.Reader) (resp *http.Response, err error) {
|
||||||
|
|
||||||
r, err := c.Do(p, req)
|
r, err := c.Do(p, req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
|
@ -446,9 +425,11 @@ func (c *FCGIClient) Request(p map[string]string, req io.Reader) (resp *http.Res
|
||||||
tp := textproto.NewReader(rb)
|
tp := textproto.NewReader(rb)
|
||||||
resp = new(http.Response)
|
resp = new(http.Response)
|
||||||
|
|
||||||
if err = c.setReadDeadline(); err != nil {
|
if c.readTimeout != 0 {
|
||||||
|
if err = c.conn.SetReadDeadline(time.Now().Add(c.readTimeout)); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Parse the response headers.
|
// Parse the response headers.
|
||||||
mimeHeader, err := tp.ReadMIMEHeader()
|
mimeHeader, err := tp.ReadMIMEHeader()
|
||||||
|
@ -582,10 +563,6 @@ func (c *FCGIClient) PostFile(p map[string]string, data url.Values, file map[str
|
||||||
return c.Post(p, "POST", bodyType, buf, buf.Len())
|
return c.Post(p, "POST", bodyType, buf, buf.Len())
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReadTimeout returns the read timeout for future calls that read from the
|
|
||||||
// fcgi responder.
|
|
||||||
func (c *FCGIClient) ReadTimeout() time.Duration { return c.readTimeout }
|
|
||||||
|
|
||||||
// SetReadTimeout sets the read timeout for future calls that read from the
|
// SetReadTimeout sets the read timeout for future calls that read from the
|
||||||
// fcgi responder. A zero value for t means no timeout will be set.
|
// fcgi responder. A zero value for t means no timeout will be set.
|
||||||
func (c *FCGIClient) SetReadTimeout(t time.Duration) error {
|
func (c *FCGIClient) SetReadTimeout(t time.Duration) error {
|
||||||
|
@ -593,6 +570,13 @@ func (c *FCGIClient) SetReadTimeout(t time.Duration) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetSendTimeout sets the read timeout for future calls that send data to
|
||||||
|
// the fcgi responder. A zero value for t means no timeout will be set.
|
||||||
|
func (c *FCGIClient) SetSendTimeout(t time.Duration) error {
|
||||||
|
c.sendTimeout = t
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// Checks whether chunked is part of the encodings stack
|
// Checks whether chunked is part of the encodings stack
|
||||||
func chunked(te []string) bool { return len(te) > 0 && te[0] == "chunked" }
|
func chunked(te []string) bool { return len(te) > 0 && te[0] == "chunked" }
|
||||||
|
|
||||||
|
|
|
@ -103,7 +103,7 @@ func (s FastCGIServer) ServeHTTP(resp http.ResponseWriter, req *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func sendFcgi(reqType int, fcgiParams map[string]string, data []byte, posts map[string]string, files map[string]string) (content []byte) {
|
func sendFcgi(reqType int, fcgiParams map[string]string, data []byte, posts map[string]string, files map[string]string) (content []byte) {
|
||||||
fcgi, err := Dial("tcp", ipPort, 0)
|
fcgi, err := DialTimeout("tcp", ipPort, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("err:", err)
|
log.Println("err:", err)
|
||||||
return
|
return
|
||||||
|
|
|
@ -59,7 +59,7 @@ func fastcgiParse(c *caddy.Controller) ([]Rule, error) {
|
||||||
return rules, c.ArgErr()
|
return rules, c.ArgErr()
|
||||||
}
|
}
|
||||||
|
|
||||||
rule := Rule{Path: args[0], ReadTimeout: 60 * time.Second}
|
rule := Rule{Path: args[0], ReadTimeout: 60 * time.Second, SendTimeout: 60 * time.Second}
|
||||||
upstreams := []string{args[1]}
|
upstreams := []string{args[1]}
|
||||||
|
|
||||||
if len(args) == 3 {
|
if len(args) == 3 {
|
||||||
|
@ -144,6 +144,15 @@ func fastcgiParse(c *caddy.Controller) ([]Rule, error) {
|
||||||
return rules, err
|
return rules, err
|
||||||
}
|
}
|
||||||
rule.ReadTimeout = readTimeout
|
rule.ReadTimeout = readTimeout
|
||||||
|
case "send_timeout":
|
||||||
|
if !c.NextArg() {
|
||||||
|
return rules, c.ArgErr()
|
||||||
|
}
|
||||||
|
sendTimeout, err := time.ParseDuration(c.Val())
|
||||||
|
if err != nil {
|
||||||
|
return rules, err
|
||||||
|
}
|
||||||
|
rule.SendTimeout = sendTimeout
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -80,6 +80,7 @@ func TestFastcgiParse(t *testing.T) {
|
||||||
dialer: &loadBalancingDialer{dialers: []dialer{basicDialer{network: "tcp", address: "127.0.0.1:9000", timeout: 60 * time.Second}}},
|
dialer: &loadBalancingDialer{dialers: []dialer{basicDialer{network: "tcp", address: "127.0.0.1:9000", timeout: 60 * time.Second}}},
|
||||||
IndexFiles: []string{"index.php"},
|
IndexFiles: []string{"index.php"},
|
||||||
ReadTimeout: 60 * time.Second,
|
ReadTimeout: 60 * time.Second,
|
||||||
|
SendTimeout: 60 * time.Second,
|
||||||
}}},
|
}}},
|
||||||
{`fastcgi /blog 127.0.0.1:9000 php {
|
{`fastcgi /blog 127.0.0.1:9000 php {
|
||||||
upstream 127.0.0.1:9001
|
upstream 127.0.0.1:9001
|
||||||
|
@ -92,6 +93,7 @@ func TestFastcgiParse(t *testing.T) {
|
||||||
dialer: &loadBalancingDialer{dialers: []dialer{basicDialer{network: "tcp", address: "127.0.0.1:9000", timeout: 60 * time.Second}, basicDialer{network: "tcp", address: "127.0.0.1:9001", timeout: 60 * time.Second}}},
|
dialer: &loadBalancingDialer{dialers: []dialer{basicDialer{network: "tcp", address: "127.0.0.1:9000", timeout: 60 * time.Second}, basicDialer{network: "tcp", address: "127.0.0.1:9001", timeout: 60 * time.Second}}},
|
||||||
IndexFiles: []string{"index.php"},
|
IndexFiles: []string{"index.php"},
|
||||||
ReadTimeout: 60 * time.Second,
|
ReadTimeout: 60 * time.Second,
|
||||||
|
SendTimeout: 60 * time.Second,
|
||||||
}}},
|
}}},
|
||||||
{`fastcgi /blog 127.0.0.1:9000 {
|
{`fastcgi /blog 127.0.0.1:9000 {
|
||||||
upstream 127.0.0.1:9001
|
upstream 127.0.0.1:9001
|
||||||
|
@ -104,6 +106,7 @@ func TestFastcgiParse(t *testing.T) {
|
||||||
dialer: &loadBalancingDialer{dialers: []dialer{basicDialer{network: "tcp", address: "127.0.0.1:9000", timeout: 60 * time.Second}, basicDialer{network: "tcp", address: "127.0.0.1:9001", timeout: 60 * time.Second}}},
|
dialer: &loadBalancingDialer{dialers: []dialer{basicDialer{network: "tcp", address: "127.0.0.1:9000", timeout: 60 * time.Second}, basicDialer{network: "tcp", address: "127.0.0.1:9001", timeout: 60 * time.Second}}},
|
||||||
IndexFiles: []string{},
|
IndexFiles: []string{},
|
||||||
ReadTimeout: 60 * time.Second,
|
ReadTimeout: 60 * time.Second,
|
||||||
|
SendTimeout: 60 * time.Second,
|
||||||
}}},
|
}}},
|
||||||
{`fastcgi / ` + defaultAddress + ` {
|
{`fastcgi / ` + defaultAddress + ` {
|
||||||
split .html
|
split .html
|
||||||
|
@ -116,6 +119,7 @@ func TestFastcgiParse(t *testing.T) {
|
||||||
dialer: &loadBalancingDialer{dialers: []dialer{basicDialer{network: network, address: address, timeout: 60 * time.Second}}},
|
dialer: &loadBalancingDialer{dialers: []dialer{basicDialer{network: network, address: address, timeout: 60 * time.Second}}},
|
||||||
IndexFiles: []string{},
|
IndexFiles: []string{},
|
||||||
ReadTimeout: 60 * time.Second,
|
ReadTimeout: 60 * time.Second,
|
||||||
|
SendTimeout: 60 * time.Second,
|
||||||
}}},
|
}}},
|
||||||
{`fastcgi / ` + defaultAddress + ` {
|
{`fastcgi / ` + defaultAddress + ` {
|
||||||
split .html
|
split .html
|
||||||
|
@ -130,6 +134,7 @@ func TestFastcgiParse(t *testing.T) {
|
||||||
IndexFiles: []string{},
|
IndexFiles: []string{},
|
||||||
IgnoredSubPaths: []string{"/admin", "/user"},
|
IgnoredSubPaths: []string{"/admin", "/user"},
|
||||||
ReadTimeout: 60 * time.Second,
|
ReadTimeout: 60 * time.Second,
|
||||||
|
SendTimeout: 60 * time.Second,
|
||||||
}}},
|
}}},
|
||||||
{`fastcgi / ` + defaultAddress + ` {
|
{`fastcgi / ` + defaultAddress + ` {
|
||||||
pool 0
|
pool 0
|
||||||
|
@ -142,6 +147,7 @@ func TestFastcgiParse(t *testing.T) {
|
||||||
dialer: &loadBalancingDialer{dialers: []dialer{&persistentDialer{size: 0, network: network, address: address, timeout: 60 * time.Second}}},
|
dialer: &loadBalancingDialer{dialers: []dialer{&persistentDialer{size: 0, network: network, address: address, timeout: 60 * time.Second}}},
|
||||||
IndexFiles: []string{},
|
IndexFiles: []string{},
|
||||||
ReadTimeout: 60 * time.Second,
|
ReadTimeout: 60 * time.Second,
|
||||||
|
SendTimeout: 60 * time.Second,
|
||||||
}}},
|
}}},
|
||||||
{`fastcgi / 127.0.0.1:8080 {
|
{`fastcgi / 127.0.0.1:8080 {
|
||||||
upstream 127.0.0.1:9000
|
upstream 127.0.0.1:9000
|
||||||
|
@ -155,6 +161,7 @@ func TestFastcgiParse(t *testing.T) {
|
||||||
dialer: &loadBalancingDialer{dialers: []dialer{&persistentDialer{size: 5, network: "tcp", address: "127.0.0.1:8080", timeout: 60 * time.Second}, &persistentDialer{size: 5, network: "tcp", address: "127.0.0.1:9000", timeout: 60 * time.Second}}},
|
dialer: &loadBalancingDialer{dialers: []dialer{&persistentDialer{size: 5, network: "tcp", address: "127.0.0.1:8080", timeout: 60 * time.Second}, &persistentDialer{size: 5, network: "tcp", address: "127.0.0.1:9000", timeout: 60 * time.Second}}},
|
||||||
IndexFiles: []string{},
|
IndexFiles: []string{},
|
||||||
ReadTimeout: 60 * time.Second,
|
ReadTimeout: 60 * time.Second,
|
||||||
|
SendTimeout: 60 * time.Second,
|
||||||
}}},
|
}}},
|
||||||
{`fastcgi / ` + defaultAddress + ` {
|
{`fastcgi / ` + defaultAddress + ` {
|
||||||
split .php
|
split .php
|
||||||
|
@ -167,6 +174,7 @@ func TestFastcgiParse(t *testing.T) {
|
||||||
dialer: &loadBalancingDialer{dialers: []dialer{basicDialer{network: network, address: address, timeout: 60 * time.Second}}},
|
dialer: &loadBalancingDialer{dialers: []dialer{basicDialer{network: network, address: address, timeout: 60 * time.Second}}},
|
||||||
IndexFiles: []string{},
|
IndexFiles: []string{},
|
||||||
ReadTimeout: 60 * time.Second,
|
ReadTimeout: 60 * time.Second,
|
||||||
|
SendTimeout: 60 * time.Second,
|
||||||
}}},
|
}}},
|
||||||
{`fastcgi / ` + defaultAddress + ` {
|
{`fastcgi / ` + defaultAddress + ` {
|
||||||
connect_timeout 5s
|
connect_timeout 5s
|
||||||
|
@ -179,7 +187,13 @@ func TestFastcgiParse(t *testing.T) {
|
||||||
dialer: &loadBalancingDialer{dialers: []dialer{basicDialer{network: network, address: address, timeout: 5 * time.Second}}},
|
dialer: &loadBalancingDialer{dialers: []dialer{basicDialer{network: network, address: address, timeout: 5 * time.Second}}},
|
||||||
IndexFiles: []string{},
|
IndexFiles: []string{},
|
||||||
ReadTimeout: 60 * time.Second,
|
ReadTimeout: 60 * time.Second,
|
||||||
|
SendTimeout: 60 * time.Second,
|
||||||
}}},
|
}}},
|
||||||
|
{
|
||||||
|
`fastcgi / ` + defaultAddress + ` { connect_timeout BADVALUE }`,
|
||||||
|
true,
|
||||||
|
[]Rule{},
|
||||||
|
},
|
||||||
{`fastcgi / ` + defaultAddress + ` {
|
{`fastcgi / ` + defaultAddress + ` {
|
||||||
read_timeout 5s
|
read_timeout 5s
|
||||||
}`,
|
}`,
|
||||||
|
@ -191,7 +205,31 @@ func TestFastcgiParse(t *testing.T) {
|
||||||
dialer: &loadBalancingDialer{dialers: []dialer{basicDialer{network: network, address: address, timeout: 60 * time.Second}}},
|
dialer: &loadBalancingDialer{dialers: []dialer{basicDialer{network: network, address: address, timeout: 60 * time.Second}}},
|
||||||
IndexFiles: []string{},
|
IndexFiles: []string{},
|
||||||
ReadTimeout: 5 * time.Second,
|
ReadTimeout: 5 * time.Second,
|
||||||
|
SendTimeout: 60 * time.Second,
|
||||||
}}},
|
}}},
|
||||||
|
{
|
||||||
|
`fastcgi / ` + defaultAddress + ` { read_timeout BADVALUE }`,
|
||||||
|
true,
|
||||||
|
[]Rule{},
|
||||||
|
},
|
||||||
|
{`fastcgi / ` + defaultAddress + ` {
|
||||||
|
send_timeout 5s
|
||||||
|
}`,
|
||||||
|
false, []Rule{{
|
||||||
|
Path: "/",
|
||||||
|
Address: defaultAddress,
|
||||||
|
Ext: "",
|
||||||
|
SplitPath: "",
|
||||||
|
dialer: &loadBalancingDialer{dialers: []dialer{basicDialer{network: network, address: address, timeout: 60 * time.Second}}},
|
||||||
|
IndexFiles: []string{},
|
||||||
|
ReadTimeout: 60 * time.Second,
|
||||||
|
SendTimeout: 5 * time.Second,
|
||||||
|
}}},
|
||||||
|
{
|
||||||
|
`fastcgi / ` + defaultAddress + ` { send_timeout BADVALUE }`,
|
||||||
|
true,
|
||||||
|
[]Rule{},
|
||||||
|
},
|
||||||
{`fastcgi / {
|
{`fastcgi / {
|
||||||
|
|
||||||
}`,
|
}`,
|
||||||
|
@ -251,6 +289,16 @@ func TestFastcgiParse(t *testing.T) {
|
||||||
t.Errorf("Test %d expected %dth FastCGI IgnoredSubPaths to be %s , but got %s",
|
t.Errorf("Test %d expected %dth FastCGI IgnoredSubPaths to be %s , but got %s",
|
||||||
i, j, test.expectedFastcgiConfig[j].IgnoredSubPaths, actualFastcgiConfig.IgnoredSubPaths)
|
i, j, test.expectedFastcgiConfig[j].IgnoredSubPaths, actualFastcgiConfig.IgnoredSubPaths)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if fmt.Sprint(actualFastcgiConfig.ReadTimeout) != fmt.Sprint(test.expectedFastcgiConfig[j].ReadTimeout) {
|
||||||
|
t.Errorf("Test %d expected %dth FastCGI ReadTimeout to be %s , but got %s",
|
||||||
|
i, j, test.expectedFastcgiConfig[j].ReadTimeout, actualFastcgiConfig.ReadTimeout)
|
||||||
|
}
|
||||||
|
|
||||||
|
if fmt.Sprint(actualFastcgiConfig.SendTimeout) != fmt.Sprint(test.expectedFastcgiConfig[j].SendTimeout) {
|
||||||
|
t.Errorf("Test %d expected %dth FastCGI SendTimeout to be %s , but got %s",
|
||||||
|
i, j, test.expectedFastcgiConfig[j].SendTimeout, actualFastcgiConfig.SendTimeout)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue