Skip to content

Commit

Permalink
Urlencode (#15)
Browse files Browse the repository at this point in the history
* 新增--data-urlencode选项支持

* 重命名

* 更新依赖

* 修改文件名

* 新增测试代码

* 更新文档
  • Loading branch information
guonaihong authored Jun 7, 2020
1 parent faf2950 commit 60cd54c
Show file tree
Hide file tree
Showing 8 changed files with 449 additions and 232 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ pcurl是解析curl表达式的库
* 支持--url选项,curl中设置url,一般不会设置这个选项
* 支持--compressed选项
* 支持-k, --insecure选项
* 支持-G, --get选项
* 支持--data-urlencode选项

# 内容
- [json](#json)
Expand Down
6 changes: 3 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ go 1.13

require (
github.com/gin-contrib/gzip v0.0.1
github.com/gin-gonic/gin v1.5.0
github.com/guonaihong/clop v0.0.7
github.com/gin-gonic/gin v1.6.3
github.com/guonaihong/clop v0.0.9
github.com/guonaihong/gout v0.0.12
github.com/stretchr/testify v1.4.0
github.com/stretchr/testify v1.6.1
)
34 changes: 17 additions & 17 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ github.com/gin-contrib/sse v0.0.0-20170109093832-22d885f9ecc7/go.mod h1:VJ0WA2NB
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
github.com/gin-gonic/gin v1.3.0/go.mod h1:7cKuhb5qV2ggCFctp2fJQ+ErvciLZrIeoOSOm6mUr7Y=
github.com/gin-gonic/gin v1.5.0 h1:fi+bqFAx/oLK54somfCtEZs9HeH1LHVoEPUgARpTqyc=
github.com/gin-gonic/gin v1.5.0/go.mod h1:Nd6IXA8m5kNZdNEHMBd93KT+mdY3+bewLgRvmCsR2Do=
github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A=
github.com/gin-gonic/gin v1.6.3 h1:ahKqKTFpO5KTPHxWZjEdPScmYaGtLo8Y4DMHoEsnp14=
github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M=
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
github.com/go-playground/locales v0.12.1/go.mod h1:IUMDtCfWo/w/mtMfIE/IG2K+Ey3ygWanZIBtBW0W2TM=
github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q=
Expand All @@ -20,38 +20,37 @@ github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+
github.com/go-playground/validator/v10 v10.2.0 h1:KgJ0snyC2R9VXYN2rneOtQcw5aHQB1Vv0sFl1UcHBOY=
github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.3 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I=
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/guonaihong/clop v0.0.7 h1:sFZfmlu48o1wq6KUYdig0AsScEc7KHrxiC0NYp73jbk=
github.com/guonaihong/clop v0.0.7/go.mod h1:6r46yf9HnBFtFgblQrzvbxzeAbFob3Qud3PnuhphwgI=
github.com/guonaihong/clop v0.0.9 h1:L3fahWQEdfLQEcicXEqgvpGAR5sitAvn2ukIMaqDA9A=
github.com/guonaihong/clop v0.0.9/go.mod h1:6r46yf9HnBFtFgblQrzvbxzeAbFob3Qud3PnuhphwgI=
github.com/guonaihong/gout v0.0.12 h1:3wMBcVnOzAaoh1l4ddShjgZtm4GecZCsgK+e8zgvj5c=
github.com/guonaihong/gout v0.0.12/go.mod h1:vXvv5Kxr70eM5wrp4F0+t9lnLWmq+YPW2GByll2f/EA=
github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.7 h1:KfgG9LzI+pYjr4xvmz/5H4FXjokeP+rlHLhv3iH62Fo=
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/leodido/go-urn v1.1.0/go.mod h1:+cyI34gQWZcE1eQU7NVgKkkzdXDQHr1dBMtdAPozLkw=
github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y=
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.9 h1:d5US/mDsogSGW37IV293h//ZFaeajb69h+EHFsv2xGg=
github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc=
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLDQ0W1YjYsBW+p8U2u7vzgW2SQVmlNazg=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo=
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
github.com/ugorji/go/codec v0.0.0-20181022190402-e5e69e061d4f/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
Expand All @@ -64,18 +63,19 @@ golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLL
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20181228144115-9a3f9b0469bb/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a h1:aYOabOQFp6Vj6W1F80affTUvO9UxmJRx8K0gsfABByQ=
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42 h1:vEOn+mP2zCOVzKckCZy6YsCtDblrpj/w7B9nxGNELpg=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/go-playground/assert.v1 v1.2.1 h1:xoYuJVE7KT85PYWrN730RguIQO0ePzVRfFMXadIrXTM=
gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE=
gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y=
gopkg.in/go-playground/validator.v9 v9.29.1 h1:SvGtYmN60a5CVKTOzMSyfzWDeZRxRuGvRQyEAKbw1xc=
gopkg.in/go-playground/validator.v9 v9.29.1/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
148 changes: 109 additions & 39 deletions pcurl.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,31 +3,39 @@ package pcurl
import (
"net/http"
"os"
"sort"
"strings"

"github.com/guonaihong/clop"
"github.com/guonaihong/gout"
"github.com/guonaihong/gout/dataflow"
)

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

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

const (
bodyURLEncode = "data-urlencode"
bodyForm = "form"
bodyData = "data"
bodyDataRaw = "data-raw"
)

// 解析curl字符串形式表达式,并返回*http.Request
func ParseAndRequest(curl string) (*http.Request, error) {
return ParseString(curl).Request()
Expand Down Expand Up @@ -69,6 +77,56 @@ func (c *Curl) createHeader() []string {
return header
}

func (c *Curl) findHighestPriority() string {

// 获取 --data-urlencoded,-F or --form, -d or --data, --data-raw的命令行优先级别
m := map[uint64]string{
c.p.GetIndex(bodyURLEncode): bodyURLEncode,
c.p.GetIndex(bodyForm): bodyForm,
c.p.GetIndex(bodyData): bodyData,
c.p.GetIndex(bodyDataRaw): bodyDataRaw,
}

index := []uint64{
c.p.GetIndex(bodyURLEncode),
c.p.GetIndex(bodyForm),
c.p.GetIndex(bodyData),
c.p.GetIndex(bodyDataRaw),
}

// 排序
sort.Slice(index, func(i, j int) bool {
return index[i] < index[j]
})

// 取优先级最高的选项
max := index[len(index)-1]

return m[max]
}

func (c *Curl) createWWWForm() ([]interface{}, error) {
if len(c.DataUrlencode) == 0 {
return nil, nil
}

form := make([]interface{}, len(c.DataUrlencode)*2)
index := 0
for _, v := range c.DataUrlencode {
pos := strings.IndexByte(v, '=')
if pos == -1 {
continue
}

form[index] = v[:pos]
index++
form[index] = v[pos+1:]
index++
}

return form, nil
}

func (c *Curl) createForm() ([]interface{}, error) {
if len(c.Form) == 0 {
return nil, nil
Expand Down Expand Up @@ -130,7 +188,10 @@ func (c *Curl) setMethod() {
func (c *Curl) Request() (req *http.Request, err error) {

var (
data interface{}
data interface{}
form []interface{}
wwwForm []interface{}
dataRaw string
)

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

header := c.createHeader()

form, err := c.createForm()
if err != nil {
return nil, err
switch c.findHighestPriority() {
case bodyURLEncode:
if wwwForm, err = c.createWWWForm(); err != nil {
return nil, err
}
case bodyForm:
if form, err = c.createForm(); err != nil {
return nil, err
}
case bodyData:
dataRaw = c.Data
case bodyDataRaw:
dataRaw = c.DataRaw
}

var dataRaw string
dataRaw = c.Data
// --data 和--data-raw同时出现的话, 取后面的选项
// --data-raw @./a.file --data @./b.file 这里取-data @./b.file
// --data-raw @./a.file -data @./b.file 这里取-data-raw @./a.file
if c.p.GetIndex("data-raw") > c.p.GetIndex("data") {
dataRaw = c.DataRaw
var hc *http.Client

if c.Insecure {
hc = &defaultInsecureSkipVerify
}

data = dataRaw
g := gout.New(hc)
g.SetMethod(c.Method) //设置method POST or GET or DELETE

if c.Compressed {
header = append(header, "Accept-Encoding", "deflate, gzip")
//header = append(header, "Accept-Encoding", "deflate, gzip")
}

if len(dataRaw) > 0 {
data = dataRaw
}
if len(dataRaw) > 0 && dataRaw[0] == '@' {
fd, err := os.Open(dataRaw[1:])
if err != nil {
Expand All @@ -169,34 +247,26 @@ func (c *Curl) Request() (req *http.Request, err error) {
data = fd
}

var g *dataflow.Gout
if c.Insecure {
g = gout.New(&defaultInsecureSkipVerify)
} else {
g = gout.New()
if len(header) > 0 {
g.SetHeader(header) //设置http header
}

g.SetMethod(c.Method). //设置method POST or GET or DELETE
Debug(true) //打开debug模式

if c.Compressed {
header = append(header, "Accept-Encoding", "deflate, gzip")
//header = append(header, "Accept-Encoding", "deflate, gzip")
if len(form) > 0 {
g.SetForm(form) //设置formdata
}

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

if len(form) > 0 {
g.SetForm(form) //设置formdata
if data != nil {
g.SetBody(data)
}

url := c.getURL()

return g.SetURL(url). //设置url
SetBody(data). //设置http body
Request() //获取*http.Request
Request() //获取*http.Request
}

func parseSlice(curl []string, c *Curl) *Curl {
Expand Down
Loading

0 comments on commit 60cd54c

Please sign in to comment.