This repository has been archived by the owner on Jul 3, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
response.go
131 lines (109 loc) · 2.77 KB
/
response.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
package etp
import (
"bufio"
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
"net/textproto"
"strconv"
"strings"
"github.com/jmoiron/jsonq"
)
type Response struct {
Status string // e.g. "200 OK"
StatusCode int // e.g. 200
Proto string // "ETP/1.0"
ProtoMajor int // 1
ProtoMinor int // 0
PathArgs []string
QueryArgs map[string][]string // TODO:
Header http.Header
Body []byte
ContentLength int64 // TODO: needed?
}
func (resp *Response) BodyQuery() *jsonq.JsonQuery {
// TODO: 根据 Header["Content-Type"] 判断
data := map[string]interface{}{}
dec := json.NewDecoder(bytes.NewBuffer(resp.Body))
dec.Decode(&data)
return jsonq.NewQuery(data)
}
func (resp *Response) BodyLoads(obj interface{}) error {
// TODO: 根据 Header["Content-Type"] 判断,处理不同类型
dec := json.NewDecoder(bytes.NewBuffer(resp.Body))
return dec.Decode(obj)
}
func (resp *Response) BodyError() string {
q := resp.BodyQuery()
error, err := q.String("error")
if err != nil {
fmt.Println("query error in body failed:", err)
}
return error
}
func ReadResponse(data []byte) (resp *Response, err error) {
tp := textproto.NewReader(bufio.NewReader(bytes.NewReader(data)))
resp = new(Response)
// read first line: GET /index.html ETP/1.0
line, err := tp.ReadLine()
if err != nil {
return nil, err
}
f := strings.SplitN(line, " ", 3)
if len(f) < 2 {
return nil, &badStringError{"malformed ETP response", line}
}
reasonPhrase := ""
if len(f) > 2 {
reasonPhrase = f[2]
}
resp.Status = f[1] + " " + reasonPhrase
resp.StatusCode, err = strconv.Atoi(f[1])
if err != nil {
return nil, &badStringError{"malformed ETP status code", f[1]}
}
resp.Proto = f[0]
var ok bool
if resp.ProtoMajor, resp.ProtoMinor, ok = ParseHTTPVersion(resp.Proto); !ok {
return nil, &badStringError{"malformed ETP version", resp.Proto}
}
mimeHeader, err := tp.ReadMIMEHeader()
if err != nil {
// TODO: etp 定制? 无 headers
if err == io.EOF {
return resp, nil
}
return nil, err
}
resp.Header = http.Header(mimeHeader)
if clen := resp.Header.Get("Content-Length"); len(clen) > 0 {
resp.ContentLength, err = strconv.ParseInt(clen, 10, 64)
if err != nil {
fmt.Printf("parse Content-Length (%s): %s\n", clen, err)
return nil, err
}
}
// TODO: ugly?
before := int64(len(data)) - resp.ContentLength
resp.Body = data[before:]
return resp, nil
}
// 参考 http.ResponseWriter
type ResponseWriter interface {
Header() http.Header
Write([]byte) (int, error)
WriteString(string) (int, error)
WriteHeader(int)
Bytes() []byte
Status() int
}
// 一些实用工具
func WriteJSON(w ResponseWriter, code int, v interface{}) error {
w.Header().Set("Content-Type", "application/json")
if code > 0 {
w.WriteHeader(code)
}
return json.NewEncoder(w).Encode(v)
}