first to commit project

This commit is contained in:
alantong
2018-12-06 15:24:18 +08:00
commit 6ad265fc0c
78 changed files with 6171 additions and 0 deletions

70
debug/http.go Normal file
View 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
View 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)
}
}