Skip to content

Commit 60cd54c

Browse files
authored
Urlencode (#15)
* 新增--data-urlencode选项支持 * 重命名 * 更新依赖 * 修改文件名 * 新增测试代码 * 更新文档
1 parent faf2950 commit 60cd54c

File tree

8 files changed

+449
-232
lines changed

8 files changed

+449
-232
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ pcurl是解析curl表达式的库
1313
* 支持--url选项,curl中设置url,一般不会设置这个选项
1414
* 支持--compressed选项
1515
* 支持-k, --insecure选项
16+
* 支持-G, --get选项
17+
* 支持--data-urlencode选项
1618

1719
# 内容
1820
- [json](#json)

go.mod

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ go 1.13
44

55
require (
66
github.com/gin-contrib/gzip v0.0.1
7-
github.com/gin-gonic/gin v1.5.0
8-
github.com/guonaihong/clop v0.0.7
7+
github.com/gin-gonic/gin v1.6.3
8+
github.com/guonaihong/clop v0.0.9
99
github.com/guonaihong/gout v0.0.12
10-
github.com/stretchr/testify v1.4.0
10+
github.com/stretchr/testify v1.6.1
1111
)

go.sum

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@ github.com/gin-contrib/sse v0.0.0-20170109093832-22d885f9ecc7/go.mod h1:VJ0WA2NB
77
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
88
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
99
github.com/gin-gonic/gin v1.3.0/go.mod h1:7cKuhb5qV2ggCFctp2fJQ+ErvciLZrIeoOSOm6mUr7Y=
10-
github.com/gin-gonic/gin v1.5.0 h1:fi+bqFAx/oLK54somfCtEZs9HeH1LHVoEPUgARpTqyc=
1110
github.com/gin-gonic/gin v1.5.0/go.mod h1:Nd6IXA8m5kNZdNEHMBd93KT+mdY3+bewLgRvmCsR2Do=
12-
github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A=
11+
github.com/gin-gonic/gin v1.6.3 h1:ahKqKTFpO5KTPHxWZjEdPScmYaGtLo8Y4DMHoEsnp14=
12+
github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M=
1313
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
1414
github.com/go-playground/locales v0.12.1/go.mod h1:IUMDtCfWo/w/mtMfIE/IG2K+Ey3ygWanZIBtBW0W2TM=
1515
github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q=
@@ -20,38 +20,37 @@ github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+
2020
github.com/go-playground/validator/v10 v10.2.0 h1:KgJ0snyC2R9VXYN2rneOtQcw5aHQB1Vv0sFl1UcHBOY=
2121
github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI=
2222
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
23-
github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs=
2423
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
24+
github.com/golang/protobuf v1.3.3 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I=
25+
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
2526
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
26-
github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
2727
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
28-
github.com/guonaihong/clop v0.0.7 h1:sFZfmlu48o1wq6KUYdig0AsScEc7KHrxiC0NYp73jbk=
29-
github.com/guonaihong/clop v0.0.7/go.mod h1:6r46yf9HnBFtFgblQrzvbxzeAbFob3Qud3PnuhphwgI=
28+
github.com/guonaihong/clop v0.0.9 h1:L3fahWQEdfLQEcicXEqgvpGAR5sitAvn2ukIMaqDA9A=
29+
github.com/guonaihong/clop v0.0.9/go.mod h1:6r46yf9HnBFtFgblQrzvbxzeAbFob3Qud3PnuhphwgI=
3030
github.com/guonaihong/gout v0.0.12 h1:3wMBcVnOzAaoh1l4ddShjgZtm4GecZCsgK+e8zgvj5c=
3131
github.com/guonaihong/gout v0.0.12/go.mod h1:vXvv5Kxr70eM5wrp4F0+t9lnLWmq+YPW2GByll2f/EA=
3232
github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
33-
github.com/json-iterator/go v1.1.7 h1:KfgG9LzI+pYjr4xvmz/5H4FXjokeP+rlHLhv3iH62Fo=
3433
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
34+
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
3535
github.com/leodido/go-urn v1.1.0/go.mod h1:+cyI34gQWZcE1eQU7NVgKkkzdXDQHr1dBMtdAPozLkw=
3636
github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y=
3737
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
3838
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
39-
github.com/mattn/go-isatty v0.0.9 h1:d5US/mDsogSGW37IV293h//ZFaeajb69h+EHFsv2xGg=
4039
github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
41-
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc=
40+
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
41+
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
4242
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
4343
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
44-
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLDQ0W1YjYsBW+p8U2u7vzgW2SQVmlNazg=
4544
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
4645
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
4746
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
4847
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
49-
github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4=
5048
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
5149
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
5250
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
53-
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
5451
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
52+
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
53+
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
5554
github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo=
5655
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
5756
github.com/ugorji/go/codec v0.0.0-20181022190402-e5e69e061d4f/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
@@ -64,18 +63,19 @@ golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLL
6463
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
6564
golang.org/x/sys v0.0.0-20181228144115-9a3f9b0469bb/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
6665
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
67-
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a h1:aYOabOQFp6Vj6W1F80affTUvO9UxmJRx8K0gsfABByQ=
6866
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
67+
golang.org/x/sys v0.0.0-20200116001909-b77594299b42 h1:vEOn+mP2zCOVzKckCZy6YsCtDblrpj/w7B9nxGNELpg=
68+
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
6969
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
7070
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
7171
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
72-
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
7372
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
74-
gopkg.in/go-playground/assert.v1 v1.2.1 h1:xoYuJVE7KT85PYWrN730RguIQO0ePzVRfFMXadIrXTM=
7573
gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE=
7674
gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y=
77-
gopkg.in/go-playground/validator.v9 v9.29.1 h1:SvGtYmN60a5CVKTOzMSyfzWDeZRxRuGvRQyEAKbw1xc=
7875
gopkg.in/go-playground/validator.v9 v9.29.1/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ=
7976
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
80-
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
8177
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
78+
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
79+
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
80+
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
81+
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

pcurl.go

Lines changed: 109 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -3,31 +3,39 @@ package pcurl
33
import (
44
"net/http"
55
"os"
6+
"sort"
67
"strings"
78

89
"github.com/guonaihong/clop"
910
"github.com/guonaihong/gout"
10-
"github.com/guonaihong/gout/dataflow"
1111
)
1212

1313
// Curl结构体
1414
type Curl struct {
15-
Method string `clop:"-X; --request" usage:"Specify request command to use"`
16-
Get bool `clop:"-G; --get" usage:"Put the post data in the URL and use GET"`
17-
Header []string `clop:"-H; --header" usage:"Pass custom header(s) to server"`
18-
Data string `clop:"-d; --data" usage:"HTTP POST data"`
19-
DataRaw string `clop:"--data-raw" usage:"HTTP POST data, '@' allowed"`
20-
Form []string `clop:"-F; --form" usage:"Specify multipart MIME data"`
21-
URL2 string `clop:"args=url2" usage:"url2"`
22-
URL string `clop:"--url" usage:"URL to work with"`
23-
Location bool `clop:"-L; --location" usage:"Follow redirects"` //TODO
15+
Method string `clop:"-X; --request" usage:"Specify request command to use"`
16+
Get bool `clop:"-G; --get" usage:"Put the post data in the URL and use GET"`
17+
Header []string `clop:"-H; --header" usage:"Pass custom header(s) to server"`
18+
Data string `clop:"-d; --data" usage:"HTTP POST data"`
19+
DataRaw string `clop:"--data-raw" usage:"HTTP POST data, '@' allowed"`
20+
Form []string `clop:"-F; --form" usage:"Specify multipart MIME data"`
21+
URL2 string `clop:"args=url2" usage:"url2"`
22+
URL string `clop:"--url" usage:"URL to work with"`
23+
Location bool `clop:"-L; --location" usage:"Follow redirects"` //TODO
24+
DataUrlencode []string `clop:"--data-urlencode" usage:"HTTP POST data url encoded"`
2425

2526
Compressed bool `clop:"--compressed" usage:"Request compressed response"`
2627
Insecure bool `clop:"-k; --insecure" "Allow insecure server connections when using SSL"`
2728
Err error
2829
p *clop.Clop
2930
}
3031

32+
const (
33+
bodyURLEncode = "data-urlencode"
34+
bodyForm = "form"
35+
bodyData = "data"
36+
bodyDataRaw = "data-raw"
37+
)
38+
3139
// 解析curl字符串形式表达式,并返回*http.Request
3240
func ParseAndRequest(curl string) (*http.Request, error) {
3341
return ParseString(curl).Request()
@@ -69,6 +77,56 @@ func (c *Curl) createHeader() []string {
6977
return header
7078
}
7179

80+
func (c *Curl) findHighestPriority() string {
81+
82+
// 获取 --data-urlencoded,-F or --form, -d or --data, --data-raw的命令行优先级别
83+
m := map[uint64]string{
84+
c.p.GetIndex(bodyURLEncode): bodyURLEncode,
85+
c.p.GetIndex(bodyForm): bodyForm,
86+
c.p.GetIndex(bodyData): bodyData,
87+
c.p.GetIndex(bodyDataRaw): bodyDataRaw,
88+
}
89+
90+
index := []uint64{
91+
c.p.GetIndex(bodyURLEncode),
92+
c.p.GetIndex(bodyForm),
93+
c.p.GetIndex(bodyData),
94+
c.p.GetIndex(bodyDataRaw),
95+
}
96+
97+
// 排序
98+
sort.Slice(index, func(i, j int) bool {
99+
return index[i] < index[j]
100+
})
101+
102+
// 取优先级最高的选项
103+
max := index[len(index)-1]
104+
105+
return m[max]
106+
}
107+
108+
func (c *Curl) createWWWForm() ([]interface{}, error) {
109+
if len(c.DataUrlencode) == 0 {
110+
return nil, nil
111+
}
112+
113+
form := make([]interface{}, len(c.DataUrlencode)*2)
114+
index := 0
115+
for _, v := range c.DataUrlencode {
116+
pos := strings.IndexByte(v, '=')
117+
if pos == -1 {
118+
continue
119+
}
120+
121+
form[index] = v[:pos]
122+
index++
123+
form[index] = v[pos+1:]
124+
index++
125+
}
126+
127+
return form, nil
128+
}
129+
72130
func (c *Curl) createForm() ([]interface{}, error) {
73131
if len(c.Form) == 0 {
74132
return nil, nil
@@ -130,7 +188,10 @@ func (c *Curl) setMethod() {
130188
func (c *Curl) Request() (req *http.Request, err error) {
131189

132190
var (
133-
data interface{}
191+
data interface{}
192+
form []interface{}
193+
wwwForm []interface{}
194+
dataRaw string
134195
)
135196

136197
defer func() {
@@ -143,21 +204,38 @@ func (c *Curl) Request() (req *http.Request, err error) {
143204

144205
header := c.createHeader()
145206

146-
form, err := c.createForm()
147-
if err != nil {
148-
return nil, err
207+
switch c.findHighestPriority() {
208+
case bodyURLEncode:
209+
if wwwForm, err = c.createWWWForm(); err != nil {
210+
return nil, err
211+
}
212+
case bodyForm:
213+
if form, err = c.createForm(); err != nil {
214+
return nil, err
215+
}
216+
case bodyData:
217+
dataRaw = c.Data
218+
case bodyDataRaw:
219+
dataRaw = c.DataRaw
149220
}
150221

151-
var dataRaw string
152-
dataRaw = c.Data
153-
// --data 和--data-raw同时出现的话, 取后面的选项
154-
// --data-raw @./a.file --data @./b.file 这里取-data @./b.file
155-
// --data-raw @./a.file -data @./b.file 这里取-data-raw @./a.file
156-
if c.p.GetIndex("data-raw") > c.p.GetIndex("data") {
157-
dataRaw = c.DataRaw
222+
var hc *http.Client
223+
224+
if c.Insecure {
225+
hc = &defaultInsecureSkipVerify
158226
}
159227

160-
data = dataRaw
228+
g := gout.New(hc)
229+
g.SetMethod(c.Method) //设置method POST or GET or DELETE
230+
231+
if c.Compressed {
232+
header = append(header, "Accept-Encoding", "deflate, gzip")
233+
//header = append(header, "Accept-Encoding", "deflate, gzip")
234+
}
235+
236+
if len(dataRaw) > 0 {
237+
data = dataRaw
238+
}
161239
if len(dataRaw) > 0 && dataRaw[0] == '@' {
162240
fd, err := os.Open(dataRaw[1:])
163241
if err != nil {
@@ -169,34 +247,26 @@ func (c *Curl) Request() (req *http.Request, err error) {
169247
data = fd
170248
}
171249

172-
var g *dataflow.Gout
173-
if c.Insecure {
174-
g = gout.New(&defaultInsecureSkipVerify)
175-
} else {
176-
g = gout.New()
250+
if len(header) > 0 {
251+
g.SetHeader(header) //设置http header
177252
}
178253

179-
g.SetMethod(c.Method). //设置method POST or GET or DELETE
180-
Debug(true) //打开debug模式
181-
182-
if c.Compressed {
183-
header = append(header, "Accept-Encoding", "deflate, gzip")
184-
//header = append(header, "Accept-Encoding", "deflate, gzip")
254+
if len(form) > 0 {
255+
g.SetForm(form) //设置formdata
185256
}
186257

187-
if header != nil {
188-
g.SetHeader(header) //设置http header
258+
if len(wwwForm) > 0 {
259+
g.SetWWWForm(wwwForm) // 设置x-www-form-urlencoded格式数据
189260
}
190261

191-
if len(form) > 0 {
192-
g.SetForm(form) //设置formdata
262+
if data != nil {
263+
g.SetBody(data)
193264
}
194265

195266
url := c.getURL()
196267

197268
return g.SetURL(url). //设置url
198-
SetBody(data). //设置http body
199-
Request() //获取*http.Request
269+
Request() //获取*http.Request
200270
}
201271

202272
func parseSlice(curl []string, c *Curl) *Curl {

0 commit comments

Comments
 (0)