mirror of
https://github.com/buger/goreplay.git
synced 2024-04-21 12:32:02 +00:00
Handle HTTP error codes
This commit is contained in:
+31
-2
@@ -21,6 +21,7 @@ type HTTPClientConfig struct {
|
||||
FollowRedirects int
|
||||
Debug bool
|
||||
OriginalHost bool
|
||||
ConnectionTimeout time.Duration
|
||||
Timeout time.Duration
|
||||
ResponseBufferSize int
|
||||
}
|
||||
@@ -69,9 +70,9 @@ func (c *HTTPClient) Connect() (err error) {
|
||||
c.Disconnect()
|
||||
|
||||
if !strings.Contains(c.host, ":") {
|
||||
c.conn, err = net.Dial("tcp", c.host+":80")
|
||||
c.conn, err = net.DialTimeout("tcp", c.host+":80", c.config.ConnectionTimeout)
|
||||
} else {
|
||||
c.conn, err = net.Dial("tcp", c.host)
|
||||
c.conn, err = net.DialTimeout("tcp", c.host, c.config.ConnectionTimeout)
|
||||
}
|
||||
|
||||
if c.scheme == "https" {
|
||||
@@ -124,6 +125,7 @@ func (c *HTTPClient) Send(data []byte) (response []byte, err error) {
|
||||
Debug("[HTTPClient] Connecting:", c.baseURL)
|
||||
if err = c.Connect(); err != nil {
|
||||
log.Println("[HTTPClient] Connection error:", err)
|
||||
response = errorPayload(HTTP_CONNECTION_ERROR)
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -142,6 +144,7 @@ func (c *HTTPClient) Send(data []byte) (response []byte, err error) {
|
||||
|
||||
if _, err = c.conn.Write(data); err != nil {
|
||||
Debug("[HTTPClient] Write error:", err, c.baseURL)
|
||||
response = errorPayload(HTTP_TIMEOUT)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -160,6 +163,7 @@ func (c *HTTPClient) Send(data []byte) (response []byte, err error) {
|
||||
|
||||
if err != nil {
|
||||
Debug("[HTTPClient] Response read error", err, c.conn)
|
||||
response = errorPayload(HTTP_TIMEOUT)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -197,3 +201,28 @@ func (c *HTTPClient) Get(path string) (response []byte, err error) {
|
||||
|
||||
return c.Send([]byte(payload))
|
||||
}
|
||||
|
||||
const (
|
||||
// https://support.cloudflare.com/hc/en-us/articles/200171936-Error-520-Web-server-is-returning-an-unknown-error
|
||||
HTTP_UNKNOWN_ERROR = "520"
|
||||
// https://support.cloudflare.com/hc/en-us/articles/200171916-Error-521-Web-server-is-down
|
||||
HTTP_CONNECTION_ERROR = "521"
|
||||
// https://support.cloudflare.com/hc/en-us/articles/200171906-Error-522-Connection-timed-out
|
||||
HTTP_CONNECTION_TIMEOUT = "522"
|
||||
// https://support.cloudflare.com/hc/en-us/articles/200171946-Error-523-Origin-is-unreachable
|
||||
HTTP_UNREACHABLE = "523"
|
||||
// https://support.cloudflare.com/hc/en-us/articles/200171926-Error-524-A-timeout-occurred
|
||||
HTTP_TIMEOUT = "524"
|
||||
)
|
||||
|
||||
var errorPayloadTemplate = "HTTP/1.1 202 Accepted\r\nDate: Mon, 17 Aug 2015 14:10:11 GMT\r\nContent-Length: 0\r\nContent-Type: text/plain; charset=utf-8\r\n\r\n"
|
||||
|
||||
func errorPayload(errorCode string) []byte {
|
||||
payload := make([]byte, len(errorPayloadTemplate))
|
||||
copy(payload, errorPayloadTemplate)
|
||||
|
||||
copy(payload[29:58], []byte(time.Now().Format(time.RFC1123)))
|
||||
copy(payload[9:12], errorCode)
|
||||
|
||||
return payload
|
||||
}
|
||||
|
||||
@@ -8,7 +8,11 @@ import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"net/http/httputil"
|
||||
"github.com/buger/gor/proto"
|
||||
"sync"
|
||||
"time"
|
||||
"log"
|
||||
_ "reflect"
|
||||
"testing"
|
||||
_ "time"
|
||||
)
|
||||
@@ -299,3 +303,90 @@ func TestHTTPClientHandleHTTP10(t *testing.T) {
|
||||
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
func TestHTTPClientErrors(t *testing.T) {
|
||||
req := []byte("GET http://foobar.com/path HTTP/1.0\r\n\r\n")
|
||||
|
||||
// Port not exists
|
||||
client := NewHTTPClient("http://127.0.0.1:1", &HTTPClientConfig{Debug: true})
|
||||
if resp, err := client.Send(req); err != nil {
|
||||
if s := proto.Status(resp); !bytes.Equal(s, []byte("521")) {
|
||||
t.Error("Should return status 521 for connection refused, instead:", string(s))
|
||||
}
|
||||
} else {
|
||||
t.Error("Should throw error")
|
||||
}
|
||||
|
||||
client = NewHTTPClient("http://not.existing", &HTTPClientConfig{Debug: true})
|
||||
if resp, err := client.Send(req); err != nil {
|
||||
if s := proto.Status(resp); !bytes.Equal(s, []byte("521")) {
|
||||
t.Error("Should return status 521 for no such host, instead:", string(s))
|
||||
}
|
||||
} else {
|
||||
t.Error("Should throw error")
|
||||
}
|
||||
|
||||
// Non routable IP address to simulate connection timeout
|
||||
client = NewHTTPClient("http://10.255.255.1", &HTTPClientConfig{Debug: true, ConnectionTimeout: 100 * time.Millisecond })
|
||||
|
||||
if resp, err := client.Send(req); err != nil {
|
||||
if s := proto.Status(resp); !bytes.Equal(s, []byte("521")) {
|
||||
t.Error("Should return status 521 for io/timeout:", string(s))
|
||||
}
|
||||
} else {
|
||||
t.Error("Should throw error")
|
||||
}
|
||||
|
||||
// Connecting but io timeout on read
|
||||
ln, _ := net.Listen("tcp", ":0")
|
||||
client = NewHTTPClient("http://" + ln.Addr().String(), &HTTPClientConfig{Debug: true, Timeout: 10 * time.Millisecond})
|
||||
|
||||
if resp, err := client.Send(req); err != nil {
|
||||
if s := proto.Status(resp); !bytes.Equal(s, []byte("524")) {
|
||||
t.Error("Should return status 524 for io read, instead:", string(s))
|
||||
}
|
||||
} else {
|
||||
t.Error("Should throw error")
|
||||
}
|
||||
|
||||
// Response read error read tcp [::1]:51128: connection reset by peer &{{0xc20802a000}}
|
||||
ln1, _ := net.Listen("tcp", ":0")
|
||||
go func(){
|
||||
ln1.Accept()
|
||||
}()
|
||||
|
||||
client = NewHTTPClient("http://" + ln1.Addr().String(), &HTTPClientConfig{Debug: true, Timeout: 10 * time.Millisecond})
|
||||
|
||||
if resp, err := client.Send(req); err != nil {
|
||||
if s := proto.Status(resp); !bytes.Equal(s, []byte("524")) {
|
||||
t.Error("Should return status 524 for connection reset by peer, instead:", string(s))
|
||||
}
|
||||
} else {
|
||||
t.Error("Should throw error")
|
||||
}
|
||||
|
||||
ln2, _ := net.Listen("tcp", ":0")
|
||||
go func(){
|
||||
for {
|
||||
buf := make([]byte, 64*1024)
|
||||
conn, err := ln2.Accept()
|
||||
|
||||
if err != nil {
|
||||
log.Println("Error while Accept()", err)
|
||||
continue
|
||||
}
|
||||
|
||||
conn.Read(buf)
|
||||
}
|
||||
}()
|
||||
|
||||
client = NewHTTPClient("http://" + ln2.Addr().String(), &HTTPClientConfig{Debug: true, Timeout: 10 * time.Millisecond})
|
||||
|
||||
if resp, err := client.Send(req); err != nil {
|
||||
if s := proto.Status(resp); !bytes.Equal(s, []byte("524")) {
|
||||
t.Error("Should return status 524 for connection reset by peer, instead:", string(s))
|
||||
}
|
||||
} else {
|
||||
t.Error("Should throw error")
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user