/
debug.go
140 lines (113 loc) · 2.81 KB
/
debug.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
package debug
import (
"bytes"
"fmt"
"io"
"io/ioutil"
"net/http"
"os"
"strings"
"github.com/guonaihong/gout/color"
)
// ToBodyType Returns the http body type,
// which mainly affects color highlighting
func ToBodyType(s string) color.BodyType {
switch strings.ToLower(s) {
case "json":
return color.JSONType
case "xml":
// return color.XmlType //TODO open
case "yaml":
// return color.YamlType //TODO open
}
return color.TxtType
}
// Options Debug mode core data structure
type Options struct {
EscapeHTML bool
Write io.Writer
Debug bool
Color bool
Trace bool
FormatTraceJSON bool
ReqBodyType string
RspBodyType string
TraceInfo
}
// Apply is an interface for operating Options
type Apply interface {
Apply(*Options)
}
// Func Apply is a function that manipulates core data structures
type Func func(*Options)
// Apply is an interface for operating Options
func (f Func) Apply(o *Options) {
f(o)
}
func (do *Options) ResetBodyAndPrint(req *http.Request, resp *http.Response) error {
all, err := ioutil.ReadAll(resp.Body)
if err != nil {
return err
}
resp.Body.Close()
resp.Body = ioutil.NopCloser(bytes.NewReader(all))
err = do.debugPrint(req, resp)
resp.Body = ioutil.NopCloser(bytes.NewReader(all))
return err
}
func (do *Options) debugPrint(req *http.Request, rsp *http.Response) error {
if t := req.Header.Get("Content-Type"); len(t) > 0 && strings.Contains(t, "json") {
do.ReqBodyType = "json"
}
if t := rsp.Header.Get("Content-Type"); len(t) != 0 &&
strings.Contains(t, "application/json") {
do.RspBodyType = "json"
}
if do.Write == nil {
do.Write = os.Stdout
}
var w io.Writer = do.Write
cl := color.New(do.Color)
path := "/"
if len(req.URL.RequestURI()) > 0 {
path = req.URL.RequestURI()
}
fmt.Fprintf(w, "> %s %s %s\r\n", req.Method, path, req.Proto)
// write request header
for k, v := range req.Header {
fmt.Fprintf(w, "> %s: %s\r\n", cl.Spurple(k),
cl.Sblue(strings.Join(v, ",")))
}
fmt.Fprint(w, ">\r\n")
fmt.Fprint(w, "\n")
// write req body
if req.GetBody != nil {
b, err := req.GetBody()
if err != nil {
return err
}
r := io.Reader(b)
format := color.NewFormatEncoder(r, do.Color, ToBodyType(do.ReqBodyType), do.EscapeHTML)
if format != nil {
r = format
}
if _, err := io.Copy(w, r); err != nil {
return err
}
fmt.Fprintf(w, "\r\n\r\n")
}
fmt.Fprintf(w, "< %s %s\r\n", rsp.Proto, rsp.Status)
for k, v := range rsp.Header {
fmt.Fprintf(w, "< %s: %s\r\n", cl.Spurple(k), cl.Sblue(strings.Join(v, ",")))
}
fmt.Fprintf(w, "\r\n\r\n")
// write rsp body
r := io.Reader(rsp.Body)
format := color.NewFormatEncoder(r, do.Color, ToBodyType(do.RspBodyType), do.EscapeHTML)
if format != nil {
r = format
}
_, err := io.Copy(w, r)
fmt.Fprintf(w, "\r\n\r\n")
return err
}