Commit e363491a authored by Matt Holt's avatar Matt Holt Committed by GitHub

Merge pull request #1284 from mholt/fastcgi-send-timeout

Add send_timeout property to fastcgi directive
parents b0685a64 9f16ac84
...@@ -19,8 +19,11 @@ type basicDialer struct { ...@@ -19,8 +19,11 @@ 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) {
func (b basicDialer) Close(c Client) error { return c.Close() } return DialTimeout(b.network, b.address, b.timeout)
}
func (b basicDialer) Close(c Client) error { return c.Close() }
// persistentDialer keeps a pool of fcgi connections. // persistentDialer keeps a pool of fcgi connections.
// connections are not closed after use, rather added back to the pool for reuse. // connections are not closed after use, rather added back to the pool for reuse.
...@@ -47,7 +50,7 @@ func (p *persistentDialer) Dial() (Client, error) { ...@@ -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 ...@@ -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) ...@@ -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,8 +103,12 @@ func (h Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error) ...@@ -97,8 +103,12 @@ 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 {
return http.StatusBadGateway, err if err, ok := err.(net.Error); ok && err.Timeout() {
return http.StatusGatewayTimeout, err
} else if err != io.EOF {
return http.StatusBadGateway, err
}
} }
// Write response header // Write response header
...@@ -110,8 +120,6 @@ func (h Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error) ...@@ -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 { ...@@ -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,38 +327,124 @@ func TestBuildEnv(t *testing.T) { ...@@ -327,38 +327,124 @@ func TestBuildEnv(t *testing.T) {
} }
func TestReadTimeout(t *testing.T) { func TestReadTimeout(t *testing.T) {
listener, err := net.Listen("tcp", "127.0.0.1:0") tests := []struct {
if err != nil { sleep time.Duration
t.Fatalf("Unable to create listener for test: %v", err) readTimeout time.Duration
shouldErr bool
}{
{75 * time.Millisecond, 50 * time.Millisecond, true},
{0, -1 * time.Second, true},
{0, time.Minute, false},
} }
defer listener.Close()
network, address := parseAddress(listener.Addr().String()) var wg sync.WaitGroup
handler := Handler{
Next: nil, for i, test := range tests {
Rules: []Rule{ listener, err := net.Listen("tcp", "127.0.0.1:0")
{ if err != nil {
Path: "/", t.Fatalf("Test %d: Unable to create listener for test: %v", i, err)
Address: listener.Addr().String(), }
dialer: basicDialer{network: network, address: address}, defer listener.Close()
ReadTimeout: time.Millisecond * 100,
network, address := parseAddress(listener.Addr().String())
handler := Handler{
Next: nil,
Rules: []Rule{
{
Path: "/",
Address: listener.Addr().String(),
dialer: basicDialer{network: network, address: address},
ReadTimeout: test.readTimeout,
},
}, },
}, }
r, err := http.NewRequest("GET", "/", nil)
if err != nil {
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()
} }
r, err := http.NewRequest("GET", "/", nil) }
if err != nil {
t.Fatalf("Unable to create request: %v", err) func TestSendTimeout(t *testing.T) {
tests := []struct {
sendTimeout time.Duration
shouldErr bool
}{
{-1 * time.Second, true},
{time.Minute, false},
} }
w := httptest.NewRecorder()
go fcgi.Serve(listener, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { for i, test := range tests {
time.Sleep(time.Millisecond * 130) 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()
_, err = handler.ServeHTTP(w, r) network, address := parseAddress(listener.Addr().String())
if err == nil { handler := Handler{
t.Error("Expected i/o timeout error but had none") Next: nil,
} else if err, ok := err.(net.Error); !ok || !err.Timeout() { Rules: []Rule{
t.Errorf("Expected i/o timeout error, got: '%s'", err.Error()) {
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()
go fcgi.Serve(listener, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
}))
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)
}
} }
} }
...@@ -15,7 +15,6 @@ import ( ...@@ -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 { ...@@ -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) { ...@@ -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
}
// Dial connects to the fcgi responder at the specified network address, using default net.Dialer. return fcgi, nil
// 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 { ...@@ -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) { ...@@ -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() } ...@@ -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,8 +425,10 @@ func (c *FCGIClient) Request(p map[string]string, req io.Reader) (resp *http.Res ...@@ -446,8 +425,10 @@ 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 {
return if err = c.conn.SetReadDeadline(time.Now().Add(c.readTimeout)); err != nil {
return
}
} }
// Parse the response headers. // Parse the response headers.
...@@ -582,10 +563,6 @@ func (c *FCGIClient) PostFile(p map[string]string, data url.Values, file map[str ...@@ -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 { ...@@ -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) { ...@@ -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) { ...@@ -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) { ...@@ -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) { ...@@ -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) { ...@@ -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) { ...@@ -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) { ...@@ -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) { ...@@ -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) { ...@@ -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) { ...@@ -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) { ...@@ -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) { ...@@ -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) { ...@@ -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) { ...@@ -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)
}
} }
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment