updated dependencies
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
Paul 2022-03-26 12:13:52 +01:00
parent aee653dbde
commit 0cae2e5138
311 changed files with 17586 additions and 11805 deletions

40
go.mod
View File

@ -3,17 +3,17 @@ module git.paulbsd.com/paulbsd/qrz
go 1.17 go 1.17
require ( require (
github.com/antchfx/htmlquery v1.2.3 github.com/antchfx/htmlquery v1.2.4
github.com/antchfx/xpath v1.2.0 // indirect github.com/antchfx/xpath v1.2.0 // indirect
github.com/gobuffalo/here v0.6.2 // indirect github.com/gobuffalo/here v0.6.5 // indirect
github.com/gobuffalo/packr/v2 v2.8.1 github.com/gobuffalo/packr/v2 v2.8.3
github.com/golang/snappy v0.0.4 // indirect github.com/golang/snappy v0.0.4 // indirect
github.com/gopherjs/gopherjs v0.0.0-20210825203111-a709d8e111b3 // indirect github.com/gopherjs/gopherjs v0.0.0-20210825203111-a709d8e111b3 // indirect
github.com/karrick/godirwalk v1.16.1 // indirect github.com/karrick/godirwalk v1.16.1 // indirect
github.com/labstack/echo/v4 v4.5.0 github.com/labstack/echo/v4 v4.7.2
github.com/lib/pq v1.10.2 github.com/lib/pq v1.10.4
github.com/markbates/pkger v0.17.1 github.com/markbates/pkger v0.17.1
github.com/mattn/go-colorable v0.1.8 // indirect github.com/mattn/go-colorable v0.1.12 // indirect
github.com/mattn/go-sqlite3 v2.0.3+incompatible // indirect github.com/mattn/go-sqlite3 v2.0.3+incompatible // indirect
github.com/onsi/ginkgo v1.16.4 // indirect github.com/onsi/ginkgo v1.16.4 // indirect
github.com/onsi/gomega v1.16.0 // indirect github.com/onsi/gomega v1.16.0 // indirect
@ -21,31 +21,31 @@ require (
github.com/rogpeppe/go-internal v1.8.0 // indirect github.com/rogpeppe/go-internal v1.8.0 // indirect
github.com/sirupsen/logrus v1.8.1 // indirect github.com/sirupsen/logrus v1.8.1 // indirect
github.com/smartystreets/assertions v1.2.0 // indirect github.com/smartystreets/assertions v1.2.0 // indirect
github.com/spf13/cobra v1.2.1 github.com/spf13/cobra v1.4.0
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 // indirect golang.org/x/crypto v0.0.0-20220321153916-2c7772ba3064 // indirect
golang.org/x/net v0.0.0-20210825183410-e898025ed96a golang.org/x/net v0.0.0-20220325170049-de3da57026de
golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf // indirect golang.org/x/sys v0.0.0-20220325203850-36772127a21f // indirect
golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b // indirect golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect
golang.org/x/text v0.3.7 // indirect golang.org/x/text v0.3.7 // indirect
gopkg.in/ini.v1 v1.62.0 gopkg.in/ini.v1 v1.66.4
xorm.io/builder v0.3.9 // indirect xorm.io/builder v0.3.9 // indirect
xorm.io/xorm v1.2.3 xorm.io/xorm v1.2.5
) )
require ( require (
github.com/gobuffalo/logger v1.0.4 // indirect github.com/gobuffalo/logger v1.0.6 // indirect
github.com/gobuffalo/packd v1.0.0 // indirect github.com/gobuffalo/packd v1.0.1 // indirect
github.com/goccy/go-json v0.7.7 // indirect github.com/goccy/go-json v0.9.6 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/inconshreveable/mousetrap v1.0.0 // indirect github.com/inconshreveable/mousetrap v1.0.0 // indirect
github.com/json-iterator/go v1.1.11 // indirect github.com/json-iterator/go v1.1.12 // indirect
github.com/labstack/gommon v0.3.0 // indirect github.com/labstack/gommon v0.3.1 // indirect
github.com/markbates/errx v1.1.0 // indirect github.com/markbates/errx v1.1.0 // indirect
github.com/markbates/oncer v1.0.0 // indirect github.com/markbates/oncer v1.0.0 // indirect
github.com/markbates/safe v1.0.1 // indirect github.com/markbates/safe v1.0.1 // indirect
github.com/mattn/go-isatty v0.0.13 // indirect github.com/mattn/go-isatty v0.0.14 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.1 // indirect github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/spf13/pflag v1.0.5 // indirect github.com/spf13/pflag v1.0.5 // indirect
github.com/syndtr/goleveldb v1.0.0 // indirect github.com/syndtr/goleveldb v1.0.0 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect

54
go.sum
View File

@ -54,6 +54,8 @@ github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRF
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/antchfx/htmlquery v1.2.3 h1:sP3NFDneHx2stfNXCKbhHFo8XgNjCACnU/4AO5gWz6M= github.com/antchfx/htmlquery v1.2.3 h1:sP3NFDneHx2stfNXCKbhHFo8XgNjCACnU/4AO5gWz6M=
github.com/antchfx/htmlquery v1.2.3/go.mod h1:B0ABL+F5irhhMWg54ymEZinzMSi0Kt3I2if0BLYa3V0= github.com/antchfx/htmlquery v1.2.3/go.mod h1:B0ABL+F5irhhMWg54ymEZinzMSi0Kt3I2if0BLYa3V0=
github.com/antchfx/htmlquery v1.2.4 h1:qLteofCMe/KGovBI6SQgmou2QNyedFUW+pE+BpeZ494=
github.com/antchfx/htmlquery v1.2.4/go.mod h1:2xO6iu3EVWs7R2JYqBbp8YzG50gj/ofqs5/0VZoDZLc=
github.com/antchfx/xpath v1.1.6/go.mod h1:Yee4kTMuNiPYJ7nSNorELQMr1J33uOpXDMByNYhvtNk= github.com/antchfx/xpath v1.1.6/go.mod h1:Yee4kTMuNiPYJ7nSNorELQMr1J33uOpXDMByNYhvtNk=
github.com/antchfx/xpath v1.2.0 h1:mbwv7co+x0RwgeGAOHdrKy89GvHaGvxxBtPK0uF9Zr8= github.com/antchfx/xpath v1.2.0 h1:mbwv7co+x0RwgeGAOHdrKy89GvHaGvxxBtPK0uF9Zr8=
github.com/antchfx/xpath v1.2.0/go.mod h1:i54GszH55fYfBmoZXapTHN8T8tkcHfRgLyVwwqzXNcs= github.com/antchfx/xpath v1.2.0/go.mod h1:i54GszH55fYfBmoZXapTHN8T8tkcHfRgLyVwwqzXNcs=
@ -103,7 +105,9 @@ github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfc
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@ -148,16 +152,26 @@ github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg78
github.com/gobuffalo/here v0.6.0/go.mod h1:wAG085dHOYqUpf+Ap+WOdrPTp5IYcDAs/x7PLa8Y5fM= github.com/gobuffalo/here v0.6.0/go.mod h1:wAG085dHOYqUpf+Ap+WOdrPTp5IYcDAs/x7PLa8Y5fM=
github.com/gobuffalo/here v0.6.2 h1:ZtCqC7F9ou3moLbYfHM1Tj+gwHGgWhjyRjVjsir9BE0= github.com/gobuffalo/here v0.6.2 h1:ZtCqC7F9ou3moLbYfHM1Tj+gwHGgWhjyRjVjsir9BE0=
github.com/gobuffalo/here v0.6.2/go.mod h1:D75Sq0p2BVHdgQu3vCRsXbg85rx943V19urJpqAVWjI= github.com/gobuffalo/here v0.6.2/go.mod h1:D75Sq0p2BVHdgQu3vCRsXbg85rx943V19urJpqAVWjI=
github.com/gobuffalo/here v0.6.5 h1:OjrFcVbQBXff4EN+/m2xa+i1Wy6lW+3fn9Jf+b5WDXY=
github.com/gobuffalo/here v0.6.5/go.mod h1:y6q8eG7YstM/DfOKKAyHV1plrNsuYS5dcIerm8Habas=
github.com/gobuffalo/logger v1.0.3/go.mod h1:SoeejUwldiS7ZsyCBphOGURmWdwUFXs0J7TCjEhjKxM= github.com/gobuffalo/logger v1.0.3/go.mod h1:SoeejUwldiS7ZsyCBphOGURmWdwUFXs0J7TCjEhjKxM=
github.com/gobuffalo/logger v1.0.4 h1:HFJRqL7AmL4QNvQb9Grss9sDz+3u02VBgAoR03A7q4o= github.com/gobuffalo/logger v1.0.4 h1:HFJRqL7AmL4QNvQb9Grss9sDz+3u02VBgAoR03A7q4o=
github.com/gobuffalo/logger v1.0.4/go.mod h1:/GRUdWb+gM3shxj0P5jiV6ecVS3X0aboJvl+hBu0HeE= github.com/gobuffalo/logger v1.0.4/go.mod h1:/GRUdWb+gM3shxj0P5jiV6ecVS3X0aboJvl+hBu0HeE=
github.com/gobuffalo/logger v1.0.6 h1:nnZNpxYo0zx+Aj9RfMPBm+x9zAU2OayFh/xrAWi34HU=
github.com/gobuffalo/logger v1.0.6/go.mod h1:J31TBEHR1QLV2683OXTAItYIg8pv2JMHnF/quuAbMjs=
github.com/gobuffalo/packd v1.0.0 h1:6ERZvJHfe24rfFmA9OaoKBdC7+c9sydrytMg8SdFGBM= github.com/gobuffalo/packd v1.0.0 h1:6ERZvJHfe24rfFmA9OaoKBdC7+c9sydrytMg8SdFGBM=
github.com/gobuffalo/packd v1.0.0/go.mod h1:6VTc4htmJRFB7u1m/4LeMTWjFoYrUiBkU9Fdec9hrhI= github.com/gobuffalo/packd v1.0.0/go.mod h1:6VTc4htmJRFB7u1m/4LeMTWjFoYrUiBkU9Fdec9hrhI=
github.com/gobuffalo/packd v1.0.1 h1:U2wXfRr4E9DH8IdsDLlRFwTZTK7hLfq9qT/QHXGVe/0=
github.com/gobuffalo/packd v1.0.1/go.mod h1:PP2POP3p3RXGz7Jh6eYEf93S7vA2za6xM7QT85L4+VY=
github.com/gobuffalo/packr/v2 v2.8.1 h1:tkQpju6i3EtMXJ9uoF5GT6kB+LMTimDWD8Xvbz6zDVA= github.com/gobuffalo/packr/v2 v2.8.1 h1:tkQpju6i3EtMXJ9uoF5GT6kB+LMTimDWD8Xvbz6zDVA=
github.com/gobuffalo/packr/v2 v2.8.1/go.mod h1:c/PLlOuTU+p3SybaJATW3H6lX/iK7xEz5OeMf+NnJpg= github.com/gobuffalo/packr/v2 v2.8.1/go.mod h1:c/PLlOuTU+p3SybaJATW3H6lX/iK7xEz5OeMf+NnJpg=
github.com/gobuffalo/packr/v2 v2.8.3 h1:xE1yzvnO56cUC0sTpKR3DIbxZgB54AftTFMhB2XEWlY=
github.com/gobuffalo/packr/v2 v2.8.3/go.mod h1:0SahksCVcx4IMnigTjiFuyldmTrdTctXsOdiU5KwbKc=
github.com/goccy/go-json v0.7.4/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/goccy/go-json v0.7.4/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/goccy/go-json v0.7.7 h1:MflzqwHECILPg/0qDYB+jx+sJeNojJHEbRYsa8q7j/o= github.com/goccy/go-json v0.7.7 h1:MflzqwHECILPg/0qDYB+jx+sJeNojJHEbRYsa8q7j/o=
github.com/goccy/go-json v0.7.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/goccy/go-json v0.7.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/goccy/go-json v0.9.6 h1:5/4CtRQdtsX0sal8fdVhTaiMN01Ri8BExZZ8iRmHQ6E=
github.com/goccy/go-json v0.9.6/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
@ -336,6 +350,8 @@ github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/u
github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.11 h1:uVUAXhF2To8cbw/3xN3pxj6kk7TYKs98NIrTqPlMWAQ= github.com/json-iterator/go v1.1.11 h1:uVUAXhF2To8cbw/3xN3pxj6kk7TYKs98NIrTqPlMWAQ=
github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
@ -355,19 +371,27 @@ github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/labstack/echo/v4 v4.5.0 h1:JXk6H5PAw9I3GwizqUHhYyS4f45iyGebR/c1xNCeOCY= github.com/labstack/echo/v4 v4.5.0 h1:JXk6H5PAw9I3GwizqUHhYyS4f45iyGebR/c1xNCeOCY=
github.com/labstack/echo/v4 v4.5.0/go.mod h1:czIriw4a0C1dFun+ObrXp7ok03xON0N1awStJ6ArI7Y= github.com/labstack/echo/v4 v4.5.0/go.mod h1:czIriw4a0C1dFun+ObrXp7ok03xON0N1awStJ6ArI7Y=
github.com/labstack/echo/v4 v4.7.2 h1:Kv2/p8OaQ+M6Ex4eGimg9b9e6icoxA42JSlOR3msKtI=
github.com/labstack/echo/v4 v4.7.2/go.mod h1:xkCDAdFCIf8jsFQ5NnbK7oqaF/yU1A1X20Ltm0OvSks=
github.com/labstack/gommon v0.3.0 h1:JEeO0bvc78PKdyHxloTKiF8BD5iGrH8T6MSeGvSgob0= github.com/labstack/gommon v0.3.0 h1:JEeO0bvc78PKdyHxloTKiF8BD5iGrH8T6MSeGvSgob0=
github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k= github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k=
github.com/labstack/gommon v0.3.1 h1:OomWaJXm7xR6L1HmEtGyQf26TEn7V6X88mktX9kee9o=
github.com/labstack/gommon v0.3.1/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM=
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.10.2 h1:AqzbZs4ZoCBp+GtejcpCpcxM3zlSMx29dXbUSeVtJb8= github.com/lib/pq v1.10.2 h1:AqzbZs4ZoCBp+GtejcpCpcxM3zlSMx29dXbUSeVtJb8=
github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/lib/pq v1.10.4 h1:SO9z7FRPzA03QhHKJrH5BXA6HU1rS4V2nIVrrNC1iYk=
github.com/lib/pq v1.10.4/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM= github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM=
github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4= github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4=
github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ=
@ -388,6 +412,9 @@ github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVc
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8= github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8=
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40=
github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
@ -397,6 +424,8 @@ github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2y
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-isatty v0.0.13 h1:qdl+GuBjcsKKDco5BsxPJlId98mSWNKqYA+Co0SC1yA= github.com/mattn/go-isatty v0.0.13 h1:qdl+GuBjcsKKDco5BsxPJlId98mSWNKqYA+Co0SC1yA=
github.com/mattn/go-isatty v0.0.13/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.13/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
github.com/mattn/go-sqlite3 v1.14.8/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= github.com/mattn/go-sqlite3 v1.14.8/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
@ -419,6 +448,8 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJ
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg= github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg=
github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU= github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU=
@ -501,12 +532,14 @@ github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6So
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.5.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.5.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8= github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8=
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU=
github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc= github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E=
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
@ -540,6 +573,8 @@ github.com/spf13/cobra v0.0.6/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHN
github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo= github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo=
github.com/spf13/cobra v1.2.1 h1:+KmjbUw1hriSNMF55oPrkZcb27aECyrj8V2ytv7kWDw= github.com/spf13/cobra v1.2.1 h1:+KmjbUw1hriSNMF55oPrkZcb27aECyrj8V2ytv7kWDw=
github.com/spf13/cobra v1.2.1/go.mod h1:ExllRjgxM/piMAM+3tAZvg8fsklGAf3tPfi+i8t68Nk= github.com/spf13/cobra v1.2.1/go.mod h1:ExllRjgxM/piMAM+3tAZvg8fsklGAf3tPfi+i8t68Nk=
github.com/spf13/cobra v1.4.0 h1:y+wJpx64xcgO1V+RcnwW0LEHxTKRi2ZDPSBjWnrg88Q=
github.com/spf13/cobra v1.4.0/go.mod h1:Wo4iy3BUC+X2Fybo0PDqwJIv3dNRiZLHQymsfxlB84g=
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
@ -582,6 +617,7 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0= github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0=
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
@ -632,6 +668,8 @@ golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 h1:HWj/xjIHfjYU5nVXpTM0s39J9CbLn7Cc5a7IC5rwsMQ= golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 h1:HWj/xjIHfjYU5nVXpTM0s39J9CbLn7Cc5a7IC5rwsMQ=
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20220321153916-2c7772ba3064 h1:S25/rfnfsMVgORT4/J61MJ7rdyseOZOyvLIrZEZ7s6s=
golang.org/x/crypto v0.0.0-20220321153916-2c7772ba3064/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@ -714,8 +752,11 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v
golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210825183410-e898025ed96a h1:bRuuGXV8wwSdGTB+CtJf+FjgO1APK1CoO39T4BN/XBw= golang.org/x/net v0.0.0-20210825183410-e898025ed96a h1:bRuuGXV8wwSdGTB+CtJf+FjgO1APK1CoO39T4BN/XBw=
golang.org/x/net v0.0.0-20210825183410-e898025ed96a/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210825183410-e898025ed96a/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220325170049-de3da57026de h1:pZB1TWnKi+o4bENlbzAgLrEbY4RMYmUIRobMcSmfeYc=
golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@ -801,13 +842,21 @@ golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf h1:2ucpDCmfkl8Bd/FsLtiD653Wf96cW37s+iGx93zsu4k= golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf h1:2ucpDCmfkl8Bd/FsLtiD653Wf96cW37s+iGx93zsu4k=
golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220325203850-36772127a21f h1:TrmogKRsSOxRMJbLYGrB4SBbW+LJcEllYBLME5Zk5pU=
golang.org/x/sys v0.0.0-20220325203850-36772127a21f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b h1:9zKuko04nR4gjZ4+DNjHqRlAJqbJETHwiNKDqTfOjfE= golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b h1:9zKuko04nR4gjZ4+DNjHqRlAJqbJETHwiNKDqTfOjfE=
golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@ -885,6 +934,7 @@ golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4f
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
golang.org/x/tools v0.1.2 h1:kRBLX7v7Af8W7Gdbbc908OJcdgtK8bOz9Uaj8/F1ACA= golang.org/x/tools v0.1.2 h1:kRBLX7v7Af8W7Gdbbc908OJcdgtK8bOz9Uaj8/F1ACA=
golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=
golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@ -1014,6 +1064,8 @@ gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:a
gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.62.0 h1:duBzk771uxoUuOlyRLkHsygud9+5lrlGjdFBb4mSKDU= gopkg.in/ini.v1 v1.62.0 h1:duBzk771uxoUuOlyRLkHsygud9+5lrlGjdFBb4mSKDU=
gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.66.4 h1:SsAcf+mM7mRZo2nJNGt8mZCjG8ZRaNGMURJw7BsIST4=
gopkg.in/ini.v1 v1.66.4/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
@ -1075,3 +1127,5 @@ xorm.io/builder v0.3.9 h1:Sd65/LdWyO7LR8+Cbd+e7mm3sK/7U9k0jS3999IDHMc=
xorm.io/builder v0.3.9/go.mod h1:aUW0S9eb9VCaPohFCH3j7czOx1PMW3i1HrSzbLYGBSE= xorm.io/builder v0.3.9/go.mod h1:aUW0S9eb9VCaPohFCH3j7czOx1PMW3i1HrSzbLYGBSE=
xorm.io/xorm v1.2.3 h1:ZsVtQEsfkA31bbe8lhrP5cZKUjrxXQQO5tsr7Tf/0eo= xorm.io/xorm v1.2.3 h1:ZsVtQEsfkA31bbe8lhrP5cZKUjrxXQQO5tsr7Tf/0eo=
xorm.io/xorm v1.2.3/go.mod h1:fTG8tSjk6O1BYxwuohZUK+S1glnRycsCF05L1qQyEU0= xorm.io/xorm v1.2.3/go.mod h1:fTG8tSjk6O1BYxwuohZUK+S1glnRycsCF05L1qQyEU0=
xorm.io/xorm v1.2.5 h1:tqN7OhN8P9xi52qBb76I8m5maAJMz/SSbgK2RGPCPbo=
xorm.io/xorm v1.2.5/go.mod h1:fTG8tSjk6O1BYxwuohZUK+S1glnRycsCF05L1qQyEU0=

View File

@ -60,15 +60,15 @@ list := htmlquery.Find(doc, "//a")
#### Find all A elements that have `href` attribute. #### Find all A elements that have `href` attribute.
```go ```go
list := range htmlquery.Find(doc, "//a[@href]") list := htmlquery.Find(doc, "//a[@href]")
``` ```
#### Find all A elements with `href` attribute and only return `href` value. #### Find all A elements with `href` attribute and only return `href` value.
```go ```go
list := range htmlquery.Find(doc, "//a/@href") list := htmlquery.Find(doc, "//a/@href")
for n := range list{ for _ , n := range list{
fmt.Println(htmlquery.InnerText(n)) // output @href value without A element. fmt.Println(htmlquery.SelectAttr(n, "href")) // output @href value
} }
``` ```
@ -78,6 +78,13 @@ for n := range list{
a := htmlquery.FindOne(doc, "//a[3]") a := htmlquery.FindOne(doc, "//a[3]")
``` ```
### Find children element (img) under A `href` and print the source
```go
a := htmlquery.FindOne(doc, "//a")
img := htmlquery.FindOne(a, "//img")
fmt.Prinln(htmlquery.SelectAttr(img, "src")) // output @src value
```
#### Evaluate the number of all IMG element. #### Evaluate the number of all IMG element.
```go ```go

View File

@ -55,10 +55,10 @@ func QueryAll(top *html.Node, expr string) ([]*html.Node, error) {
return nodes, nil return nodes, nil
} }
// Query searches the html.Node that matches by the specified XPath expr, // Query runs the given XPath expression against the given html.Node and
// and return the first element of matched html.Node. // returns the first matching html.Node, or nil if no matches are found.
// //
// Return an error if the expression `expr` cannot be parsed. // Returns an error if the expression `expr` cannot be parsed.
func Query(top *html.Node, expr string) (*html.Node, error) { func Query(top *html.Node, expr string) (*html.Node, error) {
exp, err := getQuery(expr) exp, err := getQuery(expr)
if err != nil { if err != nil {
@ -179,6 +179,19 @@ func SelectAttr(n *html.Node, name string) (val string) {
return return
} }
// ExistsAttr returns whether attribute with specified name exists.
func ExistsAttr(n *html.Node, name string) bool {
if n == nil {
return false
}
for _, attr := range n.Attr {
if attr.Key == name {
return true
}
}
return false
}
// OutputHTML returns the text including tags name. // OutputHTML returns the text including tags name.
func OutputHTML(n *html.Node, self bool) string { func OutputHTML(n *html.Node, self bool) string {
var buf bytes.Buffer var buf bytes.Buffer

View File

@ -38,7 +38,7 @@ changelog:
brews: brews:
- -
name: 'here' name: 'here'
github: tap:
owner: 'gobuffalo' owner: 'gobuffalo'
name: 'homebrew-tap' name: 'homebrew-tap'
install: | install: |

View File

@ -2,7 +2,9 @@
<p align="center"> <p align="center">
<a href="https://godoc.org/github.com/gobuffalo/logger"><img src="https://godoc.org/github.com/gobuffalo/logger?status.svg" alt="GoDoc" /></a> <a href="https://godoc.org/github.com/gobuffalo/logger"><img src="https://godoc.org/github.com/gobuffalo/logger?status.svg" alt="GoDoc" /></a>
<a href="https://travis-ci.org/gobuffalo/logger"><img src="https://travis-ci.org/gobuffalo/logger.svg?branch=master" alt="Build Status" /></a>
![Tests](https://github.com/gobuffalo/logger/actions/workflows/tests.yml/badge.svg)
<a href="https://goreportcard.com/report/github.com/gobuffalo/logger"><img src="https://goreportcard.com/badge/github.com/gobuffalo/logger" alt="Go Report Card" /></a> <a href="https://goreportcard.com/report/github.com/gobuffalo/logger"><img src="https://goreportcard.com/badge/github.com/gobuffalo/logger" alt="Go Report Card" /></a>
</p> </p>

View File

@ -1,4 +1,4 @@
package logger package logger
// Version of the logger // Version of the logger
const Version = "v1.0.1" const Version = "v1.0.6"

20
vendor/github.com/gobuffalo/packr/v2/.codeclimate.yml generated vendored Normal file
View File

@ -0,0 +1,20 @@
---
engines:
golint:
enabled: true
checks:
GoLint/Naming/MixedCaps:
enabled: false
govet:
enabled: true
gofmt:
enabled: true
fixme:
enabled: true
ratings:
paths:
- "**.go"
exclude_paths:
- "**/*_test.go"
- "*_test.go"
- "fixtures/"

37
vendor/github.com/gobuffalo/packr/v2/.gitignore generated vendored Normal file
View File

@ -0,0 +1,37 @@
*.log
./packr2
.DS_Store
doc
tmp
pkg
*.gem
*.pid
coverage
coverage.data
build/*
*.pbxuser
*.mode1v3
.svn
profile
.console_history
.sass-cache/*
.rake_tasks~
*.log.lck
solr/
.jhw-cache/
jhw.*
*.sublime*
node_modules/
dist/
generated/
.vendor/
bin/*
gin-bin
/packr_darwin_amd64
/packr_linux_amd64
.vscode/
debug.test
.grifter/
*-packr.go
.idea/

View File

@ -1,27 +1,65 @@
**NOTICE: Please consider migrating your projects to github.com/markbates/pkger. It has an idiomatic API, minimal dependencies, a stronger test suite (tested directly against the std lib counterparts), transparent tooling, and more.** **NOTICE: Please consider migrating your projects to
[embed](https://pkg.go.dev/embed) which is native file embedding feature of Go,
or github.com/markbates/pkger. It has an idiomatic API, minimal dependencies, a stronger test suite (tested directly against the std lib counterparts), transparent tooling, and more.**
https://blog.gobuffalo.io/introducing-pkger-static-file-embedding-in-go-1ce76dc79c65 https://blog.gobuffalo.io/introducing-pkger-static-file-embedding-in-go-1ce76dc79c65
# Packr (v2) # Packr (v2)
[![GoDoc](https://godoc.org/github.com/gobuffalo/packr/v2?status.svg)](https://godoc.org/github.com/gobuffalo/packr/v2) [![GoDoc](https://godoc.org/github.com/gobuffalo/packr/v2?status.svg)](https://godoc.org/github.com/gobuffalo/packr/v2)
[![Actions Status](https://github.com/gobuffalo/packr/workflows/Tests/badge.svg)](https://github.com/gobuffalo/packr/actions)
Packr is a simple solution for bundling static assets inside of Go binaries. Most importantly it does it in a way that is friendly to developers while they are developing. Packr is a simple solution for bundling static assets inside of Go binaries. Most importantly it does it in a way that is friendly to developers while they are developing.
At this moment, supported go versions are:
* 1.16.x
* 1.17.x
even though it may (or may not) working well with older versions.
## Intro Video ## Intro Video
To get an idea of the what and why of Packr, please enjoy this short video: [https://vimeo.com/219863271](https://vimeo.com/219863271). To get an idea of the what and why of Packr, please enjoy this short video: [https://vimeo.com/219863271](https://vimeo.com/219863271).
## Library Installation ## Library Installation
```text ### Go 1.16 and above
$ go get -u github.com/gobuffalo/packr/v2/...
```console
$ go install github.com/gobuffalo/packr/v2@v2.8.3
```
or
```console
$ go install github.com/gobuffalo/packr/v2@latest
```
### Go 1.15 and below
```console
$ go get -u github.com/gobuffalo/packr/...
``` ```
## Binary Installation ## Binary Installation
```text ### Go 1.16 and above
$ go get -u github.com/gobuffalo/packr/v2/packr2
```console
$ go install github.com/gobuffalo/packr/v2/packr2@v2.8.3
```
or
```console
$ go install github.com/gobuffalo/packr/v2/packr2@latest
```
### Go 1.15 and below
```console
$ go get -u github.com/gobuffalo/packr/packr2
``` ```
## New File Format FAQs ## New File Format FAQs

View File

@ -1,6 +1,6 @@
# /Users/smichalak/dev/packr/v2 Stands on the Shoulders of Giants # github.com/gobuffalo/packr/v2 Stands on the Shoulders of Giants
/Users/smichalak/dev/packr/v2 does not try to reinvent the wheel! Instead, it uses the already great wheels developed by the Go community and puts them all together in the best way possible. Without these giants, this project would not be possible. Please make sure to check them out and thank them for all of their hard work. github.com/gobuffalo/packr/v2 does not try to reinvent the wheel! Instead, it uses the already great wheels developed by the Go community and puts them all together in the best way possible. Without these giants, this project would not be possible. Please make sure to check them out and thank them for all of their hard work.
Thank you to the following **GIANTS**: Thank you to the following **GIANTS**:

View File

@ -1,4 +1,4 @@
package packr package packr
// Version of Packr // Version of Packr
const Version = "v2.8.1" const Version = "v2.8.3"

View File

@ -1,3 +1,88 @@
# v0.9.6 - 2022/03/22
### Fix bugs
* Correct the handling of the minimum value of int type for decoder ( #344 )
* Fix bugs of stream decoder's bufferSize ( #349 )
* Add a guard to use typeptr more safely ( #351 )
### Improve decoder performance
* Improve escapeString's performance ( #345 )
### Others
* Update go version for CI ( #347 )
# v0.9.5 - 2022/03/04
### Fix bugs
* Fix panic when decoding time.Time with context ( #328 )
* Fix reading the next character in buffer to nul consideration ( #338 )
* Fix incorrect handling on skipValue ( #341 )
### Improve decoder performance
* Improve performance when a payload contains escape sequence ( #334 )
# v0.9.4 - 2022/01/21
* Fix IsNilForMarshaler for string type with omitempty ( #323 )
* Fix the case where the embedded field is at the end ( #326 )
# v0.9.3 - 2022/01/14
* Fix logic of removing struct field for decoder ( #322 )
# v0.9.2 - 2022/01/14
* Add invalid decoder to delay type error judgment at decode ( #321 )
# v0.9.1 - 2022/01/11
* Fix encoding of MarshalText/MarshalJSON operation with head offset ( #319 )
# v0.9.0 - 2022/01/05
### New feature
* Supports dynamic filtering of struct fields ( #314 )
### Improve encoding performance
* Improve map encoding performance ( #310 )
* Optimize encoding path for escaped string ( #311 )
* Add encoding option for performance ( #312 )
### Fix bugs
* Fix panic at encoding map value on 1.18 ( #310 )
* Fix MarshalIndent for interface type ( #317 )
# v0.8.1 - 2021/12/05
* Fix operation conversion from PtrHead to Head in Recursive type ( #305 )
# v0.8.0 - 2021/12/02
* Fix embedded field conflict behavior ( #300 )
* Refactor compiler for encoder ( #301 #302 )
# v0.7.10 - 2021/10/16
* Fix conversion from pointer to uint64 ( #294 )
# v0.7.9 - 2021/09/28
* Fix encoding of nil value about interface type that has method ( #291 )
# v0.7.8 - 2021/09/01
* Fix mapassign_faststr for indirect struct type ( #283 )
* Fix encoding of not empty interface type ( #284 )
* Fix encoding of empty struct interface type ( #286 )
# v0.7.7 - 2021/08/25 # v0.7.7 - 2021/08/25
* Fix invalid utf8 on stream decoder ( #279 ) * Fix invalid utf8 on stream decoder ( #279 )

View File

@ -13,7 +13,7 @@ Fast JSON encoder/decoder compatible with encoding/json for Go
``` ```
* version ( expected release date ) * version ( expected release date )
* v0.7.0 * v0.9.0
| |
| while maintaining compatibility with encoding/json, we will add convenient APIs | while maintaining compatibility with encoding/json, we will add convenient APIs
| |
@ -21,9 +21,8 @@ Fast JSON encoder/decoder compatible with encoding/json for Go
* v1.0.0 * v1.0.0
``` ```
We are accepting requests for features that will be implemented between v0.7.0 and v.1.0.0. We are accepting requests for features that will be implemented between v0.9.0 and v.1.0.0.
If you have the API you need, please submit your issue [here](https://github.com/goccy/go-json/issues). If you have the API you need, please submit your issue [here](https://github.com/goccy/go-json/issues).
For example, I'm thinking of supporting `context.Context` of `json.Marshaler` and decoding using JSON Path.
# Features # Features
@ -32,6 +31,7 @@ For example, I'm thinking of supporting `context.Context` of `json.Marshaler` an
- Flexible customization with options - Flexible customization with options
- Coloring the encoded string - Coloring the encoded string
- Can propagate context.Context to `MarshalJSON` or `UnmarshalJSON` - Can propagate context.Context to `MarshalJSON` or `UnmarshalJSON`
- Can dynamically filter the fields of the structure type-safely
# Installation # Installation

View File

@ -1,7 +1,7 @@
version: '2' version: '2'
services: services:
go-json: go-json:
image: golang:1.16 image: golang:1.18
volumes: volumes:
- '.:/go/src/go-json' - '.:/go/src/go-json'
deploy: deploy:

View File

@ -61,6 +61,7 @@ func (e *Encoder) encodeWithOption(ctx *encoder.RuntimeContext, v interface{}, o
if e.enabledHTMLEscape { if e.enabledHTMLEscape {
ctx.Option.Flag |= encoder.HTMLEscapeOption ctx.Option.Flag |= encoder.HTMLEscapeOption
} }
ctx.Option.Flag |= encoder.NormalizeUTF8Option
for _, optFunc := range optFuncs { for _, optFunc := range optFuncs {
optFunc(ctx.Option) optFunc(ctx.Option)
} }
@ -111,7 +112,7 @@ func (e *Encoder) SetIndent(prefix, indent string) {
func marshalContext(ctx context.Context, v interface{}, optFuncs ...EncodeOptionFunc) ([]byte, error) { func marshalContext(ctx context.Context, v interface{}, optFuncs ...EncodeOptionFunc) ([]byte, error) {
rctx := encoder.TakeRuntimeContext() rctx := encoder.TakeRuntimeContext()
rctx.Option.Flag = 0 rctx.Option.Flag = 0
rctx.Option.Flag = encoder.HTMLEscapeOption | encoder.ContextOption rctx.Option.Flag = encoder.HTMLEscapeOption | encoder.NormalizeUTF8Option | encoder.ContextOption
rctx.Option.Context = ctx rctx.Option.Context = ctx
for _, optFunc := range optFuncs { for _, optFunc := range optFuncs {
optFunc(rctx.Option) optFunc(rctx.Option)
@ -139,7 +140,7 @@ func marshal(v interface{}, optFuncs ...EncodeOptionFunc) ([]byte, error) {
ctx := encoder.TakeRuntimeContext() ctx := encoder.TakeRuntimeContext()
ctx.Option.Flag = 0 ctx.Option.Flag = 0
ctx.Option.Flag |= encoder.HTMLEscapeOption ctx.Option.Flag |= (encoder.HTMLEscapeOption | encoder.NormalizeUTF8Option)
for _, optFunc := range optFuncs { for _, optFunc := range optFuncs {
optFunc(ctx.Option) optFunc(ctx.Option)
} }
@ -166,7 +167,7 @@ func marshalNoEscape(v interface{}) ([]byte, error) {
ctx := encoder.TakeRuntimeContext() ctx := encoder.TakeRuntimeContext()
ctx.Option.Flag = 0 ctx.Option.Flag = 0
ctx.Option.Flag |= encoder.HTMLEscapeOption ctx.Option.Flag |= (encoder.HTMLEscapeOption | encoder.NormalizeUTF8Option)
buf, err := encodeNoEscape(ctx, v) buf, err := encodeNoEscape(ctx, v)
if err != nil { if err != nil {
@ -190,7 +191,7 @@ func marshalIndent(v interface{}, prefix, indent string, optFuncs ...EncodeOptio
ctx := encoder.TakeRuntimeContext() ctx := encoder.TakeRuntimeContext()
ctx.Option.Flag = 0 ctx.Option.Flag = 0
ctx.Option.Flag |= (encoder.HTMLEscapeOption | encoder.IndentOption) ctx.Option.Flag |= (encoder.HTMLEscapeOption | encoder.NormalizeUTF8Option | encoder.IndentOption)
for _, optFunc := range optFuncs { for _, optFunc := range optFuncs {
optFunc(ctx.Option) optFunc(ctx.Option)
} }
@ -220,7 +221,7 @@ func encode(ctx *encoder.RuntimeContext, v interface{}) ([]byte, error) {
typ := header.typ typ := header.typ
typeptr := uintptr(unsafe.Pointer(typ)) typeptr := uintptr(unsafe.Pointer(typ))
codeSet, err := encoder.CompileToGetCodeSet(typeptr) codeSet, err := encoder.CompileToGetCodeSet(ctx, typeptr)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -248,7 +249,7 @@ func encodeNoEscape(ctx *encoder.RuntimeContext, v interface{}) ([]byte, error)
typ := header.typ typ := header.typ
typeptr := uintptr(unsafe.Pointer(typ)) typeptr := uintptr(unsafe.Pointer(typ))
codeSet, err := encoder.CompileToGetCodeSet(typeptr) codeSet, err := encoder.CompileToGetCodeSet(ctx, typeptr)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -275,7 +276,7 @@ func encodeIndent(ctx *encoder.RuntimeContext, v interface{}, prefix, indent str
typ := header.typ typ := header.typ
typeptr := uintptr(unsafe.Pointer(typ)) typeptr := uintptr(unsafe.Pointer(typ))
codeSet, err := encoder.CompileToGetCodeSet(typeptr) codeSet, err := encoder.CompileToGetCodeSet(ctx, typeptr)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -9,7 +9,6 @@ import (
"unicode" "unicode"
"unsafe" "unsafe"
"github.com/goccy/go-json/internal/errors"
"github.com/goccy/go-json/internal/runtime" "github.com/goccy/go-json/internal/runtime"
) )
@ -126,13 +125,7 @@ func compile(typ *runtime.Type, structName, fieldName string, structTypeToDecode
case reflect.Func: case reflect.Func:
return compileFunc(typ, structName, fieldName) return compileFunc(typ, structName, fieldName)
} }
return nil, &errors.UnmarshalTypeError{ return newInvalidDecoder(typ, structName, fieldName), nil
Value: "object",
Type: runtime.RType2Type(typ),
Offset: 0,
Struct: structName,
Field: fieldName,
}
} }
func isStringTagSupportedType(typ *runtime.Type) bool { func isStringTagSupportedType(typ *runtime.Type) bool {
@ -174,17 +167,9 @@ func compileMapKey(typ *runtime.Type, structName, fieldName string, structTypeTo
case *ptrDecoder: case *ptrDecoder:
dec = t.dec dec = t.dec
default: default:
goto ERROR return newInvalidDecoder(typ, structName, fieldName), nil
} }
} }
ERROR:
return nil, &errors.UnmarshalTypeError{
Value: "object",
Type: runtime.RType2Type(typ),
Offset: 0,
Struct: structName,
Field: fieldName,
}
} }
func compilePtr(typ *runtime.Type, structName, fieldName string, structTypeToDecoder map[uintptr]Decoder) (Decoder, error) { func compilePtr(typ *runtime.Type, structName, fieldName string, structTypeToDecoder map[uintptr]Decoder) (Decoder, error) {
@ -322,64 +307,21 @@ func compileFunc(typ *runtime.Type, strutName, fieldName string) (Decoder, error
return newFuncDecoder(typ, strutName, fieldName), nil return newFuncDecoder(typ, strutName, fieldName), nil
} }
func removeConflictFields(fieldMap map[string]*structFieldSet, conflictedMap map[string]struct{}, dec *structDecoder, field reflect.StructField) { func typeToStructTags(typ *runtime.Type) runtime.StructTags {
for k, v := range dec.fieldMap { tags := runtime.StructTags{}
if _, exists := conflictedMap[k]; exists { fieldNum := typ.NumField()
// already conflicted key for i := 0; i < fieldNum; i++ {
field := typ.Field(i)
if runtime.IsIgnoredStructField(field) {
continue continue
} }
set, exists := fieldMap[k] tags = append(tags, runtime.StructTagFromField(field))
if !exists {
fieldSet := &structFieldSet{
dec: v.dec,
offset: field.Offset + v.offset,
isTaggedKey: v.isTaggedKey,
key: k,
keyLen: int64(len(k)),
}
fieldMap[k] = fieldSet
lower := strings.ToLower(k)
if _, exists := fieldMap[lower]; !exists {
fieldMap[lower] = fieldSet
}
continue
}
if set.isTaggedKey {
if v.isTaggedKey {
// conflict tag key
delete(fieldMap, k)
delete(fieldMap, strings.ToLower(k))
conflictedMap[k] = struct{}{}
conflictedMap[strings.ToLower(k)] = struct{}{}
}
} else {
if v.isTaggedKey {
fieldSet := &structFieldSet{
dec: v.dec,
offset: field.Offset + v.offset,
isTaggedKey: v.isTaggedKey,
key: k,
keyLen: int64(len(k)),
}
fieldMap[k] = fieldSet
lower := strings.ToLower(k)
if _, exists := fieldMap[lower]; !exists {
fieldMap[lower] = fieldSet
}
} else {
// conflict tag key
delete(fieldMap, k)
delete(fieldMap, strings.ToLower(k))
conflictedMap[k] = struct{}{}
conflictedMap[strings.ToLower(k)] = struct{}{}
}
}
} }
return tags
} }
func compileStruct(typ *runtime.Type, structName, fieldName string, structTypeToDecoder map[uintptr]Decoder) (Decoder, error) { func compileStruct(typ *runtime.Type, structName, fieldName string, structTypeToDecoder map[uintptr]Decoder) (Decoder, error) {
fieldNum := typ.NumField() fieldNum := typ.NumField()
conflictedMap := map[string]struct{}{}
fieldMap := map[string]*structFieldSet{} fieldMap := map[string]*structFieldSet{}
typeptr := uintptr(unsafe.Pointer(typ)) typeptr := uintptr(unsafe.Pointer(typ))
if dec, exists := structTypeToDecoder[typeptr]; exists { if dec, exists := structTypeToDecoder[typeptr]; exists {
@ -388,6 +330,8 @@ func compileStruct(typ *runtime.Type, structName, fieldName string, structTypeTo
structDec := newStructDecoder(structName, fieldName, fieldMap) structDec := newStructDecoder(structName, fieldName, fieldMap)
structTypeToDecoder[typeptr] = structDec structTypeToDecoder[typeptr] = structDec
structName = typ.Name() structName = typ.Name()
tags := typeToStructTags(typ)
allFields := []*structFieldSet{}
for i := 0; i < fieldNum; i++ { for i := 0; i < fieldNum; i++ {
field := typ.Field(i) field := typ.Field(i)
if runtime.IsIgnoredStructField(field) { if runtime.IsIgnoredStructField(field) {
@ -405,7 +349,19 @@ func compileStruct(typ *runtime.Type, structName, fieldName string, structTypeTo
// recursive definition // recursive definition
continue continue
} }
removeConflictFields(fieldMap, conflictedMap, stDec, field) for k, v := range stDec.fieldMap {
if tags.ExistsKey(k) {
continue
}
fieldSet := &structFieldSet{
dec: v.dec,
offset: field.Offset + v.offset,
isTaggedKey: v.isTaggedKey,
key: k,
keyLen: int64(len(k)),
}
allFields = append(allFields, fieldSet)
}
} else if pdec, ok := dec.(*ptrDecoder); ok { } else if pdec, ok := dec.(*ptrDecoder); ok {
contentDec := pdec.contentDecoder() contentDec := pdec.contentDecoder()
if pdec.typ == typ { if pdec.typ == typ {
@ -421,58 +377,18 @@ func compileStruct(typ *runtime.Type, structName, fieldName string, structTypeTo
} }
if dec, ok := contentDec.(*structDecoder); ok { if dec, ok := contentDec.(*structDecoder); ok {
for k, v := range dec.fieldMap { for k, v := range dec.fieldMap {
if _, exists := conflictedMap[k]; exists { if tags.ExistsKey(k) {
// already conflicted key
continue continue
} }
set, exists := fieldMap[k] fieldSet := &structFieldSet{
if !exists { dec: newAnonymousFieldDecoder(pdec.typ, v.offset, v.dec),
fieldSet := &structFieldSet{ offset: field.Offset,
dec: newAnonymousFieldDecoder(pdec.typ, v.offset, v.dec), isTaggedKey: v.isTaggedKey,
offset: field.Offset, key: k,
isTaggedKey: v.isTaggedKey, keyLen: int64(len(k)),
key: k, err: fieldSetErr,
keyLen: int64(len(k)),
err: fieldSetErr,
}
fieldMap[k] = fieldSet
lower := strings.ToLower(k)
if _, exists := fieldMap[lower]; !exists {
fieldMap[lower] = fieldSet
}
continue
}
if set.isTaggedKey {
if v.isTaggedKey {
// conflict tag key
delete(fieldMap, k)
delete(fieldMap, strings.ToLower(k))
conflictedMap[k] = struct{}{}
conflictedMap[strings.ToLower(k)] = struct{}{}
}
} else {
if v.isTaggedKey {
fieldSet := &structFieldSet{
dec: newAnonymousFieldDecoder(pdec.typ, v.offset, v.dec),
offset: field.Offset,
isTaggedKey: v.isTaggedKey,
key: k,
keyLen: int64(len(k)),
err: fieldSetErr,
}
fieldMap[k] = fieldSet
lower := strings.ToLower(k)
if _, exists := fieldMap[lower]; !exists {
fieldMap[lower] = fieldSet
}
} else {
// conflict tag key
delete(fieldMap, k)
delete(fieldMap, strings.ToLower(k))
conflictedMap[k] = struct{}{}
conflictedMap[strings.ToLower(k)] = struct{}{}
}
} }
allFields = append(allFields, fieldSet)
} }
} }
} }
@ -493,11 +409,15 @@ func compileStruct(typ *runtime.Type, structName, fieldName string, structTypeTo
key: key, key: key,
keyLen: int64(len(key)), keyLen: int64(len(key)),
} }
fieldMap[key] = fieldSet allFields = append(allFields, fieldSet)
lower := strings.ToLower(key) }
if _, exists := fieldMap[lower]; !exists { }
fieldMap[lower] = fieldSet for _, set := range filterDuplicatedFields(allFields) {
} fieldMap[set.key] = set
lower := strings.ToLower(set.key)
if _, exists := fieldMap[lower]; !exists {
// first win
fieldMap[lower] = set
} }
} }
delete(structTypeToDecoder, typeptr) delete(structTypeToDecoder, typeptr)
@ -505,6 +425,42 @@ func compileStruct(typ *runtime.Type, structName, fieldName string, structTypeTo
return structDec, nil return structDec, nil
} }
func filterDuplicatedFields(allFields []*structFieldSet) []*structFieldSet {
fieldMap := map[string][]*structFieldSet{}
for _, field := range allFields {
fieldMap[field.key] = append(fieldMap[field.key], field)
}
duplicatedFieldMap := map[string]struct{}{}
for k, sets := range fieldMap {
sets = filterFieldSets(sets)
if len(sets) != 1 {
duplicatedFieldMap[k] = struct{}{}
}
}
filtered := make([]*structFieldSet, 0, len(allFields))
for _, field := range allFields {
if _, exists := duplicatedFieldMap[field.key]; exists {
continue
}
filtered = append(filtered, field)
}
return filtered
}
func filterFieldSets(sets []*structFieldSet) []*structFieldSet {
if len(sets) == 1 {
return sets
}
filtered := make([]*structFieldSet, 0, len(sets))
for _, set := range sets {
if set.isTaggedKey {
filtered = append(filtered, set)
}
}
return filtered
}
func implementsUnmarshalJSONType(typ *runtime.Type) bool { func implementsUnmarshalJSONType(typ *runtime.Type) bool {
return typ.Implements(unmarshalJSONType) || typ.Implements(unmarshalJSONContextType) return typ.Implements(unmarshalJSONType) || typ.Implements(unmarshalJSONContextType)
} }

View File

@ -192,15 +192,15 @@ func (d *intDecoder) DecodeStream(s *Stream, depth int64, p unsafe.Pointer) erro
} }
switch d.kind { switch d.kind {
case reflect.Int8: case reflect.Int8:
if i64 <= -1*(1<<7) || (1<<7) <= i64 { if i64 < -1*(1<<7) || (1<<7) <= i64 {
return d.typeError(bytes, s.totalOffset()) return d.typeError(bytes, s.totalOffset())
} }
case reflect.Int16: case reflect.Int16:
if i64 <= -1*(1<<15) || (1<<15) <= i64 { if i64 < -1*(1<<15) || (1<<15) <= i64 {
return d.typeError(bytes, s.totalOffset()) return d.typeError(bytes, s.totalOffset())
} }
case reflect.Int32: case reflect.Int32:
if i64 <= -1*(1<<31) || (1<<31) <= i64 { if i64 < -1*(1<<31) || (1<<31) <= i64 {
return d.typeError(bytes, s.totalOffset()) return d.typeError(bytes, s.totalOffset())
} }
} }
@ -225,15 +225,15 @@ func (d *intDecoder) Decode(ctx *RuntimeContext, cursor, depth int64, p unsafe.P
} }
switch d.kind { switch d.kind {
case reflect.Int8: case reflect.Int8:
if i64 <= -1*(1<<7) || (1<<7) <= i64 { if i64 < -1*(1<<7) || (1<<7) <= i64 {
return 0, d.typeError(bytes, cursor) return 0, d.typeError(bytes, cursor)
} }
case reflect.Int16: case reflect.Int16:
if i64 <= -1*(1<<15) || (1<<15) <= i64 { if i64 < -1*(1<<15) || (1<<15) <= i64 {
return 0, d.typeError(bytes, cursor) return 0, d.typeError(bytes, cursor)
} }
case reflect.Int32: case reflect.Int32:
if i64 <= -1*(1<<31) || (1<<31) <= i64 { if i64 < -1*(1<<31) || (1<<31) <= i64 {
return 0, d.typeError(bytes, cursor) return 0, d.typeError(bytes, cursor)
} }
} }

View File

@ -0,0 +1,45 @@
package decoder
import (
"reflect"
"unsafe"
"github.com/goccy/go-json/internal/errors"
"github.com/goccy/go-json/internal/runtime"
)
type invalidDecoder struct {
typ *runtime.Type
kind reflect.Kind
structName string
fieldName string
}
func newInvalidDecoder(typ *runtime.Type, structName, fieldName string) *invalidDecoder {
return &invalidDecoder{
typ: typ,
kind: typ.Kind(),
structName: structName,
fieldName: fieldName,
}
}
func (d *invalidDecoder) DecodeStream(s *Stream, depth int64, p unsafe.Pointer) error {
return &errors.UnmarshalTypeError{
Value: "object",
Type: runtime.RType2Type(d.typ),
Offset: s.totalOffset(),
Struct: d.structName,
Field: d.fieldName,
}
}
func (d *invalidDecoder) Decode(ctx *RuntimeContext, cursor, depth int64, p unsafe.Pointer) (int64, error) {
return 0, &errors.UnmarshalTypeError{
Value: "object",
Type: runtime.RType2Type(d.typ),
Offset: cursor,
Struct: d.structName,
Field: d.fieldName,
}
}

View File

@ -9,29 +9,42 @@ import (
) )
type mapDecoder struct { type mapDecoder struct {
mapType *runtime.Type mapType *runtime.Type
keyType *runtime.Type keyType *runtime.Type
valueType *runtime.Type valueType *runtime.Type
stringKeyType bool canUseAssignFaststrType bool
keyDecoder Decoder keyDecoder Decoder
valueDecoder Decoder valueDecoder Decoder
structName string structName string
fieldName string fieldName string
} }
func newMapDecoder(mapType *runtime.Type, keyType *runtime.Type, keyDec Decoder, valueType *runtime.Type, valueDec Decoder, structName, fieldName string) *mapDecoder { func newMapDecoder(mapType *runtime.Type, keyType *runtime.Type, keyDec Decoder, valueType *runtime.Type, valueDec Decoder, structName, fieldName string) *mapDecoder {
return &mapDecoder{ return &mapDecoder{
mapType: mapType, mapType: mapType,
keyDecoder: keyDec, keyDecoder: keyDec,
keyType: keyType, keyType: keyType,
stringKeyType: keyType.Kind() == reflect.String, canUseAssignFaststrType: canUseAssignFaststrType(keyType, valueType),
valueType: valueType, valueType: valueType,
valueDecoder: valueDec, valueDecoder: valueDec,
structName: structName, structName: structName,
fieldName: fieldName, fieldName: fieldName,
} }
} }
const (
mapMaxElemSize = 128
)
// See detail: https://github.com/goccy/go-json/pull/283
func canUseAssignFaststrType(key *runtime.Type, value *runtime.Type) bool {
indirectElem := value.Size() > mapMaxElemSize
if indirectElem {
return false
}
return key.Kind() == reflect.String
}
//go:linkname makemap reflect.makemap //go:linkname makemap reflect.makemap
func makemap(*runtime.Type, int) unsafe.Pointer func makemap(*runtime.Type, int) unsafe.Pointer
@ -45,8 +58,8 @@ func mapassign_faststr(t *runtime.Type, m unsafe.Pointer, s string) unsafe.Point
func mapassign(t *runtime.Type, m unsafe.Pointer, k, v unsafe.Pointer) func mapassign(t *runtime.Type, m unsafe.Pointer, k, v unsafe.Pointer)
func (d *mapDecoder) mapassign(t *runtime.Type, m, k, v unsafe.Pointer) { func (d *mapDecoder) mapassign(t *runtime.Type, m, k, v unsafe.Pointer) {
if d.stringKeyType { if d.canUseAssignFaststrType {
mapV := mapassign_faststr(d.mapType, m, *(*string)(k)) mapV := mapassign_faststr(t, m, *(*string)(k))
typedmemmove(d.valueType, mapV, v) typedmemmove(d.valueType, mapV, v)
} else { } else {
mapassign(t, m, k, v) mapassign(t, m, k, v)
@ -74,13 +87,13 @@ func (d *mapDecoder) DecodeStream(s *Stream, depth int64, p unsafe.Pointer) erro
if mapValue == nil { if mapValue == nil {
mapValue = makemap(d.mapType, 0) mapValue = makemap(d.mapType, 0)
} }
if s.buf[s.cursor+1] == '}' { s.cursor++
if s.equalChar('}') {
*(*unsafe.Pointer)(p) = mapValue *(*unsafe.Pointer)(p) = mapValue
s.cursor += 2 s.cursor++
return nil return nil
} }
for { for {
s.cursor++
k := unsafe_New(d.keyType) k := unsafe_New(d.keyType)
if err := d.keyDecoder.DecodeStream(s, depth, k); err != nil { if err := d.keyDecoder.DecodeStream(s, depth, k); err != nil {
return err return err
@ -104,6 +117,7 @@ func (d *mapDecoder) DecodeStream(s *Stream, depth int64, p unsafe.Pointer) erro
if !s.equalChar(',') { if !s.equalChar(',') {
return errors.ErrExpected("comma after object value", s.totalOffset()) return errors.ErrExpected("comma after object value", s.totalOffset())
} }
s.cursor++
} }
} }

View File

@ -103,7 +103,7 @@ func (s *Stream) statForRetry() ([]byte, int64, unsafe.Pointer) {
func (s *Stream) Reset() { func (s *Stream) Reset() {
s.reset() s.reset()
s.bufSize = initBufSize s.bufSize = int64(len(s.buf))
} }
func (s *Stream) More() bool { func (s *Stream) More() bool {
@ -423,7 +423,6 @@ func (s *Stream) skipValue(depth int64) error {
continue continue
} else if c == nul { } else if c == nul {
if s.read() { if s.read() {
s.cursor-- // for retry current character
_, cursor, p = s.stat() _, cursor, p = s.stat()
continue continue
} }

View File

@ -1,6 +1,7 @@
package decoder package decoder
import ( import (
"bytes"
"reflect" "reflect"
"unicode" "unicode"
"unicode/utf16" "unicode/utf16"
@ -308,49 +309,30 @@ func (d *stringDecoder) decodeByte(buf []byte, cursor int64) ([]byte, int64, err
cursor++ cursor++
start := cursor start := cursor
b := (*sliceHeader)(unsafe.Pointer(&buf)).data b := (*sliceHeader)(unsafe.Pointer(&buf)).data
escaped := 0
for { for {
switch char(b, cursor) { switch char(b, cursor) {
case '\\': case '\\':
escaped++
cursor++ cursor++
switch char(b, cursor) { switch char(b, cursor) {
case '"': case '"', '\\', '/', 'b', 'f', 'n', 'r', 't':
buf[cursor] = '"' cursor++
buf = append(buf[:cursor-1], buf[cursor:]...)
case '\\':
buf[cursor] = '\\'
buf = append(buf[:cursor-1], buf[cursor:]...)
case '/':
buf[cursor] = '/'
buf = append(buf[:cursor-1], buf[cursor:]...)
case 'b':
buf[cursor] = '\b'
buf = append(buf[:cursor-1], buf[cursor:]...)
case 'f':
buf[cursor] = '\f'
buf = append(buf[:cursor-1], buf[cursor:]...)
case 'n':
buf[cursor] = '\n'
buf = append(buf[:cursor-1], buf[cursor:]...)
case 'r':
buf[cursor] = '\r'
buf = append(buf[:cursor-1], buf[cursor:]...)
case 't':
buf[cursor] = '\t'
buf = append(buf[:cursor-1], buf[cursor:]...)
case 'u': case 'u':
buflen := int64(len(buf)) buflen := int64(len(buf))
if cursor+5 >= buflen { if cursor+5 >= buflen {
return nil, 0, errors.ErrUnexpectedEndOfJSON("escaped string", cursor) return nil, 0, errors.ErrUnexpectedEndOfJSON("escaped string", cursor)
} }
code := unicodeToRune(buf[cursor+1 : cursor+5]) cursor += 5
unicode := []byte(string(code))
buf = append(append(buf[:cursor-1], unicode...), buf[cursor+5:]...)
default: default:
return nil, 0, errors.ErrUnexpectedEndOfJSON("escaped string", cursor) return nil, 0, errors.ErrUnexpectedEndOfJSON("escaped string", cursor)
} }
continue continue
case '"': case '"':
literal := buf[start:cursor] literal := buf[start:cursor]
if escaped > 0 {
literal = literal[:unescapeString(literal)]
}
cursor++ cursor++
return literal, cursor, nil return literal, cursor, nil
case nul: case nul:
@ -369,3 +351,64 @@ func (d *stringDecoder) decodeByte(buf []byte, cursor int64) ([]byte, int64, err
} }
} }
} }
var unescapeMap = [256]byte{
'"': '"',
'\\': '\\',
'/': '/',
'b': '\b',
'f': '\f',
'n': '\n',
'r': '\r',
't': '\t',
}
func unsafeAdd(ptr unsafe.Pointer, offset int) unsafe.Pointer {
return unsafe.Pointer(uintptr(ptr) + uintptr(offset))
}
func unescapeString(buf []byte) int {
p := (*sliceHeader)(unsafe.Pointer(&buf)).data
end := unsafeAdd(p, len(buf))
src := unsafeAdd(p, bytes.IndexByte(buf, '\\'))
dst := src
for src != end {
c := char(src, 0)
if c == '\\' {
escapeChar := char(src, 1)
if escapeChar != 'u' {
*(*byte)(dst) = unescapeMap[escapeChar]
src = unsafeAdd(src, 2)
dst = unsafeAdd(dst, 1)
} else {
v1 := hexToInt[char(src, 2)]
v2 := hexToInt[char(src, 3)]
v3 := hexToInt[char(src, 4)]
v4 := hexToInt[char(src, 5)]
code := rune((v1 << 12) | (v2 << 8) | (v3 << 4) | v4)
var b [utf8.UTFMax]byte
n := utf8.EncodeRune(b[:], code)
switch n {
case 4:
*(*byte)(unsafeAdd(dst, 3)) = b[3]
fallthrough
case 3:
*(*byte)(unsafeAdd(dst, 2)) = b[2]
fallthrough
case 2:
*(*byte)(unsafeAdd(dst, 1)) = b[1]
fallthrough
case 1:
*(*byte)(unsafeAdd(dst, 0)) = b[0]
}
src = unsafeAdd(src, 6)
dst = unsafeAdd(dst, n)
}
} else {
*(*byte)(dst) = c
src = unsafeAdd(src, 1)
dst = unsafeAdd(dst, 1)
}
}
return int(uintptr(dst) - uintptr(p))
}

View File

@ -1,6 +1,7 @@
package decoder package decoder
import ( import (
"context"
"encoding/json" "encoding/json"
"unsafe" "unsafe"
@ -46,13 +47,20 @@ func (d *unmarshalJSONDecoder) DecodeStream(s *Stream, depth int64, p unsafe.Poi
typ: d.typ, typ: d.typ,
ptr: p, ptr: p,
})) }))
if (s.Option.Flags & ContextOption) != 0 { switch v := v.(type) {
if err := v.(unmarshalerContext).UnmarshalJSON(s.Option.Context, dst); err != nil { case unmarshalerContext:
var ctx context.Context
if (s.Option.Flags & ContextOption) != 0 {
ctx = s.Option.Context
} else {
ctx = context.Background()
}
if err := v.UnmarshalJSON(ctx, dst); err != nil {
d.annotateError(s.cursor, err) d.annotateError(s.cursor, err)
return err return err
} }
} else { case json.Unmarshaler:
if err := v.(json.Unmarshaler).UnmarshalJSON(dst); err != nil { if err := v.UnmarshalJSON(dst); err != nil {
d.annotateError(s.cursor, err) d.annotateError(s.cursor, err)
return err return err
} }

1005
vendor/github.com/goccy/go-json/internal/encoder/code.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,56 +1,28 @@
//go:build !race
// +build !race // +build !race
package encoder package encoder
import ( func CompileToGetCodeSet(ctx *RuntimeContext, typeptr uintptr) (*OpcodeSet, error) {
"unsafe" if typeptr > typeAddr.MaxTypeAddr || typeptr < typeAddr.BaseTypeAddr {
"github.com/goccy/go-json/internal/runtime"
)
func CompileToGetCodeSet(typeptr uintptr) (*OpcodeSet, error) {
if typeptr > typeAddr.MaxTypeAddr {
return compileToGetCodeSetSlowPath(typeptr) return compileToGetCodeSetSlowPath(typeptr)
} }
index := (typeptr - typeAddr.BaseTypeAddr) >> typeAddr.AddrShift index := (typeptr - typeAddr.BaseTypeAddr) >> typeAddr.AddrShift
if codeSet := cachedOpcodeSets[index]; codeSet != nil { if codeSet := cachedOpcodeSets[index]; codeSet != nil {
return codeSet, nil filtered, err := getFilteredCodeSetIfNeeded(ctx, codeSet)
if err != nil {
return nil, err
}
return filtered, nil
} }
codeSet, err := newCompiler().compile(typeptr)
// noescape trick for header.typ ( reflect.*rtype )
copiedType := *(**runtime.Type)(unsafe.Pointer(&typeptr))
noescapeKeyCode, err := compileHead(&compileContext{
typ: copiedType,
structTypeToCompiledCode: map[uintptr]*CompiledCode{},
})
if err != nil { if err != nil {
return nil, err return nil, err
} }
escapeKeyCode, err := compileHead(&compileContext{ filtered, err := getFilteredCodeSetIfNeeded(ctx, codeSet)
typ: copiedType,
structTypeToCompiledCode: map[uintptr]*CompiledCode{},
escapeKey: true,
})
if err != nil { if err != nil {
return nil, err return nil, err
} }
noescapeKeyCode = copyOpcode(noescapeKeyCode)
escapeKeyCode = copyOpcode(escapeKeyCode)
setTotalLengthToInterfaceOp(noescapeKeyCode)
setTotalLengthToInterfaceOp(escapeKeyCode)
interfaceNoescapeKeyCode := copyToInterfaceOpcode(noescapeKeyCode)
interfaceEscapeKeyCode := copyToInterfaceOpcode(escapeKeyCode)
codeLength := noescapeKeyCode.TotalLength()
codeSet := &OpcodeSet{
Type: copiedType,
NoescapeKeyCode: noescapeKeyCode,
EscapeKeyCode: escapeKeyCode,
InterfaceNoescapeKeyCode: interfaceNoescapeKeyCode,
InterfaceEscapeKeyCode: interfaceEscapeKeyCode,
CodeLength: codeLength,
EndCode: ToEndCode(interfaceNoescapeKeyCode),
}
cachedOpcodeSets[index] = codeSet cachedOpcodeSets[index] = codeSet
return codeSet, nil return filtered, nil
} }

View File

@ -1,65 +1,41 @@
//go:build race
// +build race // +build race
package encoder package encoder
import ( import (
"sync" "sync"
"unsafe"
"github.com/goccy/go-json/internal/runtime"
) )
var setsMu sync.RWMutex var setsMu sync.RWMutex
func CompileToGetCodeSet(typeptr uintptr) (*OpcodeSet, error) { func CompileToGetCodeSet(ctx *RuntimeContext, typeptr uintptr) (*OpcodeSet, error) {
if typeptr > typeAddr.MaxTypeAddr { if typeptr > typeAddr.MaxTypeAddr || typeptr < typeAddr.BaseTypeAddr {
return compileToGetCodeSetSlowPath(typeptr) return compileToGetCodeSetSlowPath(typeptr)
} }
index := (typeptr - typeAddr.BaseTypeAddr) >> typeAddr.AddrShift index := (typeptr - typeAddr.BaseTypeAddr) >> typeAddr.AddrShift
setsMu.RLock() setsMu.RLock()
if codeSet := cachedOpcodeSets[index]; codeSet != nil { if codeSet := cachedOpcodeSets[index]; codeSet != nil {
filtered, err := getFilteredCodeSetIfNeeded(ctx, codeSet)
if err != nil {
setsMu.RUnlock()
return nil, err
}
setsMu.RUnlock() setsMu.RUnlock()
return codeSet, nil return filtered, nil
} }
setsMu.RUnlock() setsMu.RUnlock()
// noescape trick for header.typ ( reflect.*rtype ) codeSet, err := newCompiler().compile(typeptr)
copiedType := *(**runtime.Type)(unsafe.Pointer(&typeptr))
noescapeKeyCode, err := compileHead(&compileContext{
typ: copiedType,
structTypeToCompiledCode: map[uintptr]*CompiledCode{},
})
if err != nil { if err != nil {
return nil, err return nil, err
} }
escapeKeyCode, err := compileHead(&compileContext{ filtered, err := getFilteredCodeSetIfNeeded(ctx, codeSet)
typ: copiedType,
structTypeToCompiledCode: map[uintptr]*CompiledCode{},
escapeKey: true,
})
if err != nil { if err != nil {
return nil, err return nil, err
} }
noescapeKeyCode = copyOpcode(noescapeKeyCode)
escapeKeyCode = copyOpcode(escapeKeyCode)
setTotalLengthToInterfaceOp(noescapeKeyCode)
setTotalLengthToInterfaceOp(escapeKeyCode)
interfaceNoescapeKeyCode := copyToInterfaceOpcode(noescapeKeyCode)
interfaceEscapeKeyCode := copyToInterfaceOpcode(escapeKeyCode)
codeLength := noescapeKeyCode.TotalLength()
codeSet := &OpcodeSet{
Type: copiedType,
NoescapeKeyCode: noescapeKeyCode,
EscapeKeyCode: escapeKeyCode,
InterfaceNoescapeKeyCode: interfaceNoescapeKeyCode,
InterfaceEscapeKeyCode: interfaceEscapeKeyCode,
CodeLength: codeLength,
EndCode: ToEndCode(interfaceNoescapeKeyCode),
}
setsMu.Lock() setsMu.Lock()
cachedOpcodeSets[index] = codeSet cachedOpcodeSets[index] = codeSet
setsMu.Unlock() setsMu.Unlock()
return codeSet, nil return filtered, nil
} }

View File

@ -9,44 +9,20 @@ import (
) )
type compileContext struct { type compileContext struct {
typ *runtime.Type opcodeIndex uint32
opcodeIndex uint32 ptrIndex int
ptrIndex int indent uint32
indent uint32 escapeKey bool
escapeKey bool structTypeToCodes map[uintptr]Opcodes
structTypeToCompiledCode map[uintptr]*CompiledCode recursiveCodes *Opcodes
parent *compileContext
} }
func (c *compileContext) context() *compileContext { func (c *compileContext) incIndent() {
return &compileContext{ c.indent++
typ: c.typ,
opcodeIndex: c.opcodeIndex,
ptrIndex: c.ptrIndex,
indent: c.indent,
escapeKey: c.escapeKey,
structTypeToCompiledCode: c.structTypeToCompiledCode,
parent: c,
}
} }
func (c *compileContext) withType(typ *runtime.Type) *compileContext { func (c *compileContext) decIndent() {
ctx := c.context() c.indent--
ctx.typ = typ
return ctx
}
func (c *compileContext) incIndent() *compileContext {
ctx := c.context()
ctx.indent++
return ctx
}
func (c *compileContext) decIndent() *compileContext {
ctx := c.context()
ctx.indent--
return ctx
} }
func (c *compileContext) incIndex() { func (c *compileContext) incIndex() {
@ -61,30 +37,18 @@ func (c *compileContext) decIndex() {
func (c *compileContext) incOpcodeIndex() { func (c *compileContext) incOpcodeIndex() {
c.opcodeIndex++ c.opcodeIndex++
if c.parent != nil {
c.parent.incOpcodeIndex()
}
} }
func (c *compileContext) decOpcodeIndex() { func (c *compileContext) decOpcodeIndex() {
c.opcodeIndex-- c.opcodeIndex--
if c.parent != nil {
c.parent.decOpcodeIndex()
}
} }
func (c *compileContext) incPtrIndex() { func (c *compileContext) incPtrIndex() {
c.ptrIndex++ c.ptrIndex++
if c.parent != nil {
c.parent.incPtrIndex()
}
} }
func (c *compileContext) decPtrIndex() { func (c *compileContext) decPtrIndex() {
c.ptrIndex-- c.ptrIndex--
if c.parent != nil {
c.parent.decPtrIndex()
}
} }
const ( const (

View File

@ -0,0 +1,126 @@
package encoder
import "unicode/utf8"
const (
// The default lowest and highest continuation byte.
locb = 128 //0b10000000
hicb = 191 //0b10111111
// These names of these constants are chosen to give nice alignment in the
// table below. The first nibble is an index into acceptRanges or F for
// special one-byte cases. The second nibble is the Rune length or the
// Status for the special one-byte case.
xx = 0xF1 // invalid: size 1
as = 0xF0 // ASCII: size 1
s1 = 0x02 // accept 0, size 2
s2 = 0x13 // accept 1, size 3
s3 = 0x03 // accept 0, size 3
s4 = 0x23 // accept 2, size 3
s5 = 0x34 // accept 3, size 4
s6 = 0x04 // accept 0, size 4
s7 = 0x44 // accept 4, size 4
)
// first is information about the first byte in a UTF-8 sequence.
var first = [256]uint8{
// 1 2 3 4 5 6 7 8 9 A B C D E F
as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, // 0x00-0x0F
as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, // 0x10-0x1F
as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, // 0x20-0x2F
as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, // 0x30-0x3F
as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, // 0x40-0x4F
as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, // 0x50-0x5F
as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, // 0x60-0x6F
as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, // 0x70-0x7F
// 1 2 3 4 5 6 7 8 9 A B C D E F
xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, // 0x80-0x8F
xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, // 0x90-0x9F
xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, // 0xA0-0xAF
xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, // 0xB0-0xBF
xx, xx, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, // 0xC0-0xCF
s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, // 0xD0-0xDF
s2, s3, s3, s3, s3, s3, s3, s3, s3, s3, s3, s3, s3, s4, s3, s3, // 0xE0-0xEF
s5, s6, s6, s6, s7, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, // 0xF0-0xFF
}
const (
lineSep = byte(168) //'\u2028'
paragraphSep = byte(169) //'\u2029'
)
type decodeRuneState int
const (
validUTF8State decodeRuneState = iota
runeErrorState
lineSepState
paragraphSepState
)
func decodeRuneInString(s string) (decodeRuneState, int) {
n := len(s)
s0 := s[0]
x := first[s0]
if x >= as {
// The following code simulates an additional check for x == xx and
// handling the ASCII and invalid cases accordingly. This mask-and-or
// approach prevents an additional branch.
mask := rune(x) << 31 >> 31 // Create 0x0000 or 0xFFFF.
if rune(s[0])&^mask|utf8.RuneError&mask == utf8.RuneError {
return runeErrorState, 1
}
return validUTF8State, 1
}
sz := int(x & 7)
if n < sz {
return runeErrorState, 1
}
s1 := s[1]
switch x >> 4 {
case 0:
if s1 < locb || hicb < s1 {
return runeErrorState, 1
}
case 1:
if s1 < 0xA0 || hicb < s1 {
return runeErrorState, 1
}
case 2:
if s1 < locb || 0x9F < s1 {
return runeErrorState, 1
}
case 3:
if s1 < 0x90 || hicb < s1 {
return runeErrorState, 1
}
case 4:
if s1 < locb || 0x8F < s1 {
return runeErrorState, 1
}
}
if sz <= 2 {
return validUTF8State, 2
}
s2 := s[2]
if s2 < locb || hicb < s2 {
return runeErrorState, 1
}
if sz <= 3 {
// separator character prefixes: [2]byte{226, 128}
if s0 == 226 && s1 == 128 {
switch s2 {
case lineSep:
return lineSepState, 3
case paragraphSep:
return paragraphSepState, 3
}
}
return validUTF8State, 3
}
s3 := s[3]
if s3 < locb || hicb < s3 {
return runeErrorState, 1
}
return validUTF8State, 4
}

View File

@ -101,6 +101,22 @@ type OpcodeSet struct {
InterfaceEscapeKeyCode *Opcode InterfaceEscapeKeyCode *Opcode
CodeLength int CodeLength int
EndCode *Opcode EndCode *Opcode
Code Code
QueryCache map[string]*OpcodeSet
cacheMu sync.RWMutex
}
func (s *OpcodeSet) getQueryCache(hash string) *OpcodeSet {
s.cacheMu.RLock()
codeSet := s.QueryCache[hash]
s.cacheMu.RUnlock()
return codeSet
}
func (s *OpcodeSet) setQueryCache(hash string, codeSet *OpcodeSet) {
s.cacheMu.Lock()
s.QueryCache[hash] = codeSet
s.cacheMu.Unlock()
} }
type CompiledCode struct { type CompiledCode struct {
@ -222,33 +238,56 @@ func (m *Mapslice) Swap(i, j int) {
m.Items[i], m.Items[j] = m.Items[j], m.Items[i] m.Items[i], m.Items[j] = m.Items[j], m.Items[i]
} }
//nolint:structcheck,unused
type mapIter struct {
key unsafe.Pointer
elem unsafe.Pointer
t unsafe.Pointer
h unsafe.Pointer
buckets unsafe.Pointer
bptr unsafe.Pointer
overflow unsafe.Pointer
oldoverflow unsafe.Pointer
startBucket uintptr
offset uint8
wrapped bool
B uint8
i uint8
bucket uintptr
checkBucket uintptr
}
type MapContext struct { type MapContext struct {
Pos []int Start int
First int
Idx int
Slice *Mapslice Slice *Mapslice
Buf []byte Buf []byte
Len int
Iter mapIter
} }
var mapContextPool = sync.Pool{ var mapContextPool = sync.Pool{
New: func() interface{} { New: func() interface{} {
return &MapContext{} return &MapContext{
Slice: &Mapslice{},
}
}, },
} }
func NewMapContext(mapLen int) *MapContext { func NewMapContext(mapLen int, unorderedMap bool) *MapContext {
ctx := mapContextPool.Get().(*MapContext) ctx := mapContextPool.Get().(*MapContext)
if ctx.Slice == nil { if !unorderedMap {
ctx.Slice = &Mapslice{ if len(ctx.Slice.Items) < mapLen {
Items: make([]MapItem, 0, mapLen), ctx.Slice.Items = make([]MapItem, mapLen)
} else {
ctx.Slice.Items = ctx.Slice.Items[:mapLen]
} }
} }
if cap(ctx.Pos) < (mapLen*2 + 1) {
ctx.Pos = make([]int, 0, mapLen*2+1)
ctx.Slice.Items = make([]MapItem, 0, mapLen)
} else {
ctx.Pos = ctx.Pos[:0]
ctx.Slice.Items = ctx.Slice.Items[:0]
}
ctx.Buf = ctx.Buf[:0] ctx.Buf = ctx.Buf[:0]
ctx.Iter = mapIter{}
ctx.Idx = 0
ctx.Len = mapLen
return ctx return ctx
} }
@ -256,17 +295,17 @@ func ReleaseMapContext(c *MapContext) {
mapContextPool.Put(c) mapContextPool.Put(c)
} }
//go:linkname MapIterInit reflect.mapiterinit //go:linkname MapIterInit runtime.mapiterinit
//go:noescape //go:noescape
func MapIterInit(mapType *runtime.Type, m unsafe.Pointer) unsafe.Pointer func MapIterInit(mapType *runtime.Type, m unsafe.Pointer, it *mapIter)
//go:linkname MapIterKey reflect.mapiterkey //go:linkname MapIterKey reflect.mapiterkey
//go:noescape //go:noescape
func MapIterKey(it unsafe.Pointer) unsafe.Pointer func MapIterKey(it *mapIter) unsafe.Pointer
//go:linkname MapIterNext reflect.mapiternext //go:linkname MapIterNext reflect.mapiternext
//go:noescape //go:noescape
func MapIterNext(it unsafe.Pointer) func MapIterNext(it *mapIter)
//go:linkname MapLen reflect.maplen //go:linkname MapLen reflect.maplen
//go:noescape //go:noescape
@ -374,7 +413,11 @@ func AppendMarshalJSON(ctx *RuntimeContext, code *Opcode, b []byte, v interface{
if !ok { if !ok {
return AppendNull(ctx, b), nil return AppendNull(ctx, b), nil
} }
b, err := marshaler.MarshalJSON(ctx.Option.Context) stdctx := ctx.Option.Context
if ctx.Option.Flag&FieldQueryOption != 0 {
stdctx = SetFieldQueryToContext(stdctx, code.FieldQuery)
}
b, err := marshaler.MarshalJSON(stdctx)
if err != nil { if err != nil {
return nil, &errors.MarshalerError{Type: reflect.TypeOf(v), Err: err} return nil, &errors.MarshalerError{Type: reflect.TypeOf(v), Err: err}
} }
@ -546,6 +589,8 @@ func IsNilForMarshaler(v interface{}) bool {
return rv.IsNil() return rv.IsNil()
case reflect.Slice: case reflect.Slice:
return rv.IsNil() || rv.Len() == 0 return rv.IsNil() || rv.Len() == 0
case reflect.String:
return rv.Len() == 0
} }
return false return false
} }

View File

@ -53,7 +53,18 @@ func numMask(numBitSize uint8) uint64 {
return 1<<numBitSize - 1 return 1<<numBitSize - 1
} }
func AppendInt(_ *RuntimeContext, out []byte, u64 uint64, code *Opcode) []byte { func AppendInt(_ *RuntimeContext, out []byte, p uintptr, code *Opcode) []byte {
var u64 uint64
switch code.NumBitSize {
case 8:
u64 = (uint64)(**(**uint8)(unsafe.Pointer(&p)))
case 16:
u64 = (uint64)(**(**uint16)(unsafe.Pointer(&p)))
case 32:
u64 = (uint64)(**(**uint32)(unsafe.Pointer(&p)))
case 64:
u64 = **(**uint64)(unsafe.Pointer(&p))
}
mask := numMask(code.NumBitSize) mask := numMask(code.NumBitSize)
n := u64 & mask n := u64 & mask
negative := (u64>>(code.NumBitSize-1))&1 == 1 negative := (u64>>(code.NumBitSize-1))&1 == 1
@ -96,7 +107,18 @@ func AppendInt(_ *RuntimeContext, out []byte, u64 uint64, code *Opcode) []byte {
return append(out, b[i:]...) return append(out, b[i:]...)
} }
func AppendUint(_ *RuntimeContext, out []byte, u64 uint64, code *Opcode) []byte { func AppendUint(_ *RuntimeContext, out []byte, p uintptr, code *Opcode) []byte {
var u64 uint64
switch code.NumBitSize {
case 8:
u64 = (uint64)(**(**uint8)(unsafe.Pointer(&p)))
case 16:
u64 = (uint64)(**(**uint16)(unsafe.Pointer(&p)))
case 32:
u64 = (uint64)(**(**uint32)(unsafe.Pointer(&p)))
case 64:
u64 = **(**uint64)(unsafe.Pointer(&p))
}
mask := numMask(code.NumBitSize) mask := numMask(code.NumBitSize)
n := u64 & mask n := u64 & mask
if n < 10 { if n < 10 {

View File

@ -1,3 +1,4 @@
//go:build !go1.13
// +build !go1.13 // +build !go1.13
package encoder package encoder
@ -5,4 +6,4 @@ package encoder
import "unsafe" import "unsafe"
//go:linkname MapIterValue reflect.mapitervalue //go:linkname MapIterValue reflect.mapitervalue
func MapIterValue(it unsafe.Pointer) unsafe.Pointer func MapIterValue(it *mapIter) unsafe.Pointer

View File

@ -1,3 +1,4 @@
//go:build go1.13
// +build go1.13 // +build go1.13
package encoder package encoder
@ -5,4 +6,4 @@ package encoder
import "unsafe" import "unsafe"
//go:linkname MapIterValue reflect.mapiterelem //go:linkname MapIterValue reflect.mapiterelem
func MapIterValue(it unsafe.Pointer) unsafe.Pointer func MapIterValue(it *mapIter) unsafe.Pointer

View File

@ -13,15 +13,16 @@ const uintptrSize = 4 << (^uintptr(0) >> 63)
type OpFlags uint16 type OpFlags uint16
const ( const (
AnonymousHeadFlags OpFlags = 1 << 0 AnonymousHeadFlags OpFlags = 1 << 0
AnonymousKeyFlags OpFlags = 1 << 1 AnonymousKeyFlags OpFlags = 1 << 1
IndirectFlags OpFlags = 1 << 2 IndirectFlags OpFlags = 1 << 2
IsTaggedKeyFlags OpFlags = 1 << 3 IsTaggedKeyFlags OpFlags = 1 << 3
NilCheckFlags OpFlags = 1 << 4 NilCheckFlags OpFlags = 1 << 4
AddrForMarshalerFlags OpFlags = 1 << 5 AddrForMarshalerFlags OpFlags = 1 << 5
IsNextOpPtrTypeFlags OpFlags = 1 << 6 IsNextOpPtrTypeFlags OpFlags = 1 << 6
IsNilableTypeFlags OpFlags = 1 << 7 IsNilableTypeFlags OpFlags = 1 << 7
MarshalerContextFlags OpFlags = 1 << 8 MarshalerContextFlags OpFlags = 1 << 8
NonEmptyInterfaceFlags OpFlags = 1 << 9
) )
type Opcode struct { type Opcode struct {
@ -37,26 +38,58 @@ type Opcode struct {
Flags OpFlags Flags OpFlags
Type *runtime.Type // go type Type *runtime.Type // go type
PrevField *Opcode // prev struct field
Jmp *CompiledCode // for recursive call Jmp *CompiledCode // for recursive call
ElemIdx uint32 // offset to access array/slice/map elem FieldQuery *FieldQuery // field query for Interface / MarshalJSON / MarshalText
Length uint32 // offset to access slice/map length or array length ElemIdx uint32 // offset to access array/slice elem
MapIter uint32 // offset to access map iterator Length uint32 // offset to access slice length or array length
MapPos uint32 // offset to access position list for sorted map
Indent uint32 // indent number Indent uint32 // indent number
Size uint32 // array/slice elem size Size uint32 // array/slice elem size
DisplayIdx uint32 // opcode index DisplayIdx uint32 // opcode index
DisplayKey string // key text to display DisplayKey string // key text to display
} }
func (c *Opcode) Validate() error {
var prevIdx uint32
for code := c; !code.IsEnd(); {
if prevIdx != 0 {
if code.DisplayIdx != prevIdx+1 {
return fmt.Errorf(
"invalid index. previous display index is %d but next is %d. dump = %s",
prevIdx, code.DisplayIdx, c.Dump(),
)
}
}
prevIdx = code.DisplayIdx
code = code.IterNext()
}
return nil
}
func (c *Opcode) IterNext() *Opcode {
if c == nil {
return nil
}
switch c.Op.CodeType() {
case CodeArrayElem, CodeSliceElem, CodeMapKey:
return c.End
default:
return c.Next
}
}
func (c *Opcode) IsEnd() bool {
if c == nil {
return true
}
return c.Op == OpEnd || c.Op == OpInterfaceEnd || c.Op == OpRecursiveEnd
}
func (c *Opcode) MaxIdx() uint32 { func (c *Opcode) MaxIdx() uint32 {
max := uint32(0) max := uint32(0)
for _, value := range []uint32{ for _, value := range []uint32{
c.Idx, c.Idx,
c.ElemIdx, c.ElemIdx,
c.Length, c.Length,
c.MapIter,
c.MapPos,
c.Size, c.Size,
} { } {
if max < value { if max < value {
@ -272,43 +305,75 @@ func (c *Opcode) ToFieldType(isString bool) OpType {
return OpStructField return OpStructField
} }
func newOpCode(ctx *compileContext, op OpType) *Opcode { func newOpCode(ctx *compileContext, typ *runtime.Type, op OpType) *Opcode {
return newOpCodeWithNext(ctx, op, newEndOp(ctx)) return newOpCodeWithNext(ctx, typ, op, newEndOp(ctx, typ))
} }
func opcodeOffset(idx int) uint32 { func opcodeOffset(idx int) uint32 {
return uint32(idx) * uintptrSize return uint32(idx) * uintptrSize
} }
func getCodeAddrByIdx(head *Opcode, idx uint32) *Opcode {
addr := uintptr(unsafe.Pointer(head)) + uintptr(idx)*unsafe.Sizeof(Opcode{})
return *(**Opcode)(unsafe.Pointer(&addr))
}
func copyOpcode(code *Opcode) *Opcode { func copyOpcode(code *Opcode) *Opcode {
codeMap := map[uintptr]*Opcode{} codeNum := ToEndCode(code).DisplayIdx + 1
return code.copy(codeMap) codeSlice := make([]Opcode, codeNum)
head := (*Opcode)((*runtime.SliceHeader)(unsafe.Pointer(&codeSlice)).Data)
ptr := head
c := code
for {
*ptr = Opcode{
Op: c.Op,
Key: c.Key,
PtrNum: c.PtrNum,
NumBitSize: c.NumBitSize,
Flags: c.Flags,
Idx: c.Idx,
Offset: c.Offset,
Type: c.Type,
FieldQuery: c.FieldQuery,
DisplayIdx: c.DisplayIdx,
DisplayKey: c.DisplayKey,
ElemIdx: c.ElemIdx,
Length: c.Length,
Size: c.Size,
Indent: c.Indent,
Jmp: c.Jmp,
}
if c.End != nil {
ptr.End = getCodeAddrByIdx(head, c.End.DisplayIdx)
}
if c.NextField != nil {
ptr.NextField = getCodeAddrByIdx(head, c.NextField.DisplayIdx)
}
if c.Next != nil {
ptr.Next = getCodeAddrByIdx(head, c.Next.DisplayIdx)
}
if c.IsEnd() {
break
}
ptr = getCodeAddrByIdx(head, c.DisplayIdx+1)
c = c.IterNext()
}
return head
} }
func setTotalLengthToInterfaceOp(code *Opcode) { func setTotalLengthToInterfaceOp(code *Opcode) {
c := code for c := code; !c.IsEnd(); {
for c.Op != OpEnd && c.Op != OpInterfaceEnd {
if c.Op == OpInterface { if c.Op == OpInterface {
c.Length = uint32(code.TotalLength()) c.Length = uint32(code.TotalLength())
} }
switch c.Op.CodeType() { c = c.IterNext()
case CodeArrayElem, CodeSliceElem, CodeMapKey:
c = c.End
default:
c = c.Next
}
} }
} }
func ToEndCode(code *Opcode) *Opcode { func ToEndCode(code *Opcode) *Opcode {
c := code c := code
for c.Op != OpEnd && c.Op != OpInterfaceEnd { for !c.IsEnd() {
switch c.Op.CodeType() { c = c.IterNext()
case CodeArrayElem, CodeSliceElem, CodeMapKey:
c = c.End
default:
c = c.Next
}
} }
return c return c
} }
@ -324,77 +389,25 @@ func copyToInterfaceOpcode(code *Opcode) *Opcode {
return copied return copied
} }
func newOpCodeWithNext(ctx *compileContext, op OpType, next *Opcode) *Opcode { func newOpCodeWithNext(ctx *compileContext, typ *runtime.Type, op OpType, next *Opcode) *Opcode {
return &Opcode{ return &Opcode{
Op: op, Op: op,
Idx: opcodeOffset(ctx.ptrIndex), Idx: opcodeOffset(ctx.ptrIndex),
Next: next, Next: next,
Type: ctx.typ, Type: typ,
DisplayIdx: ctx.opcodeIndex, DisplayIdx: ctx.opcodeIndex,
Indent: ctx.indent, Indent: ctx.indent,
} }
} }
func newEndOp(ctx *compileContext) *Opcode { func newEndOp(ctx *compileContext, typ *runtime.Type) *Opcode {
return newOpCodeWithNext(ctx, OpEnd, nil) return newOpCodeWithNext(ctx, typ, OpEnd, nil)
}
func (c *Opcode) copy(codeMap map[uintptr]*Opcode) *Opcode {
if c == nil {
return nil
}
addr := uintptr(unsafe.Pointer(c))
if code, exists := codeMap[addr]; exists {
return code
}
copied := &Opcode{
Op: c.Op,
Key: c.Key,
PtrNum: c.PtrNum,
NumBitSize: c.NumBitSize,
Flags: c.Flags,
Idx: c.Idx,
Offset: c.Offset,
Type: c.Type,
DisplayIdx: c.DisplayIdx,
DisplayKey: c.DisplayKey,
ElemIdx: c.ElemIdx,
Length: c.Length,
MapIter: c.MapIter,
MapPos: c.MapPos,
Size: c.Size,
Indent: c.Indent,
}
codeMap[addr] = copied
copied.End = c.End.copy(codeMap)
copied.PrevField = c.PrevField.copy(codeMap)
copied.NextField = c.NextField.copy(codeMap)
copied.Next = c.Next.copy(codeMap)
copied.Jmp = c.Jmp
return copied
}
func (c *Opcode) BeforeLastCode() *Opcode {
code := c
for {
var nextCode *Opcode
switch code.Op.CodeType() {
case CodeArrayElem, CodeSliceElem, CodeMapKey:
nextCode = code.End
default:
nextCode = code.Next
}
if nextCode.Op == OpEnd {
return code
}
code = nextCode
}
} }
func (c *Opcode) TotalLength() int { func (c *Opcode) TotalLength() int {
var idx int var idx int
code := c code := c
for code.Op != OpEnd && code.Op != OpInterfaceEnd { for !code.IsEnd() {
maxIdx := int(code.MaxIdx() / uintptrSize) maxIdx := int(code.MaxIdx() / uintptrSize)
if idx < maxIdx { if idx < maxIdx {
idx = maxIdx idx = maxIdx
@ -402,12 +415,7 @@ func (c *Opcode) TotalLength() int {
if code.Op == OpRecursiveEnd { if code.Op == OpRecursiveEnd {
break break
} }
switch code.Op.CodeType() { code = code.IterNext()
case CodeArrayElem, CodeSliceElem, CodeMapKey:
code = code.End
default:
code = code.Next
}
} }
maxIdx := int(code.MaxIdx() / uintptrSize) maxIdx := int(code.MaxIdx() / uintptrSize)
if idx < maxIdx { if idx < maxIdx {
@ -416,42 +424,6 @@ func (c *Opcode) TotalLength() int {
return idx + 1 return idx + 1
} }
func (c *Opcode) decOpcodeIndex() {
for code := c; code.Op != OpEnd; {
code.DisplayIdx--
if code.Idx > 0 {
code.Idx -= uintptrSize
}
if code.ElemIdx > 0 {
code.ElemIdx -= uintptrSize
}
if code.MapIter > 0 {
code.MapIter -= uintptrSize
}
if code.Length > 0 && code.Op.CodeType() != CodeArrayHead && code.Op.CodeType() != CodeArrayElem {
code.Length -= uintptrSize
}
switch code.Op.CodeType() {
case CodeArrayElem, CodeSliceElem, CodeMapKey:
code = code.End
default:
code = code.Next
}
}
}
func (c *Opcode) decIndent() {
for code := c; code.Op != OpEnd; {
code.Indent--
switch code.Op.CodeType() {
case CodeArrayElem, CodeSliceElem, CodeMapKey:
code = code.End
default:
code = code.Next
}
}
}
func (c *Opcode) dumpHead(code *Opcode) string { func (c *Opcode) dumpHead(code *Opcode) string {
var length uint32 var length uint32
if code.Op.CodeType() == CodeArrayHead { if code.Op.CodeType() == CodeArrayHead {
@ -460,7 +432,7 @@ func (c *Opcode) dumpHead(code *Opcode) string {
length = code.Length / uintptrSize length = code.Length / uintptrSize
} }
return fmt.Sprintf( return fmt.Sprintf(
`[%d]%s%s ([idx:%d][elemIdx:%d][length:%d])`, `[%03d]%s%s ([idx:%d][elemIdx:%d][length:%d])`,
code.DisplayIdx, code.DisplayIdx,
strings.Repeat("-", int(code.Indent)), strings.Repeat("-", int(code.Indent)),
code.Op, code.Op,
@ -472,26 +444,21 @@ func (c *Opcode) dumpHead(code *Opcode) string {
func (c *Opcode) dumpMapHead(code *Opcode) string { func (c *Opcode) dumpMapHead(code *Opcode) string {
return fmt.Sprintf( return fmt.Sprintf(
`[%d]%s%s ([idx:%d][elemIdx:%d][length:%d][mapIter:%d])`, `[%03d]%s%s ([idx:%d])`,
code.DisplayIdx, code.DisplayIdx,
strings.Repeat("-", int(code.Indent)), strings.Repeat("-", int(code.Indent)),
code.Op, code.Op,
code.Idx/uintptrSize, code.Idx/uintptrSize,
code.ElemIdx/uintptrSize,
code.Length/uintptrSize,
code.MapIter/uintptrSize,
) )
} }
func (c *Opcode) dumpMapEnd(code *Opcode) string { func (c *Opcode) dumpMapEnd(code *Opcode) string {
return fmt.Sprintf( return fmt.Sprintf(
`[%d]%s%s ([idx:%d][mapPos:%d][length:%d])`, `[%03d]%s%s ([idx:%d])`,
code.DisplayIdx, code.DisplayIdx,
strings.Repeat("-", int(code.Indent)), strings.Repeat("-", int(code.Indent)),
code.Op, code.Op,
code.Idx/uintptrSize, code.Idx/uintptrSize,
code.MapPos/uintptrSize,
code.Length/uintptrSize,
) )
} }
@ -503,7 +470,7 @@ func (c *Opcode) dumpElem(code *Opcode) string {
length = code.Length / uintptrSize length = code.Length / uintptrSize
} }
return fmt.Sprintf( return fmt.Sprintf(
`[%d]%s%s ([idx:%d][elemIdx:%d][length:%d][size:%d])`, `[%03d]%s%s ([idx:%d][elemIdx:%d][length:%d][size:%d])`,
code.DisplayIdx, code.DisplayIdx,
strings.Repeat("-", int(code.Indent)), strings.Repeat("-", int(code.Indent)),
code.Op, code.Op,
@ -516,7 +483,7 @@ func (c *Opcode) dumpElem(code *Opcode) string {
func (c *Opcode) dumpField(code *Opcode) string { func (c *Opcode) dumpField(code *Opcode) string {
return fmt.Sprintf( return fmt.Sprintf(
`[%d]%s%s ([idx:%d][key:%s][offset:%d])`, `[%03d]%s%s ([idx:%d][key:%s][offset:%d])`,
code.DisplayIdx, code.DisplayIdx,
strings.Repeat("-", int(code.Indent)), strings.Repeat("-", int(code.Indent)),
code.Op, code.Op,
@ -528,31 +495,27 @@ func (c *Opcode) dumpField(code *Opcode) string {
func (c *Opcode) dumpKey(code *Opcode) string { func (c *Opcode) dumpKey(code *Opcode) string {
return fmt.Sprintf( return fmt.Sprintf(
`[%d]%s%s ([idx:%d][elemIdx:%d][length:%d][mapIter:%d])`, `[%03d]%s%s ([idx:%d])`,
code.DisplayIdx, code.DisplayIdx,
strings.Repeat("-", int(code.Indent)), strings.Repeat("-", int(code.Indent)),
code.Op, code.Op,
code.Idx/uintptrSize, code.Idx/uintptrSize,
code.ElemIdx/uintptrSize,
code.Length/uintptrSize,
code.MapIter/uintptrSize,
) )
} }
func (c *Opcode) dumpValue(code *Opcode) string { func (c *Opcode) dumpValue(code *Opcode) string {
return fmt.Sprintf( return fmt.Sprintf(
`[%d]%s%s ([idx:%d][mapIter:%d])`, `[%03d]%s%s ([idx:%d])`,
code.DisplayIdx, code.DisplayIdx,
strings.Repeat("-", int(code.Indent)), strings.Repeat("-", int(code.Indent)),
code.Op, code.Op,
code.Idx/uintptrSize, code.Idx/uintptrSize,
code.MapIter/uintptrSize,
) )
} }
func (c *Opcode) Dump() string { func (c *Opcode) Dump() string {
codes := []string{} codes := []string{}
for code := c; code.Op != OpEnd && code.Op != OpInterfaceEnd; { for code := c; !code.IsEnd(); {
switch code.Op.CodeType() { switch code.Op.CodeType() {
case CodeSliceHead: case CodeSliceHead:
codes = append(codes, c.dumpHead(code)) codes = append(codes, c.dumpHead(code))
@ -580,7 +543,7 @@ func (c *Opcode) Dump() string {
code = code.Next code = code.Next
default: default:
codes = append(codes, fmt.Sprintf( codes = append(codes, fmt.Sprintf(
"[%d]%s%s ([idx:%d])", "[%03d]%s%s ([idx:%d])",
code.DisplayIdx, code.DisplayIdx,
strings.Repeat("-", int(code.Indent)), strings.Repeat("-", int(code.Indent)),
code.Op, code.Op,
@ -592,44 +555,7 @@ func (c *Opcode) Dump() string {
return strings.Join(codes, "\n") return strings.Join(codes, "\n")
} }
func prevField(code *Opcode, removedFields map[*Opcode]struct{}) *Opcode { func newSliceHeaderCode(ctx *compileContext, typ *runtime.Type) *Opcode {
if _, exists := removedFields[code]; exists {
return prevField(code.PrevField, removedFields)
}
return code
}
func nextField(code *Opcode, removedFields map[*Opcode]struct{}) *Opcode {
if _, exists := removedFields[code]; exists {
return nextField(code.NextField, removedFields)
}
return code
}
func linkPrevToNextField(cur *Opcode, removedFields map[*Opcode]struct{}) {
prev := prevField(cur.PrevField, removedFields)
prev.NextField = nextField(cur.NextField, removedFields)
code := prev
fcode := cur
for {
var nextCode *Opcode
switch code.Op.CodeType() {
case CodeArrayElem, CodeSliceElem, CodeMapKey:
nextCode = code.End
default:
nextCode = code.Next
}
if nextCode == fcode {
code.Next = fcode.Next
break
} else if nextCode.Op == OpEnd {
break
}
code = nextCode
}
}
func newSliceHeaderCode(ctx *compileContext) *Opcode {
idx := opcodeOffset(ctx.ptrIndex) idx := opcodeOffset(ctx.ptrIndex)
ctx.incPtrIndex() ctx.incPtrIndex()
elemIdx := opcodeOffset(ctx.ptrIndex) elemIdx := opcodeOffset(ctx.ptrIndex)
@ -637,6 +563,7 @@ func newSliceHeaderCode(ctx *compileContext) *Opcode {
length := opcodeOffset(ctx.ptrIndex) length := opcodeOffset(ctx.ptrIndex)
return &Opcode{ return &Opcode{
Op: OpSlice, Op: OpSlice,
Type: typ,
Idx: idx, Idx: idx,
DisplayIdx: ctx.opcodeIndex, DisplayIdx: ctx.opcodeIndex,
ElemIdx: elemIdx, ElemIdx: elemIdx,
@ -645,9 +572,10 @@ func newSliceHeaderCode(ctx *compileContext) *Opcode {
} }
} }
func newSliceElemCode(ctx *compileContext, head *Opcode, size uintptr) *Opcode { func newSliceElemCode(ctx *compileContext, typ *runtime.Type, head *Opcode, size uintptr) *Opcode {
return &Opcode{ return &Opcode{
Op: OpSliceElem, Op: OpSliceElem,
Type: typ,
Idx: head.Idx, Idx: head.Idx,
DisplayIdx: ctx.opcodeIndex, DisplayIdx: ctx.opcodeIndex,
ElemIdx: head.ElemIdx, ElemIdx: head.ElemIdx,
@ -657,12 +585,13 @@ func newSliceElemCode(ctx *compileContext, head *Opcode, size uintptr) *Opcode {
} }
} }
func newArrayHeaderCode(ctx *compileContext, alen int) *Opcode { func newArrayHeaderCode(ctx *compileContext, typ *runtime.Type, alen int) *Opcode {
idx := opcodeOffset(ctx.ptrIndex) idx := opcodeOffset(ctx.ptrIndex)
ctx.incPtrIndex() ctx.incPtrIndex()
elemIdx := opcodeOffset(ctx.ptrIndex) elemIdx := opcodeOffset(ctx.ptrIndex)
return &Opcode{ return &Opcode{
Op: OpArray, Op: OpArray,
Type: typ,
Idx: idx, Idx: idx,
DisplayIdx: ctx.opcodeIndex, DisplayIdx: ctx.opcodeIndex,
ElemIdx: elemIdx, ElemIdx: elemIdx,
@ -671,9 +600,10 @@ func newArrayHeaderCode(ctx *compileContext, alen int) *Opcode {
} }
} }
func newArrayElemCode(ctx *compileContext, head *Opcode, length int, size uintptr) *Opcode { func newArrayElemCode(ctx *compileContext, typ *runtime.Type, head *Opcode, length int, size uintptr) *Opcode {
return &Opcode{ return &Opcode{
Op: OpArrayElem, Op: OpArrayElem,
Type: typ,
Idx: head.Idx, Idx: head.Idx,
DisplayIdx: ctx.opcodeIndex, DisplayIdx: ctx.opcodeIndex,
ElemIdx: head.ElemIdx, ElemIdx: head.ElemIdx,
@ -683,82 +613,55 @@ func newArrayElemCode(ctx *compileContext, head *Opcode, length int, size uintpt
} }
} }
func newMapHeaderCode(ctx *compileContext) *Opcode { func newMapHeaderCode(ctx *compileContext, typ *runtime.Type) *Opcode {
idx := opcodeOffset(ctx.ptrIndex) idx := opcodeOffset(ctx.ptrIndex)
ctx.incPtrIndex() ctx.incPtrIndex()
elemIdx := opcodeOffset(ctx.ptrIndex)
ctx.incPtrIndex()
length := opcodeOffset(ctx.ptrIndex)
ctx.incPtrIndex()
mapIter := opcodeOffset(ctx.ptrIndex)
return &Opcode{ return &Opcode{
Op: OpMap, Op: OpMap,
Type: typ,
Idx: idx, Idx: idx,
Type: ctx.typ,
DisplayIdx: ctx.opcodeIndex, DisplayIdx: ctx.opcodeIndex,
ElemIdx: elemIdx,
Length: length,
MapIter: mapIter,
Indent: ctx.indent, Indent: ctx.indent,
} }
} }
func newMapKeyCode(ctx *compileContext, head *Opcode) *Opcode { func newMapKeyCode(ctx *compileContext, typ *runtime.Type, head *Opcode) *Opcode {
return &Opcode{ return &Opcode{
Op: OpMapKey, Op: OpMapKey,
Idx: opcodeOffset(ctx.ptrIndex), Type: typ,
Idx: head.Idx,
DisplayIdx: ctx.opcodeIndex, DisplayIdx: ctx.opcodeIndex,
ElemIdx: head.ElemIdx,
Length: head.Length,
MapIter: head.MapIter,
Indent: ctx.indent, Indent: ctx.indent,
} }
} }
func newMapValueCode(ctx *compileContext, head *Opcode) *Opcode { func newMapValueCode(ctx *compileContext, typ *runtime.Type, head *Opcode) *Opcode {
return &Opcode{ return &Opcode{
Op: OpMapValue, Op: OpMapValue,
Idx: opcodeOffset(ctx.ptrIndex), Type: typ,
Idx: head.Idx,
DisplayIdx: ctx.opcodeIndex, DisplayIdx: ctx.opcodeIndex,
ElemIdx: head.ElemIdx,
Length: head.Length,
MapIter: head.MapIter,
Indent: ctx.indent, Indent: ctx.indent,
} }
} }
func newMapEndCode(ctx *compileContext, head *Opcode) *Opcode { func newMapEndCode(ctx *compileContext, typ *runtime.Type, head *Opcode) *Opcode {
mapPos := opcodeOffset(ctx.ptrIndex)
ctx.incPtrIndex()
idx := opcodeOffset(ctx.ptrIndex)
return &Opcode{ return &Opcode{
Op: OpMapEnd, Op: OpMapEnd,
Idx: idx, Type: typ,
Next: newEndOp(ctx), Idx: head.Idx,
DisplayIdx: ctx.opcodeIndex, DisplayIdx: ctx.opcodeIndex,
Length: head.Length,
MapPos: mapPos,
Indent: ctx.indent, Indent: ctx.indent,
Next: newEndOp(ctx, typ),
} }
} }
func newInterfaceCode(ctx *compileContext) *Opcode { func newRecursiveCode(ctx *compileContext, typ *runtime.Type, jmp *CompiledCode) *Opcode {
return &Opcode{
Op: OpInterface,
Idx: opcodeOffset(ctx.ptrIndex),
Next: newEndOp(ctx),
Type: ctx.typ,
DisplayIdx: ctx.opcodeIndex,
Indent: ctx.indent,
}
}
func newRecursiveCode(ctx *compileContext, jmp *CompiledCode) *Opcode {
return &Opcode{ return &Opcode{
Op: OpRecursive, Op: OpRecursive,
Type: typ,
Idx: opcodeOffset(ctx.ptrIndex), Idx: opcodeOffset(ctx.ptrIndex),
Next: newEndOp(ctx), Next: newEndOp(ctx, typ),
Type: ctx.typ,
DisplayIdx: ctx.opcodeIndex, DisplayIdx: ctx.opcodeIndex,
Indent: ctx.indent, Indent: ctx.indent,
Jmp: jmp, Jmp: jmp,

View File

@ -11,6 +11,8 @@ const (
DebugOption DebugOption
ColorizeOption ColorizeOption
ContextOption ContextOption
NormalizeUTF8Option
FieldQueryOption
) )
type Option struct { type Option struct {

View File

@ -22,7 +22,7 @@ const (
CodeStructEnd CodeType = 11 CodeStructEnd CodeType = 11
) )
var opTypeStrings = [401]string{ var opTypeStrings = [400]string{
"End", "End",
"Interface", "Interface",
"Ptr", "Ptr",
@ -37,7 +37,6 @@ var opTypeStrings = [401]string{
"RecursivePtr", "RecursivePtr",
"RecursiveEnd", "RecursiveEnd",
"InterfaceEnd", "InterfaceEnd",
"StructAnonymousEnd",
"Int", "Int",
"Uint", "Uint",
"Float32", "Float32",
@ -443,397 +442,396 @@ const (
OpRecursivePtr OpType = 11 OpRecursivePtr OpType = 11
OpRecursiveEnd OpType = 12 OpRecursiveEnd OpType = 12
OpInterfaceEnd OpType = 13 OpInterfaceEnd OpType = 13
OpStructAnonymousEnd OpType = 14 OpInt OpType = 14
OpInt OpType = 15 OpUint OpType = 15
OpUint OpType = 16 OpFloat32 OpType = 16
OpFloat32 OpType = 17 OpFloat64 OpType = 17
OpFloat64 OpType = 18 OpBool OpType = 18
OpBool OpType = 19 OpString OpType = 19
OpString OpType = 20 OpBytes OpType = 20
OpBytes OpType = 21 OpNumber OpType = 21
OpNumber OpType = 22 OpArray OpType = 22
OpArray OpType = 23 OpMap OpType = 23
OpMap OpType = 24 OpSlice OpType = 24
OpSlice OpType = 25 OpStruct OpType = 25
OpStruct OpType = 26 OpMarshalJSON OpType = 26
OpMarshalJSON OpType = 27 OpMarshalText OpType = 27
OpMarshalText OpType = 28 OpIntString OpType = 28
OpIntString OpType = 29 OpUintString OpType = 29
OpUintString OpType = 30 OpFloat32String OpType = 30
OpFloat32String OpType = 31 OpFloat64String OpType = 31
OpFloat64String OpType = 32 OpBoolString OpType = 32
OpBoolString OpType = 33 OpStringString OpType = 33
OpStringString OpType = 34 OpNumberString OpType = 34
OpNumberString OpType = 35 OpIntPtr OpType = 35
OpIntPtr OpType = 36 OpUintPtr OpType = 36
OpUintPtr OpType = 37 OpFloat32Ptr OpType = 37
OpFloat32Ptr OpType = 38 OpFloat64Ptr OpType = 38
OpFloat64Ptr OpType = 39 OpBoolPtr OpType = 39
OpBoolPtr OpType = 40 OpStringPtr OpType = 40
OpStringPtr OpType = 41 OpBytesPtr OpType = 41
OpBytesPtr OpType = 42 OpNumberPtr OpType = 42
OpNumberPtr OpType = 43 OpArrayPtr OpType = 43
OpArrayPtr OpType = 44 OpMapPtr OpType = 44
OpMapPtr OpType = 45 OpSlicePtr OpType = 45
OpSlicePtr OpType = 46 OpMarshalJSONPtr OpType = 46
OpMarshalJSONPtr OpType = 47 OpMarshalTextPtr OpType = 47
OpMarshalTextPtr OpType = 48 OpInterfacePtr OpType = 48
OpInterfacePtr OpType = 49 OpIntPtrString OpType = 49
OpIntPtrString OpType = 50 OpUintPtrString OpType = 50
OpUintPtrString OpType = 51 OpFloat32PtrString OpType = 51
OpFloat32PtrString OpType = 52 OpFloat64PtrString OpType = 52
OpFloat64PtrString OpType = 53 OpBoolPtrString OpType = 53
OpBoolPtrString OpType = 54 OpStringPtrString OpType = 54
OpStringPtrString OpType = 55 OpNumberPtrString OpType = 55
OpNumberPtrString OpType = 56 OpStructHeadInt OpType = 56
OpStructHeadInt OpType = 57 OpStructHeadOmitEmptyInt OpType = 57
OpStructHeadOmitEmptyInt OpType = 58 OpStructPtrHeadInt OpType = 58
OpStructPtrHeadInt OpType = 59 OpStructPtrHeadOmitEmptyInt OpType = 59
OpStructPtrHeadOmitEmptyInt OpType = 60 OpStructHeadUint OpType = 60
OpStructHeadUint OpType = 61 OpStructHeadOmitEmptyUint OpType = 61
OpStructHeadOmitEmptyUint OpType = 62 OpStructPtrHeadUint OpType = 62
OpStructPtrHeadUint OpType = 63 OpStructPtrHeadOmitEmptyUint OpType = 63
OpStructPtrHeadOmitEmptyUint OpType = 64 OpStructHeadFloat32 OpType = 64
OpStructHeadFloat32 OpType = 65 OpStructHeadOmitEmptyFloat32 OpType = 65
OpStructHeadOmitEmptyFloat32 OpType = 66 OpStructPtrHeadFloat32 OpType = 66
OpStructPtrHeadFloat32 OpType = 67 OpStructPtrHeadOmitEmptyFloat32 OpType = 67
OpStructPtrHeadOmitEmptyFloat32 OpType = 68 OpStructHeadFloat64 OpType = 68
OpStructHeadFloat64 OpType = 69 OpStructHeadOmitEmptyFloat64 OpType = 69
OpStructHeadOmitEmptyFloat64 OpType = 70 OpStructPtrHeadFloat64 OpType = 70
OpStructPtrHeadFloat64 OpType = 71 OpStructPtrHeadOmitEmptyFloat64 OpType = 71
OpStructPtrHeadOmitEmptyFloat64 OpType = 72 OpStructHeadBool OpType = 72
OpStructHeadBool OpType = 73 OpStructHeadOmitEmptyBool OpType = 73
OpStructHeadOmitEmptyBool OpType = 74 OpStructPtrHeadBool OpType = 74
OpStructPtrHeadBool OpType = 75 OpStructPtrHeadOmitEmptyBool OpType = 75
OpStructPtrHeadOmitEmptyBool OpType = 76 OpStructHeadString OpType = 76
OpStructHeadString OpType = 77 OpStructHeadOmitEmptyString OpType = 77
OpStructHeadOmitEmptyString OpType = 78 OpStructPtrHeadString OpType = 78
OpStructPtrHeadString OpType = 79 OpStructPtrHeadOmitEmptyString OpType = 79
OpStructPtrHeadOmitEmptyString OpType = 80 OpStructHeadBytes OpType = 80
OpStructHeadBytes OpType = 81 OpStructHeadOmitEmptyBytes OpType = 81
OpStructHeadOmitEmptyBytes OpType = 82 OpStructPtrHeadBytes OpType = 82
OpStructPtrHeadBytes OpType = 83 OpStructPtrHeadOmitEmptyBytes OpType = 83
OpStructPtrHeadOmitEmptyBytes OpType = 84 OpStructHeadNumber OpType = 84
OpStructHeadNumber OpType = 85 OpStructHeadOmitEmptyNumber OpType = 85
OpStructHeadOmitEmptyNumber OpType = 86 OpStructPtrHeadNumber OpType = 86
OpStructPtrHeadNumber OpType = 87 OpStructPtrHeadOmitEmptyNumber OpType = 87
OpStructPtrHeadOmitEmptyNumber OpType = 88 OpStructHeadArray OpType = 88
OpStructHeadArray OpType = 89 OpStructHeadOmitEmptyArray OpType = 89
OpStructHeadOmitEmptyArray OpType = 90 OpStructPtrHeadArray OpType = 90
OpStructPtrHeadArray OpType = 91 OpStructPtrHeadOmitEmptyArray OpType = 91
OpStructPtrHeadOmitEmptyArray OpType = 92 OpStructHeadMap OpType = 92
OpStructHeadMap OpType = 93 OpStructHeadOmitEmptyMap OpType = 93
OpStructHeadOmitEmptyMap OpType = 94 OpStructPtrHeadMap OpType = 94
OpStructPtrHeadMap OpType = 95 OpStructPtrHeadOmitEmptyMap OpType = 95
OpStructPtrHeadOmitEmptyMap OpType = 96 OpStructHeadSlice OpType = 96
OpStructHeadSlice OpType = 97 OpStructHeadOmitEmptySlice OpType = 97
OpStructHeadOmitEmptySlice OpType = 98 OpStructPtrHeadSlice OpType = 98
OpStructPtrHeadSlice OpType = 99 OpStructPtrHeadOmitEmptySlice OpType = 99
OpStructPtrHeadOmitEmptySlice OpType = 100 OpStructHeadStruct OpType = 100
OpStructHeadStruct OpType = 101 OpStructHeadOmitEmptyStruct OpType = 101
OpStructHeadOmitEmptyStruct OpType = 102 OpStructPtrHeadStruct OpType = 102
OpStructPtrHeadStruct OpType = 103 OpStructPtrHeadOmitEmptyStruct OpType = 103
OpStructPtrHeadOmitEmptyStruct OpType = 104 OpStructHeadMarshalJSON OpType = 104
OpStructHeadMarshalJSON OpType = 105 OpStructHeadOmitEmptyMarshalJSON OpType = 105
OpStructHeadOmitEmptyMarshalJSON OpType = 106 OpStructPtrHeadMarshalJSON OpType = 106
OpStructPtrHeadMarshalJSON OpType = 107 OpStructPtrHeadOmitEmptyMarshalJSON OpType = 107
OpStructPtrHeadOmitEmptyMarshalJSON OpType = 108 OpStructHeadMarshalText OpType = 108
OpStructHeadMarshalText OpType = 109 OpStructHeadOmitEmptyMarshalText OpType = 109
OpStructHeadOmitEmptyMarshalText OpType = 110 OpStructPtrHeadMarshalText OpType = 110
OpStructPtrHeadMarshalText OpType = 111 OpStructPtrHeadOmitEmptyMarshalText OpType = 111
OpStructPtrHeadOmitEmptyMarshalText OpType = 112 OpStructHeadIntString OpType = 112
OpStructHeadIntString OpType = 113 OpStructHeadOmitEmptyIntString OpType = 113
OpStructHeadOmitEmptyIntString OpType = 114 OpStructPtrHeadIntString OpType = 114
OpStructPtrHeadIntString OpType = 115 OpStructPtrHeadOmitEmptyIntString OpType = 115
OpStructPtrHeadOmitEmptyIntString OpType = 116 OpStructHeadUintString OpType = 116
OpStructHeadUintString OpType = 117 OpStructHeadOmitEmptyUintString OpType = 117
OpStructHeadOmitEmptyUintString OpType = 118 OpStructPtrHeadUintString OpType = 118
OpStructPtrHeadUintString OpType = 119 OpStructPtrHeadOmitEmptyUintString OpType = 119
OpStructPtrHeadOmitEmptyUintString OpType = 120 OpStructHeadFloat32String OpType = 120
OpStructHeadFloat32String OpType = 121 OpStructHeadOmitEmptyFloat32String OpType = 121
OpStructHeadOmitEmptyFloat32String OpType = 122 OpStructPtrHeadFloat32String OpType = 122
OpStructPtrHeadFloat32String OpType = 123 OpStructPtrHeadOmitEmptyFloat32String OpType = 123
OpStructPtrHeadOmitEmptyFloat32String OpType = 124 OpStructHeadFloat64String OpType = 124
OpStructHeadFloat64String OpType = 125 OpStructHeadOmitEmptyFloat64String OpType = 125
OpStructHeadOmitEmptyFloat64String OpType = 126 OpStructPtrHeadFloat64String OpType = 126
OpStructPtrHeadFloat64String OpType = 127 OpStructPtrHeadOmitEmptyFloat64String OpType = 127
OpStructPtrHeadOmitEmptyFloat64String OpType = 128 OpStructHeadBoolString OpType = 128
OpStructHeadBoolString OpType = 129 OpStructHeadOmitEmptyBoolString OpType = 129
OpStructHeadOmitEmptyBoolString OpType = 130 OpStructPtrHeadBoolString OpType = 130
OpStructPtrHeadBoolString OpType = 131 OpStructPtrHeadOmitEmptyBoolString OpType = 131
OpStructPtrHeadOmitEmptyBoolString OpType = 132 OpStructHeadStringString OpType = 132
OpStructHeadStringString OpType = 133 OpStructHeadOmitEmptyStringString OpType = 133
OpStructHeadOmitEmptyStringString OpType = 134 OpStructPtrHeadStringString OpType = 134
OpStructPtrHeadStringString OpType = 135 OpStructPtrHeadOmitEmptyStringString OpType = 135
OpStructPtrHeadOmitEmptyStringString OpType = 136 OpStructHeadNumberString OpType = 136
OpStructHeadNumberString OpType = 137 OpStructHeadOmitEmptyNumberString OpType = 137
OpStructHeadOmitEmptyNumberString OpType = 138 OpStructPtrHeadNumberString OpType = 138
OpStructPtrHeadNumberString OpType = 139 OpStructPtrHeadOmitEmptyNumberString OpType = 139
OpStructPtrHeadOmitEmptyNumberString OpType = 140 OpStructHeadIntPtr OpType = 140
OpStructHeadIntPtr OpType = 141 OpStructHeadOmitEmptyIntPtr OpType = 141
OpStructHeadOmitEmptyIntPtr OpType = 142 OpStructPtrHeadIntPtr OpType = 142
OpStructPtrHeadIntPtr OpType = 143 OpStructPtrHeadOmitEmptyIntPtr OpType = 143
OpStructPtrHeadOmitEmptyIntPtr OpType = 144 OpStructHeadUintPtr OpType = 144
OpStructHeadUintPtr OpType = 145 OpStructHeadOmitEmptyUintPtr OpType = 145
OpStructHeadOmitEmptyUintPtr OpType = 146 OpStructPtrHeadUintPtr OpType = 146
OpStructPtrHeadUintPtr OpType = 147 OpStructPtrHeadOmitEmptyUintPtr OpType = 147
OpStructPtrHeadOmitEmptyUintPtr OpType = 148 OpStructHeadFloat32Ptr OpType = 148
OpStructHeadFloat32Ptr OpType = 149 OpStructHeadOmitEmptyFloat32Ptr OpType = 149
OpStructHeadOmitEmptyFloat32Ptr OpType = 150 OpStructPtrHeadFloat32Ptr OpType = 150
OpStructPtrHeadFloat32Ptr OpType = 151 OpStructPtrHeadOmitEmptyFloat32Ptr OpType = 151
OpStructPtrHeadOmitEmptyFloat32Ptr OpType = 152 OpStructHeadFloat64Ptr OpType = 152
OpStructHeadFloat64Ptr OpType = 153 OpStructHeadOmitEmptyFloat64Ptr OpType = 153
OpStructHeadOmitEmptyFloat64Ptr OpType = 154 OpStructPtrHeadFloat64Ptr OpType = 154
OpStructPtrHeadFloat64Ptr OpType = 155 OpStructPtrHeadOmitEmptyFloat64Ptr OpType = 155
OpStructPtrHeadOmitEmptyFloat64Ptr OpType = 156 OpStructHeadBoolPtr OpType = 156
OpStructHeadBoolPtr OpType = 157 OpStructHeadOmitEmptyBoolPtr OpType = 157
OpStructHeadOmitEmptyBoolPtr OpType = 158 OpStructPtrHeadBoolPtr OpType = 158
OpStructPtrHeadBoolPtr OpType = 159 OpStructPtrHeadOmitEmptyBoolPtr OpType = 159
OpStructPtrHeadOmitEmptyBoolPtr OpType = 160 OpStructHeadStringPtr OpType = 160
OpStructHeadStringPtr OpType = 161 OpStructHeadOmitEmptyStringPtr OpType = 161
OpStructHeadOmitEmptyStringPtr OpType = 162 OpStructPtrHeadStringPtr OpType = 162
OpStructPtrHeadStringPtr OpType = 163 OpStructPtrHeadOmitEmptyStringPtr OpType = 163
OpStructPtrHeadOmitEmptyStringPtr OpType = 164 OpStructHeadBytesPtr OpType = 164
OpStructHeadBytesPtr OpType = 165 OpStructHeadOmitEmptyBytesPtr OpType = 165
OpStructHeadOmitEmptyBytesPtr OpType = 166 OpStructPtrHeadBytesPtr OpType = 166
OpStructPtrHeadBytesPtr OpType = 167 OpStructPtrHeadOmitEmptyBytesPtr OpType = 167
OpStructPtrHeadOmitEmptyBytesPtr OpType = 168 OpStructHeadNumberPtr OpType = 168
OpStructHeadNumberPtr OpType = 169 OpStructHeadOmitEmptyNumberPtr OpType = 169
OpStructHeadOmitEmptyNumberPtr OpType = 170 OpStructPtrHeadNumberPtr OpType = 170
OpStructPtrHeadNumberPtr OpType = 171 OpStructPtrHeadOmitEmptyNumberPtr OpType = 171
OpStructPtrHeadOmitEmptyNumberPtr OpType = 172 OpStructHeadArrayPtr OpType = 172
OpStructHeadArrayPtr OpType = 173 OpStructHeadOmitEmptyArrayPtr OpType = 173
OpStructHeadOmitEmptyArrayPtr OpType = 174 OpStructPtrHeadArrayPtr OpType = 174
OpStructPtrHeadArrayPtr OpType = 175 OpStructPtrHeadOmitEmptyArrayPtr OpType = 175
OpStructPtrHeadOmitEmptyArrayPtr OpType = 176 OpStructHeadMapPtr OpType = 176
OpStructHeadMapPtr OpType = 177 OpStructHeadOmitEmptyMapPtr OpType = 177
OpStructHeadOmitEmptyMapPtr OpType = 178 OpStructPtrHeadMapPtr OpType = 178
OpStructPtrHeadMapPtr OpType = 179 OpStructPtrHeadOmitEmptyMapPtr OpType = 179
OpStructPtrHeadOmitEmptyMapPtr OpType = 180 OpStructHeadSlicePtr OpType = 180
OpStructHeadSlicePtr OpType = 181 OpStructHeadOmitEmptySlicePtr OpType = 181
OpStructHeadOmitEmptySlicePtr OpType = 182 OpStructPtrHeadSlicePtr OpType = 182
OpStructPtrHeadSlicePtr OpType = 183 OpStructPtrHeadOmitEmptySlicePtr OpType = 183
OpStructPtrHeadOmitEmptySlicePtr OpType = 184 OpStructHeadMarshalJSONPtr OpType = 184
OpStructHeadMarshalJSONPtr OpType = 185 OpStructHeadOmitEmptyMarshalJSONPtr OpType = 185
OpStructHeadOmitEmptyMarshalJSONPtr OpType = 186 OpStructPtrHeadMarshalJSONPtr OpType = 186
OpStructPtrHeadMarshalJSONPtr OpType = 187 OpStructPtrHeadOmitEmptyMarshalJSONPtr OpType = 187
OpStructPtrHeadOmitEmptyMarshalJSONPtr OpType = 188 OpStructHeadMarshalTextPtr OpType = 188
OpStructHeadMarshalTextPtr OpType = 189 OpStructHeadOmitEmptyMarshalTextPtr OpType = 189
OpStructHeadOmitEmptyMarshalTextPtr OpType = 190 OpStructPtrHeadMarshalTextPtr OpType = 190
OpStructPtrHeadMarshalTextPtr OpType = 191 OpStructPtrHeadOmitEmptyMarshalTextPtr OpType = 191
OpStructPtrHeadOmitEmptyMarshalTextPtr OpType = 192 OpStructHeadInterfacePtr OpType = 192
OpStructHeadInterfacePtr OpType = 193 OpStructHeadOmitEmptyInterfacePtr OpType = 193
OpStructHeadOmitEmptyInterfacePtr OpType = 194 OpStructPtrHeadInterfacePtr OpType = 194
OpStructPtrHeadInterfacePtr OpType = 195 OpStructPtrHeadOmitEmptyInterfacePtr OpType = 195
OpStructPtrHeadOmitEmptyInterfacePtr OpType = 196 OpStructHeadIntPtrString OpType = 196
OpStructHeadIntPtrString OpType = 197 OpStructHeadOmitEmptyIntPtrString OpType = 197
OpStructHeadOmitEmptyIntPtrString OpType = 198 OpStructPtrHeadIntPtrString OpType = 198
OpStructPtrHeadIntPtrString OpType = 199 OpStructPtrHeadOmitEmptyIntPtrString OpType = 199
OpStructPtrHeadOmitEmptyIntPtrString OpType = 200 OpStructHeadUintPtrString OpType = 200
OpStructHeadUintPtrString OpType = 201 OpStructHeadOmitEmptyUintPtrString OpType = 201
OpStructHeadOmitEmptyUintPtrString OpType = 202 OpStructPtrHeadUintPtrString OpType = 202
OpStructPtrHeadUintPtrString OpType = 203 OpStructPtrHeadOmitEmptyUintPtrString OpType = 203
OpStructPtrHeadOmitEmptyUintPtrString OpType = 204 OpStructHeadFloat32PtrString OpType = 204
OpStructHeadFloat32PtrString OpType = 205 OpStructHeadOmitEmptyFloat32PtrString OpType = 205
OpStructHeadOmitEmptyFloat32PtrString OpType = 206 OpStructPtrHeadFloat32PtrString OpType = 206
OpStructPtrHeadFloat32PtrString OpType = 207 OpStructPtrHeadOmitEmptyFloat32PtrString OpType = 207
OpStructPtrHeadOmitEmptyFloat32PtrString OpType = 208 OpStructHeadFloat64PtrString OpType = 208
OpStructHeadFloat64PtrString OpType = 209 OpStructHeadOmitEmptyFloat64PtrString OpType = 209
OpStructHeadOmitEmptyFloat64PtrString OpType = 210 OpStructPtrHeadFloat64PtrString OpType = 210
OpStructPtrHeadFloat64PtrString OpType = 211 OpStructPtrHeadOmitEmptyFloat64PtrString OpType = 211
OpStructPtrHeadOmitEmptyFloat64PtrString OpType = 212 OpStructHeadBoolPtrString OpType = 212
OpStructHeadBoolPtrString OpType = 213 OpStructHeadOmitEmptyBoolPtrString OpType = 213
OpStructHeadOmitEmptyBoolPtrString OpType = 214 OpStructPtrHeadBoolPtrString OpType = 214
OpStructPtrHeadBoolPtrString OpType = 215 OpStructPtrHeadOmitEmptyBoolPtrString OpType = 215
OpStructPtrHeadOmitEmptyBoolPtrString OpType = 216 OpStructHeadStringPtrString OpType = 216
OpStructHeadStringPtrString OpType = 217 OpStructHeadOmitEmptyStringPtrString OpType = 217
OpStructHeadOmitEmptyStringPtrString OpType = 218 OpStructPtrHeadStringPtrString OpType = 218
OpStructPtrHeadStringPtrString OpType = 219 OpStructPtrHeadOmitEmptyStringPtrString OpType = 219
OpStructPtrHeadOmitEmptyStringPtrString OpType = 220 OpStructHeadNumberPtrString OpType = 220
OpStructHeadNumberPtrString OpType = 221 OpStructHeadOmitEmptyNumberPtrString OpType = 221
OpStructHeadOmitEmptyNumberPtrString OpType = 222 OpStructPtrHeadNumberPtrString OpType = 222
OpStructPtrHeadNumberPtrString OpType = 223 OpStructPtrHeadOmitEmptyNumberPtrString OpType = 223
OpStructPtrHeadOmitEmptyNumberPtrString OpType = 224 OpStructHead OpType = 224
OpStructHead OpType = 225 OpStructHeadOmitEmpty OpType = 225
OpStructHeadOmitEmpty OpType = 226 OpStructPtrHead OpType = 226
OpStructPtrHead OpType = 227 OpStructPtrHeadOmitEmpty OpType = 227
OpStructPtrHeadOmitEmpty OpType = 228 OpStructFieldInt OpType = 228
OpStructFieldInt OpType = 229 OpStructFieldOmitEmptyInt OpType = 229
OpStructFieldOmitEmptyInt OpType = 230 OpStructEndInt OpType = 230
OpStructEndInt OpType = 231 OpStructEndOmitEmptyInt OpType = 231
OpStructEndOmitEmptyInt OpType = 232 OpStructFieldUint OpType = 232
OpStructFieldUint OpType = 233 OpStructFieldOmitEmptyUint OpType = 233
OpStructFieldOmitEmptyUint OpType = 234 OpStructEndUint OpType = 234
OpStructEndUint OpType = 235 OpStructEndOmitEmptyUint OpType = 235
OpStructEndOmitEmptyUint OpType = 236 OpStructFieldFloat32 OpType = 236
OpStructFieldFloat32 OpType = 237 OpStructFieldOmitEmptyFloat32 OpType = 237
OpStructFieldOmitEmptyFloat32 OpType = 238 OpStructEndFloat32 OpType = 238
OpStructEndFloat32 OpType = 239 OpStructEndOmitEmptyFloat32 OpType = 239
OpStructEndOmitEmptyFloat32 OpType = 240 OpStructFieldFloat64 OpType = 240
OpStructFieldFloat64 OpType = 241 OpStructFieldOmitEmptyFloat64 OpType = 241
OpStructFieldOmitEmptyFloat64 OpType = 242 OpStructEndFloat64 OpType = 242
OpStructEndFloat64 OpType = 243 OpStructEndOmitEmptyFloat64 OpType = 243
OpStructEndOmitEmptyFloat64 OpType = 244 OpStructFieldBool OpType = 244
OpStructFieldBool OpType = 245 OpStructFieldOmitEmptyBool OpType = 245
OpStructFieldOmitEmptyBool OpType = 246 OpStructEndBool OpType = 246
OpStructEndBool OpType = 247 OpStructEndOmitEmptyBool OpType = 247
OpStructEndOmitEmptyBool OpType = 248 OpStructFieldString OpType = 248
OpStructFieldString OpType = 249 OpStructFieldOmitEmptyString OpType = 249
OpStructFieldOmitEmptyString OpType = 250 OpStructEndString OpType = 250
OpStructEndString OpType = 251 OpStructEndOmitEmptyString OpType = 251
OpStructEndOmitEmptyString OpType = 252 OpStructFieldBytes OpType = 252
OpStructFieldBytes OpType = 253 OpStructFieldOmitEmptyBytes OpType = 253
OpStructFieldOmitEmptyBytes OpType = 254 OpStructEndBytes OpType = 254
OpStructEndBytes OpType = 255 OpStructEndOmitEmptyBytes OpType = 255
OpStructEndOmitEmptyBytes OpType = 256 OpStructFieldNumber OpType = 256
OpStructFieldNumber OpType = 257 OpStructFieldOmitEmptyNumber OpType = 257
OpStructFieldOmitEmptyNumber OpType = 258 OpStructEndNumber OpType = 258
OpStructEndNumber OpType = 259 OpStructEndOmitEmptyNumber OpType = 259
OpStructEndOmitEmptyNumber OpType = 260 OpStructFieldArray OpType = 260
OpStructFieldArray OpType = 261 OpStructFieldOmitEmptyArray OpType = 261
OpStructFieldOmitEmptyArray OpType = 262 OpStructEndArray OpType = 262
OpStructEndArray OpType = 263 OpStructEndOmitEmptyArray OpType = 263
OpStructEndOmitEmptyArray OpType = 264 OpStructFieldMap OpType = 264
OpStructFieldMap OpType = 265 OpStructFieldOmitEmptyMap OpType = 265
OpStructFieldOmitEmptyMap OpType = 266 OpStructEndMap OpType = 266
OpStructEndMap OpType = 267 OpStructEndOmitEmptyMap OpType = 267
OpStructEndOmitEmptyMap OpType = 268 OpStructFieldSlice OpType = 268
OpStructFieldSlice OpType = 269 OpStructFieldOmitEmptySlice OpType = 269
OpStructFieldOmitEmptySlice OpType = 270 OpStructEndSlice OpType = 270
OpStructEndSlice OpType = 271 OpStructEndOmitEmptySlice OpType = 271
OpStructEndOmitEmptySlice OpType = 272 OpStructFieldStruct OpType = 272
OpStructFieldStruct OpType = 273 OpStructFieldOmitEmptyStruct OpType = 273
OpStructFieldOmitEmptyStruct OpType = 274 OpStructEndStruct OpType = 274
OpStructEndStruct OpType = 275 OpStructEndOmitEmptyStruct OpType = 275
OpStructEndOmitEmptyStruct OpType = 276 OpStructFieldMarshalJSON OpType = 276
OpStructFieldMarshalJSON OpType = 277 OpStructFieldOmitEmptyMarshalJSON OpType = 277
OpStructFieldOmitEmptyMarshalJSON OpType = 278 OpStructEndMarshalJSON OpType = 278
OpStructEndMarshalJSON OpType = 279 OpStructEndOmitEmptyMarshalJSON OpType = 279
OpStructEndOmitEmptyMarshalJSON OpType = 280 OpStructFieldMarshalText OpType = 280
OpStructFieldMarshalText OpType = 281 OpStructFieldOmitEmptyMarshalText OpType = 281
OpStructFieldOmitEmptyMarshalText OpType = 282 OpStructEndMarshalText OpType = 282
OpStructEndMarshalText OpType = 283 OpStructEndOmitEmptyMarshalText OpType = 283
OpStructEndOmitEmptyMarshalText OpType = 284 OpStructFieldIntString OpType = 284
OpStructFieldIntString OpType = 285 OpStructFieldOmitEmptyIntString OpType = 285
OpStructFieldOmitEmptyIntString OpType = 286 OpStructEndIntString OpType = 286
OpStructEndIntString OpType = 287 OpStructEndOmitEmptyIntString OpType = 287
OpStructEndOmitEmptyIntString OpType = 288 OpStructFieldUintString OpType = 288
OpStructFieldUintString OpType = 289 OpStructFieldOmitEmptyUintString OpType = 289
OpStructFieldOmitEmptyUintString OpType = 290 OpStructEndUintString OpType = 290
OpStructEndUintString OpType = 291 OpStructEndOmitEmptyUintString OpType = 291
OpStructEndOmitEmptyUintString OpType = 292 OpStructFieldFloat32String OpType = 292
OpStructFieldFloat32String OpType = 293 OpStructFieldOmitEmptyFloat32String OpType = 293
OpStructFieldOmitEmptyFloat32String OpType = 294 OpStructEndFloat32String OpType = 294
OpStructEndFloat32String OpType = 295 OpStructEndOmitEmptyFloat32String OpType = 295
OpStructEndOmitEmptyFloat32String OpType = 296 OpStructFieldFloat64String OpType = 296
OpStructFieldFloat64String OpType = 297 OpStructFieldOmitEmptyFloat64String OpType = 297
OpStructFieldOmitEmptyFloat64String OpType = 298 OpStructEndFloat64String OpType = 298
OpStructEndFloat64String OpType = 299 OpStructEndOmitEmptyFloat64String OpType = 299
OpStructEndOmitEmptyFloat64String OpType = 300 OpStructFieldBoolString OpType = 300
OpStructFieldBoolString OpType = 301 OpStructFieldOmitEmptyBoolString OpType = 301
OpStructFieldOmitEmptyBoolString OpType = 302 OpStructEndBoolString OpType = 302
OpStructEndBoolString OpType = 303 OpStructEndOmitEmptyBoolString OpType = 303
OpStructEndOmitEmptyBoolString OpType = 304 OpStructFieldStringString OpType = 304
OpStructFieldStringString OpType = 305 OpStructFieldOmitEmptyStringString OpType = 305
OpStructFieldOmitEmptyStringString OpType = 306 OpStructEndStringString OpType = 306
OpStructEndStringString OpType = 307 OpStructEndOmitEmptyStringString OpType = 307
OpStructEndOmitEmptyStringString OpType = 308 OpStructFieldNumberString OpType = 308
OpStructFieldNumberString OpType = 309 OpStructFieldOmitEmptyNumberString OpType = 309
OpStructFieldOmitEmptyNumberString OpType = 310 OpStructEndNumberString OpType = 310
OpStructEndNumberString OpType = 311 OpStructEndOmitEmptyNumberString OpType = 311
OpStructEndOmitEmptyNumberString OpType = 312 OpStructFieldIntPtr OpType = 312
OpStructFieldIntPtr OpType = 313 OpStructFieldOmitEmptyIntPtr OpType = 313
OpStructFieldOmitEmptyIntPtr OpType = 314 OpStructEndIntPtr OpType = 314
OpStructEndIntPtr OpType = 315 OpStructEndOmitEmptyIntPtr OpType = 315
OpStructEndOmitEmptyIntPtr OpType = 316 OpStructFieldUintPtr OpType = 316
OpStructFieldUintPtr OpType = 317 OpStructFieldOmitEmptyUintPtr OpType = 317
OpStructFieldOmitEmptyUintPtr OpType = 318 OpStructEndUintPtr OpType = 318
OpStructEndUintPtr OpType = 319 OpStructEndOmitEmptyUintPtr OpType = 319
OpStructEndOmitEmptyUintPtr OpType = 320 OpStructFieldFloat32Ptr OpType = 320
OpStructFieldFloat32Ptr OpType = 321 OpStructFieldOmitEmptyFloat32Ptr OpType = 321
OpStructFieldOmitEmptyFloat32Ptr OpType = 322 OpStructEndFloat32Ptr OpType = 322
OpStructEndFloat32Ptr OpType = 323 OpStructEndOmitEmptyFloat32Ptr OpType = 323
OpStructEndOmitEmptyFloat32Ptr OpType = 324 OpStructFieldFloat64Ptr OpType = 324
OpStructFieldFloat64Ptr OpType = 325 OpStructFieldOmitEmptyFloat64Ptr OpType = 325
OpStructFieldOmitEmptyFloat64Ptr OpType = 326 OpStructEndFloat64Ptr OpType = 326
OpStructEndFloat64Ptr OpType = 327 OpStructEndOmitEmptyFloat64Ptr OpType = 327
OpStructEndOmitEmptyFloat64Ptr OpType = 328 OpStructFieldBoolPtr OpType = 328
OpStructFieldBoolPtr OpType = 329 OpStructFieldOmitEmptyBoolPtr OpType = 329
OpStructFieldOmitEmptyBoolPtr OpType = 330 OpStructEndBoolPtr OpType = 330
OpStructEndBoolPtr OpType = 331 OpStructEndOmitEmptyBoolPtr OpType = 331
OpStructEndOmitEmptyBoolPtr OpType = 332 OpStructFieldStringPtr OpType = 332
OpStructFieldStringPtr OpType = 333 OpStructFieldOmitEmptyStringPtr OpType = 333
OpStructFieldOmitEmptyStringPtr OpType = 334 OpStructEndStringPtr OpType = 334
OpStructEndStringPtr OpType = 335 OpStructEndOmitEmptyStringPtr OpType = 335
OpStructEndOmitEmptyStringPtr OpType = 336 OpStructFieldBytesPtr OpType = 336
OpStructFieldBytesPtr OpType = 337 OpStructFieldOmitEmptyBytesPtr OpType = 337
OpStructFieldOmitEmptyBytesPtr OpType = 338 OpStructEndBytesPtr OpType = 338
OpStructEndBytesPtr OpType = 339 OpStructEndOmitEmptyBytesPtr OpType = 339
OpStructEndOmitEmptyBytesPtr OpType = 340 OpStructFieldNumberPtr OpType = 340
OpStructFieldNumberPtr OpType = 341 OpStructFieldOmitEmptyNumberPtr OpType = 341
OpStructFieldOmitEmptyNumberPtr OpType = 342 OpStructEndNumberPtr OpType = 342
OpStructEndNumberPtr OpType = 343 OpStructEndOmitEmptyNumberPtr OpType = 343
OpStructEndOmitEmptyNumberPtr OpType = 344 OpStructFieldArrayPtr OpType = 344
OpStructFieldArrayPtr OpType = 345 OpStructFieldOmitEmptyArrayPtr OpType = 345
OpStructFieldOmitEmptyArrayPtr OpType = 346 OpStructEndArrayPtr OpType = 346
OpStructEndArrayPtr OpType = 347 OpStructEndOmitEmptyArrayPtr OpType = 347
OpStructEndOmitEmptyArrayPtr OpType = 348 OpStructFieldMapPtr OpType = 348
OpStructFieldMapPtr OpType = 349 OpStructFieldOmitEmptyMapPtr OpType = 349
OpStructFieldOmitEmptyMapPtr OpType = 350 OpStructEndMapPtr OpType = 350
OpStructEndMapPtr OpType = 351 OpStructEndOmitEmptyMapPtr OpType = 351
OpStructEndOmitEmptyMapPtr OpType = 352 OpStructFieldSlicePtr OpType = 352
OpStructFieldSlicePtr OpType = 353 OpStructFieldOmitEmptySlicePtr OpType = 353
OpStructFieldOmitEmptySlicePtr OpType = 354 OpStructEndSlicePtr OpType = 354
OpStructEndSlicePtr OpType = 355 OpStructEndOmitEmptySlicePtr OpType = 355
OpStructEndOmitEmptySlicePtr OpType = 356 OpStructFieldMarshalJSONPtr OpType = 356
OpStructFieldMarshalJSONPtr OpType = 357 OpStructFieldOmitEmptyMarshalJSONPtr OpType = 357
OpStructFieldOmitEmptyMarshalJSONPtr OpType = 358 OpStructEndMarshalJSONPtr OpType = 358
OpStructEndMarshalJSONPtr OpType = 359 OpStructEndOmitEmptyMarshalJSONPtr OpType = 359
OpStructEndOmitEmptyMarshalJSONPtr OpType = 360 OpStructFieldMarshalTextPtr OpType = 360
OpStructFieldMarshalTextPtr OpType = 361 OpStructFieldOmitEmptyMarshalTextPtr OpType = 361
OpStructFieldOmitEmptyMarshalTextPtr OpType = 362 OpStructEndMarshalTextPtr OpType = 362
OpStructEndMarshalTextPtr OpType = 363 OpStructEndOmitEmptyMarshalTextPtr OpType = 363
OpStructEndOmitEmptyMarshalTextPtr OpType = 364 OpStructFieldInterfacePtr OpType = 364
OpStructFieldInterfacePtr OpType = 365 OpStructFieldOmitEmptyInterfacePtr OpType = 365
OpStructFieldOmitEmptyInterfacePtr OpType = 366 OpStructEndInterfacePtr OpType = 366
OpStructEndInterfacePtr OpType = 367 OpStructEndOmitEmptyInterfacePtr OpType = 367
OpStructEndOmitEmptyInterfacePtr OpType = 368 OpStructFieldIntPtrString OpType = 368
OpStructFieldIntPtrString OpType = 369 OpStructFieldOmitEmptyIntPtrString OpType = 369
OpStructFieldOmitEmptyIntPtrString OpType = 370 OpStructEndIntPtrString OpType = 370
OpStructEndIntPtrString OpType = 371 OpStructEndOmitEmptyIntPtrString OpType = 371
OpStructEndOmitEmptyIntPtrString OpType = 372 OpStructFieldUintPtrString OpType = 372
OpStructFieldUintPtrString OpType = 373 OpStructFieldOmitEmptyUintPtrString OpType = 373
OpStructFieldOmitEmptyUintPtrString OpType = 374 OpStructEndUintPtrString OpType = 374
OpStructEndUintPtrString OpType = 375 OpStructEndOmitEmptyUintPtrString OpType = 375
OpStructEndOmitEmptyUintPtrString OpType = 376 OpStructFieldFloat32PtrString OpType = 376
OpStructFieldFloat32PtrString OpType = 377 OpStructFieldOmitEmptyFloat32PtrString OpType = 377
OpStructFieldOmitEmptyFloat32PtrString OpType = 378 OpStructEndFloat32PtrString OpType = 378
OpStructEndFloat32PtrString OpType = 379 OpStructEndOmitEmptyFloat32PtrString OpType = 379
OpStructEndOmitEmptyFloat32PtrString OpType = 380 OpStructFieldFloat64PtrString OpType = 380
OpStructFieldFloat64PtrString OpType = 381 OpStructFieldOmitEmptyFloat64PtrString OpType = 381
OpStructFieldOmitEmptyFloat64PtrString OpType = 382 OpStructEndFloat64PtrString OpType = 382
OpStructEndFloat64PtrString OpType = 383 OpStructEndOmitEmptyFloat64PtrString OpType = 383
OpStructEndOmitEmptyFloat64PtrString OpType = 384 OpStructFieldBoolPtrString OpType = 384
OpStructFieldBoolPtrString OpType = 385 OpStructFieldOmitEmptyBoolPtrString OpType = 385
OpStructFieldOmitEmptyBoolPtrString OpType = 386 OpStructEndBoolPtrString OpType = 386
OpStructEndBoolPtrString OpType = 387 OpStructEndOmitEmptyBoolPtrString OpType = 387
OpStructEndOmitEmptyBoolPtrString OpType = 388 OpStructFieldStringPtrString OpType = 388
OpStructFieldStringPtrString OpType = 389 OpStructFieldOmitEmptyStringPtrString OpType = 389
OpStructFieldOmitEmptyStringPtrString OpType = 390 OpStructEndStringPtrString OpType = 390
OpStructEndStringPtrString OpType = 391 OpStructEndOmitEmptyStringPtrString OpType = 391
OpStructEndOmitEmptyStringPtrString OpType = 392 OpStructFieldNumberPtrString OpType = 392
OpStructFieldNumberPtrString OpType = 393 OpStructFieldOmitEmptyNumberPtrString OpType = 393
OpStructFieldOmitEmptyNumberPtrString OpType = 394 OpStructEndNumberPtrString OpType = 394
OpStructEndNumberPtrString OpType = 395 OpStructEndOmitEmptyNumberPtrString OpType = 395
OpStructEndOmitEmptyNumberPtrString OpType = 396 OpStructField OpType = 396
OpStructField OpType = 397 OpStructFieldOmitEmpty OpType = 397
OpStructFieldOmitEmpty OpType = 398 OpStructEnd OpType = 398
OpStructEnd OpType = 399 OpStructEndOmitEmpty OpType = 399
OpStructEndOmitEmpty OpType = 400
) )
func (t OpType) String() string { func (t OpType) String() string {
if int(t) >= 401 { if int(t) >= 400 {
return "" return ""
} }
return opTypeStrings[int(t)] return opTypeStrings[int(t)]
@ -896,7 +894,7 @@ func (t OpType) HeadToOmitEmptyHead() OpType {
} }
func (t OpType) PtrHeadToHead() OpType { func (t OpType) PtrHeadToHead() OpType {
idx := strings.Index(t.String(), "Ptr") idx := strings.Index(t.String(), "PtrHead")
if idx == -1 { if idx == -1 {
return t return t
} }

View File

@ -0,0 +1,135 @@
package encoder
import (
"context"
"fmt"
"reflect"
)
var (
Marshal func(interface{}) ([]byte, error)
Unmarshal func([]byte, interface{}) error
)
type FieldQuery struct {
Name string
Fields []*FieldQuery
hash string
}
func (q *FieldQuery) Hash() string {
if q.hash != "" {
return q.hash
}
b, _ := Marshal(q)
q.hash = string(b)
return q.hash
}
func (q *FieldQuery) MarshalJSON() ([]byte, error) {
if q.Name != "" {
if len(q.Fields) > 0 {
return Marshal(map[string][]*FieldQuery{q.Name: q.Fields})
}
return Marshal(q.Name)
}
return Marshal(q.Fields)
}
func (q *FieldQuery) QueryString() (FieldQueryString, error) {
b, err := Marshal(q)
if err != nil {
return "", err
}
return FieldQueryString(b), nil
}
type FieldQueryString string
func (s FieldQueryString) Build() (*FieldQuery, error) {
var query interface{}
if err := Unmarshal([]byte(s), &query); err != nil {
return nil, err
}
return s.build(reflect.ValueOf(query))
}
func (s FieldQueryString) build(v reflect.Value) (*FieldQuery, error) {
switch v.Type().Kind() {
case reflect.String:
return s.buildString(v)
case reflect.Map:
return s.buildMap(v)
case reflect.Slice:
return s.buildSlice(v)
case reflect.Interface:
return s.build(reflect.ValueOf(v.Interface()))
}
return nil, fmt.Errorf("failed to build field query")
}
func (s FieldQueryString) buildString(v reflect.Value) (*FieldQuery, error) {
b := []byte(v.String())
switch b[0] {
case '[', '{':
var query interface{}
if err := Unmarshal(b, &query); err != nil {
return nil, err
}
if str, ok := query.(string); ok {
return &FieldQuery{Name: str}, nil
}
return s.build(reflect.ValueOf(query))
}
return &FieldQuery{Name: string(b)}, nil
}
func (s FieldQueryString) buildSlice(v reflect.Value) (*FieldQuery, error) {
fields := make([]*FieldQuery, 0, v.Len())
for i := 0; i < v.Len(); i++ {
def, err := s.build(v.Index(i))
if err != nil {
return nil, err
}
fields = append(fields, def)
}
return &FieldQuery{Fields: fields}, nil
}
func (s FieldQueryString) buildMap(v reflect.Value) (*FieldQuery, error) {
keys := v.MapKeys()
if len(keys) != 1 {
return nil, fmt.Errorf("failed to build field query object")
}
key := keys[0]
if key.Type().Kind() != reflect.String {
return nil, fmt.Errorf("failed to build field query. invalid object key type")
}
name := key.String()
def, err := s.build(v.MapIndex(key))
if err != nil {
return nil, err
}
return &FieldQuery{
Name: name,
Fields: def.Fields,
}, nil
}
type queryKey struct{}
func FieldQueryFromContext(ctx context.Context) *FieldQuery {
query := ctx.Value(queryKey{})
if query == nil {
return nil
}
q, ok := query.(*FieldQuery)
if !ok {
return nil
}
return q
}
func SetFieldQueryToContext(ctx context.Context, query *FieldQuery) context.Context {
return context.WithValue(ctx, queryKey{}, query)
}

View File

@ -3,7 +3,6 @@ package encoder
import ( import (
"math/bits" "math/bits"
"reflect" "reflect"
"unicode/utf8"
"unsafe" "unsafe"
) )
@ -12,390 +11,8 @@ const (
msb = 0x8080808080808080 msb = 0x8080808080808080
) )
var needEscapeWithHTML = [256]bool{
'"': true,
'&': true,
'<': true,
'>': true,
'\\': true,
0x00: true,
0x01: true,
0x02: true,
0x03: true,
0x04: true,
0x05: true,
0x06: true,
0x07: true,
0x08: true,
0x09: true,
0x0a: true,
0x0b: true,
0x0c: true,
0x0d: true,
0x0e: true,
0x0f: true,
0x10: true,
0x11: true,
0x12: true,
0x13: true,
0x14: true,
0x15: true,
0x16: true,
0x17: true,
0x18: true,
0x19: true,
0x1a: true,
0x1b: true,
0x1c: true,
0x1d: true,
0x1e: true,
0x1f: true,
/* 0x20 - 0x7f */
0x80: true,
0x81: true,
0x82: true,
0x83: true,
0x84: true,
0x85: true,
0x86: true,
0x87: true,
0x88: true,
0x89: true,
0x8a: true,
0x8b: true,
0x8c: true,
0x8d: true,
0x8e: true,
0x8f: true,
0x90: true,
0x91: true,
0x92: true,
0x93: true,
0x94: true,
0x95: true,
0x96: true,
0x97: true,
0x98: true,
0x99: true,
0x9a: true,
0x9b: true,
0x9c: true,
0x9d: true,
0x9e: true,
0x9f: true,
0xa0: true,
0xa1: true,
0xa2: true,
0xa3: true,
0xa4: true,
0xa5: true,
0xa6: true,
0xa7: true,
0xa8: true,
0xa9: true,
0xaa: true,
0xab: true,
0xac: true,
0xad: true,
0xae: true,
0xaf: true,
0xb0: true,
0xb1: true,
0xb2: true,
0xb3: true,
0xb4: true,
0xb5: true,
0xb6: true,
0xb7: true,
0xb8: true,
0xb9: true,
0xba: true,
0xbb: true,
0xbc: true,
0xbd: true,
0xbe: true,
0xbf: true,
0xc0: true,
0xc1: true,
0xc2: true,
0xc3: true,
0xc4: true,
0xc5: true,
0xc6: true,
0xc7: true,
0xc8: true,
0xc9: true,
0xca: true,
0xcb: true,
0xcc: true,
0xcd: true,
0xce: true,
0xcf: true,
0xd0: true,
0xd1: true,
0xd2: true,
0xd3: true,
0xd4: true,
0xd5: true,
0xd6: true,
0xd7: true,
0xd8: true,
0xd9: true,
0xda: true,
0xdb: true,
0xdc: true,
0xdd: true,
0xde: true,
0xdf: true,
0xe0: true,
0xe1: true,
0xe2: true,
0xe3: true,
0xe4: true,
0xe5: true,
0xe6: true,
0xe7: true,
0xe8: true,
0xe9: true,
0xea: true,
0xeb: true,
0xec: true,
0xed: true,
0xee: true,
0xef: true,
0xf0: true,
0xf1: true,
0xf2: true,
0xf3: true,
0xf4: true,
0xf5: true,
0xf6: true,
0xf7: true,
0xf8: true,
0xf9: true,
0xfa: true,
0xfb: true,
0xfc: true,
0xfd: true,
0xfe: true,
0xff: true,
}
var needEscape = [256]bool{
'"': true,
'\\': true,
0x00: true,
0x01: true,
0x02: true,
0x03: true,
0x04: true,
0x05: true,
0x06: true,
0x07: true,
0x08: true,
0x09: true,
0x0a: true,
0x0b: true,
0x0c: true,
0x0d: true,
0x0e: true,
0x0f: true,
0x10: true,
0x11: true,
0x12: true,
0x13: true,
0x14: true,
0x15: true,
0x16: true,
0x17: true,
0x18: true,
0x19: true,
0x1a: true,
0x1b: true,
0x1c: true,
0x1d: true,
0x1e: true,
0x1f: true,
/* 0x20 - 0x7f */
0x80: true,
0x81: true,
0x82: true,
0x83: true,
0x84: true,
0x85: true,
0x86: true,
0x87: true,
0x88: true,
0x89: true,
0x8a: true,
0x8b: true,
0x8c: true,
0x8d: true,
0x8e: true,
0x8f: true,
0x90: true,
0x91: true,
0x92: true,
0x93: true,
0x94: true,
0x95: true,
0x96: true,
0x97: true,
0x98: true,
0x99: true,
0x9a: true,
0x9b: true,
0x9c: true,
0x9d: true,
0x9e: true,
0x9f: true,
0xa0: true,
0xa1: true,
0xa2: true,
0xa3: true,
0xa4: true,
0xa5: true,
0xa6: true,
0xa7: true,
0xa8: true,
0xa9: true,
0xaa: true,
0xab: true,
0xac: true,
0xad: true,
0xae: true,
0xaf: true,
0xb0: true,
0xb1: true,
0xb2: true,
0xb3: true,
0xb4: true,
0xb5: true,
0xb6: true,
0xb7: true,
0xb8: true,
0xb9: true,
0xba: true,
0xbb: true,
0xbc: true,
0xbd: true,
0xbe: true,
0xbf: true,
0xc0: true,
0xc1: true,
0xc2: true,
0xc3: true,
0xc4: true,
0xc5: true,
0xc6: true,
0xc7: true,
0xc8: true,
0xc9: true,
0xca: true,
0xcb: true,
0xcc: true,
0xcd: true,
0xce: true,
0xcf: true,
0xd0: true,
0xd1: true,
0xd2: true,
0xd3: true,
0xd4: true,
0xd5: true,
0xd6: true,
0xd7: true,
0xd8: true,
0xd9: true,
0xda: true,
0xdb: true,
0xdc: true,
0xdd: true,
0xde: true,
0xdf: true,
0xe0: true,
0xe1: true,
0xe2: true,
0xe3: true,
0xe4: true,
0xe5: true,
0xe6: true,
0xe7: true,
0xe8: true,
0xe9: true,
0xea: true,
0xeb: true,
0xec: true,
0xed: true,
0xee: true,
0xef: true,
0xf0: true,
0xf1: true,
0xf2: true,
0xf3: true,
0xf4: true,
0xf5: true,
0xf6: true,
0xf7: true,
0xf8: true,
0xf9: true,
0xfa: true,
0xfb: true,
0xfc: true,
0xfd: true,
0xfe: true,
0xff: true,
}
var hex = "0123456789abcdef" var hex = "0123456789abcdef"
// escapeIndex finds the index of the first char in `s` that requires escaping.
// A char requires escaping if it's outside of the range of [0x20, 0x7F] or if
// it includes a double quote or backslash.
// If no chars in `s` require escaping, the return value is -1.
func escapeIndex(s string) int {
chunks := stringToUint64Slice(s)
for _, n := range chunks {
// combine masks before checking for the MSB of each byte. We include
// `n` in the mask to check whether any of the *input* byte MSBs were
// set (i.e. the byte was outside the ASCII range).
mask := n | below(n, 0x20) | contains(n, '"') | contains(n, '\\')
if (mask & msb) != 0 {
return bits.TrailingZeros64(mask&msb) / 8
}
}
valLen := len(s)
for i := len(chunks) * 8; i < valLen; i++ {
if needEscape[s[i]] {
return i
}
}
return -1
}
// below return a mask that can be used to determine if any of the bytes
// in `n` are below `b`. If a byte's MSB is set in the mask then that byte was
// below `b`. The result is only valid if `b`, and each byte in `n`, is below
// 0x80.
func below(n uint64, b byte) uint64 {
return n - expand(b)
}
// contains returns a mask that can be used to determine if any of the
// bytes in `n` are equal to `b`. If a byte's MSB is set in the mask then
// that byte is equal to `b`. The result is only valid if `b`, and each
// byte in `n`, is below 0x80.
func contains(n uint64, b byte) uint64 {
return (n ^ expand(b)) - lsb
}
// expand puts the specified byte into each of the 8 bytes of a uint64.
func expand(b byte) uint64 {
return lsb * uint64(b)
}
//nolint:govet //nolint:govet
func stringToUint64Slice(s string) []uint64 { func stringToUint64Slice(s string) []uint64 {
return *(*[]uint64)(unsafe.Pointer(&reflect.SliceHeader{ return *(*[]uint64)(unsafe.Pointer(&reflect.SliceHeader{
@ -406,9 +23,19 @@ func stringToUint64Slice(s string) []uint64 {
} }
func AppendString(ctx *RuntimeContext, buf []byte, s string) []byte { func AppendString(ctx *RuntimeContext, buf []byte, s string) []byte {
if ctx.Option.Flag&HTMLEscapeOption == 0 { if ctx.Option.Flag&HTMLEscapeOption != 0 {
return appendString(buf, s) if ctx.Option.Flag&NormalizeUTF8Option != 0 {
return appendNormalizedHTMLString(buf, s)
}
return appendHTMLString(buf, s)
} }
if ctx.Option.Flag&NormalizeUTF8Option != 0 {
return appendNormalizedString(buf, s)
}
return appendString(buf, s)
}
func appendNormalizedHTMLString(buf []byte, s string) []byte {
valLen := len(s) valLen := len(s)
if valLen == 0 { if valLen == 0 {
return append(buf, `""`...) return append(buf, `""`...)
@ -435,7 +62,7 @@ func AppendString(ctx *RuntimeContext, buf []byte, s string) []byte {
} }
} }
for i := len(chunks) * 8; i < valLen; i++ { for i := len(chunks) * 8; i < valLen; i++ {
if needEscapeWithHTML[s[i]] { if needEscapeHTMLNormalizeUTF8[s[i]] {
j = i j = i
goto ESCAPE_END goto ESCAPE_END
} }
@ -447,7 +74,7 @@ ESCAPE_END:
for j < valLen { for j < valLen {
c := s[j] c := s[j]
if !needEscapeWithHTML[c] { if !needEscapeHTMLNormalizeUTF8[c] {
// fast path: most of the time, printable ascii characters are used // fast path: most of the time, printable ascii characters are used
j++ j++
continue continue
@ -489,10 +116,220 @@ ESCAPE_END:
i = j + 1 i = j + 1
j = j + 1 j = j + 1
continue continue
case 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x0B, 0x0C, 0x0E, 0x0F, // 0x00-0x0F
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F: // 0x10-0x1F
buf = append(buf, s[i:j]...)
buf = append(buf, `\u00`...)
buf = append(buf, hex[c>>4], hex[c&0xF])
i = j + 1
j = j + 1
continue
}
state, size := decodeRuneInString(s[j:])
switch state {
case runeErrorState:
buf = append(buf, s[i:j]...)
buf = append(buf, `\ufffd`...)
i = j + 1
j = j + 1
continue
// U+2028 is LINE SEPARATOR.
// U+2029 is PARAGRAPH SEPARATOR.
// They are both technically valid characters in JSON strings,
// but don't work in JSONP, which has to be evaluated as JavaScript,
// and can lead to security holes there. It is valid JSON to
// escape them, so we do so unconditionally.
// See http://timelessrepo.com/json-isnt-a-javascript-subset for discussion.
case lineSepState:
buf = append(buf, s[i:j]...)
buf = append(buf, `\u2028`...)
i = j + 3
j = j + 3
continue
case paragraphSepState:
buf = append(buf, s[i:j]...)
buf = append(buf, `\u2029`...)
i = j + 3
j = j + 3
continue
}
j += size
}
return append(append(buf, s[i:]...), '"')
}
func appendHTMLString(buf []byte, s string) []byte {
valLen := len(s)
if valLen == 0 {
return append(buf, `""`...)
}
buf = append(buf, '"')
var (
i, j int
)
if valLen >= 8 {
chunks := stringToUint64Slice(s)
for _, n := range chunks {
// combine masks before checking for the MSB of each byte. We include
// `n` in the mask to check whether any of the *input* byte MSBs were
// set (i.e. the byte was outside the ASCII range).
mask := n | (n - (lsb * 0x20)) |
((n ^ (lsb * '"')) - lsb) |
((n ^ (lsb * '\\')) - lsb) |
((n ^ (lsb * '<')) - lsb) |
((n ^ (lsb * '>')) - lsb) |
((n ^ (lsb * '&')) - lsb)
if (mask & msb) != 0 {
j = bits.TrailingZeros64(mask&msb) / 8
goto ESCAPE_END
}
}
for i := len(chunks) * 8; i < valLen; i++ {
if needEscapeHTML[s[i]] {
j = i
goto ESCAPE_END
}
}
// no found any escape characters.
return append(append(buf, s...), '"')
}
ESCAPE_END:
for j < valLen {
c := s[j]
if !needEscapeHTML[c] {
// fast path: most of the time, printable ascii characters are used
j++
continue
} }
// This encodes bytes < 0x20 except for \t, \n and \r. switch c {
if c < 0x20 { case '\\', '"':
buf = append(buf, s[i:j]...)
buf = append(buf, '\\', c)
i = j + 1
j = j + 1
continue
case '\n':
buf = append(buf, s[i:j]...)
buf = append(buf, '\\', 'n')
i = j + 1
j = j + 1
continue
case '\r':
buf = append(buf, s[i:j]...)
buf = append(buf, '\\', 'r')
i = j + 1
j = j + 1
continue
case '\t':
buf = append(buf, s[i:j]...)
buf = append(buf, '\\', 't')
i = j + 1
j = j + 1
continue
case '<', '>', '&':
buf = append(buf, s[i:j]...)
buf = append(buf, `\u00`...)
buf = append(buf, hex[c>>4], hex[c&0xF])
i = j + 1
j = j + 1
continue
case 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x0B, 0x0C, 0x0E, 0x0F, // 0x00-0x0F
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F: // 0x10-0x1F
buf = append(buf, s[i:j]...)
buf = append(buf, `\u00`...)
buf = append(buf, hex[c>>4], hex[c&0xF])
i = j + 1
j = j + 1
continue
}
j++
}
return append(append(buf, s[i:]...), '"')
}
func appendNormalizedString(buf []byte, s string) []byte {
valLen := len(s)
if valLen == 0 {
return append(buf, `""`...)
}
buf = append(buf, '"')
var (
i, j int
)
if valLen >= 8 {
chunks := stringToUint64Slice(s)
for _, n := range chunks {
// combine masks before checking for the MSB of each byte. We include
// `n` in the mask to check whether any of the *input* byte MSBs were
// set (i.e. the byte was outside the ASCII range).
mask := n | (n - (lsb * 0x20)) |
((n ^ (lsb * '"')) - lsb) |
((n ^ (lsb * '\\')) - lsb)
if (mask & msb) != 0 {
j = bits.TrailingZeros64(mask&msb) / 8
goto ESCAPE_END
}
}
valLen := len(s)
for i := len(chunks) * 8; i < valLen; i++ {
if needEscapeNormalizeUTF8[s[i]] {
j = i
goto ESCAPE_END
}
}
return append(append(buf, s...), '"')
}
ESCAPE_END:
for j < valLen {
c := s[j]
if !needEscapeNormalizeUTF8[c] {
// fast path: most of the time, printable ascii characters are used
j++
continue
}
switch c {
case '\\', '"':
buf = append(buf, s[i:j]...)
buf = append(buf, '\\', c)
i = j + 1
j = j + 1
continue
case '\n':
buf = append(buf, s[i:j]...)
buf = append(buf, '\\', 'n')
i = j + 1
j = j + 1
continue
case '\r':
buf = append(buf, s[i:j]...)
buf = append(buf, '\\', 'r')
i = j + 1
j = j + 1
continue
case '\t':
buf = append(buf, s[i:j]...)
buf = append(buf, '\\', 't')
i = j + 1
j = j + 1
continue
case 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x0B, 0x0C, 0x0E, 0x0F, // 0x00-0x0F
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F: // 0x10-0x1F
buf = append(buf, s[i:j]...) buf = append(buf, s[i:j]...)
buf = append(buf, `\u00`...) buf = append(buf, `\u00`...)
buf = append(buf, hex[c>>4], hex[c&0xF]) buf = append(buf, hex[c>>4], hex[c&0xF])
@ -501,18 +338,14 @@ ESCAPE_END:
continue continue
} }
r, size := utf8.DecodeRuneInString(s[j:]) state, size := decodeRuneInString(s[j:])
switch state {
if r == utf8.RuneError && size == 1 { case runeErrorState:
buf = append(buf, s[i:j]...) buf = append(buf, s[i:j]...)
buf = append(buf, `\ufffd`...) buf = append(buf, `\ufffd`...)
i = j + size i = j + 1
j = j + size j = j + 1
continue continue
}
switch r {
case '\u2028', '\u2029':
// U+2028 is LINE SEPARATOR. // U+2028 is LINE SEPARATOR.
// U+2029 is PARAGRAPH SEPARATOR. // U+2029 is PARAGRAPH SEPARATOR.
// They are both technically valid characters in JSON strings, // They are both technically valid characters in JSON strings,
@ -520,14 +353,19 @@ ESCAPE_END:
// and can lead to security holes there. It is valid JSON to // and can lead to security holes there. It is valid JSON to
// escape them, so we do so unconditionally. // escape them, so we do so unconditionally.
// See http://timelessrepo.com/json-isnt-a-javascript-subset for discussion. // See http://timelessrepo.com/json-isnt-a-javascript-subset for discussion.
case lineSepState:
buf = append(buf, s[i:j]...) buf = append(buf, s[i:j]...)
buf = append(buf, `\u202`...) buf = append(buf, `\u2028`...)
buf = append(buf, hex[r&0xF]) i = j + 3
i = j + size j = j + 3
j = j + size continue
case paragraphSepState:
buf = append(buf, s[i:j]...)
buf = append(buf, `\u2029`...)
i = j + 3
j = j + 3
continue continue
} }
j += size j += size
} }
@ -540,19 +378,37 @@ func appendString(buf []byte, s string) []byte {
return append(buf, `""`...) return append(buf, `""`...)
} }
buf = append(buf, '"') buf = append(buf, '"')
var escapeIdx int var (
i, j int
)
if valLen >= 8 { if valLen >= 8 {
if escapeIdx = escapeIndex(s); escapeIdx < 0 { chunks := stringToUint64Slice(s)
return append(append(buf, s...), '"') for _, n := range chunks {
// combine masks before checking for the MSB of each byte. We include
// `n` in the mask to check whether any of the *input* byte MSBs were
// set (i.e. the byte was outside the ASCII range).
mask := n | (n - (lsb * 0x20)) |
((n ^ (lsb * '"')) - lsb) |
((n ^ (lsb * '\\')) - lsb)
if (mask & msb) != 0 {
j = bits.TrailingZeros64(mask&msb) / 8
goto ESCAPE_END
}
} }
valLen := len(s)
for i := len(chunks) * 8; i < valLen; i++ {
if needEscape[s[i]] {
j = i
goto ESCAPE_END
}
}
return append(append(buf, s...), '"')
} }
ESCAPE_END:
i := 0
j := escapeIdx
for j < valLen { for j < valLen {
c := s[j] c := s[j]
if c >= 0x20 && c <= 0x7f && c != '\\' && c != '"' { if !needEscape[c] {
// fast path: most of the time, printable ascii characters are used // fast path: most of the time, printable ascii characters are used
j++ j++
continue continue
@ -587,7 +443,8 @@ func appendString(buf []byte, s string) []byte {
j = j + 1 j = j + 1
continue continue
case '<', '>', '&': case 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x0B, 0x0C, 0x0E, 0x0F, // 0x00-0x0F
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F: // 0x10-0x1F
buf = append(buf, s[i:j]...) buf = append(buf, s[i:j]...)
buf = append(buf, `\u00`...) buf = append(buf, `\u00`...)
buf = append(buf, hex[c>>4], hex[c&0xF]) buf = append(buf, hex[c>>4], hex[c&0xF])
@ -595,45 +452,7 @@ func appendString(buf []byte, s string) []byte {
j = j + 1 j = j + 1
continue continue
} }
j++
// This encodes bytes < 0x20 except for \t, \n and \r.
if c < 0x20 {
buf = append(buf, s[i:j]...)
buf = append(buf, `\u00`...)
buf = append(buf, hex[c>>4], hex[c&0xF])
i = j + 1
j = j + 1
continue
}
r, size := utf8.DecodeRuneInString(s[j:])
if r == utf8.RuneError && size == 1 {
buf = append(buf, s[i:j]...)
buf = append(buf, `\ufffd`...)
i = j + size
j = j + size
continue
}
switch r {
case '\u2028', '\u2029':
// U+2028 is LINE SEPARATOR.
// U+2029 is PARAGRAPH SEPARATOR.
// They are both technically valid characters in JSON strings,
// but don't work in JSONP, which has to be evaluated as JavaScript,
// and can lead to security holes there. It is valid JSON to
// escape them, so we do so unconditionally.
// See http://timelessrepo.com/json-isnt-a-javascript-subset for discussion.
buf = append(buf, s[i:j]...)
buf = append(buf, `\u202`...)
buf = append(buf, hex[r&0xF])
i = j + size
j = j + size
continue
}
j += size
} }
return append(append(buf, s[i:]...), '"') return append(append(buf, s[i:]...), '"')

View File

@ -0,0 +1,415 @@
package encoder
var needEscapeHTMLNormalizeUTF8 = [256]bool{
'"': true,
'&': true,
'<': true,
'>': true,
'\\': true,
0x00: true,
0x01: true,
0x02: true,
0x03: true,
0x04: true,
0x05: true,
0x06: true,
0x07: true,
0x08: true,
0x09: true,
0x0a: true,
0x0b: true,
0x0c: true,
0x0d: true,
0x0e: true,
0x0f: true,
0x10: true,
0x11: true,
0x12: true,
0x13: true,
0x14: true,
0x15: true,
0x16: true,
0x17: true,
0x18: true,
0x19: true,
0x1a: true,
0x1b: true,
0x1c: true,
0x1d: true,
0x1e: true,
0x1f: true,
/* 0x20 - 0x7f */
0x80: true,
0x81: true,
0x82: true,
0x83: true,
0x84: true,
0x85: true,
0x86: true,
0x87: true,
0x88: true,
0x89: true,
0x8a: true,
0x8b: true,
0x8c: true,
0x8d: true,
0x8e: true,
0x8f: true,
0x90: true,
0x91: true,
0x92: true,
0x93: true,
0x94: true,
0x95: true,
0x96: true,
0x97: true,
0x98: true,
0x99: true,
0x9a: true,
0x9b: true,
0x9c: true,
0x9d: true,
0x9e: true,
0x9f: true,
0xa0: true,
0xa1: true,
0xa2: true,
0xa3: true,
0xa4: true,
0xa5: true,
0xa6: true,
0xa7: true,
0xa8: true,
0xa9: true,
0xaa: true,
0xab: true,
0xac: true,
0xad: true,
0xae: true,
0xaf: true,
0xb0: true,
0xb1: true,
0xb2: true,
0xb3: true,
0xb4: true,
0xb5: true,
0xb6: true,
0xb7: true,
0xb8: true,
0xb9: true,
0xba: true,
0xbb: true,
0xbc: true,
0xbd: true,
0xbe: true,
0xbf: true,
0xc0: true,
0xc1: true,
0xc2: true,
0xc3: true,
0xc4: true,
0xc5: true,
0xc6: true,
0xc7: true,
0xc8: true,
0xc9: true,
0xca: true,
0xcb: true,
0xcc: true,
0xcd: true,
0xce: true,
0xcf: true,
0xd0: true,
0xd1: true,
0xd2: true,
0xd3: true,
0xd4: true,
0xd5: true,
0xd6: true,
0xd7: true,
0xd8: true,
0xd9: true,
0xda: true,
0xdb: true,
0xdc: true,
0xdd: true,
0xde: true,
0xdf: true,
0xe0: true,
0xe1: true,
0xe2: true,
0xe3: true,
0xe4: true,
0xe5: true,
0xe6: true,
0xe7: true,
0xe8: true,
0xe9: true,
0xea: true,
0xeb: true,
0xec: true,
0xed: true,
0xee: true,
0xef: true,
0xf0: true,
0xf1: true,
0xf2: true,
0xf3: true,
0xf4: true,
0xf5: true,
0xf6: true,
0xf7: true,
0xf8: true,
0xf9: true,
0xfa: true,
0xfb: true,
0xfc: true,
0xfd: true,
0xfe: true,
0xff: true,
}
var needEscapeNormalizeUTF8 = [256]bool{
'"': true,
'\\': true,
0x00: true,
0x01: true,
0x02: true,
0x03: true,
0x04: true,
0x05: true,
0x06: true,
0x07: true,
0x08: true,
0x09: true,
0x0a: true,
0x0b: true,
0x0c: true,
0x0d: true,
0x0e: true,
0x0f: true,
0x10: true,
0x11: true,
0x12: true,
0x13: true,
0x14: true,
0x15: true,
0x16: true,
0x17: true,
0x18: true,
0x19: true,
0x1a: true,
0x1b: true,
0x1c: true,
0x1d: true,
0x1e: true,
0x1f: true,
/* 0x20 - 0x7f */
0x80: true,
0x81: true,
0x82: true,
0x83: true,
0x84: true,
0x85: true,
0x86: true,
0x87: true,
0x88: true,
0x89: true,
0x8a: true,
0x8b: true,
0x8c: true,
0x8d: true,
0x8e: true,
0x8f: true,
0x90: true,
0x91: true,
0x92: true,
0x93: true,
0x94: true,
0x95: true,
0x96: true,
0x97: true,
0x98: true,
0x99: true,
0x9a: true,
0x9b: true,
0x9c: true,
0x9d: true,
0x9e: true,
0x9f: true,
0xa0: true,
0xa1: true,
0xa2: true,
0xa3: true,
0xa4: true,
0xa5: true,
0xa6: true,
0xa7: true,
0xa8: true,
0xa9: true,
0xaa: true,
0xab: true,
0xac: true,
0xad: true,
0xae: true,
0xaf: true,
0xb0: true,
0xb1: true,
0xb2: true,
0xb3: true,
0xb4: true,
0xb5: true,
0xb6: true,
0xb7: true,
0xb8: true,
0xb9: true,
0xba: true,
0xbb: true,
0xbc: true,
0xbd: true,
0xbe: true,
0xbf: true,
0xc0: true,
0xc1: true,
0xc2: true,
0xc3: true,
0xc4: true,
0xc5: true,
0xc6: true,
0xc7: true,
0xc8: true,
0xc9: true,
0xca: true,
0xcb: true,
0xcc: true,
0xcd: true,
0xce: true,
0xcf: true,
0xd0: true,
0xd1: true,
0xd2: true,
0xd3: true,
0xd4: true,
0xd5: true,
0xd6: true,
0xd7: true,
0xd8: true,
0xd9: true,
0xda: true,
0xdb: true,
0xdc: true,
0xdd: true,
0xde: true,
0xdf: true,
0xe0: true,
0xe1: true,
0xe2: true,
0xe3: true,
0xe4: true,
0xe5: true,
0xe6: true,
0xe7: true,
0xe8: true,
0xe9: true,
0xea: true,
0xeb: true,
0xec: true,
0xed: true,
0xee: true,
0xef: true,
0xf0: true,
0xf1: true,
0xf2: true,
0xf3: true,
0xf4: true,
0xf5: true,
0xf6: true,
0xf7: true,
0xf8: true,
0xf9: true,
0xfa: true,
0xfb: true,
0xfc: true,
0xfd: true,
0xfe: true,
0xff: true,
}
var needEscapeHTML = [256]bool{
'"': true,
'&': true,
'<': true,
'>': true,
'\\': true,
0x00: true,
0x01: true,
0x02: true,
0x03: true,
0x04: true,
0x05: true,
0x06: true,
0x07: true,
0x08: true,
0x09: true,
0x0a: true,
0x0b: true,
0x0c: true,
0x0d: true,
0x0e: true,
0x0f: true,
0x10: true,
0x11: true,
0x12: true,
0x13: true,
0x14: true,
0x15: true,
0x16: true,
0x17: true,
0x18: true,
0x19: true,
0x1a: true,
0x1b: true,
0x1c: true,
0x1d: true,
0x1e: true,
0x1f: true,
/* 0x20 - 0xff */
}
var needEscape = [256]bool{
'"': true,
'\\': true,
0x00: true,
0x01: true,
0x02: true,
0x03: true,
0x04: true,
0x05: true,
0x06: true,
0x07: true,
0x08: true,
0x09: true,
0x0a: true,
0x0b: true,
0x0c: true,
0x0d: true,
0x0e: true,
0x0f: true,
0x10: true,
0x11: true,
0x12: true,
0x13: true,
0x14: true,
0x15: true,
0x16: true,
0x17: true,
0x18: true,
0x19: true,
0x1a: true,
0x1b: true,
0x1c: true,
0x1d: true,
0x1e: true,
0x1f: true,
/* 0x20 - 0xff */
}

View File

@ -33,6 +33,15 @@ type emptyInterface struct {
ptr unsafe.Pointer ptr unsafe.Pointer
} }
type nonEmptyInterface struct {
itab *struct {
ityp *runtime.Type // static interface type
typ *runtime.Type // dynamic concrete type
// unused fields...
}
ptr unsafe.Pointer
}
func errUnimplementedOp(op encoder.OpType) error { func errUnimplementedOp(op encoder.OpType) error {
return fmt.Errorf("encoder: opcode %s has not been implemented", op) return fmt.Errorf("encoder: opcode %s has not been implemented", op)
} }
@ -59,7 +68,19 @@ func loadNPtr(base uintptr, idx uint32, ptrNum uint8) uintptr {
return p return p
} }
func ptrToUint64(p uintptr) uint64 { return **(**uint64)(unsafe.Pointer(&p)) } func ptrToUint64(p uintptr, bitSize uint8) uint64 {
switch bitSize {
case 8:
return (uint64)(**(**uint8)(unsafe.Pointer(&p)))
case 16:
return (uint64)(**(**uint16)(unsafe.Pointer(&p)))
case 32:
return (uint64)(**(**uint32)(unsafe.Pointer(&p)))
case 64:
return **(**uint64)(unsafe.Pointer(&p))
}
return 0
}
func ptrToFloat32(p uintptr) float32 { return **(**float32)(unsafe.Pointer(&p)) } func ptrToFloat32(p uintptr) float32 { return **(**float32)(unsafe.Pointer(&p)) }
func ptrToFloat64(p uintptr) float64 { return **(**float64)(unsafe.Pointer(&p)) } func ptrToFloat64(p uintptr) float64 { return **(**float64)(unsafe.Pointer(&p)) }
func ptrToBool(p uintptr) bool { return **(**bool)(unsafe.Pointer(&p)) } func ptrToBool(p uintptr) bool { return **(**bool)(unsafe.Pointer(&p)) }
@ -105,6 +126,10 @@ func appendComma(_ *encoder.RuntimeContext, b []byte) []byte {
return append(b, ',') return append(b, ',')
} }
func appendNullComma(_ *encoder.RuntimeContext, b []byte) []byte {
return append(b, "null,"...)
}
func appendColon(_ *encoder.RuntimeContext, b []byte) []byte { func appendColon(_ *encoder.RuntimeContext, b []byte) []byte {
last := len(b) - 1 last := len(b) - 1
b[last] = ':' b[last] = ':'

File diff suppressed because it is too large Load Diff

View File

@ -26,6 +26,15 @@ type emptyInterface struct {
ptr unsafe.Pointer ptr unsafe.Pointer
} }
type nonEmptyInterface struct {
itab *struct {
ityp *runtime.Type // static interface type
typ *runtime.Type // dynamic concrete type
// unused fields...
}
ptr unsafe.Pointer
}
func errUnimplementedOp(op encoder.OpType) error { func errUnimplementedOp(op encoder.OpType) error {
return fmt.Errorf("encoder: opcode %s has not been implemented", op) return fmt.Errorf("encoder: opcode %s has not been implemented", op)
} }
@ -52,7 +61,19 @@ func loadNPtr(base uintptr, idx uint32, ptrNum uint8) uintptr {
return p return p
} }
func ptrToUint64(p uintptr) uint64 { return **(**uint64)(unsafe.Pointer(&p)) } func ptrToUint64(p uintptr, bitSize uint8) uint64 {
switch bitSize {
case 8:
return (uint64)(**(**uint8)(unsafe.Pointer(&p)))
case 16:
return (uint64)(**(**uint16)(unsafe.Pointer(&p)))
case 32:
return (uint64)(**(**uint32)(unsafe.Pointer(&p)))
case 64:
return **(**uint64)(unsafe.Pointer(&p))
}
return 0
}
func ptrToFloat32(p uintptr) float32 { return **(**float32)(unsafe.Pointer(&p)) } func ptrToFloat32(p uintptr) float32 { return **(**float32)(unsafe.Pointer(&p)) }
func ptrToFloat64(p uintptr) float64 { return **(**float64)(unsafe.Pointer(&p)) } func ptrToFloat64(p uintptr) float64 { return **(**float64)(unsafe.Pointer(&p)) }
func ptrToBool(p uintptr) bool { return **(**bool)(unsafe.Pointer(&p)) } func ptrToBool(p uintptr) bool { return **(**bool)(unsafe.Pointer(&p)) }
@ -83,17 +104,17 @@ func ptrToInterface(code *encoder.Opcode, p uintptr) interface{} {
})) }))
} }
func appendInt(ctx *encoder.RuntimeContext, b []byte, v uint64, code *encoder.Opcode) []byte { func appendInt(ctx *encoder.RuntimeContext, b []byte, p uintptr, code *encoder.Opcode) []byte {
format := ctx.Option.ColorScheme.Int format := ctx.Option.ColorScheme.Int
b = append(b, format.Header...) b = append(b, format.Header...)
b = encoder.AppendInt(ctx, b, v, code) b = encoder.AppendInt(ctx, b, p, code)
return append(b, format.Footer...) return append(b, format.Footer...)
} }
func appendUint(ctx *encoder.RuntimeContext, b []byte, v uint64, code *encoder.Opcode) []byte { func appendUint(ctx *encoder.RuntimeContext, b []byte, p uintptr, code *encoder.Opcode) []byte {
format := ctx.Option.ColorScheme.Uint format := ctx.Option.ColorScheme.Uint
b = append(b, format.Header...) b = append(b, format.Header...)
b = encoder.AppendUint(ctx, b, v, code) b = encoder.AppendUint(ctx, b, p, code)
return append(b, format.Footer...) return append(b, format.Footer...)
} }
@ -157,6 +178,13 @@ func appendComma(_ *encoder.RuntimeContext, b []byte) []byte {
return append(b, ',') return append(b, ',')
} }
func appendNullComma(ctx *encoder.RuntimeContext, b []byte) []byte {
format := ctx.Option.ColorScheme.Null
b = append(b, format.Header...)
b = append(b, "null"...)
return append(append(b, format.Footer...), ',')
}
func appendColon(_ *encoder.RuntimeContext, b []byte) []byte { func appendColon(_ *encoder.RuntimeContext, b []byte) []byte {
last := len(b) - 1 last := len(b) - 1
b[last] = ':' b[last] = ':'

File diff suppressed because it is too large Load Diff

View File

@ -28,6 +28,15 @@ type emptyInterface struct {
ptr unsafe.Pointer ptr unsafe.Pointer
} }
type nonEmptyInterface struct {
itab *struct {
ityp *runtime.Type // static interface type
typ *runtime.Type // dynamic concrete type
// unused fields...
}
ptr unsafe.Pointer
}
func errUnimplementedOp(op encoder.OpType) error { func errUnimplementedOp(op encoder.OpType) error {
return fmt.Errorf("encoder (indent): opcode %s has not been implemented", op) return fmt.Errorf("encoder (indent): opcode %s has not been implemented", op)
} }
@ -54,7 +63,20 @@ func loadNPtr(base uintptr, idx uint32, ptrNum uint8) uintptr {
return p return p
} }
func ptrToUint64(p uintptr) uint64 { return **(**uint64)(unsafe.Pointer(&p)) } func ptrToUint64(p uintptr, bitSize uint8) uint64 {
switch bitSize {
case 8:
return (uint64)(**(**uint8)(unsafe.Pointer(&p)))
case 16:
return (uint64)(**(**uint16)(unsafe.Pointer(&p)))
case 32:
return (uint64)(**(**uint32)(unsafe.Pointer(&p)))
case 64:
return **(**uint64)(unsafe.Pointer(&p))
}
return 0
}
func ptrToFloat32(p uintptr) float32 { return **(**float32)(unsafe.Pointer(&p)) } func ptrToFloat32(p uintptr) float32 { return **(**float32)(unsafe.Pointer(&p)) }
func ptrToFloat64(p uintptr) float64 { return **(**float64)(unsafe.Pointer(&p)) } func ptrToFloat64(p uintptr) float64 { return **(**float64)(unsafe.Pointer(&p)) }
func ptrToBool(p uintptr) bool { return **(**bool)(unsafe.Pointer(&p)) } func ptrToBool(p uintptr) bool { return **(**bool)(unsafe.Pointer(&p)) }
@ -85,17 +107,17 @@ func ptrToInterface(code *encoder.Opcode, p uintptr) interface{} {
})) }))
} }
func appendInt(ctx *encoder.RuntimeContext, b []byte, v uint64, code *encoder.Opcode) []byte { func appendInt(ctx *encoder.RuntimeContext, b []byte, p uintptr, code *encoder.Opcode) []byte {
format := ctx.Option.ColorScheme.Int format := ctx.Option.ColorScheme.Int
b = append(b, format.Header...) b = append(b, format.Header...)
b = encoder.AppendInt(ctx, b, v, code) b = encoder.AppendInt(ctx, b, p, code)
return append(b, format.Footer...) return append(b, format.Footer...)
} }
func appendUint(ctx *encoder.RuntimeContext, b []byte, v uint64, code *encoder.Opcode) []byte { func appendUint(ctx *encoder.RuntimeContext, b []byte, p uintptr, code *encoder.Opcode) []byte {
format := ctx.Option.ColorScheme.Uint format := ctx.Option.ColorScheme.Uint
b = append(b, format.Header...) b = append(b, format.Header...)
b = encoder.AppendUint(ctx, b, v, code) b = encoder.AppendUint(ctx, b, p, code)
return append(b, format.Footer...) return append(b, format.Footer...)
} }
@ -159,6 +181,13 @@ func appendComma(_ *encoder.RuntimeContext, b []byte) []byte {
return append(b, ',', '\n') return append(b, ',', '\n')
} }
func appendNullComma(ctx *encoder.RuntimeContext, b []byte) []byte {
format := ctx.Option.ColorScheme.Null
b = append(b, format.Header...)
b = append(b, "null"...)
return append(append(b, format.Footer...), ',', '\n')
}
func appendColon(_ *encoder.RuntimeContext, b []byte) []byte { func appendColon(_ *encoder.RuntimeContext, b []byte) []byte {
return append(b, ':', ' ') return append(b, ':', ' ')
} }

File diff suppressed because it is too large Load Diff

View File

@ -35,6 +35,15 @@ type emptyInterface struct {
ptr unsafe.Pointer ptr unsafe.Pointer
} }
type nonEmptyInterface struct {
itab *struct {
ityp *runtime.Type // static interface type
typ *runtime.Type // dynamic concrete type
// unused fields...
}
ptr unsafe.Pointer
}
func errUnimplementedOp(op encoder.OpType) error { func errUnimplementedOp(op encoder.OpType) error {
return fmt.Errorf("encoder (indent): opcode %s has not been implemented", op) return fmt.Errorf("encoder (indent): opcode %s has not been implemented", op)
} }
@ -61,7 +70,19 @@ func loadNPtr(base uintptr, idx uint32, ptrNum uint8) uintptr {
return p return p
} }
func ptrToUint64(p uintptr) uint64 { return **(**uint64)(unsafe.Pointer(&p)) } func ptrToUint64(p uintptr, bitSize uint8) uint64 {
switch bitSize {
case 8:
return (uint64)(**(**uint8)(unsafe.Pointer(&p)))
case 16:
return (uint64)(**(**uint16)(unsafe.Pointer(&p)))
case 32:
return (uint64)(**(**uint32)(unsafe.Pointer(&p)))
case 64:
return **(**uint64)(unsafe.Pointer(&p))
}
return 0
}
func ptrToFloat32(p uintptr) float32 { return **(**float32)(unsafe.Pointer(&p)) } func ptrToFloat32(p uintptr) float32 { return **(**float32)(unsafe.Pointer(&p)) }
func ptrToFloat64(p uintptr) float64 { return **(**float64)(unsafe.Pointer(&p)) } func ptrToFloat64(p uintptr) float64 { return **(**float64)(unsafe.Pointer(&p)) }
func ptrToBool(p uintptr) bool { return **(**bool)(unsafe.Pointer(&p)) } func ptrToBool(p uintptr) bool { return **(**bool)(unsafe.Pointer(&p)) }
@ -107,6 +128,10 @@ func appendComma(_ *encoder.RuntimeContext, b []byte) []byte {
return append(b, ',', '\n') return append(b, ',', '\n')
} }
func appendNullComma(_ *encoder.RuntimeContext, b []byte) []byte {
return append(b, "null,\n"...)
}
func appendColon(_ *encoder.RuntimeContext, b []byte) []byte { func appendColon(_ *encoder.RuntimeContext, b []byte) []byte {
return append(b, ':', ' ') return append(b, ':', ' ')
} }

File diff suppressed because it is too large Load Diff

View File

@ -364,3 +364,8 @@ func Valid(data []byte) bool {
} }
return decoder.InputOffset() >= int64(len(data)) return decoder.InputOffset() >= int64(len(data))
} }
func init() {
encoder.Marshal = Marshal
encoder.Unmarshal = Unmarshal
}

View File

@ -15,6 +15,23 @@ func UnorderedMap() EncodeOptionFunc {
} }
} }
// DisableHTMLEscape disables escaping of HTML characters ( '&', '<', '>' ) when encoding string.
func DisableHTMLEscape() EncodeOptionFunc {
return func(opt *EncodeOption) {
opt.Flag &= ^encoder.HTMLEscapeOption
}
}
// DisableNormalizeUTF8
// By default, when encoding string, UTF8 characters in the range of 0x80 - 0xFF are processed by applying \ufffd for invalid code and escaping for \u2028 and \u2029.
// This option disables this behaviour. You can expect faster speeds by applying this option, but be careful.
// encoding/json implements here: https://github.com/golang/go/blob/6178d25fc0b28724b1b5aec2b1b74fc06d9294c7/src/encoding/json/encode.go#L1067-L1093.
func DisableNormalizeUTF8() EncodeOptionFunc {
return func(opt *EncodeOption) {
opt.Flag &= ^encoder.NormalizeUTF8Option
}
}
// Debug outputs debug information when panic occurs during encoding. // Debug outputs debug information when panic occurs during encoding.
func Debug() EncodeOptionFunc { func Debug() EncodeOptionFunc {
return func(opt *EncodeOption) { return func(opt *EncodeOption) {

47
vendor/github.com/goccy/go-json/query.go generated vendored Normal file
View File

@ -0,0 +1,47 @@
package json
import (
"github.com/goccy/go-json/internal/encoder"
)
type (
// FieldQuery you can dynamically filter the fields in the structure by creating a FieldQuery,
// adding it to context.Context using SetFieldQueryToContext and then passing it to MarshalContext.
// This is a type-safe operation, so it is faster than filtering using map[string]interface{}.
FieldQuery = encoder.FieldQuery
FieldQueryString = encoder.FieldQueryString
)
var (
// FieldQueryFromContext get current FieldQuery from context.Context.
FieldQueryFromContext = encoder.FieldQueryFromContext
// SetFieldQueryToContext set current FieldQuery to context.Context.
SetFieldQueryToContext = encoder.SetFieldQueryToContext
)
// BuildFieldQuery builds FieldQuery by fieldName or sub field query.
// First, specify the field name that you want to keep in structure type.
// If the field you want to keep is a structure type, by creating a sub field query using BuildSubFieldQuery,
// you can select the fields you want to keep in the structure.
// This description can be written recursively.
func BuildFieldQuery(fields ...FieldQueryString) (*FieldQuery, error) {
query, err := Marshal(fields)
if err != nil {
return nil, err
}
return FieldQueryString(query).Build()
}
// BuildSubFieldQuery builds sub field query.
func BuildSubFieldQuery(name string) *SubFieldQuery {
return &SubFieldQuery{name: name}
}
type SubFieldQuery struct {
name string
}
func (q *SubFieldQuery) Fields(fields ...FieldQueryString) FieldQueryString {
query, _ := Marshal(map[string][]FieldQueryString{q.name: fields})
return FieldQueryString(query)
}

View File

@ -8,8 +8,6 @@
A high-performance 100% compatible drop-in replacement of "encoding/json" A high-performance 100% compatible drop-in replacement of "encoding/json"
You can also use thrift like JSON using [thrift-iterator](https://github.com/thrift-iterator/go)
# Benchmark # Benchmark
![benchmark](http://jsoniter.com/benchmarks/go-benchmark.png) ![benchmark](http://jsoniter.com/benchmarks/go-benchmark.png)

View File

@ -1,5 +1,96 @@
# Changelog # Changelog
## v4.7.2 - 2022-03-16
**Fixes**
* Fix nil pointer exception when calling Start again after address binding error [#2131](https://github.com/labstack/echo/pull/2131)
* Fix CSRF middleware not being able to extract token from multipart/form-data form [#2136](https://github.com/labstack/echo/pull/2136)
* Fix Timeout middleware write race [#2126](https://github.com/labstack/echo/pull/2126)
**Enhancements**
* Recover middleware should not log panic for aborted handler [#2134](https://github.com/labstack/echo/pull/2134)
## v4.7.1 - 2022-03-13
**Fixes**
* Fix `e.Static`, `.File()`, `c.Attachment()` being picky with paths starting with `./`, `../` and `/` after 4.7.0 introduced echo.Filesystem support (Go1.16+) [#2123](https://github.com/labstack/echo/pull/2123)
**Enhancements**
* Remove some unused code [#2116](https://github.com/labstack/echo/pull/2116)
## v4.7.0 - 2022-03-01
**Enhancements**
* Add JWT, KeyAuth, CSRF multivalue extractors [#2060](https://github.com/labstack/echo/pull/2060)
* Add LogErrorFunc to recover middleware [#2072](https://github.com/labstack/echo/pull/2072)
* Add support for HEAD method query params binding [#2027](https://github.com/labstack/echo/pull/2027)
* Improve filesystem support with echo.FileFS, echo.StaticFS, group.FileFS, group.StaticFS [#2064](https://github.com/labstack/echo/pull/2064)
**Fixes**
* Fix X-Real-IP bug, improve tests [#2007](https://github.com/labstack/echo/pull/2007)
* Minor syntax fixes [#1994](https://github.com/labstack/echo/pull/1994), [#2102](https://github.com/labstack/echo/pull/2102), [#2102](https://github.com/labstack/echo/pull/2102)
**General**
* Add cache-control and connection headers [#2103](https://github.com/labstack/echo/pull/2103)
* Add Retry-After header constant [#2078](https://github.com/labstack/echo/pull/2078)
* Upgrade `go` directive in `go.mod` to 1.17 [#2049](https://github.com/labstack/echo/pull/2049)
* Add Pagoda [#2077](https://github.com/labstack/echo/pull/2077) and Souin [#2069](https://github.com/labstack/echo/pull/2069) to 3rd-party middlewares in README
## v4.6.3 - 2022-01-10
**Fixes**
* Fixed Echo version number in greeting message which was not incremented to `4.6.2` [#2066](https://github.com/labstack/echo/issues/2066)
## v4.6.2 - 2022-01-08
**Fixes**
* Fixed route containing escaped colon should be matchable but is not matched to request path [#2047](https://github.com/labstack/echo/pull/2047)
* Fixed a problem that returned wrong content-encoding when the gzip compressed content was empty. [#1921](https://github.com/labstack/echo/pull/1921)
* Update (test) dependencies [#2021](https://github.com/labstack/echo/pull/2021)
**Enhancements**
* Add support for configurable target header for the request_id middleware [#2040](https://github.com/labstack/echo/pull/2040)
* Change decompress middleware to use stream decompression instead of buffering [#2018](https://github.com/labstack/echo/pull/2018)
* Documentation updates
## v4.6.1 - 2021-09-26
**Enhancements**
* Add start time to request logger middleware values [#1991](https://github.com/labstack/echo/pull/1991)
## v4.6.0 - 2021-09-20
Introduced a new [request logger](https://github.com/labstack/echo/blob/master/middleware/request_logger.go) middleware
to help with cases when you want to use some other logging library in your application.
**Fixes**
* fix timeout middleware warning: superfluous response.WriteHeader [#1905](https://github.com/labstack/echo/issues/1905)
**Enhancements**
* Add Cookie to KeyAuth middleware's KeyLookup [#1929](https://github.com/labstack/echo/pull/1929)
* JWT middleware should ignore case of auth scheme in request header [#1951](https://github.com/labstack/echo/pull/1951)
* Refactor default error handler to return first if response is already committed [#1956](https://github.com/labstack/echo/pull/1956)
* Added request logger middleware which helps to use custom logger library for logging requests. [#1980](https://github.com/labstack/echo/pull/1980)
* Allow escaping of colon in route path so Google Cloud API "custom methods" could be implemented [#1988](https://github.com/labstack/echo/pull/1988)
## v4.5.0 - 2021-08-01 ## v4.5.0 - 2021-08-01
**Important notes** **Important notes**

View File

@ -5,7 +5,6 @@
[![Go Report Card](https://goreportcard.com/badge/github.com/labstack/echo?style=flat-square)](https://goreportcard.com/report/github.com/labstack/echo) [![Go Report Card](https://goreportcard.com/badge/github.com/labstack/echo?style=flat-square)](https://goreportcard.com/report/github.com/labstack/echo)
[![Build Status](http://img.shields.io/travis/labstack/echo.svg?style=flat-square)](https://travis-ci.org/labstack/echo) [![Build Status](http://img.shields.io/travis/labstack/echo.svg?style=flat-square)](https://travis-ci.org/labstack/echo)
[![Codecov](https://img.shields.io/codecov/c/github/labstack/echo.svg?style=flat-square)](https://codecov.io/gh/labstack/echo) [![Codecov](https://img.shields.io/codecov/c/github/labstack/echo.svg?style=flat-square)](https://codecov.io/gh/labstack/echo)
[![Join the chat at https://gitter.im/labstack/echo](https://img.shields.io/badge/gitter-join%20chat-brightgreen.svg?style=flat-square)](https://gitter.im/labstack/echo)
[![Forum](https://img.shields.io/badge/community-forum-00afd1.svg?style=flat-square)](https://github.com/labstack/echo/discussions) [![Forum](https://img.shields.io/badge/community-forum-00afd1.svg?style=flat-square)](https://github.com/labstack/echo/discussions)
[![Twitter](https://img.shields.io/badge/twitter-@labstack-55acee.svg?style=flat-square)](https://twitter.com/labstack) [![Twitter](https://img.shields.io/badge/twitter-@labstack-55acee.svg?style=flat-square)](https://twitter.com/labstack)
[![License](http://img.shields.io/badge/license-mit-blue.svg?style=flat-square)](https://raw.githubusercontent.com/labstack/echo/master/LICENSE) [![License](http://img.shields.io/badge/license-mit-blue.svg?style=flat-square)](https://raw.githubusercontent.com/labstack/echo/master/LICENSE)
@ -66,9 +65,9 @@ go get github.com/labstack/echo/v4
package main package main
import ( import (
"net/http"
"github.com/labstack/echo/v4" "github.com/labstack/echo/v4"
"github.com/labstack/echo/v4/middleware" "github.com/labstack/echo/v4/middleware"
"net/http"
) )
func main() { func main() {
@ -92,10 +91,23 @@ func hello(c echo.Context) error {
} }
``` ```
# Third-party middlewares
| Repository | Description |
|------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| [github.com/labstack/echo-contrib](https://github.com/labstack/echo-contrib) | (by Echo team) [casbin](https://github.com/casbin/casbin), [gorilla/sessions](https://github.com/gorilla/sessions), [jaegertracing](github.com/uber/jaeger-client-go), [prometheus](https://github.com/prometheus/client_golang/), [pprof](https://pkg.go.dev/net/http/pprof), [zipkin](https://github.com/openzipkin/zipkin-go) middlewares |
| [deepmap/oapi-codegen](https://github.com/deepmap/oapi-codegen) | Automatically generate RESTful API documentation with [OpenAPI](https://swagger.io/specification/) Client and Server Code Generator |
| [github.com/swaggo/echo-swagger](https://github.com/swaggo/echo-swagger) | Automatically generate RESTful API documentation with [Swagger](https://swagger.io/) 2.0. |
| [github.com/ziflex/lecho](https://github.com/ziflex/lecho) | [Zerolog](https://github.com/rs/zerolog) logging library wrapper for Echo logger interface. |
| [github.com/brpaz/echozap](https://github.com/brpaz/echozap) | Uber´s [Zap](https://github.com/uber-go/zap) logging library wrapper for Echo logger interface. |
| [github.com/darkweak/souin/plugins/echo](https://github.com/darkweak/souin/tree/master/plugins/echo) | HTTP cache system based on [Souin](https://github.com/darkweak/souin) to automatically get your endpoints cached. It supports some distributed and non-distributed storage systems depending your needs. |
| [github.com/mikestefanello/pagoda](https://github.com/mikestefanello/pagoda) | Rapid, easy full-stack web development starter kit built with Echo.
Please send a PR to add your own library here.
## Help ## Help
- [Forum](https://github.com/labstack/echo/discussions) - [Forum](https://github.com/labstack/echo/discussions)
- [Chat](https://gitter.im/labstack/echo)
## Contribute ## Contribute
@ -114,8 +126,11 @@ func hello(c echo.Context) error {
## Credits ## Credits
- [Vishal Rana](https://github.com/vishr) - Author - [Vishal Rana](https://github.com/vishr) (Author)
- [Nitin Rana](https://github.com/nr17) - Consultant - [Nitin Rana](https://github.com/nr17) (Consultant)
- [Roland Lammel](https://github.com/lammel) (Maintainer)
- [Martti T.](https://github.com/aldas) (Maintainer)
- [Pablo Andres Fuente](https://github.com/pafuent) (Maintainer)
- [Contributors](https://github.com/labstack/echo/graphs/contributors) - [Contributors](https://github.com/labstack/echo/graphs/contributors)
## License ## License

View File

@ -111,11 +111,11 @@ func (b *DefaultBinder) Bind(i interface{}, c Context) (err error) {
if err := b.BindPathParams(c, i); err != nil { if err := b.BindPathParams(c, i); err != nil {
return err return err
} }
// Issue #1670 - Query params are binded only for GET/DELETE and NOT for usual request with body (POST/PUT/PATCH) // Only bind query parameters for GET/DELETE/HEAD to avoid unexpected behavior with destination struct binding from body.
// Reasoning here is that parameters in query and bind destination struct could have UNEXPECTED matches and results due that. // For example a request URL `&id=1&lang=en` with body `{"id":100,"lang":"de"}` would lead to precedence issues.
// i.e. is `&id=1&lang=en` from URL same as `{"id":100,"lang":"de"}` request body and which one should have priority when binding. // The HTTP method check restores pre-v4.1.11 behavior to avoid these problems (see issue #1670)
// This HTTP method check restores pre v4.1.11 behavior and avoids different problems when query is mixed with body method := c.Request().Method
if c.Request().Method == http.MethodGet || c.Request().Method == http.MethodDelete { if method == http.MethodGet || method == http.MethodDelete || method == http.MethodHead {
if err = b.BindQueryParams(c, i); err != nil { if err = b.BindQueryParams(c, i); err != nil {
return err return err
} }

View File

@ -9,8 +9,6 @@ import (
"net" "net"
"net/http" "net/http"
"net/url" "net/url"
"os"
"path/filepath"
"strings" "strings"
"sync" "sync"
) )
@ -210,6 +208,13 @@ type (
} }
) )
const (
// ContextKeyHeaderAllow is set by Router for getting value for `Allow` header in later stages of handler call chain.
// Allow header is mandatory for status 405 (method not found) and useful for OPTIONS method requests.
// It is added to context only when Router does not find matching method handler for request.
ContextKeyHeaderAllow = "echo_header_allow"
)
const ( const (
defaultMemory = 32 << 20 // 32 MB defaultMemory = 32 << 20 // 32 MB
indexPage = "index.html" indexPage = "index.html"
@ -562,29 +567,6 @@ func (c *context) Stream(code int, contentType string, r io.Reader) (err error)
return return
} }
func (c *context) File(file string) (err error) {
f, err := os.Open(file)
if err != nil {
return NotFoundHandler(c)
}
defer f.Close()
fi, _ := f.Stat()
if fi.IsDir() {
file = filepath.Join(file, indexPage)
f, err = os.Open(file)
if err != nil {
return NotFoundHandler(c)
}
defer f.Close()
if fi, err = f.Stat(); err != nil {
return
}
}
http.ServeContent(c.Response(), c.Request(), fi.Name(), fi.ModTime(), f)
return
}
func (c *context) Attachment(file, name string) error { func (c *context) Attachment(file, name string) error {
return c.contentDisposition(file, name, "attachment") return c.contentDisposition(file, name, "attachment")
} }

33
vendor/github.com/labstack/echo/v4/context_fs.go generated vendored Normal file
View File

@ -0,0 +1,33 @@
//go:build !go1.16
// +build !go1.16
package echo
import (
"net/http"
"os"
"path/filepath"
)
func (c *context) File(file string) (err error) {
f, err := os.Open(file)
if err != nil {
return NotFoundHandler(c)
}
defer f.Close()
fi, _ := f.Stat()
if fi.IsDir() {
file = filepath.Join(file, indexPage)
f, err = os.Open(file)
if err != nil {
return NotFoundHandler(c)
}
defer f.Close()
if fi, err = f.Stat(); err != nil {
return
}
}
http.ServeContent(c.Response(), c.Request(), fi.Name(), fi.ModTime(), f)
return
}

View File

@ -0,0 +1,52 @@
//go:build go1.16
// +build go1.16
package echo
import (
"errors"
"io"
"io/fs"
"net/http"
"path/filepath"
)
func (c *context) File(file string) error {
return fsFile(c, file, c.echo.Filesystem)
}
// FileFS serves file from given file system.
//
// When dealing with `embed.FS` use `fs := echo.MustSubFS(fs, "rootDirectory") to create sub fs which uses necessary
// prefix for directory path. This is necessary as `//go:embed assets/images` embeds files with paths
// including `assets/images` as their prefix.
func (c *context) FileFS(file string, filesystem fs.FS) error {
return fsFile(c, file, filesystem)
}
func fsFile(c Context, file string, filesystem fs.FS) error {
f, err := filesystem.Open(file)
if err != nil {
return ErrNotFound
}
defer f.Close()
fi, _ := f.Stat()
if fi.IsDir() {
file = filepath.ToSlash(filepath.Join(file, indexPage)) // ToSlash is necessary for Windows. fs.Open and os.Open are different in that aspect.
f, err = filesystem.Open(file)
if err != nil {
return ErrNotFound
}
defer f.Close()
if fi, err = f.Stat(); err != nil {
return err
}
}
ff, ok := f.(io.ReadSeeker)
if !ok {
return errors.New("file does not implement io.ReadSeeker")
}
http.ServeContent(c.Response(), c.Request(), fi.Name(), fi.ModTime(), ff)
return nil
}

View File

@ -47,9 +47,6 @@ import (
stdLog "log" stdLog "log"
"net" "net"
"net/http" "net/http"
"net/url"
"os"
"path/filepath"
"reflect" "reflect"
"runtime" "runtime"
"sync" "sync"
@ -66,6 +63,7 @@ import (
type ( type (
// Echo is the top-level framework instance. // Echo is the top-level framework instance.
Echo struct { Echo struct {
filesystem
common common
// startupMutex is mutex to lock Echo instance access during server configuration and startup. Useful for to get // startupMutex is mutex to lock Echo instance access during server configuration and startup. Useful for to get
// listener address info (on which interface/port was listener binded) without having data races. // listener address info (on which interface/port was listener binded) without having data races.
@ -77,7 +75,6 @@ type (
maxParam *int maxParam *int
router *Router router *Router
routers map[string]*Router routers map[string]*Router
notFoundHandler HandlerFunc
pool sync.Pool pool sync.Pool
Server *http.Server Server *http.Server
TLSServer *http.Server TLSServer *http.Server
@ -113,10 +110,10 @@ type (
} }
// MiddlewareFunc defines a function to process middleware. // MiddlewareFunc defines a function to process middleware.
MiddlewareFunc func(HandlerFunc) HandlerFunc MiddlewareFunc func(next HandlerFunc) HandlerFunc
// HandlerFunc defines a function to serve HTTP requests. // HandlerFunc defines a function to serve HTTP requests.
HandlerFunc func(Context) error HandlerFunc func(c Context) error
// HTTPErrorHandler is a centralized HTTP error handler. // HTTPErrorHandler is a centralized HTTP error handler.
HTTPErrorHandler func(error, Context) HTTPErrorHandler func(error, Context)
@ -190,8 +187,12 @@ const (
// Headers // Headers
const ( const (
HeaderAccept = "Accept" HeaderAccept = "Accept"
HeaderAcceptEncoding = "Accept-Encoding" HeaderAcceptEncoding = "Accept-Encoding"
// HeaderAllow is the name of the "Allow" header field used to list the set of methods
// advertised as supported by the target resource. Returning an Allow header is mandatory
// for status 405 (method not found) and useful for the OPTIONS method in responses.
// See RFC 7231: https://datatracker.ietf.org/doc/html/rfc7231#section-7.4.1
HeaderAllow = "Allow" HeaderAllow = "Allow"
HeaderAuthorization = "Authorization" HeaderAuthorization = "Authorization"
HeaderContentDisposition = "Content-Disposition" HeaderContentDisposition = "Content-Disposition"
@ -203,6 +204,7 @@ const (
HeaderIfModifiedSince = "If-Modified-Since" HeaderIfModifiedSince = "If-Modified-Since"
HeaderLastModified = "Last-Modified" HeaderLastModified = "Last-Modified"
HeaderLocation = "Location" HeaderLocation = "Location"
HeaderRetryAfter = "Retry-After"
HeaderUpgrade = "Upgrade" HeaderUpgrade = "Upgrade"
HeaderVary = "Vary" HeaderVary = "Vary"
HeaderWWWAuthenticate = "WWW-Authenticate" HeaderWWWAuthenticate = "WWW-Authenticate"
@ -212,11 +214,14 @@ const (
HeaderXForwardedSsl = "X-Forwarded-Ssl" HeaderXForwardedSsl = "X-Forwarded-Ssl"
HeaderXUrlScheme = "X-Url-Scheme" HeaderXUrlScheme = "X-Url-Scheme"
HeaderXHTTPMethodOverride = "X-HTTP-Method-Override" HeaderXHTTPMethodOverride = "X-HTTP-Method-Override"
HeaderXRealIP = "X-Real-IP" HeaderXRealIP = "X-Real-Ip"
HeaderXRequestID = "X-Request-ID" HeaderXRequestID = "X-Request-Id"
HeaderXCorrelationID = "X-Correlation-Id"
HeaderXRequestedWith = "X-Requested-With" HeaderXRequestedWith = "X-Requested-With"
HeaderServer = "Server" HeaderServer = "Server"
HeaderOrigin = "Origin" HeaderOrigin = "Origin"
HeaderCacheControl = "Cache-Control"
HeaderConnection = "Connection"
// Access control // Access control
HeaderAccessControlRequestMethod = "Access-Control-Request-Method" HeaderAccessControlRequestMethod = "Access-Control-Request-Method"
@ -241,7 +246,7 @@ const (
const ( const (
// Version of Echo // Version of Echo
Version = "4.5.0" Version = "4.7.2"
website = "https://echo.labstack.com" website = "https://echo.labstack.com"
// http://patorjk.com/software/taag/#p=display&f=Small%20Slant&t=Echo // http://patorjk.com/software/taag/#p=display&f=Small%20Slant&t=Echo
banner = ` banner = `
@ -301,6 +306,12 @@ var (
} }
MethodNotAllowedHandler = func(c Context) error { MethodNotAllowedHandler = func(c Context) error {
// See RFC 7231 section 7.4.1: An origin server MUST generate an Allow field in a 405 (Method Not Allowed)
// response and MAY do so in any other response. For disabled resources an empty Allow header may be returned
routerAllowMethods, ok := c.Get(ContextKeyHeaderAllow).(string)
if ok && routerAllowMethods != "" {
c.Response().Header().Set(HeaderAllow, routerAllowMethods)
}
return ErrMethodNotAllowed return ErrMethodNotAllowed
} }
) )
@ -308,8 +319,9 @@ var (
// New creates an instance of Echo. // New creates an instance of Echo.
func New() (e *Echo) { func New() (e *Echo) {
e = &Echo{ e = &Echo{
Server: new(http.Server), filesystem: createFilesystem(),
TLSServer: new(http.Server), Server: new(http.Server),
TLSServer: new(http.Server),
AutoTLSManager: autocert.Manager{ AutoTLSManager: autocert.Manager{
Prompt: autocert.AcceptTOS, Prompt: autocert.AcceptTOS,
}, },
@ -357,7 +369,17 @@ func (e *Echo) Routers() map[string]*Router {
// DefaultHTTPErrorHandler is the default HTTP error handler. It sends a JSON response // DefaultHTTPErrorHandler is the default HTTP error handler. It sends a JSON response
// with status code. // with status code.
//
// NOTE: In case errors happens in middleware call-chain that is returning from handler (which did not return an error).
// When handler has already sent response (ala c.JSON()) and there is error in middleware that is returning from
// handler. Then the error that global error handler received will be ignored because we have already "commited" the
// response and status code header has been sent to the client.
func (e *Echo) DefaultHTTPErrorHandler(err error, c Context) { func (e *Echo) DefaultHTTPErrorHandler(err error, c Context) {
if c.Response().Committed {
return
}
he, ok := err.(*HTTPError) he, ok := err.(*HTTPError)
if ok { if ok {
if he.Internal != nil { if he.Internal != nil {
@ -384,15 +406,13 @@ func (e *Echo) DefaultHTTPErrorHandler(err error, c Context) {
} }
// Send response // Send response
if !c.Response().Committed { if c.Request().Method == http.MethodHead { // Issue #608
if c.Request().Method == http.MethodHead { // Issue #608 err = c.NoContent(he.Code)
err = c.NoContent(he.Code) } else {
} else { err = c.JSON(code, message)
err = c.JSON(code, message) }
} if err != nil {
if err != nil { e.Logger.Error(err)
e.Logger.Error(err)
}
} }
} }
@ -480,50 +500,6 @@ func (e *Echo) Match(methods []string, path string, handler HandlerFunc, middlew
return routes return routes
} }
// Static registers a new route with path prefix to serve static files from the
// provided root directory.
func (e *Echo) Static(prefix, root string) *Route {
if root == "" {
root = "." // For security we want to restrict to CWD.
}
return e.static(prefix, root, e.GET)
}
func (common) static(prefix, root string, get func(string, HandlerFunc, ...MiddlewareFunc) *Route) *Route {
h := func(c Context) error {
p, err := url.PathUnescape(c.Param("*"))
if err != nil {
return err
}
name := filepath.Join(root, filepath.Clean("/"+p)) // "/"+ for security
fi, err := os.Stat(name)
if err != nil {
// The access path does not exist
return NotFoundHandler(c)
}
// If the request is for a directory and does not end with "/"
p = c.Request().URL.Path // path must not be empty.
if fi.IsDir() && p[len(p)-1] != '/' {
// Redirect to ends with "/"
return c.Redirect(http.StatusMovedPermanently, p+"/")
}
return c.File(name)
}
// Handle added routes based on trailing slash:
// /prefix => exact route "/prefix" + any route "/prefix/*"
// /prefix/ => only any route "/prefix/*"
if prefix != "" {
if prefix[len(prefix)-1] == '/' {
// Only add any route for intentional trailing slash
return get(prefix+"*", h)
}
get(prefix, h)
}
return get(prefix+"/*", h)
}
func (common) file(path, file string, get func(string, HandlerFunc, ...MiddlewareFunc) *Route, func (common) file(path, file string, get func(string, HandlerFunc, ...MiddlewareFunc) *Route,
m ...MiddlewareFunc) *Route { m ...MiddlewareFunc) *Route {
return get(path, func(c Context) error { return get(path, func(c Context) error {
@ -634,7 +610,7 @@ func (e *Echo) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// Acquire context // Acquire context
c := e.pool.Get().(*context) c := e.pool.Get().(*context)
c.Reset(r, w) c.Reset(r, w)
h := NotFoundHandler var h func(Context) error
if e.premiddleware == nil { if e.premiddleware == nil {
e.findRouter(r.Host).Find(r.Method, GetPath(r), c) e.findRouter(r.Host).Find(r.Method, GetPath(r), c)
@ -756,7 +732,7 @@ func (e *Echo) StartServer(s *http.Server) (err error) {
return s.Serve(e.Listener) return s.Serve(e.Listener)
} }
func (e *Echo) configureServer(s *http.Server) (err error) { func (e *Echo) configureServer(s *http.Server) error {
// Setup // Setup
e.colorer.SetOutput(e.Logger.Output()) e.colorer.SetOutput(e.Logger.Output())
s.ErrorLog = e.StdLogger s.ErrorLog = e.StdLogger
@ -771,10 +747,11 @@ func (e *Echo) configureServer(s *http.Server) (err error) {
if s.TLSConfig == nil { if s.TLSConfig == nil {
if e.Listener == nil { if e.Listener == nil {
e.Listener, err = newListener(s.Addr, e.ListenerNetwork) l, err := newListener(s.Addr, e.ListenerNetwork)
if err != nil { if err != nil {
return err return err
} }
e.Listener = l
} }
if !e.HidePort { if !e.HidePort {
e.colorer.Printf("⇨ http server started on %s\n", e.colorer.Green(e.Listener.Addr())) e.colorer.Printf("⇨ http server started on %s\n", e.colorer.Green(e.Listener.Addr()))
@ -815,7 +792,7 @@ func (e *Echo) TLSListenerAddr() net.Addr {
} }
// StartH2CServer starts a custom http/2 server with h2c (HTTP/2 Cleartext). // StartH2CServer starts a custom http/2 server with h2c (HTTP/2 Cleartext).
func (e *Echo) StartH2CServer(address string, h2s *http2.Server) (err error) { func (e *Echo) StartH2CServer(address string, h2s *http2.Server) error {
e.startupMutex.Lock() e.startupMutex.Lock()
// Setup // Setup
s := e.Server s := e.Server
@ -832,11 +809,12 @@ func (e *Echo) StartH2CServer(address string, h2s *http2.Server) (err error) {
} }
if e.Listener == nil { if e.Listener == nil {
e.Listener, err = newListener(s.Addr, e.ListenerNetwork) l, err := newListener(s.Addr, e.ListenerNetwork)
if err != nil { if err != nil {
e.startupMutex.Unlock() e.startupMutex.Unlock()
return err return err
} }
e.Listener = l
} }
if !e.HidePort { if !e.HidePort {
e.colorer.Printf("⇨ http server started on %s\n", e.colorer.Green(e.Listener.Addr())) e.colorer.Printf("⇨ http server started on %s\n", e.colorer.Green(e.Listener.Addr()))

62
vendor/github.com/labstack/echo/v4/echo_fs.go generated vendored Normal file
View File

@ -0,0 +1,62 @@
//go:build !go1.16
// +build !go1.16
package echo
import (
"net/http"
"net/url"
"os"
"path/filepath"
)
type filesystem struct {
}
func createFilesystem() filesystem {
return filesystem{}
}
// Static registers a new route with path prefix to serve static files from the
// provided root directory.
func (e *Echo) Static(prefix, root string) *Route {
if root == "" {
root = "." // For security we want to restrict to CWD.
}
return e.static(prefix, root, e.GET)
}
func (common) static(prefix, root string, get func(string, HandlerFunc, ...MiddlewareFunc) *Route) *Route {
h := func(c Context) error {
p, err := url.PathUnescape(c.Param("*"))
if err != nil {
return err
}
name := filepath.Join(root, filepath.Clean("/"+p)) // "/"+ for security
fi, err := os.Stat(name)
if err != nil {
// The access path does not exist
return NotFoundHandler(c)
}
// If the request is for a directory and does not end with "/"
p = c.Request().URL.Path // path must not be empty.
if fi.IsDir() && p[len(p)-1] != '/' {
// Redirect to ends with "/"
return c.Redirect(http.StatusMovedPermanently, p+"/")
}
return c.File(name)
}
// Handle added routes based on trailing slash:
// /prefix => exact route "/prefix" + any route "/prefix/*"
// /prefix/ => only any route "/prefix/*"
if prefix != "" {
if prefix[len(prefix)-1] == '/' {
// Only add any route for intentional trailing slash
return get(prefix+"*", h)
}
get(prefix, h)
}
return get(prefix+"/*", h)
}

169
vendor/github.com/labstack/echo/v4/echo_fs_go1.16.go generated vendored Normal file
View File

@ -0,0 +1,169 @@
//go:build go1.16
// +build go1.16
package echo
import (
"fmt"
"io/fs"
"net/http"
"net/url"
"os"
"path/filepath"
"runtime"
"strings"
)
type filesystem struct {
// Filesystem is file system used by Static and File handlers to access files.
// Defaults to os.DirFS(".")
//
// When dealing with `embed.FS` use `fs := echo.MustSubFS(fs, "rootDirectory") to create sub fs which uses necessary
// prefix for directory path. This is necessary as `//go:embed assets/images` embeds files with paths
// including `assets/images` as their prefix.
Filesystem fs.FS
}
func createFilesystem() filesystem {
return filesystem{
Filesystem: newDefaultFS(),
}
}
// Static registers a new route with path prefix to serve static files from the provided root directory.
func (e *Echo) Static(pathPrefix, fsRoot string) *Route {
subFs := MustSubFS(e.Filesystem, fsRoot)
return e.Add(
http.MethodGet,
pathPrefix+"*",
StaticDirectoryHandler(subFs, false),
)
}
// StaticFS registers a new route with path prefix to serve static files from the provided file system.
//
// When dealing with `embed.FS` use `fs := echo.MustSubFS(fs, "rootDirectory") to create sub fs which uses necessary
// prefix for directory path. This is necessary as `//go:embed assets/images` embeds files with paths
// including `assets/images` as their prefix.
func (e *Echo) StaticFS(pathPrefix string, filesystem fs.FS) *Route {
return e.Add(
http.MethodGet,
pathPrefix+"*",
StaticDirectoryHandler(filesystem, false),
)
}
// StaticDirectoryHandler creates handler function to serve files from provided file system
// When disablePathUnescaping is set then file name from path is not unescaped and is served as is.
func StaticDirectoryHandler(fileSystem fs.FS, disablePathUnescaping bool) HandlerFunc {
return func(c Context) error {
p := c.Param("*")
if !disablePathUnescaping { // when router is already unescaping we do not want to do is twice
tmpPath, err := url.PathUnescape(p)
if err != nil {
return fmt.Errorf("failed to unescape path variable: %w", err)
}
p = tmpPath
}
// fs.FS.Open() already assumes that file names are relative to FS root path and considers name with prefix `/` as invalid
name := filepath.ToSlash(filepath.Clean(strings.TrimPrefix(p, "/")))
fi, err := fs.Stat(fileSystem, name)
if err != nil {
return ErrNotFound
}
// If the request is for a directory and does not end with "/"
p = c.Request().URL.Path // path must not be empty.
if fi.IsDir() && len(p) > 0 && p[len(p)-1] != '/' {
// Redirect to ends with "/"
return c.Redirect(http.StatusMovedPermanently, p+"/")
}
return fsFile(c, name, fileSystem)
}
}
// FileFS registers a new route with path to serve file from the provided file system.
func (e *Echo) FileFS(path, file string, filesystem fs.FS, m ...MiddlewareFunc) *Route {
return e.GET(path, StaticFileHandler(file, filesystem), m...)
}
// StaticFileHandler creates handler function to serve file from provided file system
func StaticFileHandler(file string, filesystem fs.FS) HandlerFunc {
return func(c Context) error {
return fsFile(c, file, filesystem)
}
}
// defaultFS exists to preserve pre v4.7.0 behaviour where files were open by `os.Open`.
// v4.7 introduced `echo.Filesystem` field which is Go1.16+ `fs.Fs` interface.
// Difference between `os.Open` and `fs.Open` is that FS does not allow opening path that start with `.`, `..` or `/`
// etc. For example previously you could have `../images` in your application but `fs := os.DirFS("./")` would not
// allow you to use `fs.Open("../images")` and this would break all old applications that rely on being able to
// traverse up from current executable run path.
// NB: private because you really should use fs.FS implementation instances
type defaultFS struct {
prefix string
fs fs.FS
}
func newDefaultFS() *defaultFS {
dir, _ := os.Getwd()
return &defaultFS{
prefix: dir,
fs: nil,
}
}
func (fs defaultFS) Open(name string) (fs.File, error) {
if fs.fs == nil {
return os.Open(name)
}
return fs.fs.Open(name)
}
func subFS(currentFs fs.FS, root string) (fs.FS, error) {
root = filepath.ToSlash(filepath.Clean(root)) // note: fs.FS operates only with slashes. `ToSlash` is necessary for Windows
if dFS, ok := currentFs.(*defaultFS); ok {
// we need to make exception for `defaultFS` instances as it interprets root prefix differently from fs.FS.
// fs.Fs.Open does not like relative paths ("./", "../") and absolute paths at all but prior echo.Filesystem we
// were able to use paths like `./myfile.log`, `/etc/hosts` and these would work fine with `os.Open` but not with fs.Fs
if isRelativePath(root) {
root = filepath.Join(dFS.prefix, root)
}
return &defaultFS{
prefix: root,
fs: os.DirFS(root),
}, nil
}
return fs.Sub(currentFs, root)
}
func isRelativePath(path string) bool {
if path == "" {
return true
}
if path[0] == '/' {
return false
}
if runtime.GOOS == "windows" && strings.IndexByte(path, ':') != -1 {
// https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file?redirectedfrom=MSDN#file_and_directory_names
// https://docs.microsoft.com/en-us/dotnet/standard/io/file-path-formats
return false
}
return true
}
// MustSubFS creates sub FS from current filesystem or panic on failure.
// Panic happens when `fsRoot` contains invalid path according to `fs.ValidPath` rules.
//
// MustSubFS is helpful when dealing with `embed.FS` because for example `//go:embed assets/images` embeds files with
// paths including `assets/images` as their prefix. In that case use `fs := echo.MustSubFS(fs, "rootDirectory") to
// create sub fs which uses necessary prefix for directory path.
func MustSubFS(currentFs fs.FS, fsRoot string) fs.FS {
subFs, err := subFS(currentFs, fsRoot)
if err != nil {
panic(fmt.Errorf("can not create sub FS, invalid root given, err: %w", err))
}
return subFs
}

View File

@ -102,11 +102,6 @@ func (g *Group) Group(prefix string, middleware ...MiddlewareFunc) (sg *Group) {
return return
} }
// Static implements `Echo#Static()` for sub-routes within the Group.
func (g *Group) Static(prefix, root string) {
g.static(prefix, root, g.GET)
}
// File implements `Echo#File()` for sub-routes within the Group. // File implements `Echo#File()` for sub-routes within the Group.
func (g *Group) File(path, file string) { func (g *Group) File(path, file string) {
g.file(path, file, g.GET) g.file(path, file, g.GET)

9
vendor/github.com/labstack/echo/v4/group_fs.go generated vendored Normal file
View File

@ -0,0 +1,9 @@
//go:build !go1.16
// +build !go1.16
package echo
// Static implements `Echo#Static()` for sub-routes within the Group.
func (g *Group) Static(prefix, root string) {
g.static(prefix, root, g.GET)
}

33
vendor/github.com/labstack/echo/v4/group_fs_go1.16.go generated vendored Normal file
View File

@ -0,0 +1,33 @@
//go:build go1.16
// +build go1.16
package echo
import (
"io/fs"
"net/http"
)
// Static implements `Echo#Static()` for sub-routes within the Group.
func (g *Group) Static(pathPrefix, fsRoot string) {
subFs := MustSubFS(g.echo.Filesystem, fsRoot)
g.StaticFS(pathPrefix, subFs)
}
// StaticFS implements `Echo#StaticFS()` for sub-routes within the Group.
//
// When dealing with `embed.FS` use `fs := echo.MustSubFS(fs, "rootDirectory") to create sub fs which uses necessary
// prefix for directory path. This is necessary as `//go:embed assets/images` embeds files with paths
// including `assets/images` as their prefix.
func (g *Group) StaticFS(pathPrefix string, filesystem fs.FS) {
g.Add(
http.MethodGet,
pathPrefix+"*",
StaticDirectoryHandler(filesystem, false),
)
}
// FileFS implements `Echo#FileFS()` for sub-routes within the Group.
func (g *Group) FileFS(path, file string, filesystem fs.FS, m ...MiddlewareFunc) *Route {
return g.GET(path, StaticFileHandler(file, filesystem), m...)
}

View File

@ -6,6 +6,130 @@ import (
"strings" "strings"
) )
/**
By: https://github.com/tmshn (See: https://github.com/labstack/echo/pull/1478 , https://github.com/labstack/echox/pull/134 )
Source: https://echo.labstack.com/guide/ip-address/
IP address plays fundamental role in HTTP; it's used for access control, auditing, geo-based access analysis and more.
Echo provides handy method [`Context#RealIP()`](https://godoc.org/github.com/labstack/echo#Context) for that.
However, it is not trivial to retrieve the _real_ IP address from requests especially when you put L7 proxies before the application.
In such situation, _real_ IP needs to be relayed on HTTP layer from proxies to your app, but you must not trust HTTP headers unconditionally.
Otherwise, you might give someone a chance of deceiving you. **A security risk!**
To retrieve IP address reliably/securely, you must let your application be aware of the entire architecture of your infrastructure.
In Echo, this can be done by configuring `Echo#IPExtractor` appropriately.
This guides show you why and how.
> Note: if you dont' set `Echo#IPExtractor` explicitly, Echo fallback to legacy behavior, which is not a good choice.
Let's start from two questions to know the right direction:
1. Do you put any HTTP (L7) proxy in front of the application?
- It includes both cloud solutions (such as AWS ALB or GCP HTTP LB) and OSS ones (such as Nginx, Envoy or Istio ingress gateway).
2. If yes, what HTTP header do your proxies use to pass client IP to the application?
## Case 1. With no proxy
If you put no proxy (e.g.: directory facing to the internet), all you need to (and have to) see is IP address from network layer.
Any HTTP header is untrustable because the clients have full control what headers to be set.
In this case, use `echo.ExtractIPDirect()`.
```go
e.IPExtractor = echo.ExtractIPDirect()
```
## Case 2. With proxies using `X-Forwarded-For` header
[`X-Forwared-For` (XFF)](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-For) is the popular header
to relay clients' IP addresses.
At each hop on the proxies, they append the request IP address at the end of the header.
Following example diagram illustrates this behavior.
```text
"Origin" > Proxy 1 > Proxy 2 > Your app
(IP: a) (IP: b) (IP: c)
Case 1.
XFF: "" "a" "a, b"
~~~~~~
Case 2.
XFF: "x" "x, a" "x, a, b"
~~~~~~~~~
What your app will see
```
In this case, use **first _untrustable_ IP reading from right**. Never use first one reading from left, as it is
configurable by client. Here "trustable" means "you are sure the IP address belongs to your infrastructre".
In above example, if `b` and `c` are trustable, the IP address of the client is `a` for both cases, never be `x`.
In Echo, use `ExtractIPFromXFFHeader(...TrustOption)`.
```go
e.IPExtractor = echo.ExtractIPFromXFFHeader()
```
By default, it trusts internal IP addresses (loopback, link-local unicast, private-use and unique local address
from [RFC6890](https://tools.ietf.org/html/rfc6890), [RFC4291](https://tools.ietf.org/html/rfc4291) and
[RFC4193](https://tools.ietf.org/html/rfc4193)).
To control this behavior, use [`TrustOption`](https://godoc.org/github.com/labstack/echo#TrustOption)s.
E.g.:
```go
e.IPExtractor = echo.ExtractIPFromXFFHeader(
TrustLinkLocal(false),
TrustIPRanges(lbIPRange),
)
```
- Ref: https://godoc.org/github.com/labstack/echo#TrustOption
## Case 3. With proxies using `X-Real-IP` header
`X-Real-IP` is another HTTP header to relay clients' IP addresses, but it carries only one address unlike XFF.
If your proxies set this header, use `ExtractIPFromRealIPHeader(...TrustOption)`.
```go
e.IPExtractor = echo.ExtractIPFromRealIPHeader()
```
Again, it trusts internal IP addresses by default (loopback, link-local unicast, private-use and unique local address
from [RFC6890](https://tools.ietf.org/html/rfc6890), [RFC4291](https://tools.ietf.org/html/rfc4291) and
[RFC4193](https://tools.ietf.org/html/rfc4193)).
To control this behavior, use [`TrustOption`](https://godoc.org/github.com/labstack/echo#TrustOption)s.
- Ref: https://godoc.org/github.com/labstack/echo#TrustOption
> **Never forget** to configure the outermost proxy (i.e.; at the edge of your infrastructure) **not to pass through incoming headers**.
> Otherwise there is a chance of fraud, as it is what clients can control.
## About default behavior
In default behavior, Echo sees all of first XFF header, X-Real-IP header and IP from network layer.
As you might already notice, after reading this article, this is not good.
Sole reason this is default is just backward compatibility.
## Private IP ranges
See: https://en.wikipedia.org/wiki/Private_network
Private IPv4 address ranges (RFC 1918):
* 10.0.0.0 10.255.255.255 (24-bit block)
* 172.16.0.0 172.31.255.255 (20-bit block)
* 192.168.0.0 192.168.255.255 (16-bit block)
Private IPv6 address ranges:
* fc00::/7 address block = RFC 4193 Unique Local Addresses (ULA)
*/
type ipChecker struct { type ipChecker struct {
trustLoopback bool trustLoopback bool
trustLinkLocal bool trustLinkLocal bool
@ -52,6 +176,7 @@ func newIPChecker(configs []TrustOption) *ipChecker {
return checker return checker
} }
// Go1.16+ added `ip.IsPrivate()` but until that use this implementation
func isPrivateIPRange(ip net.IP) bool { func isPrivateIPRange(ip net.IP) bool {
if ip4 := ip.To4(); ip4 != nil { if ip4 := ip.To4(); ip4 != nil {
return ip4[0] == 10 || return ip4[0] == 10 ||
@ -87,10 +212,12 @@ type IPExtractor func(*http.Request) string
// ExtractIPDirect extracts IP address using actual IP address. // ExtractIPDirect extracts IP address using actual IP address.
// Use this if your server faces to internet directory (i.e.: uses no proxy). // Use this if your server faces to internet directory (i.e.: uses no proxy).
func ExtractIPDirect() IPExtractor { func ExtractIPDirect() IPExtractor {
return func(req *http.Request) string { return extractIP
ra, _, _ := net.SplitHostPort(req.RemoteAddr) }
return ra
} func extractIP(req *http.Request) string {
ra, _, _ := net.SplitHostPort(req.RemoteAddr)
return ra
} }
// ExtractIPFromRealIPHeader extracts IP address using x-real-ip header. // ExtractIPFromRealIPHeader extracts IP address using x-real-ip header.
@ -98,14 +225,13 @@ func ExtractIPDirect() IPExtractor {
func ExtractIPFromRealIPHeader(options ...TrustOption) IPExtractor { func ExtractIPFromRealIPHeader(options ...TrustOption) IPExtractor {
checker := newIPChecker(options) checker := newIPChecker(options)
return func(req *http.Request) string { return func(req *http.Request) string {
directIP := ExtractIPDirect()(req)
realIP := req.Header.Get(HeaderXRealIP) realIP := req.Header.Get(HeaderXRealIP)
if realIP != "" { if realIP != "" {
if ip := net.ParseIP(directIP); ip != nil && checker.trust(ip) { if ip := net.ParseIP(realIP); ip != nil && checker.trust(ip) {
return realIP return realIP
} }
} }
return directIP return extractIP(req)
} }
} }
@ -115,7 +241,7 @@ func ExtractIPFromRealIPHeader(options ...TrustOption) IPExtractor {
func ExtractIPFromXFFHeader(options ...TrustOption) IPExtractor { func ExtractIPFromXFFHeader(options ...TrustOption) IPExtractor {
checker := newIPChecker(options) checker := newIPChecker(options)
return func(req *http.Request) string { return func(req *http.Request) string {
directIP := ExtractIPDirect()(req) directIP := extractIP(req)
xffs := req.Header[HeaderXForwardedFor] xffs := req.Header[HeaderXForwardedFor]
if len(xffs) == 0 { if len(xffs) == 0 {
return directIP return directIP

View File

@ -1,6 +1,7 @@
package echo package echo
import ( import (
"bytes"
"net/http" "net/http"
) )
@ -31,17 +32,18 @@ type (
kind uint8 kind uint8
children []*node children []*node
methodHandler struct { methodHandler struct {
connect HandlerFunc connect HandlerFunc
delete HandlerFunc delete HandlerFunc
get HandlerFunc get HandlerFunc
head HandlerFunc head HandlerFunc
options HandlerFunc options HandlerFunc
patch HandlerFunc patch HandlerFunc
post HandlerFunc post HandlerFunc
propfind HandlerFunc propfind HandlerFunc
put HandlerFunc put HandlerFunc
trace HandlerFunc trace HandlerFunc
report HandlerFunc report HandlerFunc
allowHeader string
} }
) )
@ -68,6 +70,51 @@ func (m *methodHandler) isHandler() bool {
m.report != nil m.report != nil
} }
func (m *methodHandler) updateAllowHeader() {
buf := new(bytes.Buffer)
buf.WriteString(http.MethodOptions)
if m.connect != nil {
buf.WriteString(", ")
buf.WriteString(http.MethodConnect)
}
if m.delete != nil {
buf.WriteString(", ")
buf.WriteString(http.MethodDelete)
}
if m.get != nil {
buf.WriteString(", ")
buf.WriteString(http.MethodGet)
}
if m.head != nil {
buf.WriteString(", ")
buf.WriteString(http.MethodHead)
}
if m.patch != nil {
buf.WriteString(", ")
buf.WriteString(http.MethodPatch)
}
if m.post != nil {
buf.WriteString(", ")
buf.WriteString(http.MethodPost)
}
if m.propfind != nil {
buf.WriteString(", PROPFIND")
}
if m.put != nil {
buf.WriteString(", ")
buf.WriteString(http.MethodPut)
}
if m.trace != nil {
buf.WriteString(", ")
buf.WriteString(http.MethodTrace)
}
if m.report != nil {
buf.WriteString(", REPORT")
}
m.allowHeader = buf.String()
}
// NewRouter returns a new Router instance. // NewRouter returns a new Router instance.
func NewRouter(e *Echo) *Router { func NewRouter(e *Echo) *Router {
return &Router{ return &Router{
@ -98,6 +145,12 @@ func (r *Router) Add(method, path string, h HandlerFunc) {
for i, lcpIndex := 0, len(path); i < lcpIndex; i++ { for i, lcpIndex := 0, len(path); i < lcpIndex; i++ {
if path[i] == ':' { if path[i] == ':' {
if i > 0 && path[i-1] == '\\' {
path = path[:i-1] + path[i:]
i--
lcpIndex--
continue
}
j := i + 1 j := i + 1
r.insert(method, path[:i], nil, staticKind, "", nil) r.insert(method, path[:i], nil, staticKind, "", nil)
@ -320,6 +373,7 @@ func (n *node) addHandler(method string, h HandlerFunc) {
n.methodHandler.report = h n.methodHandler.report = h
} }
n.methodHandler.updateAllowHeader()
if h != nil { if h != nil {
n.isHandler = true n.isHandler = true
} else { } else {
@ -356,13 +410,14 @@ func (n *node) findHandler(method string) HandlerFunc {
} }
} }
func (n *node) checkMethodNotAllowed() HandlerFunc { func optionsMethodHandler(allowMethods string) func(c Context) error {
for _, m := range methods { return func(c Context) error {
if h := n.findHandler(m); h != nil { // Note: we are not handling most of the CORS headers here. CORS is handled by CORS middleware
return MethodNotAllowedHandler // 'OPTIONS' method RFC: https://httpwg.org/specs/rfc7231.html#OPTIONS
} // 'Allow' header RFC: https://datatracker.ietf.org/doc/html/rfc7231#section-7.4.1
c.Response().Header().Add(HeaderAllow, allowMethods)
return c.NoContent(http.StatusNoContent)
} }
return NotFoundHandler
} }
// Find lookup a handler registered for method and path. It also parses URL for path // Find lookup a handler registered for method and path. It also parses URL for path
@ -557,10 +612,16 @@ func (r *Router) Find(method, path string, c Context) {
// use previous match as basis. although we have no matching handler we have path match. // use previous match as basis. although we have no matching handler we have path match.
// so we can send http.StatusMethodNotAllowed (405) instead of http.StatusNotFound (404) // so we can send http.StatusMethodNotAllowed (405) instead of http.StatusNotFound (404)
currentNode = previousBestMatchNode currentNode = previousBestMatchNode
ctx.handler = currentNode.checkMethodNotAllowed()
ctx.handler = NotFoundHandler
if currentNode.isHandler {
ctx.Set(ContextKeyHeaderAllow, currentNode.methodHandler.allowHeader)
ctx.handler = MethodNotAllowedHandler
if method == http.MethodOptions {
ctx.handler = optionsMethodHandler(currentNode.methodHandler.allowHeader)
}
}
} }
ctx.path = currentNode.ppath ctx.path = currentNode.ppath
ctx.pnames = currentNode.pnames ctx.pnames = currentNode.pnames
return
} }

71
vendor/github.com/lib/pq/.travis.sh generated vendored
View File

@ -1,71 +0,0 @@
#!/bin/bash
set -eux
client_configure() {
sudo chmod 600 $PQSSLCERTTEST_PATH/postgresql.key
}
pgdg_repository() {
curl -sS 'https://www.postgresql.org/media/keys/ACCC4CF8.asc' | sudo apt-key add -
echo "deb http://apt.postgresql.org/pub/repos/apt/ `lsb_release -cs`-pgdg main" | sudo tee /etc/apt/sources.list.d/pgdg.list
sudo apt-get update
}
postgresql_configure() {
sudo tee /etc/postgresql/$PGVERSION/main/pg_hba.conf > /dev/null <<-config
local all all trust
hostnossl all pqgossltest 127.0.0.1/32 reject
hostnossl all pqgosslcert 127.0.0.1/32 reject
hostssl all pqgossltest 127.0.0.1/32 trust
hostssl all pqgosslcert 127.0.0.1/32 cert
host all all 127.0.0.1/32 trust
hostnossl all pqgossltest ::1/128 reject
hostnossl all pqgosslcert ::1/128 reject
hostssl all pqgossltest ::1/128 trust
hostssl all pqgosslcert ::1/128 cert
host all all ::1/128 trust
config
xargs sudo install -o postgres -g postgres -m 600 -t /var/lib/postgresql/$PGVERSION/main/ <<-certificates
certs/root.crt
certs/server.crt
certs/server.key
certificates
sort -VCu <<-versions ||
$PGVERSION
9.2
versions
sudo tee -a /etc/postgresql/$PGVERSION/main/postgresql.conf > /dev/null <<-config
ssl_ca_file = 'root.crt'
ssl_cert_file = 'server.crt'
ssl_key_file = 'server.key'
config
echo 127.0.0.1 postgres | sudo tee -a /etc/hosts > /dev/null
sudo service postgresql restart
}
postgresql_install() {
xargs sudo apt-get -y install <<-packages
postgresql-$PGVERSION
postgresql-client-$PGVERSION
postgresql-server-dev-$PGVERSION
packages
}
postgresql_uninstall() {
sudo service postgresql stop
xargs sudo apt-get -y --purge remove <<-packages
libpq-dev
libpq5
postgresql
postgresql-client-common
postgresql-common
packages
sudo rm -rf /var/lib/postgresql
}
$1

45
vendor/github.com/lib/pq/.travis.yml generated vendored
View File

@ -1,45 +0,0 @@
language: go
go:
- 1.14.x
- 1.15.x
- 1.16.x
sudo: true
env:
global:
- PGUSER=postgres
- PQGOSSLTESTS=1
- PQSSLCERTTEST_PATH=$PWD/certs
- PGHOST=127.0.0.1
- GODEBUG=x509ignoreCN=0
matrix:
- PGVERSION=10
- PGVERSION=9.6
- PGVERSION=9.5
- PGVERSION=9.4
before_install:
- ./.travis.sh postgresql_uninstall
- ./.travis.sh pgdg_repository
- ./.travis.sh postgresql_install
- ./.travis.sh postgresql_configure
- ./.travis.sh client_configure
- go get golang.org/x/tools/cmd/goimports
- go get golang.org/x/lint/golint
- GO111MODULE=on go get honnef.co/go/tools/cmd/staticcheck@2020.1.3
before_script:
- createdb pqgotest
- createuser -DRS pqgossltest
- createuser -DRS pqgosslcert
script:
- >
goimports -d -e $(find -name '*.go') | awk '{ print } END { exit NR == 0 ? 0 : 1 }'
- go vet ./...
- staticcheck -go 1.13 ./...
- golint ./...
- PQTEST_BINARY_PARAMETERS=no go test -race -v ./...
- PQTEST_BINARY_PARAMETERS=yes go test -race -v ./...

8
vendor/github.com/lib/pq/README.md generated vendored
View File

@ -27,4 +27,10 @@
## Status ## Status
This package is effectively in maintenance mode and is not actively developed. Small patches and features are only rarely reviewed and merged. We recommend using [pgx](https://github.com/jackc/pgx) which is actively maintained. This package is currently in maintenance mode, which means:
1. It generally does not accept new features.
2. It does accept bug fixes and version compatability changes provided by the community.
3. Maintainers usually do not resolve reported issues.
4. Community members are encouraged to help each other with reported issues.
For users that require new features or reliable resolution of reported bugs, we recommend using [pgx](https://github.com/jackc/pgx) which is under active development.

4
vendor/github.com/lib/pq/array.go generated vendored
View File

@ -587,8 +587,8 @@ func (a *Int32Array) scanBytes(src []byte) error {
} else { } else {
b := make(Int32Array, len(elems)) b := make(Int32Array, len(elems))
for i, v := range elems { for i, v := range elems {
var x int x, err := strconv.ParseInt(string(v), 10, 32)
if x, err = strconv.Atoi(string(v)); err != nil { if err != nil {
return fmt.Errorf("pq: parsing array element index %d: %v", i, err) return fmt.Errorf("pq: parsing array element index %d: %v", i, err)
} }
b[i] = int32(x) b[i] = int32(x)

153
vendor/github.com/lib/pq/conn.go generated vendored
View File

@ -18,7 +18,7 @@ import (
"path/filepath" "path/filepath"
"strconv" "strconv"
"strings" "strings"
"sync/atomic" "sync"
"time" "time"
"unicode" "unicode"
@ -140,9 +140,10 @@ type conn struct {
saveMessageType byte saveMessageType byte
saveMessageBuffer []byte saveMessageBuffer []byte
// If true, this connection is bad and all public-facing functions should // If an error is set, this connection is bad and all public-facing
// return ErrBadConn. // functions should return the appropriate error by calling get()
bad *atomic.Value // (ErrBadConn) or getForNext().
err syncErr
// If set, this connection should never use the binary format when // If set, this connection should never use the binary format when
// receiving query results from prepared statements. Only provided for // receiving query results from prepared statements. Only provided for
@ -166,6 +167,40 @@ type conn struct {
gss GSS gss GSS
} }
type syncErr struct {
err error
sync.Mutex
}
// Return ErrBadConn if connection is bad.
func (e *syncErr) get() error {
e.Lock()
defer e.Unlock()
if e.err != nil {
return driver.ErrBadConn
}
return nil
}
// Return the error set on the connection. Currently only used by rows.Next.
func (e *syncErr) getForNext() error {
e.Lock()
defer e.Unlock()
return e.err
}
// Set error, only if it isn't set yet.
func (e *syncErr) set(err error) {
if err == nil {
panic("attempt to set nil err")
}
e.Lock()
defer e.Unlock()
if e.err == nil {
e.err = err
}
}
// Handle driver-side settings in parsed connection string. // Handle driver-side settings in parsed connection string.
func (cn *conn) handleDriverSettings(o values) (err error) { func (cn *conn) handleDriverSettings(o values) (err error) {
boolSetting := func(key string, val *bool) error { boolSetting := func(key string, val *bool) error {
@ -306,12 +341,9 @@ func (c *Connector) open(ctx context.Context) (cn *conn, err error) {
o[k] = v o[k] = v
} }
bad := &atomic.Value{}
bad.Store(false)
cn = &conn{ cn = &conn{
opts: o, opts: o,
dialer: c.dialer, dialer: c.dialer,
bad: bad,
} }
err = cn.handleDriverSettings(o) err = cn.handleDriverSettings(o)
if err != nil { if err != nil {
@ -516,22 +548,9 @@ func (cn *conn) isInTransaction() bool {
cn.txnStatus == txnStatusInFailedTransaction cn.txnStatus == txnStatusInFailedTransaction
} }
func (cn *conn) setBad() {
if cn.bad != nil {
cn.bad.Store(true)
}
}
func (cn *conn) getBad() bool {
if cn.bad != nil {
return cn.bad.Load().(bool)
}
return false
}
func (cn *conn) checkIsInTransaction(intxn bool) { func (cn *conn) checkIsInTransaction(intxn bool) {
if cn.isInTransaction() != intxn { if cn.isInTransaction() != intxn {
cn.setBad() cn.err.set(driver.ErrBadConn)
errorf("unexpected transaction status %v", cn.txnStatus) errorf("unexpected transaction status %v", cn.txnStatus)
} }
} }
@ -541,8 +560,8 @@ func (cn *conn) Begin() (_ driver.Tx, err error) {
} }
func (cn *conn) begin(mode string) (_ driver.Tx, err error) { func (cn *conn) begin(mode string) (_ driver.Tx, err error) {
if cn.getBad() { if err := cn.err.get(); err != nil {
return nil, driver.ErrBadConn return nil, err
} }
defer cn.errRecover(&err) defer cn.errRecover(&err)
@ -552,11 +571,11 @@ func (cn *conn) begin(mode string) (_ driver.Tx, err error) {
return nil, err return nil, err
} }
if commandTag != "BEGIN" { if commandTag != "BEGIN" {
cn.setBad() cn.err.set(driver.ErrBadConn)
return nil, fmt.Errorf("unexpected command tag %s", commandTag) return nil, fmt.Errorf("unexpected command tag %s", commandTag)
} }
if cn.txnStatus != txnStatusIdleInTransaction { if cn.txnStatus != txnStatusIdleInTransaction {
cn.setBad() cn.err.set(driver.ErrBadConn)
return nil, fmt.Errorf("unexpected transaction status %v", cn.txnStatus) return nil, fmt.Errorf("unexpected transaction status %v", cn.txnStatus)
} }
return cn, nil return cn, nil
@ -570,8 +589,8 @@ func (cn *conn) closeTxn() {
func (cn *conn) Commit() (err error) { func (cn *conn) Commit() (err error) {
defer cn.closeTxn() defer cn.closeTxn()
if cn.getBad() { if err := cn.err.get(); err != nil {
return driver.ErrBadConn return err
} }
defer cn.errRecover(&err) defer cn.errRecover(&err)
@ -592,12 +611,12 @@ func (cn *conn) Commit() (err error) {
_, commandTag, err := cn.simpleExec("COMMIT") _, commandTag, err := cn.simpleExec("COMMIT")
if err != nil { if err != nil {
if cn.isInTransaction() { if cn.isInTransaction() {
cn.setBad() cn.err.set(driver.ErrBadConn)
} }
return err return err
} }
if commandTag != "COMMIT" { if commandTag != "COMMIT" {
cn.setBad() cn.err.set(driver.ErrBadConn)
return fmt.Errorf("unexpected command tag %s", commandTag) return fmt.Errorf("unexpected command tag %s", commandTag)
} }
cn.checkIsInTransaction(false) cn.checkIsInTransaction(false)
@ -606,8 +625,8 @@ func (cn *conn) Commit() (err error) {
func (cn *conn) Rollback() (err error) { func (cn *conn) Rollback() (err error) {
defer cn.closeTxn() defer cn.closeTxn()
if cn.getBad() { if err := cn.err.get(); err != nil {
return driver.ErrBadConn return err
} }
defer cn.errRecover(&err) defer cn.errRecover(&err)
return cn.rollback() return cn.rollback()
@ -618,7 +637,7 @@ func (cn *conn) rollback() (err error) {
_, commandTag, err := cn.simpleExec("ROLLBACK") _, commandTag, err := cn.simpleExec("ROLLBACK")
if err != nil { if err != nil {
if cn.isInTransaction() { if cn.isInTransaction() {
cn.setBad() cn.err.set(driver.ErrBadConn)
} }
return err return err
} }
@ -658,7 +677,7 @@ func (cn *conn) simpleExec(q string) (res driver.Result, commandTag string, err
case 'T', 'D': case 'T', 'D':
// ignore any results // ignore any results
default: default:
cn.setBad() cn.err.set(driver.ErrBadConn)
errorf("unknown response for simple query: %q", t) errorf("unknown response for simple query: %q", t)
} }
} }
@ -680,7 +699,7 @@ func (cn *conn) simpleQuery(q string) (res *rows, err error) {
// the user can close, though, to avoid connections from being // the user can close, though, to avoid connections from being
// leaked. A "rows" with done=true works fine for that purpose. // leaked. A "rows" with done=true works fine for that purpose.
if err != nil { if err != nil {
cn.setBad() cn.err.set(driver.ErrBadConn)
errorf("unexpected message %q in simple query execution", t) errorf("unexpected message %q in simple query execution", t)
} }
if res == nil { if res == nil {
@ -707,7 +726,7 @@ func (cn *conn) simpleQuery(q string) (res *rows, err error) {
err = parseError(r) err = parseError(r)
case 'D': case 'D':
if res == nil { if res == nil {
cn.setBad() cn.err.set(driver.ErrBadConn)
errorf("unexpected DataRow in simple query execution") errorf("unexpected DataRow in simple query execution")
} }
// the query didn't fail; kick off to Next // the query didn't fail; kick off to Next
@ -722,7 +741,7 @@ func (cn *conn) simpleQuery(q string) (res *rows, err error) {
// To work around a bug in QueryRow in Go 1.2 and earlier, wait // To work around a bug in QueryRow in Go 1.2 and earlier, wait
// until the first DataRow has been received. // until the first DataRow has been received.
default: default:
cn.setBad() cn.err.set(driver.ErrBadConn)
errorf("unknown response for simple query: %q", t) errorf("unknown response for simple query: %q", t)
} }
} }
@ -815,8 +834,8 @@ func (cn *conn) prepareTo(q, stmtName string) *stmt {
} }
func (cn *conn) Prepare(q string) (_ driver.Stmt, err error) { func (cn *conn) Prepare(q string) (_ driver.Stmt, err error) {
if cn.getBad() { if err := cn.err.get(); err != nil {
return nil, driver.ErrBadConn return nil, err
} }
defer cn.errRecover(&err) defer cn.errRecover(&err)
@ -854,8 +873,8 @@ func (cn *conn) Query(query string, args []driver.Value) (driver.Rows, error) {
} }
func (cn *conn) query(query string, args []driver.Value) (_ *rows, err error) { func (cn *conn) query(query string, args []driver.Value) (_ *rows, err error) {
if cn.getBad() { if err := cn.err.get(); err != nil {
return nil, driver.ErrBadConn return nil, err
} }
if cn.inCopy { if cn.inCopy {
return nil, errCopyInProgress return nil, errCopyInProgress
@ -888,8 +907,8 @@ func (cn *conn) query(query string, args []driver.Value) (_ *rows, err error) {
// Implement the optional "Execer" interface for one-shot queries // Implement the optional "Execer" interface for one-shot queries
func (cn *conn) Exec(query string, args []driver.Value) (res driver.Result, err error) { func (cn *conn) Exec(query string, args []driver.Value) (res driver.Result, err error) {
if cn.getBad() { if err := cn.err.get(); err != nil {
return nil, driver.ErrBadConn return nil, err
} }
defer cn.errRecover(&err) defer cn.errRecover(&err)
@ -960,7 +979,7 @@ func (cn *conn) sendSimpleMessage(typ byte) (err error) {
// the message yourself. // the message yourself.
func (cn *conn) saveMessage(typ byte, buf *readBuf) { func (cn *conn) saveMessage(typ byte, buf *readBuf) {
if cn.saveMessageType != 0 { if cn.saveMessageType != 0 {
cn.setBad() cn.err.set(driver.ErrBadConn)
errorf("unexpected saveMessageType %d", cn.saveMessageType) errorf("unexpected saveMessageType %d", cn.saveMessageType)
} }
cn.saveMessageType = typ cn.saveMessageType = typ
@ -1330,8 +1349,8 @@ func (st *stmt) Close() (err error) {
if st.closed { if st.closed {
return nil return nil
} }
if st.cn.getBad() { if err := st.cn.err.get(); err != nil {
return driver.ErrBadConn return err
} }
defer st.cn.errRecover(&err) defer st.cn.errRecover(&err)
@ -1344,14 +1363,14 @@ func (st *stmt) Close() (err error) {
t, _ := st.cn.recv1() t, _ := st.cn.recv1()
if t != '3' { if t != '3' {
st.cn.setBad() st.cn.err.set(driver.ErrBadConn)
errorf("unexpected close response: %q", t) errorf("unexpected close response: %q", t)
} }
st.closed = true st.closed = true
t, r := st.cn.recv1() t, r := st.cn.recv1()
if t != 'Z' { if t != 'Z' {
st.cn.setBad() st.cn.err.set(driver.ErrBadConn)
errorf("expected ready for query, but got: %q", t) errorf("expected ready for query, but got: %q", t)
} }
st.cn.processReadyForQuery(r) st.cn.processReadyForQuery(r)
@ -1360,8 +1379,12 @@ func (st *stmt) Close() (err error) {
} }
func (st *stmt) Query(v []driver.Value) (r driver.Rows, err error) { func (st *stmt) Query(v []driver.Value) (r driver.Rows, err error) {
if st.cn.getBad() { return st.query(v)
return nil, driver.ErrBadConn }
func (st *stmt) query(v []driver.Value) (r *rows, err error) {
if err := st.cn.err.get(); err != nil {
return nil, err
} }
defer st.cn.errRecover(&err) defer st.cn.errRecover(&err)
@ -1373,8 +1396,8 @@ func (st *stmt) Query(v []driver.Value) (r driver.Rows, err error) {
} }
func (st *stmt) Exec(v []driver.Value) (res driver.Result, err error) { func (st *stmt) Exec(v []driver.Value) (res driver.Result, err error) {
if st.cn.getBad() { if err := st.cn.err.get(); err != nil {
return nil, driver.ErrBadConn return nil, err
} }
defer st.cn.errRecover(&err) defer st.cn.errRecover(&err)
@ -1460,7 +1483,7 @@ func (cn *conn) parseComplete(commandTag string) (driver.Result, string) {
if affectedRows == nil && strings.HasPrefix(commandTag, "INSERT ") { if affectedRows == nil && strings.HasPrefix(commandTag, "INSERT ") {
parts := strings.Split(commandTag, " ") parts := strings.Split(commandTag, " ")
if len(parts) != 3 { if len(parts) != 3 {
cn.setBad() cn.err.set(driver.ErrBadConn)
errorf("unexpected INSERT command tag %s", commandTag) errorf("unexpected INSERT command tag %s", commandTag)
} }
affectedRows = &parts[len(parts)-1] affectedRows = &parts[len(parts)-1]
@ -1472,7 +1495,7 @@ func (cn *conn) parseComplete(commandTag string) (driver.Result, string) {
} }
n, err := strconv.ParseInt(*affectedRows, 10, 64) n, err := strconv.ParseInt(*affectedRows, 10, 64)
if err != nil { if err != nil {
cn.setBad() cn.err.set(driver.ErrBadConn)
errorf("could not parse commandTag: %s", err) errorf("could not parse commandTag: %s", err)
} }
return driver.RowsAffected(n), commandTag return driver.RowsAffected(n), commandTag
@ -1539,8 +1562,8 @@ func (rs *rows) Next(dest []driver.Value) (err error) {
} }
conn := rs.cn conn := rs.cn
if conn.getBad() { if err := conn.err.getForNext(); err != nil {
return driver.ErrBadConn return err
} }
defer conn.errRecover(&err) defer conn.errRecover(&err)
@ -1564,7 +1587,7 @@ func (rs *rows) Next(dest []driver.Value) (err error) {
case 'D': case 'D':
n := rs.rb.int16() n := rs.rb.int16()
if err != nil { if err != nil {
conn.setBad() conn.err.set(driver.ErrBadConn)
errorf("unexpected DataRow after error %s", err) errorf("unexpected DataRow after error %s", err)
} }
if n < len(dest) { if n < len(dest) {
@ -1758,7 +1781,7 @@ func (cn *conn) readReadyForQuery() {
cn.processReadyForQuery(r) cn.processReadyForQuery(r)
return return
default: default:
cn.setBad() cn.err.set(driver.ErrBadConn)
errorf("unexpected message %q; expected ReadyForQuery", t) errorf("unexpected message %q; expected ReadyForQuery", t)
} }
} }
@ -1778,7 +1801,7 @@ func (cn *conn) readParseResponse() {
cn.readReadyForQuery() cn.readReadyForQuery()
panic(err) panic(err)
default: default:
cn.setBad() cn.err.set(driver.ErrBadConn)
errorf("unexpected Parse response %q", t) errorf("unexpected Parse response %q", t)
} }
} }
@ -1803,7 +1826,7 @@ func (cn *conn) readStatementDescribeResponse() (paramTyps []oid.Oid, colNames [
cn.readReadyForQuery() cn.readReadyForQuery()
panic(err) panic(err)
default: default:
cn.setBad() cn.err.set(driver.ErrBadConn)
errorf("unexpected Describe statement response %q", t) errorf("unexpected Describe statement response %q", t)
} }
} }
@ -1821,7 +1844,7 @@ func (cn *conn) readPortalDescribeResponse() rowsHeader {
cn.readReadyForQuery() cn.readReadyForQuery()
panic(err) panic(err)
default: default:
cn.setBad() cn.err.set(driver.ErrBadConn)
errorf("unexpected Describe response %q", t) errorf("unexpected Describe response %q", t)
} }
panic("not reached") panic("not reached")
@ -1837,7 +1860,7 @@ func (cn *conn) readBindResponse() {
cn.readReadyForQuery() cn.readReadyForQuery()
panic(err) panic(err)
default: default:
cn.setBad() cn.err.set(driver.ErrBadConn)
errorf("unexpected Bind response %q", t) errorf("unexpected Bind response %q", t)
} }
} }
@ -1864,7 +1887,7 @@ func (cn *conn) postExecuteWorkaround() {
cn.saveMessage(t, r) cn.saveMessage(t, r)
return return
default: default:
cn.setBad() cn.err.set(driver.ErrBadConn)
errorf("unexpected message during extended query execution: %q", t) errorf("unexpected message during extended query execution: %q", t)
} }
} }
@ -1877,7 +1900,7 @@ func (cn *conn) readExecuteResponse(protocolState string) (res driver.Result, co
switch t { switch t {
case 'C': case 'C':
if err != nil { if err != nil {
cn.setBad() cn.err.set(driver.ErrBadConn)
errorf("unexpected CommandComplete after error %s", err) errorf("unexpected CommandComplete after error %s", err)
} }
res, commandTag = cn.parseComplete(r.string()) res, commandTag = cn.parseComplete(r.string())
@ -1891,7 +1914,7 @@ func (cn *conn) readExecuteResponse(protocolState string) (res driver.Result, co
err = parseError(r) err = parseError(r)
case 'T', 'D', 'I': case 'T', 'D', 'I':
if err != nil { if err != nil {
cn.setBad() cn.err.set(driver.ErrBadConn)
errorf("unexpected %q after error %s", t, err) errorf("unexpected %q after error %s", t, err)
} }
if t == 'I' { if t == 'I' {
@ -1899,7 +1922,7 @@ func (cn *conn) readExecuteResponse(protocolState string) (res driver.Result, co
} }
// ignore any results // ignore any results
default: default:
cn.setBad() cn.err.set(driver.ErrBadConn)
errorf("unknown %s response: %q", protocolState, t) errorf("unknown %s response: %q", protocolState, t)
} }
} }

View File

@ -7,10 +7,13 @@ import (
"fmt" "fmt"
"io" "io"
"io/ioutil" "io/ioutil"
"sync/atomic"
"time" "time"
) )
const (
watchCancelDialContextTimeout = time.Second * 10
)
// Implement the "QueryerContext" interface // Implement the "QueryerContext" interface
func (cn *conn) QueryContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Rows, error) { func (cn *conn) QueryContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Rows, error) {
list := make([]driver.Value, len(args)) list := make([]driver.Value, len(args))
@ -43,6 +46,14 @@ func (cn *conn) ExecContext(ctx context.Context, query string, args []driver.Nam
return cn.Exec(query, list) return cn.Exec(query, list)
} }
// Implement the "ConnPrepareContext" interface
func (cn *conn) PrepareContext(ctx context.Context, query string) (driver.Stmt, error) {
if finish := cn.watchCancel(ctx); finish != nil {
defer finish()
}
return cn.Prepare(query)
}
// Implement the "ConnBeginTx" interface // Implement the "ConnBeginTx" interface
func (cn *conn) BeginTx(ctx context.Context, opts driver.TxOptions) (driver.Tx, error) { func (cn *conn) BeginTx(ctx context.Context, opts driver.TxOptions) (driver.Tx, error) {
var mode string var mode string
@ -103,13 +114,13 @@ func (cn *conn) watchCancel(ctx context.Context) func() {
} }
// Set the connection state to bad so it does not get reused. // Set the connection state to bad so it does not get reused.
cn.setBad() cn.err.set(ctx.Err())
// At this point the function level context is canceled, // At this point the function level context is canceled,
// so it must not be used for the additional network // so it must not be used for the additional network
// request to cancel the query. // request to cancel the query.
// Create a new context to pass into the dial. // Create a new context to pass into the dial.
ctxCancel, cancel := context.WithTimeout(context.Background(), time.Second*10) ctxCancel, cancel := context.WithTimeout(context.Background(), watchCancelDialContextTimeout)
defer cancel() defer cancel()
_ = cn.cancel(ctxCancel) _ = cn.cancel(ctxCancel)
@ -119,7 +130,7 @@ func (cn *conn) watchCancel(ctx context.Context) func() {
return func() { return func() {
select { select {
case <-finished: case <-finished:
cn.setBad() cn.err.set(ctx.Err())
cn.Close() cn.Close()
case finished <- struct{}{}: case finished <- struct{}{}:
} }
@ -145,11 +156,8 @@ func (cn *conn) cancel(ctx context.Context) error {
defer c.Close() defer c.Close()
{ {
bad := &atomic.Value{}
bad.Store(false)
can := conn{ can := conn{
c: c, c: c,
bad: bad,
} }
err = can.ssl(o) err = can.ssl(o)
if err != nil { if err != nil {
@ -172,3 +180,68 @@ func (cn *conn) cancel(ctx context.Context) error {
return err return err
} }
} }
// Implement the "StmtQueryContext" interface
func (st *stmt) QueryContext(ctx context.Context, args []driver.NamedValue) (driver.Rows, error) {
list := make([]driver.Value, len(args))
for i, nv := range args {
list[i] = nv.Value
}
finish := st.watchCancel(ctx)
r, err := st.query(list)
if err != nil {
if finish != nil {
finish()
}
return nil, err
}
r.finish = finish
return r, nil
}
// Implement the "StmtExecContext" interface
func (st *stmt) ExecContext(ctx context.Context, args []driver.NamedValue) (driver.Result, error) {
list := make([]driver.Value, len(args))
for i, nv := range args {
list[i] = nv.Value
}
if finish := st.watchCancel(ctx); finish != nil {
defer finish()
}
return st.Exec(list)
}
// watchCancel is implemented on stmt in order to not mark the parent conn as bad
func (st *stmt) watchCancel(ctx context.Context) func() {
if done := ctx.Done(); done != nil {
finished := make(chan struct{})
go func() {
select {
case <-done:
// At this point the function level context is canceled,
// so it must not be used for the additional network
// request to cancel the query.
// Create a new context to pass into the dial.
ctxCancel, cancel := context.WithTimeout(context.Background(), watchCancelDialContextTimeout)
defer cancel()
_ = st.cancel(ctxCancel)
finished <- struct{}{}
case <-finished:
}
}()
return func() {
select {
case <-finished:
case finished <- struct{}{}:
}
}
}
return nil
}
func (st *stmt) cancel(ctx context.Context) error {
return st.cn.cancel(ctx)
}

76
vendor/github.com/lib/pq/copy.go generated vendored
View File

@ -49,12 +49,14 @@ type copyin struct {
buffer []byte buffer []byte
rowData chan []byte rowData chan []byte
done chan bool done chan bool
driver.Result
closed bool closed bool
sync.Mutex // guards err mu struct {
err error sync.Mutex
err error
driver.Result
}
} }
const ciBufferSize = 64 * 1024 const ciBufferSize = 64 * 1024
@ -98,13 +100,13 @@ awaitCopyInResponse:
err = parseError(r) err = parseError(r)
case 'Z': case 'Z':
if err == nil { if err == nil {
ci.setBad() ci.setBad(driver.ErrBadConn)
errorf("unexpected ReadyForQuery in response to COPY") errorf("unexpected ReadyForQuery in response to COPY")
} }
cn.processReadyForQuery(r) cn.processReadyForQuery(r)
return nil, err return nil, err
default: default:
ci.setBad() ci.setBad(driver.ErrBadConn)
errorf("unknown response for copy query: %q", t) errorf("unknown response for copy query: %q", t)
} }
} }
@ -123,7 +125,7 @@ awaitCopyInResponse:
cn.processReadyForQuery(r) cn.processReadyForQuery(r)
return nil, err return nil, err
default: default:
ci.setBad() ci.setBad(driver.ErrBadConn)
errorf("unknown response for CopyFail: %q", t) errorf("unknown response for CopyFail: %q", t)
} }
} }
@ -144,7 +146,7 @@ func (ci *copyin) resploop() {
var r readBuf var r readBuf
t, err := ci.cn.recvMessage(&r) t, err := ci.cn.recvMessage(&r)
if err != nil { if err != nil {
ci.setBad() ci.setBad(driver.ErrBadConn)
ci.setError(err) ci.setError(err)
ci.done <- true ci.done <- true
return return
@ -166,7 +168,7 @@ func (ci *copyin) resploop() {
err := parseError(&r) err := parseError(&r)
ci.setError(err) ci.setError(err)
default: default:
ci.setBad() ci.setBad(driver.ErrBadConn)
ci.setError(fmt.Errorf("unknown response during CopyIn: %q", t)) ci.setError(fmt.Errorf("unknown response during CopyIn: %q", t))
ci.done <- true ci.done <- true
return return
@ -174,46 +176,41 @@ func (ci *copyin) resploop() {
} }
} }
func (ci *copyin) setBad() { func (ci *copyin) setBad(err error) {
ci.Lock() ci.cn.err.set(err)
ci.cn.setBad()
ci.Unlock()
} }
func (ci *copyin) isBad() bool { func (ci *copyin) getBad() error {
ci.Lock() return ci.cn.err.get()
b := ci.cn.getBad()
ci.Unlock()
return b
} }
func (ci *copyin) isErrorSet() bool { func (ci *copyin) err() error {
ci.Lock() ci.mu.Lock()
isSet := (ci.err != nil) err := ci.mu.err
ci.Unlock() ci.mu.Unlock()
return isSet return err
} }
// setError() sets ci.err if one has not been set already. Caller must not be // setError() sets ci.err if one has not been set already. Caller must not be
// holding ci.Mutex. // holding ci.Mutex.
func (ci *copyin) setError(err error) { func (ci *copyin) setError(err error) {
ci.Lock() ci.mu.Lock()
if ci.err == nil { if ci.mu.err == nil {
ci.err = err ci.mu.err = err
} }
ci.Unlock() ci.mu.Unlock()
} }
func (ci *copyin) setResult(result driver.Result) { func (ci *copyin) setResult(result driver.Result) {
ci.Lock() ci.mu.Lock()
ci.Result = result ci.mu.Result = result
ci.Unlock() ci.mu.Unlock()
} }
func (ci *copyin) getResult() driver.Result { func (ci *copyin) getResult() driver.Result {
ci.Lock() ci.mu.Lock()
result := ci.Result result := ci.mu.Result
ci.Unlock() ci.mu.Unlock()
if result == nil { if result == nil {
return driver.RowsAffected(0) return driver.RowsAffected(0)
} }
@ -240,13 +237,13 @@ func (ci *copyin) Exec(v []driver.Value) (r driver.Result, err error) {
return nil, errCopyInClosed return nil, errCopyInClosed
} }
if ci.isBad() { if err := ci.getBad(); err != nil {
return nil, driver.ErrBadConn return nil, err
} }
defer ci.cn.errRecover(&err) defer ci.cn.errRecover(&err)
if ci.isErrorSet() { if err := ci.err(); err != nil {
return nil, ci.err return nil, err
} }
if len(v) == 0 { if len(v) == 0 {
@ -282,8 +279,8 @@ func (ci *copyin) Close() (err error) {
} }
ci.closed = true ci.closed = true
if ci.isBad() { if err := ci.getBad(); err != nil {
return driver.ErrBadConn return err
} }
defer ci.cn.errRecover(&err) defer ci.cn.errRecover(&err)
@ -299,8 +296,7 @@ func (ci *copyin) Close() (err error) {
<-ci.done <-ci.done
ci.cn.inCopy = false ci.cn.inCopy = false
if ci.isErrorSet() { if err := ci.err(); err != nil {
err = ci.err
return err return err
} }
return nil return nil

2
vendor/github.com/lib/pq/encode.go generated vendored
View File

@ -559,7 +559,7 @@ func parseBytea(s []byte) (result []byte, err error) {
if len(s) < 4 { if len(s) < 4 {
return nil, fmt.Errorf("invalid bytea sequence %v", s) return nil, fmt.Errorf("invalid bytea sequence %v", s)
} }
r, err := strconv.ParseInt(string(s[1:4]), 8, 9) r, err := strconv.ParseUint(string(s[1:4]), 8, 8)
if err != nil { if err != nil {
return nil, fmt.Errorf("could not parse bytea value: %s", err.Error()) return nil, fmt.Errorf("could not parse bytea value: %s", err.Error())
} }

12
vendor/github.com/lib/pq/error.go generated vendored
View File

@ -484,7 +484,7 @@ func (cn *conn) errRecover(err *error) {
case nil: case nil:
// Do nothing // Do nothing
case runtime.Error: case runtime.Error:
cn.setBad() cn.err.set(driver.ErrBadConn)
panic(v) panic(v)
case *Error: case *Error:
if v.Fatal() { if v.Fatal() {
@ -493,26 +493,26 @@ func (cn *conn) errRecover(err *error) {
*err = v *err = v
} }
case *net.OpError: case *net.OpError:
cn.setBad() cn.err.set(driver.ErrBadConn)
*err = v *err = v
case *safeRetryError: case *safeRetryError:
cn.setBad() cn.err.set(driver.ErrBadConn)
*err = driver.ErrBadConn *err = driver.ErrBadConn
case error: case error:
if v == io.EOF || v.(error).Error() == "remote error: handshake failure" { if v == io.EOF || v.Error() == "remote error: handshake failure" {
*err = driver.ErrBadConn *err = driver.ErrBadConn
} else { } else {
*err = v *err = v
} }
default: default:
cn.setBad() cn.err.set(driver.ErrBadConn)
panic(fmt.Sprintf("unknown error: %#v", e)) panic(fmt.Sprintf("unknown error: %#v", e))
} }
// Any time we return ErrBadConn, we need to remember it since *Tx doesn't // Any time we return ErrBadConn, we need to remember it since *Tx doesn't
// mark the connection bad in database/sql. // mark the connection bad in database/sql.
if *err == driver.ErrBadConn { if *err == driver.ErrBadConn {
cn.setBad() cn.err.set(driver.ErrBadConn)
} }
} }

1
vendor/github.com/lib/pq/notice.go generated vendored
View File

@ -1,3 +1,4 @@
//go:build go1.10
// +build go1.10 // +build go1.10
package pq package pq

View File

@ -1,3 +1,4 @@
//go:build !windows
// +build !windows // +build !windows
package pq package pq

View File

@ -1,3 +1,4 @@
//go:build windows
// +build windows // +build windows
package pq package pq

View File

@ -1,6 +1,7 @@
// Package pq is a pure Go Postgres driver for the database/sql package. // Package pq is a pure Go Postgres driver for the database/sql package.
// +build js android hurd illumos zos //go:build js || android || hurd || zos
// +build js android hurd zos
package pq package pq

View File

@ -1,6 +1,7 @@
// Package pq is a pure Go Postgres driver for the database/sql package. // Package pq is a pure Go Postgres driver for the database/sql package.
// +build aix darwin dragonfly freebsd linux nacl netbsd openbsd plan9 solaris rumprun //go:build aix || darwin || dragonfly || freebsd || (linux && !android) || nacl || netbsd || openbsd || plan9 || solaris || rumprun || illumos
// +build aix darwin dragonfly freebsd linux,!android nacl netbsd openbsd plan9 solaris rumprun illumos
package pq package pq

View File

@ -1,15 +0,0 @@
language: go
sudo: false
go:
- 1.13.x
- tip
before_install:
- go get -t -v ./...
script:
- ./go.test.sh
after_success:
- bash <(curl -s https://codecov.io/bash)

View File

@ -1,6 +1,6 @@
# go-colorable # go-colorable
[![Build Status](https://travis-ci.org/mattn/go-colorable.svg?branch=master)](https://travis-ci.org/mattn/go-colorable) [![Build Status](https://github.com/mattn/go-colorable/workflows/test/badge.svg)](https://github.com/mattn/go-colorable/actions?query=workflow%3Atest)
[![Codecov](https://codecov.io/gh/mattn/go-colorable/branch/master/graph/badge.svg)](https://codecov.io/gh/mattn/go-colorable) [![Codecov](https://codecov.io/gh/mattn/go-colorable/branch/master/graph/badge.svg)](https://codecov.io/gh/mattn/go-colorable)
[![GoDoc](https://godoc.org/github.com/mattn/go-colorable?status.svg)](http://godoc.org/github.com/mattn/go-colorable) [![GoDoc](https://godoc.org/github.com/mattn/go-colorable?status.svg)](http://godoc.org/github.com/mattn/go-colorable)
[![Go Report Card](https://goreportcard.com/badge/mattn/go-colorable)](https://goreportcard.com/report/mattn/go-colorable) [![Go Report Card](https://goreportcard.com/badge/mattn/go-colorable)](https://goreportcard.com/report/mattn/go-colorable)

View File

@ -1,3 +1,4 @@
//go:build appengine
// +build appengine // +build appengine
package colorable package colorable

View File

@ -1,5 +1,5 @@
// +build !windows //go:build !windows && !appengine
// +build !appengine // +build !windows,!appengine
package colorable package colorable

View File

@ -1,5 +1,5 @@
// +build windows //go:build windows && !appengine
// +build !appengine // +build windows,!appengine
package colorable package colorable
@ -452,18 +452,22 @@ func (w *Writer) Write(data []byte) (n int, err error) {
} else { } else {
er = bytes.NewReader(data) er = bytes.NewReader(data)
} }
var bw [1]byte var plaintext bytes.Buffer
loop: loop:
for { for {
c1, err := er.ReadByte() c1, err := er.ReadByte()
if err != nil { if err != nil {
plaintext.WriteTo(w.out)
break loop break loop
} }
if c1 != 0x1b { if c1 != 0x1b {
bw[0] = c1 plaintext.WriteByte(c1)
w.out.Write(bw[:])
continue continue
} }
_, err = plaintext.WriteTo(w.out)
if err != nil {
break loop
}
c2, err := er.ReadByte() c2, err := er.ReadByte()
if err != nil { if err != nil {
break loop break loop

View File

@ -18,18 +18,22 @@ func NewNonColorable(w io.Writer) io.Writer {
// Write writes data on console // Write writes data on console
func (w *NonColorable) Write(data []byte) (n int, err error) { func (w *NonColorable) Write(data []byte) (n int, err error) {
er := bytes.NewReader(data) er := bytes.NewReader(data)
var bw [1]byte var plaintext bytes.Buffer
loop: loop:
for { for {
c1, err := er.ReadByte() c1, err := er.ReadByte()
if err != nil { if err != nil {
plaintext.WriteTo(w.out)
break loop break loop
} }
if c1 != 0x1b { if c1 != 0x1b {
bw[0] = c1 plaintext.WriteByte(c1)
w.out.Write(bw[:])
continue continue
} }
_, err = plaintext.WriteTo(w.out)
if err != nil {
break loop
}
c2, err := er.ReadByte() c2, err := er.ReadByte()
if err != nil { if err != nil {
break loop break loop
@ -38,7 +42,6 @@ loop:
continue continue
} }
var buf bytes.Buffer
for { for {
c, err := er.ReadByte() c, err := er.ReadByte()
if err != nil { if err != nil {
@ -47,7 +50,6 @@ loop:
if ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || c == '@' { if ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || c == '@' {
break break
} }
buf.Write([]byte(string(c)))
} }
} }

View File

@ -1,14 +0,0 @@
language: go
sudo: false
go:
- 1.13.x
- tip
before_install:
- go get -t -v ./...
script:
- ./go.test.sh
after_success:
- bash <(curl -s https://codecov.io/bash)

View File

@ -1,3 +1,4 @@
//go:build (darwin || freebsd || openbsd || netbsd || dragonfly) && !appengine
// +build darwin freebsd openbsd netbsd dragonfly // +build darwin freebsd openbsd netbsd dragonfly
// +build !appengine // +build !appengine

View File

@ -1,3 +1,4 @@
//go:build appengine || js || nacl || wasm
// +build appengine js nacl wasm // +build appengine js nacl wasm
package isatty package isatty

View File

@ -1,3 +1,4 @@
//go:build plan9
// +build plan9 // +build plan9
package isatty package isatty

View File

@ -1,5 +1,5 @@
// +build solaris //go:build solaris && !appengine
// +build !appengine // +build solaris,!appengine
package isatty package isatty

View File

@ -1,3 +1,4 @@
//go:build (linux || aix || zos) && !appengine
// +build linux aix zos // +build linux aix zos
// +build !appengine // +build !appengine

View File

@ -1,5 +1,5 @@
// +build windows //go:build windows && !appengine
// +build !appengine // +build windows,!appengine
package isatty package isatty
@ -76,7 +76,7 @@ func isCygwinPipeName(name string) bool {
} }
// getFileNameByHandle use the undocomented ntdll NtQueryObject to get file full name from file handler // getFileNameByHandle use the undocomented ntdll NtQueryObject to get file full name from file handler
// since GetFileInformationByHandleEx is not avilable under windows Vista and still some old fashion // since GetFileInformationByHandleEx is not available under windows Vista and still some old fashion
// guys are using Windows XP, this is a workaround for those guys, it will also work on system from // guys are using Windows XP, this is a workaround for those guys, it will also work on system from
// Windows vista to 10 // Windows vista to 10
// see https://stackoverflow.com/a/18792477 for details // see https://stackoverflow.com/a/18792477 for details

View File

@ -1,7 +1,7 @@
language: go language: go
go: go:
- 1.8.x - 1.9.x
- 1.x - 1.x
before_install: before_install:

View File

@ -1,15 +1,9 @@
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'. # This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
[[projects]]
name = "github.com/modern-go/concurrent"
packages = ["."]
revision = "e0a39a4cb4216ea8db28e22a69f4ec25610d513a"
version = "1.0.0"
[solve-meta] [solve-meta]
analyzer-name = "dep" analyzer-name = "dep"
analyzer-version = 1 analyzer-version = 1
inputs-digest = "daee8a88b3498b61c5640056665b8b9eea062006f5e596bbb6a3ed9119a11ec7" input-imports = []
solver-name = "gps-cdcl" solver-name = "gps-cdcl"
solver-version = 1 solver-version = 1

View File

@ -26,10 +26,6 @@
ignored = [] ignored = []
[[constraint]]
name = "github.com/modern-go/concurrent"
version = "1.0.0"
[prune] [prune]
go-tests = true go-tests = true
unused-packages = true unused-packages = true

23
vendor/github.com/modern-go/reflect2/go_above_118.go generated vendored Normal file
View File

@ -0,0 +1,23 @@
//+build go1.18
package reflect2
import (
"unsafe"
)
// m escapes into the return value, but the caller of mapiterinit
// doesn't let the return value escape.
//go:noescape
//go:linkname mapiterinit reflect.mapiterinit
func mapiterinit(rtype unsafe.Pointer, m unsafe.Pointer, it *hiter)
func (type2 *UnsafeMapType) UnsafeIterate(obj unsafe.Pointer) MapIterator {
var it hiter
mapiterinit(type2.rtype, *(*unsafe.Pointer)(obj), &it)
return &UnsafeMapIterator{
hiter: &it,
pKeyRType: type2.pKeyRType,
pElemRType: type2.pElemRType,
}
}

View File

@ -1,8 +0,0 @@
//+build go1.7
package reflect2
import "unsafe"
//go:linkname resolveTypeOff reflect.resolveTypeOff
func resolveTypeOff(rtype unsafe.Pointer, off int32) unsafe.Pointer

View File

@ -6,6 +6,9 @@ import (
"unsafe" "unsafe"
) )
//go:linkname resolveTypeOff reflect.resolveTypeOff
func resolveTypeOff(rtype unsafe.Pointer, off int32) unsafe.Pointer
//go:linkname makemap reflect.makemap //go:linkname makemap reflect.makemap
func makemap(rtype unsafe.Pointer, cap int) (m unsafe.Pointer) func makemap(rtype unsafe.Pointer, cap int) (m unsafe.Pointer)

21
vendor/github.com/modern-go/reflect2/go_below_118.go generated vendored Normal file
View File

@ -0,0 +1,21 @@
//+build !go1.18
package reflect2
import (
"unsafe"
)
// m escapes into the return value, but the caller of mapiterinit
// doesn't let the return value escape.
//go:noescape
//go:linkname mapiterinit reflect.mapiterinit
func mapiterinit(rtype unsafe.Pointer, m unsafe.Pointer) (val *hiter)
func (type2 *UnsafeMapType) UnsafeIterate(obj unsafe.Pointer) MapIterator {
return &UnsafeMapIterator{
hiter: mapiterinit(type2.rtype, *(*unsafe.Pointer)(obj)),
pKeyRType: type2.pKeyRType,
pElemRType: type2.pElemRType,
}
}

View File

@ -1,9 +0,0 @@
//+build !go1.7
package reflect2
import "unsafe"
func resolveTypeOff(rtype unsafe.Pointer, off int32) unsafe.Pointer {
return nil
}

Some files were not shown because too many files have changed in this diff Show More