diff options
Diffstat (limited to 'vendor/github.com/gin-gonic')
36 files changed, 4504 insertions, 0 deletions
| diff --git a/vendor/github.com/gin-gonic/gin/.gitignore b/vendor/github.com/gin-gonic/gin/.gitignore new file mode 100644 index 0000000..9f48f14 --- /dev/null +++ b/vendor/github.com/gin-gonic/gin/.gitignore @@ -0,0 +1,4 @@ +Godeps/* +!Godeps/Godeps.json +coverage.out +count.out diff --git a/vendor/github.com/gin-gonic/gin/.travis.yml b/vendor/github.com/gin-gonic/gin/.travis.yml new file mode 100644 index 0000000..695f0b7 --- /dev/null +++ b/vendor/github.com/gin-gonic/gin/.travis.yml @@ -0,0 +1,22 @@ +language: go +sudo: false +go: +  - 1.4 +  - 1.4.2 +  - tip + +script: +  - go get golang.org/x/tools/cmd/cover +  - go get github.com/mattn/goveralls +  - go test -v -covermode=count -coverprofile=coverage.out + +after_success: +  - goveralls -coverprofile=coverage.out -service=travis-ci -repotoken yFj7FrCeddvBzUaaCyG33jCLfWXeb93eA + +notifications: +  webhooks: +    urls: +      - https://webhooks.gitter.im/e/acc2c57482e94b44f557 +    on_success: change  # options: [always|never|change] default: always +    on_failure: always  # options: [always|never|change] default: always +    on_start: false     # default: false diff --git a/vendor/github.com/gin-gonic/gin/AUTHORS.md b/vendor/github.com/gin-gonic/gin/AUTHORS.md new file mode 100644 index 0000000..2feaf46 --- /dev/null +++ b/vendor/github.com/gin-gonic/gin/AUTHORS.md @@ -0,0 +1,229 @@ +List of all the awesome people working to make Gin the best Web Framework in Go. + + + +##gin 0.x series authors + +**Maintainer:** Manu Martinez-Almeida (@manucorporat), Javier Provecho (@javierprovecho) + +People and companies, who have contributed, in alphabetical order. + +**@858806258 (杰哥)** +- Fix typo in example + + +**@achedeuzot (Klemen Sever)** +- Fix newline debug printing + + +**@adammck (Adam Mckaig)** +- Add MIT license + + +**@AlexanderChen1989 (Alexander)** +- Typos in README + + +**@alexanderdidenko (Aleksandr Didenko)** +- Add support multipart/form-data + + +**@alexandernyquist (Alexander Nyquist)** +- Using template.Must to fix multiple return issue +- ★ Added support for OPTIONS verb +- ★ Setting response headers before calling WriteHeader +- Improved documentation for model binding +- ★ Added Content.Redirect() +- ★ Added tons of Unit tests + + +**@austinheap (Austin Heap)** +- Added travis CI integration + + +**@andredublin (Andre Dublin)** +- Fix typo in comment + + +**@bredov (Ludwig Valda Vasquez)** +- Fix html templating in debug mode + + +**@bluele (Jun Kimura)** +- Fixes code examples in README + + +**@chad-russell** +- ★ Support for serializing gin.H into XML + + +**@dickeyxxx (Jeff Dickey)** +- Typos in README +- Add example about serving static files + + +**@donileo (Adonis)** +- Add NoMethod handler + + +**@dutchcoders (DutchCoders)** +- ★ Fix security bug that allows client to spoof ip +- Fix typo. r.HTMLTemplates -> SetHTMLTemplate + + +**@el3ctro- (Joshua Loper)** +- Fix typo in example + + +**@ethankan (Ethan Kan)** +- Unsigned integers in binding + + +**(Evgeny Persienko)** +- Validate sub structures + + +**@frankbille (Frank Bille)** +- Add support for HTTP Realm Auth + + +**@fmd (Fareed Dudhia)** +- Fix typo. SetHTTPTemplate -> SetHTMLTemplate + + +**@ironiridis (Christopher Harrington)** +- Remove old reference + + +**@jammie-stackhouse (Jamie Stackhouse)** +- Add more shortcuts for router methods + + +**@jasonrhansen** +- Fix spelling and grammar errors in documentation + + +**@JasonSoft (Jason Lee)** +- Fix typo in comment + + +**@joiggama (Ignacio Galindo)** +- Add utf-8 charset header on renders + + +**@julienschmidt (Julien Schmidt)** +- gofmt the code examples + + +**@kelcecil (Kel Cecil)** +- Fix readme typo + + +**@kyledinh (Kyle Dinh)** +- Adds RunTLS() + + +**@LinusU (Linus Unnebäck)** +- Small fixes in README + + +**@loongmxbt (Saint Asky)** +- Fix typo in example + + +**@lucas-clemente (Lucas Clemente)** +- ★ work around path.Join removing trailing slashes from routes + + +**@mattn (Yasuhiro Matsumoto)** +- Improve color logger + + +**@mdigger (Dmitry Sedykh)** +- Fixes Form binding when content-type is x-www-form-urlencoded +- No repeat call c.Writer.Status() in gin.Logger +- Fixes Content-Type for json render + + +**@mirzac (Mirza Ceric)** +- Fix debug printing + + +**@mopemope (Yutaka Matsubara)** +- ★ Adds Godep support (Dependencies Manager) +- Fix variadic parameter in the flexible render API +- Fix Corrupted plain render +- Add Pluggable View Renderer Example +  + +**@msemenistyi (Mykyta Semenistyi)** +- update Readme.md. Add code to String method + + +**@msoedov (Sasha Myasoedov)** +- ★ Adds tons of unit tests. + + +**@ngerakines (Nick Gerakines)** +- ★ Improves API, c.GET() doesn't panic +- Adds MustGet() method + + +**@r8k (Rajiv Kilaparti)** +- Fix Port usage in README. + + +**@rayrod2030 (Ray Rodriguez)** +- Fix typo in example + + +**@rns** +- Fix typo in example + + +**@RobAWilkinson (Robert Wilkinson)** +- Add example of forms and params + + +**@rogierlommers (Rogier Lommers)** +- Add updated static serve example + + +**@se77en (Damon Zhao)** +- Improve color logging + + +**@silasb (Silas Baronda)** +- Fixing quotes in README + + +**@SkuliOskarsson (Skuli Oskarsson)** +- Fixes some texts in README II + + +**@slimmy (Jimmy Pettersson)** +- Added messages for required bindings + + +**@smira (Andrey Smirnov)** +- Add support for ignored/unexported fields in binding + + +**@superalsrk (SRK.Lyu)** +- Update httprouter godeps + + +**@tebeka (Miki Tebeka)** +- Use net/http constants instead of numeric values + + +**@techjanitor** +- Update context.go reserved IPs + + +**@yosssi (Keiji Yoshida)** +- Fix link in README + + +**@yuyabee** +- Fixed README
\ No newline at end of file diff --git a/vendor/github.com/gin-gonic/gin/BENCHMARKS.md b/vendor/github.com/gin-gonic/gin/BENCHMARKS.md new file mode 100644 index 0000000..181f75b --- /dev/null +++ b/vendor/github.com/gin-gonic/gin/BENCHMARKS.md @@ -0,0 +1,298 @@ +**Machine:** intel i7 ivy bridge quad-core. 8GB RAM.   +**Date:** June 4th, 2015   +[https://github.com/gin-gonic/go-http-routing-benchmark](https://github.com/gin-gonic/go-http-routing-benchmark) + +``` +BenchmarkAce_Param   5000000           372 ns/op          32 B/op          1 allocs/op +BenchmarkBear_Param  1000000          1165 ns/op         424 B/op          5 allocs/op +BenchmarkBeego_Param     1000000          2440 ns/op         720 B/op         10 allocs/op +BenchmarkBone_Param  1000000          1067 ns/op         384 B/op          3 allocs/op +BenchmarkDenco_Param     5000000           240 ns/op          32 B/op          1 allocs/op +BenchmarkEcho_Param 10000000           130 ns/op           0 B/op          0 allocs/op +BenchmarkGin_Param  10000000           133 ns/op           0 B/op          0 allocs/op +BenchmarkGocraftWeb_Param    1000000          1826 ns/op         656 B/op          9 allocs/op +BenchmarkGoji_Param  2000000           957 ns/op         336 B/op          2 allocs/op +BenchmarkGoJsonRest_Param    1000000          2021 ns/op         657 B/op         14 allocs/op +BenchmarkGoRestful_Param      200000          8825 ns/op        2496 B/op         31 allocs/op +BenchmarkGorillaMux_Param     500000          3340 ns/op         784 B/op          9 allocs/op +BenchmarkHttpRouter_Param   10000000           152 ns/op          32 B/op          1 allocs/op +BenchmarkHttpTreeMux_Param   2000000           717 ns/op         336 B/op          2 allocs/op +BenchmarkKocha_Param     3000000           423 ns/op          56 B/op          3 allocs/op +BenchmarkMacaron_Param   1000000          3410 ns/op        1104 B/op         11 allocs/op +BenchmarkMartini_Param    200000          7101 ns/op        1152 B/op         12 allocs/op +BenchmarkPat_Param   1000000          2040 ns/op         656 B/op         14 allocs/op +BenchmarkPossum_Param    1000000          2048 ns/op         624 B/op          7 allocs/op +BenchmarkR2router_Param  1000000          1144 ns/op         432 B/op          6 allocs/op +BenchmarkRevel_Param      200000          6725 ns/op        1672 B/op         28 allocs/op +BenchmarkRivet_Param     1000000          1121 ns/op         464 B/op          5 allocs/op +BenchmarkTango_Param     1000000          1479 ns/op         256 B/op         10 allocs/op +BenchmarkTigerTonic_Param    1000000          3393 ns/op         992 B/op         19 allocs/op +BenchmarkTraffic_Param    300000          5525 ns/op        1984 B/op         23 allocs/op +BenchmarkVulcan_Param    2000000           924 ns/op          98 B/op          3 allocs/op +BenchmarkZeus_Param  1000000          1084 ns/op         368 B/op          3 allocs/op +BenchmarkAce_Param5  3000000           614 ns/op         160 B/op          1 allocs/op +BenchmarkBear_Param5     1000000          1617 ns/op         469 B/op          5 allocs/op +BenchmarkBeego_Param5    1000000          3373 ns/op         992 B/op         13 allocs/op +BenchmarkBone_Param5     1000000          1478 ns/op         432 B/op          3 allocs/op +BenchmarkDenco_Param5    3000000           570 ns/op         160 B/op          1 allocs/op +BenchmarkEcho_Param5     5000000           256 ns/op           0 B/op          0 allocs/op +BenchmarkGin_Param5 10000000           222 ns/op           0 B/op          0 allocs/op +BenchmarkGocraftWeb_Param5   1000000          2789 ns/op         928 B/op         12 allocs/op +BenchmarkGoji_Param5     1000000          1287 ns/op         336 B/op          2 allocs/op +BenchmarkGoJsonRest_Param5   1000000          3670 ns/op        1105 B/op         17 allocs/op +BenchmarkGoRestful_Param5     200000         10756 ns/op        2672 B/op         31 allocs/op +BenchmarkGorillaMux_Param5    300000          5543 ns/op         912 B/op          9 allocs/op +BenchmarkHttpRouter_Param5   5000000           403 ns/op         160 B/op          1 allocs/op +BenchmarkHttpTreeMux_Param5  1000000          1089 ns/op         336 B/op          2 allocs/op +BenchmarkKocha_Param5    1000000          1682 ns/op         440 B/op         10 allocs/op +BenchmarkMacaron_Param5   300000          4596 ns/op        1376 B/op         14 allocs/op +BenchmarkMartini_Param5   100000         15703 ns/op        1280 B/op         12 allocs/op +BenchmarkPat_Param5   300000          5320 ns/op        1008 B/op         42 allocs/op +BenchmarkPossum_Param5   1000000          2155 ns/op         624 B/op          7 allocs/op +BenchmarkR2router_Param5     1000000          1559 ns/op         432 B/op          6 allocs/op +BenchmarkRevel_Param5     200000          8184 ns/op        2024 B/op         35 allocs/op +BenchmarkRivet_Param5    1000000          1914 ns/op         528 B/op          9 allocs/op +BenchmarkTango_Param5    1000000          3280 ns/op         944 B/op         18 allocs/op +BenchmarkTigerTonic_Param5    200000         11638 ns/op        2519 B/op         53 allocs/op +BenchmarkTraffic_Param5   200000          8941 ns/op        2280 B/op         31 allocs/op +BenchmarkVulcan_Param5   1000000          1279 ns/op          98 B/op          3 allocs/op +BenchmarkZeus_Param5     1000000          1574 ns/op         416 B/op          3 allocs/op +BenchmarkAce_Param20     1000000          1528 ns/op         640 B/op          1 allocs/op +BenchmarkBear_Param20     300000          4906 ns/op        1633 B/op          5 allocs/op +BenchmarkBeego_Param20    200000         10529 ns/op        3868 B/op         17 allocs/op +BenchmarkBone_Param20     300000          7362 ns/op        2539 B/op          5 allocs/op +BenchmarkDenco_Param20   1000000          1884 ns/op         640 B/op          1 allocs/op +BenchmarkEcho_Param20    2000000           689 ns/op           0 B/op          0 allocs/op +BenchmarkGin_Param20     3000000           545 ns/op           0 B/op          0 allocs/op +BenchmarkGocraftWeb_Param20   200000          9437 ns/op        3804 B/op         16 allocs/op +BenchmarkGoji_Param20     500000          3987 ns/op        1246 B/op          2 allocs/op +BenchmarkGoJsonRest_Param20   100000         12799 ns/op        4492 B/op         21 allocs/op +BenchmarkGoRestful_Param20    100000         19451 ns/op        5244 B/op         33 allocs/op +BenchmarkGorillaMux_Param20   100000         12456 ns/op        3275 B/op         11 allocs/op +BenchmarkHttpRouter_Param20  1000000          1333 ns/op         640 B/op          1 allocs/op +BenchmarkHttpTreeMux_Param20      300000          6490 ns/op        2187 B/op          4 allocs/op +BenchmarkKocha_Param20    300000          5335 ns/op        1808 B/op         27 allocs/op +BenchmarkMacaron_Param20      200000         11325 ns/op        4252 B/op         18 allocs/op +BenchmarkMartini_Param20       20000         64419 ns/op        3644 B/op         14 allocs/op +BenchmarkPat_Param20       50000         24672 ns/op        4888 B/op        151 allocs/op +BenchmarkPossum_Param20  1000000          2085 ns/op         624 B/op          7 allocs/op +BenchmarkR2router_Param20     300000          6809 ns/op        2283 B/op          8 allocs/op +BenchmarkRevel_Param20    100000         16600 ns/op        5551 B/op         54 allocs/op +BenchmarkRivet_Param20    200000          8428 ns/op        2620 B/op         26 allocs/op +BenchmarkTango_Param20    100000         16302 ns/op        8224 B/op         48 allocs/op +BenchmarkTigerTonic_Param20    30000         46828 ns/op       10538 B/op        178 allocs/op +BenchmarkTraffic_Param20       50000         28871 ns/op        7998 B/op         66 allocs/op +BenchmarkVulcan_Param20  1000000          2267 ns/op          98 B/op          3 allocs/op +BenchmarkZeus_Param20     300000          6828 ns/op        2507 B/op          5 allocs/op +BenchmarkAce_ParamWrite  3000000           502 ns/op          40 B/op          2 allocs/op +BenchmarkBear_ParamWrite     1000000          1303 ns/op         424 B/op          5 allocs/op +BenchmarkBeego_ParamWrite    1000000          2489 ns/op         728 B/op         11 allocs/op +BenchmarkBone_ParamWrite     1000000          1181 ns/op         384 B/op          3 allocs/op +BenchmarkDenco_ParamWrite    5000000           315 ns/op          32 B/op          1 allocs/op +BenchmarkEcho_ParamWrite    10000000           237 ns/op           8 B/op          1 allocs/op +BenchmarkGin_ParamWrite  5000000           336 ns/op           0 B/op          0 allocs/op +BenchmarkGocraftWeb_ParamWrite   1000000          2079 ns/op         664 B/op         10 allocs/op +BenchmarkGoji_ParamWrite     1000000          1092 ns/op         336 B/op          2 allocs/op +BenchmarkGoJsonRest_ParamWrite   1000000          3329 ns/op        1136 B/op         19 allocs/op +BenchmarkGoRestful_ParamWrite     200000          9273 ns/op        2504 B/op         32 allocs/op +BenchmarkGorillaMux_ParamWrite    500000          3919 ns/op         792 B/op         10 allocs/op +BenchmarkHttpRouter_ParamWrite  10000000           223 ns/op          32 B/op          1 allocs/op +BenchmarkHttpTreeMux_ParamWrite  2000000           788 ns/op         336 B/op          2 allocs/op +BenchmarkKocha_ParamWrite    3000000           549 ns/op          56 B/op          3 allocs/op +BenchmarkMacaron_ParamWrite   500000          4558 ns/op        1216 B/op         16 allocs/op +BenchmarkMartini_ParamWrite   200000          8850 ns/op        1256 B/op         16 allocs/op +BenchmarkPat_ParamWrite   500000          3679 ns/op        1088 B/op         19 allocs/op +BenchmarkPossum_ParamWrite   1000000          2114 ns/op         624 B/op          7 allocs/op +BenchmarkR2router_ParamWrite     1000000          1320 ns/op         432 B/op          6 allocs/op +BenchmarkRevel_ParamWrite     200000          8048 ns/op        2128 B/op         33 allocs/op +BenchmarkRivet_ParamWrite    1000000          1393 ns/op         472 B/op          6 allocs/op +BenchmarkTango_ParamWrite    2000000           819 ns/op         136 B/op          5 allocs/op +BenchmarkTigerTonic_ParamWrite    300000          5860 ns/op        1440 B/op         25 allocs/op +BenchmarkTraffic_ParamWrite   200000          7429 ns/op        2400 B/op         27 allocs/op +BenchmarkVulcan_ParamWrite   2000000           972 ns/op          98 B/op          3 allocs/op +BenchmarkZeus_ParamWrite     1000000          1226 ns/op         368 B/op          3 allocs/op +BenchmarkAce_GithubStatic    5000000           294 ns/op           0 B/op          0 allocs/op +BenchmarkBear_GithubStatic   3000000           575 ns/op          88 B/op          3 allocs/op +BenchmarkBeego_GithubStatic  1000000          1561 ns/op         368 B/op          7 allocs/op +BenchmarkBone_GithubStatic    200000         12301 ns/op        2880 B/op         60 allocs/op +BenchmarkDenco_GithubStatic 20000000            74.6 ns/op         0 B/op          0 allocs/op +BenchmarkEcho_GithubStatic  10000000           176 ns/op           0 B/op          0 allocs/op +BenchmarkGin_GithubStatic   10000000           159 ns/op           0 B/op          0 allocs/op +BenchmarkGocraftWeb_GithubStatic     1000000          1116 ns/op         304 B/op          6 allocs/op +BenchmarkGoji_GithubStatic   5000000           413 ns/op           0 B/op          0 allocs/op +BenchmarkGoRestful_GithubStatic    30000         55200 ns/op        3520 B/op         36 allocs/op +BenchmarkGoJsonRest_GithubStatic     1000000          1504 ns/op         337 B/op         12 allocs/op +BenchmarkGorillaMux_GithubStatic      100000         23620 ns/op         464 B/op          8 allocs/op +BenchmarkHttpRouter_GithubStatic    20000000            78.3 ns/op         0 B/op          0 allocs/op +BenchmarkHttpTreeMux_GithubStatic   20000000            84.9 ns/op         0 B/op          0 allocs/op +BenchmarkKocha_GithubStatic 20000000           111 ns/op           0 B/op          0 allocs/op +BenchmarkMacaron_GithubStatic    1000000          2686 ns/op         752 B/op          8 allocs/op +BenchmarkMartini_GithubStatic     100000         22244 ns/op         832 B/op         11 allocs/op +BenchmarkPat_GithubStatic     100000         13278 ns/op        3648 B/op         76 allocs/op +BenchmarkPossum_GithubStatic     1000000          1429 ns/op         480 B/op          4 allocs/op +BenchmarkR2router_GithubStatic   2000000           726 ns/op         144 B/op          5 allocs/op +BenchmarkRevel_GithubStatic   300000          6271 ns/op        1288 B/op         25 allocs/op +BenchmarkRivet_GithubStatic  3000000           474 ns/op         112 B/op          2 allocs/op +BenchmarkTango_GithubStatic  1000000          1842 ns/op         256 B/op         10 allocs/op +BenchmarkTigerTonic_GithubStatic     5000000           361 ns/op          48 B/op          1 allocs/op +BenchmarkTraffic_GithubStatic      30000         47197 ns/op       18920 B/op        149 allocs/op +BenchmarkVulcan_GithubStatic     1000000          1415 ns/op          98 B/op          3 allocs/op +BenchmarkZeus_GithubStatic   1000000          2522 ns/op         512 B/op         11 allocs/op +BenchmarkAce_GithubParam     3000000           578 ns/op          96 B/op          1 allocs/op +BenchmarkBear_GithubParam    1000000          1592 ns/op         464 B/op          5 allocs/op +BenchmarkBeego_GithubParam   1000000          2891 ns/op         784 B/op         11 allocs/op +BenchmarkBone_GithubParam     300000          6440 ns/op        1456 B/op         16 allocs/op +BenchmarkDenco_GithubParam   3000000           514 ns/op         128 B/op          1 allocs/op +BenchmarkEcho_GithubParam    5000000           292 ns/op           0 B/op          0 allocs/op +BenchmarkGin_GithubParam    10000000           242 ns/op           0 B/op          0 allocs/op +BenchmarkGocraftWeb_GithubParam  1000000          2343 ns/op         720 B/op         10 allocs/op +BenchmarkGoji_GithubParam    1000000          1566 ns/op         336 B/op          2 allocs/op +BenchmarkGoJsonRest_GithubParam  1000000          2828 ns/op         721 B/op         15 allocs/op +BenchmarkGoRestful_GithubParam     10000        177711 ns/op        2816 B/op         35 allocs/op +BenchmarkGorillaMux_GithubParam   100000         13591 ns/op         816 B/op          9 allocs/op +BenchmarkHttpRouter_GithubParam  5000000           352 ns/op          96 B/op          1 allocs/op +BenchmarkHttpTreeMux_GithubParam     2000000           973 ns/op         336 B/op          2 allocs/op +BenchmarkKocha_GithubParam   2000000           889 ns/op         128 B/op          5 allocs/op +BenchmarkMacaron_GithubParam      500000          4047 ns/op        1168 B/op         12 allocs/op +BenchmarkMartini_GithubParam       50000         28982 ns/op        1184 B/op         12 allocs/op +BenchmarkPat_GithubParam      200000          8747 ns/op        2480 B/op         56 allocs/op +BenchmarkPossum_GithubParam  1000000          2158 ns/op         624 B/op          7 allocs/op +BenchmarkR2router_GithubParam    1000000          1352 ns/op         432 B/op          6 allocs/op +BenchmarkRevel_GithubParam    200000          7673 ns/op        1784 B/op         30 allocs/op +BenchmarkRivet_GithubParam   1000000          1573 ns/op         480 B/op          6 allocs/op +BenchmarkTango_GithubParam   1000000          2418 ns/op         480 B/op         13 allocs/op +BenchmarkTigerTonic_GithubParam   300000          6048 ns/op        1440 B/op         28 allocs/op +BenchmarkTraffic_GithubParam      100000         20143 ns/op        6024 B/op         55 allocs/op +BenchmarkVulcan_GithubParam  1000000          2224 ns/op          98 B/op          3 allocs/op +BenchmarkZeus_GithubParam     500000          4156 ns/op        1312 B/op         12 allocs/op +BenchmarkAce_GithubAll     10000        109482 ns/op       13792 B/op        167 allocs/op +BenchmarkBear_GithubAll    10000        287490 ns/op       79952 B/op        943 allocs/op +BenchmarkBeego_GithubAll        3000        562184 ns/op      146272 B/op       2092 allocs/op +BenchmarkBone_GithubAll      500       2578716 ns/op      648016 B/op       8119 allocs/op +BenchmarkDenco_GithubAll       20000         94955 ns/op       20224 B/op        167 allocs/op +BenchmarkEcho_GithubAll    30000         58705 ns/op           0 B/op          0 allocs/op +BenchmarkGin_GithubAll     30000         50991 ns/op           0 B/op          0 allocs/op +BenchmarkGocraftWeb_GithubAll       5000        449648 ns/op      133280 B/op       1889 allocs/op +BenchmarkGoji_GithubAll     2000        689748 ns/op       56113 B/op        334 allocs/op +BenchmarkGoJsonRest_GithubAll       5000        537769 ns/op      135995 B/op       2940 allocs/op +BenchmarkGoRestful_GithubAll         100      18410628 ns/op      797236 B/op       7725 allocs/op +BenchmarkGorillaMux_GithubAll        200       8036360 ns/op      153137 B/op       1791 allocs/op +BenchmarkHttpRouter_GithubAll      20000         63506 ns/op       13792 B/op        167 allocs/op +BenchmarkHttpTreeMux_GithubAll     10000        165927 ns/op       56112 B/op        334 allocs/op +BenchmarkKocha_GithubAll       10000        171362 ns/op       23304 B/op        843 allocs/op +BenchmarkMacaron_GithubAll      2000        817008 ns/op      224960 B/op       2315 allocs/op +BenchmarkMartini_GithubAll       100      12609209 ns/op      237952 B/op       2686 allocs/op +BenchmarkPat_GithubAll       300       4830398 ns/op     1504101 B/op      32222 allocs/op +BenchmarkPossum_GithubAll      10000        301716 ns/op       97440 B/op        812 allocs/op +BenchmarkR2router_GithubAll    10000        270691 ns/op       77328 B/op       1182 allocs/op +BenchmarkRevel_GithubAll        1000       1491919 ns/op      345553 B/op       5918 allocs/op +BenchmarkRivet_GithubAll       10000        283860 ns/op       84272 B/op       1079 allocs/op +BenchmarkTango_GithubAll        5000        473821 ns/op       87078 B/op       2470 allocs/op +BenchmarkTigerTonic_GithubAll       2000       1120131 ns/op      241088 B/op       6052 allocs/op +BenchmarkTraffic_GithubAll       200       8708979 ns/op     2664762 B/op      22390 allocs/op +BenchmarkVulcan_GithubAll       5000        353392 ns/op       19894 B/op        609 allocs/op +BenchmarkZeus_GithubAll     2000        944234 ns/op      300688 B/op       2648 allocs/op +BenchmarkAce_GPlusStatic     5000000           251 ns/op           0 B/op          0 allocs/op +BenchmarkBear_GPlusStatic    3000000           415 ns/op          72 B/op          3 allocs/op +BenchmarkBeego_GPlusStatic   1000000          1416 ns/op         352 B/op          7 allocs/op +BenchmarkBone_GPlusStatic   10000000           192 ns/op          32 B/op          1 allocs/op +BenchmarkDenco_GPlusStatic  30000000            47.6 ns/op         0 B/op          0 allocs/op +BenchmarkEcho_GPlusStatic   10000000           131 ns/op           0 B/op          0 allocs/op +BenchmarkGin_GPlusStatic    10000000           131 ns/op           0 B/op          0 allocs/op +BenchmarkGocraftWeb_GPlusStatic  1000000          1035 ns/op         288 B/op          6 allocs/op +BenchmarkGoji_GPlusStatic    5000000           304 ns/op           0 B/op          0 allocs/op +BenchmarkGoJsonRest_GPlusStatic  1000000          1286 ns/op         337 B/op         12 allocs/op +BenchmarkGoRestful_GPlusStatic    200000          9649 ns/op        2160 B/op         30 allocs/op +BenchmarkGorillaMux_GPlusStatic  1000000          2346 ns/op         464 B/op          8 allocs/op +BenchmarkHttpRouter_GPlusStatic 30000000            42.7 ns/op         0 B/op          0 allocs/op +BenchmarkHttpTreeMux_GPlusStatic    30000000            49.5 ns/op         0 B/op          0 allocs/op +BenchmarkKocha_GPlusStatic  20000000            74.8 ns/op         0 B/op          0 allocs/op +BenchmarkMacaron_GPlusStatic     1000000          2520 ns/op         736 B/op          8 allocs/op +BenchmarkMartini_GPlusStatic      300000          5310 ns/op         832 B/op         11 allocs/op +BenchmarkPat_GPlusStatic     5000000           398 ns/op          96 B/op          2 allocs/op +BenchmarkPossum_GPlusStatic  1000000          1434 ns/op         480 B/op          4 allocs/op +BenchmarkR2router_GPlusStatic    2000000           646 ns/op         144 B/op          5 allocs/op +BenchmarkRevel_GPlusStatic    300000          6172 ns/op        1272 B/op         25 allocs/op +BenchmarkRivet_GPlusStatic   3000000           444 ns/op         112 B/op          2 allocs/op +BenchmarkTango_GPlusStatic   1000000          1400 ns/op         208 B/op         10 allocs/op +BenchmarkTigerTonic_GPlusStatic 10000000           213 ns/op          32 B/op          1 allocs/op +BenchmarkTraffic_GPlusStatic     1000000          3091 ns/op        1208 B/op         16 allocs/op +BenchmarkVulcan_GPlusStatic  2000000           863 ns/op          98 B/op          3 allocs/op +BenchmarkZeus_GPlusStatic   10000000           237 ns/op          16 B/op          1 allocs/op +BenchmarkAce_GPlusParam  3000000           435 ns/op          64 B/op          1 allocs/op +BenchmarkBear_GPlusParam     1000000          1205 ns/op         448 B/op          5 allocs/op +BenchmarkBeego_GPlusParam    1000000          2494 ns/op         720 B/op         10 allocs/op +BenchmarkBone_GPlusParam     1000000          1126 ns/op         384 B/op          3 allocs/op +BenchmarkDenco_GPlusParam    5000000           325 ns/op          64 B/op          1 allocs/op +BenchmarkEcho_GPlusParam    10000000           168 ns/op           0 B/op          0 allocs/op +BenchmarkGin_GPlusParam 10000000           170 ns/op           0 B/op          0 allocs/op +BenchmarkGocraftWeb_GPlusParam   1000000          1895 ns/op         656 B/op          9 allocs/op +BenchmarkGoji_GPlusParam     1000000          1071 ns/op         336 B/op          2 allocs/op +BenchmarkGoJsonRest_GPlusParam   1000000          2282 ns/op         657 B/op         14 allocs/op +BenchmarkGoRestful_GPlusParam     100000         19400 ns/op        2560 B/op         33 allocs/op +BenchmarkGorillaMux_GPlusParam    500000          5001 ns/op         784 B/op          9 allocs/op +BenchmarkHttpRouter_GPlusParam  10000000           240 ns/op          64 B/op          1 allocs/op +BenchmarkHttpTreeMux_GPlusParam  2000000           797 ns/op         336 B/op          2 allocs/op +BenchmarkKocha_GPlusParam    3000000           505 ns/op          56 B/op          3 allocs/op +BenchmarkMacaron_GPlusParam  1000000          3668 ns/op        1104 B/op         11 allocs/op +BenchmarkMartini_GPlusParam   200000         10672 ns/op        1152 B/op         12 allocs/op +BenchmarkPat_GPlusParam  1000000          2376 ns/op         704 B/op         14 allocs/op +BenchmarkPossum_GPlusParam   1000000          2090 ns/op         624 B/op          7 allocs/op +BenchmarkR2router_GPlusParam     1000000          1233 ns/op         432 B/op          6 allocs/op +BenchmarkRevel_GPlusParam     200000          6778 ns/op        1704 B/op         28 allocs/op +BenchmarkRivet_GPlusParam    1000000          1279 ns/op         464 B/op          5 allocs/op +BenchmarkTango_GPlusParam    1000000          1981 ns/op         272 B/op         10 allocs/op +BenchmarkTigerTonic_GPlusParam    500000          3893 ns/op        1064 B/op         19 allocs/op +BenchmarkTraffic_GPlusParam   200000          6585 ns/op        2000 B/op         23 allocs/op +BenchmarkVulcan_GPlusParam   1000000          1233 ns/op          98 B/op          3 allocs/op +BenchmarkZeus_GPlusParam     1000000          1350 ns/op         368 B/op          3 allocs/op +BenchmarkAce_GPlus2Params    3000000           512 ns/op          64 B/op          1 allocs/op +BenchmarkBear_GPlus2Params   1000000          1564 ns/op         464 B/op          5 allocs/op +BenchmarkBeego_GPlus2Params  1000000          3043 ns/op         784 B/op         11 allocs/op +BenchmarkBone_GPlus2Params   1000000          3152 ns/op         736 B/op          7 allocs/op +BenchmarkDenco_GPlus2Params  3000000           431 ns/op          64 B/op          1 allocs/op +BenchmarkEcho_GPlus2Params   5000000           247 ns/op           0 B/op          0 allocs/op +BenchmarkGin_GPlus2Params   10000000           219 ns/op           0 B/op          0 allocs/op +BenchmarkGocraftWeb_GPlus2Params     1000000          2363 ns/op         720 B/op         10 allocs/op +BenchmarkGoji_GPlus2Params   1000000          1540 ns/op         336 B/op          2 allocs/op +BenchmarkGoJsonRest_GPlus2Params     1000000          2872 ns/op         721 B/op         15 allocs/op +BenchmarkGoRestful_GPlus2Params   100000         23030 ns/op        2720 B/op         35 allocs/op +BenchmarkGorillaMux_GPlus2Params      200000         10516 ns/op         816 B/op          9 allocs/op +BenchmarkHttpRouter_GPlus2Params     5000000           273 ns/op          64 B/op          1 allocs/op +BenchmarkHttpTreeMux_GPlus2Params    2000000           939 ns/op         336 B/op          2 allocs/op +BenchmarkKocha_GPlus2Params  2000000           844 ns/op         128 B/op          5 allocs/op +BenchmarkMacaron_GPlus2Params     500000          3914 ns/op        1168 B/op         12 allocs/op +BenchmarkMartini_GPlus2Params      50000         35759 ns/op        1280 B/op         16 allocs/op +BenchmarkPat_GPlus2Params     200000          7089 ns/op        2304 B/op         41 allocs/op +BenchmarkPossum_GPlus2Params     1000000          2093 ns/op         624 B/op          7 allocs/op +BenchmarkR2router_GPlus2Params   1000000          1320 ns/op         432 B/op          6 allocs/op +BenchmarkRevel_GPlus2Params   200000          7351 ns/op        1800 B/op         30 allocs/op +BenchmarkRivet_GPlus2Params  1000000          1485 ns/op         480 B/op          6 allocs/op +BenchmarkTango_GPlus2Params  1000000          2111 ns/op         448 B/op         12 allocs/op +BenchmarkTigerTonic_GPlus2Params      300000          6271 ns/op        1528 B/op         28 allocs/op +BenchmarkTraffic_GPlus2Params     100000         14886 ns/op        3312 B/op         34 allocs/op +BenchmarkVulcan_GPlus2Params     1000000          1883 ns/op          98 B/op          3 allocs/op +BenchmarkZeus_GPlus2Params   1000000          2686 ns/op         784 B/op          6 allocs/op +BenchmarkAce_GPlusAll     300000          5912 ns/op         640 B/op         11 allocs/op +BenchmarkBear_GPlusAll    100000         16448 ns/op        5072 B/op         61 allocs/op +BenchmarkBeego_GPlusAll    50000         32916 ns/op        8976 B/op        129 allocs/op +BenchmarkBone_GPlusAll     50000         25836 ns/op        6992 B/op         76 allocs/op +BenchmarkDenco_GPlusAll   500000          4462 ns/op         672 B/op         11 allocs/op +BenchmarkEcho_GPlusAll    500000          2806 ns/op           0 B/op          0 allocs/op +BenchmarkGin_GPlusAll     500000          2579 ns/op           0 B/op          0 allocs/op +BenchmarkGocraftWeb_GPlusAll       50000         25223 ns/op        8144 B/op        116 allocs/op +BenchmarkGoji_GPlusAll    100000         14237 ns/op        3696 B/op         22 allocs/op +BenchmarkGoJsonRest_GPlusAll       50000         29227 ns/op        8221 B/op        183 allocs/op +BenchmarkGoRestful_GPlusAll    10000        203144 ns/op       36064 B/op        441 allocs/op +BenchmarkGorillaMux_GPlusAll       20000         80906 ns/op        9712 B/op        115 allocs/op +BenchmarkHttpRouter_GPlusAll      500000          3040 ns/op         640 B/op         11 allocs/op +BenchmarkHttpTreeMux_GPlusAll     200000          9627 ns/op        3696 B/op         22 allocs/op +BenchmarkKocha_GPlusAll   200000          8108 ns/op         976 B/op         43 allocs/op +BenchmarkMacaron_GPlusAll      30000         48083 ns/op       13968 B/op        142 allocs/op +BenchmarkMartini_GPlusAll      10000        196978 ns/op       15072 B/op        178 allocs/op +BenchmarkPat_GPlusAll      30000         58865 ns/op       16880 B/op        343 allocs/op +BenchmarkPossum_GPlusAll      100000         19685 ns/op        6240 B/op         52 allocs/op +BenchmarkR2router_GPlusAll    100000         16251 ns/op        5040 B/op         76 allocs/op +BenchmarkRevel_GPlusAll    20000         93489 ns/op       21656 B/op        368 allocs/op +BenchmarkRivet_GPlusAll   100000         16907 ns/op        5408 B/op         64 allocs/op +```
\ No newline at end of file diff --git a/vendor/github.com/gin-gonic/gin/CHANGELOG.md b/vendor/github.com/gin-gonic/gin/CHANGELOG.md new file mode 100644 index 0000000..938084c --- /dev/null +++ b/vendor/github.com/gin-gonic/gin/CHANGELOG.md @@ -0,0 +1,141 @@ +#CHANGELOG + +###Gin 1.0rc2 (...) + +- [PERFORMANCE] Fast path for writting Content-Type. +- [PERFORMANCE] Much faster 404 routing +- [PERFORMANCE] Allocation optimizations +- [PERFORMANCE] Faster root tree lookup +- [PERFORMANCE] Zero overhead, String() and JSON() rendering. +- [PERFORMANCE] Faster ClientIP parsing +- [PERFORMANCE] Much faster SSE implementation +- [NEW] Benchmarks suite +- [NEW] Bind validation can be disabled and replaced with custom validators. +- [NEW] More flexible HTML render +- [FIX] Binding multipart form +- [FIX] Integration tests +- [FIX] Crash when binding non struct object in Context. +- [FIX] RunTLS() implementation +- [FIX] Logger() unit tests +- [FIX] Better approach to avoid directory listing in StaticFS() +- [FIX] Context.ClientIP() always returns the IP with trimmed spaces. +- [FIX] Better warning when running in debug mode. +- [FIX] Google App Engine integration. debugPrint does not use os.Stdout +- [FIX] Fixes integer overflow in error type +- [FIX] Error implements the json.Marshaller interface +- [FIX] MIT license in every file + + +###Gin 1.0rc1 (May 22, 2015) + +- [PERFORMANCE] Zero allocation router +- [PERFORMANCE] Faster JSON, XML and text rendering +- [PERFORMANCE] Custom hand optimized HttpRouter for Gin +- [PERFORMANCE] Misc code optimizations. Inlining, tail call optimizations +- [NEW] Built-in support for golang.org/x/net/context +- [NEW] Any(path, handler). Create a route that matches any path +- [NEW] Refactored rendering pipeline (faster and static typeded) +- [NEW] Refactored errors API +- [NEW] IndentedJSON() prints pretty JSON +- [NEW] Added gin.DefaultWriter +- [NEW] UNIX socket support +- [NEW] RouterGroup.BasePath is exposed +- [NEW] JSON validation using go-validate-yourself (very powerful options) +- [NEW] Completed suite of unit tests +- [NEW] HTTP streaming with c.Stream() +- [NEW] StaticFile() creates a router for serving just one file. +- [NEW] StaticFS() has an option to disable directory listing. +- [NEW] StaticFS() for serving static files through virtual filesystems +- [NEW] Server-Sent Events native support +- [NEW] WrapF() and WrapH() helpers for wrapping http.HandlerFunc and http.Handler +- [NEW] Added LoggerWithWriter() middleware +- [NEW] Added RecoveryWithWriter() middleware +- [NEW] Added DefaultPostFormValue() +- [NEW] Added DefaultFormValue() +- [NEW] Added DefaultParamValue() +- [FIX] BasicAuth() when using custom realm +- [FIX] Bug when serving static files in nested routing group +- [FIX] Redirect using built-in http.Redirect() +- [FIX] Logger when printing the requested path +- [FIX] Documentation typos +- [FIX] Context.Engine renamed to Context.engine +- [FIX] Better debugging messages +- [FIX] ErrorLogger +- [FIX] Debug HTTP render +- [FIX] Refactored binding and render modules  +- [FIX] Refactored Context initialization +- [FIX] Refactored BasicAuth() +- [FIX] NoMethod/NoRoute handlers +- [FIX] Hijacking http +- [FIX] Better support for Google App Engine (using log instead of fmt) + + +###Gin 0.6 (Mar 9, 2015) + +- [NEW] Support multipart/form-data +- [NEW] NoMethod handler +- [NEW] Validate sub structures +- [NEW] Support for HTTP Realm Auth +- [FIX] Unsigned integers in binding +- [FIX] Improve color logger + + +###Gin 0.5 (Feb 7, 2015) + +- [NEW] Content Negotiation +- [FIX] Solved security bug that allow a client to spoof ip +- [FIX] Fix unexported/ignored fields in binding + + +###Gin 0.4 (Aug 21, 2014) + +- [NEW] Development mode +- [NEW] Unit tests +- [NEW] Add Content.Redirect() +- [FIX] Deferring WriteHeader() +- [FIX] Improved documentation for model binding + + +###Gin 0.3 (Jul 18, 2014) + +- [PERFORMANCE] Normal log and error log are printed in the same call. +- [PERFORMANCE] Improve performance of NoRouter() +- [PERFORMANCE] Improve context's memory locality, reduce CPU cache faults. +- [NEW] Flexible rendering API +- [NEW] Add Context.File() +- [NEW] Add shorcut RunTLS() for http.ListenAndServeTLS +- [FIX] Rename NotFound404() to NoRoute() +- [FIX] Errors in context are purged +- [FIX] Adds HEAD method in Static file serving +- [FIX] Refactors Static() file serving +- [FIX] Using keyed initialization to fix app-engine integration +- [FIX] Can't unmarshal JSON array, #63 +- [FIX] Renaming Context.Req to Context.Request +- [FIX] Check application/x-www-form-urlencoded when parsing form + + +###Gin 0.2b (Jul 08, 2014) +- [PERFORMANCE] Using sync.Pool to allocatio/gc overhead +- [NEW] Travis CI integration +- [NEW] Completely new logger +- [NEW] New API for serving static files. gin.Static() +- [NEW] gin.H() can be serialized into XML +- [NEW] Typed errors. Errors can be typed. Internet/external/custom. +- [NEW] Support for Godeps +- [NEW] Travis/Godocs badges in README +- [NEW] New Bind() and BindWith() methods for parsing request body. +- [NEW] Add Content.Copy() +- [NEW] Add context.LastError() +- [NEW] Add shorcut for OPTIONS HTTP method +- [FIX] Tons of README fixes +- [FIX] Header is written before body +- [FIX] BasicAuth() and changes API a little bit +- [FIX] Recovery() middleware only prints panics +- [FIX] Context.Get() does not panic anymore. Use MustGet() instead. +- [FIX] Multiple http.WriteHeader() in NotFound handlers +- [FIX] Engine.Run() panics if http server can't be setted up +- [FIX] Crash when route path doesn't start with '/' +- [FIX] Do not update header when status code is negative +- [FIX] Setting response headers before calling WriteHeader in context.String() +- [FIX] Add MIT license +- [FIX] Changes behaviour of ErrorLogger() and Logger() diff --git a/vendor/github.com/gin-gonic/gin/LICENSE b/vendor/github.com/gin-gonic/gin/LICENSE new file mode 100644 index 0000000..1ff7f37 --- /dev/null +++ b/vendor/github.com/gin-gonic/gin/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2014 Manuel Martínez-Almeida + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/vendor/github.com/gin-gonic/gin/README.md b/vendor/github.com/gin-gonic/gin/README.md new file mode 100644 index 0000000..67c9fa8 --- /dev/null +++ b/vendor/github.com/gin-gonic/gin/README.md @@ -0,0 +1,579 @@ +#Gin Web Framework [](https://travis-ci.org/gin-gonic/gin) [](https://coveralls.io/r/gin-gonic/gin?branch=master)   + + [](https://godoc.org/github.com/gin-gonic/gin)  [](https://gitter.im/gin-gonic/gin?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) + +Gin is a web framework written in Golang. It features a martini-like API with much better performance, up to 40 times faster thanks to [httprouter](https://github.com/julienschmidt/httprouter). If you need performance and good productivity, you will love Gin.  + + + +``` +$ cat test.go +``` +```go  +package main + +import "github.com/gin-gonic/gin" + +func main() { +	r := gin.Default() +	r.GET("/ping", func(c *gin.Context) { +		c.String(200, "pong") +	}) +	r.Run(":8080") // listen and serve on 0.0.0.0:8080 +} +``` + +## Benchmarks + +Gin uses a custom version of [HttpRouter](https://github.com/julienschmidt/httprouter)   + +[See all benchmarks](/BENCHMARKS.md) + + +``` +BenchmarkAce_GithubAll     10000        109482 ns/op       13792 B/op        167 allocs/op +BenchmarkBear_GithubAll    10000        287490 ns/op       79952 B/op        943 allocs/op +BenchmarkBeego_GithubAll        3000        562184 ns/op      146272 B/op       2092 allocs/op +BenchmarkBone_GithubAll      500       2578716 ns/op      648016 B/op       8119 allocs/op +BenchmarkDenco_GithubAll       20000         94955 ns/op       20224 B/op        167 allocs/op +BenchmarkEcho_GithubAll    30000         58705 ns/op           0 B/op          0 allocs/op +BenchmarkGin_GithubAll     30000         50991 ns/op           0 B/op          0 allocs/op +BenchmarkGocraftWeb_GithubAll       5000        449648 ns/op      133280 B/op       1889 allocs/op +BenchmarkGoji_GithubAll     2000        689748 ns/op       56113 B/op        334 allocs/op +BenchmarkGoJsonRest_GithubAll       5000        537769 ns/op      135995 B/op       2940 allocs/op +BenchmarkGoRestful_GithubAll         100      18410628 ns/op      797236 B/op       7725 allocs/op +BenchmarkGorillaMux_GithubAll        200       8036360 ns/op      153137 B/op       1791 allocs/op +BenchmarkHttpRouter_GithubAll      20000         63506 ns/op       13792 B/op        167 allocs/op +BenchmarkHttpTreeMux_GithubAll     10000        165927 ns/op       56112 B/op        334 allocs/op +BenchmarkKocha_GithubAll       10000        171362 ns/op       23304 B/op        843 allocs/op +BenchmarkMacaron_GithubAll      2000        817008 ns/op      224960 B/op       2315 allocs/op +BenchmarkMartini_GithubAll       100      12609209 ns/op      237952 B/op       2686 allocs/op +BenchmarkPat_GithubAll       300       4830398 ns/op     1504101 B/op      32222 allocs/op +BenchmarkPossum_GithubAll      10000        301716 ns/op       97440 B/op        812 allocs/op +BenchmarkR2router_GithubAll    10000        270691 ns/op       77328 B/op       1182 allocs/op +BenchmarkRevel_GithubAll        1000       1491919 ns/op      345553 B/op       5918 allocs/op +BenchmarkRivet_GithubAll       10000        283860 ns/op       84272 B/op       1079 allocs/op +BenchmarkTango_GithubAll        5000        473821 ns/op       87078 B/op       2470 allocs/op +BenchmarkTigerTonic_GithubAll       2000       1120131 ns/op      241088 B/op       6052 allocs/op +BenchmarkTraffic_GithubAll       200       8708979 ns/op     2664762 B/op      22390 allocs/op +BenchmarkVulcan_GithubAll       5000        353392 ns/op       19894 B/op        609 allocs/op +BenchmarkZeus_GithubAll     2000        944234 ns/op      300688 B/op       2648 allocs/op +``` + + +##Gin v1. stable + +- [x] Zero allocation router. +- [x] Still the fastest http router and framework. From routing to writing. +- [x] Complete suite of unit tests +- [x] Battle tested +- [x] API frozen, new releases will not break your code. + + +## Start using it +1. Download and install it: + +```sh +go get github.com/gin-gonic/gin +``` +2. Import it in your code: + +```go +import "github.com/gin-gonic/gin" +``` + +##API Examples + +#### Using GET, POST, PUT, PATCH, DELETE and OPTIONS + +```go +func main() { +	// Creates a gin router with default middlewares: +	// logger and recovery (crash-free) middlewares +	router := gin.Default() + +	router.GET("/someGet", getting) +	router.POST("/somePost", posting) +	router.PUT("/somePut", putting) +	router.DELETE("/someDelete", deleting) +	router.PATCH("/somePatch", patching) +	router.HEAD("/someHead", head) +	router.OPTIONS("/someOptions", options) + +	// Listen and server on 0.0.0.0:8080 +	router.Run(":8080") +} +``` + +#### Parameters in path + +```go +func main() { +	router := gin.Default() +	 +	// This handler will match /user/john but will not match neither /user/ or /user +	router.GET("/user/:name", func(c *gin.Context) { +		name := c.Param("name") +		c.String(http.StatusOK, "Hello %s", name) +	}) + +	// However, this one will match /user/john/ and also /user/john/send +	// If no other routers match /user/john, it will redirect to /user/join/ +	router.GET("/user/:name/*action", func(c *gin.Context) { +		name := c.Param("name") +		action := c.Param("action") +		message := name + " is " + action +		c.String(http.StatusOK, message) +	}) +	 +	router.Run(":8080") +} +``` + +#### Querystring parameters +```go +func main() { +    router := gin.Default() + +    // Query string parameters are parsed using the existing underlying request object.   +    // The request responds to a url matching:  /welcome?firstname=Jane&lastname=Doe +    router.GET("/welcome", func(c *gin.Context) { +        firstname := c.DefaultQuery("firstname", "Guest") +        lastname := c.Query("lastname") // shortcut for c.Request.URL.Query().Get("lastname") + +        c.String(http.StatusOK, "Hello %s %s", firstname, lastname) +    }) +    router.Run(":8080") +} +``` + +### Multipart/Urlencoded Form  + +```go +func main() { +    router := gin.Default() + +    router.POST("/form_post", func(c *gin.Context) { +        message := c.PostForm("message") +        nick := c.DefaultPostForm("nick", "anonymous") +                 +        c.JSON(200, gin.H{ +            "status": "posted", +            "message": message, +        }) +    }) +    router.Run(":8080") +} +``` + +#### Grouping routes +```go +func main() { +	router := gin.Default() + +	// Simple group: v1 +	v1 := router.Group("/v1") +	{ +		v1.POST("/login", loginEndpoint) +		v1.POST("/submit", submitEndpoint) +		v1.POST("/read", readEndpoint) +	} + +	// Simple group: v2 +	v2 := router.Group("/v2") +	{ +		v2.POST("/login", loginEndpoint) +		v2.POST("/submit", submitEndpoint) +		v2.POST("/read", readEndpoint) +	} + +	router.Run(":8080") +} +``` + + +#### Blank Gin without middlewares by default + +Use + +```go +r := gin.New() +``` +instead of + +```go +r := gin.Default() +``` + + +#### Using middlewares +```go +func main() { +	// Creates a router without any middleware by default +	r := gin.New() + +	// Global middlewares +	r.Use(gin.Logger()) +	r.Use(gin.Recovery()) + +	// Per route middlewares, you can add as many as you desire. +	r.GET("/benchmark", MyBenchLogger(), benchEndpoint) + +	// Authorization group +	// authorized := r.Group("/", AuthRequired()) +	// exactly the same than: +	authorized := r.Group("/") +	// per group middlewares! in this case we use the custom created +	// AuthRequired() middleware just in the "authorized" group. +	authorized.Use(AuthRequired()) +	{ +		authorized.POST("/login", loginEndpoint) +		authorized.POST("/submit", submitEndpoint) +		authorized.POST("/read", readEndpoint) + +		// nested group +		testing := authorized.Group("testing") +		testing.GET("/analytics", analyticsEndpoint) +	} + +	// Listen and server on 0.0.0.0:8080 +	r.Run(":8080") +} +``` + +#### Model binding and validation + +To bind a request body into a type, use model binding. We currently support binding of JSON, XML and standard form values (foo=bar&boo=baz). + +Note that you need to set the corresponding binding tag on all fields you want to bind. For example, when binding from JSON, set `json:"fieldname"`. + +When using the Bind-method, Gin tries to infer the binder depending on the Content-Type header. If you are sure what you are binding, you can use BindWith.  + +You can also specify that specific fields are required. If a field is decorated with `binding:"required"` and has a empty value when binding, the current request will fail with an error. + +```go +// Binding from JSON +type LoginJSON struct { +	User     string `json:"user" binding:"required"` +	Password string `json:"password" binding:"required"` +} + +// Binding from form values +type LoginForm struct { +    User     string `form:"user" binding:"required"` +    Password string `form:"password" binding:"required"`    +} + +func main() { +	r := gin.Default() + +    // Example for binding JSON ({"user": "manu", "password": "123"}) +	r.POST("/loginJSON", func(c *gin.Context) { +		var json LoginJSON + +        c.Bind(&json) // This will infer what binder to use depending on the content-type header. +        if json.User == "manu" && json.Password == "123" { +            c.JSON(http.StatusOK, gin.H{"status": "you are logged in"}) +        } else { +            c.JSON(http.StatusUnauthorized, gin.H{"status": "unauthorized"}) +        } +	}) + +    // Example for binding a HTML form (user=manu&password=123) +    r.POST("/loginHTML", func(c *gin.Context) { +        var form LoginForm + +        c.BindWith(&form, binding.Form) // You can also specify which binder to use. We support binding.Form, binding.JSON and binding.XML. +        if form.User == "manu" && form.Password == "123" { +            c.JSON(http.StatusOK, gin.H{"status": "you are logged in"}) +        } else { +            c.JSON(http.StatusUnauthorized, gin.H{"status": "unauthorized"}) +        } +    }) + +	// Listen and server on 0.0.0.0:8080 +	r.Run(":8080") +} +``` + + +###Multipart/Urlencoded binding  +```go +package main + +import ( +	"github.com/gin-gonic/gin" +	"github.com/gin-gonic/gin/binding" +) + +type LoginForm struct { +	User     string `form:"user" binding:"required"` +	Password string `form:"password" binding:"required"` +} + +func main() { + +	router := gin.Default() + +	router.POST("/login", func(c *gin.Context) { +		// you can bind multipart form with explicit binding declaration: +		// c.BindWith(&form, binding.Form) +		// or you can simply use autobinding with Bind method: +		var form LoginForm +		c.Bind(&form) // in this case proper binding will be automatically selected + +		if form.User == "user" && form.Password == "password" { +			c.JSON(200, gin.H{"status": "you are logged in"}) +		} else { +			c.JSON(401, gin.H{"status": "unauthorized"}) +		} +	}) + +	router.Run(":8080") + +} +``` + +Test it with: +```bash +$ curl -v --form user=user --form password=password http://localhost:8080/login +``` + + +#### XML and JSON rendering + +```go +func main() { +	r := gin.Default() + +	// gin.H is a shortcut for map[string]interface{} +	r.GET("/someJSON", func(c *gin.Context) { +		c.JSON(http.StatusOK, gin.H{"message": "hey", "status": http.StatusOK}) +	}) + +	r.GET("/moreJSON", func(c *gin.Context) { +		// You also can use a struct +		var msg struct { +			Name    string `json:"user"` +			Message string +			Number  int +		} +		msg.Name = "Lena" +		msg.Message = "hey" +		msg.Number = 123 +		// Note that msg.Name becomes "user" in the JSON +		// Will output  :   {"user": "Lena", "Message": "hey", "Number": 123} +		c.JSON(http.StatusOK, msg) +	}) + +	r.GET("/someXML", func(c *gin.Context) { +		c.XML(http.StatusOK, gin.H{"message": "hey", "status": http.StatusOK}) +	}) + +	// Listen and server on 0.0.0.0:8080 +	r.Run(":8080") +} +``` + +####Serving static files + +```go +func main() { +    router := gin.Default() +    router.Static("/assets", "./assets") +    router.StaticFS("/more_static", http.Dir("my_file_system")) +    router.StaticFile("/favicon.ico", "./resources/favicon.ico") + +    // Listen and server on 0.0.0.0:8080 +    router.Run(":8080") +} +``` + +####HTML rendering + +Using LoadHTMLTemplates() + +```go +func main() { +	router := gin.Default() +	router.LoadHTMLGlob("templates/*") +	//router.LoadHTMLFiles("templates/template1.html", "templates/template2.html") +	router.GET("/index", func(c *gin.Context) { +		c.HTML(http.StatusOK, "index.tmpl", gin.H{ +			"title": "Main website", +		}) +	}) +	router.Run(":8080") +} +``` +```html +<html><h1> +	{{ .title }} +</h1> +</html> +``` + +You can also use your own html template render + +```go +import "html/template" + +func main() { +	router := gin.Default() +	html := template.Must(template.ParseFiles("file1", "file2")) +	router.SetHTMLTemplate(html) +	router.Run(":8080") +} +``` + + +#### Redirects + +Issuing a HTTP redirect is easy: + +```go +r.GET("/test", func(c *gin.Context) { +	c.Redirect(http.StatusMovedPermanently, "http://www.google.com/") +}) +``` +Both internal and external locations are supported. + + +#### Custom Middlewares + +```go +func Logger() gin.HandlerFunc { +	return func(c *gin.Context) { +		t := time.Now() + +		// Set example variable +		c.Set("example", "12345") + +		// before request + +		c.Next() + +		// after request +		latency := time.Since(t) +		log.Print(latency) + +		// access the status we are sending +		status := c.Writer.Status() +		log.Println(status) +	} +} + +func main() { +	r := gin.New() +	r.Use(Logger()) + +	r.GET("/test", func(c *gin.Context) { +		example := c.MustGet("example").(string) + +		// it would print: "12345" +		log.Println(example) +	}) + +	// Listen and server on 0.0.0.0:8080 +	r.Run(":8080") +} +``` + +#### Using BasicAuth() middleware +```go +// simulate some private data +var secrets = gin.H{ +	"foo":    gin.H{"email": "foo@bar.com", "phone": "123433"}, +	"austin": gin.H{"email": "austin@example.com", "phone": "666"}, +	"lena":   gin.H{"email": "lena@guapa.com", "phone": "523443"}, +} + +func main() { +	r := gin.Default() + +	// Group using gin.BasicAuth() middleware +	// gin.Accounts is a shortcut for map[string]string +	authorized := r.Group("/admin", gin.BasicAuth(gin.Accounts{ +		"foo":    "bar", +		"austin": "1234", +		"lena":   "hello2", +		"manu":   "4321", +	})) + +	// /admin/secrets endpoint +	// hit "localhost:8080/admin/secrets +	authorized.GET("/secrets", func(c *gin.Context) { +		// get user, it was setted by the BasicAuth middleware +		user := c.MustGet(gin.AuthUserKey).(string) +		if secret, ok := secrets[user]; ok { +			c.JSON(http.StatusOK, gin.H{"user": user, "secret": secret}) +		} else { +			c.JSON(http.StatusOK, gin.H{"user": user, "secret": "NO SECRET :("}) +		} +	}) + +	// Listen and server on 0.0.0.0:8080 +	r.Run(":8080") +} +``` + + +#### Goroutines inside a middleware +When starting inside a middleware or handler, you **SHOULD NOT** use the original context inside it, you have to use a read-only copy. + +```go +func main() { +	r := gin.Default() + +	r.GET("/long_async", func(c *gin.Context) { +		// create copy to be used inside the goroutine +		c_cp := c.Copy() +		go func() { +			// simulate a long task with time.Sleep(). 5 seconds +			time.Sleep(5 * time.Second) + +			// note than you are using the copied context "c_cp", IMPORTANT +			log.Println("Done! in path " + c_cp.Request.URL.Path) +		}() +	}) + + +	r.GET("/long_sync", func(c *gin.Context) { +		// simulate a long task with time.Sleep(). 5 seconds +		time.Sleep(5 * time.Second) + +		// since we are NOT using a goroutine, we do not have to copy the context +		log.Println("Done! in path " + c.Request.URL.Path) +	}) + +    // Listen and server on 0.0.0.0:8080 +    r.Run(":8080") +} +``` + +#### Custom HTTP configuration + +Use `http.ListenAndServe()` directly, like this: + +```go +func main() { +	router := gin.Default() +	http.ListenAndServe(":8080", router) +} +``` +or + +```go +func main() { +	router := gin.Default() + +	s := &http.Server{ +		Addr:           ":8080", +		Handler:        router, +		ReadTimeout:    10 * time.Second, +		WriteTimeout:   10 * time.Second, +		MaxHeaderBytes: 1 << 20, +	} +	s.ListenAndServe() +} +``` diff --git a/vendor/github.com/gin-gonic/gin/auth.go b/vendor/github.com/gin-gonic/gin/auth.go new file mode 100644 index 0000000..33f8e9a --- /dev/null +++ b/vendor/github.com/gin-gonic/gin/auth.go @@ -0,0 +1,98 @@ +// Copyright 2014 Manu Martinez-Almeida.  All rights reserved. +// Use of this source code is governed by a MIT style +// license that can be found in the LICENSE file. + +package gin + +import ( +	"crypto/subtle" +	"encoding/base64" +	"strconv" +) + +const ( +	AuthUserKey = "user" +) + +type ( +	Accounts map[string]string +	authPair struct { +		Value string +		User  string +	} +	authPairs []authPair +) + +func (a authPairs) searchCredential(authValue string) (string, bool) { +	if len(authValue) == 0 { +		return "", false +	} +	for _, pair := range a { +		if pair.Value == authValue { +			return pair.User, true +		} +	} +	return "", false +} + +// Implements a basic Basic HTTP Authorization. It takes as arguments a map[string]string where +// the key is the user name and the value is the password, as well as the name of the Realm +// (see http://tools.ietf.org/html/rfc2617#section-1.2) +func BasicAuthForRealm(accounts Accounts, realm string) HandlerFunc { +	if realm == "" { +		realm = "Authorization Required" +	} +	realm = "Basic realm=" + strconv.Quote(realm) +	pairs := processAccounts(accounts) +	return func(c *Context) { +		// Search user in the slice of allowed credentials +		user, found := pairs.searchCredential(c.Request.Header.Get("Authorization")) +		if !found { +			// Credentials doesn't match, we return 401 and abort handlers chain. +			c.Header("WWW-Authenticate", realm) +			c.AbortWithStatus(401) +		} else { +			// The user credentials was found, set user's id to key AuthUserKey in this context, the userId can be read later using +			// c.MustGet(gin.AuthUserKey) +			c.Set(AuthUserKey, user) +		} +	} +} + +// Implements a basic Basic HTTP Authorization. It takes as argument a map[string]string where +// the key is the user name and the value is the password. +func BasicAuth(accounts Accounts) HandlerFunc { +	return BasicAuthForRealm(accounts, "") +} + +func processAccounts(accounts Accounts) authPairs { +	if len(accounts) == 0 { +		panic("Empty list of authorized credentials") +	} +	pairs := make(authPairs, 0, len(accounts)) +	for user, password := range accounts { +		if len(user) == 0 { +			panic("User can not be empty") +		} +		value := authorizationHeader(user, password) +		pairs = append(pairs, authPair{ +			Value: value, +			User:  user, +		}) +	} +	return pairs +} + +func authorizationHeader(user, password string) string { +	base := user + ":" + password +	return "Basic " + base64.StdEncoding.EncodeToString([]byte(base)) +} + +func secureCompare(given, actual string) bool { +	if subtle.ConstantTimeEq(int32(len(given)), int32(len(actual))) == 1 { +		return subtle.ConstantTimeCompare([]byte(given), []byte(actual)) == 1 +	} else { +		/* Securely compare actual to itself to keep constant time, but always return false */ +		return subtle.ConstantTimeCompare([]byte(actual), []byte(actual)) == 1 && false +	} +} diff --git a/vendor/github.com/gin-gonic/gin/binding/binding.go b/vendor/github.com/gin-gonic/gin/binding/binding.go new file mode 100644 index 0000000..f719fbc --- /dev/null +++ b/vendor/github.com/gin-gonic/gin/binding/binding.go @@ -0,0 +1,61 @@ +// Copyright 2014 Manu Martinez-Almeida.  All rights reserved. +// Use of this source code is governed by a MIT style +// license that can be found in the LICENSE file. + +package binding + +import "net/http" + +const ( +	MIMEJSON              = "application/json" +	MIMEHTML              = "text/html" +	MIMEXML               = "application/xml" +	MIMEXML2              = "text/xml" +	MIMEPlain             = "text/plain" +	MIMEPOSTForm          = "application/x-www-form-urlencoded" +	MIMEMultipartPOSTForm = "multipart/form-data" +) + +type Binding interface { +	Name() string +	Bind(*http.Request, interface{}) error +} + +type StructValidator interface { +	// ValidateStruct can receive any kind of type and it should never panic, even if the configuration is not right. +	// If the received type is not a struct, any validation should be skipped and nil must be returned. +	// If the received type is a struct or pointer to a struct, the validation should be performed. +	// If the struct is not valid or the validation itself fails, a descriptive error should be returned. +	// Otherwise nil must be returned. +	ValidateStruct(interface{}) error +} + +var Validator StructValidator = &defaultValidator{} + +var ( +	JSON = jsonBinding{} +	XML  = xmlBinding{} +	Form = formBinding{} +) + +func Default(method, contentType string) Binding { +	if method == "GET" { +		return Form +	} else { +		switch contentType { +		case MIMEJSON: +			return JSON +		case MIMEXML, MIMEXML2: +			return XML +		default: //case MIMEPOSTForm, MIMEMultipartPOSTForm: +			return Form +		} +	} +} + +func validate(obj interface{}) error { +	if Validator == nil { +		return nil +	} +	return Validator.ValidateStruct(obj) +} diff --git a/vendor/github.com/gin-gonic/gin/binding/default_validator.go b/vendor/github.com/gin-gonic/gin/binding/default_validator.go new file mode 100644 index 0000000..7f12152 --- /dev/null +++ b/vendor/github.com/gin-gonic/gin/binding/default_validator.go @@ -0,0 +1,40 @@ +package binding + +import ( +	"reflect" +	"sync" + +	"gopkg.in/bluesuncorp/validator.v5" +) + +type defaultValidator struct { +	once     sync.Once +	validate *validator.Validate +} + +var _ StructValidator = &defaultValidator{} + +func (v *defaultValidator) ValidateStruct(obj interface{}) error { +	if kindOfData(obj) == reflect.Struct { +		v.lazyinit() +		if err := v.validate.Struct(obj); err != nil { +			return error(err) +		} +	} +	return nil +} + +func (v *defaultValidator) lazyinit() { +	v.once.Do(func() { +		v.validate = validator.New("binding", validator.BakedInValidators) +	}) +} + +func kindOfData(data interface{}) reflect.Kind { +	value := reflect.ValueOf(data) +	valueType := value.Kind() +	if valueType == reflect.Ptr { +		valueType = value.Elem().Kind() +	} +	return valueType +} diff --git a/vendor/github.com/gin-gonic/gin/binding/form.go b/vendor/github.com/gin-gonic/gin/binding/form.go new file mode 100644 index 0000000..ff00b0d --- /dev/null +++ b/vendor/github.com/gin-gonic/gin/binding/form.go @@ -0,0 +1,24 @@ +// Copyright 2014 Manu Martinez-Almeida.  All rights reserved. +// Use of this source code is governed by a MIT style +// license that can be found in the LICENSE file. + +package binding + +import "net/http" + +type formBinding struct{} + +func (_ formBinding) Name() string { +	return "form" +} + +func (_ formBinding) Bind(req *http.Request, obj interface{}) error { +	if err := req.ParseForm(); err != nil { +		return err +	} +	req.ParseMultipartForm(32 << 10) // 32 MB +	if err := mapForm(obj, req.Form); err != nil { +		return err +	} +	return validate(obj) +} diff --git a/vendor/github.com/gin-gonic/gin/binding/form_mapping.go b/vendor/github.com/gin-gonic/gin/binding/form_mapping.go new file mode 100644 index 0000000..d8b13b1 --- /dev/null +++ b/vendor/github.com/gin-gonic/gin/binding/form_mapping.go @@ -0,0 +1,151 @@ +// Copyright 2014 Manu Martinez-Almeida.  All rights reserved. +// Use of this source code is governed by a MIT style +// license that can be found in the LICENSE file. + +package binding + +import ( +	"errors" +	"reflect" +	"strconv" +) + +func mapForm(ptr interface{}, form map[string][]string) error { +	typ := reflect.TypeOf(ptr).Elem() +	val := reflect.ValueOf(ptr).Elem() +	for i := 0; i < typ.NumField(); i++ { +		typeField := typ.Field(i) +		structField := val.Field(i) +		if !structField.CanSet() { +			continue +		} + +		structFieldKind := structField.Kind() +		inputFieldName := typeField.Tag.Get("form") +		if inputFieldName == "" { +			inputFieldName = typeField.Name + +			// if "form" tag is nil, we inspect if the field is a struct. +			// this would not make sense for JSON parsing but it does for a form +			// since data is flatten +			if structFieldKind == reflect.Struct { +				err := mapForm(structField.Addr().Interface(), form) +				if err != nil { +					return err +				} +				continue +			} +		} +		inputValue, exists := form[inputFieldName] +		if !exists { +			continue +		} + +		numElems := len(inputValue) +		if structFieldKind == reflect.Slice && numElems > 0 { +			sliceOf := structField.Type().Elem().Kind() +			slice := reflect.MakeSlice(structField.Type(), numElems, numElems) +			for i := 0; i < numElems; i++ { +				if err := setWithProperType(sliceOf, inputValue[i], slice.Index(i)); err != nil { +					return err +				} +			} +			val.Field(i).Set(slice) +		} else { +			if err := setWithProperType(typeField.Type.Kind(), inputValue[0], structField); err != nil { +				return err +			} +		} + +	} +	return nil +} + +func setWithProperType(valueKind reflect.Kind, val string, structField reflect.Value) error { +	switch valueKind { +	case reflect.Int: +		return setIntField(val, 0, structField) +	case reflect.Int8: +		return setIntField(val, 8, structField) +	case reflect.Int16: +		return setIntField(val, 16, structField) +	case reflect.Int32: +		return setIntField(val, 32, structField) +	case reflect.Int64: +		return setIntField(val, 64, structField) +	case reflect.Uint: +		return setUintField(val, 0, structField) +	case reflect.Uint8: +		return setUintField(val, 8, structField) +	case reflect.Uint16: +		return setUintField(val, 16, structField) +	case reflect.Uint32: +		return setUintField(val, 32, structField) +	case reflect.Uint64: +		return setUintField(val, 64, structField) +	case reflect.Bool: +		return setBoolField(val, structField) +	case reflect.Float32: +		return setFloatField(val, 32, structField) +	case reflect.Float64: +		return setFloatField(val, 64, structField) +	case reflect.String: +		structField.SetString(val) +	default: +		return errors.New("Unknown type") +	} +	return nil +} + +func setIntField(val string, bitSize int, field reflect.Value) error { +	if val == "" { +		val = "0" +	} +	intVal, err := strconv.ParseInt(val, 10, bitSize) +	if err == nil { +		field.SetInt(intVal) +	} +	return err +} + +func setUintField(val string, bitSize int, field reflect.Value) error { +	if val == "" { +		val = "0" +	} +	uintVal, err := strconv.ParseUint(val, 10, bitSize) +	if err == nil { +		field.SetUint(uintVal) +	} +	return err +} + +func setBoolField(val string, field reflect.Value) error { +	if val == "" { +		val = "false" +	} +	boolVal, err := strconv.ParseBool(val) +	if err == nil { +		field.SetBool(boolVal) +	} +	return nil +} + +func setFloatField(val string, bitSize int, field reflect.Value) error { +	if val == "" { +		val = "0.0" +	} +	floatVal, err := strconv.ParseFloat(val, bitSize) +	if err == nil { +		field.SetFloat(floatVal) +	} +	return err +} + +// Don't pass in pointers to bind to. Can lead to bugs. See: +// https://github.com/codegangsta/martini-contrib/issues/40 +// https://github.com/codegangsta/martini-contrib/pull/34#issuecomment-29683659 +func ensureNotPointer(obj interface{}) { +	if reflect.TypeOf(obj).Kind() == reflect.Ptr { +		panic("Pointers are not accepted as binding models") +	} +} diff --git a/vendor/github.com/gin-gonic/gin/binding/json.go b/vendor/github.com/gin-gonic/gin/binding/json.go new file mode 100644 index 0000000..25c5a06 --- /dev/null +++ b/vendor/github.com/gin-gonic/gin/binding/json.go @@ -0,0 +1,25 @@ +// Copyright 2014 Manu Martinez-Almeida.  All rights reserved. +// Use of this source code is governed by a MIT style +// license that can be found in the LICENSE file. + +package binding + +import ( +	"encoding/json" + +	"net/http" +) + +type jsonBinding struct{} + +func (_ jsonBinding) Name() string { +	return "json" +} + +func (_ jsonBinding) Bind(req *http.Request, obj interface{}) error { +	decoder := json.NewDecoder(req.Body) +	if err := decoder.Decode(obj); err != nil { +		return err +	} +	return validate(obj) +} diff --git a/vendor/github.com/gin-gonic/gin/binding/xml.go b/vendor/github.com/gin-gonic/gin/binding/xml.go new file mode 100644 index 0000000..cac4be8 --- /dev/null +++ b/vendor/github.com/gin-gonic/gin/binding/xml.go @@ -0,0 +1,24 @@ +// Copyright 2014 Manu Martinez-Almeida.  All rights reserved. +// Use of this source code is governed by a MIT style +// license that can be found in the LICENSE file. + +package binding + +import ( +	"encoding/xml" +	"net/http" +) + +type xmlBinding struct{} + +func (_ xmlBinding) Name() string { +	return "xml" +} + +func (_ xmlBinding) Bind(req *http.Request, obj interface{}) error { +	decoder := xml.NewDecoder(req.Body) +	if err := decoder.Decode(obj); err != nil { +		return err +	} +	return validate(obj) +} diff --git a/vendor/github.com/gin-gonic/gin/context.go b/vendor/github.com/gin-gonic/gin/context.go new file mode 100644 index 0000000..12920fd --- /dev/null +++ b/vendor/github.com/gin-gonic/gin/context.go @@ -0,0 +1,477 @@ +// Copyright 2014 Manu Martinez-Almeida.  All rights reserved. +// Use of this source code is governed by a MIT style +// license that can be found in the LICENSE file. + +package gin + +import ( +	"errors" +	"io" +	"math" +	"net/http" +	"strings" +	"time" + +	"github.com/gin-gonic/gin/binding" +	"github.com/gin-gonic/gin/render" +	"github.com/manucorporat/sse" +	"golang.org/x/net/context" +) + +const ( +	MIMEJSON              = binding.MIMEJSON +	MIMEHTML              = binding.MIMEHTML +	MIMEXML               = binding.MIMEXML +	MIMEXML2              = binding.MIMEXML2 +	MIMEPlain             = binding.MIMEPlain +	MIMEPOSTForm          = binding.MIMEPOSTForm +	MIMEMultipartPOSTForm = binding.MIMEMultipartPOSTForm +) + +const AbortIndex int8 = math.MaxInt8 / 2 + +// Context is the most important part of gin. It allows us to pass variables between middleware, +// manage the flow, validate the JSON of a request and render a JSON response for example. +type Context struct { +	writermem responseWriter +	Request   *http.Request +	Writer    ResponseWriter + +	Params   Params +	handlers HandlersChain +	index    int8 + +	engine   *Engine +	Keys     map[string]interface{} +	Errors   errorMsgs +	Accepted []string +} + +var _ context.Context = &Context{} + +/************************************/ +/********** CONTEXT CREATION ********/ +/************************************/ + +func (c *Context) reset() { +	c.Writer = &c.writermem +	c.Params = c.Params[0:0] +	c.handlers = nil +	c.index = -1 +	c.Keys = nil +	c.Errors = c.Errors[0:0] +	c.Accepted = nil +} + +func (c *Context) Copy() *Context { +	var cp Context = *c +	cp.writermem.ResponseWriter = nil +	cp.Writer = &cp.writermem +	cp.index = AbortIndex +	cp.handlers = nil +	return &cp +} + +func (c *Context) HandlerName() string { +	return nameOfFunction(c.handlers.Last()) +} + +/************************************/ +/*********** FLOW CONTROL ***********/ +/************************************/ + +// Next should be used only in the middlewares. +// It executes the pending handlers in the chain inside the calling handler. +// See example in github. +func (c *Context) Next() { +	c.index++ +	s := int8(len(c.handlers)) +	for ; c.index < s; c.index++ { +		c.handlers[c.index](c) +	} +} + +// Returns if the currect context was aborted. +func (c *Context) IsAborted() bool { +	return c.index == AbortIndex +} + +// Stops the system to continue calling the pending handlers in the chain. +// Let's say you have an authorization middleware that validates if the request is authorized +// if the authorization fails (the password does not match). This method (Abort()) should be called +// in order to stop the execution of the actual handler. +func (c *Context) Abort() { +	c.index = AbortIndex +} + +// It calls Abort() and writes the headers with the specified status code. +// For example, a failed attempt to authentificate a request could use: context.AbortWithStatus(401). +func (c *Context) AbortWithStatus(code int) { +	c.Writer.WriteHeader(code) +	c.Abort() +} + +// It calls AbortWithStatus() and Error() internally. This method stops the chain, writes the status code and +// pushes the specified error to `c.Errors`. +// See Context.Error() for more details. +func (c *Context) AbortWithError(code int, err error) *Error { +	c.AbortWithStatus(code) +	return c.Error(err) +} + +/************************************/ +/********* ERROR MANAGEMENT *********/ +/************************************/ + +// Attaches an error to the current context. The error is pushed to a list of errors. +// It's a good idea to call Error for each error that occurred during the resolution of a request. +// A middleware can be used to collect all the errors and push them to a database together, print a log, or append it in the HTTP response. +func (c *Context) Error(err error) *Error { +	var parsedError *Error +	switch err.(type) { +	case *Error: +		parsedError = err.(*Error) +	default: +		parsedError = &Error{ +			Err:  err, +			Type: ErrorTypePrivate, +		} +	} +	c.Errors = append(c.Errors, parsedError) +	return parsedError +} + +/************************************/ +/******** METADATA MANAGEMENT********/ +/************************************/ + +// Sets a new pair key/value just for this context. +// It also lazy initializes the hashmap if it was not used previously. +func (c *Context) Set(key string, value interface{}) { +	if c.Keys == nil { +		c.Keys = make(map[string]interface{}) +	} +	c.Keys[key] = value +} + +// Returns the value for the given key, ie: (value, true). +// If the value does not exists it returns (nil, false) +func (c *Context) Get(key string) (value interface{}, exists bool) { +	if c.Keys != nil { +		value, exists = c.Keys[key] +	} +	return +} + +// Returns the value for the given key if it exists, otherwise it panics. +func (c *Context) MustGet(key string) interface{} { +	if value, exists := c.Get(key); exists { +		return value +	} +	panic("Key \"" + key + "\" does not exist") +} + +/************************************/ +/************ INPUT DATA ************/ +/************************************/ + +// Shortcut for c.Request.URL.Query().Get(key) +func (c *Context) Query(key string) (va string) { +	va, _ = c.query(key) +	return +} + +// Shortcut for c.Request.PostFormValue(key) +func (c *Context) PostForm(key string) (va string) { +	va, _ = c.postForm(key) +	return +} + +// Shortcut for c.Params.ByName(key) +func (c *Context) Param(key string) string { +	return c.Params.ByName(key) +} + +func (c *Context) DefaultPostForm(key, defaultValue string) string { +	if va, ok := c.postForm(key); ok { +		return va +	} +	return defaultValue +} + +func (c *Context) DefaultQuery(key, defaultValue string) string { +	if va, ok := c.query(key); ok { +		return va +	} +	return defaultValue +} + +func (c *Context) query(key string) (string, bool) { +	req := c.Request +	if values, ok := req.URL.Query()[key]; ok && len(values) > 0 { +		return values[0], true +	} +	return "", false +} + +func (c *Context) postForm(key string) (string, bool) { +	req := c.Request +	req.ParseMultipartForm(32 << 20) // 32 MB +	if values := req.PostForm[key]; len(values) > 0 { +		return values[0], true +	} +	if req.MultipartForm != nil && req.MultipartForm.File != nil { +		if values := req.MultipartForm.Value[key]; len(values) > 0 { +			return values[0], true +		} +	} +	return "", false +} + +// This function checks the Content-Type to select a binding engine automatically, +// Depending the "Content-Type" header different bindings are used: +// "application/json" --> JSON binding +// "application/xml"  --> XML binding +// else --> returns an error +// if Parses the request's body as JSON if Content-Type == "application/json"  using JSON or XML  as a JSON input. It decodes the json payload into the struct specified as a pointer.Like ParseBody() but this method also writes a 400 error if the json is not valid. +func (c *Context) Bind(obj interface{}) error { +	b := binding.Default(c.Request.Method, c.ContentType()) +	return c.BindWith(obj, b) +} + +// Shortcut for c.BindWith(obj, binding.JSON) +func (c *Context) BindJSON(obj interface{}) error { +	return c.BindWith(obj, binding.JSON) +} + +func (c *Context) BindWith(obj interface{}, b binding.Binding) error { +	if err := b.Bind(c.Request, obj); err != nil { +		c.AbortWithError(400, err).SetType(ErrorTypeBind) +		return err +	} +	return nil +} + +// Best effort algoritm to return the real client IP, it parses +// X-Real-IP and X-Forwarded-For in order to work properly with reverse-proxies such us: nginx or haproxy. +func (c *Context) ClientIP() string { +	if c.engine.ForwardedByClientIP { +		clientIP := strings.TrimSpace(c.requestHeader("X-Real-Ip")) +		if len(clientIP) > 0 { +			return clientIP +		} +		clientIP = c.requestHeader("X-Forwarded-For") +		if index := strings.IndexByte(clientIP, ','); index >= 0 { +			clientIP = clientIP[0:index] +		} +		clientIP = strings.TrimSpace(clientIP) +		if len(clientIP) > 0 { +			return clientIP +		} +	} +	return strings.TrimSpace(c.Request.RemoteAddr) +} + +func (c *Context) ContentType() string { +	return filterFlags(c.requestHeader("Content-Type")) +} + +func (c *Context) requestHeader(key string) string { +	if values, _ := c.Request.Header[key]; len(values) > 0 { +		return values[0] +	} +	return "" +} + +/************************************/ +/******** RESPONSE RENDERING ********/ +/************************************/ + +// Intelligent shortcut for c.Writer.Header().Set(key, value) +// it writes a header in the response. +// If value == "", this method removes the header `c.Writer.Header().Del(key)` +func (c *Context) Header(key, value string) { +	if len(value) == 0 { +		c.Writer.Header().Del(key) +	} else { +		c.Writer.Header().Set(key, value) +	} +} + +func (c *Context) Render(code int, r render.Render) { +	c.writermem.WriteHeader(code) +	if err := r.Render(c.Writer); err != nil { +		c.renderError(err) +	} +} + +func (c *Context) renderError(err error) { +	debugPrintError(err) +	c.AbortWithError(500, err).SetType(ErrorTypeRender) +} + +// Renders the HTTP template specified by its file name. +// It also updates the HTTP code and sets the Content-Type as "text/html". +// See http://golang.org/doc/articles/wiki/ +func (c *Context) HTML(code int, name string, obj interface{}) { +	instance := c.engine.HTMLRender.Instance(name, obj) +	c.Render(code, instance) +} + +// Serializes the given struct as pretty JSON (indented + endlines) into the response body. +// It also sets the Content-Type as "application/json". +// WARNING: we recommend to use this only for development propuses since printing pretty JSON is +// more CPU and bandwidth consuming. Use Context.JSON() instead. +func (c *Context) IndentedJSON(code int, obj interface{}) { +	c.Render(code, render.IndentedJSON{Data: obj}) +} + +// Serializes the given struct as JSON into the response body. +// It also sets the Content-Type as "application/json". +func (c *Context) JSON(code int, obj interface{}) { +	c.writermem.WriteHeader(code) +	if err := render.WriteJSON(c.Writer, obj); err != nil { +		c.renderError(err) +	} +} + +// Serializes the given struct as XML into the response body. +// It also sets the Content-Type as "application/xml". +func (c *Context) XML(code int, obj interface{}) { +	c.Render(code, render.XML{Data: obj}) +} + +// Writes the given string into the response body. +func (c *Context) String(code int, format string, values ...interface{}) { +	c.writermem.WriteHeader(code) +	render.WriteString(c.Writer, format, values) +} + +// Returns a HTTP redirect to the specific location. +func (c *Context) Redirect(code int, location string) { +	c.Render(-1, render.Redirect{ +		Code:     code, +		Location: location, +		Request:  c.Request, +	}) +} + +// Writes some data into the body stream and updates the HTTP code. +func (c *Context) Data(code int, contentType string, data []byte) { +	c.Render(code, render.Data{ +		ContentType: contentType, +		Data:        data, +	}) +} + +// Writes the specified file into the body stream in a efficient way. +func (c *Context) File(filepath string) { +	http.ServeFile(c.Writer, c.Request, filepath) +} + +func (c *Context) SSEvent(name string, message interface{}) { +	c.Render(-1, sse.Event{ +		Event: name, +		Data:  message, +	}) +} + +func (c *Context) Stream(step func(w io.Writer) bool) { +	w := c.Writer +	clientGone := w.CloseNotify() +	for { +		select { +		case <-clientGone: +			return +		default: +			keepopen := step(w) +			w.Flush() +			if !keepopen { +				return +			} +		} +	} +} + +/************************************/ +/******** CONTENT NEGOTIATION *******/ +/************************************/ + +type Negotiate struct { +	Offered  []string +	HTMLName string +	HTMLData interface{} +	JSONData interface{} +	XMLData  interface{} +	Data     interface{} +} + +func (c *Context) Negotiate(code int, config Negotiate) { +	switch c.NegotiateFormat(config.Offered...) { +	case binding.MIMEJSON: +		data := chooseData(config.JSONData, config.Data) +		c.JSON(code, data) + +	case binding.MIMEHTML: +		data := chooseData(config.HTMLData, config.Data) +		c.HTML(code, config.HTMLName, data) + +	case binding.MIMEXML: +		data := chooseData(config.XMLData, config.Data) +		c.XML(code, data) + +	default: +		c.AbortWithError(http.StatusNotAcceptable, errors.New("the accepted formats are not offered by the server")) +	} +} + +func (c *Context) NegotiateFormat(offered ...string) string { +	if len(offered) == 0 { +		panic("you must provide at least one offer") +	} +	if c.Accepted == nil { +		c.Accepted = parseAccept(c.requestHeader("Accept")) +	} +	if len(c.Accepted) == 0 { +		return offered[0] +	} +	for _, accepted := range c.Accepted { +		for _, offert := range offered { +			if accepted == offert { +				return offert +			} +		} +	} +	return "" +} + +func (c *Context) SetAccepted(formats ...string) { +	c.Accepted = formats +} + +/************************************/ +/***** GOLANG.ORG/X/NET/CONTEXT *****/ +/************************************/ + +func (c *Context) Deadline() (deadline time.Time, ok bool) { +	return +} + +func (c *Context) Done() <-chan struct{} { +	return nil +} + +func (c *Context) Err() error { +	return nil +} + +func (c *Context) Value(key interface{}) interface{} { +	if key == 0 { +		return c.Request +	} +	if keyAsString, ok := key.(string); ok { +		val, _ := c.Get(keyAsString) +		return val +	} +	return nil +} diff --git a/vendor/github.com/gin-gonic/gin/debug.go b/vendor/github.com/gin-gonic/gin/debug.go new file mode 100644 index 0000000..2f4b101 --- /dev/null +++ b/vendor/github.com/gin-gonic/gin/debug.go @@ -0,0 +1,52 @@ +// Copyright 2014 Manu Martinez-Almeida.  All rights reserved. +// Use of this source code is governed by a MIT style +// license that can be found in the LICENSE file. + +package gin + +import "log" + +func init() { +	log.SetFlags(0) +} +func IsDebugging() bool { +	return ginMode == debugCode +} + +func debugPrintRoute(httpMethod, absolutePath string, handlers HandlersChain) { +	if IsDebugging() { +		nuHandlers := len(handlers) +		handlerName := nameOfFunction(handlers.Last()) +		debugPrint("%-5s %-25s --> %s (%d handlers)\n", httpMethod, absolutePath, handlerName, nuHandlers) +	} +} + +func debugPrint(format string, values ...interface{}) { +	if IsDebugging() { +		log.Printf("[GIN-debug] "+format, values...) +	} +} + +func debugPrintWARNING_New() { +	debugPrint(`[WARNING] Running in "debug" mode. Switch to "release" mode in production. + - using env:	export GIN_MODE=release + - using code:	gin.SetMode(gin.ReleaseMode) + +`) +} + +func debugPrintWARNING_SetHTMLTemplate() { +	debugPrint(`[WARNING] Since SetHTMLTemplate() is NOT thread-safe. It should only be called +at initialization. ie. before any route is registered or the router is listening in a socket: + +	router := gin.Default() +	router.SetHTMLTemplate(template) // << good place + +`) +} + +func debugPrintError(err error) { +	if err != nil { +		debugPrint("[ERROR] %v\n", err) +	} +} diff --git a/vendor/github.com/gin-gonic/gin/deprecated.go b/vendor/github.com/gin-gonic/gin/deprecated.go new file mode 100644 index 0000000..b2e874f --- /dev/null +++ b/vendor/github.com/gin-gonic/gin/deprecated.go @@ -0,0 +1,5 @@ +// Copyright 2014 Manu Martinez-Almeida.  All rights reserved. +// Use of this source code is governed by a MIT style +// license that can be found in the LICENSE file. + +package gin diff --git a/vendor/github.com/gin-gonic/gin/errors.go b/vendor/github.com/gin-gonic/gin/errors.go new file mode 100644 index 0000000..982c026 --- /dev/null +++ b/vendor/github.com/gin-gonic/gin/errors.go @@ -0,0 +1,161 @@ +// Copyright 2014 Manu Martinez-Almeida.  All rights reserved. +// Use of this source code is governed by a MIT style +// license that can be found in the LICENSE file. + +package gin + +import ( +	"bytes" +	"encoding/json" +	"fmt" +	"reflect" +) + +type ErrorType uint64 + +const ( +	ErrorTypeBind    ErrorType = 1 << 63 // used when c.Bind() fails +	ErrorTypeRender  ErrorType = 1 << 62 // used when c.Render() fails +	ErrorTypePrivate ErrorType = 1 << 0 +	ErrorTypePublic  ErrorType = 1 << 1 + +	ErrorTypeAny ErrorType = 1<<64 - 1 +	ErrorTypeNu            = 2 +) + +type ( +	Error struct { +		Err  error +		Type ErrorType +		Meta interface{} +	} + +	errorMsgs []*Error +) + +var _ error = &Error{} + +func (msg *Error) SetType(flags ErrorType) *Error { +	msg.Type = flags +	return msg +} + +func (msg *Error) SetMeta(data interface{}) *Error { +	msg.Meta = data +	return msg +} + +func (msg *Error) JSON() interface{} { +	json := H{} +	if msg.Meta != nil { +		value := reflect.ValueOf(msg.Meta) +		switch value.Kind() { +		case reflect.Struct: +			return msg.Meta +		case reflect.Map: +			for _, key := range value.MapKeys() { +				json[key.String()] = value.MapIndex(key).Interface() +			} +		default: +			json["meta"] = msg.Meta +		} +	} +	if _, ok := json["error"]; !ok { +		json["error"] = msg.Error() +	} +	return json +} + +// Implements the json.Marshaller interface +func (msg *Error) MarshalJSON() ([]byte, error) { +	return json.Marshal(msg.JSON()) +} + +// Implements the error interface +func (msg *Error) Error() string { +	return msg.Err.Error() +} + +func (msg *Error) IsType(flags ErrorType) bool { +	return (msg.Type & flags) > 0 +} + +// Returns a readonly copy filterd the byte. +// ie ByType(gin.ErrorTypePublic) returns a slice of errors with type=ErrorTypePublic +func (a errorMsgs) ByType(typ ErrorType) errorMsgs { +	if len(a) == 0 { +		return nil +	} +	if typ == ErrorTypeAny { +		return a +	} +	var result errorMsgs = nil +	for _, msg := range a { +		if msg.IsType(typ) { +			result = append(result, msg) +		} +	} +	return result +} + +// Returns the last error in the slice. It returns nil if the array is empty. +// Shortcut for errors[len(errors)-1] +func (a errorMsgs) Last() *Error { +	length := len(a) +	if length == 0 { +		return nil +	} +	return a[length-1] +} + +// Returns an array will all the error messages. +// Example +// ``` +// c.Error(errors.New("first")) +// c.Error(errors.New("second")) +// c.Error(errors.New("third")) +// c.Errors.Errors() // == []string{"first", "second", "third"} +// `` +func (a errorMsgs) Errors() []string { +	if len(a) == 0 { +		return nil +	} +	errorStrings := make([]string, len(a)) +	for i, err := range a { +		errorStrings[i] = err.Error() +	} +	return errorStrings +} + +func (a errorMsgs) JSON() interface{} { +	switch len(a) { +	case 0: +		return nil +	case 1: +		return a.Last().JSON() +	default: +		json := make([]interface{}, len(a)) +		for i, err := range a { +			json[i] = err.JSON() +		} +		return json +	} +} + +func (a errorMsgs) MarshalJSON() ([]byte, error) { +	return json.Marshal(a.JSON()) +} + +func (a errorMsgs) String() string { +	if len(a) == 0 { +		return "" +	} +	var buffer bytes.Buffer +	for i, msg := range a { +		fmt.Fprintf(&buffer, "Error #%02d: %s\n", (i + 1), msg.Err) +		if msg.Meta != nil { +			fmt.Fprintf(&buffer, "     Meta: %v\n", msg.Meta) +		} +	} +	return buffer.String() +} diff --git a/vendor/github.com/gin-gonic/gin/fs.go b/vendor/github.com/gin-gonic/gin/fs.go new file mode 100644 index 0000000..f95dc84 --- /dev/null +++ b/vendor/github.com/gin-gonic/gin/fs.go @@ -0,0 +1,43 @@ +package gin + +import ( +	"net/http" +	"os" +) + +type ( +	onlyfilesFS struct { +		fs http.FileSystem +	} +	neuteredReaddirFile struct { +		http.File +	} +) + +// It returns a http.Filesystem that can be used by http.FileServer(). It is used interally +// in router.Static(). +// if listDirectory == true, then it works the same as http.Dir() otherwise it returns +// a filesystem that prevents http.FileServer() to list the directory files. +func Dir(root string, listDirectory bool) http.FileSystem { +	fs := http.Dir(root) +	if listDirectory { +		return fs +	} else { +		return &onlyfilesFS{fs} +	} +} + +// Conforms to http.Filesystem +func (fs onlyfilesFS) Open(name string) (http.File, error) { +	f, err := fs.fs.Open(name) +	if err != nil { +		return nil, err +	} +	return neuteredReaddirFile{f}, nil +} + +// Overrides the http.File default implementation +func (f neuteredReaddirFile) Readdir(count int) ([]os.FileInfo, error) { +	// this disables directory listing +	return nil, nil +} diff --git a/vendor/github.com/gin-gonic/gin/gin.go b/vendor/github.com/gin-gonic/gin/gin.go new file mode 100644 index 0000000..7b0ede1 --- /dev/null +++ b/vendor/github.com/gin-gonic/gin/gin.go @@ -0,0 +1,369 @@ +// Copyright 2014 Manu Martinez-Almeida.  All rights reserved. +// Use of this source code is governed by a MIT style +// license that can be found in the LICENSE file. + +package gin + +import ( +	"html/template" +	"net" +	"net/http" +	"os" +	"sync" + +	"github.com/gin-gonic/gin/render" +) + +const Version = "v1.0rc2" + +var default404Body = []byte("404 page not found") +var default405Body = []byte("405 method not allowed") + +type HandlerFunc func(*Context) +type HandlersChain []HandlerFunc + +func (c HandlersChain) Last() HandlerFunc { +	length := len(c) +	if length > 0 { +		return c[length-1] +	} +	return nil +} + +type ( +	RoutesInfo []RouteInfo +	RouteInfo  struct { +		Method  string +		Path    string +		Handler string +	} + +	// Represents the web framework, it wraps the blazing fast httprouter multiplexer and a list of global middlewares. +	Engine struct { +		RouterGroup +		HTMLRender  render.HTMLRender +		allNoRoute  HandlersChain +		allNoMethod HandlersChain +		noRoute     HandlersChain +		noMethod    HandlersChain +		pool        sync.Pool +		trees       methodTrees + +		// Enables automatic redirection if the current route can't be matched but a +		// handler for the path with (without) the trailing slash exists. +		// For example if /foo/ is requested but a route only exists for /foo, the +		// client is redirected to /foo with http status code 301 for GET requests +		// and 307 for all other request methods. +		RedirectTrailingSlash bool + +		// If enabled, the router tries to fix the current request path, if no +		// handle is registered for it. +		// First superfluous path elements like ../ or // are removed. +		// Afterwards the router does a case-insensitive lookup of the cleaned path. +		// If a handle can be found for this route, the router makes a redirection +		// to the corrected path with status code 301 for GET requests and 307 for +		// all other request methods. +		// For example /FOO and /..//Foo could be redirected to /foo. +		// RedirectTrailingSlash is independent of this option. +		RedirectFixedPath bool + +		// If enabled, the router checks if another method is allowed for the +		// current route, if the current request can not be routed. +		// If this is the case, the request is answered with 'Method Not Allowed' +		// and HTTP status code 405. +		// If no other Method is allowed, the request is delegated to the NotFound +		// handler. +		HandleMethodNotAllowed bool +		ForwardedByClientIP    bool +	} +) + +var _ RoutesInterface = &Engine{} + +// Returns a new blank Engine instance without any middleware attached. +// The most basic configuration +func New() *Engine { +	debugPrintWARNING_New() +	engine := &Engine{ +		RouterGroup: RouterGroup{ +			Handlers: nil, +			BasePath: "/", +			root:     true, +		}, +		RedirectTrailingSlash:  true, +		RedirectFixedPath:      false, +		HandleMethodNotAllowed: false, +		ForwardedByClientIP:    true, +		trees:                  make(methodTrees, 0, 9), +	} +	engine.RouterGroup.engine = engine +	engine.pool.New = func() interface{} { +		return engine.allocateContext() +	} +	return engine +} + +// Returns a Engine instance with the Logger and Recovery already attached. +func Default() *Engine { +	engine := New() +	engine.Use(Recovery(), Logger()) +	return engine +} + +func (engine *Engine) allocateContext() *Context { +	return &Context{engine: engine} +} + +func (engine *Engine) LoadHTMLGlob(pattern string) { +	if IsDebugging() { +		engine.HTMLRender = render.HTMLDebug{Glob: pattern} +	} else { +		templ := template.Must(template.ParseGlob(pattern)) +		engine.SetHTMLTemplate(templ) +	} +} + +func (engine *Engine) LoadHTMLFiles(files ...string) { +	if IsDebugging() { +		engine.HTMLRender = render.HTMLDebug{Files: files} +	} else { +		templ := template.Must(template.ParseFiles(files...)) +		engine.SetHTMLTemplate(templ) +	} +} + +func (engine *Engine) SetHTMLTemplate(templ *template.Template) { +	if len(engine.trees) > 0 { +		debugPrintWARNING_SetHTMLTemplate() +	} +	engine.HTMLRender = render.HTMLProduction{Template: templ} +} + +// Adds handlers for NoRoute. It return a 404 code by default. +func (engine *Engine) NoRoute(handlers ...HandlerFunc) { +	engine.noRoute = handlers +	engine.rebuild404Handlers() +} + +// Sets the handlers called when... TODO +func (engine *Engine) NoMethod(handlers ...HandlerFunc) { +	engine.noMethod = handlers +	engine.rebuild405Handlers() +} + +// Attachs a global middleware to the router. ie. the middlewares attached though Use() will be +// included in the handlers chain for every single request. Even 404, 405, static files... +// For example, this is the right place for a logger or error management middleware. +func (engine *Engine) Use(middlewares ...HandlerFunc) routesInterface { +	engine.RouterGroup.Use(middlewares...) +	engine.rebuild404Handlers() +	engine.rebuild405Handlers() +	return engine +} + +func (engine *Engine) rebuild404Handlers() { +	engine.allNoRoute = engine.combineHandlers(engine.noRoute) +} + +func (engine *Engine) rebuild405Handlers() { +	engine.allNoMethod = engine.combineHandlers(engine.noMethod) +} + +func (engine *Engine) addRoute(method, path string, handlers HandlersChain) { +	debugPrintRoute(method, path, handlers) + +	if path[0] != '/' { +		panic("path must begin with '/'") +	} +	if method == "" { +		panic("HTTP method can not be empty") +	} +	if len(handlers) == 0 { +		panic("there must be at least one handler") +	} + +	root := engine.trees.get(method) +	if root == nil { +		root = new(node) +		engine.trees = append(engine.trees, methodTree{ +			method: method, +			root:   root, +		}) +	} +	root.addRoute(path, handlers) +} + +func (engine *Engine) Routes() (routes RoutesInfo) { +	for _, tree := range engine.trees { +		routes = iterate("", tree.method, routes, tree.root) +	} +	return routes +} + +func iterate(path, method string, routes RoutesInfo, root *node) RoutesInfo { +	path += root.path +	if len(root.handlers) > 0 { +		routes = append(routes, RouteInfo{ +			Method:  method, +			Path:    path, +			Handler: nameOfFunction(root.handlers.Last()), +		}) +	} +	for _, node := range root.children { +		routes = iterate(path, method, routes, node) +	} +	return routes +} + +// The router is attached to a http.Server and starts listening and serving HTTP requests. +// It is a shortcut for http.ListenAndServe(addr, router) +// Note: this method will block the calling goroutine undefinitelly unless an error happens. +func (engine *Engine) Run(addr string) (err error) { +	debugPrint("Listening and serving HTTP on %s\n", addr) +	defer func() { debugPrintError(err) }() + +	err = http.ListenAndServe(addr, engine) +	return +} + +// The router is attached to a http.Server and starts listening and serving HTTPS requests. +// It is a shortcut for http.ListenAndServeTLS(addr, certFile, keyFile, router) +// Note: this method will block the calling goroutine undefinitelly unless an error happens. +func (engine *Engine) RunTLS(addr string, certFile string, keyFile string) (err error) { +	debugPrint("Listening and serving HTTPS on %s\n", addr) +	defer func() { debugPrintError(err) }() + +	err = http.ListenAndServeTLS(addr, certFile, keyFile, engine) +	return +} + +// The router is attached to a http.Server and starts listening and serving HTTP requests +// through the specified unix socket (ie. a file) +// Note: this method will block the calling goroutine undefinitelly unless an error happens. +func (engine *Engine) RunUnix(file string) (err error) { +	debugPrint("Listening and serving HTTP on unix:/%s", file) +	defer func() { debugPrintError(err) }() + +	os.Remove(file) +	listener, err := net.Listen("unix", file) +	if err != nil { +		return +	} +	defer listener.Close() +	err = http.Serve(listener, engine) +	return +} + +// Conforms to the http.Handler interface. +func (engine *Engine) ServeHTTP(w http.ResponseWriter, req *http.Request) { +	c := engine.pool.Get().(*Context) +	c.writermem.reset(w) +	c.Request = req +	c.reset() + +	engine.handleHTTPRequest(c) + +	engine.pool.Put(c) +} + +func (engine *Engine) handleHTTPRequest(context *Context) { +	httpMethod := context.Request.Method +	path := context.Request.URL.Path + +	// Find root of the tree for the given HTTP method +	t := engine.trees +	for i, tl := 0, len(t); i < tl; i++ { +		if t[i].method == httpMethod { +			root := t[i].root +			// Find route in tree +			handlers, params, tsr := root.getValue(path, context.Params) +			if handlers != nil { +				context.handlers = handlers +				context.Params = params +				context.Next() +				context.writermem.WriteHeaderNow() +				return + +			} else if httpMethod != "CONNECT" && path != "/" { +				if tsr && engine.RedirectFixedPath { +					redirectTrailingSlash(context) +					return +				} +				if engine.RedirectFixedPath && redirectFixedPath(context, root, engine.RedirectFixedPath) { +					return +				} +			} +			break +		} +	} + +	// TODO: unit test +	if engine.HandleMethodNotAllowed { +		for _, tree := range engine.trees { +			if tree.method != httpMethod { +				if handlers, _, _ := tree.root.getValue(path, nil); handlers != nil { +					context.handlers = engine.allNoMethod +					serveError(context, 405, default405Body) +					return +				} +			} +		} +	} +	context.handlers = engine.allNoRoute +	serveError(context, 404, default404Body) +} + +var mimePlain = []string{MIMEPlain} + +func serveError(c *Context, code int, defaultMessage []byte) { +	c.writermem.status = code +	c.Next() +	if !c.writermem.Written() { +		if c.writermem.Status() == code { +			c.writermem.Header()["Content-Type"] = mimePlain +			c.Writer.Write(defaultMessage) +		} else { +			c.writermem.WriteHeaderNow() +		} +	} +} + +func redirectTrailingSlash(c *Context) { +	req := c.Request +	path := req.URL.Path +	code := 301 // Permanent redirect, request with GET method +	if req.Method != "GET" { +		code = 307 +	} + +	if len(path) > 1 && path[len(path)-1] == '/' { +		req.URL.Path = path[:len(path)-1] +	} else { +		req.URL.Path = path + "/" +	} +	debugPrint("redirecting request %d: %s --> %s", code, path, req.URL.String()) +	http.Redirect(c.Writer, req, req.URL.String(), code) +	c.writermem.WriteHeaderNow() +} + +func redirectFixedPath(c *Context, root *node, trailingSlash bool) bool { +	req := c.Request +	path := req.URL.Path + +	fixedPath, found := root.findCaseInsensitivePath( +		cleanPath(path), +		trailingSlash, +	) +	if found { +		code := 301 // Permanent redirect, request with GET method +		if req.Method != "GET" { +			code = 307 +		} +		req.URL.Path = string(fixedPath) +		debugPrint("redirecting request %d: %s --> %s", code, path, req.URL.String()) +		http.Redirect(c.Writer, req, req.URL.String(), code) +		c.writermem.WriteHeaderNow() +		return true +	} +	return false +} diff --git a/vendor/github.com/gin-gonic/gin/logger.go b/vendor/github.com/gin-gonic/gin/logger.go new file mode 100644 index 0000000..e0f9b36 --- /dev/null +++ b/vendor/github.com/gin-gonic/gin/logger.go @@ -0,0 +1,113 @@ +// Copyright 2014 Manu Martinez-Almeida.  All rights reserved. +// Use of this source code is governed by a MIT style +// license that can be found in the LICENSE file. + +package gin + +import ( +	"fmt" +	"io" +	"time" +) + +var ( +	green   = string([]byte{27, 91, 57, 55, 59, 52, 50, 109}) +	white   = string([]byte{27, 91, 57, 48, 59, 52, 55, 109}) +	yellow  = string([]byte{27, 91, 57, 55, 59, 52, 51, 109}) +	red     = string([]byte{27, 91, 57, 55, 59, 52, 49, 109}) +	blue    = string([]byte{27, 91, 57, 55, 59, 52, 52, 109}) +	magenta = string([]byte{27, 91, 57, 55, 59, 52, 53, 109}) +	cyan    = string([]byte{27, 91, 57, 55, 59, 52, 54, 109}) +	reset   = string([]byte{27, 91, 48, 109}) +) + +func ErrorLogger() HandlerFunc { +	return ErrorLoggerT(ErrorTypeAny) +} + +func ErrorLoggerT(typ ErrorType) HandlerFunc { +	return func(c *Context) { +		c.Next() +		// avoid writting if we already wrote into the response body +		if !c.Writer.Written() { +			errors := c.Errors.ByType(typ) +			if len(errors) > 0 { +				c.JSON(-1, errors) +			} +		} +	} +} + +// Instances a Logger middleware that will write the logs to gin.DefaultWriter +// By default gin.DefaultWriter = os.Stdout +func Logger() HandlerFunc { +	return LoggerWithWriter(DefaultWriter) +} + +// Instance a Logger middleware with the specified writter buffer. +// Example: os.Stdout, a file opened in write mode, a socket... +func LoggerWithWriter(out io.Writer) HandlerFunc { +	return func(c *Context) { +		// Start timer +		start := time.Now() +		path := c.Request.URL.Path + +		// Process request +		c.Next() + +		// Stop timer +		end := time.Now() +		latency := end.Sub(start) + +		clientIP := c.ClientIP() +		method := c.Request.Method +		statusCode := c.Writer.Status() +		statusColor := colorForStatus(statusCode) +		methodColor := colorForMethod(method) +		comment := c.Errors.ByType(ErrorTypePrivate).String() + +		fmt.Fprintf(out, "[GIN] %v |%s %3d %s| %13v | %s |%s  %s %-7s %s\n%s", +			end.Format("2006/01/02 - 15:04:05"), +			statusColor, statusCode, reset, +			latency, +			clientIP, +			methodColor, reset, method, +			path, +			comment, +		) +	} +} + +func colorForStatus(code int) string { +	switch { +	case code >= 200 && code < 300: +		return green +	case code >= 300 && code < 400: +		return white +	case code >= 400 && code < 500: +		return yellow +	default: +		return red +	} +} + +func colorForMethod(method string) string { +	switch method { +	case "GET": +		return blue +	case "POST": +		return cyan +	case "PUT": +		return yellow +	case "DELETE": +		return red +	case "PATCH": +		return green +	case "HEAD": +		return magenta +	case "OPTIONS": +		return white +	default: +		return reset +	} +} diff --git a/vendor/github.com/gin-gonic/gin/mode.go b/vendor/github.com/gin-gonic/gin/mode.go new file mode 100644 index 0000000..15efaeb --- /dev/null +++ b/vendor/github.com/gin-gonic/gin/mode.go @@ -0,0 +1,61 @@ +// Copyright 2014 Manu Martinez-Almeida.  All rights reserved. +// Use of this source code is governed by a MIT style +// license that can be found in the LICENSE file. + +package gin + +import ( +	"io" +	"os" + +	"github.com/gin-gonic/gin/binding" +	"github.com/mattn/go-colorable" +) + +const ENV_GIN_MODE = "GIN_MODE" + +const ( +	DebugMode   string = "debug" +	ReleaseMode string = "release" +	TestMode    string = "test" +) +const ( +	debugCode   = iota +	releaseCode = iota +	testCode    = iota +) + +var DefaultWriter io.Writer = colorable.NewColorableStdout() +var ginMode int = debugCode +var modeName string = DebugMode + +func init() { +	mode := os.Getenv(ENV_GIN_MODE) +	if len(mode) == 0 { +		SetMode(DebugMode) +	} else { +		SetMode(mode) +	} +} + +func SetMode(value string) { +	switch value { +	case DebugMode: +		ginMode = debugCode +	case ReleaseMode: +		ginMode = releaseCode +	case TestMode: +		ginMode = testCode +	default: +		panic("gin mode unknown: " + value) +	} +	modeName = value +} + +func DisableBindValidation() { +	binding.Validator = nil +} + +func Mode() string { +	return modeName +} diff --git a/vendor/github.com/gin-gonic/gin/path.go b/vendor/github.com/gin-gonic/gin/path.go new file mode 100644 index 0000000..43cdd04 --- /dev/null +++ b/vendor/github.com/gin-gonic/gin/path.go @@ -0,0 +1,123 @@ +// Copyright 2013 Julien Schmidt. All rights reserved. +// Based on the path package, Copyright 2009 The Go Authors. +// Use of this source code is governed by a BSD-style license that can be found +// in the LICENSE file. + +package gin + +// CleanPath is the URL version of path.Clean, it returns a canonical URL path +// for p, eliminating . and .. elements. +// +// The following rules are applied iteratively until no further processing can +// be done: +//	1. Replace multiple slashes with a single slash. +//	2. Eliminate each . path name element (the current directory). +//	3. Eliminate each inner .. path name element (the parent directory) +//	   along with the non-.. element that precedes it. +//	4. Eliminate .. elements that begin a rooted path: +//	   that is, replace "/.." by "/" at the beginning of a path. +// +// If the result of this process is an empty string, "/" is returned +func cleanPath(p string) string { +	// Turn empty string into "/" +	if p == "" { +		return "/" +	} + +	n := len(p) +	var buf []byte + +	// Invariants: +	//      reading from path; r is index of next byte to process. +	//      writing to buf; w is index of next byte to write. + +	// path must start with '/' +	r := 1 +	w := 1 + +	if p[0] != '/' { +		r = 0 +		buf = make([]byte, n+1) +		buf[0] = '/' +	} + +	trailing := n > 2 && p[n-1] == '/' + +	// A bit more clunky without a 'lazybuf' like the path package, but the loop +	// gets completely inlined (bufApp). So in contrast to the path package this +	// loop has no expensive function calls (except 1x make) + +	for r < n { +		switch { +		case p[r] == '/': +			// empty path element, trailing slash is added after the end +			r++ + +		case p[r] == '.' && r+1 == n: +			trailing = true +			r++ + +		case p[r] == '.' && p[r+1] == '/': +			// . element +			r++ + +		case p[r] == '.' && p[r+1] == '.' && (r+2 == n || p[r+2] == '/'): +			// .. element: remove to last / +			r += 2 + +			if w > 1 { +				// can backtrack +				w-- + +				if buf == nil { +					for w > 1 && p[w] != '/' { +						w-- +					} +				} else { +					for w > 1 && buf[w] != '/' { +						w-- +					} +				} +			} + +		default: +			// real path element. +			// add slash if needed +			if w > 1 { +				bufApp(&buf, p, w, '/') +				w++ +			} + +			// copy element +			for r < n && p[r] != '/' { +				bufApp(&buf, p, w, p[r]) +				w++ +				r++ +			} +		} +	} + +	// re-append trailing slash +	if trailing && w > 1 { +		bufApp(&buf, p, w, '/') +		w++ +	} + +	if buf == nil { +		return p[:w] +	} +	return string(buf[:w]) +} + +// internal helper to lazily create a buffer if necessary +func bufApp(buf *[]byte, s string, w int, c byte) { +	if *buf == nil { +		if s[w] == c { +			return +		} + +		*buf = make([]byte, len(s)) +		copy(*buf, s[:w]) +	} +	(*buf)[w] = c +} diff --git a/vendor/github.com/gin-gonic/gin/recovery.go b/vendor/github.com/gin-gonic/gin/recovery.go new file mode 100644 index 0000000..e296e33 --- /dev/null +++ b/vendor/github.com/gin-gonic/gin/recovery.go @@ -0,0 +1,106 @@ +// Copyright 2014 Manu Martinez-Almeida.  All rights reserved. +// Use of this source code is governed by a MIT style +// license that can be found in the LICENSE file. + +package gin + +import ( +	"bytes" +	"fmt" +	"io" +	"io/ioutil" +	"log" +	"runtime" +) + +var ( +	dunno     = []byte("???") +	centerDot = []byte("·") +	dot       = []byte(".") +	slash     = []byte("/") +) + +// Recovery returns a middleware that recovers from any panics and writes a 500 if there was one. +func Recovery() HandlerFunc { +	return RecoveryWithWriter(DefaultWriter) +} + +func RecoveryWithWriter(out io.Writer) HandlerFunc { +	var logger *log.Logger +	if out != nil { +		logger = log.New(out, "", log.LstdFlags) +	} +	return func(c *Context) { +		defer func() { +			if err := recover(); err != nil { +				if logger != nil { +					stack := stack(3) +					logger.Printf("Panic recovery -> %s\n%s\n", err, stack) +				} +				c.AbortWithStatus(500) +			} +		}() +		c.Next() +	} +} + +// stack returns a nicely formated stack frame, skipping skip frames +func stack(skip int) []byte { +	buf := new(bytes.Buffer) // the returned data +	// As we loop, we open files and read them. These variables record the currently +	// loaded file. +	var lines [][]byte +	var lastFile string +	for i := skip; ; i++ { // Skip the expected number of frames +		pc, file, line, ok := runtime.Caller(i) +		if !ok { +			break +		} +		// Print this much at least.  If we can't find the source, it won't show. +		fmt.Fprintf(buf, "%s:%d (0x%x)\n", file, line, pc) +		if file != lastFile { +			data, err := ioutil.ReadFile(file) +			if err != nil { +				continue +			} +			lines = bytes.Split(data, []byte{'\n'}) +			lastFile = file +		} +		fmt.Fprintf(buf, "\t%s: %s\n", function(pc), source(lines, line)) +	} +	return buf.Bytes() +} + +// source returns a space-trimmed slice of the n'th line. +func source(lines [][]byte, n int) []byte { +	n-- // in stack trace, lines are 1-indexed but our array is 0-indexed +	if n < 0 || n >= len(lines) { +		return dunno +	} +	return bytes.TrimSpace(lines[n]) +} + +// function returns, if possible, the name of the function containing the PC. +func function(pc uintptr) []byte { +	fn := runtime.FuncForPC(pc) +	if fn == nil { +		return dunno +	} +	name := []byte(fn.Name()) +	// The name includes the path name to the package, which is unnecessary +	// since the file name is already included.  Plus, it has center dots. +	// That is, we see +	//	runtime/debug.*T·ptrmethod +	// and want +	//	*T.ptrmethod +	// Also the package path might contains dot (e.g. code.google.com/...), +	// so first eliminate the path prefix +	if lastslash := bytes.LastIndex(name, slash); lastslash >= 0 { +		name = name[lastslash+1:] +	} +	if period := bytes.Index(name, dot); period >= 0 { +		name = name[period+1:] +	} +	name = bytes.Replace(name, centerDot, dot, -1) +	return name +} diff --git a/vendor/github.com/gin-gonic/gin/render/data.go b/vendor/github.com/gin-gonic/gin/render/data.go new file mode 100644 index 0000000..efa75d5 --- /dev/null +++ b/vendor/github.com/gin-gonic/gin/render/data.go @@ -0,0 +1,20 @@ +// Copyright 2014 Manu Martinez-Almeida.  All rights reserved. +// Use of this source code is governed by a MIT style +// license that can be found in the LICENSE file. + +package render + +import "net/http" + +type Data struct { +	ContentType string +	Data        []byte +} + +func (r Data) Render(w http.ResponseWriter) error { +	if len(r.ContentType) > 0 { +		w.Header()["Content-Type"] = []string{r.ContentType} +	} +	w.Write(r.Data) +	return nil +} diff --git a/vendor/github.com/gin-gonic/gin/render/html.go b/vendor/github.com/gin-gonic/gin/render/html.go new file mode 100644 index 0000000..01f6bf2 --- /dev/null +++ b/vendor/github.com/gin-gonic/gin/render/html.go @@ -0,0 +1,67 @@ +// Copyright 2014 Manu Martinez-Almeida.  All rights reserved. +// Use of this source code is governed by a MIT style +// license that can be found in the LICENSE file. + +package render + +import ( +	"html/template" +	"net/http" +) + +type ( +	HTMLRender interface { +		Instance(string, interface{}) Render +	} + +	HTMLProduction struct { +		Template *template.Template +	} + +	HTMLDebug struct { +		Files []string +		Glob  string +	} + +	HTML struct { +		Template *template.Template +		Name     string +		Data     interface{} +	} +) + +var htmlContentType = []string{"text/html; charset=utf-8"} + +func (r HTMLProduction) Instance(name string, data interface{}) Render { +	return HTML{ +		Template: r.Template, +		Name:     name, +		Data:     data, +	} +} + +func (r HTMLDebug) Instance(name string, data interface{}) Render { +	return HTML{ +		Template: r.loadTemplate(), +		Name:     name, +		Data:     data, +	} +} +func (r HTMLDebug) loadTemplate() *template.Template { +	if len(r.Files) > 0 { +		return template.Must(template.ParseFiles(r.Files...)) +	} +	if len(r.Glob) > 0 { +		return template.Must(template.ParseGlob(r.Glob)) +	} +	panic("the HTML debug render was created without files or glob pattern") +} + +func (r HTML) Render(w http.ResponseWriter) error { +	writeContentType(w, htmlContentType) +	if len(r.Name) == 0 { +		return r.Template.Execute(w, r.Data) +	} else { +		return r.Template.ExecuteTemplate(w, r.Name, r.Data) +	} +} diff --git a/vendor/github.com/gin-gonic/gin/render/json.go b/vendor/github.com/gin-gonic/gin/render/json.go new file mode 100644 index 0000000..32e6058 --- /dev/null +++ b/vendor/github.com/gin-gonic/gin/render/json.go @@ -0,0 +1,41 @@ +// Copyright 2014 Manu Martinez-Almeida.  All rights reserved. +// Use of this source code is governed by a MIT style +// license that can be found in the LICENSE file. + +package render + +import ( +	"encoding/json" +	"net/http" +) + +type ( +	JSON struct { +		Data interface{} +	} + +	IndentedJSON struct { +		Data interface{} +	} +) + +var jsonContentType = []string{"application/json; charset=utf-8"} + +func (r JSON) Render(w http.ResponseWriter) error { +	return WriteJSON(w, r.Data) +} + +func (r IndentedJSON) Render(w http.ResponseWriter) error { +	writeContentType(w, jsonContentType) +	jsonBytes, err := json.MarshalIndent(r.Data, "", "    ") +	if err != nil { +		return err +	} +	w.Write(jsonBytes) +	return nil +} + +func WriteJSON(w http.ResponseWriter, obj interface{}) error { +	writeContentType(w, jsonContentType) +	return json.NewEncoder(w).Encode(obj) +} diff --git a/vendor/github.com/gin-gonic/gin/render/redirect.go b/vendor/github.com/gin-gonic/gin/render/redirect.go new file mode 100644 index 0000000..d64e4d7 --- /dev/null +++ b/vendor/github.com/gin-gonic/gin/render/redirect.go @@ -0,0 +1,24 @@ +// Copyright 2014 Manu Martinez-Almeida.  All rights reserved. +// Use of this source code is governed by a MIT style +// license that can be found in the LICENSE file. + +package render + +import ( +	"fmt" +	"net/http" +) + +type Redirect struct { +	Code     int +	Request  *http.Request +	Location string +} + +func (r Redirect) Render(w http.ResponseWriter) error { +	if r.Code < 300 || r.Code > 308 { +		panic(fmt.Sprintf("Cannot redirect with status code %d", r.Code)) +	} +	http.Redirect(w, r.Request, r.Location, r.Code) +	return nil +} diff --git a/vendor/github.com/gin-gonic/gin/render/render.go b/vendor/github.com/gin-gonic/gin/render/render.go new file mode 100644 index 0000000..994fcd7 --- /dev/null +++ b/vendor/github.com/gin-gonic/gin/render/render.go @@ -0,0 +1,30 @@ +// Copyright 2014 Manu Martinez-Almeida.  All rights reserved. +// Use of this source code is governed by a MIT style +// license that can be found in the LICENSE file. + +package render + +import "net/http" + +type Render interface { +	Render(http.ResponseWriter) error +} + +var ( +	_ Render     = JSON{} +	_ Render     = IndentedJSON{} +	_ Render     = XML{} +	_ Render     = String{} +	_ Render     = Redirect{} +	_ Render     = Data{} +	_ Render     = HTML{} +	_ HTMLRender = HTMLDebug{} +	_ HTMLRender = HTMLProduction{} +) + +func writeContentType(w http.ResponseWriter, value []string) { +	header := w.Header() +	if val := header["Content-Type"]; len(val) == 0 { +		header["Content-Type"] = value +	} +} diff --git a/vendor/github.com/gin-gonic/gin/render/text.go b/vendor/github.com/gin-gonic/gin/render/text.go new file mode 100644 index 0000000..5a9e280 --- /dev/null +++ b/vendor/github.com/gin-gonic/gin/render/text.go @@ -0,0 +1,33 @@ +// Copyright 2014 Manu Martinez-Almeida.  All rights reserved. +// Use of this source code is governed by a MIT style +// license that can be found in the LICENSE file. + +package render + +import ( +	"fmt" +	"io" +	"net/http" +) + +type String struct { +	Format string +	Data   []interface{} +} + +var plainContentType = []string{"text/plain; charset=utf-8"} + +func (r String) Render(w http.ResponseWriter) error { +	WriteString(w, r.Format, r.Data) +	return nil +} + +func WriteString(w http.ResponseWriter, format string, data []interface{}) { +	writeContentType(w, plainContentType) + +	if len(data) > 0 { +		fmt.Fprintf(w, format, data...) +	} else { +		io.WriteString(w, format) +	} +} diff --git a/vendor/github.com/gin-gonic/gin/render/xml.go b/vendor/github.com/gin-gonic/gin/render/xml.go new file mode 100644 index 0000000..be22e6f --- /dev/null +++ b/vendor/github.com/gin-gonic/gin/render/xml.go @@ -0,0 +1,21 @@ +// Copyright 2014 Manu Martinez-Almeida.  All rights reserved. +// Use of this source code is governed by a MIT style +// license that can be found in the LICENSE file. + +package render + +import ( +	"encoding/xml" +	"net/http" +) + +type XML struct { +	Data interface{} +} + +var xmlContentType = []string{"application/xml; charset=utf-8"} + +func (r XML) Render(w http.ResponseWriter) error { +	writeContentType(w, xmlContentType) +	return xml.NewEncoder(w).Encode(r.Data) +} diff --git a/vendor/github.com/gin-gonic/gin/response_writer.go b/vendor/github.com/gin-gonic/gin/response_writer.go new file mode 100644 index 0000000..5a75335 --- /dev/null +++ b/vendor/github.com/gin-gonic/gin/response_writer.go @@ -0,0 +1,106 @@ +// Copyright 2014 Manu Martinez-Almeida.  All rights reserved. +// Use of this source code is governed by a MIT style +// license that can be found in the LICENSE file. + +package gin + +import ( +	"bufio" +	"io" +	"net" +	"net/http" +) + +const ( +	noWritten     = -1 +	defaultStatus = 200 +) + +type ( +	ResponseWriter interface { +		http.ResponseWriter +		http.Hijacker +		http.Flusher +		http.CloseNotifier + +		Status() int +		Size() int +		WriteString(string) (int, error) +		Written() bool +		WriteHeaderNow() +	} + +	responseWriter struct { +		http.ResponseWriter +		size   int +		status int +	} +) + +var _ ResponseWriter = &responseWriter{} + +func (w *responseWriter) reset(writer http.ResponseWriter) { +	w.ResponseWriter = writer +	w.size = noWritten +	w.status = defaultStatus +} + +func (w *responseWriter) WriteHeader(code int) { +	if code > 0 && w.status != code { +		if w.Written() { +			debugPrint("[WARNING] Headers were already written. Wanted to override status code %d with %d", w.status, code) +		} +		w.status = code +	} +} + +func (w *responseWriter) WriteHeaderNow() { +	if !w.Written() { +		w.size = 0 +		w.ResponseWriter.WriteHeader(w.status) +	} +} + +func (w *responseWriter) Write(data []byte) (n int, err error) { +	w.WriteHeaderNow() +	n, err = w.ResponseWriter.Write(data) +	w.size += n +	return +} + +func (w *responseWriter) WriteString(s string) (n int, err error) { +	w.WriteHeaderNow() +	n, err = io.WriteString(w.ResponseWriter, s) +	w.size += n +	return +} + +func (w *responseWriter) Status() int { +	return w.status +} + +func (w *responseWriter) Size() int { +	return w.size +} + +func (w *responseWriter) Written() bool { +	return w.size != noWritten +} + +// Implements the http.Hijacker interface +func (w *responseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) { +	if w.size < 0 { +		w.size = 0 +	} +	return w.ResponseWriter.(http.Hijacker).Hijack() +} + +// Implements the http.CloseNotify interface +func (w *responseWriter) CloseNotify() <-chan bool { +	return w.ResponseWriter.(http.CloseNotifier).CloseNotify() +} + +// Implements the http.Flush interface +func (w *responseWriter) Flush() { +	w.ResponseWriter.(http.Flusher).Flush() +} diff --git a/vendor/github.com/gin-gonic/gin/routergroup.go b/vendor/github.com/gin-gonic/gin/routergroup.go new file mode 100644 index 0000000..b77a55b --- /dev/null +++ b/vendor/github.com/gin-gonic/gin/routergroup.go @@ -0,0 +1,207 @@ +// Copyright 2014 Manu Martinez-Almeida.  All rights reserved. +// Use of this source code is governed by a MIT style +// license that can be found in the LICENSE file. + +package gin + +import ( +	"net/http" +	"path" +	"regexp" +	"strings" +) + +type ( +	RoutesInterface interface { +		routesInterface +		Group(string, ...HandlerFunc) *RouterGroup +	} + +	routesInterface interface { +		Use(...HandlerFunc) routesInterface + +		Handle(string, string, ...HandlerFunc) routesInterface +		Any(string, ...HandlerFunc) routesInterface +		GET(string, ...HandlerFunc) routesInterface +		POST(string, ...HandlerFunc) routesInterface +		DELETE(string, ...HandlerFunc) routesInterface +		PATCH(string, ...HandlerFunc) routesInterface +		PUT(string, ...HandlerFunc) routesInterface +		OPTIONS(string, ...HandlerFunc) routesInterface +		HEAD(string, ...HandlerFunc) routesInterface + +		StaticFile(string, string) routesInterface +		Static(string, string) routesInterface +		StaticFS(string, http.FileSystem) routesInterface +	} + +	// Used internally to configure router, a RouterGroup is associated with a prefix +	// and an array of handlers (middlewares) +	RouterGroup struct { +		Handlers HandlersChain +		BasePath string +		engine   *Engine +		root     bool +	} +) + +var _ RoutesInterface = &RouterGroup{} + +// Adds middlewares to the group, see example code in github. +func (group *RouterGroup) Use(middlewares ...HandlerFunc) routesInterface { +	group.Handlers = append(group.Handlers, middlewares...) +	return group.returnObj() +} + +// Creates a new router group. You should add all the routes that have common middlwares or the same path prefix. +// For example, all the routes that use a common middlware for authorization could be grouped. +func (group *RouterGroup) Group(relativePath string, handlers ...HandlerFunc) *RouterGroup { +	return &RouterGroup{ +		Handlers: group.combineHandlers(handlers), +		BasePath: group.calculateAbsolutePath(relativePath), +		engine:   group.engine, +	} +} + +// Handle registers a new request handle and middlewares with the given path and method. +// The last handler should be the real handler, the other ones should be middlewares that can and should be shared among different routes. +// See the example code in github. +// +// For GET, POST, PUT, PATCH and DELETE requests the respective shortcut +// functions can be used. +// +// This function is intended for bulk loading and to allow the usage of less +// frequently used, non-standardized or custom methods (e.g. for internal +// communication with a proxy). +func (group *RouterGroup) handle(httpMethod, relativePath string, handlers HandlersChain) routesInterface { +	absolutePath := group.calculateAbsolutePath(relativePath) +	handlers = group.combineHandlers(handlers) +	group.engine.addRoute(httpMethod, absolutePath, handlers) +	return group.returnObj() +} + +func (group *RouterGroup) Handle(httpMethod, relativePath string, handlers ...HandlerFunc) routesInterface { +	if matches, err := regexp.MatchString("^[A-Z]+$", httpMethod); !matches || err != nil { +		panic("http method " + httpMethod + " is not valid") +	} +	return group.handle(httpMethod, relativePath, handlers) +} + +// POST is a shortcut for router.Handle("POST", path, handle) +func (group *RouterGroup) POST(relativePath string, handlers ...HandlerFunc) routesInterface { +	return group.handle("POST", relativePath, handlers) +} + +// GET is a shortcut for router.Handle("GET", path, handle) +func (group *RouterGroup) GET(relativePath string, handlers ...HandlerFunc) routesInterface { +	return group.handle("GET", relativePath, handlers) +} + +// DELETE is a shortcut for router.Handle("DELETE", path, handle) +func (group *RouterGroup) DELETE(relativePath string, handlers ...HandlerFunc) routesInterface { +	return group.handle("DELETE", relativePath, handlers) +} + +// PATCH is a shortcut for router.Handle("PATCH", path, handle) +func (group *RouterGroup) PATCH(relativePath string, handlers ...HandlerFunc) routesInterface { +	return group.handle("PATCH", relativePath, handlers) +} + +// PUT is a shortcut for router.Handle("PUT", path, handle) +func (group *RouterGroup) PUT(relativePath string, handlers ...HandlerFunc) routesInterface { +	return group.handle("PUT", relativePath, handlers) +} + +// OPTIONS is a shortcut for router.Handle("OPTIONS", path, handle) +func (group *RouterGroup) OPTIONS(relativePath string, handlers ...HandlerFunc) routesInterface { +	return group.handle("OPTIONS", relativePath, handlers) +} + +// HEAD is a shortcut for router.Handle("HEAD", path, handle) +func (group *RouterGroup) HEAD(relativePath string, handlers ...HandlerFunc) routesInterface { +	return group.handle("HEAD", relativePath, handlers) +} + +func (group *RouterGroup) Any(relativePath string, handlers ...HandlerFunc) routesInterface { +	// GET, POST, PUT, PATCH, HEAD, OPTIONS, DELETE, CONNECT, TRACE +	group.handle("GET", relativePath, handlers) +	group.handle("POST", relativePath, handlers) +	group.handle("PUT", relativePath, handlers) +	group.handle("PATCH", relativePath, handlers) +	group.handle("HEAD", relativePath, handlers) +	group.handle("OPTIONS", relativePath, handlers) +	group.handle("DELETE", relativePath, handlers) +	group.handle("CONNECT", relativePath, handlers) +	group.handle("TRACE", relativePath, handlers) +	return group.returnObj() +} + +func (group *RouterGroup) StaticFile(relativePath, filepath string) routesInterface { +	if strings.Contains(relativePath, ":") || strings.Contains(relativePath, "*") { +		panic("URL parameters can not be used when serving a static file") +	} +	handler := func(c *Context) { +		c.File(filepath) +	} +	group.GET(relativePath, handler) +	group.HEAD(relativePath, handler) +	return group.returnObj() +} + +// Static serves files from the given file system root. +// Internally a http.FileServer is used, therefore http.NotFound is used instead +// of the Router's NotFound handler. +// To use the operating system's file system implementation, +// use : +//     router.Static("/static", "/var/www") +func (group *RouterGroup) Static(relativePath, root string) routesInterface { +	return group.StaticFS(relativePath, Dir(root, false)) +} + +func (group *RouterGroup) StaticFS(relativePath string, fs http.FileSystem) routesInterface { +	if strings.Contains(relativePath, ":") || strings.Contains(relativePath, "*") { +		panic("URL parameters can not be used when serving a static folder") +	} +	handler := group.createStaticHandler(relativePath, fs) +	urlPattern := path.Join(relativePath, "/*filepath") + +	// Register GET and HEAD handlers +	group.GET(urlPattern, handler) +	group.HEAD(urlPattern, handler) +	return group.returnObj() +} + +func (group *RouterGroup) createStaticHandler(relativePath string, fs http.FileSystem) HandlerFunc { +	absolutePath := group.calculateAbsolutePath(relativePath) +	fileServer := http.StripPrefix(absolutePath, http.FileServer(fs)) +	_, nolisting := fs.(*onlyfilesFS) +	return func(c *Context) { +		if nolisting { +			c.Writer.WriteHeader(404) +		} +		fileServer.ServeHTTP(c.Writer, c.Request) +	} +} + +func (group *RouterGroup) combineHandlers(handlers HandlersChain) HandlersChain { +	finalSize := len(group.Handlers) + len(handlers) +	if finalSize >= int(AbortIndex) { +		panic("too many handlers") +	} +	mergedHandlers := make(HandlersChain, finalSize) +	copy(mergedHandlers, group.Handlers) +	copy(mergedHandlers[len(group.Handlers):], handlers) +	return mergedHandlers +} + +func (group *RouterGroup) calculateAbsolutePath(relativePath string) string { +	return joinPaths(group.BasePath, relativePath) +} + +func (group *RouterGroup) returnObj() routesInterface { +	if group.root { +		return group.engine +	} else { +		return group +	} +} diff --git a/vendor/github.com/gin-gonic/gin/tree.go b/vendor/github.com/gin-gonic/gin/tree.go new file mode 100644 index 0000000..c87e0d8 --- /dev/null +++ b/vendor/github.com/gin-gonic/gin/tree.go @@ -0,0 +1,596 @@ +// Copyright 2013 Julien Schmidt. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be found +// in the LICENSE file. + +package gin + +import ( +	"strings" +	"unicode" +) + +// Param is a single URL parameter, consisting of a key and a value. +type Param struct { +	Key   string +	Value string +} + +// Params is a Param-slice, as returned by the router. +// The slice is ordered, the first URL parameter is also the first slice value. +// It is therefore safe to read values by the index. +type Params []Param + +// ByName returns the value of the first Param which key matches the given name. +// If no matching Param is found, an empty string is returned. +func (ps Params) Get(name string) (string, bool) { +	for _, entry := range ps { +		if entry.Key == name { +			return entry.Value, true +		} +	} +	return "", false +} + +func (ps Params) ByName(name string) (va string) { +	va, _ = ps.Get(name) +	return +} + +type methodTree struct { +	method string +	root   *node +} + +type methodTrees []methodTree + +func (trees methodTrees) get(method string) *node { +	for _, tree := range trees { +		if tree.method == method { +			return tree.root +		} +	} +	return nil +} + +func min(a, b int) int { +	if a <= b { +		return a +	} +	return b +} + +func countParams(path string) uint8 { +	var n uint +	for i := 0; i < len(path); i++ { +		if path[i] != ':' && path[i] != '*' { +			continue +		} +		n++ +	} +	if n >= 255 { +		return 255 +	} +	return uint8(n) +} + +type nodeType uint8 + +const ( +	static   nodeType = 0 +	param    nodeType = 1 +	catchAll nodeType = 2 +) + +type node struct { +	path      string +	wildChild bool +	nType     nodeType +	maxParams uint8 +	indices   string +	children  []*node +	handlers  HandlersChain +	priority  uint32 +} + +// increments priority of the given child and reorders if necessary +func (n *node) incrementChildPrio(pos int) int { +	n.children[pos].priority++ +	prio := n.children[pos].priority + +	// adjust position (move to front) +	newPos := pos +	for newPos > 0 && n.children[newPos-1].priority < prio { +		// swap node positions +		tmpN := n.children[newPos-1] +		n.children[newPos-1] = n.children[newPos] +		n.children[newPos] = tmpN + +		newPos-- +	} + +	// build new index char string +	if newPos != pos { +		n.indices = n.indices[:newPos] + // unchanged prefix, might be empty +			n.indices[pos:pos+1] + // the index char we move +			n.indices[newPos:pos] + n.indices[pos+1:] // rest without char at 'pos' +	} + +	return newPos +} + +// addRoute adds a node with the given handle to the path. +// Not concurrency-safe! +func (n *node) addRoute(path string, handlers HandlersChain) { +	fullPath := path +	n.priority++ +	numParams := countParams(path) + +	// non-empty tree +	if len(n.path) > 0 || len(n.children) > 0 { +	walk: +		for { +			// Update maxParams of the current node +			if numParams > n.maxParams { +				n.maxParams = numParams +			} + +			// Find the longest common prefix. +			// This also implies that the common prefix contains no ':' or '*' +			// since the existing key can't contain those chars. +			i := 0 +			max := min(len(path), len(n.path)) +			for i < max && path[i] == n.path[i] { +				i++ +			} + +			// Split edge +			if i < len(n.path) { +				child := node{ +					path:      n.path[i:], +					wildChild: n.wildChild, +					indices:   n.indices, +					children:  n.children, +					handlers:  n.handlers, +					priority:  n.priority - 1, +				} + +				// Update maxParams (max of all children) +				for i := range child.children { +					if child.children[i].maxParams > child.maxParams { +						child.maxParams = child.children[i].maxParams +					} +				} + +				n.children = []*node{&child} +				// []byte for proper unicode char conversion, see #65 +				n.indices = string([]byte{n.path[i]}) +				n.path = path[:i] +				n.handlers = nil +				n.wildChild = false +			} + +			// Make new node a child of this node +			if i < len(path) { +				path = path[i:] + +				if n.wildChild { +					n = n.children[0] +					n.priority++ + +					// Update maxParams of the child node +					if numParams > n.maxParams { +						n.maxParams = numParams +					} +					numParams-- + +					// Check if the wildcard matches +					if len(path) >= len(n.path) && n.path == path[:len(n.path)] { +						// check for longer wildcard, e.g. :name and :names +						if len(n.path) >= len(path) || path[len(n.path)] == '/' { +							continue walk +						} +					} + +					panic("path segment '" + path + +						"' conflicts with existing wildcard '" + n.path + +						"' in path '" + fullPath + "'") +				} + +				c := path[0] + +				// slash after param +				if n.nType == param && c == '/' && len(n.children) == 1 { +					n = n.children[0] +					n.priority++ +					continue walk +				} + +				// Check if a child with the next path byte exists +				for i := 0; i < len(n.indices); i++ { +					if c == n.indices[i] { +						i = n.incrementChildPrio(i) +						n = n.children[i] +						continue walk +					} +				} + +				// Otherwise insert it +				if c != ':' && c != '*' { +					// []byte for proper unicode char conversion, see #65 +					n.indices += string([]byte{c}) +					child := &node{ +						maxParams: numParams, +					} +					n.children = append(n.children, child) +					n.incrementChildPrio(len(n.indices) - 1) +					n = child +				} +				n.insertChild(numParams, path, fullPath, handlers) +				return + +			} else if i == len(path) { // Make node a (in-path) leaf +				if n.handlers != nil { +					panic("handlers are already registered for path ''" + fullPath + "'") +				} +				n.handlers = handlers +			} +			return +		} +	} else { // Empty tree +		n.insertChild(numParams, path, fullPath, handlers) +	} +} + +func (n *node) insertChild(numParams uint8, path string, fullPath string, handlers HandlersChain) { +	var offset int // already handled bytes of the path + +	// find prefix until first wildcard (beginning with ':'' or '*'') +	for i, max := 0, len(path); numParams > 0; i++ { +		c := path[i] +		if c != ':' && c != '*' { +			continue +		} + +		// find wildcard end (either '/' or path end) +		end := i + 1 +		for end < max && path[end] != '/' { +			switch path[end] { +			// the wildcard name must not contain ':' and '*' +			case ':', '*': +				panic("only one wildcard per path segment is allowed, has: '" + +					path[i:] + "' in path '" + fullPath + "'") +			default: +				end++ +			} +		} + +		// check if this Node existing children which would be +		// unreachable if we insert the wildcard here +		if len(n.children) > 0 { +			panic("wildcard route '" + path[i:end] + +				"' conflicts with existing children in path '" + fullPath + "'") +		} + +		// check if the wildcard has a name +		if end-i < 2 { +			panic("wildcards must be named with a non-empty name in path '" + fullPath + "'") +		} + +		if c == ':' { // param +			// split path at the beginning of the wildcard +			if i > 0 { +				n.path = path[offset:i] +				offset = i +			} + +			child := &node{ +				nType:     param, +				maxParams: numParams, +			} +			n.children = []*node{child} +			n.wildChild = true +			n = child +			n.priority++ +			numParams-- + +			// if the path doesn't end with the wildcard, then there +			// will be another non-wildcard subpath starting with '/' +			if end < max { +				n.path = path[offset:end] +				offset = end + +				child := &node{ +					maxParams: numParams, +					priority:  1, +				} +				n.children = []*node{child} +				n = child +			} + +		} else { // catchAll +			if end != max || numParams > 1 { +				panic("catch-all routes are only allowed at the end of the path in path '" + fullPath + "'") +			} + +			if len(n.path) > 0 && n.path[len(n.path)-1] == '/' { +				panic("catch-all conflicts with existing handle for the path segment root in path '" + fullPath + "'") +			} + +			// currently fixed width 1 for '/' +			i-- +			if path[i] != '/' { +				panic("no / before catch-all in path '" + fullPath + "'") +			} + +			n.path = path[offset:i] + +			// first node: catchAll node with empty path +			child := &node{ +				wildChild: true, +				nType:     catchAll, +				maxParams: 1, +			} +			n.children = []*node{child} +			n.indices = string(path[i]) +			n = child +			n.priority++ + +			// second node: node holding the variable +			child = &node{ +				path:      path[i:], +				nType:     catchAll, +				maxParams: 1, +				handlers:  handlers, +				priority:  1, +			} +			n.children = []*node{child} + +			return +		} +	} + +	// insert remaining path part and handle to the leaf +	n.path = path[offset:] +	n.handlers = handlers +} + +// Returns the handle registered with the given path (key). The values of +// wildcards are saved to a map. +// If no handle can be found, a TSR (trailing slash redirect) recommendation is +// made if a handle exists with an extra (without the) trailing slash for the +// given path. +func (n *node) getValue(path string, po Params) (handlers HandlersChain, p Params, tsr bool) { +	p = po +walk: // Outer loop for walking the tree +	for { +		if len(path) > len(n.path) { +			if path[:len(n.path)] == n.path { +				path = path[len(n.path):] +				// If this node does not have a wildcard (param or catchAll) +				// child,  we can just look up the next child node and continue +				// to walk down the tree +				if !n.wildChild { +					c := path[0] +					for i := 0; i < len(n.indices); i++ { +						if c == n.indices[i] { +							n = n.children[i] +							continue walk +						} +					} + +					// Nothing found. +					// We can recommend to redirect to the same URL without a +					// trailing slash if a leaf exists for that path. +					tsr = (path == "/" && n.handlers != nil) +					return +				} + +				// handle wildcard child +				n = n.children[0] +				switch n.nType { +				case param: +					// find param end (either '/' or path end) +					end := 0 +					for end < len(path) && path[end] != '/' { +						end++ +					} + +					// save param value +					if cap(p) < int(n.maxParams) { +						p = make(Params, 0, n.maxParams) +					} +					i := len(p) +					p = p[:i+1] // expand slice within preallocated capacity +					p[i].Key = n.path[1:] +					p[i].Value = path[:end] + +					// we need to go deeper! +					if end < len(path) { +						if len(n.children) > 0 { +							path = path[end:] +							n = n.children[0] +							continue walk +						} + +						// ... but we can't +						tsr = (len(path) == end+1) +						return +					} + +					if handlers = n.handlers; handlers != nil { +						return +					} else if len(n.children) == 1 { +						// No handle found. Check if a handle for this path + a +						// trailing slash exists for TSR recommendation +						n = n.children[0] +						tsr = (n.path == "/" && n.handlers != nil) +					} + +					return + +				case catchAll: +					// save param value +					if cap(p) < int(n.maxParams) { +						p = make(Params, 0, n.maxParams) +					} +					i := len(p) +					p = p[:i+1] // expand slice within preallocated capacity +					p[i].Key = n.path[2:] +					p[i].Value = path + +					handlers = n.handlers +					return + +				default: +					panic("invalid node type") +				} +			} +		} else if path == n.path { +			// We should have reached the node containing the handle. +			// Check if this node has a handle registered. +			if handlers = n.handlers; handlers != nil { +				return +			} + +			// No handle found. Check if a handle for this path + a +			// trailing slash exists for trailing slash recommendation +			for i := 0; i < len(n.indices); i++ { +				if n.indices[i] == '/' { +					n = n.children[i] +					tsr = (len(n.path) == 1 && n.handlers != nil) || +						(n.nType == catchAll && n.children[0].handlers != nil) +					return +				} +			} + +			return +		} + +		// Nothing found. We can recommend to redirect to the same URL with an +		// extra trailing slash if a leaf exists for that path +		tsr = (path == "/") || +			(len(n.path) == len(path)+1 && n.path[len(path)] == '/' && +				path == n.path[:len(n.path)-1] && n.handlers != nil) +		return +	} +} + +// Makes a case-insensitive lookup of the given path and tries to find a handler. +// It can optionally also fix trailing slashes. +// It returns the case-corrected path and a bool indicating whether the lookup +// was successful. +func (n *node) findCaseInsensitivePath(path string, fixTrailingSlash bool) (ciPath []byte, found bool) { +	ciPath = make([]byte, 0, len(path)+1) // preallocate enough memory + +	// Outer loop for walking the tree +	for len(path) >= len(n.path) && strings.ToLower(path[:len(n.path)]) == strings.ToLower(n.path) { +		path = path[len(n.path):] +		ciPath = append(ciPath, n.path...) + +		if len(path) > 0 { +			// If this node does not have a wildcard (param or catchAll) child, +			// we can just look up the next child node and continue to walk down +			// the tree +			if !n.wildChild { +				r := unicode.ToLower(rune(path[0])) +				for i, index := range n.indices { +					// must use recursive approach since both index and +					// ToLower(index) could exist. We must check both. +					if r == unicode.ToLower(index) { +						out, found := n.children[i].findCaseInsensitivePath(path, fixTrailingSlash) +						if found { +							return append(ciPath, out...), true +						} +					} +				} + +				// Nothing found. We can recommend to redirect to the same URL +				// without a trailing slash if a leaf exists for that path +				found = (fixTrailingSlash && path == "/" && n.handlers != nil) +				return +			} + +			n = n.children[0] +			switch n.nType { +			case param: +				// find param end (either '/' or path end) +				k := 0 +				for k < len(path) && path[k] != '/' { +					k++ +				} + +				// add param value to case insensitive path +				ciPath = append(ciPath, path[:k]...) + +				// we need to go deeper! +				if k < len(path) { +					if len(n.children) > 0 { +						path = path[k:] +						n = n.children[0] +						continue +					} + +					// ... but we can't +					if fixTrailingSlash && len(path) == k+1 { +						return ciPath, true +					} +					return +				} + +				if n.handlers != nil { +					return ciPath, true +				} else if fixTrailingSlash && len(n.children) == 1 { +					// No handle found. Check if a handle for this path + a +					// trailing slash exists +					n = n.children[0] +					if n.path == "/" && n.handlers != nil { +						return append(ciPath, '/'), true +					} +				} +				return + +			case catchAll: +				return append(ciPath, path...), true + +			default: +				panic("invalid node type") +			} +		} else { +			// We should have reached the node containing the handle. +			// Check if this node has a handle registered. +			if n.handlers != nil { +				return ciPath, true +			} + +			// No handle found. +			// Try to fix the path by adding a trailing slash +			if fixTrailingSlash { +				for i := 0; i < len(n.indices); i++ { +					if n.indices[i] == '/' { +						n = n.children[i] +						if (len(n.path) == 1 && n.handlers != nil) || +							(n.nType == catchAll && n.children[0].handlers != nil) { +							return append(ciPath, '/'), true +						} +						return +					} +				} +			} +			return +		} +	} + +	// Nothing found. +	// Try to fix the path by adding / removing a trailing slash +	if fixTrailingSlash { +		if path == "/" { +			return ciPath, true +		} +		if len(path)+1 == len(n.path) && n.path[len(path)] == '/' && +			strings.ToLower(path) == strings.ToLower(n.path[:len(path)]) && +			n.handlers != nil { +			return append(ciPath, n.path...), true +		} +	} +	return +} diff --git a/vendor/github.com/gin-gonic/gin/utils.go b/vendor/github.com/gin-gonic/gin/utils.go new file mode 100644 index 0000000..7e64687 --- /dev/null +++ b/vendor/github.com/gin-gonic/gin/utils.go @@ -0,0 +1,131 @@ +// Copyright 2014 Manu Martinez-Almeida.  All rights reserved. +// Use of this source code is governed by a MIT style +// license that can be found in the LICENSE file. + +package gin + +import ( +	"encoding/xml" +	"net/http" +	"path" +	"reflect" +	"runtime" +	"strings" +) + +const BindKey = "_gin-gonic/gin/bindkey" + +func Bind(val interface{}) HandlerFunc { +	value := reflect.ValueOf(val) +	if value.Kind() == reflect.Ptr { +		panic(`Bind struct can not be a pointer. Example: +	Use: gin.Bind(Struct{}) instead of gin.Bind(&Struct{}) +`) +	} +	typ := value.Type() + +	return func(c *Context) { +		obj := reflect.New(typ).Interface() +		if c.Bind(obj) == nil { +			c.Set(BindKey, obj) +		} +	} +} + +func WrapF(f http.HandlerFunc) HandlerFunc { +	return func(c *Context) { +		f(c.Writer, c.Request) +	} +} + +func WrapH(h http.Handler) HandlerFunc { +	return func(c *Context) { +		h.ServeHTTP(c.Writer, c.Request) +	} +} + +type H map[string]interface{} + +// Allows type H to be used with xml.Marshal +func (h H) MarshalXML(e *xml.Encoder, start xml.StartElement) error { +	start.Name = xml.Name{ +		Space: "", +		Local: "map", +	} +	if err := e.EncodeToken(start); err != nil { +		return err +	} +	for key, value := range h { +		elem := xml.StartElement{ +			Name: xml.Name{Space: "", Local: key}, +			Attr: []xml.Attr{}, +		} +		if err := e.EncodeElement(value, elem); err != nil { +			return err +		} +	} +	if err := e.EncodeToken(xml.EndElement{Name: start.Name}); err != nil { +		return err +	} +	return nil +} + +func filterFlags(content string) string { +	for i, char := range content { +		if char == ' ' || char == ';' { +			return content[:i] +		} +	} +	return content +} + +func chooseData(custom, wildcard interface{}) interface{} { +	if custom == nil { +		if wildcard == nil { +			panic("negotiation config is invalid") +		} +		return wildcard +	} +	return custom +} + +func parseAccept(acceptHeader string) []string { +	parts := strings.Split(acceptHeader, ",") +	out := make([]string, 0, len(parts)) +	for _, part := range parts { +		index := strings.IndexByte(part, ';') +		if index >= 0 { +			part = part[0:index] +		} +		part = strings.TrimSpace(part) +		if len(part) > 0 { +			out = append(out, part) +		} +	} +	return out +} + +func lastChar(str string) uint8 { +	size := len(str) +	if size == 0 { +		panic("The length of the string can't be 0") +	} +	return str[size-1] +} + +func nameOfFunction(f interface{}) string { +	return runtime.FuncForPC(reflect.ValueOf(f).Pointer()).Name() +} + +func joinPaths(absolutePath, relativePath string) string { +	if len(relativePath) == 0 { +		return absolutePath +	} + +	finalPath := path.Join(absolutePath, relativePath) +	appendSlash := lastChar(relativePath) == '/' && lastChar(finalPath) != '/' +	if appendSlash { +		return finalPath + "/" +	} +	return finalPath +} diff --git a/vendor/github.com/gin-gonic/gin/wercker.yml b/vendor/github.com/gin-gonic/gin/wercker.yml new file mode 100644 index 0000000..3ab8084 --- /dev/null +++ b/vendor/github.com/gin-gonic/gin/wercker.yml @@ -0,0 +1 @@ +box: wercker/default
\ No newline at end of file |