diff --git a/custom/conf/app.ini.sample b/custom/conf/app.ini.sample index f25ef8b8f..f166912aa 100755 --- a/custom/conf/app.ini.sample +++ b/custom/conf/app.ini.sample @@ -1049,6 +1049,9 @@ RESULT_BACKEND = redis://localhost:6379 HOST = http://192.168.204.24 USERNAME = PASSWORD = +; cloudbrain visit opendata +USER = cW4cMtH24eoWPE7X +PWD = 4BPmgvK2hb2Eywwyp4YZRY4B7yQf4DAC [decompress] HOST = http://192.168.207.34:39987 diff --git a/go.mod b/go.mod old mode 100755 new mode 100644 index 684fcf879..e74bdf513 --- a/go.mod +++ b/go.mod @@ -42,6 +42,7 @@ require ( github.com/go-git/go-billy/v5 v5.0.0 github.com/go-git/go-git/v5 v5.0.0 github.com/go-ini/ini v1.56.0 // indirect + github.com/go-macaron/auth v0.0.0-20161228062157-884c0e6c9b92 github.com/go-openapi/jsonreference v0.19.3 // indirect github.com/go-redis/redis v6.15.2+incompatible github.com/go-resty/resty/v2 v2.3.0 @@ -121,6 +122,7 @@ require ( gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df gopkg.in/ini.v1 v1.52.0 gopkg.in/ldap.v3 v3.0.2 + gopkg.in/macaron.v1 v1.3.9 // indirect gopkg.in/testfixtures.v2 v2.5.0 gopkg.in/yaml.v2 v2.2.8 mvdan.cc/xurls/v2 v2.1.0 diff --git a/go.sum b/go.sum old mode 100755 new mode 100644 index 7ed818a6a..35b7cd295 --- a/go.sum +++ b/go.sum @@ -234,6 +234,10 @@ github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2 github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= +github.com/go-macaron/auth v0.0.0-20161228062157-884c0e6c9b92 h1:71YL0o1ch/APk7bmW9jWKBY7ibd9U8NQX2bQ25EJMHI= +github.com/go-macaron/auth v0.0.0-20161228062157-884c0e6c9b92/go.mod h1:saPJfEeea+kiiZJF4GG7TSOao0T/Yrm5rpsqYglss6k= +github.com/go-macaron/inject v0.0.0-20160627170012-d8a0b8677191 h1:NjHlg70DuOkcAMqgt0+XA+NHwtu66MkTVVgR4fFWbcI= +github.com/go-macaron/inject v0.0.0-20160627170012-d8a0b8677191/go.mod h1:VFI2o2q9kYsC4o7VP1HrEVosiZZTd+MVT3YZx4gqvJw= github.com/go-openapi/analysis v0.0.0-20180825180245-b006789cd277/go.mod h1:k70tL6pCuVxPJOHXQ+wIac1FUrvNkHolPie/cLEU6hI= github.com/go-openapi/analysis v0.17.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik= github.com/go-openapi/analysis v0.18.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik= @@ -1032,6 +1036,8 @@ gopkg.in/ini.v1 v1.52.0 h1:j+Lt/M1oPPejkniCg1TkWE2J3Eh1oZTsHSXzMTzUXn4= gopkg.in/ini.v1 v1.52.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ldap.v3 v3.0.2 h1:R6RBtabK6e1GO0eQKtkyOFbAHO73QesLzI2w2DZ6b9w= gopkg.in/ldap.v3 v3.0.2/go.mod h1:oxD7NyBuxchC+SgJDE1Q5Od05eGt29SDQVBmV+HYbzw= +gopkg.in/macaron.v1 v1.3.9 h1:Dw+DDRYdXgQyEsPlfAfKz+UA5qVUrH3KPD7JhmZ9MFc= +gopkg.in/macaron.v1 v1.3.9/go.mod h1:uMZCFccv9yr5TipIalVOyAyZQuOH3OkmXvgcWwhJuP4= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/testfixtures.v2 v2.5.0 h1:N08B7l2GzFQenyYbzqthDnKAA+cmb17iAZhhFxr7JHw= diff --git a/models/attachment.go b/models/attachment.go index afb2bbe16..be0507d37 100755 --- a/models/attachment.go +++ b/models/attachment.go @@ -346,3 +346,12 @@ func getUnDecompressAttachments(e Engine) ([]*Attachment, error) { attachments := make([]*Attachment, 0, 10) return attachments, e.Where("decompress_state = ? and dataset_id != 0 and name like '%.zip'", DecompressStateInit).Find(&attachments) } + +func GetAllPublicAttachments() ([]*Attachment, error) { + return getAllPublicAttachments(x) +} + +func getAllPublicAttachments(e Engine) ([]*Attachment, error) { + attachments := make([]*Attachment, 0, 10) + return attachments, e.Where("is_private = true ").Find(&attachments) +} diff --git a/modules/context/auth.go b/modules/context/auth.go old mode 100644 new mode 100755 index 7410db75a..34b74523d --- a/modules/context/auth.go +++ b/modules/context/auth.go @@ -10,9 +10,13 @@ import ( "code.gitea.io/gitea/modules/auth" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" + "encoding/base64" + "net/http" "gitea.com/macaron/csrf" "gitea.com/macaron/macaron" + + marc_auth "github.com/go-macaron/auth" ) // ToggleOptions contains required or check options @@ -21,6 +25,7 @@ type ToggleOptions struct { SignOutRequired bool AdminRequired bool DisableCSRF bool + BasicAuthRequired bool } // Toggle returns toggle options as middleware @@ -130,5 +135,29 @@ func Toggle(options *ToggleOptions) macaron.Handler { } ctx.Data["PageIsAdmin"] = true } + + if options.BasicAuthRequired { + if !basicAuth(ctx) { + basicUnauthorized(ctx.Resp) + return + } + } } } + +func basicAuth(ctx *Context) bool { + var siteAuth = base64.StdEncoding.EncodeToString([]byte(setting.CBAuthUser + ":" + setting.CBAuthPassword)) + auth := ctx.Req.Header.Get("Authorization") + + if !marc_auth.SecureCompare(auth, "Basic " + siteAuth) { + return false + } + + return true + +} + +func basicUnauthorized(res http.ResponseWriter) { + res.Header().Set("WWW-Authenticate", "Basic realm=\"" + marc_auth.BasicRealm + "\"") + http.Error(res, "Not Authorized", http.StatusUnauthorized) +} diff --git a/modules/setting/setting.go b/modules/setting/setting.go index d103fb796..a1b72594e 100755 --- a/modules/setting/setting.go +++ b/modules/setting/setting.go @@ -430,6 +430,10 @@ var ( DecompressAddress string AuthUser string AuthPassword string + + //cloudbrain config + CBAuthUser string + CBAuthPassword string ) // DateLang transforms standard language locale name to corresponding value in datetime plugin. @@ -1097,6 +1101,10 @@ func NewContext() { DecompressAddress = sec.Key("HOST").MustString("http://192.168.207.34:39987") AuthUser = sec.Key("USER").MustString("cW4cMtH24eoWPE7X") AuthPassword = sec.Key("PASSWORD").MustString("4BPmgvK2hb2Eywwyp4YZRY4B7yQf4DAC") + + sec = Cfg.Section("cloudbrain") + CBAuthUser = sec.Key("USER").MustString("cW4cMtH24eoWPE7X") + CBAuthPassword = sec.Key("PWD").MustString("4BPmgvK2hb2Eywwyp4YZRY4B7yQf4DAC") } func loadInternalToken(sec *ini.Section) string { diff --git a/routers/repo/attachment.go b/routers/repo/attachment.go index 71446f1d4..c500a8867 100755 --- a/routers/repo/attachment.go +++ b/routers/repo/attachment.go @@ -6,6 +6,7 @@ package repo import ( contexExt "context" + "encoding/json" "fmt" "net/http" "strconv" @@ -29,6 +30,11 @@ const ( DecompressFailed = "1" ) +type PublicDataset struct { + Name string `json:"name"` + Path string `json:"path"` +} + func RenderAttachmentSettings(ctx *context.Context) { renderAttachmentSettings(ctx) } @@ -374,7 +380,7 @@ func GetSuccessChunks(ctx *context.Context) { chunks, err = storage.GetPartInfos(fileChunk.UUID, fileChunk.UploadID) if err != nil { - ctx.ServerError("json.Marshal failed", err) + ctx.ServerError("GetPartInfos failed", err) return } } @@ -601,3 +607,39 @@ func HandleUnDecompressAttachment() { return } + +func QueryAllPublicDataset(ctx *context.Context){ + log.Info("QueryAllPublicDataset") + + attachs, err := models.GetAllPublicAttachments() + if err != nil { + ctx.JSON(200, map[string]string{ + "result_code": "-1", + "data": "", + }) + return + } + + var publicDatasets []PublicDataset + for _, attch := range attachs { + publicDatasets = append(publicDatasets, PublicDataset{attch.Name, + models.AttachmentRelativePath(attch.UUID)}) + } + + data,err := json.Marshal(publicDatasets) + if err != nil { + log.Error("json.Marshal failed:", err.Error()) + ctx.JSON(200, map[string]string{ + "result_code": "-1", + "data": "", + }) + return + } + + log.Info(string(data)) + + ctx.JSON(200, map[string]string{ + "result_code": "0", + "data": string(data), + }) +} diff --git a/routers/routes/routes.go b/routers/routes/routes.go index 0ef12c581..5d6e015f1 100755 --- a/routers/routes/routes.go +++ b/routers/routes/routes.go @@ -245,6 +245,7 @@ func RegisterRoutes(m *macaron.Macaron) { ignSignIn := context.Toggle(&context.ToggleOptions{SignInRequired: setting.Service.RequireSignInView}) ignSignInAndCsrf := context.Toggle(&context.ToggleOptions{DisableCSRF: true}) reqSignOut := context.Toggle(&context.ToggleOptions{SignOutRequired: true}) + reqBasicAuth := context.Toggle(&context.ToggleOptions{BasicAuthRequired:true}) bindIgnErr := binding.BindIgnErr validation.AddBindingRules() @@ -533,6 +534,10 @@ func RegisterRoutes(m *macaron.Macaron) { m.Post("/decompress_done_notify", repo.UpdateAttachmentDecompressState) }) + m.Group("/attachments/public", func() { + m.Get("/query", repo.QueryAllPublicDataset) + }, reqBasicAuth) + m.Group("/:username", func() { m.Post("/action/:action", user.Action) }, reqSignIn) diff --git a/vendor/github.com/go-macaron/auth/LICENSE b/vendor/github.com/go-macaron/auth/LICENSE new file mode 100644 index 000000000..eb68a0e05 --- /dev/null +++ b/vendor/github.com/go-macaron/auth/LICENSE @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) 2013 Jeremy Saenz + +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/go-macaron/auth/README.md b/vendor/github.com/go-macaron/auth/README.md new file mode 100644 index 000000000..da39231a5 --- /dev/null +++ b/vendor/github.com/go-macaron/auth/README.md @@ -0,0 +1,68 @@ +# auth +Macaron middleware/handler for http basic authentication. Modified from + +[API Reference](http://godoc.org/github.com/go-macaron/auth) + +## Simple Usage + +Use `auth.Basic` to authenticate against a pre-defined username and password: + +~~~ go +import ( + "gopkg.in/macaron.v1" + "github.com/go-macaron/auth" +) + +func main() { + m := macaron.Classic() + // authenticate every request + m.Use(auth.Basic("username", "secretpassword")) + m.Run() +} +~~~ + +## Advanced Usage + +Using `auth.BasicFunc` lets you authenticate on a per-user level, by checking +the username and password in the callback function: + +~~~ go +import ( + "gopkg.in/macaron.v1" + "github.com/go-macaron/auth" +) + +func main() { + m := macaron.Classic() + // authenticate every request + m.Use(auth.BasicFunc(func(username, password string) bool { + return username == "admin" && password == "guessme" + })) + m.Run() +} +~~~ + +Note that checking usernames and passwords with string comparison might be +susceptible to timing attacks. To avoid that, use `auth.SecureCompare` instead: + +~~~ go + m.Use(auth.BasicFunc(func(username, password string) bool { + return auth.SecureCompare(username, "admin") && auth.SecureCompare(password, "guessme") + })) +} +~~~ + +Upon successful authentication, the username is available to all subsequent +handlers via the `auth.User` type: + +~~~ go + m.Get("/", func(user auth.User) string { + return "Welcome, " + string(user) + }) +} +~~~ + +## Authors +* [Jeremy Saenz](https://github.com/codegangsta) +* [Brendon Murphy](https://github.com/bemurphy) +* [codeskyblue](https://github.com/codeskyblue) diff --git a/vendor/github.com/go-macaron/auth/basic.go b/vendor/github.com/go-macaron/auth/basic.go new file mode 100644 index 000000000..3516d8a36 --- /dev/null +++ b/vendor/github.com/go-macaron/auth/basic.go @@ -0,0 +1,59 @@ +package auth + +import ( + "encoding/base64" + "net/http" + "strings" + + "gopkg.in/macaron.v1" +) + +// User is the authenticated username that was extracted from the request. +type User string + +// BasicRealm is used when setting the WWW-Authenticate response header. +var BasicRealm = "Authorization Required" +var basicPrefix = "Basic " + +// Basic returns a Handler that authenticates via Basic Auth. Writes a http.StatusUnauthorized +// if authentication fails. +func Basic(username string, password string) macaron.Handler { + var siteAuth = base64.StdEncoding.EncodeToString([]byte(username + ":" + password)) + return func(res http.ResponseWriter, req *http.Request, c *macaron.Context) { + auth := req.Header.Get("Authorization") + if !SecureCompare(auth, basicPrefix+siteAuth) { + basicUnauthorized(res) + return + } + c.Map(User(username)) + } +} + +// BasicFunc returns a Handler that authenticates via Basic Auth using the provided function. +// The function should return true for a valid username/password combination. +func BasicFunc(authfn func(string, string) bool) macaron.Handler { + return func(res http.ResponseWriter, req *http.Request, c *macaron.Context) { + auth := req.Header.Get("Authorization") + n := len(basicPrefix) + if len(auth) < n || auth[:n] != basicPrefix { + basicUnauthorized(res) + return + } + b, err := base64.StdEncoding.DecodeString(auth[n:]) + if err != nil { + basicUnauthorized(res) + return + } + tokens := strings.SplitN(string(b), ":", 2) + if len(tokens) != 2 || !authfn(tokens[0], tokens[1]) { + basicUnauthorized(res) + return + } + c.Map(User(tokens[0])) + } +} + +func basicUnauthorized(res http.ResponseWriter) { + res.Header().Set("WWW-Authenticate", "Basic realm=\""+BasicRealm+"\"") + http.Error(res, "Not Authorized", http.StatusUnauthorized) +} diff --git a/vendor/github.com/go-macaron/auth/bearer.go b/vendor/github.com/go-macaron/auth/bearer.go new file mode 100644 index 000000000..5415ddfd4 --- /dev/null +++ b/vendor/github.com/go-macaron/auth/bearer.go @@ -0,0 +1,44 @@ +package auth + +import ( + "net/http" + + "gopkg.in/macaron.v1" +) + +var bearerPrefix = "Bearer " + +// Bearer returns a Handler that authenticates via Bearer Auth. Writes a http.StatusUnauthorized +// if authentication fails. +func Bearer(token string) macaron.Handler { + return func(res http.ResponseWriter, req *http.Request, c *macaron.Context) { + auth := req.Header.Get("Authorization") + if !SecureCompare(auth, bearerPrefix+token) { + bearerUnauthorized(res) + return + } + c.Map(User("")) + } +} + +// BearerFunc returns a Handler that authenticates via Bearer Auth using the provided function. +// The function should return true for a valid bearer token. +func BearerFunc(authfn func(string) bool) macaron.Handler { + return func(res http.ResponseWriter, req *http.Request, c *macaron.Context) { + auth := req.Header.Get("Authorization") + n := len(bearerPrefix) + if len(auth) < n || auth[:n] != bearerPrefix { + bearerUnauthorized(res) + return + } + if !authfn(auth[n:]) { + bearerUnauthorized(res) + return + } + c.Map(User("")) + } +} + +func bearerUnauthorized(res http.ResponseWriter) { + http.Error(res, "Not Authorized", http.StatusUnauthorized) +} diff --git a/vendor/github.com/go-macaron/auth/util.go b/vendor/github.com/go-macaron/auth/util.go new file mode 100644 index 000000000..9ee606cc4 --- /dev/null +++ b/vendor/github.com/go-macaron/auth/util.go @@ -0,0 +1,14 @@ +package auth + +import ( + "crypto/sha512" + "crypto/subtle" +) + +// SecureCompare performs a constant time compare of two strings to limit timing attacks. +func SecureCompare(given string, actual string) bool { + givenSha := sha512.Sum512([]byte(given)) + actualSha := sha512.Sum512([]byte(actual)) + + return subtle.ConstantTimeCompare(givenSha[:], actualSha[:]) == 1 +} diff --git a/vendor/github.com/go-macaron/auth/wercker.yml b/vendor/github.com/go-macaron/auth/wercker.yml new file mode 100644 index 000000000..f8bf918a8 --- /dev/null +++ b/vendor/github.com/go-macaron/auth/wercker.yml @@ -0,0 +1 @@ +box: wercker/golang@1.1.1 \ No newline at end of file diff --git a/vendor/github.com/go-macaron/inject/.travis.yml b/vendor/github.com/go-macaron/inject/.travis.yml new file mode 100644 index 000000000..2774fb35d --- /dev/null +++ b/vendor/github.com/go-macaron/inject/.travis.yml @@ -0,0 +1,14 @@ +sudo: false +language: go + +go: + - 1.3 + - 1.4 + - 1.5 + - tip + +script: go test -v -cover -race + +notifications: + email: + - u@gogs.io diff --git a/vendor/github.com/go-macaron/inject/LICENSE b/vendor/github.com/go-macaron/inject/LICENSE new file mode 100644 index 000000000..37ec93a14 --- /dev/null +++ b/vendor/github.com/go-macaron/inject/LICENSE @@ -0,0 +1,191 @@ +Apache License +Version 2.0, January 2004 +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and +distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright +owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities +that control, are controlled by, or are under common control with that entity. +For the purposes of this definition, "control" means (i) the power, direct or +indirect, to cause the direction or management of such entity, whether by +contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the +outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising +permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including +but not limited to software source code, documentation source, and configuration +files. + +"Object" form shall mean any form resulting from mechanical transformation or +translation of a Source form, including but not limited to compiled object code, +generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made +available under the License, as indicated by a copyright notice that is included +in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that +is based on (or derived from) the Work and for which the editorial revisions, +annotations, elaborations, or other modifications represent, as a whole, an +original work of authorship. For the purposes of this License, Derivative Works +shall not include works that remain separable from, or merely link (or bind by +name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version +of the Work and any modifications or additions to that Work or Derivative Works +thereof, that is intentionally submitted to Licensor for inclusion in the Work +by the copyright owner or by an individual or Legal Entity authorized to submit +on behalf of the copyright owner. For the purposes of this definition, +"submitted" means any form of electronic, verbal, or written communication sent +to the Licensor or its representatives, including but not limited to +communication on electronic mailing lists, source code control systems, and +issue tracking systems that are managed by, or on behalf of, the Licensor for +the purpose of discussing and improving the Work, but excluding communication +that is conspicuously marked or otherwise designated in writing by the copyright +owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf +of whom a Contribution has been received by Licensor and subsequently +incorporated within the Work. + +2. Grant of Copyright License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable copyright license to reproduce, prepare Derivative Works of, +publicly display, publicly perform, sublicense, and distribute the Work and such +Derivative Works in Source or Object form. + +3. Grant of Patent License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable (except as stated in this section) patent license to make, have +made, use, offer to sell, sell, import, and otherwise transfer the Work, where +such license applies only to those patent claims licensable by such Contributor +that are necessarily infringed by their Contribution(s) alone or by combination +of their Contribution(s) with the Work to which such Contribution(s) was +submitted. If You institute patent litigation against any entity (including a +cross-claim or counterclaim in a lawsuit) alleging that the Work or a +Contribution incorporated within the Work constitutes direct or contributory +patent infringement, then any patent licenses granted to You under this License +for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. + +You may reproduce and distribute copies of the Work or Derivative Works thereof +in any medium, with or without modifications, and in Source or Object form, +provided that You meet the following conditions: + +You must give any other recipients of the Work or Derivative Works a copy of +this License; and +You must cause any modified files to carry prominent notices stating that You +changed the files; and +You must retain, in the Source form of any Derivative Works that You distribute, +all copyright, patent, trademark, and attribution notices from the Source form +of the Work, excluding those notices that do not pertain to any part of the +Derivative Works; and +If the Work includes a "NOTICE" text file as part of its distribution, then any +Derivative Works that You distribute must include a readable copy of the +attribution notices contained within such NOTICE file, excluding those notices +that do not pertain to any part of the Derivative Works, in at least one of the +following places: within a NOTICE text file distributed as part of the +Derivative Works; within the Source form or documentation, if provided along +with the Derivative Works; or, within a display generated by the Derivative +Works, if and wherever such third-party notices normally appear. The contents of +the NOTICE file are for informational purposes only and do not modify the +License. You may add Your own attribution notices within Derivative Works that +You distribute, alongside or as an addendum to the NOTICE text from the Work, +provided that such additional attribution notices cannot be construed as +modifying the License. +You may add Your own copyright statement to Your modifications and may provide +additional or different license terms and conditions for use, reproduction, or +distribution of Your modifications, or for any such Derivative Works as a whole, +provided Your use, reproduction, and distribution of the Work otherwise complies +with the conditions stated in this License. + +5. Submission of Contributions. + +Unless You explicitly state otherwise, any Contribution intentionally submitted +for inclusion in the Work by You to the Licensor shall be under the terms and +conditions of this License, without any additional terms or conditions. +Notwithstanding the above, nothing herein shall supersede or modify the terms of +any separate license agreement you may have executed with Licensor regarding +such Contributions. + +6. Trademarks. + +This License does not grant permission to use the trade names, trademarks, +service marks, or product names of the Licensor, except as required for +reasonable and customary use in describing the origin of the Work and +reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. + +Unless required by applicable law or agreed to in writing, Licensor provides the +Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, +including, without limitation, any warranties or conditions of TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are +solely responsible for determining the appropriateness of using or +redistributing the Work and assume any risks associated with Your exercise of +permissions under this License. + +8. Limitation of Liability. + +In no event and under no legal theory, whether in tort (including negligence), +contract, or otherwise, unless required by applicable law (such as deliberate +and grossly negligent acts) or agreed to in writing, shall any Contributor be +liable to You for damages, including any direct, indirect, special, incidental, +or consequential damages of any character arising as a result of this License or +out of the use or inability to use the Work (including but not limited to +damages for loss of goodwill, work stoppage, computer failure or malfunction, or +any and all other commercial damages or losses), even if such Contributor has +been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. + +While redistributing the Work or Derivative Works thereof, You may choose to +offer, and charge a fee for, acceptance of support, warranty, indemnity, or +other liability obligations and/or rights consistent with this License. However, +in accepting such obligations, You may act only on Your own behalf and on Your +sole responsibility, not on behalf of any other Contributor, and only if You +agree to indemnify, defend, and hold each Contributor harmless for any liability +incurred by, or claims asserted against, such Contributor by reason of your +accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work + +To apply the Apache License to your work, attach the following boilerplate +notice, with the fields enclosed by brackets "[]" replaced with your own +identifying information. (Don't include the brackets!) The text should be +enclosed in the appropriate comment syntax for the file format. We also +recommend that a file or class name and description of purpose be included on +the same "printed page" as the copyright notice for easier identification within +third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/github.com/go-macaron/inject/README.md b/vendor/github.com/go-macaron/inject/README.md new file mode 100644 index 000000000..c65c76955 --- /dev/null +++ b/vendor/github.com/go-macaron/inject/README.md @@ -0,0 +1,11 @@ +# inject [![Build Status](https://travis-ci.org/go-macaron/inject.svg?branch=master)](https://travis-ci.org/go-macaron/inject) [![](http://gocover.io/_badge/github.com/go-macaron/inject)](http://gocover.io/github.com/go-macaron/inject) + +Package inject provides utilities for mapping and injecting dependencies in various ways. + +**This a modified version of [codegangsta/inject](https://github.com/codegangsta/inject) for special purpose of Macaron** + +**Please use the original version if you need dependency injection feature** + +## License + +This project is under the Apache License, Version 2.0. See the [LICENSE](LICENSE) file for the full license text. \ No newline at end of file diff --git a/vendor/github.com/go-macaron/inject/inject.go b/vendor/github.com/go-macaron/inject/inject.go new file mode 100644 index 000000000..1c1f98eaa --- /dev/null +++ b/vendor/github.com/go-macaron/inject/inject.go @@ -0,0 +1,262 @@ +// Copyright 2013 Jeremy Saenz +// Copyright 2015 The Macaron Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"): you may +// not use this file except in compliance with the License. You may obtain +// a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. + +// Package inject provides utilities for mapping and injecting dependencies in various ways. +package inject + +import ( + "fmt" + "reflect" +) + +// Injector represents an interface for mapping and injecting dependencies into structs +// and function arguments. +type Injector interface { + Applicator + Invoker + TypeMapper + // SetParent sets the parent of the injector. If the injector cannot find a + // dependency in its Type map it will check its parent before returning an + // error. + SetParent(Injector) +} + +// Applicator represents an interface for mapping dependencies to a struct. +type Applicator interface { + // Maps dependencies in the Type map to each field in the struct + // that is tagged with 'inject'. Returns an error if the injection + // fails. + Apply(interface{}) error +} + +// Invoker represents an interface for calling functions via reflection. +type Invoker interface { + // Invoke attempts to call the interface{} provided as a function, + // providing dependencies for function arguments based on Type. Returns + // a slice of reflect.Value representing the returned values of the function. + // Returns an error if the injection fails. + Invoke(interface{}) ([]reflect.Value, error) +} + +// FastInvoker represents an interface in order to avoid the calling function via reflection. +// +// example: +// type handlerFuncHandler func(http.ResponseWriter, *http.Request) error +// func (f handlerFuncHandler)Invoke([]interface{}) ([]reflect.Value, error){ +// ret := f(p[0].(http.ResponseWriter), p[1].(*http.Request)) +// return []reflect.Value{reflect.ValueOf(ret)}, nil +// } +// +// type funcHandler func(int, string) +// func (f funcHandler)Invoke([]interface{}) ([]reflect.Value, error){ +// f(p[0].(int), p[1].(string)) +// return nil, nil +// } +type FastInvoker interface { + // Invoke attempts to call the ordinary functions. If f is a function + // with the appropriate signature, f.Invoke([]interface{}) is a Call that calls f. + // Returns a slice of reflect.Value representing the returned values of the function. + // Returns an error if the injection fails. + Invoke([]interface{}) ([]reflect.Value, error) +} + +// IsFastInvoker check interface is FastInvoker +func IsFastInvoker(h interface{}) bool { + _, ok := h.(FastInvoker) + return ok +} + +// TypeMapper represents an interface for mapping interface{} values based on type. +type TypeMapper interface { + // Maps the interface{} value based on its immediate type from reflect.TypeOf. + Map(interface{}) TypeMapper + // Maps the interface{} value based on the pointer of an Interface provided. + // This is really only useful for mapping a value as an interface, as interfaces + // cannot at this time be referenced directly without a pointer. + MapTo(interface{}, interface{}) TypeMapper + // Provides a possibility to directly insert a mapping based on type and value. + // This makes it possible to directly map type arguments not possible to instantiate + // with reflect like unidirectional channels. + Set(reflect.Type, reflect.Value) TypeMapper + // Returns the Value that is mapped to the current type. Returns a zeroed Value if + // the Type has not been mapped. + GetVal(reflect.Type) reflect.Value +} + +type injector struct { + values map[reflect.Type]reflect.Value + parent Injector +} + +// InterfaceOf dereferences a pointer to an Interface type. +// It panics if value is not an pointer to an interface. +func InterfaceOf(value interface{}) reflect.Type { + t := reflect.TypeOf(value) + + for t.Kind() == reflect.Ptr { + t = t.Elem() + } + + if t.Kind() != reflect.Interface { + panic("Called inject.InterfaceOf with a value that is not a pointer to an interface. (*MyInterface)(nil)") + } + + return t +} + +// New returns a new Injector. +func New() Injector { + return &injector{ + values: make(map[reflect.Type]reflect.Value), + } +} + +// Invoke attempts to call the interface{} provided as a function, +// providing dependencies for function arguments based on Type. +// Returns a slice of reflect.Value representing the returned values of the function. +// Returns an error if the injection fails. +// It panics if f is not a function +func (inj *injector) Invoke(f interface{}) ([]reflect.Value, error) { + t := reflect.TypeOf(f) + switch v := f.(type) { + case FastInvoker: + return inj.fastInvoke(v, t, t.NumIn()) + default: + return inj.callInvoke(f, t, t.NumIn()) + } +} + +func (inj *injector) fastInvoke(f FastInvoker, t reflect.Type, numIn int) ([]reflect.Value, error) { + var in []interface{} + if numIn > 0 { + in = make([]interface{}, numIn) // Panic if t is not kind of Func + var argType reflect.Type + var val reflect.Value + for i := 0; i < numIn; i++ { + argType = t.In(i) + val = inj.GetVal(argType) + if !val.IsValid() { + return nil, fmt.Errorf("Value not found for type %v", argType) + } + + in[i] = val.Interface() + } + } + return f.Invoke(in) +} + +// callInvoke reflect.Value.Call +func (inj *injector) callInvoke(f interface{}, t reflect.Type, numIn int) ([]reflect.Value, error) { + var in []reflect.Value + if numIn > 0 { + in = make([]reflect.Value, numIn) + var argType reflect.Type + var val reflect.Value + for i := 0; i < numIn; i++ { + argType = t.In(i) + val = inj.GetVal(argType) + if !val.IsValid() { + return nil, fmt.Errorf("Value not found for type %v", argType) + } + + in[i] = val + } + } + return reflect.ValueOf(f).Call(in), nil +} + +// Maps dependencies in the Type map to each field in the struct +// that is tagged with 'inject'. +// Returns an error if the injection fails. +func (inj *injector) Apply(val interface{}) error { + v := reflect.ValueOf(val) + + for v.Kind() == reflect.Ptr { + v = v.Elem() + } + + if v.Kind() != reflect.Struct { + return nil // Should not panic here ? + } + + t := v.Type() + + for i := 0; i < v.NumField(); i++ { + f := v.Field(i) + structField := t.Field(i) + if f.CanSet() && (structField.Tag == "inject" || structField.Tag.Get("inject") != "") { + ft := f.Type() + v := inj.GetVal(ft) + if !v.IsValid() { + return fmt.Errorf("Value not found for type %v", ft) + } + + f.Set(v) + } + + } + + return nil +} + +// Maps the concrete value of val to its dynamic type using reflect.TypeOf, +// It returns the TypeMapper registered in. +func (i *injector) Map(val interface{}) TypeMapper { + i.values[reflect.TypeOf(val)] = reflect.ValueOf(val) + return i +} + +func (i *injector) MapTo(val interface{}, ifacePtr interface{}) TypeMapper { + i.values[InterfaceOf(ifacePtr)] = reflect.ValueOf(val) + return i +} + +// Maps the given reflect.Type to the given reflect.Value and returns +// the Typemapper the mapping has been registered in. +func (i *injector) Set(typ reflect.Type, val reflect.Value) TypeMapper { + i.values[typ] = val + return i +} + +func (i *injector) GetVal(t reflect.Type) reflect.Value { + val := i.values[t] + + if val.IsValid() { + return val + } + + // no concrete types found, try to find implementors + // if t is an interface + if t.Kind() == reflect.Interface { + for k, v := range i.values { + if k.Implements(t) { + val = v + break + } + } + } + + // Still no type found, try to look it up on the parent + if !val.IsValid() && i.parent != nil { + val = i.parent.GetVal(t) + } + + return val + +} + +func (i *injector) SetParent(parent Injector) { + i.parent = parent +} diff --git a/vendor/gopkg.in/macaron.v1/.gitignore b/vendor/gopkg.in/macaron.v1/.gitignore new file mode 100644 index 000000000..fc5aca3e4 --- /dev/null +++ b/vendor/gopkg.in/macaron.v1/.gitignore @@ -0,0 +1,3 @@ +macaron.sublime-project +macaron.sublime-workspace +.idea diff --git a/vendor/gopkg.in/macaron.v1/LICENSE b/vendor/gopkg.in/macaron.v1/LICENSE new file mode 100644 index 000000000..c8a16eb2e --- /dev/null +++ b/vendor/gopkg.in/macaron.v1/LICENSE @@ -0,0 +1,191 @@ +Apache License +Version 2.0, January 2004 +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and +distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright +owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities +that control, are controlled by, or are under common control with that entity. +For the purposes of this definition, "control" means (i) the power, direct or +indirect, to cause the direction or management of such entity, whether by +contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the +outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising +permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including +but not limited to software source code, documentation source, and configuration +files. + +"Object" form shall mean any form resulting from mechanical transformation or +translation of a Source form, including but not limited to compiled object code, +generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made +available under the License, as indicated by a copyright notice that is included +in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that +is based on (or derived from) the Work and for which the editorial revisions, +annotations, elaborations, or other modifications represent, as a whole, an +original work of authorship. For the purposes of this License, Derivative Works +shall not include works that remain separable from, or merely link (or bind by +name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version +of the Work and any modifications or additions to that Work or Derivative Works +thereof, that is intentionally submitted to Licensor for inclusion in the Work +by the copyright owner or by an individual or Legal Entity authorized to submit +on behalf of the copyright owner. For the purposes of this definition, +"submitted" means any form of electronic, verbal, or written communication sent +to the Licensor or its representatives, including but not limited to +communication on electronic mailing lists, source code control systems, and +issue tracking systems that are managed by, or on behalf of, the Licensor for +the purpose of discussing and improving the Work, but excluding communication +that is conspicuously marked or otherwise designated in writing by the copyright +owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf +of whom a Contribution has been received by Licensor and subsequently +incorporated within the Work. + +2. Grant of Copyright License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable copyright license to reproduce, prepare Derivative Works of, +publicly display, publicly perform, sublicense, and distribute the Work and such +Derivative Works in Source or Object form. + +3. Grant of Patent License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable (except as stated in this section) patent license to make, have +made, use, offer to sell, sell, import, and otherwise transfer the Work, where +such license applies only to those patent claims licensable by such Contributor +that are necessarily infringed by their Contribution(s) alone or by combination +of their Contribution(s) with the Work to which such Contribution(s) was +submitted. If You institute patent litigation against any entity (including a +cross-claim or counterclaim in a lawsuit) alleging that the Work or a +Contribution incorporated within the Work constitutes direct or contributory +patent infringement, then any patent licenses granted to You under this License +for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. + +You may reproduce and distribute copies of the Work or Derivative Works thereof +in any medium, with or without modifications, and in Source or Object form, +provided that You meet the following conditions: + +You must give any other recipients of the Work or Derivative Works a copy of +this License; and +You must cause any modified files to carry prominent notices stating that You +changed the files; and +You must retain, in the Source form of any Derivative Works that You distribute, +all copyright, patent, trademark, and attribution notices from the Source form +of the Work, excluding those notices that do not pertain to any part of the +Derivative Works; and +If the Work includes a "NOTICE" text file as part of its distribution, then any +Derivative Works that You distribute must include a readable copy of the +attribution notices contained within such NOTICE file, excluding those notices +that do not pertain to any part of the Derivative Works, in at least one of the +following places: within a NOTICE text file distributed as part of the +Derivative Works; within the Source form or documentation, if provided along +with the Derivative Works; or, within a display generated by the Derivative +Works, if and wherever such third-party notices normally appear. The contents of +the NOTICE file are for informational purposes only and do not modify the +License. You may add Your own attribution notices within Derivative Works that +You distribute, alongside or as an addendum to the NOTICE text from the Work, +provided that such additional attribution notices cannot be construed as +modifying the License. +You may add Your own copyright statement to Your modifications and may provide +additional or different license terms and conditions for use, reproduction, or +distribution of Your modifications, or for any such Derivative Works as a whole, +provided Your use, reproduction, and distribution of the Work otherwise complies +with the conditions stated in this License. + +5. Submission of Contributions. + +Unless You explicitly state otherwise, any Contribution intentionally submitted +for inclusion in the Work by You to the Licensor shall be under the terms and +conditions of this License, without any additional terms or conditions. +Notwithstanding the above, nothing herein shall supersede or modify the terms of +any separate license agreement you may have executed with Licensor regarding +such Contributions. + +6. Trademarks. + +This License does not grant permission to use the trade names, trademarks, +service marks, or product names of the Licensor, except as required for +reasonable and customary use in describing the origin of the Work and +reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. + +Unless required by applicable law or agreed to in writing, Licensor provides the +Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, +including, without limitation, any warranties or conditions of TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are +solely responsible for determining the appropriateness of using or +redistributing the Work and assume any risks associated with Your exercise of +permissions under this License. + +8. Limitation of Liability. + +In no event and under no legal theory, whether in tort (including negligence), +contract, or otherwise, unless required by applicable law (such as deliberate +and grossly negligent acts) or agreed to in writing, shall any Contributor be +liable to You for damages, including any direct, indirect, special, incidental, +or consequential damages of any character arising as a result of this License or +out of the use or inability to use the Work (including but not limited to +damages for loss of goodwill, work stoppage, computer failure or malfunction, or +any and all other commercial damages or losses), even if such Contributor has +been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. + +While redistributing the Work or Derivative Works thereof, You may choose to +offer, and charge a fee for, acceptance of support, warranty, indemnity, or +other liability obligations and/or rights consistent with this License. However, +in accepting such obligations, You may act only on Your own behalf and on Your +sole responsibility, not on behalf of any other Contributor, and only if You +agree to indemnify, defend, and hold each Contributor harmless for any liability +incurred by, or claims asserted against, such Contributor by reason of your +accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work + +To apply the Apache License to your work, attach the following boilerplate +notice, with the fields enclosed by brackets "[]" replaced with your own +identifying information. (Don't include the brackets!) The text should be +enclosed in the appropriate comment syntax for the file format. We also +recommend that a file or class name and description of purpose be included on +the same "printed page" as the copyright notice for easier identification within +third-party archives. + + Copyright 2014 The Macaron Authors + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/gopkg.in/macaron.v1/README.md b/vendor/gopkg.in/macaron.v1/README.md new file mode 100644 index 000000000..22856be35 --- /dev/null +++ b/vendor/gopkg.in/macaron.v1/README.md @@ -0,0 +1,96 @@ +# Macaron + +[![GitHub Workflow Status](https://img.shields.io/github/workflow/status/go-macaron/macaron/Go?logo=github&style=for-the-badge)](https://github.com/go-macaron/macaron/actions?query=workflow%3AGo) +[![codecov](https://img.shields.io/codecov/c/github/go-macaron/macaron/master?logo=codecov&style=for-the-badge)](https://codecov.io/gh/go-macaron/macaron) +[![GoDoc](https://img.shields.io/badge/GoDoc-Reference-blue?style=for-the-badge&logo=go)](https://pkg.go.dev/gopkg.in/macaron.v1?tab=doc) +[![Sourcegraph](https://img.shields.io/badge/view%20on-Sourcegraph-brightgreen.svg?style=for-the-badge&logo=sourcegraph)](https://sourcegraph.com/github.com/go-macaron/macaron) + +![Macaron Logo](https://raw.githubusercontent.com/go-macaron/macaron/v1/macaronlogo.png) + +Package macaron is a high productive and modular web framework in Go. + +## Getting Started + +The minimum requirement of Go is **1.6**. + +To install Macaron: + + go get gopkg.in/macaron.v1 + +The very basic usage of Macaron: + +```go +package main + +import "gopkg.in/macaron.v1" + +func main() { + m := macaron.Classic() + m.Get("/", func() string { + return "Hello world!" + }) + m.Run() +} +``` + +## Features + +- Powerful routing with suburl. +- Flexible routes combinations. +- Unlimited nested group routers. +- Directly integrate with existing services. +- Dynamically change template files at runtime. +- Allow to use in-memory template and static files. +- Easy to plugin/unplugin features with modular design. +- Handy dependency injection powered by [inject](https://github.com/codegangsta/inject). +- Better router layer and less reflection make faster speed. + +## Middlewares + +Middlewares allow you easily plugin/unplugin features for your Macaron applications. + +There are already many [middlewares](https://github.com/go-macaron) to simplify your work: + +- render - Go template engine +- static - Serves static files +- [gzip](https://github.com/go-macaron/gzip) - Gzip compression to all responses +- [binding](https://github.com/go-macaron/binding) - Request data binding and validation +- [i18n](https://github.com/go-macaron/i18n) - Internationalization and Localization +- [cache](https://github.com/go-macaron/cache) - Cache manager +- [session](https://github.com/go-macaron/session) - Session manager +- [csrf](https://github.com/go-macaron/csrf) - Generates and validates csrf tokens +- [captcha](https://github.com/go-macaron/captcha) - Captcha service +- [pongo2](https://github.com/go-macaron/pongo2) - Pongo2 template engine support +- [sockets](https://github.com/go-macaron/sockets) - WebSockets channels binding +- [bindata](https://github.com/go-macaron/bindata) - Embed binary data as static and template files +- [toolbox](https://github.com/go-macaron/toolbox) - Health check, pprof, profile and statistic services +- [oauth2](https://github.com/go-macaron/oauth2) - OAuth 2.0 backend +- [authz](https://github.com/go-macaron/authz) - ACL/RBAC/ABAC authorization based on Casbin +- [switcher](https://github.com/go-macaron/switcher) - Multiple-site support +- [method](https://github.com/go-macaron/method) - HTTP method override +- [permissions2](https://github.com/xyproto/permissions2) - Cookies, users and permissions +- [renders](https://github.com/go-macaron/renders) - Beego-like render engine(Macaron has built-in template engine, this is another option) +- [piwik](https://github.com/veecue/piwik-middleware) - Server-side piwik analytics + +## Use Cases + +- [Gogs](https://gogs.io): A painless self-hosted Git Service +- [Grafana](http://grafana.org/): The open platform for beautiful analytics and monitoring +- [Peach](https://peachdocs.org): A modern web documentation server +- [Go Walker](https://gowalker.org): Go online API documentation +- [Critical Stack Intel](https://intel.criticalstack.com/): A 100% free intel marketplace from Critical Stack, Inc. + +## Getting Help + +- [API Reference](https://gowalker.org/gopkg.in/macaron.v1) +- [Documentation](https://go-macaron.com) +- [FAQs](https://go-macaron.com/docs/faqs) + +## Credits + +- Basic design of [Martini](https://github.com/go-martini/martini). +- Logo is modified by [@insionng](https://github.com/insionng) based on [Tribal Dragon](http://xtremeyamazaki.deviantart.com/art/Tribal-Dragon-27005087). + +## License + +This project is under the Apache License, Version 2.0. See the [LICENSE](LICENSE) file for the full license text. diff --git a/vendor/gopkg.in/macaron.v1/codecov.yml b/vendor/gopkg.in/macaron.v1/codecov.yml new file mode 100644 index 000000000..fc947f230 --- /dev/null +++ b/vendor/gopkg.in/macaron.v1/codecov.yml @@ -0,0 +1,9 @@ +coverage: + range: "60...95" + status: + project: + default: + threshold: 1% + +comment: + layout: 'diff, files' diff --git a/vendor/gopkg.in/macaron.v1/context.go b/vendor/gopkg.in/macaron.v1/context.go new file mode 100644 index 000000000..be94d3501 --- /dev/null +++ b/vendor/gopkg.in/macaron.v1/context.go @@ -0,0 +1,537 @@ +// Copyright 2014 The Macaron Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"): you may +// not use this file except in compliance with the License. You may obtain +// a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. + +package macaron + +import ( + "crypto/sha256" + "encoding/hex" + "html/template" + "io" + "io/ioutil" + "mime/multipart" + "net/http" + "net/url" + "os" + "path" + "path/filepath" + "reflect" + "strconv" + "strings" + "time" + + "github.com/go-macaron/inject" + "github.com/unknwon/com" + "golang.org/x/crypto/pbkdf2" +) + +// Locale reprents a localization interface. +type Locale interface { + Language() string + Tr(string, ...interface{}) string +} + +// RequestBody represents a request body. +type RequestBody struct { + reader io.ReadCloser +} + +// Bytes reads and returns content of request body in bytes. +func (rb *RequestBody) Bytes() ([]byte, error) { + return ioutil.ReadAll(rb.reader) +} + +// String reads and returns content of request body in string. +func (rb *RequestBody) String() (string, error) { + data, err := rb.Bytes() + return string(data), err +} + +// ReadCloser returns a ReadCloser for request body. +func (rb *RequestBody) ReadCloser() io.ReadCloser { + return rb.reader +} + +// Request represents an HTTP request received by a server or to be sent by a client. +type Request struct { + *http.Request +} + +func (r *Request) Body() *RequestBody { + return &RequestBody{r.Request.Body} +} + +// ContextInvoker is an inject.FastInvoker wrapper of func(ctx *Context). +type ContextInvoker func(ctx *Context) + +func (invoke ContextInvoker) Invoke(params []interface{}) ([]reflect.Value, error) { + invoke(params[0].(*Context)) + return nil, nil +} + +// Context represents the runtime context of current request of Macaron instance. +// It is the integration of most frequently used middlewares and helper methods. +type Context struct { + inject.Injector + handlers []Handler + action Handler + index int + + *Router + Req Request + Resp ResponseWriter + params Params + Render + Locale + Data map[string]interface{} +} + +func (c *Context) handler() Handler { + if c.index < len(c.handlers) { + return c.handlers[c.index] + } + if c.index == len(c.handlers) { + return c.action + } + panic("invalid index for context handler") +} + +func (c *Context) Next() { + c.index += 1 + c.run() +} + +func (c *Context) Written() bool { + return c.Resp.Written() +} + +func (c *Context) run() { + for c.index <= len(c.handlers) { + vals, err := c.Invoke(c.handler()) + if err != nil { + panic(err) + } + c.index += 1 + + // if the handler returned something, write it to the http response + if len(vals) > 0 { + ev := c.GetVal(reflect.TypeOf(ReturnHandler(nil))) + handleReturn := ev.Interface().(ReturnHandler) + handleReturn(c, vals) + } + + if c.Written() { + return + } + } +} + +// RemoteAddr returns more real IP address. +func (ctx *Context) RemoteAddr() string { + addr := ctx.Req.Header.Get("X-Real-IP") + if len(addr) == 0 { + addr = ctx.Req.Header.Get("X-Forwarded-For") + if addr == "" { + addr = ctx.Req.RemoteAddr + if i := strings.LastIndex(addr, ":"); i > -1 { + addr = addr[:i] + } + } + } + return addr +} + +func (ctx *Context) renderHTML(status int, setName, tplName string, data ...interface{}) { + if len(data) <= 0 { + ctx.Render.HTMLSet(status, setName, tplName, ctx.Data) + } else if len(data) == 1 { + ctx.Render.HTMLSet(status, setName, tplName, data[0]) + } else { + ctx.Render.HTMLSet(status, setName, tplName, data[0], data[1].(HTMLOptions)) + } +} + +// HTML renders the HTML with default template set. +func (ctx *Context) HTML(status int, name string, data ...interface{}) { + ctx.renderHTML(status, DEFAULT_TPL_SET_NAME, name, data...) +} + +// HTMLSet renders the HTML with given template set name. +func (ctx *Context) HTMLSet(status int, setName, tplName string, data ...interface{}) { + ctx.renderHTML(status, setName, tplName, data...) +} + +func (ctx *Context) Redirect(location string, status ...int) { + code := http.StatusFound + if len(status) == 1 { + code = status[0] + } + + http.Redirect(ctx.Resp, ctx.Req.Request, location, code) +} + +// Maximum amount of memory to use when parsing a multipart form. +// Set this to whatever value you prefer; default is 10 MB. +var MaxMemory = int64(1024 * 1024 * 10) + +func (ctx *Context) parseForm() { + if ctx.Req.Form != nil { + return + } + + contentType := ctx.Req.Header.Get(_CONTENT_TYPE) + if (ctx.Req.Method == "POST" || ctx.Req.Method == "PUT") && + len(contentType) > 0 && strings.Contains(contentType, "multipart/form-data") { + _ = ctx.Req.ParseMultipartForm(MaxMemory) + } else { + _ = ctx.Req.ParseForm() + } +} + +// Query querys form parameter. +func (ctx *Context) Query(name string) string { + ctx.parseForm() + return ctx.Req.Form.Get(name) +} + +// QueryTrim querys and trims spaces form parameter. +func (ctx *Context) QueryTrim(name string) string { + return strings.TrimSpace(ctx.Query(name)) +} + +// QueryStrings returns a list of results by given query name. +func (ctx *Context) QueryStrings(name string) []string { + ctx.parseForm() + + vals, ok := ctx.Req.Form[name] + if !ok { + return []string{} + } + return vals +} + +// QueryEscape returns escapred query result. +func (ctx *Context) QueryEscape(name string) string { + return template.HTMLEscapeString(ctx.Query(name)) +} + +// QueryBool returns query result in bool type. +func (ctx *Context) QueryBool(name string) bool { + v, _ := strconv.ParseBool(ctx.Query(name)) + return v +} + +// QueryInt returns query result in int type. +func (ctx *Context) QueryInt(name string) int { + return com.StrTo(ctx.Query(name)).MustInt() +} + +// QueryInt64 returns query result in int64 type. +func (ctx *Context) QueryInt64(name string) int64 { + return com.StrTo(ctx.Query(name)).MustInt64() +} + +// QueryFloat64 returns query result in float64 type. +func (ctx *Context) QueryFloat64(name string) float64 { + v, _ := strconv.ParseFloat(ctx.Query(name), 64) + return v +} + +// Params returns value of given param name. +// e.g. ctx.Params(":uid") or ctx.Params("uid") +func (ctx *Context) Params(name string) string { + if len(name) == 0 { + return "" + } + if len(name) > 1 && name[0] != ':' { + name = ":" + name + } + return ctx.params[name] +} + +// AllParams returns all params. +func (ctx *Context) AllParams() Params { + return ctx.params +} + +// SetParams sets value of param with given name. +func (ctx *Context) SetParams(name, val string) { + if name != "*" && !strings.HasPrefix(name, ":") { + name = ":" + name + } + ctx.params[name] = val +} + +// ReplaceAllParams replace all current params with given params +func (ctx *Context) ReplaceAllParams(params Params) { + ctx.params = params +} + +// ParamsEscape returns escapred params result. +// e.g. ctx.ParamsEscape(":uname") +func (ctx *Context) ParamsEscape(name string) string { + return template.HTMLEscapeString(ctx.Params(name)) +} + +// ParamsInt returns params result in int type. +// e.g. ctx.ParamsInt(":uid") +func (ctx *Context) ParamsInt(name string) int { + return com.StrTo(ctx.Params(name)).MustInt() +} + +// ParamsInt64 returns params result in int64 type. +// e.g. ctx.ParamsInt64(":uid") +func (ctx *Context) ParamsInt64(name string) int64 { + return com.StrTo(ctx.Params(name)).MustInt64() +} + +// ParamsFloat64 returns params result in int64 type. +// e.g. ctx.ParamsFloat64(":uid") +func (ctx *Context) ParamsFloat64(name string) float64 { + v, _ := strconv.ParseFloat(ctx.Params(name), 64) + return v +} + +// GetFile returns information about user upload file by given form field name. +func (ctx *Context) GetFile(name string) (multipart.File, *multipart.FileHeader, error) { + return ctx.Req.FormFile(name) +} + +// SaveToFile reads a file from request by field name and saves to given path. +func (ctx *Context) SaveToFile(name, savePath string) error { + fr, _, err := ctx.GetFile(name) + if err != nil { + return err + } + defer fr.Close() + + fw, err := os.OpenFile(savePath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666) + if err != nil { + return err + } + defer fw.Close() + + _, err = io.Copy(fw, fr) + return err +} + +// SetCookie sets given cookie value to response header. +// FIXME: IE support? http://golanghome.com/post/620#reply2 +func (ctx *Context) SetCookie(name string, value string, others ...interface{}) { + cookie := http.Cookie{} + cookie.Name = name + cookie.Value = url.QueryEscape(value) + + if len(others) > 0 { + switch v := others[0].(type) { + case int: + cookie.MaxAge = v + case int64: + cookie.MaxAge = int(v) + case int32: + cookie.MaxAge = int(v) + } + } + + cookie.Path = "/" + if len(others) > 1 { + if v, ok := others[1].(string); ok && len(v) > 0 { + cookie.Path = v + } + } + + if len(others) > 2 { + if v, ok := others[2].(string); ok && len(v) > 0 { + cookie.Domain = v + } + } + + if len(others) > 3 { + switch v := others[3].(type) { + case bool: + cookie.Secure = v + default: + if others[3] != nil { + cookie.Secure = true + } + } + } + + if len(others) > 4 { + if v, ok := others[4].(bool); ok && v { + cookie.HttpOnly = true + } + } + + if len(others) > 5 { + if v, ok := others[5].(time.Time); ok { + cookie.Expires = v + cookie.RawExpires = v.Format(time.UnixDate) + } + } + + ctx.Resp.Header().Add("Set-Cookie", cookie.String()) +} + +// GetCookie returns given cookie value from request header. +func (ctx *Context) GetCookie(name string) string { + cookie, err := ctx.Req.Cookie(name) + if err != nil { + return "" + } + val, _ := url.QueryUnescape(cookie.Value) + return val +} + +// GetCookieInt returns cookie result in int type. +func (ctx *Context) GetCookieInt(name string) int { + return com.StrTo(ctx.GetCookie(name)).MustInt() +} + +// GetCookieInt64 returns cookie result in int64 type. +func (ctx *Context) GetCookieInt64(name string) int64 { + return com.StrTo(ctx.GetCookie(name)).MustInt64() +} + +// GetCookieFloat64 returns cookie result in float64 type. +func (ctx *Context) GetCookieFloat64(name string) float64 { + v, _ := strconv.ParseFloat(ctx.GetCookie(name), 64) + return v +} + +var defaultCookieSecret string + +// SetDefaultCookieSecret sets global default secure cookie secret. +func (m *Macaron) SetDefaultCookieSecret(secret string) { + defaultCookieSecret = secret +} + +// SetSecureCookie sets given cookie value to response header with default secret string. +func (ctx *Context) SetSecureCookie(name, value string, others ...interface{}) { + ctx.SetSuperSecureCookie(defaultCookieSecret, name, value, others...) +} + +// GetSecureCookie returns given cookie value from request header with default secret string. +func (ctx *Context) GetSecureCookie(key string) (string, bool) { + return ctx.GetSuperSecureCookie(defaultCookieSecret, key) +} + +// SetSuperSecureCookie sets given cookie value to response header with secret string. +func (ctx *Context) SetSuperSecureCookie(secret, name, value string, others ...interface{}) { + key := pbkdf2.Key([]byte(secret), []byte(secret), 1000, 16, sha256.New) + text, err := com.AESGCMEncrypt(key, []byte(value)) + if err != nil { + panic("error encrypting cookie: " + err.Error()) + } + + ctx.SetCookie(name, hex.EncodeToString(text), others...) +} + +// GetSuperSecureCookie returns given cookie value from request header with secret string. +func (ctx *Context) GetSuperSecureCookie(secret, name string) (string, bool) { + val := ctx.GetCookie(name) + if val == "" { + return "", false + } + + text, err := hex.DecodeString(val) + if err != nil { + return "", false + } + + key := pbkdf2.Key([]byte(secret), []byte(secret), 1000, 16, sha256.New) + text, err = com.AESGCMDecrypt(key, text) + return string(text), err == nil +} + +func (ctx *Context) setRawContentHeader() { + ctx.Resp.Header().Set("Content-Description", "Raw content") + ctx.Resp.Header().Set("Content-Type", "text/plain") + ctx.Resp.Header().Set("Expires", "0") + ctx.Resp.Header().Set("Cache-Control", "must-revalidate") + ctx.Resp.Header().Set("Pragma", "public") +} + +// ServeContent serves given content to response. +func (ctx *Context) ServeContent(name string, r io.ReadSeeker, params ...interface{}) { + modtime := time.Now() + for _, p := range params { + switch v := p.(type) { + case time.Time: + modtime = v + } + } + + ctx.setRawContentHeader() + http.ServeContent(ctx.Resp, ctx.Req.Request, name, modtime, r) +} + +// ServeFileContent serves given file as content to response. +func (ctx *Context) ServeFileContent(file string, names ...string) { + var name string + if len(names) > 0 { + name = names[0] + } else { + name = path.Base(file) + } + + f, err := os.Open(file) + if err != nil { + if Env == PROD { + http.Error(ctx.Resp, "Internal Server Error", 500) + } else { + http.Error(ctx.Resp, err.Error(), 500) + } + return + } + defer f.Close() + + ctx.setRawContentHeader() + http.ServeContent(ctx.Resp, ctx.Req.Request, name, time.Now(), f) +} + +// ServeFile serves given file to response. +func (ctx *Context) ServeFile(file string, names ...string) { + var name string + if len(names) > 0 { + name = names[0] + } else { + name = path.Base(file) + } + ctx.Resp.Header().Set("Content-Description", "File Transfer") + ctx.Resp.Header().Set("Content-Type", "application/octet-stream") + ctx.Resp.Header().Set("Content-Disposition", "attachment; filename="+name) + ctx.Resp.Header().Set("Content-Transfer-Encoding", "binary") + ctx.Resp.Header().Set("Expires", "0") + ctx.Resp.Header().Set("Cache-Control", "must-revalidate") + ctx.Resp.Header().Set("Pragma", "public") + http.ServeFile(ctx.Resp, ctx.Req.Request, file) +} + +// ChangeStaticPath changes static path from old to new one. +func (ctx *Context) ChangeStaticPath(oldPath, newPath string) { + if !filepath.IsAbs(oldPath) { + oldPath = filepath.Join(Root, oldPath) + } + dir := statics.Get(oldPath) + if dir != nil { + statics.Delete(oldPath) + + if !filepath.IsAbs(newPath) { + newPath = filepath.Join(Root, newPath) + } + *dir = http.Dir(newPath) + statics.Set(dir) + } +} diff --git a/vendor/gopkg.in/macaron.v1/go.mod b/vendor/gopkg.in/macaron.v1/go.mod new file mode 100644 index 000000000..e82c77846 --- /dev/null +++ b/vendor/gopkg.in/macaron.v1/go.mod @@ -0,0 +1,13 @@ +module gopkg.in/macaron.v1 + +go 1.12 + +require ( + github.com/go-macaron/inject v0.0.0-20160627170012-d8a0b8677191 + github.com/gopherjs/gopherjs v0.0.0-20190430165422-3e4dfb77656c // indirect + github.com/smartystreets/assertions v1.0.1 // indirect + github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337 + github.com/unknwon/com v0.0.0-20190804042917-757f69c95f3e + golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 + gopkg.in/ini.v1 v1.46.0 +) diff --git a/vendor/gopkg.in/macaron.v1/go.sum b/vendor/gopkg.in/macaron.v1/go.sum new file mode 100644 index 000000000..23cb914eb --- /dev/null +++ b/vendor/gopkg.in/macaron.v1/go.sum @@ -0,0 +1,32 @@ +github.com/go-macaron/inject v0.0.0-20160627170012-d8a0b8677191 h1:NjHlg70DuOkcAMqgt0+XA+NHwtu66MkTVVgR4fFWbcI= +github.com/go-macaron/inject v0.0.0-20160627170012-d8a0b8677191/go.mod h1:VFI2o2q9kYsC4o7VP1HrEVosiZZTd+MVT3YZx4gqvJw= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gopherjs/gopherjs v0.0.0-20190430165422-3e4dfb77656c h1:7lF+Vz0LqiRidnzC1Oq86fpX1q/iEv2KJdrCtttYjT4= +github.com/gopherjs/gopherjs v0.0.0-20190430165422-3e4dfb77656c/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/jtolds/gls v4.2.1+incompatible h1:fSuqC+Gmlu6l/ZYAoZzx2pyucC8Xza35fpRVWLVmUEE= +github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/assertions v0.0.0-20190116191733-b6c0e53d7304 h1:Jpy1PXuP99tXNrhbq2BaPz9B+jNAvH1JPQQpG/9GCXY= +github.com/smartystreets/assertions v0.0.0-20190116191733-b6c0e53d7304/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/assertions v1.0.1 h1:voD4ITNjPL5jjBfgR/r8fPIIBrliWrWHeiJApdr3r4w= +github.com/smartystreets/assertions v1.0.1/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM= +github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c h1:Ho+uVpkel/udgjbwB5Lktg9BtvJSh2DT0Hi6LPSyI2w= +github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c/go.mod h1:XDJAKZRPZ1CvBcN2aX5YOUTYGHki24fSF0Iv48Ibg0s= +github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337 h1:WN9BUFbdyOsSH/XohnWpXOlq9NBD5sGAB2FciQMUEe8= +github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/unknwon/com v0.0.0-20190804042917-757f69c95f3e h1:GSGeB9EAKY2spCABz6xOX5DbxZEXolK+nBSvmsQwRjM= +github.com/unknwon/com v0.0.0-20190804042917-757f69c95f3e/go.mod h1:tOOxU81rwgoCLoOVVPHb6T/wt8HZygqH5id+GNnlCXM= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 h1:HuIa8hRrWRSrqYzx1qI49NNxhdi2PrY7gxVSq1JjLDc= +golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +gopkg.in/ini.v1 v1.46.0 h1:VeDZbLYGaupuvIrsYCEOe/L/2Pcs5n7hdO1ZTjporag= +gopkg.in/ini.v1 v1.46.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= diff --git a/vendor/gopkg.in/macaron.v1/logger.go b/vendor/gopkg.in/macaron.v1/logger.go new file mode 100644 index 000000000..34178d78a --- /dev/null +++ b/vendor/gopkg.in/macaron.v1/logger.go @@ -0,0 +1,73 @@ +// Copyright 2013 Martini Authors +// Copyright 2014 The Macaron Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"): you may +// not use this file except in compliance with the License. You may obtain +// a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. + +package macaron + +import ( + "fmt" + "log" + "net/http" + "reflect" + "runtime" + "time" +) + +var ( + ColorLog = true + LogTimeFormat = "2006-01-02 15:04:05" +) + +func init() { + ColorLog = runtime.GOOS != "windows" +} + +// LoggerInvoker is an inject.FastInvoker wrapper of func(ctx *Context, log *log.Logger). +type LoggerInvoker func(ctx *Context, log *log.Logger) + +func (invoke LoggerInvoker) Invoke(params []interface{}) ([]reflect.Value, error) { + invoke(params[0].(*Context), params[1].(*log.Logger)) + return nil, nil +} + +// Logger returns a middleware handler that logs the request as it goes in and the response as it goes out. +func Logger() Handler { + return func(ctx *Context, log *log.Logger) { + start := time.Now() + + log.Printf("%s: Started %s %s for %s", time.Now().Format(LogTimeFormat), ctx.Req.Method, ctx.Req.RequestURI, ctx.RemoteAddr()) + + rw := ctx.Resp.(ResponseWriter) + ctx.Next() + + content := fmt.Sprintf("%s: Completed %s %s %v %s in %v", time.Now().Format(LogTimeFormat), ctx.Req.Method, ctx.Req.RequestURI, rw.Status(), http.StatusText(rw.Status()), time.Since(start)) + if ColorLog { + switch rw.Status() { + case 200, 201, 202: + content = fmt.Sprintf("\033[1;32m%s\033[0m", content) + case 301, 302: + content = fmt.Sprintf("\033[1;37m%s\033[0m", content) + case 304: + content = fmt.Sprintf("\033[1;33m%s\033[0m", content) + case 401, 403: + content = fmt.Sprintf("\033[4;31m%s\033[0m", content) + case 404: + content = fmt.Sprintf("\033[1;31m%s\033[0m", content) + case 500: + content = fmt.Sprintf("\033[1;36m%s\033[0m", content) + } + } + log.Println(content) + } +} diff --git a/vendor/gopkg.in/macaron.v1/macaron.go b/vendor/gopkg.in/macaron.v1/macaron.go new file mode 100644 index 000000000..8b9297a3a --- /dev/null +++ b/vendor/gopkg.in/macaron.v1/macaron.go @@ -0,0 +1,334 @@ +// +build go1.3 + +// Copyright 2014 The Macaron Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"): you may +// not use this file except in compliance with the License. You may obtain +// a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. + +// Package macaron is a high productive and modular web framework in Go. +package macaron // import "gopkg.in/macaron.v1" + +import ( + "io" + "log" + "net/http" + "os" + "reflect" + "strings" + "sync" + + "github.com/unknwon/com" + "gopkg.in/ini.v1" + + "github.com/go-macaron/inject" +) + +const _VERSION = "1.3.4.0805" + +func Version() string { + return _VERSION +} + +// Handler can be any callable function. +// Macaron attempts to inject services into the handler's argument list, +// and panics if an argument could not be fullfilled via dependency injection. +type Handler interface{} + +// handlerFuncInvoker is an inject.FastInvoker wrapper of func(http.ResponseWriter, *http.Request). +type handlerFuncInvoker func(http.ResponseWriter, *http.Request) + +func (invoke handlerFuncInvoker) Invoke(params []interface{}) ([]reflect.Value, error) { + invoke(params[0].(http.ResponseWriter), params[1].(*http.Request)) + return nil, nil +} + +// internalServerErrorInvoker is an inject.FastInvoker wrapper of func(rw http.ResponseWriter, err error). +type internalServerErrorInvoker func(rw http.ResponseWriter, err error) + +func (invoke internalServerErrorInvoker) Invoke(params []interface{}) ([]reflect.Value, error) { + invoke(params[0].(http.ResponseWriter), params[1].(error)) + return nil, nil +} + +// validateAndWrapHandler makes sure a handler is a callable function, it panics if not. +// When the handler is also potential to be any built-in inject.FastInvoker, +// it wraps the handler automatically to have some performance gain. +func validateAndWrapHandler(h Handler) Handler { + if reflect.TypeOf(h).Kind() != reflect.Func { + panic("Macaron handler must be a callable function") + } + + if !inject.IsFastInvoker(h) { + switch v := h.(type) { + case func(*Context): + return ContextInvoker(v) + case func(*Context, *log.Logger): + return LoggerInvoker(v) + case func(http.ResponseWriter, *http.Request): + return handlerFuncInvoker(v) + case func(http.ResponseWriter, error): + return internalServerErrorInvoker(v) + } + } + return h +} + +// validateAndWrapHandlers preforms validation and wrapping for each input handler. +// It accepts an optional wrapper function to perform custom wrapping on handlers. +func validateAndWrapHandlers(handlers []Handler, wrappers ...func(Handler) Handler) []Handler { + var wrapper func(Handler) Handler + if len(wrappers) > 0 { + wrapper = wrappers[0] + } + + wrappedHandlers := make([]Handler, len(handlers)) + for i, h := range handlers { + h = validateAndWrapHandler(h) + if wrapper != nil && !inject.IsFastInvoker(h) { + h = wrapper(h) + } + wrappedHandlers[i] = h + } + + return wrappedHandlers +} + +// Macaron represents the top level web application. +// inject.Injector methods can be invoked to map services on a global level. +type Macaron struct { + inject.Injector + befores []BeforeHandler + handlers []Handler + action Handler + + hasURLPrefix bool + urlPrefix string // For suburl support. + *Router + + logger *log.Logger +} + +// NewWithLogger creates a bare bones Macaron instance. +// Use this method if you want to have full control over the middleware that is used. +// You can specify logger output writer with this function. +func NewWithLogger(out io.Writer) *Macaron { + m := &Macaron{ + Injector: inject.New(), + action: func() {}, + Router: NewRouter(), + logger: log.New(out, "[Macaron] ", 0), + } + m.Router.m = m + m.Map(m.logger) + m.Map(defaultReturnHandler()) + m.NotFound(http.NotFound) + m.InternalServerError(func(rw http.ResponseWriter, err error) { + http.Error(rw, err.Error(), 500) + }) + return m +} + +// New creates a bare bones Macaron instance. +// Use this method if you want to have full control over the middleware that is used. +func New() *Macaron { + return NewWithLogger(os.Stdout) +} + +// Classic creates a classic Macaron with some basic default middleware: +// macaron.Logger, macaron.Recovery and macaron.Static. +func Classic() *Macaron { + m := New() + m.Use(Logger()) + m.Use(Recovery()) + m.Use(Static("public")) + return m +} + +// Handlers sets the entire middleware stack with the given Handlers. +// This will clear any current middleware handlers, +// and panics if any of the handlers is not a callable function +func (m *Macaron) Handlers(handlers ...Handler) { + m.handlers = make([]Handler, 0) + for _, handler := range handlers { + m.Use(handler) + } +} + +// Action sets the handler that will be called after all the middleware has been invoked. +// This is set to macaron.Router in a macaron.Classic(). +func (m *Macaron) Action(handler Handler) { + handler = validateAndWrapHandler(handler) + m.action = handler +} + +// BeforeHandler represents a handler executes at beginning of every request. +// Macaron stops future process when it returns true. +type BeforeHandler func(rw http.ResponseWriter, req *http.Request) bool + +func (m *Macaron) Before(handler BeforeHandler) { + m.befores = append(m.befores, handler) +} + +// Use adds a middleware Handler to the stack, +// and panics if the handler is not a callable func. +// Middleware Handlers are invoked in the order that they are added. +func (m *Macaron) Use(handler Handler) { + handler = validateAndWrapHandler(handler) + m.handlers = append(m.handlers, handler) +} + +func (m *Macaron) createContext(rw http.ResponseWriter, req *http.Request) *Context { + c := &Context{ + Injector: inject.New(), + handlers: m.handlers, + action: m.action, + index: 0, + Router: m.Router, + Req: Request{req}, + Resp: NewResponseWriter(req.Method, rw), + Render: &DummyRender{rw}, + Data: make(map[string]interface{}), + } + c.SetParent(m) + c.Map(c) + c.MapTo(c.Resp, (*http.ResponseWriter)(nil)) + c.Map(req) + return c +} + +// ServeHTTP is the HTTP Entry point for a Macaron instance. +// Useful if you want to control your own HTTP server. +// Be aware that none of middleware will run without registering any router. +func (m *Macaron) ServeHTTP(rw http.ResponseWriter, req *http.Request) { + if m.hasURLPrefix { + req.URL.Path = strings.TrimPrefix(req.URL.Path, m.urlPrefix) + } + for _, h := range m.befores { + if h(rw, req) { + return + } + } + m.Router.ServeHTTP(rw, req) +} + +func GetDefaultListenInfo() (string, int) { + host := os.Getenv("HOST") + if len(host) == 0 { + host = "0.0.0.0" + } + port := com.StrTo(os.Getenv("PORT")).MustInt() + if port == 0 { + port = 4000 + } + return host, port +} + +// Run the http server. Listening on os.GetEnv("PORT") or 4000 by default. +func (m *Macaron) Run(args ...interface{}) { + host, port := GetDefaultListenInfo() + if len(args) == 1 { + switch arg := args[0].(type) { + case string: + host = arg + case int: + port = arg + } + } else if len(args) >= 2 { + if arg, ok := args[0].(string); ok { + host = arg + } + if arg, ok := args[1].(int); ok { + port = arg + } + } + + addr := host + ":" + com.ToStr(port) + logger := m.GetVal(reflect.TypeOf(m.logger)).Interface().(*log.Logger) + logger.Printf("listening on %s (%s)\n", addr, safeEnv()) + logger.Fatalln(http.ListenAndServe(addr, m)) +} + +// SetURLPrefix sets URL prefix of router layer, so that it support suburl. +func (m *Macaron) SetURLPrefix(prefix string) { + m.urlPrefix = prefix + m.hasURLPrefix = len(m.urlPrefix) > 0 +} + +// ____ ____ .__ ___. .__ +// \ \ / /____ _______|__|____ \_ |__ | | ____ ______ +// \ Y /\__ \\_ __ \ \__ \ | __ \| | _/ __ \ / ___/ +// \ / / __ \| | \/ |/ __ \| \_\ \ |_\ ___/ \___ \ +// \___/ (____ /__| |__(____ /___ /____/\___ >____ > +// \/ \/ \/ \/ \/ + +const ( + DEV = "development" + PROD = "production" + TEST = "test" +) + +var ( + // Env is the environment that Macaron is executing in. + // The MACARON_ENV is read on initialization to set this variable. + Env = DEV + envLock sync.Mutex + + // Path of work directory. + Root string + + // Flash applies to current request. + FlashNow bool + + // Configuration convention object. + cfg *ini.File +) + +func setENV(e string) { + envLock.Lock() + defer envLock.Unlock() + + if len(e) > 0 { + Env = e + } +} + +func safeEnv() string { + envLock.Lock() + defer envLock.Unlock() + + return Env +} + +func init() { + setENV(os.Getenv("MACARON_ENV")) + + var err error + Root, err = os.Getwd() + if err != nil { + panic("error getting work directory: " + err.Error()) + } +} + +// SetConfig sets data sources for configuration. +func SetConfig(source interface{}, others ...interface{}) (_ *ini.File, err error) { + cfg, err = ini.Load(source, others...) + return Config(), err +} + +// Config returns configuration convention object. +// It returns an empty object if there is no one available. +func Config() *ini.File { + if cfg == nil { + return ini.Empty() + } + return cfg +} diff --git a/vendor/gopkg.in/macaron.v1/macaronlogo.png b/vendor/gopkg.in/macaron.v1/macaronlogo.png new file mode 100644 index 000000000..399759769 Binary files /dev/null and b/vendor/gopkg.in/macaron.v1/macaronlogo.png differ diff --git a/vendor/gopkg.in/macaron.v1/recovery.go b/vendor/gopkg.in/macaron.v1/recovery.go new file mode 100644 index 000000000..c45c54c94 --- /dev/null +++ b/vendor/gopkg.in/macaron.v1/recovery.go @@ -0,0 +1,163 @@ +// Copyright 2013 Martini Authors +// Copyright 2014 The Macaron Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"): you may +// not use this file except in compliance with the License. You may obtain +// a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. + +package macaron + +import ( + "bytes" + "fmt" + "io/ioutil" + "log" + "net/http" + "runtime" + + "github.com/go-macaron/inject" +) + +const ( + panicHtml = ` +PANIC: %s + + + +

PANIC

+
%s
+
%s
+ +` +) + +var ( + dunno = []byte("???") + centerDot = []byte("·") + dot = []byte(".") + slash = []byte("/") +) + +// 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 +} + +// Recovery returns a middleware that recovers from any panics and writes a 500 if there was one. +// While Martini is in development mode, Recovery will also output the panic as HTML. +func Recovery() Handler { + return func(c *Context, log *log.Logger) { + defer func() { + if err := recover(); err != nil { + stack := stack(3) + log.Printf("PANIC: %s\n%s", err, stack) + + // Lookup the current responsewriter + val := c.GetVal(inject.InterfaceOf((*http.ResponseWriter)(nil))) + res := val.Interface().(http.ResponseWriter) + + // respond with panic message while in development mode + var body []byte + if Env == DEV { + res.Header().Set("Content-Type", "text/html") + body = []byte(fmt.Sprintf(panicHtml, err, err, stack)) + } + + res.WriteHeader(http.StatusInternalServerError) + if nil != body { + _, _ = res.Write(body) + } + } + }() + + c.Next() + } +} diff --git a/vendor/gopkg.in/macaron.v1/render.go b/vendor/gopkg.in/macaron.v1/render.go new file mode 100644 index 000000000..04687c4f4 --- /dev/null +++ b/vendor/gopkg.in/macaron.v1/render.go @@ -0,0 +1,724 @@ +// Copyright 2013 Martini Authors +// Copyright 2014 The Macaron Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"): you may +// not use this file except in compliance with the License. You may obtain +// a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. + +package macaron + +import ( + "bytes" + "encoding/json" + "encoding/xml" + "fmt" + "html/template" + "io" + "io/ioutil" + "net/http" + "os" + "path" + "path/filepath" + "strings" + "sync" + "time" + + "github.com/unknwon/com" +) + +const ( + _CONTENT_TYPE = "Content-Type" + _CONTENT_BINARY = "application/octet-stream" + _CONTENT_JSON = "application/json" + _CONTENT_HTML = "text/html" + _CONTENT_PLAIN = "text/plain" + _CONTENT_XHTML = "application/xhtml+xml" + _CONTENT_XML = "text/xml" + _DEFAULT_CHARSET = "UTF-8" +) + +var ( + // Provides a temporary buffer to execute templates into and catch errors. + bufpool = sync.Pool{ + New: func() interface{} { return new(bytes.Buffer) }, + } + + // Included helper functions for use when rendering html + helperFuncs = template.FuncMap{ + "yield": func() (string, error) { + return "", fmt.Errorf("yield called with no layout defined") + }, + "current": func() (string, error) { + return "", nil + }, + } +) + +type ( + // TemplateFile represents a interface of template file that has name and can be read. + TemplateFile interface { + Name() string + Data() []byte + Ext() string + } + // TemplateFileSystem represents a interface of template file system that able to list all files. + TemplateFileSystem interface { + ListFiles() []TemplateFile + Get(string) (io.Reader, error) + } + + // Delims represents a set of Left and Right delimiters for HTML template rendering + Delims struct { + // Left delimiter, defaults to {{ + Left string + // Right delimiter, defaults to }} + Right string + } + + // RenderOptions represents a struct for specifying configuration options for the Render middleware. + RenderOptions struct { + // Directory to load templates. Default is "templates". + Directory string + // Addtional directories to overwite templates. + AppendDirectories []string + // Layout template name. Will not render a layout if "". Default is to "". + Layout string + // Extensions to parse template files from. Defaults are [".tmpl", ".html"]. + Extensions []string + // Funcs is a slice of FuncMaps to apply to the template upon compilation. This is useful for helper functions. Default is []. + Funcs []template.FuncMap + // Delims sets the action delimiters to the specified strings in the Delims struct. + Delims Delims + // Appends the given charset to the Content-Type header. Default is "UTF-8". + Charset string + // Outputs human readable JSON. + IndentJSON bool + // Outputs human readable XML. + IndentXML bool + // Prefixes the JSON output with the given bytes. + PrefixJSON []byte + // Prefixes the XML output with the given bytes. + PrefixXML []byte + // Allows changing of output to XHTML instead of HTML. Default is "text/html" + HTMLContentType string + // TemplateFileSystem is the interface for supporting any implmentation of template file system. + TemplateFileSystem + } + + // HTMLOptions is a struct for overriding some rendering Options for specific HTML call + HTMLOptions struct { + // Layout template name. Overrides Options.Layout. + Layout string + } + + Render interface { + http.ResponseWriter + SetResponseWriter(http.ResponseWriter) + + JSON(int, interface{}) + JSONString(interface{}) (string, error) + RawData(int, []byte) // Serve content as binary + PlainText(int, []byte) // Serve content as plain text + HTML(int, string, interface{}, ...HTMLOptions) + HTMLSet(int, string, string, interface{}, ...HTMLOptions) + HTMLSetString(string, string, interface{}, ...HTMLOptions) (string, error) + HTMLString(string, interface{}, ...HTMLOptions) (string, error) + HTMLSetBytes(string, string, interface{}, ...HTMLOptions) ([]byte, error) + HTMLBytes(string, interface{}, ...HTMLOptions) ([]byte, error) + XML(int, interface{}) + Error(int, ...string) + Status(int) + SetTemplatePath(string, string) + HasTemplateSet(string) bool + } +) + +// TplFile implements TemplateFile interface. +type TplFile struct { + name string + data []byte + ext string +} + +// NewTplFile cerates new template file with given name and data. +func NewTplFile(name string, data []byte, ext string) *TplFile { + return &TplFile{name, data, ext} +} + +func (f *TplFile) Name() string { + return f.name +} + +func (f *TplFile) Data() []byte { + return f.data +} + +func (f *TplFile) Ext() string { + return f.ext +} + +// TplFileSystem implements TemplateFileSystem interface. +type TplFileSystem struct { + files []TemplateFile +} + +// NewTemplateFileSystem creates new template file system with given options. +func NewTemplateFileSystem(opt RenderOptions, omitData bool) TplFileSystem { + fs := TplFileSystem{} + fs.files = make([]TemplateFile, 0, 10) + + // Directories are composed in reverse order because later one overwrites previous ones, + // so once found, we can directly jump out of the loop. + dirs := make([]string, 0, len(opt.AppendDirectories)+1) + for i := len(opt.AppendDirectories) - 1; i >= 0; i-- { + dirs = append(dirs, opt.AppendDirectories[i]) + } + dirs = append(dirs, opt.Directory) + + var err error + for i := range dirs { + // Skip ones that does not exists for symlink test, + // but allow non-symlink ones added after start. + if !com.IsExist(dirs[i]) { + continue + } + + dirs[i], err = filepath.EvalSymlinks(dirs[i]) + if err != nil { + panic("EvalSymlinks(" + dirs[i] + "): " + err.Error()) + } + } + lastDir := dirs[len(dirs)-1] + + // We still walk the last (original) directory because it's non-sense we load templates not exist in original directory. + if err = filepath.Walk(lastDir, func(path string, info os.FileInfo, _ error) error { + r, err := filepath.Rel(lastDir, path) + if err != nil { + return err + } + + ext := GetExt(r) + + for _, extension := range opt.Extensions { + if ext != extension { + continue + } + + var data []byte + if !omitData { + // Loop over candidates of directory, break out once found. + // The file always exists because it's inside the walk function, + // and read original file is the worst case. + for i := range dirs { + path = filepath.Join(dirs[i], r) + if !com.IsFile(path) { + continue + } + + data, err = ioutil.ReadFile(path) + if err != nil { + return err + } + break + } + } + + name := filepath.ToSlash((r[0 : len(r)-len(ext)])) + fs.files = append(fs.files, NewTplFile(name, data, ext)) + } + + return nil + }); err != nil { + panic("NewTemplateFileSystem: " + err.Error()) + } + + return fs +} + +func (fs TplFileSystem) ListFiles() []TemplateFile { + return fs.files +} + +func (fs TplFileSystem) Get(name string) (io.Reader, error) { + for i := range fs.files { + if fs.files[i].Name()+fs.files[i].Ext() == name { + return bytes.NewReader(fs.files[i].Data()), nil + } + } + return nil, fmt.Errorf("file '%s' not found", name) +} + +func PrepareCharset(charset string) string { + if len(charset) != 0 { + return "; charset=" + charset + } + + return "; charset=" + _DEFAULT_CHARSET +} + +func GetExt(s string) string { + index := strings.Index(s, ".") + if index == -1 { + return "" + } + return s[index:] +} + +func compile(opt RenderOptions) *template.Template { + t := template.New(opt.Directory) + t.Delims(opt.Delims.Left, opt.Delims.Right) + // Parse an initial template in case we don't have any. + template.Must(t.Parse("Macaron")) + + if opt.TemplateFileSystem == nil { + opt.TemplateFileSystem = NewTemplateFileSystem(opt, false) + } + + for _, f := range opt.TemplateFileSystem.ListFiles() { + tmpl := t.New(f.Name()) + for _, funcs := range opt.Funcs { + tmpl.Funcs(funcs) + } + // Bomb out if parse fails. We don't want any silent server starts. + template.Must(tmpl.Funcs(helperFuncs).Parse(string(f.Data()))) + } + + return t +} + +const ( + DEFAULT_TPL_SET_NAME = "DEFAULT" +) + +// TemplateSet represents a template set of type *template.Template. +type TemplateSet struct { + lock sync.RWMutex + sets map[string]*template.Template + dirs map[string]string +} + +// NewTemplateSet initializes a new empty template set. +func NewTemplateSet() *TemplateSet { + return &TemplateSet{ + sets: make(map[string]*template.Template), + dirs: make(map[string]string), + } +} + +func (ts *TemplateSet) Set(name string, opt *RenderOptions) *template.Template { + t := compile(*opt) + + ts.lock.Lock() + defer ts.lock.Unlock() + + ts.sets[name] = t + ts.dirs[name] = opt.Directory + return t +} + +func (ts *TemplateSet) Get(name string) *template.Template { + ts.lock.RLock() + defer ts.lock.RUnlock() + + return ts.sets[name] +} + +func (ts *TemplateSet) GetDir(name string) string { + ts.lock.RLock() + defer ts.lock.RUnlock() + + return ts.dirs[name] +} + +func prepareRenderOptions(options []RenderOptions) RenderOptions { + var opt RenderOptions + if len(options) > 0 { + opt = options[0] + } + + // Defaults. + if len(opt.Directory) == 0 { + opt.Directory = "templates" + } + if len(opt.Extensions) == 0 { + opt.Extensions = []string{".tmpl", ".html"} + } + if len(opt.HTMLContentType) == 0 { + opt.HTMLContentType = _CONTENT_HTML + } + + return opt +} + +func ParseTplSet(tplSet string) (tplName string, tplDir string) { + tplSet = strings.TrimSpace(tplSet) + if len(tplSet) == 0 { + panic("empty template set argument") + } + infos := strings.Split(tplSet, ":") + if len(infos) == 1 { + tplDir = infos[0] + tplName = path.Base(tplDir) + } else { + tplName = infos[0] + tplDir = infos[1] + } + + if !com.IsDir(tplDir) { + panic("template set path does not exist or is not a directory") + } + return tplName, tplDir +} + +func renderHandler(opt RenderOptions, tplSets []string) Handler { + cs := PrepareCharset(opt.Charset) + ts := NewTemplateSet() + ts.Set(DEFAULT_TPL_SET_NAME, &opt) + + var tmpOpt RenderOptions + for _, tplSet := range tplSets { + tplName, tplDir := ParseTplSet(tplSet) + tmpOpt = opt + tmpOpt.Directory = tplDir + ts.Set(tplName, &tmpOpt) + } + + return func(ctx *Context) { + r := &TplRender{ + ResponseWriter: ctx.Resp, + TemplateSet: ts, + Opt: &opt, + CompiledCharset: cs, + } + ctx.Data["TmplLoadTimes"] = func() string { + if r.startTime.IsZero() { + return "" + } + return fmt.Sprint(time.Since(r.startTime).Nanoseconds()/1e6) + "ms" + } + + ctx.Render = r + ctx.MapTo(r, (*Render)(nil)) + } +} + +// Renderer is a Middleware that maps a macaron.Render service into the Macaron handler chain. +// An single variadic macaron.RenderOptions struct can be optionally provided to configure +// HTML rendering. The default directory for templates is "templates" and the default +// file extension is ".tmpl" and ".html". +// +// If MACARON_ENV is set to "" or "development" then templates will be recompiled on every request. For more performance, set the +// MACARON_ENV environment variable to "production". +func Renderer(options ...RenderOptions) Handler { + return renderHandler(prepareRenderOptions(options), []string{}) +} + +func Renderers(options RenderOptions, tplSets ...string) Handler { + return renderHandler(prepareRenderOptions([]RenderOptions{options}), tplSets) +} + +type TplRender struct { + http.ResponseWriter + *TemplateSet + Opt *RenderOptions + CompiledCharset string + + startTime time.Time +} + +func (r *TplRender) SetResponseWriter(rw http.ResponseWriter) { + r.ResponseWriter = rw +} + +func (r *TplRender) JSON(status int, v interface{}) { + var ( + result []byte + err error + ) + if r.Opt.IndentJSON { + result, err = json.MarshalIndent(v, "", " ") + } else { + result, err = json.Marshal(v) + } + if err != nil { + http.Error(r, err.Error(), 500) + return + } + + // json rendered fine, write out the result + r.Header().Set(_CONTENT_TYPE, _CONTENT_JSON+r.CompiledCharset) + r.WriteHeader(status) + if len(r.Opt.PrefixJSON) > 0 { + _, _ = r.Write(r.Opt.PrefixJSON) + } + _, _ = r.Write(result) +} + +func (r *TplRender) JSONString(v interface{}) (string, error) { + var result []byte + var err error + if r.Opt.IndentJSON { + result, err = json.MarshalIndent(v, "", " ") + } else { + result, err = json.Marshal(v) + } + if err != nil { + return "", err + } + return string(result), nil +} + +func (r *TplRender) XML(status int, v interface{}) { + var result []byte + var err error + if r.Opt.IndentXML { + result, err = xml.MarshalIndent(v, "", " ") + } else { + result, err = xml.Marshal(v) + } + if err != nil { + http.Error(r, err.Error(), 500) + return + } + + // XML rendered fine, write out the result + r.Header().Set(_CONTENT_TYPE, _CONTENT_XML+r.CompiledCharset) + r.WriteHeader(status) + if len(r.Opt.PrefixXML) > 0 { + _, _ = r.Write(r.Opt.PrefixXML) + } + _, _ = r.Write(result) +} + +func (r *TplRender) data(status int, contentType string, v []byte) { + if r.Header().Get(_CONTENT_TYPE) == "" { + r.Header().Set(_CONTENT_TYPE, contentType) + } + r.WriteHeader(status) + _, _ = r.Write(v) +} + +func (r *TplRender) RawData(status int, v []byte) { + r.data(status, _CONTENT_BINARY, v) +} + +func (r *TplRender) PlainText(status int, v []byte) { + r.data(status, _CONTENT_PLAIN, v) +} + +func (r *TplRender) execute(t *template.Template, name string, data interface{}) (*bytes.Buffer, error) { + buf := bufpool.Get().(*bytes.Buffer) + return buf, t.ExecuteTemplate(buf, name, data) +} + +func (r *TplRender) addYield(t *template.Template, tplName string, data interface{}) { + funcs := template.FuncMap{ + "yield": func() (template.HTML, error) { + buf, err := r.execute(t, tplName, data) + // return safe html here since we are rendering our own template + return template.HTML(buf.String()), err + }, + "current": func() (string, error) { + return tplName, nil + }, + } + t.Funcs(funcs) +} + +func (r *TplRender) renderBytes(setName, tplName string, data interface{}, htmlOpt ...HTMLOptions) (*bytes.Buffer, error) { + t := r.TemplateSet.Get(setName) + if Env == DEV { + opt := *r.Opt + opt.Directory = r.TemplateSet.GetDir(setName) + t = r.TemplateSet.Set(setName, &opt) + } + if t == nil { + return nil, fmt.Errorf("html/template: template \"%s\" is undefined", tplName) + } + + opt := r.prepareHTMLOptions(htmlOpt) + + if len(opt.Layout) > 0 { + r.addYield(t, tplName, data) + tplName = opt.Layout + } + + out, err := r.execute(t, tplName, data) + if err != nil { + return nil, err + } + + return out, nil +} + +func (r *TplRender) renderHTML(status int, setName, tplName string, data interface{}, htmlOpt ...HTMLOptions) { + r.startTime = time.Now() + + out, err := r.renderBytes(setName, tplName, data, htmlOpt...) + if err != nil { + http.Error(r, err.Error(), http.StatusInternalServerError) + return + } + + r.Header().Set(_CONTENT_TYPE, r.Opt.HTMLContentType+r.CompiledCharset) + r.WriteHeader(status) + + if _, err := out.WriteTo(r); err != nil { + out.Reset() + } + bufpool.Put(out) +} + +func (r *TplRender) HTML(status int, name string, data interface{}, htmlOpt ...HTMLOptions) { + r.renderHTML(status, DEFAULT_TPL_SET_NAME, name, data, htmlOpt...) +} + +func (r *TplRender) HTMLSet(status int, setName, tplName string, data interface{}, htmlOpt ...HTMLOptions) { + r.renderHTML(status, setName, tplName, data, htmlOpt...) +} + +func (r *TplRender) HTMLSetBytes(setName, tplName string, data interface{}, htmlOpt ...HTMLOptions) ([]byte, error) { + out, err := r.renderBytes(setName, tplName, data, htmlOpt...) + if err != nil { + return []byte(""), err + } + return out.Bytes(), nil +} + +func (r *TplRender) HTMLBytes(name string, data interface{}, htmlOpt ...HTMLOptions) ([]byte, error) { + return r.HTMLSetBytes(DEFAULT_TPL_SET_NAME, name, data, htmlOpt...) +} + +func (r *TplRender) HTMLSetString(setName, tplName string, data interface{}, htmlOpt ...HTMLOptions) (string, error) { + p, err := r.HTMLSetBytes(setName, tplName, data, htmlOpt...) + return string(p), err +} + +func (r *TplRender) HTMLString(name string, data interface{}, htmlOpt ...HTMLOptions) (string, error) { + p, err := r.HTMLBytes(name, data, htmlOpt...) + return string(p), err +} + +// Error writes the given HTTP status to the current ResponseWriter +func (r *TplRender) Error(status int, message ...string) { + r.WriteHeader(status) + if len(message) > 0 { + _, _ = r.Write([]byte(message[0])) + } +} + +func (r *TplRender) Status(status int) { + r.WriteHeader(status) +} + +func (r *TplRender) prepareHTMLOptions(htmlOpt []HTMLOptions) HTMLOptions { + if len(htmlOpt) > 0 { + return htmlOpt[0] + } + + return HTMLOptions{ + Layout: r.Opt.Layout, + } +} + +func (r *TplRender) SetTemplatePath(setName, dir string) { + if len(setName) == 0 { + setName = DEFAULT_TPL_SET_NAME + } + opt := *r.Opt + opt.Directory = dir + r.TemplateSet.Set(setName, &opt) +} + +func (r *TplRender) HasTemplateSet(name string) bool { + return r.TemplateSet.Get(name) != nil +} + +// DummyRender is used when user does not choose any real render to use. +// This way, we can print out friendly message which asks them to register one, +// instead of ugly and confusing 'nil pointer' panic. +type DummyRender struct { + http.ResponseWriter +} + +func renderNotRegistered() { + panic("middleware render hasn't been registered") +} + +func (r *DummyRender) SetResponseWriter(http.ResponseWriter) { + renderNotRegistered() +} + +func (r *DummyRender) JSON(int, interface{}) { + renderNotRegistered() +} + +func (r *DummyRender) JSONString(interface{}) (string, error) { + renderNotRegistered() + return "", nil +} + +func (r *DummyRender) RawData(int, []byte) { + renderNotRegistered() +} + +func (r *DummyRender) PlainText(int, []byte) { + renderNotRegistered() +} + +func (r *DummyRender) HTML(int, string, interface{}, ...HTMLOptions) { + renderNotRegistered() +} + +func (r *DummyRender) HTMLSet(int, string, string, interface{}, ...HTMLOptions) { + renderNotRegistered() +} + +func (r *DummyRender) HTMLSetString(string, string, interface{}, ...HTMLOptions) (string, error) { + renderNotRegistered() + return "", nil +} + +func (r *DummyRender) HTMLString(string, interface{}, ...HTMLOptions) (string, error) { + renderNotRegistered() + return "", nil +} + +func (r *DummyRender) HTMLSetBytes(string, string, interface{}, ...HTMLOptions) ([]byte, error) { + renderNotRegistered() + return nil, nil +} + +func (r *DummyRender) HTMLBytes(string, interface{}, ...HTMLOptions) ([]byte, error) { + renderNotRegistered() + return nil, nil +} + +func (r *DummyRender) XML(int, interface{}) { + renderNotRegistered() +} + +func (r *DummyRender) Error(int, ...string) { + renderNotRegistered() +} + +func (r *DummyRender) Status(int) { + renderNotRegistered() +} + +func (r *DummyRender) SetTemplatePath(string, string) { + renderNotRegistered() +} + +func (r *DummyRender) HasTemplateSet(string) bool { + renderNotRegistered() + return false +} diff --git a/vendor/gopkg.in/macaron.v1/response_writer.go b/vendor/gopkg.in/macaron.v1/response_writer.go new file mode 100644 index 000000000..eeb35f642 --- /dev/null +++ b/vendor/gopkg.in/macaron.v1/response_writer.go @@ -0,0 +1,124 @@ +// Copyright 2013 Martini Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"): you may +// not use this file except in compliance with the License. You may obtain +// a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. + +package macaron + +import ( + "bufio" + "errors" + "net" + "net/http" +) + +// ResponseWriter is a wrapper around http.ResponseWriter that provides extra information about +// the response. It is recommended that middleware handlers use this construct to wrap a responsewriter +// if the functionality calls for it. +type ResponseWriter interface { + http.ResponseWriter + http.Flusher + http.Pusher + // Status returns the status code of the response or 0 if the response has not been written. + Status() int + // Written returns whether or not the ResponseWriter has been written. + Written() bool + // Size returns the size of the response body. + Size() int + // Before allows for a function to be called before the ResponseWriter has been written to. This is + // useful for setting headers or any other operations that must happen before a response has been written. + Before(BeforeFunc) +} + +// BeforeFunc is a function that is called before the ResponseWriter has been written to. +type BeforeFunc func(ResponseWriter) + +// NewResponseWriter creates a ResponseWriter that wraps an http.ResponseWriter +func NewResponseWriter(method string, rw http.ResponseWriter) ResponseWriter { + return &responseWriter{method, rw, 0, 0, nil} +} + +type responseWriter struct { + method string + http.ResponseWriter + status int + size int + beforeFuncs []BeforeFunc +} + +func (rw *responseWriter) WriteHeader(s int) { + rw.callBefore() + rw.ResponseWriter.WriteHeader(s) + rw.status = s +} + +func (rw *responseWriter) Write(b []byte) (size int, err error) { + if !rw.Written() { + // The status will be StatusOK if WriteHeader has not been called yet + rw.WriteHeader(http.StatusOK) + } + if rw.method != "HEAD" { + size, err = rw.ResponseWriter.Write(b) + rw.size += size + } + return size, err +} + +func (rw *responseWriter) Status() int { + return rw.status +} + +func (rw *responseWriter) Size() int { + return rw.size +} + +func (rw *responseWriter) Written() bool { + return rw.status != 0 +} + +func (rw *responseWriter) Before(before BeforeFunc) { + rw.beforeFuncs = append(rw.beforeFuncs, before) +} + +func (rw *responseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) { + hijacker, ok := rw.ResponseWriter.(http.Hijacker) + if !ok { + return nil, nil, errors.New("the ResponseWriter doesn't support the Hijacker interface") + } + return hijacker.Hijack() +} + +//nolint +func (rw *responseWriter) CloseNotify() <-chan bool { + return rw.ResponseWriter.(http.CloseNotifier).CloseNotify() +} + +func (rw *responseWriter) callBefore() { + for i := len(rw.beforeFuncs) - 1; i >= 0; i-- { + rw.beforeFuncs[i](rw) + } +} + +func (rw *responseWriter) Flush() { + flusher, ok := rw.ResponseWriter.(http.Flusher) + if ok { + flusher.Flush() + } +} + +func (rw *responseWriter) Push(target string, opts *http.PushOptions) error { + pusher, ok := rw.ResponseWriter.(http.Pusher) + if !ok { + return errors.New("the ResponseWriter doesn't support the Pusher interface") + } + return pusher.Push(target, opts) +} diff --git a/vendor/gopkg.in/macaron.v1/return_handler.go b/vendor/gopkg.in/macaron.v1/return_handler.go new file mode 100644 index 000000000..33b7fd2be --- /dev/null +++ b/vendor/gopkg.in/macaron.v1/return_handler.go @@ -0,0 +1,76 @@ +// Copyright 2013 Martini Authors +// Copyright 2014 The Macaron Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"): you may +// not use this file except in compliance with the License. You may obtain +// a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. + +package macaron + +import ( + "net/http" + "reflect" + + "github.com/go-macaron/inject" +) + +// ReturnHandler is a service that Martini provides that is called +// when a route handler returns something. The ReturnHandler is +// responsible for writing to the ResponseWriter based on the values +// that are passed into this function. +type ReturnHandler func(*Context, []reflect.Value) + +func canDeref(val reflect.Value) bool { + return val.Kind() == reflect.Interface || val.Kind() == reflect.Ptr +} + +func isError(val reflect.Value) bool { + _, ok := val.Interface().(error) + return ok +} + +func isByteSlice(val reflect.Value) bool { + return val.Kind() == reflect.Slice && val.Type().Elem().Kind() == reflect.Uint8 +} + +func defaultReturnHandler() ReturnHandler { + return func(ctx *Context, vals []reflect.Value) { + rv := ctx.GetVal(inject.InterfaceOf((*http.ResponseWriter)(nil))) + resp := rv.Interface().(http.ResponseWriter) + var respVal reflect.Value + if len(vals) > 1 && vals[0].Kind() == reflect.Int { + resp.WriteHeader(int(vals[0].Int())) + respVal = vals[1] + } else if len(vals) > 0 { + respVal = vals[0] + + if isError(respVal) { + err := respVal.Interface().(error) + if err != nil { + ctx.internalServerError(ctx, err) + } + return + } else if canDeref(respVal) { + if respVal.IsNil() { + return // Ignore nil error + } + } + } + if canDeref(respVal) { + respVal = respVal.Elem() + } + if isByteSlice(respVal) { + _, _ = resp.Write(respVal.Bytes()) + } else { + _, _ = resp.Write([]byte(respVal.String())) + } + } +} diff --git a/vendor/gopkg.in/macaron.v1/router.go b/vendor/gopkg.in/macaron.v1/router.go new file mode 100644 index 000000000..df593d669 --- /dev/null +++ b/vendor/gopkg.in/macaron.v1/router.go @@ -0,0 +1,380 @@ +// Copyright 2014 The Macaron Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"): you may +// not use this file except in compliance with the License. You may obtain +// a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. + +package macaron + +import ( + "net/http" + "strings" + "sync" +) + +var ( + // Known HTTP methods. + _HTTP_METHODS = map[string]bool{ + "GET": true, + "POST": true, + "PUT": true, + "DELETE": true, + "PATCH": true, + "OPTIONS": true, + "HEAD": true, + } +) + +// routeMap represents a thread-safe map for route tree. +type routeMap struct { + lock sync.RWMutex + routes map[string]map[string]*Leaf +} + +// NewRouteMap initializes and returns a new routeMap. +func NewRouteMap() *routeMap { + rm := &routeMap{ + routes: make(map[string]map[string]*Leaf), + } + for m := range _HTTP_METHODS { + rm.routes[m] = make(map[string]*Leaf) + } + return rm +} + +// getLeaf returns Leaf object if a route has been registered. +func (rm *routeMap) getLeaf(method, pattern string) *Leaf { + rm.lock.RLock() + defer rm.lock.RUnlock() + + return rm.routes[method][pattern] +} + +// add adds new route to route tree map. +func (rm *routeMap) add(method, pattern string, leaf *Leaf) { + rm.lock.Lock() + defer rm.lock.Unlock() + + rm.routes[method][pattern] = leaf +} + +type group struct { + pattern string + handlers []Handler +} + +// Router represents a Macaron router layer. +type Router struct { + m *Macaron + autoHead bool + routers map[string]*Tree + *routeMap + namedRoutes map[string]*Leaf + + groups []group + notFound http.HandlerFunc + internalServerError func(*Context, error) + + // handlerWrapper is used to wrap arbitrary function from Handler to inject.FastInvoker. + handlerWrapper func(Handler) Handler +} + +func NewRouter() *Router { + return &Router{ + routers: make(map[string]*Tree), + routeMap: NewRouteMap(), + namedRoutes: make(map[string]*Leaf), + } +} + +// SetAutoHead sets the value who determines whether add HEAD method automatically +// when GET method is added. +func (r *Router) SetAutoHead(v bool) { + r.autoHead = v +} + +type Params map[string]string + +// Handle is a function that can be registered to a route to handle HTTP requests. +// Like http.HandlerFunc, but has a third parameter for the values of wildcards (variables). +type Handle func(http.ResponseWriter, *http.Request, Params) + +// Route represents a wrapper of leaf route and upper level router. +type Route struct { + router *Router + leaf *Leaf +} + +// Name sets name of route. +func (r *Route) Name(name string) { + if len(name) == 0 { + panic("route name cannot be empty") + } else if r.router.namedRoutes[name] != nil { + panic("route with given name already exists: " + name) + } + r.router.namedRoutes[name] = r.leaf +} + +// handle adds new route to the router tree. +func (r *Router) handle(method, pattern string, handle Handle) *Route { + method = strings.ToUpper(method) + + var leaf *Leaf + // Prevent duplicate routes. + if leaf = r.getLeaf(method, pattern); leaf != nil { + return &Route{r, leaf} + } + + // Validate HTTP methods. + if !_HTTP_METHODS[method] && method != "*" { + panic("unknown HTTP method: " + method) + } + + // Generate methods need register. + methods := make(map[string]bool) + if method == "*" { + for m := range _HTTP_METHODS { + methods[m] = true + } + } else { + methods[method] = true + } + + // Add to router tree. + for m := range methods { + if t, ok := r.routers[m]; ok { + leaf = t.Add(pattern, handle) + } else { + t := NewTree() + leaf = t.Add(pattern, handle) + r.routers[m] = t + } + r.add(m, pattern, leaf) + } + return &Route{r, leaf} +} + +// Handle registers a new request handle with the given pattern, method and handlers. +func (r *Router) Handle(method string, pattern string, handlers []Handler) *Route { + if len(r.groups) > 0 { + groupPattern := "" + h := make([]Handler, 0) + for _, g := range r.groups { + groupPattern += g.pattern + h = append(h, g.handlers...) + } + + pattern = groupPattern + pattern + h = append(h, handlers...) + handlers = h + } + handlers = validateAndWrapHandlers(handlers, r.handlerWrapper) + + return r.handle(method, pattern, func(resp http.ResponseWriter, req *http.Request, params Params) { + c := r.m.createContext(resp, req) + c.params = params + c.handlers = make([]Handler, 0, len(r.m.handlers)+len(handlers)) + c.handlers = append(c.handlers, r.m.handlers...) + c.handlers = append(c.handlers, handlers...) + c.run() + }) +} + +func (r *Router) Group(pattern string, fn func(), h ...Handler) { + r.groups = append(r.groups, group{pattern, h}) + fn() + r.groups = r.groups[:len(r.groups)-1] +} + +// Get is a shortcut for r.Handle("GET", pattern, handlers) +func (r *Router) Get(pattern string, h ...Handler) (leaf *Route) { + leaf = r.Handle("GET", pattern, h) + if r.autoHead { + r.Head(pattern, h...) + } + return leaf +} + +// Patch is a shortcut for r.Handle("PATCH", pattern, handlers) +func (r *Router) Patch(pattern string, h ...Handler) *Route { + return r.Handle("PATCH", pattern, h) +} + +// Post is a shortcut for r.Handle("POST", pattern, handlers) +func (r *Router) Post(pattern string, h ...Handler) *Route { + return r.Handle("POST", pattern, h) +} + +// Put is a shortcut for r.Handle("PUT", pattern, handlers) +func (r *Router) Put(pattern string, h ...Handler) *Route { + return r.Handle("PUT", pattern, h) +} + +// Delete is a shortcut for r.Handle("DELETE", pattern, handlers) +func (r *Router) Delete(pattern string, h ...Handler) *Route { + return r.Handle("DELETE", pattern, h) +} + +// Options is a shortcut for r.Handle("OPTIONS", pattern, handlers) +func (r *Router) Options(pattern string, h ...Handler) *Route { + return r.Handle("OPTIONS", pattern, h) +} + +// Head is a shortcut for r.Handle("HEAD", pattern, handlers) +func (r *Router) Head(pattern string, h ...Handler) *Route { + return r.Handle("HEAD", pattern, h) +} + +// Any is a shortcut for r.Handle("*", pattern, handlers) +func (r *Router) Any(pattern string, h ...Handler) *Route { + return r.Handle("*", pattern, h) +} + +// Route is a shortcut for same handlers but different HTTP methods. +// +// Example: +// m.Route("/", "GET,POST", h) +func (r *Router) Route(pattern, methods string, h ...Handler) (route *Route) { + for _, m := range strings.Split(methods, ",") { + route = r.Handle(strings.TrimSpace(m), pattern, h) + } + return route +} + +// Combo returns a combo router. +func (r *Router) Combo(pattern string, h ...Handler) *ComboRouter { + return &ComboRouter{r, pattern, h, map[string]bool{}, nil} +} + +// NotFound configurates http.HandlerFunc which is called when no matching route is +// found. If it is not set, http.NotFound is used. +// Be sure to set 404 response code in your handler. +func (r *Router) NotFound(handlers ...Handler) { + handlers = validateAndWrapHandlers(handlers) + r.notFound = func(rw http.ResponseWriter, req *http.Request) { + c := r.m.createContext(rw, req) + c.handlers = make([]Handler, 0, len(r.m.handlers)+len(handlers)) + c.handlers = append(c.handlers, r.m.handlers...) + c.handlers = append(c.handlers, handlers...) + c.run() + } +} + +// InternalServerError configurates handler which is called when route handler returns +// error. If it is not set, default handler is used. +// Be sure to set 500 response code in your handler. +func (r *Router) InternalServerError(handlers ...Handler) { + handlers = validateAndWrapHandlers(handlers) + r.internalServerError = func(c *Context, err error) { + c.index = 0 + c.handlers = handlers + c.Map(err) + c.run() + } +} + +// SetHandlerWrapper sets handlerWrapper for the router. +func (r *Router) SetHandlerWrapper(f func(Handler) Handler) { + r.handlerWrapper = f +} + +func (r *Router) ServeHTTP(rw http.ResponseWriter, req *http.Request) { + if t, ok := r.routers[req.Method]; ok { + // Fast match for static routes + leaf := r.getLeaf(req.Method, req.URL.Path) + if leaf != nil { + leaf.handle(rw, req, nil) + return + } + + h, p, ok := t.Match(req.URL.EscapedPath()) + if ok { + if splat, ok := p["*0"]; ok { + p["*"] = splat // Easy name. + } + h(rw, req, p) + return + } + } + + r.notFound(rw, req) +} + +// URLFor builds path part of URL by given pair values. +func (r *Router) URLFor(name string, pairs ...string) string { + leaf, ok := r.namedRoutes[name] + if !ok { + panic("route with given name does not exists: " + name) + } + return leaf.URLPath(pairs...) +} + +// ComboRouter represents a combo router. +type ComboRouter struct { + router *Router + pattern string + handlers []Handler + methods map[string]bool // Registered methods. + + lastRoute *Route +} + +func (cr *ComboRouter) checkMethod(name string) { + if cr.methods[name] { + panic("method '" + name + "' has already been registered") + } + cr.methods[name] = true +} + +func (cr *ComboRouter) route(fn func(string, ...Handler) *Route, method string, h ...Handler) *ComboRouter { + cr.checkMethod(method) + cr.lastRoute = fn(cr.pattern, append(cr.handlers, h...)...) + return cr +} + +func (cr *ComboRouter) Get(h ...Handler) *ComboRouter { + if cr.router.autoHead { + cr.Head(h...) + } + return cr.route(cr.router.Get, "GET", h...) +} + +func (cr *ComboRouter) Patch(h ...Handler) *ComboRouter { + return cr.route(cr.router.Patch, "PATCH", h...) +} + +func (cr *ComboRouter) Post(h ...Handler) *ComboRouter { + return cr.route(cr.router.Post, "POST", h...) +} + +func (cr *ComboRouter) Put(h ...Handler) *ComboRouter { + return cr.route(cr.router.Put, "PUT", h...) +} + +func (cr *ComboRouter) Delete(h ...Handler) *ComboRouter { + return cr.route(cr.router.Delete, "DELETE", h...) +} + +func (cr *ComboRouter) Options(h ...Handler) *ComboRouter { + return cr.route(cr.router.Options, "OPTIONS", h...) +} + +func (cr *ComboRouter) Head(h ...Handler) *ComboRouter { + return cr.route(cr.router.Head, "HEAD", h...) +} + +// Name sets name of ComboRouter route. +func (cr *ComboRouter) Name(name string) { + if cr.lastRoute == nil { + panic("no corresponding route to be named") + } + cr.lastRoute.Name(name) +} diff --git a/vendor/gopkg.in/macaron.v1/static.go b/vendor/gopkg.in/macaron.v1/static.go new file mode 100644 index 000000000..f1c0c75af --- /dev/null +++ b/vendor/gopkg.in/macaron.v1/static.go @@ -0,0 +1,230 @@ +// Copyright 2013 Martini Authors +// Copyright 2014 The Macaron Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"): you may +// not use this file except in compliance with the License. You may obtain +// a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. + +package macaron + +import ( + "encoding/base64" + "log" + "net/http" + "path" + "path/filepath" + "strings" + "sync" +) + +// StaticOptions is a struct for specifying configuration options for the macaron.Static middleware. +type StaticOptions struct { + // Prefix is the optional prefix used to serve the static directory content + Prefix string + // SkipLogging will disable [Static] log messages when a static file is served. + SkipLogging bool + // IndexFile defines which file to serve as index if it exists. + IndexFile string + // Expires defines which user-defined function to use for producing a HTTP Expires Header + // https://developers.google.com/speed/docs/insights/LeverageBrowserCaching + Expires func() string + // ETag defines if we should add an ETag header + // https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/http-caching#validating-cached-responses-with-etags + ETag bool + // FileSystem is the interface for supporting any implmentation of file system. + FileSystem http.FileSystem +} + +// FIXME: to be deleted. +type staticMap struct { + lock sync.RWMutex + data map[string]*http.Dir +} + +func (sm *staticMap) Set(dir *http.Dir) { + sm.lock.Lock() + defer sm.lock.Unlock() + + sm.data[string(*dir)] = dir +} + +func (sm *staticMap) Get(name string) *http.Dir { + sm.lock.RLock() + defer sm.lock.RUnlock() + + return sm.data[name] +} + +func (sm *staticMap) Delete(name string) { + sm.lock.Lock() + defer sm.lock.Unlock() + + delete(sm.data, name) +} + +var statics = staticMap{sync.RWMutex{}, map[string]*http.Dir{}} + +// staticFileSystem implements http.FileSystem interface. +type staticFileSystem struct { + dir *http.Dir +} + +func newStaticFileSystem(directory string) staticFileSystem { + if !filepath.IsAbs(directory) { + directory = filepath.Join(Root, directory) + } + dir := http.Dir(directory) + statics.Set(&dir) + return staticFileSystem{&dir} +} + +func (fs staticFileSystem) Open(name string) (http.File, error) { + return fs.dir.Open(name) +} + +func prepareStaticOption(dir string, opt StaticOptions) StaticOptions { + // Defaults + if len(opt.IndexFile) == 0 { + opt.IndexFile = "index.html" + } + // Normalize the prefix if provided + if opt.Prefix != "" { + // Ensure we have a leading '/' + if opt.Prefix[0] != '/' { + opt.Prefix = "/" + opt.Prefix + } + // Remove any trailing '/' + opt.Prefix = strings.TrimRight(opt.Prefix, "/") + } + if opt.FileSystem == nil { + opt.FileSystem = newStaticFileSystem(dir) + } + return opt +} + +func prepareStaticOptions(dir string, options []StaticOptions) StaticOptions { + var opt StaticOptions + if len(options) > 0 { + opt = options[0] + } + return prepareStaticOption(dir, opt) +} + +func staticHandler(ctx *Context, log *log.Logger, opt StaticOptions) bool { + if ctx.Req.Method != "GET" && ctx.Req.Method != "HEAD" { + return false + } + + file := ctx.Req.URL.Path + // if we have a prefix, filter requests by stripping the prefix + if opt.Prefix != "" { + if !strings.HasPrefix(file, opt.Prefix) { + return false + } + file = file[len(opt.Prefix):] + if file != "" && file[0] != '/' { + return false + } + } + + f, err := opt.FileSystem.Open(file) + if err != nil { + return false + } + defer f.Close() + + fi, err := f.Stat() + if err != nil { + return true // File exists but fail to open. + } + + // Try to serve index file + if fi.IsDir() { + redirPath := path.Clean(ctx.Req.URL.Path) + // path.Clean removes the trailing slash, so we need to add it back when + // the original path has it. + if strings.HasSuffix(ctx.Req.URL.Path, "/") { + redirPath = redirPath + "/" + } + // Redirect if missing trailing slash. + if !strings.HasSuffix(redirPath, "/") { + http.Redirect(ctx.Resp, ctx.Req.Request, redirPath+"/", http.StatusFound) + return true + } + + file = path.Join(file, opt.IndexFile) + f, err = opt.FileSystem.Open(file) + if err != nil { + return false // Discard error. + } + defer f.Close() + + fi, err = f.Stat() + if err != nil || fi.IsDir() { + return true + } + } + + if !opt.SkipLogging { + log.Println("[Static] Serving " + file) + } + + // Add an Expires header to the static content + if opt.Expires != nil { + ctx.Resp.Header().Set("Expires", opt.Expires()) + } + + if opt.ETag { + tag := `"` + GenerateETag(string(fi.Size()), fi.Name(), fi.ModTime().UTC().Format(http.TimeFormat)) + `"` + ctx.Resp.Header().Set("ETag", tag) + if ctx.Req.Header.Get("If-None-Match") == tag { + ctx.Resp.WriteHeader(http.StatusNotModified) + return true + } + } + + http.ServeContent(ctx.Resp, ctx.Req.Request, file, fi.ModTime(), f) + return true +} + +// GenerateETag generates an ETag based on size, filename and file modification time +func GenerateETag(fileSize, fileName, modTime string) string { + etag := fileSize + fileName + modTime + return base64.StdEncoding.EncodeToString([]byte(etag)) +} + +// Static returns a middleware handler that serves static files in the given directory. +func Static(directory string, staticOpt ...StaticOptions) Handler { + opt := prepareStaticOptions(directory, staticOpt) + + return func(ctx *Context, log *log.Logger) { + staticHandler(ctx, log, opt) + } +} + +// Statics registers multiple static middleware handlers all at once. +func Statics(opt StaticOptions, dirs ...string) Handler { + if len(dirs) == 0 { + panic("no static directory is given") + } + opts := make([]StaticOptions, len(dirs)) + for i := range dirs { + opts[i] = prepareStaticOption(dirs[i], opt) + } + + return func(ctx *Context, log *log.Logger) { + for i := range opts { + if staticHandler(ctx, log, opts[i]) { + return + } + } + } +} diff --git a/vendor/gopkg.in/macaron.v1/tree.go b/vendor/gopkg.in/macaron.v1/tree.go new file mode 100644 index 000000000..0ab094dd6 --- /dev/null +++ b/vendor/gopkg.in/macaron.v1/tree.go @@ -0,0 +1,390 @@ +// Copyright 2015 The Macaron Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"): you may +// not use this file except in compliance with the License. You may obtain +// a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. + +package macaron + +import ( + "regexp" + "strings" + + "github.com/unknwon/com" +) + +type patternType int8 + +const ( + _PATTERN_STATIC patternType = iota // /home + _PATTERN_REGEXP // /:id([0-9]+) + _PATTERN_PATH_EXT // /*.* + _PATTERN_HOLDER // /:user + _PATTERN_MATCH_ALL // /* +) + +// Leaf represents a leaf route information. +type Leaf struct { + parent *Tree + + typ patternType + pattern string + rawPattern string // Contains wildcard instead of regexp + wildcards []string + reg *regexp.Regexp + optional bool + + handle Handle +} + +var wildcardPattern = regexp.MustCompile(`:[a-zA-Z0-9]+`) + +func isSpecialRegexp(pattern, regStr string, pos []int) bool { + return len(pattern) >= pos[1]+len(regStr) && pattern[pos[1]:pos[1]+len(regStr)] == regStr +} + +// getNextWildcard tries to find next wildcard and update pattern with corresponding regexp. +func getNextWildcard(pattern string) (wildcard, _ string) { + pos := wildcardPattern.FindStringIndex(pattern) + if pos == nil { + return "", pattern + } + wildcard = pattern[pos[0]:pos[1]] + + // Reach last character or no regexp is given. + if len(pattern) == pos[1] { + return wildcard, strings.Replace(pattern, wildcard, `(.+)`, 1) + } else if pattern[pos[1]] != '(' { + switch { + case isSpecialRegexp(pattern, ":int", pos): + pattern = strings.Replace(pattern, ":int", "([0-9]+)", 1) + case isSpecialRegexp(pattern, ":string", pos): + pattern = strings.Replace(pattern, ":string", "([\\w]+)", 1) + default: + return wildcard, strings.Replace(pattern, wildcard, `(.+)`, 1) + } + } + + // Cut out placeholder directly. + return wildcard, pattern[:pos[0]] + pattern[pos[1]:] +} + +func getWildcards(pattern string) (string, []string) { + wildcards := make([]string, 0, 2) + + // Keep getting next wildcard until nothing is left. + var wildcard string + for { + wildcard, pattern = getNextWildcard(pattern) + if len(wildcard) > 0 { + wildcards = append(wildcards, wildcard) + } else { + break + } + } + + return pattern, wildcards +} + +// getRawPattern removes all regexp but keeps wildcards for building URL path. +func getRawPattern(rawPattern string) string { + rawPattern = strings.Replace(rawPattern, ":int", "", -1) + rawPattern = strings.Replace(rawPattern, ":string", "", -1) + + for { + startIdx := strings.Index(rawPattern, "(") + if startIdx == -1 { + break + } + + closeIdx := strings.Index(rawPattern, ")") + if closeIdx > -1 { + rawPattern = rawPattern[:startIdx] + rawPattern[closeIdx+1:] + } + } + return rawPattern +} + +func checkPattern(pattern string) (typ patternType, rawPattern string, wildcards []string, reg *regexp.Regexp) { + pattern = strings.TrimLeft(pattern, "?") + rawPattern = getRawPattern(pattern) + + if pattern == "*" { + typ = _PATTERN_MATCH_ALL + } else if pattern == "*.*" { + typ = _PATTERN_PATH_EXT + } else if strings.Contains(pattern, ":") { + typ = _PATTERN_REGEXP + pattern, wildcards = getWildcards(pattern) + if pattern == "(.+)" { + typ = _PATTERN_HOLDER + } else { + reg = regexp.MustCompile(pattern) + } + } + return typ, rawPattern, wildcards, reg +} + +func NewLeaf(parent *Tree, pattern string, handle Handle) *Leaf { + typ, rawPattern, wildcards, reg := checkPattern(pattern) + optional := false + if len(pattern) > 0 && pattern[0] == '?' { + optional = true + } + return &Leaf{parent, typ, pattern, rawPattern, wildcards, reg, optional, handle} +} + +// URLPath build path part of URL by given pair values. +func (l *Leaf) URLPath(pairs ...string) string { + if len(pairs)%2 != 0 { + panic("number of pairs does not match") + } + + urlPath := l.rawPattern + parent := l.parent + for parent != nil { + urlPath = parent.rawPattern + "/" + urlPath + parent = parent.parent + } + for i := 0; i < len(pairs); i += 2 { + if len(pairs[i]) == 0 { + panic("pair value cannot be empty: " + com.ToStr(i)) + } else if pairs[i][0] != ':' && pairs[i] != "*" && pairs[i] != "*.*" { + pairs[i] = ":" + pairs[i] + } + urlPath = strings.Replace(urlPath, pairs[i], pairs[i+1], 1) + } + return urlPath +} + +// Tree represents a router tree in Macaron. +type Tree struct { + parent *Tree + + typ patternType + pattern string + rawPattern string + wildcards []string + reg *regexp.Regexp + + subtrees []*Tree + leaves []*Leaf +} + +func NewSubtree(parent *Tree, pattern string) *Tree { + typ, rawPattern, wildcards, reg := checkPattern(pattern) + return &Tree{parent, typ, pattern, rawPattern, wildcards, reg, make([]*Tree, 0, 5), make([]*Leaf, 0, 5)} +} + +func NewTree() *Tree { + return NewSubtree(nil, "") +} + +func (t *Tree) addLeaf(pattern string, handle Handle) *Leaf { + for i := 0; i < len(t.leaves); i++ { + if t.leaves[i].pattern == pattern { + return t.leaves[i] + } + } + + leaf := NewLeaf(t, pattern, handle) + + // Add exact same leaf to grandparent/parent level without optional. + if leaf.optional { + parent := leaf.parent + if parent.parent != nil { + parent.parent.addLeaf(parent.pattern, handle) + } else { + parent.addLeaf("", handle) // Root tree can add as empty pattern. + } + } + + i := 0 + for ; i < len(t.leaves); i++ { + if leaf.typ < t.leaves[i].typ { + break + } + } + + if i == len(t.leaves) { + t.leaves = append(t.leaves, leaf) + } else { + t.leaves = append(t.leaves[:i], append([]*Leaf{leaf}, t.leaves[i:]...)...) + } + return leaf +} + +func (t *Tree) addSubtree(segment, pattern string, handle Handle) *Leaf { + for i := 0; i < len(t.subtrees); i++ { + if t.subtrees[i].pattern == segment { + return t.subtrees[i].addNextSegment(pattern, handle) + } + } + + subtree := NewSubtree(t, segment) + i := 0 + for ; i < len(t.subtrees); i++ { + if subtree.typ < t.subtrees[i].typ { + break + } + } + + if i == len(t.subtrees) { + t.subtrees = append(t.subtrees, subtree) + } else { + t.subtrees = append(t.subtrees[:i], append([]*Tree{subtree}, t.subtrees[i:]...)...) + } + return subtree.addNextSegment(pattern, handle) +} + +func (t *Tree) addNextSegment(pattern string, handle Handle) *Leaf { + pattern = strings.TrimPrefix(pattern, "/") + + i := strings.Index(pattern, "/") + if i == -1 { + return t.addLeaf(pattern, handle) + } + return t.addSubtree(pattern[:i], pattern[i+1:], handle) +} + +func (t *Tree) Add(pattern string, handle Handle) *Leaf { + pattern = strings.TrimSuffix(pattern, "/") + return t.addNextSegment(pattern, handle) +} + +func (t *Tree) matchLeaf(globLevel int, url string, params Params) (Handle, bool) { + url, err := PathUnescape(url) + if err != nil { + return nil, false + } + for i := 0; i < len(t.leaves); i++ { + switch t.leaves[i].typ { + case _PATTERN_STATIC: + if t.leaves[i].pattern == url { + return t.leaves[i].handle, true + } + case _PATTERN_REGEXP: + results := t.leaves[i].reg.FindStringSubmatch(url) + // Number of results and wildcasrd should be exact same. + if len(results)-1 != len(t.leaves[i].wildcards) { + break + } + + for j := 0; j < len(t.leaves[i].wildcards); j++ { + params[t.leaves[i].wildcards[j]] = results[j+1] + } + return t.leaves[i].handle, true + case _PATTERN_PATH_EXT: + j := strings.LastIndex(url, ".") + if j > -1 { + params[":path"] = url[:j] + params[":ext"] = url[j+1:] + } else { + params[":path"] = url + } + return t.leaves[i].handle, true + case _PATTERN_HOLDER: + params[t.leaves[i].wildcards[0]] = url + return t.leaves[i].handle, true + case _PATTERN_MATCH_ALL: + params["*"] = url + params["*"+com.ToStr(globLevel)] = url + return t.leaves[i].handle, true + } + } + return nil, false +} + +func (t *Tree) matchSubtree(globLevel int, segment, url string, params Params) (Handle, bool) { + unescapedSegment, err := PathUnescape(segment) + if err != nil { + return nil, false + } + for i := 0; i < len(t.subtrees); i++ { + switch t.subtrees[i].typ { + case _PATTERN_STATIC: + if t.subtrees[i].pattern == unescapedSegment { + if handle, ok := t.subtrees[i].matchNextSegment(globLevel, url, params); ok { + return handle, true + } + } + case _PATTERN_REGEXP: + results := t.subtrees[i].reg.FindStringSubmatch(unescapedSegment) + if len(results)-1 != len(t.subtrees[i].wildcards) { + break + } + + for j := 0; j < len(t.subtrees[i].wildcards); j++ { + params[t.subtrees[i].wildcards[j]] = results[j+1] + } + if handle, ok := t.subtrees[i].matchNextSegment(globLevel, url, params); ok { + return handle, true + } + case _PATTERN_HOLDER: + if handle, ok := t.subtrees[i].matchNextSegment(globLevel+1, url, params); ok { + params[t.subtrees[i].wildcards[0]] = unescapedSegment + return handle, true + } + case _PATTERN_MATCH_ALL: + if handle, ok := t.subtrees[i].matchNextSegment(globLevel+1, url, params); ok { + params["*"+com.ToStr(globLevel)] = unescapedSegment + return handle, true + } + } + } + + if len(t.leaves) > 0 { + leaf := t.leaves[len(t.leaves)-1] + unescapedURL, err := PathUnescape(segment + "/" + url) + if err != nil { + return nil, false + } + if leaf.typ == _PATTERN_PATH_EXT { + j := strings.LastIndex(unescapedURL, ".") + if j > -1 { + params[":path"] = unescapedURL[:j] + params[":ext"] = unescapedURL[j+1:] + } else { + params[":path"] = unescapedURL + } + return leaf.handle, true + } else if leaf.typ == _PATTERN_MATCH_ALL { + params["*"] = unescapedURL + params["*"+com.ToStr(globLevel)] = unescapedURL + return leaf.handle, true + } + } + return nil, false +} + +func (t *Tree) matchNextSegment(globLevel int, url string, params Params) (Handle, bool) { + i := strings.Index(url, "/") + if i == -1 { + return t.matchLeaf(globLevel, url, params) + } + return t.matchSubtree(globLevel, url[:i], url[i+1:], params) +} + +func (t *Tree) Match(url string) (Handle, Params, bool) { + url = strings.TrimPrefix(url, "/") + url = strings.TrimSuffix(url, "/") + params := make(Params) + handle, ok := t.matchNextSegment(0, url, params) + return handle, params, ok +} + +// MatchTest returns true if given URL is matched by given pattern. +func MatchTest(pattern, url string) bool { + t := NewTree() + t.Add(pattern, nil) + _, _, ok := t.Match(url) + return ok +} diff --git a/vendor/gopkg.in/macaron.v1/util_go17.go b/vendor/gopkg.in/macaron.v1/util_go17.go new file mode 100644 index 000000000..a80c696c7 --- /dev/null +++ b/vendor/gopkg.in/macaron.v1/util_go17.go @@ -0,0 +1,25 @@ +// +build !go1.8 + +// Copyright 2017 The Macaron Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"): you may +// not use this file except in compliance with the License. You may obtain +// a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. + +package macaron + +import "net/url" + +// PathUnescape unescapes a path. Ideally, this function would use +// url.PathUnescape(..), but the function was not introduced until go1.8. +func PathUnescape(s string) (string, error) { + return url.QueryUnescape(s) +} diff --git a/vendor/gopkg.in/macaron.v1/util_go18.go b/vendor/gopkg.in/macaron.v1/util_go18.go new file mode 100644 index 000000000..d5eb1dfb2 --- /dev/null +++ b/vendor/gopkg.in/macaron.v1/util_go18.go @@ -0,0 +1,24 @@ +// +build go1.8 + +// Copyright 2017 The Macaron Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"): you may +// not use this file except in compliance with the License. You may obtain +// a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. + +package macaron + +import "net/url" + +// PathUnescape unescapes a path. +func PathUnescape(s string) (string, error) { + return url.PathUnescape(s) +} diff --git a/vendor/modules.txt b/vendor/modules.txt index 8f60c2382..b0360e8ed 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -1,5 +1,4 @@ # cloud.google.com/go v0.45.0 -## explicit cloud.google.com/go/compute/metadata cloud.google.com/go/iam cloud.google.com/go/internal/optional @@ -8,43 +7,31 @@ cloud.google.com/go/pubsub cloud.google.com/go/pubsub/apiv1 cloud.google.com/go/pubsub/internal/distribution # gitea.com/jolheiser/gitea-vet v0.1.0 -## explicit gitea.com/jolheiser/gitea-vet gitea.com/jolheiser/gitea-vet/checks # gitea.com/lunny/levelqueue v0.3.0 -## explicit gitea.com/lunny/levelqueue # gitea.com/macaron/binding v0.0.0-20190822013154-a5f53841ed2b -## explicit gitea.com/macaron/binding # gitea.com/macaron/cache v0.0.0-20190822004001-a6e7fee4ee76 -## explicit gitea.com/macaron/cache gitea.com/macaron/cache/memcache gitea.com/macaron/cache/redis # gitea.com/macaron/captcha v0.0.0-20190822015246-daa973478bae -## explicit gitea.com/macaron/captcha # gitea.com/macaron/cors v0.0.0-20190826180238-95aec09ea8b4 -## explicit gitea.com/macaron/cors # gitea.com/macaron/csrf v0.0.0-20190822024205-3dc5a4474439 -## explicit gitea.com/macaron/csrf # gitea.com/macaron/gzip v0.0.0-20191118041502-506895b47aae -## explicit gitea.com/macaron/gzip # gitea.com/macaron/i18n v0.0.0-20190822004228-474e714e2223 -## explicit gitea.com/macaron/i18n # gitea.com/macaron/inject v0.0.0-20190805023432-d4c86e31027a -## explicit gitea.com/macaron/inject # gitea.com/macaron/macaron v1.4.0 -## explicit gitea.com/macaron/macaron # gitea.com/macaron/session v0.0.0-20191207215012-613cebf0674d -## explicit gitea.com/macaron/session gitea.com/macaron/session/couchbase gitea.com/macaron/session/memcache @@ -53,13 +40,10 @@ gitea.com/macaron/session/nodb gitea.com/macaron/session/postgres gitea.com/macaron/session/redis # gitea.com/macaron/toolbox v0.0.0-20190822013122-05ff0fc766b7 -## explicit gitea.com/macaron/toolbox # github.com/BurntSushi/toml v0.3.1 -## explicit github.com/BurntSushi/toml # github.com/PuerkitoBio/goquery v1.5.0 -## explicit github.com/PuerkitoBio/goquery # github.com/PuerkitoBio/purell v1.1.1 github.com/PuerkitoBio/purell @@ -68,7 +52,6 @@ github.com/PuerkitoBio/urlesc # github.com/RichardKnop/logging v0.0.0-20181101035820-b1d5d44c82d6 github.com/RichardKnop/logging # github.com/RichardKnop/machinery v1.6.9 -## explicit github.com/RichardKnop/machinery/v1 github.com/RichardKnop/machinery/v1/backends/amqp github.com/RichardKnop/machinery/v1/backends/dynamodb @@ -95,7 +78,6 @@ github.com/RichardKnop/machinery/v1/tracing # github.com/RichardKnop/redsync v1.2.0 github.com/RichardKnop/redsync # github.com/RoaringBitmap/roaring v0.4.23 -## explicit github.com/RoaringBitmap/roaring # github.com/andybalholm/cascadia v1.0.0 github.com/andybalholm/cascadia @@ -147,10 +129,7 @@ github.com/aws/aws-sdk-go/service/sts/stsiface github.com/aymerick/douceur/css # github.com/beorn7/perks v1.0.1 github.com/beorn7/perks/quantile -# github.com/bgentry/speakeasy v0.1.0 -## explicit # github.com/blevesearch/bleve v1.0.7 -## explicit github.com/blevesearch/bleve github.com/blevesearch/bleve/analysis github.com/blevesearch/bleve/analysis/analyzer/custom @@ -212,7 +191,6 @@ github.com/bradfitz/gomemcache/memcache # github.com/chris-ramon/douceur v0.2.0 github.com/chris-ramon/douceur/parser # github.com/couchbase/gomemcached v0.0.0-20191004160342-7b5da2ec40b2 -## explicit github.com/couchbase/gomemcached github.com/couchbase/gomemcached/client # github.com/couchbase/goutils v0.0.0-20191018232750-b49639060d85 @@ -227,31 +205,20 @@ github.com/couchbase/vellum/utf8 github.com/couchbaselabs/go-couchbase # github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d github.com/cpuguy83/go-md2man/v2/md2man -# github.com/cznic/b v0.0.0-20181122101859-a26611c4d92d -## explicit -# github.com/cznic/mathutil v0.0.0-20181122101859-297441e03548 -## explicit -# github.com/cznic/strutil v0.0.0-20181122101858-275e90344537 -## explicit # github.com/davecgh/go-spew v1.1.1 github.com/davecgh/go-spew/spew # github.com/denisenkom/go-mssqldb v0.0.0-20200428022330-06a60b6afbbc -## explicit github.com/denisenkom/go-mssqldb github.com/denisenkom/go-mssqldb/internal/cp github.com/denisenkom/go-mssqldb/internal/decimal github.com/denisenkom/go-mssqldb/internal/querytext # github.com/dgrijalva/jwt-go v3.2.0+incompatible -## explicit github.com/dgrijalva/jwt-go # github.com/dustin/go-humanize v1.0.0 -## explicit github.com/dustin/go-humanize # github.com/editorconfig/editorconfig-core-go/v2 v2.1.1 -## explicit github.com/editorconfig/editorconfig-core-go/v2 # github.com/emirpasic/gods v1.12.0 -## explicit github.com/emirpasic/gods/containers github.com/emirpasic/gods/lists github.com/emirpasic/gods/lists/arraylist @@ -259,14 +226,7 @@ github.com/emirpasic/gods/trees github.com/emirpasic/gods/trees/binaryheap github.com/emirpasic/gods/utils # github.com/ethantkoenig/rupture v0.0.0-20180203182544-0a76f03a811a -## explicit github.com/ethantkoenig/rupture -# github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51 -## explicit -# github.com/facebookgo/stack v0.0.0-20160209184415-751773369052 -## explicit -# github.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870 -## explicit # github.com/fatih/color v1.9.0 github.com/fatih/color # github.com/fatih/structtag v1.2.0 @@ -274,13 +234,10 @@ github.com/fatih/structtag # github.com/fsnotify/fsnotify v1.4.7 github.com/fsnotify/fsnotify # github.com/gliderlabs/ssh v0.2.2 -## explicit github.com/gliderlabs/ssh # github.com/glycerine/go-unsnap-stream v0.0.0-20190901134440-81cf024a9e0a -## explicit github.com/glycerine/go-unsnap-stream # github.com/go-enry/go-enry/v2 v2.3.0 -## explicit github.com/go-enry/go-enry/v2 github.com/go-enry/go-enry/v2/data github.com/go-enry/go-enry/v2/data/rule @@ -295,14 +252,12 @@ github.com/go-git/gcfg/scanner github.com/go-git/gcfg/token github.com/go-git/gcfg/types # github.com/go-git/go-billy/v5 v5.0.0 -## explicit github.com/go-git/go-billy/v5 github.com/go-git/go-billy/v5/helper/chroot github.com/go-git/go-billy/v5/helper/polyfill github.com/go-git/go-billy/v5/osfs github.com/go-git/go-billy/v5/util # github.com/go-git/go-git/v5 v5.0.0 -## explicit github.com/go-git/go-git/v5 github.com/go-git/go-git/v5/config github.com/go-git/go-git/v5/internal/revision @@ -347,8 +302,11 @@ github.com/go-git/go-git/v5/utils/merkletrie/index github.com/go-git/go-git/v5/utils/merkletrie/internal/frame github.com/go-git/go-git/v5/utils/merkletrie/noder # github.com/go-ini/ini v1.56.0 -## explicit github.com/go-ini/ini +# github.com/go-macaron/auth v0.0.0-20161228062157-884c0e6c9b92 +github.com/go-macaron/auth +# github.com/go-macaron/inject v0.0.0-20160627170012-d8a0b8677191 +github.com/go-macaron/inject # github.com/go-openapi/analysis v0.19.5 github.com/go-openapi/analysis github.com/go-openapi/analysis/internal @@ -359,7 +317,6 @@ github.com/go-openapi/inflect # github.com/go-openapi/jsonpointer v0.19.3 github.com/go-openapi/jsonpointer # github.com/go-openapi/jsonreference v0.19.3 -## explicit github.com/go-openapi/jsonreference # github.com/go-openapi/loads v0.19.3 github.com/go-openapi/loads @@ -381,7 +338,6 @@ github.com/go-openapi/swag # github.com/go-openapi/validate v0.19.3 github.com/go-openapi/validate # github.com/go-redis/redis v6.15.2+incompatible -## explicit github.com/go-redis/redis github.com/go-redis/redis/internal github.com/go-redis/redis/internal/consistenthash @@ -390,15 +346,12 @@ github.com/go-redis/redis/internal/pool github.com/go-redis/redis/internal/proto github.com/go-redis/redis/internal/util # github.com/go-resty/resty/v2 v2.3.0 -## explicit github.com/go-resty/resty/v2 # github.com/go-sql-driver/mysql v1.4.1 -## explicit github.com/go-sql-driver/mysql # github.com/go-stack/stack v1.8.0 github.com/go-stack/stack # github.com/go-swagger/go-swagger v0.21.0 -## explicit github.com/go-swagger/go-swagger/cmd/swagger github.com/go-swagger/go-swagger/cmd/swagger/commands github.com/go-swagger/go-swagger/cmd/swagger/commands/diff @@ -408,7 +361,6 @@ github.com/go-swagger/go-swagger/codescan github.com/go-swagger/go-swagger/generator github.com/go-swagger/go-swagger/scan # github.com/gobwas/glob v0.2.3 -## explicit github.com/gobwas/glob github.com/gobwas/glob/compiler github.com/gobwas/glob/match @@ -418,17 +370,14 @@ github.com/gobwas/glob/syntax/lexer github.com/gobwas/glob/util/runes github.com/gobwas/glob/util/strings # github.com/gogs/chardet v0.0.0-20191104214054-4b6791f73a28 -## explicit github.com/gogs/chardet # github.com/gogs/cron v0.0.0-20171120032916-9f6c956d3e14 -## explicit github.com/gogs/cron # github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe github.com/golang-sql/civil # github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6 github.com/golang/groupcache/lru # github.com/golang/protobuf v1.4.1 -## explicit github.com/golang/protobuf/proto github.com/golang/protobuf/protoc-gen-go/descriptor github.com/golang/protobuf/ptypes @@ -442,7 +391,6 @@ github.com/golang/snappy github.com/gomodule/redigo/internal github.com/gomodule/redigo/redis # github.com/google/go-github/v24 v24.0.1 -## explicit github.com/google/go-github/v24/github # github.com/google/go-querystring v1.0.0 github.com/google/go-querystring/query @@ -451,7 +399,6 @@ github.com/google/uuid # github.com/googleapis/gax-go/v2 v2.0.5 github.com/googleapis/gax-go/v2 # github.com/gorilla/context v1.1.1 -## explicit github.com/gorilla/context # github.com/gorilla/css v1.0.0 github.com/gorilla/css/scanner @@ -466,7 +413,6 @@ github.com/gorilla/sessions # github.com/hashicorp/go-cleanhttp v0.5.1 github.com/hashicorp/go-cleanhttp # github.com/hashicorp/go-retryablehttp v0.6.6 -## explicit github.com/hashicorp/go-retryablehttp # github.com/hashicorp/hcl v1.0.0 github.com/hashicorp/hcl @@ -480,15 +426,10 @@ github.com/hashicorp/hcl/json/parser github.com/hashicorp/hcl/json/scanner github.com/hashicorp/hcl/json/token # github.com/huandu/xstrings v1.3.0 -## explicit github.com/huandu/xstrings -# github.com/issue9/assert v1.3.2 -## explicit # github.com/issue9/identicon v1.0.1 -## explicit github.com/issue9/identicon # github.com/jaytaylor/html2text v0.0.0-20160923191438-8fb95d837f7d -## explicit github.com/jaytaylor/html2text # github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 github.com/jbenet/go-context/io @@ -496,21 +437,15 @@ github.com/jbenet/go-context/io github.com/jessevdk/go-flags # github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af github.com/jmespath/go-jmespath -# github.com/jmhodges/levigo v1.0.0 -## explicit -# github.com/joho/godotenv v1.3.0 -## explicit # github.com/json-iterator/go v1.1.9 github.com/json-iterator/go # github.com/kballard/go-shellquote v0.0.0-20170619183022-cd60e84ee657 -## explicit github.com/kballard/go-shellquote # github.com/kelseyhightower/envconfig v1.3.0 github.com/kelseyhightower/envconfig # github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd github.com/kevinburke/ssh_config # github.com/keybase/go-crypto v0.0.0-20200123153347-de78d2cb44f4 -## explicit github.com/keybase/go-crypto/brainpool github.com/keybase/go-crypto/cast5 github.com/keybase/go-crypto/curve25519 @@ -525,7 +460,6 @@ github.com/keybase/go-crypto/openpgp/packet github.com/keybase/go-crypto/openpgp/s2k github.com/keybase/go-crypto/rsa # github.com/klauspost/compress v1.10.2 -## explicit github.com/klauspost/compress/flate github.com/klauspost/compress/gzip # github.com/klauspost/cpuid v1.2.3 @@ -535,16 +469,13 @@ github.com/kr/pretty # github.com/kr/text v0.2.0 github.com/kr/text # github.com/lafriks/xormstore v1.3.2 -## explicit github.com/lafriks/xormstore github.com/lafriks/xormstore/util # github.com/lib/pq v1.2.0 -## explicit github.com/lib/pq github.com/lib/pq/oid github.com/lib/pq/scram # github.com/lunny/dingtalk_webhook v0.0.0-20171025031554-e3534c89ef96 -## explicit github.com/lunny/dingtalk_webhook # github.com/lunny/log v0.0.0-20160921050905-7887c61bf0de github.com/lunny/log @@ -557,13 +488,11 @@ github.com/lunny/nodb/store/goleveldb # github.com/magiconair/properties v1.8.1 github.com/magiconair/properties # github.com/mailru/easyjson v0.7.0 -## explicit github.com/mailru/easyjson github.com/mailru/easyjson/buffer github.com/mailru/easyjson/jlexer github.com/mailru/easyjson/jwriter # github.com/markbates/goth v1.61.2 -## explicit github.com/markbates/goth github.com/markbates/goth/gothic github.com/markbates/goth/providers/bitbucket @@ -581,35 +510,26 @@ github.com/markbates/goth/providers/yandex # github.com/mattn/go-colorable v0.1.4 github.com/mattn/go-colorable # github.com/mattn/go-isatty v0.0.11 -## explicit github.com/mattn/go-isatty -# github.com/mattn/go-oci8 v0.0.0-20190320171441-14ba190cf52d -## explicit # github.com/mattn/go-runewidth v0.0.7 github.com/mattn/go-runewidth # github.com/mattn/go-sqlite3 v1.11.0 -## explicit github.com/mattn/go-sqlite3 # github.com/matttproud/golang_protobuf_extensions v1.0.1 github.com/matttproud/golang_protobuf_extensions/pbutil # github.com/mcuadros/go-version v0.0.0-20190308113854-92cdf37c5b75 -## explicit github.com/mcuadros/go-version # github.com/mgechev/dots v0.0.0-20190921121421-c36f7dcfbb81 -## explicit github.com/mgechev/dots # github.com/mgechev/revive v1.0.2 -## explicit github.com/mgechev/revive/formatter github.com/mgechev/revive/lint github.com/mgechev/revive/rule # github.com/microcosm-cc/bluemonday v1.0.3-0.20191119130333-0a75d7616912 -## explicit github.com/microcosm-cc/bluemonday # github.com/minio/md5-simd v1.1.0 github.com/minio/md5-simd # github.com/minio/minio-go v6.0.14+incompatible -## explicit github.com/minio/minio-go github.com/minio/minio-go/pkg/credentials github.com/minio/minio-go/pkg/encrypt @@ -617,7 +537,6 @@ github.com/minio/minio-go/pkg/s3signer github.com/minio/minio-go/pkg/s3utils github.com/minio/minio-go/pkg/set # github.com/minio/minio-go/v6 v6.0.57 -## explicit github.com/minio/minio-go/v6 github.com/minio/minio-go/v6/pkg/credentials github.com/minio/minio-go/v6/pkg/encrypt @@ -628,7 +547,6 @@ github.com/minio/minio-go/v6/pkg/tags # github.com/minio/sha256-simd v0.1.1 github.com/minio/sha256-simd # github.com/mitchellh/go-homedir v1.1.0 -## explicit github.com/mitchellh/go-homedir # github.com/mitchellh/mapstructure v1.1.2 github.com/mitchellh/mapstructure @@ -641,21 +559,16 @@ github.com/mrjones/oauth # github.com/mschoch/smat v0.2.0 github.com/mschoch/smat # github.com/msteinert/pam v0.0.0-20151204160544-02ccfbfaf0cc -## explicit github.com/msteinert/pam # github.com/nfnt/resize v0.0.0-20160724205520-891127d8d1b5 -## explicit github.com/nfnt/resize # github.com/niklasfasching/go-org v0.1.9 -## explicit github.com/niklasfasching/go-org/org # github.com/olekukonko/tablewriter v0.0.4 github.com/olekukonko/tablewriter # github.com/oliamb/cutter v0.2.2 -## explicit github.com/oliamb/cutter # github.com/olivere/elastic/v7 v7.0.9 -## explicit github.com/olivere/elastic/v7 github.com/olivere/elastic/v7/config github.com/olivere/elastic/v7/uritemplates @@ -668,53 +581,41 @@ github.com/pelletier/go-toml # github.com/philhofer/fwd v1.0.0 github.com/philhofer/fwd # github.com/pkg/errors v0.9.1 -## explicit github.com/pkg/errors # github.com/pmezard/go-difflib v1.0.0 github.com/pmezard/go-difflib/difflib # github.com/pquerna/otp v1.2.0 -## explicit github.com/pquerna/otp github.com/pquerna/otp/hotp github.com/pquerna/otp/totp # github.com/prometheus/client_golang v1.1.0 -## explicit github.com/prometheus/client_golang/prometheus github.com/prometheus/client_golang/prometheus/internal github.com/prometheus/client_golang/prometheus/promhttp # github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4 -## explicit github.com/prometheus/client_model/go # github.com/prometheus/common v0.6.0 github.com/prometheus/common/expfmt github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg github.com/prometheus/common/model # github.com/prometheus/procfs v0.0.4 -## explicit github.com/prometheus/procfs github.com/prometheus/procfs/internal/fs github.com/prometheus/procfs/internal/util # github.com/quasoft/websspi v1.0.0 -## explicit github.com/quasoft/websspi github.com/quasoft/websspi/secctx -# github.com/remyoudompheng/bigfft v0.0.0-20190321074620-2f0d2b0e0001 -## explicit # github.com/russross/blackfriday/v2 v2.0.1 github.com/russross/blackfriday/v2 # github.com/satori/go.uuid v1.2.0 -## explicit github.com/satori/go.uuid # github.com/sergi/go-diff v1.1.0 -## explicit github.com/sergi/go-diff/diffmatchpatch # github.com/shurcooL/httpfs v0.0.0-20190527155220-6a4d4a70508b -## explicit github.com/shurcooL/httpfs/vfsutil # github.com/shurcooL/sanitized_anchor_name v1.0.0 github.com/shurcooL/sanitized_anchor_name # github.com/shurcooL/vfsgen v0.0.0-20181202132449-6a9ea43bcacd -## explicit github.com/shurcooL/vfsgen # github.com/siddontang/go-snappy v0.0.0-20140704025258-d8f7bb82a96d github.com/siddontang/go-snappy/snappy @@ -734,7 +635,6 @@ github.com/steveyen/gtreap # github.com/streadway/amqp v0.0.0-20190214183023-884228600bc9 github.com/streadway/amqp # github.com/stretchr/testify v1.4.0 -## explicit github.com/stretchr/testify/assert github.com/stretchr/testify/require # github.com/syndtr/goleveldb v1.0.0 @@ -750,38 +650,28 @@ github.com/syndtr/goleveldb/leveldb/opt github.com/syndtr/goleveldb/leveldb/storage github.com/syndtr/goleveldb/leveldb/table github.com/syndtr/goleveldb/leveldb/util -# github.com/tecbot/gorocksdb v0.0.0-20181010114359-8752a9433481 -## explicit # github.com/tinylib/msgp v1.1.2 -## explicit github.com/tinylib/msgp/msgp # github.com/toqueteos/trie v1.0.0 github.com/toqueteos/trie # github.com/toqueteos/webbrowser v1.2.0 github.com/toqueteos/webbrowser # github.com/tstranex/u2f v1.0.0 -## explicit github.com/tstranex/u2f # github.com/unknwon/cae v1.0.0 -## explicit github.com/unknwon/cae github.com/unknwon/cae/zip # github.com/unknwon/com v1.0.1 -## explicit github.com/unknwon/com # github.com/unknwon/i18n v0.0.0-20190805065654-5c6446a380b6 -## explicit github.com/unknwon/i18n # github.com/unknwon/paginater v0.0.0-20151104151617-7748a72e0141 -## explicit github.com/unknwon/paginater # github.com/urfave/cli v1.22.1 -## explicit github.com/urfave/cli # github.com/willf/bitset v1.1.10 github.com/willf/bitset # github.com/xanzy/go-gitlab v0.31.0 -## explicit github.com/xanzy/go-gitlab # github.com/xanzy/ssh-agent v0.2.1 github.com/xanzy/ssh-agent @@ -790,10 +680,8 @@ github.com/xdg/scram # github.com/xdg/stringprep v1.0.0 github.com/xdg/stringprep # github.com/yohcop/openid-go v1.0.0 -## explicit github.com/yohcop/openid-go # github.com/yuin/goldmark v1.1.27 -## explicit github.com/yuin/goldmark github.com/yuin/goldmark/ast github.com/yuin/goldmark/extension @@ -804,7 +692,6 @@ github.com/yuin/goldmark/renderer/html github.com/yuin/goldmark/text github.com/yuin/goldmark/util # github.com/yuin/goldmark-meta v0.0.0-20191126180153-f0638e958b60 -## explicit github.com/yuin/goldmark-meta # go.etcd.io/bbolt v1.3.4 go.etcd.io/bbolt @@ -856,7 +743,6 @@ go.opencensus.io/trace/internal go.opencensus.io/trace/propagation go.opencensus.io/trace/tracestate # golang.org/x/crypto v0.0.0-20200429183012-4b2356b1ed79 -## explicit golang.org/x/crypto/acme golang.org/x/crypto/acme/autocert golang.org/x/crypto/argon2 @@ -884,11 +770,9 @@ golang.org/x/crypto/ssh/agent golang.org/x/crypto/ssh/internal/bcrypt_pbkdf golang.org/x/crypto/ssh/knownhosts # golang.org/x/mod v0.3.0 -## explicit golang.org/x/mod/module golang.org/x/mod/semver # golang.org/x/net v0.0.0-20200513185701-a91f0712d120 -## explicit golang.org/x/net/context golang.org/x/net/context/ctxhttp golang.org/x/net/html @@ -904,7 +788,6 @@ golang.org/x/net/proxy golang.org/x/net/publicsuffix golang.org/x/net/trace # golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d -## explicit golang.org/x/oauth2 golang.org/x/oauth2/google golang.org/x/oauth2/internal @@ -914,7 +797,6 @@ golang.org/x/oauth2/jwt golang.org/x/sync/errgroup golang.org/x/sync/semaphore # golang.org/x/sys v0.0.0-20200509044756-6aff5f38e54f -## explicit golang.org/x/sys/cpu golang.org/x/sys/internal/unsafeheader golang.org/x/sys/unix @@ -922,7 +804,6 @@ golang.org/x/sys/windows golang.org/x/sys/windows/svc golang.org/x/sys/windows/svc/debug # golang.org/x/text v0.3.2 -## explicit golang.org/x/text/encoding golang.org/x/text/encoding/charmap golang.org/x/text/encoding/htmlindex @@ -945,10 +826,8 @@ golang.org/x/text/unicode/bidi golang.org/x/text/unicode/norm golang.org/x/text/width # golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1 -## explicit golang.org/x/time/rate # golang.org/x/tools v0.0.0-20200515220128-d3bf790afa53 -## explicit golang.org/x/tools/cover golang.org/x/tools/go/analysis golang.org/x/tools/go/analysis/internal/analysisflags @@ -988,7 +867,6 @@ google.golang.org/api/transport/grpc google.golang.org/api/transport/http google.golang.org/api/transport/http/internal/propagation # google.golang.org/appengine v1.6.5 -## explicit google.golang.org/appengine google.golang.org/appengine/cloudsql google.golang.org/appengine/internal @@ -1087,41 +965,32 @@ google.golang.org/protobuf/types/known/durationpb google.golang.org/protobuf/types/known/emptypb google.golang.org/protobuf/types/known/timestamppb # gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc -## explicit gopkg.in/alexcesaro/quotedprintable.v3 # gopkg.in/asn1-ber.v1 v1.0.0-20150924051756-4e86f4367175 -## explicit gopkg.in/asn1-ber.v1 # gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df -## explicit gopkg.in/gomail.v2 # gopkg.in/ini.v1 v1.52.0 -## explicit gopkg.in/ini.v1 # gopkg.in/ldap.v3 v3.0.2 -## explicit gopkg.in/ldap.v3 +# gopkg.in/macaron.v1 v1.3.9 +gopkg.in/macaron.v1 # gopkg.in/testfixtures.v2 v2.5.0 -## explicit gopkg.in/testfixtures.v2 # gopkg.in/toqueteos/substring.v1 v1.0.2 gopkg.in/toqueteos/substring.v1 # gopkg.in/warnings.v0 v0.1.2 gopkg.in/warnings.v0 # gopkg.in/yaml.v2 v2.2.8 -## explicit gopkg.in/yaml.v2 # mvdan.cc/xurls/v2 v2.1.0 -## explicit mvdan.cc/xurls/v2 # strk.kbt.io/projects/go/libravatar v0.0.0-20191008002943-06d1c002b251 -## explicit strk.kbt.io/projects/go/libravatar # xorm.io/builder v0.3.7 -## explicit xorm.io/builder # xorm.io/xorm v1.0.1 -## explicit xorm.io/xorm xorm.io/xorm/caches xorm.io/xorm/contexts