first to commit project
This commit is contained in:
70
debug/http.go
Normal file
70
debug/http.go
Normal file
@@ -0,0 +1,70 @@
|
||||
package debug
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/http/httputil"
|
||||
"os"
|
||||
)
|
||||
|
||||
// DebugRequestTransport 会打印请求和响应信息, 方便调试.
|
||||
type DebugRequestTransport struct {
|
||||
RequestHeader bool
|
||||
RequestBody bool // RequestHeader 为 true 时,这个选项才会生效
|
||||
ResponseHeader bool
|
||||
ResponseBody bool // ResponseHeader 为 true 时,这个选项才会生效
|
||||
|
||||
// debug 信息输出到 Writer 中, 默认是 os.Stderr
|
||||
Writer io.Writer
|
||||
|
||||
Transport http.RoundTripper
|
||||
}
|
||||
|
||||
// RoundTrip implements the RoundTripper interface.
|
||||
func (t *DebugRequestTransport) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
req = cloneRequest(req) // per RoundTrip contract
|
||||
w := t.Writer
|
||||
if w == nil {
|
||||
w = os.Stderr
|
||||
}
|
||||
|
||||
if t.RequestHeader {
|
||||
a, _ := httputil.DumpRequestOut(req, t.RequestBody)
|
||||
fmt.Fprintf(w, "%s\n\n", string(a))
|
||||
}
|
||||
|
||||
resp, err := t.transport().RoundTrip(req)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
|
||||
if t.ResponseHeader {
|
||||
|
||||
b, _ := httputil.DumpResponse(resp, t.ResponseBody)
|
||||
fmt.Fprintf(w, "%s\n", string(b))
|
||||
}
|
||||
|
||||
return resp, err
|
||||
}
|
||||
|
||||
func (t *DebugRequestTransport) transport() http.RoundTripper {
|
||||
if t.Transport != nil {
|
||||
return t.Transport
|
||||
}
|
||||
return http.DefaultTransport
|
||||
}
|
||||
|
||||
// cloneRequest returns a clone of the provided *http.Request. The clone is a
|
||||
// shallow copy of the struct and its Header map.
|
||||
func cloneRequest(r *http.Request) *http.Request {
|
||||
// shallow copy of the struct
|
||||
r2 := new(http.Request)
|
||||
*r2 = *r
|
||||
// deep copy of the Header
|
||||
r2.Header = make(http.Header, len(r.Header))
|
||||
for k, s := range r.Header {
|
||||
r2.Header[k] = append([]string(nil), s...)
|
||||
}
|
||||
return r2
|
||||
}
|
||||
78
debug/http_test.go
Normal file
78
debug/http_test.go
Normal file
@@ -0,0 +1,78 @@
|
||||
package debug
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var (
|
||||
// mux is the HTTP request multiplexer used with the test server.
|
||||
mux *http.ServeMux
|
||||
|
||||
// server is a test HTTP server used to provide mock API responses.
|
||||
server *httptest.Server
|
||||
)
|
||||
|
||||
// setup sets up a test HTTP server along with a cos.Client that is
|
||||
// configured to talk to that test server. Tests should register handlers on
|
||||
// mux which provide mock responses for the API method being tested.
|
||||
func setup() {
|
||||
// test server
|
||||
mux = http.NewServeMux()
|
||||
server = httptest.NewServer(mux)
|
||||
}
|
||||
|
||||
// teardown closes the test HTTP server.
|
||||
func teardown() {
|
||||
server.Close()
|
||||
}
|
||||
|
||||
func TestDebugRequestTransport(t *testing.T) {
|
||||
setup()
|
||||
defer teardown()
|
||||
|
||||
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Add("X-Test-Response", "2333")
|
||||
w.WriteHeader(http.StatusBadGateway)
|
||||
w.Write([]byte("test response body"))
|
||||
})
|
||||
|
||||
w := bytes.NewBufferString("")
|
||||
client := http.Client{}
|
||||
|
||||
client.Transport = &DebugRequestTransport{
|
||||
RequestHeader: true,
|
||||
RequestBody: true,
|
||||
ResponseHeader: true,
|
||||
ResponseBody: true,
|
||||
Writer: w,
|
||||
}
|
||||
|
||||
body := bytes.NewReader([]byte("test_request body"))
|
||||
req, _ := http.NewRequest("GET", server.URL, body)
|
||||
req.Header.Add("X-Test-Debug", "123")
|
||||
client.Do(req)
|
||||
|
||||
b := make([]byte, 800)
|
||||
w.Read(b)
|
||||
info := string(b)
|
||||
if !strings.Contains(info, "GET / HTTP/1.1\r\n") ||
|
||||
!strings.Contains(info, "X-Test-Debug: 123\r\n") {
|
||||
t.Errorf("DebugRequestTransport debug info %#v don't contains request header", info)
|
||||
}
|
||||
if !strings.Contains(info, "\r\n\r\ntest_request body") {
|
||||
t.Errorf("DebugRequestTransport debug info %#v don't contains request body", info)
|
||||
}
|
||||
|
||||
if !strings.Contains(info, "HTTP/1.1 502 Bad Gateway\r\n") ||
|
||||
!strings.Contains(info, "X-Test-Response: 2333\r\n") {
|
||||
t.Errorf("DebugRequestTransport debug info %#v don't contains response header", info)
|
||||
}
|
||||
|
||||
if !strings.Contains(info, "\r\n\r\ntest response body") {
|
||||
t.Errorf("DebugRequestTransport debug info %#v don't contains response body", info)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user