pax_global_header00006660000000000000000000000064146640562470014530gustar00rootroot0000000000000052 comment=a814d7990a5449fcc211a536119d271469cc4157 cors-1.11.1/000077500000000000000000000000001466405624700125575ustar00rootroot00000000000000cors-1.11.1/.github/000077500000000000000000000000001466405624700141175ustar00rootroot00000000000000cors-1.11.1/.github/workflows/000077500000000000000000000000001466405624700161545ustar00rootroot00000000000000cors-1.11.1/.github/workflows/go.yml000066400000000000000000000012451466405624700173060ustar00rootroot00000000000000on: [push] name: Test jobs: test: runs-on: ubuntu-latest strategy: matrix: go: ["1.17", "1.21"] steps: - name: Set up Go ${{ matrix.go }} uses: actions/setup-go@v1 with: go-version: ${{ matrix.go }} id: go - name: Check out code uses: actions/checkout@v3 - name: Get dependencies run: go get -v -t -d ./... - name: Test run: go test ./... coverage: runs-on: ubuntu-latest steps: - name: Update coverage report uses: ncruces/go-coverage-report@main with: report: 'true' chart: 'true' amend: 'true' continue-on-error: true cors-1.11.1/LICENSE000066400000000000000000000020701466405624700135630ustar00rootroot00000000000000Copyright (c) 2014 Olivier Poitrey 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. cors-1.11.1/README.md000066400000000000000000000172701466405624700140450ustar00rootroot00000000000000# Go CORS handler [![godoc](http://img.shields.io/badge/godoc-reference-blue.svg?style=flat)](https://godoc.org/github.com/rs/cors) [![license](http://img.shields.io/badge/license-MIT-red.svg?style=flat)](https://raw.githubusercontent.com/rs/cors/master/LICENSE) [![Go Coverage](https://github.com/rs/cors/wiki/coverage.svg)](https://raw.githack.com/wiki/rs/cors/coverage.html) CORS is a `net/http` handler implementing [Cross Origin Resource Sharing W3 specification](http://www.w3.org/TR/cors/) in Golang. ## Getting Started After installing Go and setting up your [GOPATH](http://golang.org/doc/code.html#GOPATH), create your first `.go` file. We'll call it `server.go`. ```go package main import ( "net/http" "github.com/rs/cors" ) func main() { mux := http.NewServeMux() mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") w.Write([]byte("{\"hello\": \"world\"}")) }) // cors.Default() setup the middleware with default options being // all origins accepted with simple methods (GET, POST). See // documentation below for more options. handler := cors.Default().Handler(mux) http.ListenAndServe(":8080", handler) } ``` Install `cors`: go get github.com/rs/cors Then run your server: go run server.go The server now runs on `localhost:8080`: $ curl -D - -H 'Origin: http://foo.com' http://localhost:8080/ HTTP/1.1 200 OK Access-Control-Allow-Origin: foo.com Content-Type: application/json Date: Sat, 25 Oct 2014 03:43:57 GMT Content-Length: 18 {"hello": "world"} ### Allow * With Credentials Security Protection This library has been modified to avoid a well known security issue when configured with `AllowedOrigins` to `*` and `AllowCredentials` to `true`. Such setup used to make the library reflects the request `Origin` header value, working around a security protection embedded into the standard that makes clients to refuse such configuration. This behavior has been removed with [#55](https://github.com/rs/cors/issues/55) and [#57](https://github.com/rs/cors/issues/57). If you depend on this behavior and understand the implications, you can restore it using the `AllowOriginFunc` with `func(origin string) {return true}`. Please refer to [#55](https://github.com/rs/cors/issues/55) for more information about the security implications. ### More Examples * `net/http`: [examples/nethttp/server.go](https://github.com/rs/cors/blob/master/examples/nethttp/server.go) * [Goji](https://goji.io): [examples/goji/server.go](https://github.com/rs/cors/blob/master/examples/goji/server.go) * [Martini](http://martini.codegangsta.io): [examples/martini/server.go](https://github.com/rs/cors/blob/master/examples/martini/server.go) * [Negroni](https://github.com/codegangsta/negroni): [examples/negroni/server.go](https://github.com/rs/cors/blob/master/examples/negroni/server.go) * [Alice](https://github.com/justinas/alice): [examples/alice/server.go](https://github.com/rs/cors/blob/master/examples/alice/server.go) * [HttpRouter](https://github.com/julienschmidt/httprouter): [examples/httprouter/server.go](https://github.com/rs/cors/blob/master/examples/httprouter/server.go) * [Gorilla](http://www.gorillatoolkit.org/pkg/mux): [examples/gorilla/server.go](https://github.com/rs/cors/blob/master/examples/gorilla/server.go) * [Buffalo](https://gobuffalo.io): [examples/buffalo/server.go](https://github.com/rs/cors/blob/master/examples/buffalo/server.go) * [Gin](https://gin-gonic.github.io/gin): [examples/gin/server.go](https://github.com/rs/cors/blob/master/examples/gin/server.go) * [Chi](https://github.com/go-chi/chi): [examples/chi/server.go](https://github.com/rs/cors/blob/master/examples/chi/server.go) ## Parameters Parameters are passed to the middleware thru the `cors.New` method as follow: ```go c := cors.New(cors.Options{ AllowedOrigins: []string{"http://foo.com", "http://foo.com:8080"}, AllowCredentials: true, // Enable Debugging for testing, consider disabling in production Debug: true, }) // Insert the middleware handler = c.Handler(handler) ``` * **AllowedOrigins** `[]string`: A list of origins a cross-domain request can be executed from. If the special `*` value is present in the list, all origins will be allowed. An origin may contain a wildcard (`*`) to replace 0 or more characters (i.e.: `http://*.domain.com`). Usage of wildcards implies a small performance penality. Only one wildcard can be used per origin. The default value is `*`. * **AllowOriginFunc** `func (origin string) bool`: A custom function to validate the origin. It takes the origin as an argument and returns true if allowed, or false otherwise. If this option is set, the content of `AllowedOrigins` is ignored. * **AllowOriginRequestFunc** `func (r *http.Request, origin string) bool`: A custom function to validate the origin. It takes the HTTP Request object and the origin as argument and returns true if allowed or false otherwise. If this option is set, the contents of `AllowedOrigins` and `AllowOriginFunc` are ignored. Deprecated: use `AllowOriginVaryRequestFunc` instead. * **AllowOriginVaryRequestFunc** `func(r *http.Request, origin string) (bool, []string)`: A custom function to validate the origin. It takes the HTTP Request object and the origin as argument and returns true if allowed or false otherwise with a list of headers used to take that decision if any so they can be added to the Vary header. If this option is set, the contents of `AllowedOrigins`, `AllowOriginFunc` and `AllowOriginRequestFunc` are ignored. * **AllowedMethods** `[]string`: A list of methods the client is allowed to use with cross-domain requests. Default value is simple methods (`GET` and `POST`). * **AllowedHeaders** `[]string`: A list of non simple headers the client is allowed to use with cross-domain requests. * **ExposedHeaders** `[]string`: Indicates which headers are safe to expose to the API of a CORS API specification. * **AllowCredentials** `bool`: Indicates whether the request can include user credentials like cookies, HTTP authentication or client side SSL certificates. The default is `false`. * **AllowPrivateNetwork** `bool`: Indicates whether to accept cross-origin requests over a private network. * **MaxAge** `int`: Indicates how long (in seconds) the results of a preflight request can be cached. The default is `0` which stands for no max age. * **OptionsPassthrough** `bool`: Instructs preflight to let other potential next handlers to process the `OPTIONS` method. Turn this on if your application handles `OPTIONS`. * **OptionsSuccessStatus** `int`: Provides a status code to use for successful OPTIONS requests. Default value is `http.StatusNoContent` (`204`). * **Debug** `bool`: Debugging flag adds additional output to debug server side CORS issues. See [API documentation](http://godoc.org/github.com/rs/cors) for more info. ## Benchmarks ``` goos: darwin goarch: arm64 pkg: github.com/rs/cors BenchmarkWithout-10 135325480 8.124 ns/op 0 B/op 0 allocs/op BenchmarkDefault-10 24082140 51.40 ns/op 0 B/op 0 allocs/op BenchmarkAllowedOrigin-10 16424518 88.25 ns/op 0 B/op 0 allocs/op BenchmarkPreflight-10 8010259 147.3 ns/op 0 B/op 0 allocs/op BenchmarkPreflightHeader-10 6850962 175.0 ns/op 0 B/op 0 allocs/op BenchmarkWildcard/match-10 253275342 4.714 ns/op 0 B/op 0 allocs/op BenchmarkWildcard/too_short-10 1000000000 0.6235 ns/op 0 B/op 0 allocs/op PASS ok github.com/rs/cors 99.131s ``` ## Licenses All source code is licensed under the [MIT License](https://raw.github.com/rs/cors/master/LICENSE). cors-1.11.1/bench_test.go000066400000000000000000000055571466405624700152400ustar00rootroot00000000000000package cors import ( "net/http" "strings" "testing" ) type FakeResponse struct { header http.Header } func (r FakeResponse) Header() http.Header { return r.header } func (r FakeResponse) WriteHeader(n int) { } func (r FakeResponse) Write(b []byte) (n int, err error) { return len(b), nil } const ( headerOrigin = "Origin" headerACRM = "Access-Control-Request-Method" headerACRH = "Access-Control-Request-Headers" dummyEndpoint = "http://example.com/foo" dummyOrigin = "https://somedomain.com" ) func BenchmarkWithout(b *testing.B) { resps := makeFakeResponses(b.N) req, _ := http.NewRequest(http.MethodGet, dummyEndpoint, nil) b.ReportAllocs() b.ResetTimer() for i := 0; i < b.N; i++ { testHandler.ServeHTTP(resps[i], req) } } func BenchmarkDefault(b *testing.B) { resps := makeFakeResponses(b.N) req, _ := http.NewRequest(http.MethodGet, dummyEndpoint, nil) req.Header.Add(headerOrigin, dummyOrigin) handler := Default().Handler(testHandler) b.ReportAllocs() b.ResetTimer() for i := 0; i < b.N; i++ { handler.ServeHTTP(resps[i], req) } } func BenchmarkAllowedOrigin(b *testing.B) { resps := makeFakeResponses(b.N) req, _ := http.NewRequest(http.MethodGet, dummyEndpoint, nil) req.Header.Add(headerOrigin, dummyOrigin) c := New(Options{ AllowedOrigins: []string{dummyOrigin}, }) handler := c.Handler(testHandler) b.ReportAllocs() b.ResetTimer() for i := 0; i < b.N; i++ { handler.ServeHTTP(resps[i], req) } } func BenchmarkPreflight(b *testing.B) { resps := makeFakeResponses(b.N) req, _ := http.NewRequest(http.MethodOptions, dummyEndpoint, nil) req.Header.Add(headerOrigin, dummyOrigin) req.Header.Add(headerACRM, http.MethodGet) handler := Default().Handler(testHandler) b.ReportAllocs() b.ResetTimer() for i := 0; i < b.N; i++ { handler.ServeHTTP(resps[i], req) } } func BenchmarkPreflightHeader(b *testing.B) { resps := makeFakeResponses(b.N) req, _ := http.NewRequest(http.MethodOptions, dummyEndpoint, nil) req.Header.Add(headerOrigin, dummyOrigin) req.Header.Add(headerACRM, http.MethodGet) req.Header.Add(headerACRH, "accept") handler := Default().Handler(testHandler) b.ReportAllocs() b.ResetTimer() for i := 0; i < b.N; i++ { handler.ServeHTTP(resps[i], req) } } func BenchmarkPreflightAdversarialACRH(b *testing.B) { resps := makeFakeResponses(b.N) req, _ := http.NewRequest(http.MethodOptions, dummyEndpoint, nil) req.Header.Add(headerOrigin, dummyOrigin) req.Header.Add(headerACRM, http.MethodGet) req.Header.Add(headerACRH, strings.Repeat(",", 1024)) handler := Default().Handler(testHandler) b.ReportAllocs() b.ResetTimer() for i := 0; i < b.N; i++ { handler.ServeHTTP(resps[i], req) } } func makeFakeResponses(n int) []*FakeResponse { resps := make([]*FakeResponse, n) for i := 0; i < n; i++ { resps[i] = &FakeResponse{http.Header{ "Content-Type": []string{"text/plain"}, }} } return resps } cors-1.11.1/cors.go000066400000000000000000000423621466405624700140630ustar00rootroot00000000000000/* Package cors is net/http handler to handle CORS related requests as defined by http://www.w3.org/TR/cors/ You can configure it by passing an option struct to cors.New: c := cors.New(cors.Options{ AllowedOrigins: []string{"foo.com"}, AllowedMethods: []string{http.MethodGet, http.MethodPost, http.MethodDelete}, AllowCredentials: true, }) Then insert the handler in the chain: handler = c.Handler(handler) See Options documentation for more options. The resulting handler is a standard net/http handler. */ package cors import ( "log" "net/http" "os" "strconv" "strings" "github.com/rs/cors/internal" ) var headerVaryOrigin = []string{"Origin"} var headerOriginAll = []string{"*"} var headerTrue = []string{"true"} // Options is a configuration container to setup the CORS middleware. type Options struct { // AllowedOrigins is a list of origins a cross-domain request can be executed from. // If the special "*" value is present in the list, all origins will be allowed. // An origin may contain a wildcard (*) to replace 0 or more characters // (i.e.: http://*.domain.com). Usage of wildcards implies a small performance penalty. // Only one wildcard can be used per origin. // Default value is ["*"] AllowedOrigins []string // AllowOriginFunc is a custom function to validate the origin. It take the // origin as argument and returns true if allowed or false otherwise. If // this option is set, the content of `AllowedOrigins` is ignored. AllowOriginFunc func(origin string) bool // AllowOriginRequestFunc is a custom function to validate the origin. It // takes the HTTP Request object and the origin as argument and returns true // if allowed or false otherwise. If headers are used take the decision, // consider using AllowOriginVaryRequestFunc instead. If this option is set, // the contents of `AllowedOrigins`, `AllowOriginFunc` are ignored. // // Deprecated: use `AllowOriginVaryRequestFunc` instead. AllowOriginRequestFunc func(r *http.Request, origin string) bool // AllowOriginVaryRequestFunc is a custom function to validate the origin. // It takes the HTTP Request object and the origin as argument and returns // true if allowed or false otherwise with a list of headers used to take // that decision if any so they can be added to the Vary header. If this // option is set, the contents of `AllowedOrigins`, `AllowOriginFunc` and // `AllowOriginRequestFunc` are ignored. AllowOriginVaryRequestFunc func(r *http.Request, origin string) (bool, []string) // AllowedMethods is a list of methods the client is allowed to use with // cross-domain requests. Default value is simple methods (HEAD, GET and POST). AllowedMethods []string // AllowedHeaders is list of non simple headers the client is allowed to use with // cross-domain requests. // If the special "*" value is present in the list, all headers will be allowed. // Default value is []. AllowedHeaders []string // ExposedHeaders indicates which headers are safe to expose to the API of a CORS // API specification ExposedHeaders []string // MaxAge indicates how long (in seconds) the results of a preflight request // can be cached. Default value is 0, which stands for no // Access-Control-Max-Age header to be sent back, resulting in browsers // using their default value (5s by spec). If you need to force a 0 max-age, // set `MaxAge` to a negative value (ie: -1). MaxAge int // AllowCredentials indicates whether the request can include user credentials like // cookies, HTTP authentication or client side SSL certificates. AllowCredentials bool // AllowPrivateNetwork indicates whether to accept cross-origin requests over a // private network. AllowPrivateNetwork bool // OptionsPassthrough instructs preflight to let other potential next handlers to // process the OPTIONS method. Turn this on if your application handles OPTIONS. OptionsPassthrough bool // Provides a status code to use for successful OPTIONS requests. // Default value is http.StatusNoContent (204). OptionsSuccessStatus int // Debugging flag adds additional output to debug server side CORS issues Debug bool // Adds a custom logger, implies Debug is true Logger Logger } // Logger generic interface for logger type Logger interface { Printf(string, ...interface{}) } // Cors http handler type Cors struct { // Debug logger Log Logger // Normalized list of plain allowed origins allowedOrigins []string // List of allowed origins containing wildcards allowedWOrigins []wildcard // Optional origin validator function allowOriginFunc func(r *http.Request, origin string) (bool, []string) // Normalized list of allowed headers // Note: the Fetch standard guarantees that CORS-unsafe request-header names // (i.e. the values listed in the Access-Control-Request-Headers header) // are unique and sorted; // see https://fetch.spec.whatwg.org/#cors-unsafe-request-header-names. allowedHeaders internal.SortedSet // Normalized list of allowed methods allowedMethods []string // Pre-computed normalized list of exposed headers exposedHeaders []string // Pre-computed maxAge header value maxAge []string // Set to true when allowed origins contains a "*" allowedOriginsAll bool // Set to true when allowed headers contains a "*" allowedHeadersAll bool // Status code to use for successful OPTIONS requests optionsSuccessStatus int allowCredentials bool allowPrivateNetwork bool optionPassthrough bool preflightVary []string } // New creates a new Cors handler with the provided options. func New(options Options) *Cors { c := &Cors{ allowCredentials: options.AllowCredentials, allowPrivateNetwork: options.AllowPrivateNetwork, optionPassthrough: options.OptionsPassthrough, Log: options.Logger, } if options.Debug && c.Log == nil { c.Log = log.New(os.Stdout, "[cors] ", log.LstdFlags) } // Allowed origins switch { case options.AllowOriginVaryRequestFunc != nil: c.allowOriginFunc = options.AllowOriginVaryRequestFunc case options.AllowOriginRequestFunc != nil: c.allowOriginFunc = func(r *http.Request, origin string) (bool, []string) { return options.AllowOriginRequestFunc(r, origin), nil } case options.AllowOriginFunc != nil: c.allowOriginFunc = func(r *http.Request, origin string) (bool, []string) { return options.AllowOriginFunc(origin), nil } case len(options.AllowedOrigins) == 0: if c.allowOriginFunc == nil { // Default is all origins c.allowedOriginsAll = true } default: c.allowedOrigins = []string{} c.allowedWOrigins = []wildcard{} for _, origin := range options.AllowedOrigins { // Note: for origins matching, the spec requires a case-sensitive matching. // As it may error prone, we chose to ignore the spec here. origin = strings.ToLower(origin) if origin == "*" { // If "*" is present in the list, turn the whole list into a match all c.allowedOriginsAll = true c.allowedOrigins = nil c.allowedWOrigins = nil break } else if i := strings.IndexByte(origin, '*'); i >= 0 { // Split the origin in two: start and end string without the * w := wildcard{origin[0:i], origin[i+1:]} c.allowedWOrigins = append(c.allowedWOrigins, w) } else { c.allowedOrigins = append(c.allowedOrigins, origin) } } } // Allowed Headers // Note: the Fetch standard guarantees that CORS-unsafe request-header names // (i.e. the values listed in the Access-Control-Request-Headers header) // are lowercase; see https://fetch.spec.whatwg.org/#cors-unsafe-request-header-names. if len(options.AllowedHeaders) == 0 { // Use sensible defaults c.allowedHeaders = internal.NewSortedSet("accept", "content-type", "x-requested-with") } else { normalized := convert(options.AllowedHeaders, strings.ToLower) c.allowedHeaders = internal.NewSortedSet(normalized...) for _, h := range options.AllowedHeaders { if h == "*" { c.allowedHeadersAll = true c.allowedHeaders = internal.SortedSet{} break } } } // Allowed Methods if len(options.AllowedMethods) == 0 { // Default is spec's "simple" methods c.allowedMethods = []string{http.MethodGet, http.MethodPost, http.MethodHead} } else { c.allowedMethods = options.AllowedMethods } // Options Success Status Code if options.OptionsSuccessStatus == 0 { c.optionsSuccessStatus = http.StatusNoContent } else { c.optionsSuccessStatus = options.OptionsSuccessStatus } // Pre-compute exposed headers header value if len(options.ExposedHeaders) > 0 { c.exposedHeaders = []string{strings.Join(convert(options.ExposedHeaders, http.CanonicalHeaderKey), ", ")} } // Pre-compute prefight Vary header to save allocations if c.allowPrivateNetwork { c.preflightVary = []string{"Origin, Access-Control-Request-Method, Access-Control-Request-Headers, Access-Control-Request-Private-Network"} } else { c.preflightVary = []string{"Origin, Access-Control-Request-Method, Access-Control-Request-Headers"} } // Precompute max-age if options.MaxAge > 0 { c.maxAge = []string{strconv.Itoa(options.MaxAge)} } else if options.MaxAge < 0 { c.maxAge = []string{"0"} } return c } // Default creates a new Cors handler with default options. func Default() *Cors { return New(Options{}) } // AllowAll create a new Cors handler with permissive configuration allowing all // origins with all standard methods with any header and credentials. func AllowAll() *Cors { return New(Options{ AllowedOrigins: []string{"*"}, AllowedMethods: []string{ http.MethodHead, http.MethodGet, http.MethodPost, http.MethodPut, http.MethodPatch, http.MethodDelete, }, AllowedHeaders: []string{"*"}, AllowCredentials: false, }) } // Handler apply the CORS specification on the request, and add relevant CORS headers // as necessary. func (c *Cors) Handler(h http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if r.Method == http.MethodOptions && r.Header.Get("Access-Control-Request-Method") != "" { c.logf("Handler: Preflight request") c.handlePreflight(w, r) // Preflight requests are standalone and should stop the chain as some other // middleware may not handle OPTIONS requests correctly. One typical example // is authentication middleware ; OPTIONS requests won't carry authentication // headers (see #1) if c.optionPassthrough { h.ServeHTTP(w, r) } else { w.WriteHeader(c.optionsSuccessStatus) } } else { c.logf("Handler: Actual request") c.handleActualRequest(w, r) h.ServeHTTP(w, r) } }) } // HandlerFunc provides Martini compatible handler func (c *Cors) HandlerFunc(w http.ResponseWriter, r *http.Request) { if r.Method == http.MethodOptions && r.Header.Get("Access-Control-Request-Method") != "" { c.logf("HandlerFunc: Preflight request") c.handlePreflight(w, r) w.WriteHeader(c.optionsSuccessStatus) } else { c.logf("HandlerFunc: Actual request") c.handleActualRequest(w, r) } } // Negroni compatible interface func (c *Cors) ServeHTTP(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) { if r.Method == http.MethodOptions && r.Header.Get("Access-Control-Request-Method") != "" { c.logf("ServeHTTP: Preflight request") c.handlePreflight(w, r) // Preflight requests are standalone and should stop the chain as some other // middleware may not handle OPTIONS requests correctly. One typical example // is authentication middleware ; OPTIONS requests won't carry authentication // headers (see #1) if c.optionPassthrough { next(w, r) } else { w.WriteHeader(c.optionsSuccessStatus) } } else { c.logf("ServeHTTP: Actual request") c.handleActualRequest(w, r) next(w, r) } } // handlePreflight handles pre-flight CORS requests func (c *Cors) handlePreflight(w http.ResponseWriter, r *http.Request) { headers := w.Header() origin := r.Header.Get("Origin") if r.Method != http.MethodOptions { c.logf(" Preflight aborted: %s!=OPTIONS", r.Method) return } // Always set Vary headers // see https://github.com/rs/cors/issues/10, // https://github.com/rs/cors/commit/dbdca4d95feaa7511a46e6f1efb3b3aa505bc43f#commitcomment-12352001 if vary, found := headers["Vary"]; found { headers["Vary"] = append(vary, c.preflightVary[0]) } else { headers["Vary"] = c.preflightVary } allowed, additionalVaryHeaders := c.isOriginAllowed(r, origin) if len(additionalVaryHeaders) > 0 { headers.Add("Vary", strings.Join(convert(additionalVaryHeaders, http.CanonicalHeaderKey), ", ")) } if origin == "" { c.logf(" Preflight aborted: empty origin") return } if !allowed { c.logf(" Preflight aborted: origin '%s' not allowed", origin) return } reqMethod := r.Header.Get("Access-Control-Request-Method") if !c.isMethodAllowed(reqMethod) { c.logf(" Preflight aborted: method '%s' not allowed", reqMethod) return } // Note: the Fetch standard guarantees that at most one // Access-Control-Request-Headers header is present in the preflight request; // see step 5.2 in https://fetch.spec.whatwg.org/#cors-preflight-fetch-0. // However, some gateways split that header into multiple headers of the same name; // see https://github.com/rs/cors/issues/184. reqHeaders, found := r.Header["Access-Control-Request-Headers"] if found && !c.allowedHeadersAll && !c.allowedHeaders.Accepts(reqHeaders) { c.logf(" Preflight aborted: headers '%v' not allowed", reqHeaders) return } if c.allowedOriginsAll { headers["Access-Control-Allow-Origin"] = headerOriginAll } else { headers["Access-Control-Allow-Origin"] = r.Header["Origin"] } // Spec says: Since the list of methods can be unbounded, simply returning the method indicated // by Access-Control-Request-Method (if supported) can be enough headers["Access-Control-Allow-Methods"] = r.Header["Access-Control-Request-Method"] if found && len(reqHeaders[0]) > 0 { // Spec says: Since the list of headers can be unbounded, simply returning supported headers // from Access-Control-Request-Headers can be enough headers["Access-Control-Allow-Headers"] = reqHeaders } if c.allowCredentials { headers["Access-Control-Allow-Credentials"] = headerTrue } if c.allowPrivateNetwork && r.Header.Get("Access-Control-Request-Private-Network") == "true" { headers["Access-Control-Allow-Private-Network"] = headerTrue } if len(c.maxAge) > 0 { headers["Access-Control-Max-Age"] = c.maxAge } c.logf(" Preflight response headers: %v", headers) } // handleActualRequest handles simple cross-origin requests, actual request or redirects func (c *Cors) handleActualRequest(w http.ResponseWriter, r *http.Request) { headers := w.Header() origin := r.Header.Get("Origin") allowed, additionalVaryHeaders := c.isOriginAllowed(r, origin) // Always set Vary, see https://github.com/rs/cors/issues/10 if vary := headers["Vary"]; vary == nil { headers["Vary"] = headerVaryOrigin } else { headers["Vary"] = append(vary, headerVaryOrigin[0]) } if len(additionalVaryHeaders) > 0 { headers.Add("Vary", strings.Join(convert(additionalVaryHeaders, http.CanonicalHeaderKey), ", ")) } if origin == "" { c.logf(" Actual request no headers added: missing origin") return } if !allowed { c.logf(" Actual request no headers added: origin '%s' not allowed", origin) return } // Note that spec does define a way to specifically disallow a simple method like GET or // POST. Access-Control-Allow-Methods is only used for pre-flight requests and the // spec doesn't instruct to check the allowed methods for simple cross-origin requests. // We think it's a nice feature to be able to have control on those methods though. if !c.isMethodAllowed(r.Method) { c.logf(" Actual request no headers added: method '%s' not allowed", r.Method) return } if c.allowedOriginsAll { headers["Access-Control-Allow-Origin"] = headerOriginAll } else { headers["Access-Control-Allow-Origin"] = r.Header["Origin"] } if len(c.exposedHeaders) > 0 { headers["Access-Control-Expose-Headers"] = c.exposedHeaders } if c.allowCredentials { headers["Access-Control-Allow-Credentials"] = headerTrue } c.logf(" Actual response added headers: %v", headers) } // convenience method. checks if a logger is set. func (c *Cors) logf(format string, a ...interface{}) { if c.Log != nil { c.Log.Printf(format, a...) } } // check the Origin of a request. No origin at all is also allowed. func (c *Cors) OriginAllowed(r *http.Request) bool { origin := r.Header.Get("Origin") allowed, _ := c.isOriginAllowed(r, origin) return allowed } // isOriginAllowed checks if a given origin is allowed to perform cross-domain requests // on the endpoint func (c *Cors) isOriginAllowed(r *http.Request, origin string) (allowed bool, varyHeaders []string) { if c.allowOriginFunc != nil { return c.allowOriginFunc(r, origin) } if c.allowedOriginsAll { return true, nil } origin = strings.ToLower(origin) for _, o := range c.allowedOrigins { if o == origin { return true, nil } } for _, w := range c.allowedWOrigins { if w.match(origin) { return true, nil } } return false, nil } // isMethodAllowed checks if a given method can be used as part of a cross-domain request // on the endpoint func (c *Cors) isMethodAllowed(method string) bool { if len(c.allowedMethods) == 0 { // If no method allowed, always return false, even for preflight request return false } if method == http.MethodOptions { // Always allow preflight requests return true } for _, m := range c.allowedMethods { if m == method { return true } } return false } cors-1.11.1/cors_test.go000066400000000000000000000535161466405624700151250ustar00rootroot00000000000000package cors import ( "bytes" "fmt" "net/http" "net/http/httptest" "regexp" "strings" "testing" ) var testResponse = []byte("bar") var testHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { _, _ = w.Write(testResponse) }) // For each key-value pair of this map, the value indicates whether the key // is a list-based field (i.e. not a singleton field); // see https://httpwg.org/specs/rfc9110.html#abnf.extension. var allRespHeaders = map[string]bool{ // see https://www.rfc-editor.org/rfc/rfc9110#section-12.5.5 "Vary": true, // see https://fetch.spec.whatwg.org/#http-new-header-syntax "Access-Control-Allow-Origin": false, "Access-Control-Allow-Credentials": false, "Access-Control-Allow-Methods": true, "Access-Control-Allow-Headers": true, "Access-Control-Max-Age": false, "Access-Control-Expose-Headers": true, // see https://wicg.github.io/private-network-access/ "Access-Control-Allow-Private-Network": false, } func assertHeaders(t *testing.T, resHeaders http.Header, expHeaders http.Header) { t.Helper() for name, listBased := range allRespHeaders { got := resHeaders[name] want := expHeaders[name] if !listBased && !slicesEqual(got, want) { t.Errorf("Response header %q = %q, want %q", name, got, want) continue } if listBased && !slicesEqual(normalize(got), normalize(want)) { t.Errorf("Response header %q = %q, want %q", name, got, want) continue } } } // normalize normalizes a list-based field value, // preserving both empty elements and the order of elements. func normalize(s []string) (res []string) { for _, v := range s { for _, e := range strings.Split(v, ",") { e = strings.Trim(e, " \t") res = append(res, e) } } return } // TODO: when updating go directive to 1.21 or later, // use slices.Equal instead. func slicesEqual(s1, s2 []string) bool { if len(s1) != len(s2) { return false } for i := range s1 { if s1[i] != s2[i] { return false } } return true } func assertResponse(t *testing.T, res *httptest.ResponseRecorder, responseCode int) { t.Helper() if responseCode != res.Code { t.Errorf("assertResponse: expected response code to be %d but got %d. ", responseCode, res.Code) } } func TestSpec(t *testing.T) { cases := []struct { name string options Options method string reqHeaders http.Header resHeaders http.Header originAllowed bool }{ { "NoConfig", Options{ // Intentionally left blank. }, "GET", http.Header{}, http.Header{ "Vary": {"Origin"}, }, true, }, { "MatchAllOrigin", Options{ AllowedOrigins: []string{"*"}, }, "GET", http.Header{ "Origin": {"http://foobar.com"}, }, http.Header{ "Vary": {"Origin"}, "Access-Control-Allow-Origin": {"*"}, }, true, }, { "MatchAllOriginWithCredentials", Options{ AllowedOrigins: []string{"*"}, AllowCredentials: true, }, "GET", http.Header{ "Origin": {"http://foobar.com"}, }, http.Header{ "Vary": {"Origin"}, "Access-Control-Allow-Origin": {"*"}, "Access-Control-Allow-Credentials": {"true"}, }, true, }, { "AllowedOrigin", Options{ AllowedOrigins: []string{"http://foobar.com"}, }, "GET", http.Header{ "Origin": {"http://foobar.com"}, }, http.Header{ "Vary": {"Origin"}, "Access-Control-Allow-Origin": {"http://foobar.com"}, }, true, }, { "WildcardOrigin", Options{ AllowedOrigins: []string{"http://*.bar.com"}, }, "GET", http.Header{ "Origin": {"http://foo.bar.com"}, }, http.Header{ "Vary": {"Origin"}, "Access-Control-Allow-Origin": {"http://foo.bar.com"}, }, true, }, { "DisallowedOrigin", Options{ AllowedOrigins: []string{"http://foobar.com"}, }, "GET", http.Header{ "Origin": {"http://barbaz.com"}, }, http.Header{ "Vary": {"Origin"}, }, false, }, { "DisallowedWildcardOrigin", Options{ AllowedOrigins: []string{"http://*.bar.com"}, }, "GET", http.Header{ "Origin": {"http://foo.baz.com"}, }, http.Header{ "Vary": {"Origin"}, }, false, }, { "AllowedOriginFuncMatch", Options{ AllowOriginFunc: func(o string) bool { return regexp.MustCompile("^http://foo").MatchString(o) }, }, "GET", http.Header{ "Origin": {"http://foobar.com"}, }, http.Header{ "Vary": {"Origin"}, "Access-Control-Allow-Origin": {"http://foobar.com"}, }, true, }, { "AllowOriginRequestFuncMatch", Options{ AllowOriginRequestFunc: func(r *http.Request, o string) bool { return regexp.MustCompile("^http://foo").MatchString(o) && r.Header.Get("Authorization") == "secret" }, }, "GET", http.Header{ "Origin": {"http://foobar.com"}, "Authorization": {"secret"}, }, http.Header{ "Vary": {"Origin"}, "Access-Control-Allow-Origin": {"http://foobar.com"}, }, true, }, { "AllowOriginVaryRequestFuncMatch", Options{ AllowOriginVaryRequestFunc: func(r *http.Request, o string) (bool, []string) { return regexp.MustCompile("^http://foo").MatchString(o) && r.Header.Get("Authorization") == "secret", []string{"Authorization"} }, }, "GET", http.Header{ "Origin": {"http://foobar.com"}, "Authorization": {"secret"}, }, http.Header{ "Vary": {"Origin, Authorization"}, "Access-Control-Allow-Origin": {"http://foobar.com"}, }, true, }, { "AllowOriginRequestFuncNotMatch", Options{ AllowOriginRequestFunc: func(r *http.Request, o string) bool { return regexp.MustCompile("^http://foo").MatchString(o) && r.Header.Get("Authorization") == "secret" }, }, "GET", http.Header{ "Origin": {"http://foobar.com"}, "Authorization": {"not-secret"}, }, http.Header{ "Vary": {"Origin"}, }, false, }, { "MaxAge", Options{ AllowedOrigins: []string{"http://example.com"}, AllowedMethods: []string{"GET"}, MaxAge: 10, }, "OPTIONS", http.Header{ "Origin": {"http://example.com"}, "Access-Control-Request-Method": {"GET"}, }, http.Header{ "Vary": {"Origin, Access-Control-Request-Method, Access-Control-Request-Headers"}, "Access-Control-Allow-Origin": {"http://example.com"}, "Access-Control-Allow-Methods": {"GET"}, "Access-Control-Max-Age": {"10"}, }, true, }, { "MaxAgeNegative", Options{ AllowedOrigins: []string{"http://example.com"}, AllowedMethods: []string{"GET"}, MaxAge: -1, }, "OPTIONS", http.Header{ "Origin": {"http://example.com"}, "Access-Control-Request-Method": {"GET"}, }, http.Header{ "Vary": {"Origin, Access-Control-Request-Method, Access-Control-Request-Headers"}, "Access-Control-Allow-Origin": {"http://example.com"}, "Access-Control-Allow-Methods": {"GET"}, "Access-Control-Max-Age": {"0"}, }, true, }, { "AllowedMethod", Options{ AllowedOrigins: []string{"http://foobar.com"}, AllowedMethods: []string{"PUT", "DELETE"}, }, "OPTIONS", http.Header{ "Origin": {"http://foobar.com"}, "Access-Control-Request-Method": {"PUT"}, }, http.Header{ "Vary": {"Origin, Access-Control-Request-Method, Access-Control-Request-Headers"}, "Access-Control-Allow-Origin": {"http://foobar.com"}, "Access-Control-Allow-Methods": {"PUT"}, }, true, }, { "DisallowedMethod", Options{ AllowedOrigins: []string{"http://foobar.com"}, AllowedMethods: []string{"PUT", "DELETE"}, }, "OPTIONS", http.Header{ "Origin": {"http://foobar.com"}, "Access-Control-Request-Method": {"PATCH"}, }, http.Header{ "Vary": {"Origin, Access-Control-Request-Method, Access-Control-Request-Headers"}, }, true, }, { "AllowedHeaders", Options{ AllowedOrigins: []string{"http://foobar.com"}, AllowedHeaders: []string{"X-Header-1", "x-header-2", "X-HEADER-3"}, }, "OPTIONS", http.Header{ "Origin": {"http://foobar.com"}, "Access-Control-Request-Method": {"GET"}, "Access-Control-Request-Headers": {"x-header-1,x-header-2"}, }, http.Header{ "Vary": {"Origin, Access-Control-Request-Method, Access-Control-Request-Headers"}, "Access-Control-Allow-Origin": {"http://foobar.com"}, "Access-Control-Allow-Methods": {"GET"}, "Access-Control-Allow-Headers": {"x-header-1,x-header-2"}, }, true, }, { "DefaultAllowedHeaders", Options{ AllowedOrigins: []string{"http://foobar.com"}, AllowedHeaders: []string{}, }, "OPTIONS", http.Header{ "Origin": {"http://foobar.com"}, "Access-Control-Request-Method": {"GET"}, "Access-Control-Request-Headers": {"x-requested-with"}, }, http.Header{ "Vary": {"Origin, Access-Control-Request-Method, Access-Control-Request-Headers"}, "Access-Control-Allow-Origin": {"http://foobar.com"}, "Access-Control-Allow-Methods": {"GET"}, "Access-Control-Allow-Headers": {"x-requested-with"}, }, true, }, { "AllowedWildcardHeader", Options{ AllowedOrigins: []string{"http://foobar.com"}, AllowedHeaders: []string{"*"}, }, "OPTIONS", http.Header{ "Origin": {"http://foobar.com"}, "Access-Control-Request-Method": {"GET"}, "Access-Control-Request-Headers": {"x-header-1,x-header-2"}, }, http.Header{ "Vary": {"Origin, Access-Control-Request-Method, Access-Control-Request-Headers"}, "Access-Control-Allow-Origin": {"http://foobar.com"}, "Access-Control-Allow-Methods": {"GET"}, "Access-Control-Allow-Headers": {"x-header-1,x-header-2"}, }, true, }, { "DisallowedHeader", Options{ AllowedOrigins: []string{"http://foobar.com"}, AllowedHeaders: []string{"X-Header-1", "x-header-2"}, }, "OPTIONS", http.Header{ "Origin": {"http://foobar.com"}, "Access-Control-Request-Method": {"GET"}, "Access-Control-Request-Headers": {"x-header-1,x-header-3"}, }, http.Header{ "Vary": {"Origin, Access-Control-Request-Method, Access-Control-Request-Headers"}, }, true, }, { "ExposedHeader", Options{ AllowedOrigins: []string{"http://foobar.com"}, ExposedHeaders: []string{"X-Header-1", "x-header-2"}, }, "GET", http.Header{ "Origin": {"http://foobar.com"}, }, http.Header{ "Vary": {"Origin"}, "Access-Control-Allow-Origin": {"http://foobar.com"}, "Access-Control-Expose-Headers": {"X-Header-1, X-Header-2"}, }, true, }, { "AllowedCredentials", Options{ AllowedOrigins: []string{"http://foobar.com"}, AllowCredentials: true, }, "OPTIONS", http.Header{ "Origin": {"http://foobar.com"}, "Access-Control-Request-Method": {"GET"}, }, http.Header{ "Vary": {"Origin, Access-Control-Request-Method, Access-Control-Request-Headers"}, "Access-Control-Allow-Origin": {"http://foobar.com"}, "Access-Control-Allow-Methods": {"GET"}, "Access-Control-Allow-Credentials": {"true"}, }, true, }, { "AllowedPrivateNetwork", Options{ AllowedOrigins: []string{"http://foobar.com"}, AllowPrivateNetwork: true, }, "OPTIONS", http.Header{ "Origin": {"http://foobar.com"}, "Access-Control-Request-Method": {"GET"}, "Access-Control-Request-Private-Network": {"true"}, }, http.Header{ "Vary": {"Origin, Access-Control-Request-Method, Access-Control-Request-Headers, Access-Control-Request-Private-Network"}, "Access-Control-Allow-Origin": {"http://foobar.com"}, "Access-Control-Allow-Methods": {"GET"}, "Access-Control-Allow-Private-Network": {"true"}, }, true, }, { "DisallowedPrivateNetwork", Options{ AllowedOrigins: []string{"http://foobar.com"}, }, "OPTIONS", http.Header{ "Origin": {"http://foobar.com"}, "Access-Control-Request-Method": {"GET"}, "Access-Control-Request-PrivateNetwork": {"true"}, }, http.Header{ "Vary": {"Origin, Access-Control-Request-Method, Access-Control-Request-Headers"}, "Access-Control-Allow-Origin": {"http://foobar.com"}, "Access-Control-Allow-Methods": {"GET"}, }, true, }, { "OptionPassthrough", Options{ OptionsPassthrough: true, }, "OPTIONS", http.Header{ "Origin": {"http://foobar.com"}, "Access-Control-Request-Method": {"GET"}, }, http.Header{ "Vary": {"Origin, Access-Control-Request-Method, Access-Control-Request-Headers"}, "Access-Control-Allow-Origin": {"*"}, "Access-Control-Allow-Methods": {"GET"}, }, true, }, { "NonPreflightOptions", Options{ AllowedOrigins: []string{"http://foobar.com"}, }, "OPTIONS", http.Header{ "Origin": {"http://foobar.com"}, }, http.Header{ "Vary": {"Origin"}, "Access-Control-Allow-Origin": {"http://foobar.com"}, }, true, }, { "AllowedOriginsPlusAllowOriginFunc", Options{ AllowedOrigins: []string{"*"}, AllowOriginFunc: func(origin string) bool { return true }, }, "GET", http.Header{ "Origin": {"http://foobar.com"}, }, http.Header{ "Vary": {"Origin"}, "Access-Control-Allow-Origin": {"http://foobar.com"}, }, true, }, { "MultipleACRHHeaders", Options{ AllowedOrigins: []string{"http://foobar.com"}, AllowedHeaders: []string{"Content-Type", "Authorization"}, }, "OPTIONS", http.Header{ "Origin": {"http://foobar.com"}, "Access-Control-Request-Method": {"GET"}, "Access-Control-Request-Headers": {"authorization", "content-type"}, }, http.Header{ "Vary": {"Origin, Access-Control-Request-Method, Access-Control-Request-Headers"}, "Access-Control-Allow-Origin": {"http://foobar.com"}, "Access-Control-Allow-Methods": {"GET"}, "Access-Control-Allow-Headers": {"authorization", "content-type"}, }, true, }, { "MultipleACRHHeadersWithOWSAndEmptyElements", Options{ AllowedOrigins: []string{"http://foobar.com"}, AllowedHeaders: []string{"Content-Type", "Authorization"}, }, "OPTIONS", http.Header{ "Origin": {"http://foobar.com"}, "Access-Control-Request-Method": {"GET"}, "Access-Control-Request-Headers": {"authorization\t", " ", " content-type"}, }, http.Header{ "Vary": {"Origin, Access-Control-Request-Method, Access-Control-Request-Headers"}, "Access-Control-Allow-Origin": {"http://foobar.com"}, "Access-Control-Allow-Methods": {"GET"}, "Access-Control-Allow-Headers": {"authorization\t", " ", " content-type"}, }, true, }, } for i := range cases { tc := cases[i] t.Run(tc.name, func(t *testing.T) { s := New(tc.options) req, _ := http.NewRequest(tc.method, "http://example.com/foo", nil) for name, values := range tc.reqHeaders { for _, value := range values { req.Header.Add(name, value) } } t.Run("OriginAllowed", func(t *testing.T) { if have, want := s.OriginAllowed(req), tc.originAllowed; have != want { t.Errorf("OriginAllowed have: %t want: %t", have, want) } }) t.Run("Handler", func(t *testing.T) { res := httptest.NewRecorder() s.Handler(testHandler).ServeHTTP(res, req) assertHeaders(t, res.Header(), tc.resHeaders) }) t.Run("HandlerFunc", func(t *testing.T) { res := httptest.NewRecorder() s.HandlerFunc(res, req) assertHeaders(t, res.Header(), tc.resHeaders) }) t.Run("Negroni", func(t *testing.T) { res := httptest.NewRecorder() s.ServeHTTP(res, req, testHandler) assertHeaders(t, res.Header(), tc.resHeaders) }) }) } } func TestDebug(t *testing.T) { s := New(Options{ Debug: true, }) if s.Log == nil { t.Error("Logger not created when debug=true") } } type testLogger struct { buf *bytes.Buffer } func (l *testLogger) Printf(format string, v ...interface{}) { fmt.Fprintf(l.buf, format, v...) } func TestLogger(t *testing.T) { logger := &testLogger{buf: &bytes.Buffer{}} s := New(Options{ Logger: logger, }) if s.Log == nil { t.Error("Logger not created when Logger is set") } s.logf("test") if logger.buf.String() != "test" { t.Error("Logger not used") } } func TestDefault(t *testing.T) { s := Default() if s.Log != nil { t.Error("c.log should be nil when Default") } if !s.allowedOriginsAll { t.Error("c.allowedOriginsAll should be true when Default") } if s.allowedHeaders.Size() == 0 { t.Error("c.allowedHeaders should be empty when Default") } if s.allowedMethods == nil { t.Error("c.allowedMethods should be nil when Default") } } func TestHandlePreflightInvalidOriginAbortion(t *testing.T) { s := New(Options{ AllowedOrigins: []string{"http://foo.com"}, }) res := httptest.NewRecorder() req, _ := http.NewRequest("OPTIONS", "http://example.com/foo", nil) req.Header.Add("Origin", "http://example.com") s.handlePreflight(res, req) assertHeaders(t, res.Header(), http.Header{ "Vary": {"Origin, Access-Control-Request-Method, Access-Control-Request-Headers"}, }) } func TestHandlePreflightNoOptionsAbortion(t *testing.T) { s := New(Options{ // Intentionally left blank. }) res := httptest.NewRecorder() req, _ := http.NewRequest("GET", "http://example.com/foo", nil) s.handlePreflight(res, req) assertHeaders(t, res.Header(), http.Header{}) } func TestHandleActualRequestInvalidOriginAbortion(t *testing.T) { s := New(Options{ AllowedOrigins: []string{"http://foo.com"}, }) res := httptest.NewRecorder() req, _ := http.NewRequest("GET", "http://example.com/foo", nil) req.Header.Add("Origin", "http://example.com") s.handleActualRequest(res, req) assertHeaders(t, res.Header(), http.Header{ "Vary": {"Origin"}, }) } func TestHandleActualRequestInvalidMethodAbortion(t *testing.T) { s := New(Options{ AllowedMethods: []string{"POST"}, AllowCredentials: true, }) res := httptest.NewRecorder() req, _ := http.NewRequest("GET", "http://example.com/foo", nil) req.Header.Add("Origin", "http://example.com") s.handleActualRequest(res, req) assertHeaders(t, res.Header(), http.Header{ "Vary": {"Origin"}, }) } func TestIsMethodAllowedReturnsFalseWithNoMethods(t *testing.T) { s := New(Options{ // Intentionally left blank. }) s.allowedMethods = []string{} if s.isMethodAllowed("") { t.Error("IsMethodAllowed should return false when c.allowedMethods is nil.") } } func TestIsMethodAllowedReturnsTrueWithOptions(t *testing.T) { s := New(Options{ // Intentionally left blank. }) if !s.isMethodAllowed("OPTIONS") { t.Error("IsMethodAllowed should return true when c.allowedMethods is nil.") } } func TestOptionsSuccessStatusCodeDefault(t *testing.T) { s := New(Options{ // Intentionally left blank. }) req, _ := http.NewRequest("OPTIONS", "http://example.com/foo", nil) req.Header.Add("Access-Control-Request-Method", "GET") t.Run("Handler", func(t *testing.T) { res := httptest.NewRecorder() s.Handler(testHandler).ServeHTTP(res, req) assertResponse(t, res, http.StatusNoContent) }) t.Run("HandlerFunc", func(t *testing.T) { res := httptest.NewRecorder() s.HandlerFunc(res, req) assertResponse(t, res, http.StatusNoContent) }) t.Run("Negroni", func(t *testing.T) { res := httptest.NewRecorder() s.ServeHTTP(res, req, testHandler) assertResponse(t, res, http.StatusNoContent) }) } func TestOptionsSuccessStatusCodeOverride(t *testing.T) { s := New(Options{ OptionsSuccessStatus: http.StatusOK, }) req, _ := http.NewRequest("OPTIONS", "http://example.com/foo", nil) req.Header.Add("Access-Control-Request-Method", "GET") t.Run("Handler", func(t *testing.T) { res := httptest.NewRecorder() s.Handler(testHandler).ServeHTTP(res, req) assertResponse(t, res, http.StatusOK) }) t.Run("HandlerFunc", func(t *testing.T) { res := httptest.NewRecorder() s.HandlerFunc(res, req) assertResponse(t, res, http.StatusOK) }) t.Run("Negroni", func(t *testing.T) { res := httptest.NewRecorder() s.ServeHTTP(res, req, testHandler) assertResponse(t, res, http.StatusOK) }) } func TestAccessControlExposeHeadersPresence(t *testing.T) { cases := []struct { name string options Options want bool }{ { name: "omit", options: Options{}, want: false, }, { name: "include", options: Options{ ExposedHeaders: []string{"X-Something"}, }, want: true, }, } for _, tt := range cases { t.Run(tt.name, func(t *testing.T) { s := New(tt.options) req, _ := http.NewRequest("GET", "http://example.com/foo", nil) req.Header.Add("Origin", "http://foobar.com") assertExposeHeaders := func(t *testing.T, resHeaders http.Header) { if _, have := resHeaders["Access-Control-Expose-Headers"]; have != tt.want { t.Errorf("Access-Control-Expose-Headers have: %t want: %t", have, tt.want) } } t.Run("Handler", func(t *testing.T) { res := httptest.NewRecorder() s.Handler(testHandler).ServeHTTP(res, req) assertExposeHeaders(t, res.Header()) }) t.Run("HandlerFunc", func(t *testing.T) { res := httptest.NewRecorder() s.HandlerFunc(res, req) assertExposeHeaders(t, res.Header()) }) t.Run("Negroni", func(t *testing.T) { res := httptest.NewRecorder() s.ServeHTTP(res, req, testHandler) assertExposeHeaders(t, res.Header()) }) }) } } cors-1.11.1/examples/000077500000000000000000000000001466405624700143755ustar00rootroot00000000000000cors-1.11.1/examples/alice/000077500000000000000000000000001466405624700154525ustar00rootroot00000000000000cors-1.11.1/examples/alice/server.go000066400000000000000000000007161466405624700173130ustar00rootroot00000000000000package main import ( "net/http" "github.com/justinas/alice" "github.com/rs/cors" ) func main() { c := cors.New(cors.Options{ AllowedOrigins: []string{"http://foo.com"}, }) mux := http.NewServeMux() mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") w.Write([]byte("{\"hello\": \"world\"}")) }) chain := alice.New(c.Handler).Then(mux) http.ListenAndServe(":8080", chain) } cors-1.11.1/examples/buffalo/000077500000000000000000000000001466405624700160135ustar00rootroot00000000000000cors-1.11.1/examples/buffalo/server.go000066400000000000000000000011071466405624700176470ustar00rootroot00000000000000package main import ( "log" "github.com/gobuffalo/buffalo" "github.com/gobuffalo/buffalo/render" "github.com/rs/cors" ) var r *render.Engine func init() { r = render.New(render.Options{}) } func main() { app := App() if err := app.Serve(); err != nil { log.Fatal(err) } } func App() *buffalo.App { app := buffalo.New(buffalo.Options{ PreWares: []buffalo.PreWare{cors.Default().Handler}, }) app.GET("/", HomeHandler) return app } func HomeHandler(c buffalo.Context) error { return c.Render(200, r.JSON(map[string]string{"message": "Welcome to Buffalo!"})) } cors-1.11.1/examples/chi/000077500000000000000000000000001466405624700151405ustar00rootroot00000000000000cors-1.11.1/examples/chi/server.go000066400000000000000000000004631466405624700170000ustar00rootroot00000000000000package main import ( "net/http" "github.com/go-chi/chi" "github.com/rs/cors" ) func main() { r := chi.NewRouter() // Use default options r.Use(cors.Default().Handler) r.Get("/", func(w http.ResponseWriter, r *http.Request) { w.Write([]byte("welcome")) }) http.ListenAndServe(":8080", r) } cors-1.11.1/examples/default/000077500000000000000000000000001466405624700160215ustar00rootroot00000000000000cors-1.11.1/examples/default/server.go000066400000000000000000000005711466405624700176610ustar00rootroot00000000000000package main import ( "net/http" "github.com/rs/cors" ) func main() { mux := http.NewServeMux() mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") w.Write([]byte("{\"hello\": \"world\"}")) }) // Use default options handler := cors.Default().Handler(mux) http.ListenAndServe(":8080", handler) } cors-1.11.1/examples/gin/000077500000000000000000000000001466405624700151525ustar00rootroot00000000000000cors-1.11.1/examples/gin/server.go000066400000000000000000000004571466405624700170150ustar00rootroot00000000000000package main import ( "net/http" "github.com/gin-gonic/gin" cors "github.com/rs/cors/wrapper/gin" ) func main() { router := gin.Default() router.Use(cors.Default()) router.GET("/", func(context *gin.Context) { context.JSON(http.StatusOK, gin.H{"hello": "world"}) }) router.Run(":8080") } cors-1.11.1/examples/go.mod000066400000000000000000000075321466405624700155120ustar00rootroot00000000000000module github.com/rs/cors/examples go 1.22.2 require ( github.com/codegangsta/negroni v1.0.0 github.com/gin-gonic/gin v1.9.1 github.com/go-chi/chi v1.5.5 github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab github.com/gobuffalo/buffalo v1.1.0 github.com/gorilla/mux v1.8.1 github.com/julienschmidt/httprouter v1.3.0 github.com/justinas/alice v1.2.0 github.com/martini-contrib/render v0.0.0-20150707142108-ec18f8345a11 github.com/rs/cors v1.11.0 github.com/rs/cors/wrapper/gin v0.0.0-20240428121854-85fc0cac7b03 github.com/zenazn/goji v1.0.1 ) require ( github.com/BurntSushi/toml v1.2.1 // indirect github.com/aymerick/douceur v0.2.0 // indirect github.com/bytedance/sonic v1.9.1 // indirect github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0 // indirect github.com/dustin/go-humanize v1.0.1 // indirect github.com/fatih/color v1.13.0 // indirect github.com/fatih/structs v1.1.0 // indirect github.com/felixge/httpsnoop v1.0.1 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect github.com/gabriel-vasile/mimetype v1.4.2 // indirect github.com/gin-contrib/sse v0.1.0 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-playground/validator/v10 v10.14.0 // indirect github.com/gobuffalo/envy v1.10.2 // indirect github.com/gobuffalo/events v1.4.3 // indirect github.com/gobuffalo/flect v1.0.0 // indirect github.com/gobuffalo/github_flavored_markdown v1.1.3 // indirect github.com/gobuffalo/grift v1.5.2 // indirect github.com/gobuffalo/helpers v0.6.7 // indirect github.com/gobuffalo/logger v1.0.7 // indirect github.com/gobuffalo/meta v0.3.3 // indirect github.com/gobuffalo/nulls v0.4.2 // indirect github.com/gobuffalo/plush/v4 v4.1.18 // indirect github.com/gobuffalo/refresh v1.13.3 // indirect github.com/gobuffalo/tags/v3 v3.1.4 // indirect github.com/gobuffalo/validate/v3 v3.3.3 // indirect github.com/goccy/go-json v0.10.2 // indirect github.com/gofrs/uuid v4.2.0+incompatible // indirect github.com/gorilla/css v1.0.0 // indirect github.com/gorilla/handlers v1.5.1 // indirect github.com/gorilla/securecookie v1.1.1 // indirect github.com/gorilla/sessions v1.2.1 // indirect github.com/inconshreveable/mousetrap v1.0.1 // indirect github.com/joho/godotenv v1.4.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/cpuid/v2 v2.2.4 // indirect github.com/leodido/go-urn v1.2.4 // indirect github.com/mattn/go-colorable v0.1.9 // indirect github.com/mattn/go-isatty v0.0.19 // indirect github.com/microcosm-cc/bluemonday v1.0.20 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/monoculum/formam v3.5.5+incompatible // indirect github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c // indirect github.com/pelletier/go-toml/v2 v2.0.8 // indirect github.com/rogpeppe/go-internal v1.9.0 // indirect github.com/sergi/go-diff v1.2.0 // indirect github.com/sirupsen/logrus v1.9.0 // indirect github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d // indirect github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e // indirect github.com/spf13/cobra v1.6.1 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.2.11 // indirect golang.org/x/arch v0.3.0 // indirect golang.org/x/crypto v0.9.0 // indirect golang.org/x/net v0.10.0 // indirect golang.org/x/sys v0.8.0 // indirect golang.org/x/term v0.8.0 // indirect golang.org/x/text v0.9.0 // indirect google.golang.org/protobuf v1.30.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) cors-1.11.1/examples/go.sum000066400000000000000000000562111466405624700155350ustar00rootroot00000000000000github.com/BurntSushi/toml v1.2.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/toml v1.2.1 h1:9F2/+DoOYIOksmaJFPw1tGFy1eDnIJXg+UHjuD8lTak= github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk= github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4= github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s= github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams= github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0 h1:sDMmm+q/3+BukdIpxwO365v/Rbspp2Nt5XntgQRXq8Q= github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcjuz89kmFXt9morQgcfYZAYZ5n8WHjt81YYWIwtTM= github.com/codegangsta/negroni v1.0.0 h1:+aYywywx4bnKXWvoWtRfJ91vC59NbEhEY03sZjQhbVY= github.com/codegangsta/negroni v1.0.0/go.mod h1:v0y3T5G7Y1UlFfyxFn/QLRU4a2EuNau2iZY63YTKWo0= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= github.com/felixge/httpsnoop v1.0.1 h1:lvB5Jl89CsZtGIWuTcDM1E/vkVs49/Ml7JJe07l8SPQ= github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU= github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg= github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU= github.com/go-chi/chi v1.5.5 h1:vOB/HbEMt9QqBqErz07QehcOKHaWFtuj87tTDVz2qXE= github.com/go-chi/chi v1.5.5/go.mod h1:C9JqLr3tIYjDOZpzn+BCuxY8z8vmca43EeMgyZt7irw= github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab h1:xveKWz2iaueeTaUgdetzel+U7exyigDYBryyVfV/rZk= github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab/go.mod h1:/P9AEU963A2AYjv4d1V5eVL1CQbEJq6aCNHDDjibzu8= github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js= github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/gobuffalo/buffalo v1.1.0 h1:6y1fUC47QWevaM1ImukJFHNgxiRIT+Y74VcP4ZQaz80= github.com/gobuffalo/buffalo v1.1.0/go.mod h1:lLsx9Y8bFYu9uvQyIEB3M0QA908ChHUPjwOGumZWARU= github.com/gobuffalo/envy v1.10.2 h1:EIi03p9c3yeuRCFPOKcSfajzkLb3hrRjEpHGI8I2Wo4= github.com/gobuffalo/envy v1.10.2/go.mod h1:qGAGwdvDsaEtPhfBzb3o0SfDea8ByGn9j8bKmVft9z8= github.com/gobuffalo/events v1.4.3 h1:JYDq7NbozP10zaN9Ijfem6Ozox2KacU2fU38RyquXM8= github.com/gobuffalo/events v1.4.3/go.mod h1:2BwfpV5X63t8xkUcVqIv4IbyAobJazRSVu1F1pgf3rc= github.com/gobuffalo/flect v0.3.0/go.mod h1:5pf3aGnsvqvCj50AVni7mJJF8ICxGZ8HomberC3pXLE= github.com/gobuffalo/flect v1.0.0 h1:eBFmskjXZgAOagiTXJH25Nt5sdFwNRcb8DKZsIsAUQI= github.com/gobuffalo/flect v1.0.0/go.mod h1:l9V6xSb4BlXwsxEMj3FVEub2nkdQjWhPvD8XTTlHPQc= github.com/gobuffalo/github_flavored_markdown v1.1.3 h1:rSMPtx9ePkFB22vJ+dH+m/EUBS8doQ3S8LeEXcdwZHk= github.com/gobuffalo/github_flavored_markdown v1.1.3/go.mod h1:IzgO5xS6hqkDmUh91BW/+Qxo/qYnvfzoz3A7uLkg77I= github.com/gobuffalo/grift v1.5.2 h1:mC0vHRs+nXz+JhkH3sv+rVnnTQRDXrUrOXOPYpgPjpo= github.com/gobuffalo/grift v1.5.2/go.mod h1:Uf/3T2AR1Vv+t84EPmxCjqQ8oyJwXs0FAoLMFUn/JVs= github.com/gobuffalo/helpers v0.6.7 h1:C9CedoRSfgWg2ZoIkVXgjI5kgmSpL34Z3qdnzpfNVd8= github.com/gobuffalo/helpers v0.6.7/go.mod h1:j0u1iC1VqlCaJEEVkZN8Ia3TEzfj/zoXANqyJExTMTA= github.com/gobuffalo/here v0.6.7/go.mod h1:vuCfanjqckTuRlqAitJz6QC4ABNnS27wLb816UhsPcc= github.com/gobuffalo/httptest v1.5.2 h1:GpGy520SfY1QEmyPvaqmznTpG4gEQqQ82HtHqyNEreM= github.com/gobuffalo/httptest v1.5.2/go.mod h1:FA23yjsWLGj92mVV74Qtc8eqluc11VqcWr8/C1vxt4g= github.com/gobuffalo/logger v1.0.7 h1:LTLwWelETXDYyqF/ASf0nxaIcdEOIJNxRokPcfI/xbU= github.com/gobuffalo/logger v1.0.7/go.mod h1:u40u6Bq3VVvaMcy5sRBclD8SXhBYPS0Qk95ubt+1xJM= github.com/gobuffalo/meta v0.3.3 h1:GwPWdbdnp4JrKASvMLa03OtmzISq7z/nE7T6aMqzoYM= github.com/gobuffalo/meta v0.3.3/go.mod h1:o4B099IUFUfK4555Guqxz1zHAqyuUQ/KtHXi8WvVeFE= github.com/gobuffalo/nulls v0.4.2 h1:GAqBR29R3oPY+WCC7JL9KKk9erchaNuV6unsOSZGQkw= github.com/gobuffalo/nulls v0.4.2/go.mod h1:EElw2zmBYafU2R9W4Ii1ByIj177wA/pc0JdjtD0EsH8= github.com/gobuffalo/plush/v4 v4.1.18 h1:bnPjdMTEUQHqj9TNX2Ck3mxEXYZa+0nrFMNM07kpX9g= github.com/gobuffalo/plush/v4 v4.1.18/go.mod h1:xi2tJIhFI4UdzIL8sxZtzGYOd2xbBpcFbLZlIPGGZhU= github.com/gobuffalo/refresh v1.13.3 h1:HYQlI6RiqWUf2yzCXvUHAYqm9M9/teVnox+mjzo/9rQ= github.com/gobuffalo/refresh v1.13.3/go.mod h1:NkzgLKZGk5suOvgvOD0/VALog0fH29Ib7fwym9JmRxA= github.com/gobuffalo/tags/v3 v3.1.4 h1:X/ydLLPhgXV4h04Hp2xlbI2oc5MDaa7eub6zw8oHjsM= github.com/gobuffalo/tags/v3 v3.1.4/go.mod h1:ArRNo3ErlHO8BtdA0REaZxijuWnWzF6PUXngmMXd2I0= github.com/gobuffalo/validate/v3 v3.3.3 h1:o7wkIGSvZBYBd6ChQoLxkz2y1pfmhbI4jNJYh6PuNJ4= github.com/gobuffalo/validate/v3 v3.3.3/go.mod h1:YC7FsbJ/9hW/VjQdmXPvFqvRis4vrRYFxr69WiNZw6g= github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/gofrs/uuid v4.2.0+incompatible h1:yyYWMnhkhrKwwr8gAOcOCYxOOscHgDS9yZgBrnJfGa0= github.com/gofrs/uuid v4.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/gorilla/css v1.0.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY= github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c= github.com/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH4= github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ= github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= github.com/gorilla/sessions v1.2.1 h1:DHd3rPN5lE3Ts3D8rKkQ8x/0kqfeNmBAaiSi+o7FsgI= github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= github.com/inconshreveable/mousetrap v1.0.1 h1:U3uMjPSQEBMNp1lFxmllqCPM6P5u/Xq7Pgzkat/bFNc= github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/jmoiron/sqlx v1.3.5 h1:vFFPA71p1o5gAeqtEAwLU4dnX2napprKtHr7PYIcN3g= github.com/jmoiron/sqlx v1.3.5/go.mod h1:nRVWtLre0KfCLJvgxzCsLVMogSvQ1zNJtpYr2Ccp0mQ= github.com/joho/godotenv v1.4.0 h1:3l4+N6zfMWnkbPEXKng2o2/MR5mSwTrBih4ZEkkz1lg= github.com/joho/godotenv v1.4.0/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/justinas/alice v1.2.0 h1:+MHSA/vccVCF4Uq37S42jwlkvI2Xzl7zTPCN5BnZNVo= github.com/justinas/alice v1.2.0/go.mod h1:fN5HRH/reO/zrUflLfTN43t3vXvKzvZIENsNEe7i7qA= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk= github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q= github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4= github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/martini-contrib/render v0.0.0-20150707142108-ec18f8345a11 h1:YFh+sjyJTMQSYjKwM4dFKhJPJC/wfo98tPUc17HdoYw= github.com/martini-contrib/render v0.0.0-20150707142108-ec18f8345a11/go.mod h1:Ah2dBMoxZEqk118as2T4u4fjfXarE0pPnMJaArZQZsI= github.com/mattn/go-colorable v0.1.9 h1:sqDoxXbdeALODt0DAeJCVp38ps9ZogZEAXjus69YV3U= github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= github.com/mattn/go-sqlite3 v1.14.15 h1:vfoHhTN1af61xCRSWzFIWzx2YskyMTwHLrExkBOjvxI= github.com/mattn/go-sqlite3 v1.14.15/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= github.com/microcosm-cc/bluemonday v1.0.20 h1:flpzsq4KU3QIYAYGV/szUat7H+GPOXR0B2JU5A1Wp8Y= github.com/microcosm-cc/bluemonday v1.0.20/go.mod h1:yfBmMi8mxvaZut3Yytv+jTXRY8mxyjJ0/kQBTElld50= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/monoculum/formam v3.5.5+incompatible h1:iPl5csfEN96G2N2mGu8V/ZB62XLf9ySTpC8KRH6qXec= github.com/monoculum/formam v3.5.5+incompatible/go.mod h1:RKgILGEJq24YyJ2ban8EO0RUVSJlF1pGsEvoLEACr/Q= github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c h1:rp5dCmg/yLR3mgFuSOe4oEnDDmGLROTvMragMUXpTQw= github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c/go.mod h1:X07ZCGwUbLaax7L0S3Tw4hpejzu63ZrrQiUe6W0hcy0= github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ= github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/psanford/memfs v0.0.0-20210214183328-a001468d78ef h1:NKxTG6GVGbfMXc2mIk+KphcH6hagbVXhcFkbTgYleTI= github.com/psanford/memfs v0.0.0-20210214183328-a001468d78ef/go.mod h1:tcaRap0jS3eifrEEllL6ZMd9dg8IlDpi2S1oARrQ+NI= github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/rs/cors v1.11.0 h1:0B9GE/r9Bc2UxRMMtymBkHTenPkHDv0CW4Y98GBY+po= github.com/rs/cors v1.11.0/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= github.com/rs/cors/wrapper/gin v0.0.0-20240428121854-85fc0cac7b03 h1:s7fD08L5WjfD/iFHrOOp9gmAAGcv2nWPEIJLEn07XDQ= github.com/rs/cors/wrapper/gin v0.0.0-20240428121854-85fc0cac7b03/go.mod h1:742Ialb8SOs5yB2PqRDzFcyND3280PoaS5/wcKQUQKE= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ= github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d h1:yKm7XZV6j9Ev6lojP2XaIshpT4ymkqhMeSghO5Ps00E= github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE= github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e h1:qpG93cPwA5f7s/ZPBJnGOYQNK/vKsaDaseuKT5Asee8= github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA= github.com/spf13/cobra v1.6.0/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY= github.com/spf13/cobra v1.6.1 h1:o94oiPyS4KD1mPy2fmcYYHHfCxLqYjJOhGsCHFZtEzA= github.com/spf13/cobra v1.6.1/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/zenazn/goji v1.0.1 h1:4lbD8Mx2h7IvloP7r2C0D6ltZP6Ufip8Hn0wmSK5LR8= github.com/zenazn/goji v1.0.1/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k= golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g= golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= golang.org/x/net v0.0.0-20221002022538-bcab6841153b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20220722155259-a9ba230a4035/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.8.0 h1:n5xxQn2i3PC0yLAbjTpNT85q/Kgzcr2gIoX9OrJUols= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= cors-1.11.1/examples/goji/000077500000000000000000000000001466405624700153255ustar00rootroot00000000000000cors-1.11.1/examples/goji/server.go000066400000000000000000000005761466405624700171720ustar00rootroot00000000000000package main import ( "net/http" "github.com/rs/cors" "github.com/zenazn/goji" ) func main() { c := cors.New(cors.Options{ AllowedOrigins: []string{"http://foo.com"}, }) goji.Use(c.Handler) goji.Get("/", func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") w.Write([]byte("{\"hello\": \"world\"}")) }) goji.Serve() } cors-1.11.1/examples/gorilla/000077500000000000000000000000001466405624700160265ustar00rootroot00000000000000cors-1.11.1/examples/gorilla/server.go000066400000000000000000000006121466405624700176620ustar00rootroot00000000000000package main import ( "net/http" "github.com/gorilla/mux" "github.com/rs/cors" ) func main() { r := mux.NewRouter() r.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") w.Write([]byte("{\"hello\": \"world\"}")) }) // Use default options handler := cors.Default().Handler(r) http.ListenAndServe(":8080", handler) } cors-1.11.1/examples/httprouter/000077500000000000000000000000001466405624700166155ustar00rootroot00000000000000cors-1.11.1/examples/httprouter/server.go000066400000000000000000000006501466405624700204530ustar00rootroot00000000000000package main import ( "net/http" "github.com/julienschmidt/httprouter" "github.com/rs/cors" ) func Hello(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { w.Header().Set("Content-Type", "application/json") w.Write([]byte("{\"hello\": \"world\"}")) } func main() { router := httprouter.New() router.GET("/", Hello) handler := cors.Default().Handler(router) http.ListenAndServe(":8080", handler) } cors-1.11.1/examples/martini/000077500000000000000000000000001466405624700160405ustar00rootroot00000000000000cors-1.11.1/examples/martini/server.go000066400000000000000000000006111466405624700176730ustar00rootroot00000000000000package main import ( "github.com/go-martini/martini" "github.com/martini-contrib/render" "github.com/rs/cors" ) func main() { c := cors.New(cors.Options{ AllowedOrigins: []string{"http://foo.com"}, }) m := martini.Classic() m.Use(render.Renderer()) m.Use(c.HandlerFunc) m.Get("/", func(r render.Render) { r.JSON(200, map[string]interface{}{"hello": "world"}) }) m.Run() } cors-1.11.1/examples/negroni/000077500000000000000000000000001466405624700160365ustar00rootroot00000000000000cors-1.11.1/examples/negroni/server.go000066400000000000000000000007121466405624700176730ustar00rootroot00000000000000package main import ( "net/http" "github.com/codegangsta/negroni" "github.com/rs/cors" ) func main() { c := cors.New(cors.Options{ AllowedOrigins: []string{"http://foo.com"}, }) mux := http.NewServeMux() mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") w.Write([]byte("{\"hello\": \"world\"}")) }) n := negroni.Classic() n.Use(c) n.UseHandler(mux) n.Run(":3000") } cors-1.11.1/examples/nethttp/000077500000000000000000000000001466405624700160635ustar00rootroot00000000000000cors-1.11.1/examples/nethttp/server.go000066400000000000000000000006011466405624700177150ustar00rootroot00000000000000package main import ( "net/http" "github.com/rs/cors" ) func main() { c := cors.New(cors.Options{ AllowedOrigins: []string{"http://foo.com"}, }) handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") w.Write([]byte("{\"hello\": \"world\"}")) }) http.ListenAndServe(":8080", c.Handler(handler)) } cors-1.11.1/examples/openbar/000077500000000000000000000000001466405624700160235ustar00rootroot00000000000000cors-1.11.1/examples/openbar/server.go000066400000000000000000000007021466405624700176570ustar00rootroot00000000000000package main import ( "net/http" "github.com/rs/cors" ) func main() { c := cors.New(cors.Options{ AllowedOrigins: []string{"*"}, AllowedMethods: []string{"GET", "POST", "PUT", "DELETE"}, AllowCredentials: true, }) h := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") w.Write([]byte("{\"hello\": \"world\"}")) }) http.ListenAndServe(":8080", c.Handler(h)) } cors-1.11.1/go.mod000066400000000000000000000000431466405624700136620ustar00rootroot00000000000000module github.com/rs/cors go 1.13 cors-1.11.1/go.sum000066400000000000000000000000001466405624700137000ustar00rootroot00000000000000cors-1.11.1/internal/000077500000000000000000000000001466405624700143735ustar00rootroot00000000000000cors-1.11.1/internal/sortedset.go000066400000000000000000000112551466405624700167420ustar00rootroot00000000000000// adapted from github.com/jub0bs/cors package internal import ( "sort" "strings" ) // A SortedSet represents a mathematical set of strings sorted in // lexicographical order. // Each element has a unique position ranging from 0 (inclusive) // to the set's cardinality (exclusive). // The zero value represents an empty set. type SortedSet struct { m map[string]int maxLen int } // NewSortedSet returns a SortedSet that contains all of elems, // but no other elements. func NewSortedSet(elems ...string) SortedSet { sort.Strings(elems) m := make(map[string]int) var maxLen int i := 0 for _, s := range elems { if _, exists := m[s]; exists { continue } m[s] = i i++ maxLen = max(maxLen, len(s)) } return SortedSet{ m: m, maxLen: maxLen, } } // Size returns the cardinality of set. func (set SortedSet) Size() int { return len(set.m) } // String sorts joins the elements of set (in lexicographical order) // with a comma and returns the resulting string. func (set SortedSet) String() string { elems := make([]string, len(set.m)) for elem, i := range set.m { elems[i] = elem // safe indexing, by construction of SortedSet } return strings.Join(elems, ",") } // Accepts reports whether values is a sequence of list-based field values // whose elements are // - all members of set, // - sorted in lexicographical order, // - unique. func (set SortedSet) Accepts(values []string) bool { var ( // effectively constant maxLen = maxOWSBytes + set.maxLen + maxOWSBytes + 1 // +1 for comma ) var ( posOfLastNameSeen = -1 name string commaFound bool emptyElements int ok bool ) for _, s := range values { for { // As a defense against maliciously long names in s, // we process only a small number of s's leading bytes per iteration. name, s, commaFound = cutAtComma(s, maxLen) name, ok = trimOWS(name, maxOWSBytes) if !ok { return false } if name == "" { // RFC 9110 requires recipients to tolerate // "a reasonable number of empty list elements"; see // https://httpwg.org/specs/rfc9110.html#abnf.extension.recipient. emptyElements++ if emptyElements > maxEmptyElements { return false } if !commaFound { // We have now exhausted the names in s. break } continue } pos, ok := set.m[name] if !ok { return false } // The names in s are expected to be sorted in lexicographical order // and to each appear at most once. // Therefore, the positions (in set) of the names that // appear in s should form a strictly increasing sequence. // If that's not actually the case, bail out. if pos <= posOfLastNameSeen { return false } posOfLastNameSeen = pos if !commaFound { // We have now exhausted the names in s. break } } } return true } const ( maxOWSBytes = 1 // number of leading/trailing OWS bytes tolerated maxEmptyElements = 16 // number of empty list elements tolerated ) func cutAtComma(s string, n int) (before, after string, found bool) { // Note: this implementation draws inspiration from strings.Cut's. end := min(len(s), n) if i := strings.IndexByte(s[:end], ','); i >= 0 { after = s[i+1:] // deal with this first to save one bounds check return s[:i], after, true } return s, "", false } // TrimOWS trims up to n bytes of [optional whitespace (OWS)] // from the start of and/or the end of s. // If no more than n bytes of OWS are found at the start of s // and no more than n bytes of OWS are found at the end of s, // it returns the trimmed result and true. // Otherwise, it returns the original string and false. // // [optional whitespace (OWS)]: https://httpwg.org/specs/rfc9110.html#whitespace func trimOWS(s string, n int) (trimmed string, ok bool) { if s == "" { return s, true } trimmed, ok = trimRightOWS(s, n) if !ok { return s, false } trimmed, ok = trimLeftOWS(trimmed, n) if !ok { return s, false } return trimmed, true } func trimLeftOWS(s string, n int) (string, bool) { sCopy := s var i int for len(s) > 0 { if i > n { return sCopy, false } if !(s[0] == ' ' || s[0] == '\t') { break } s = s[1:] i++ } return s, true } func trimRightOWS(s string, n int) (string, bool) { sCopy := s var i int for len(s) > 0 { if i > n { return sCopy, false } last := len(s) - 1 if !(s[last] == ' ' || s[last] == '\t') { break } s = s[:last] i++ } return s, true } // TODO: when updating go directive to 1.21 or later, // use min builtin instead. func min(a, b int) int { if a < b { return a } return b } // TODO: when updating go directive to 1.21 or later, // use max builtin instead. func max(a, b int) int { if a > b { return a } return b } cors-1.11.1/internal/sortedset_test.go000066400000000000000000000132561466405624700200040ustar00rootroot00000000000000package internal import ( "strings" "testing" ) func TestSortedSet(t *testing.T) { cases := []struct { desc string elems []string // expectations size int combined string slice []string accepted [][]string rejected [][]string }{ { desc: "empty set", size: 0, combined: "", accepted: [][]string{ // some empty elements, possibly with OWS {""}, {","}, {"\t, , "}, // multiple field lines, some empty elements make([]string, maxEmptyElements), }, rejected: [][]string{ {"x-bar"}, {"x-bar,x-foo"}, // too many empty elements {strings.Repeat(",", maxEmptyElements+1)}, // multiple field lines, too many empty elements make([]string, maxEmptyElements+1), }, }, { desc: "singleton set", elems: []string{"x-foo"}, size: 1, combined: "x-foo", slice: []string{"X-Foo"}, accepted: [][]string{ {"x-foo"}, // some empty elements, possibly with OWS {""}, {","}, {"\t, , "}, {"\tx-foo ,"}, {" x-foo\t,"}, {strings.Repeat(",", maxEmptyElements) + "x-foo"}, // multiple field lines, some empty elements append(make([]string, maxEmptyElements), "x-foo"), make([]string, maxEmptyElements), }, rejected: [][]string{ {"x-bar"}, {"x-bar,x-foo"}, // too much OWS {"x-foo "}, {" x-foo "}, {" x-foo "}, {"x-foo\t\t"}, {"\tx-foo\t\t"}, {"\t\tx-foo\t\t"}, // too many empty elements {strings.Repeat(",", maxEmptyElements+1) + "x-foo"}, // multiple field lines, too many empty elements append(make([]string, maxEmptyElements+1), "x-foo"), make([]string, maxEmptyElements+1), }, }, { desc: "no dupes", elems: []string{"x-foo", "x-bar", "x-baz"}, size: 3, combined: "x-bar,x-baz,x-foo", slice: []string{"X-Bar", "X-Baz", "X-Foo"}, accepted: [][]string{ {"x-bar"}, {"x-baz"}, {"x-foo"}, {"x-bar,x-baz"}, {"x-bar,x-foo"}, {"x-baz,x-foo"}, {"x-bar,x-baz,x-foo"}, // some empty elements, possibly with OWS {""}, {","}, {"\t, , "}, {"\tx-bar ,"}, {" x-baz\t,"}, {"x-foo,"}, {"\tx-bar ,\tx-baz ,"}, {" x-bar\t, x-foo\t,"}, {"x-baz,x-foo,"}, {" x-bar , x-baz , x-foo ,"}, {"x-bar" + strings.Repeat(",", maxEmptyElements+1) + "x-foo"}, // multiple field lines {"x-bar", "x-foo"}, {"x-bar", "x-baz,x-foo"}, // multiple field lines, some empty elements append(make([]string, maxEmptyElements), "x-bar", "x-foo"), make([]string, maxEmptyElements), }, rejected: [][]string{ {"x-qux"}, {"x-bar,x-baz,x-baz"}, {"x-qux,x-baz"}, {"x-qux,x-foo"}, {"x-quxbaz,x-foo"}, // too much OWS {"x-bar "}, {" x-baz "}, {" x-foo "}, {"x-bar\t\t,x-baz"}, {"x-bar,\tx-foo\t\t"}, {"\t\tx-baz,x-foo\t\t"}, {" x-bar\t,\tx-baz\t ,x-foo"}, // too many empty elements {"x-bar" + strings.Repeat(",", maxEmptyElements+2) + "x-foo"}, // multiple field lines, elements in the wrong order {"x-foo", "x-bar"}, // multiple field lines, too many empty elements append(make([]string, maxEmptyElements+1), "x-bar", "x-foo"), make([]string, maxEmptyElements+1), }, }, { desc: "some dupes", elems: []string{"x-foo", "x-bar", "x-foo"}, size: 2, combined: "x-bar,x-foo", slice: []string{"X-Bar", "X-Foo"}, accepted: [][]string{ {"x-bar"}, {"x-foo"}, {"x-bar,x-foo"}, // some empty elements, possibly with OWS {""}, {","}, {"\t, , "}, {"\tx-bar ,"}, {" x-foo\t,"}, {"x-foo,"}, {"\tx-bar ,\tx-foo ,"}, {" x-bar\t, x-foo\t,"}, {"x-bar,x-foo,"}, {" x-bar , x-foo ,"}, {"x-bar" + strings.Repeat(",", maxEmptyElements+1) + "x-foo"}, // multiple field lines {"x-bar", "x-foo"}, // multiple field lines, some empty elements append(make([]string, maxEmptyElements), "x-bar", "x-foo"), make([]string, maxEmptyElements), }, rejected: [][]string{ {"x-qux"}, {"x-qux,x-bar"}, {"x-qux,x-foo"}, {"x-qux,x-baz,x-foo"}, // too much OWS {"x-qux "}, {"x-qux,\t\tx-bar"}, {"x-qux,x-foo\t\t"}, {"\tx-qux , x-baz\t\t,x-foo"}, // too many empty elements {"x-bar" + strings.Repeat(",", maxEmptyElements+2) + "x-foo"}, // multiple field lines, elements in the wrong order {"x-foo", "x-bar"}, // multiple field lines, too much whitespace {"x-qux", "\t\tx-bar"}, {"x-qux", "x-foo\t\t"}, {"\tx-qux ", " x-baz\t\t,x-foo"}, // multiple field lines, too many empty elements append(make([]string, maxEmptyElements+1), "x-bar", "x-foo"), make([]string, maxEmptyElements+1), }, }, } for _, tc := range cases { f := func(t *testing.T) { elems := clone(tc.elems) set := NewSortedSet(tc.elems...) size := set.Size() if set.Size() != tc.size { const tmpl = "NewSortedSet(%#v...).Size(): got %d; want %d" t.Errorf(tmpl, elems, size, tc.size) } combined := set.String() if combined != tc.combined { const tmpl = "NewSortedSet(%#v...).String(): got %q; want %q" t.Errorf(tmpl, elems, combined, tc.combined) } for _, a := range tc.accepted { if !set.Accepts(a) { const tmpl = "%q rejects %q, but should accept it" t.Errorf(tmpl, set, a) } } for _, r := range tc.rejected { if set.Accepts(r) { const tmpl = "%q accepts %q, but should reject it" t.Errorf(tmpl, set, r) } } } t.Run(tc.desc, f) } } // adapted from https://pkg.go.dev/slices#Clone // TODO: when updating go directive to 1.21 or later, // use slices.Clone instead. func clone(s []string) []string { // The s[:0:0] preserves nil in case it matters. return append(s[:0:0], s...) } cors-1.11.1/utils.go000066400000000000000000000007321466405624700142500ustar00rootroot00000000000000package cors import ( "strings" ) type wildcard struct { prefix string suffix string } func (w wildcard) match(s string) bool { return len(s) >= len(w.prefix)+len(w.suffix) && strings.HasPrefix(s, w.prefix) && strings.HasSuffix(s, w.suffix) } // convert converts a list of string using the passed converter function func convert(s []string, f func(string) string) []string { out := make([]string, len(s)) for i := range s { out[i] = f(s[i]) } return out } cors-1.11.1/utils_test.go000066400000000000000000000016501466405624700153070ustar00rootroot00000000000000package cors import ( "strings" "testing" ) func TestWildcard(t *testing.T) { w := wildcard{"foo", "bar"} if !w.match("foobar") { t.Error("foo*bar should match foobar") } if !w.match("foobazbar") { t.Error("foo*bar should match foobazbar") } if w.match("foobaz") { t.Error("foo*bar should not match foobaz") } w = wildcard{"foo", "oof"} if w.match("foof") { t.Error("foo*oof should not match foof") } } func TestConvert(t *testing.T) { s := convert([]string{"A", "b", "C"}, strings.ToLower) e := []string{"a", "b", "c"} if s[0] != e[0] || s[1] != e[1] || s[2] != e[2] { t.Errorf("%v != %v", s, e) } } func BenchmarkWildcard(b *testing.B) { w := wildcard{"foo", "bar"} b.Run("match", func(b *testing.B) { b.ReportAllocs() for i := 0; i < b.N; i++ { w.match("foobazbar") } }) b.Run("too short", func(b *testing.B) { b.ReportAllocs() for i := 0; i < b.N; i++ { w.match("fobar") } }) } cors-1.11.1/wrapper/000077500000000000000000000000001466405624700142375ustar00rootroot00000000000000cors-1.11.1/wrapper/gin/000077500000000000000000000000001466405624700150145ustar00rootroot00000000000000cors-1.11.1/wrapper/gin/gin.go000066400000000000000000000033301466405624700161170ustar00rootroot00000000000000// Package cors/wrapper/gin provides gin.HandlerFunc to handle CORS related // requests as a wrapper of github.com/rs/cors handler. package gin import ( "net/http" "github.com/gin-gonic/gin" "github.com/rs/cors" ) // Options is a configuration container to setup the CORS middleware. type Options = cors.Options // corsWrapper is a wrapper of cors.Cors handler which preserves information // about configured 'optionPassthrough' option. type corsWrapper struct { *cors.Cors optionsSuccessStatus int optionsPassthrough bool } // build transforms wrapped cors.Cors handler into Gin middleware. func (c corsWrapper) build() gin.HandlerFunc { return func(ctx *gin.Context) { c.HandlerFunc(ctx.Writer, ctx.Request) if !c.optionsPassthrough && ctx.Request.Method == http.MethodOptions && ctx.GetHeader("Access-Control-Request-Method") != "" { // Abort processing next Gin middlewares. ctx.AbortWithStatus(c.optionsSuccessStatus) } } } // AllowAll creates a new CORS Gin middleware with permissive configuration // allowing all origins with all standard methods with any header and // credentials. func AllowAll() gin.HandlerFunc { return corsWrapper{Cors: cors.AllowAll()}.build() } // Default creates a new CORS Gin middleware with default options. func Default() gin.HandlerFunc { return corsWrapper{Cors: cors.Default()}.build() } // New creates a new CORS Gin middleware with the provided options. func New(options Options) gin.HandlerFunc { status := options.OptionsSuccessStatus if status == 0 { status = http.StatusNoContent } wrapper := corsWrapper{ Cors: cors.New(options), optionsSuccessStatus: status, optionsPassthrough: options.OptionsPassthrough, } return wrapper.build() } cors-1.11.1/wrapper/gin/gin_test.go000066400000000000000000000032351466405624700171620ustar00rootroot00000000000000package gin import ( "net/http" "net/http/httptest" "testing" "github.com/gin-gonic/gin" ) func init() { gin.SetMode(gin.ReleaseMode) } func TestAllowAllNotNil(t *testing.T) { handler := AllowAll() if handler == nil { t.Error("Should not return nil Gin handler") } } func TestDefaultNotNil(t *testing.T) { handler := Default() if handler == nil { t.Error("Should not return nil Gin handler") } } func TestNewNotNil(t *testing.T) { handler := New(Options{}) if handler == nil { t.Error("Should not return nil Gin handler") } } func TestCorsWrapper_buildAbortsWhenPreflight(t *testing.T) { res := httptest.NewRecorder() ctx, _ := gin.CreateTestContext(res) ctx.Request, _ = http.NewRequest("OPTIONS", "http://example.com/foo", nil) ctx.Request.Header.Add("Origin", "http://example.org") ctx.Request.Header.Add("Access-Control-Request-Method", "POST") ctx.Status(http.StatusAccepted) res.Code = http.StatusAccepted handler := New(Options{ /* Intentionally left blank. */ }) handler(ctx) if !ctx.IsAborted() { t.Error("Should abort on preflight requests") } if res.Code != http.StatusNoContent { t.Error("Should abort with 204 Non Content status") } } func TestCorsWrapper_buildNotAbortsWhenPassthrough(t *testing.T) { res := httptest.NewRecorder() ctx, _ := gin.CreateTestContext(res) ctx.Request, _ = http.NewRequest("OPTIONS", "http://example.com/foo", nil) ctx.Request.Header.Add("Origin", "http://example.org") ctx.Request.Header.Add("Access-Control-Request-Method", "POST") handler := New(Options{ OptionsPassthrough: true, }) handler(ctx) if ctx.IsAborted() { t.Error("Should not abort when OPTIONS passthrough enabled") } } cors-1.11.1/wrapper/gin/go.mod000066400000000000000000000025511466405624700161250ustar00rootroot00000000000000module github.com/rs/cors/wrapper/gin go 1.17 require ( github.com/gin-gonic/gin v1.9.1 github.com/rs/cors v1.11.0 ) require ( github.com/bytedance/sonic v1.9.1 // indirect github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect github.com/gabriel-vasile/mimetype v1.4.2 // indirect github.com/gin-contrib/sse v0.1.0 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-playground/validator/v10 v10.14.0 // indirect github.com/goccy/go-json v0.10.2 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/cpuid/v2 v2.2.4 // indirect github.com/leodido/go-urn v1.2.4 // indirect github.com/mattn/go-isatty v0.0.19 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/pelletier/go-toml/v2 v2.0.8 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.2.11 // indirect golang.org/x/arch v0.3.0 // indirect golang.org/x/crypto v0.9.0 // indirect golang.org/x/net v0.10.0 // indirect golang.org/x/sys v0.8.0 // indirect golang.org/x/text v0.9.0 // indirect google.golang.org/protobuf v1.30.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) replace github.com/rs/cors => ../../ cors-1.11.1/wrapper/gin/go.sum000066400000000000000000000256751466405624700161660ustar00rootroot00000000000000github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s= github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams= github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU= github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg= github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU= github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js= github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk= github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q= github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4= github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ= github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k= golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g= golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=