-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathhttpie.go
121 lines (112 loc) · 2.31 KB
/
httpie.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
package args
import (
"encoding/json"
"fmt"
"net/url"
"strings"
)
type argType int
const (
unknownArg argType = iota
headerArg
paramArg
fieldArg
jsonArg
)
type PostMode int
const (
PostModeJSON PostMode = iota + 1
PostModeFORM
)
func parseFancyArgs(args []string, postMode PostMode) (opts Opts) {
if len(args) == 0 {
return
}
method := strings.ToUpper(args[0])
switch method {
case "GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS", "TRACE":
opts = append(opts, "-X", method)
args = args[1:]
case "HEAD":
opts = append(opts, "-I")
args = args[1:]
}
if len(args) == 0 {
return
}
url := args[0]
data := map[string]interface{}{}
for _, arg := range args[1:] {
typ, name, value := parseArg(arg)
switch typ {
case headerArg:
opts = append(opts, "-H", name+":"+value)
case paramArg:
url = appendURLParam(url, name, value)
case fieldArg:
if postMode == PostModeFORM {
opts = append(opts, "-F", name+"="+value)
} else {
data[name] = value
}
case jsonArg:
var v interface{}
json.Unmarshal([]byte(value), &v)
data[name] = v
default:
opts = append(opts, arg)
}
}
if len(data) > 0 {
j, _ := json.Marshal(data)
opts = append(opts, "-d", string(j))
}
opts = append(opts, normalizeURL(url))
return
}
func normalizeURL(u string) string {
// If scheme is omitted, use http:
if !strings.HasPrefix(u, "http") {
if strings.HasPrefix(u, "//") {
u = "http:" + u
} else {
u = "http://" + u
}
}
pu, err := url.Parse(u)
if err != nil {
fmt.Print(err)
return u
}
if pu.Host == ":" {
pu.Host = "localhost"
} else if pu.Host != "" && pu.Host[0] == ':' {
// If :port is given with no hostname, add localhost
pu.Host = "localhost" + pu.Host
}
return pu.String()
}
func parseArg(arg string) (typ argType, name, value string) {
for i := 0; i < len(arg); i++ {
switch arg[i] {
case ':':
if i+1 < len(arg) && arg[i+1] == '=' {
return jsonArg, arg[:i], arg[i+2:]
}
return headerArg, arg[:i], arg[i+1:]
case '=':
if i+1 < len(arg) && arg[i+1] == '=' {
return paramArg, arg[:i], arg[i+2:]
}
return fieldArg, arg[:i], arg[i+1:]
}
}
return
}
func appendURLParam(u, name, value string) string {
sep := "?"
if strings.IndexByte(u, '?') != -1 {
sep = "&"
}
return u + sep + url.QueryEscape(name) + "=" + url.QueryEscape(value)
}