diff options
author | 2025-03-09 17:47:56 +0100 | |
---|---|---|
committer | 2025-03-10 01:59:49 +0100 | |
commit | 3ac1ee16f377d31a0fb80c8dae28b6239ac4229e (patch) | |
tree | f61faa581feaaeaba2542b9f2b8234a590684413 /vendor/github.com/gorilla | |
parent | [chore] update URLs to forked source (diff) | |
download | gotosocial-3ac1ee16f377d31a0fb80c8dae28b6239ac4229e.tar.xz |
[chore] remove vendor
Diffstat (limited to 'vendor/github.com/gorilla')
77 files changed, 0 insertions, 9087 deletions
diff --git a/vendor/github.com/gorilla/context/.editorconfig b/vendor/github.com/gorilla/context/.editorconfig deleted file mode 100644 index 2940ec92a..000000000 --- a/vendor/github.com/gorilla/context/.editorconfig +++ /dev/null @@ -1,20 +0,0 @@ -; https://editorconfig.org/ - -root = true - -[*] -insert_final_newline = true -charset = utf-8 -trim_trailing_whitespace = true -indent_style = space -indent_size = 2 - -[{Makefile,go.mod,go.sum,*.go,.gitmodules}] -indent_style = tab -indent_size = 4 - -[*.md] -indent_size = 4 -trim_trailing_whitespace = false - -eclint_indent_style = unset diff --git a/vendor/github.com/gorilla/context/.gitignore b/vendor/github.com/gorilla/context/.gitignore deleted file mode 100644 index 84039fec6..000000000 --- a/vendor/github.com/gorilla/context/.gitignore +++ /dev/null @@ -1 +0,0 @@ -coverage.coverprofile diff --git a/vendor/github.com/gorilla/context/.golangci.yml b/vendor/github.com/gorilla/context/.golangci.yml deleted file mode 100644 index 1def5e627..000000000 --- a/vendor/github.com/gorilla/context/.golangci.yml +++ /dev/null @@ -1,12 +0,0 @@ -linters: - enable: - - errcheck - - gosimple - - govet - - ineffassign - - staticcheck - - unused - - contextcheck - - goconst - - gofmt - - misspell diff --git a/vendor/github.com/gorilla/context/LICENSE b/vendor/github.com/gorilla/context/LICENSE deleted file mode 100644 index f2f8749bc..000000000 --- a/vendor/github.com/gorilla/context/LICENSE +++ /dev/null @@ -1,27 +0,0 @@ -Copyright (c) 2012-2023 The Gorilla web toolkit authors. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/gorilla/context/Makefile b/vendor/github.com/gorilla/context/Makefile deleted file mode 100644 index c02b8a41f..000000000 --- a/vendor/github.com/gorilla/context/Makefile +++ /dev/null @@ -1,52 +0,0 @@ -GO_LINT=$(shell which golangci-lint 2> /dev/null || echo '') -GO_LINT_URI=github.com/golangci/golangci-lint/cmd/golangci-lint@latest - -GO_SEC=$(shell which gosec 2> /dev/null || echo '') -GO_SEC_URI=github.com/securego/gosec/v2/cmd/gosec@latest - -GO_VULNCHECK=$(shell which govulncheck 2> /dev/null || echo '') -GO_VULNCHECK_URI=golang.org/x/vuln/cmd/govulncheck@latest - -.PHONY: golangci-lint -golangci-lint: ## Run golangci-lint. Example: make golangci-lint - $(if $(GO_LINT), ,go install $(GO_LINT_URI)) - @echo "##### Running golangci-lint #####" - golangci-lint run -v - -.PHONY: verify -verify: ## Run all verifications [golangci-lint]. Example: make verify - @echo "##### Running verifications #####" - $(MAKE) golangci-lint - -.PHONY: gosec -gosec: ## Run gosec. Example: make gosec - $(if $(GO_SEC), ,go install $(GO_SEC_URI)) - @echo "##### Running gosec #####" - gosec ./... - -.PHONY: govulncheck -govulncheck: ## Run govulncheck. Example: make govulncheck - $(if $(GO_VULNCHECK), ,go install $(GO_VULNCHECK_URI)) - @echo "##### Running govulncheck #####" - govulncheck ./... - -.PHONY: security -security: ## Run all security checks [gosec, govulncheck]. Example: make security - @echo "##### Running security checks #####" - $(MAKE) gosec - $(MAKE) govulncheck - -.PHONY: test-unit -test-unit: ## Run unit tests. Example: make test-unit - @echo "##### Running unit tests #####" - go test -race -cover -coverprofile=coverage.coverprofile -covermode=atomic -v ./... - -.PHONY: test -test: ## Run all tests [test-unit]. Example: make test - @echo "##### Running tests #####" - $(MAKE) test-unit - -.PHONY: help -help: ## Print this help. Example: make help - @echo "##### Printing help #####" - @awk 'BEGIN {FS = ":.*?## "} /^[a-zA-Z_-]+:.*?## / {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' $(MAKEFILE_LIST) diff --git a/vendor/github.com/gorilla/context/README.md b/vendor/github.com/gorilla/context/README.md deleted file mode 100644 index 6fb5fb049..000000000 --- a/vendor/github.com/gorilla/context/README.md +++ /dev/null @@ -1,26 +0,0 @@ -# gorilla/context - -[](https://img.shields.io/github/license/gorilla/.github) - -[](https://codecov.io/github/gorilla/context) -[](https://godoc.org/github.com/gorilla/context) -[](https://sourcegraph.com/github.com/gorilla/context?badge) -[](https://bestpractices.coreinfrastructure.org/projects/7656) - - - -> ⚠⚠⚠ **Note** ⚠⚠⚠ gorilla/context, having been born well before `context.Context` existed, does not play well -> with the shallow copying of the request that [`http.Request.WithContext`](https://golang.org/pkg/net/http/#Request.WithContext) (added to net/http Go 1.7 onwards) performs. -> -> Using gorilla/context may lead to memory leaks under those conditions, as the pointers to each `http.Request` become "islanded" and will not be cleaned up when the response is sent. -> -> You should use the `http.Request.Context()` feature in Go 1.7. - -gorilla/context is a general purpose registry for global request variables. - -* It stores a `map[*http.Request]map[interface{}]interface{}` as a global singleton, and thus tracks variables by their HTTP request. - - -### License - -See the LICENSE file for details. diff --git a/vendor/github.com/gorilla/context/context.go b/vendor/github.com/gorilla/context/context.go deleted file mode 100644 index 9160564dd..000000000 --- a/vendor/github.com/gorilla/context/context.go +++ /dev/null @@ -1,139 +0,0 @@ -package context - -import ( - "net/http" - "sync" - "time" -) - -var ( - mutex sync.RWMutex - data = make(map[*http.Request]map[interface{}]interface{}) - datat = make(map[*http.Request]int64) -) - -// Set stores a value for a given key in a given request. -func Set(r *http.Request, key, val interface{}) { - mutex.Lock() - if data[r] == nil { - data[r] = make(map[interface{}]interface{}) - datat[r] = time.Now().Unix() - } - data[r][key] = val - mutex.Unlock() -} - -// Get returns a value stored for a given key in a given request. -func Get(r *http.Request, key interface{}) interface{} { - mutex.RLock() - if ctx := data[r]; ctx != nil { - value := ctx[key] - mutex.RUnlock() - return value - } - mutex.RUnlock() - return nil -} - -// GetOk returns stored value and presence state like multi-value return of map access. -func GetOk(r *http.Request, key interface{}) (interface{}, bool) { - mutex.RLock() - if _, ok := data[r]; ok { - value, ok := data[r][key] - mutex.RUnlock() - return value, ok - } - mutex.RUnlock() - return nil, false -} - -// GetAll returns all stored values for the request as a map. Nil is returned for invalid requests. -func GetAll(r *http.Request) map[interface{}]interface{} { - mutex.RLock() - if context, ok := data[r]; ok { - result := make(map[interface{}]interface{}, len(context)) - for k, v := range context { - result[k] = v - } - mutex.RUnlock() - return result - } - mutex.RUnlock() - return nil -} - -// GetAllOk returns all stored values for the request as a map and a boolean value that indicates if -// the request was registered. -func GetAllOk(r *http.Request) (map[interface{}]interface{}, bool) { - mutex.RLock() - context, ok := data[r] - result := make(map[interface{}]interface{}, len(context)) - for k, v := range context { - result[k] = v - } - mutex.RUnlock() - return result, ok -} - -// Delete removes a value stored for a given key in a given request. -func Delete(r *http.Request, key interface{}) { - mutex.Lock() - if data[r] != nil { - delete(data[r], key) - } - mutex.Unlock() -} - -// Clear removes all values stored for a given request. -// -// This is usually called by a handler wrapper to clean up request -// variables at the end of a request lifetime. See ClearHandler(). -func Clear(r *http.Request) { - mutex.Lock() - clear(r) - mutex.Unlock() -} - -// clear is Clear without the lock. -func clear(r *http.Request) { - delete(data, r) - delete(datat, r) -} - -// Purge removes request data stored for longer than maxAge, in seconds. -// It returns the amount of requests removed. -// -// If maxAge <= 0, all request data is removed. -// -// This is only used for sanity check: in case context cleaning was not -// properly set some request data can be kept forever, consuming an increasing -// amount of memory. In case this is detected, Purge() must be called -// periodically until the problem is fixed. -func Purge(maxAge int) int { - mutex.Lock() - count := 0 - if maxAge <= 0 { - count = len(data) - data = make(map[*http.Request]map[interface{}]interface{}) - datat = make(map[*http.Request]int64) - } else { - min := time.Now().Unix() - int64(maxAge) - for r := range data { - if datat[r] < min { - clear(r) - count++ - } - } - } - mutex.Unlock() - return count -} - -// ClearHandler wraps an http.Handler and clears request values at the end -// of a request lifetime. -func ClearHandler(h http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - defer Clear(r) - h.ServeHTTP(w, r) - }) -} diff --git a/vendor/github.com/gorilla/context/doc.go b/vendor/github.com/gorilla/context/doc.go deleted file mode 100644 index 448d1bfca..000000000 --- a/vendor/github.com/gorilla/context/doc.go +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright 2012 The Gorilla Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -/* -Package context stores values shared during a request lifetime. - -Note: gorilla/context, having been born well before `context.Context` existed, -does not play well > with the shallow copying of the request that -[`http.Request.WithContext`](https://golang.org/pkg/net/http/#Request.WithContext) -(added to net/http Go 1.7 onwards) performs. You should either use *just* -gorilla/context, or moving forward, the new `http.Request.Context()`. - -For example, a router can set variables extracted from the URL and later -application handlers can access those values, or it can be used to store -sessions values to be saved at the end of a request. There are several -others common uses. - -The idea was posted by Brad Fitzpatrick to the go-nuts mailing list: - - http://groups.google.com/group/golang-nuts/msg/e2d679d303aa5d53 - -Here's the basic usage: first define the keys that you will need. The key -type is interface{} so a key can be of any type that supports equality. -Here we define a key using a custom int type to avoid name collisions: - - package foo - - import ( - "github.com/gorilla/context" - ) - - type key int - - const MyKey key = 0 - -Then set a variable. Variables are bound to an http.Request object, so you -need a request instance to set a value: - - context.Set(r, MyKey, "bar") - -The application can later access the variable using the same key you provided: - - func MyHandler(w http.ResponseWriter, r *http.Request) { - // val is "bar". - val := context.Get(r, foo.MyKey) - - // returns ("bar", true) - val, ok := context.GetOk(r, foo.MyKey) - // ... - } - -And that's all about the basic usage. We discuss some other ideas below. - -Any type can be stored in the context. To enforce a given type, make the key -private and wrap Get() and Set() to accept and return values of a specific -type: - - type key int - - const mykey key = 0 - - // GetMyKey returns a value for this package from the request values. - func GetMyKey(r *http.Request) SomeType { - if rv := context.Get(r, mykey); rv != nil { - return rv.(SomeType) - } - return nil - } - - // SetMyKey sets a value for this package in the request values. - func SetMyKey(r *http.Request, val SomeType) { - context.Set(r, mykey, val) - } - -Variables must be cleared at the end of a request, to remove all values -that were stored. This can be done in an http.Handler, after a request was -served. Just call Clear() passing the request: - - context.Clear(r) - -...or use ClearHandler(), which conveniently wraps an http.Handler to clear -variables at the end of a request lifetime. - -The Routers from the packages gorilla/mux and gorilla/pat call Clear() -so if you are using either of them you don't need to clear the context manually. -*/ -package context diff --git a/vendor/github.com/gorilla/css/LICENSE b/vendor/github.com/gorilla/css/LICENSE deleted file mode 100644 index ee0d53cef..000000000 --- a/vendor/github.com/gorilla/css/LICENSE +++ /dev/null @@ -1,28 +0,0 @@ -Copyright (c) 2023 The Gorilla Authors. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - diff --git a/vendor/github.com/gorilla/css/scanner/doc.go b/vendor/github.com/gorilla/css/scanner/doc.go deleted file mode 100644 index f19850e15..000000000 --- a/vendor/github.com/gorilla/css/scanner/doc.go +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2012 The Gorilla Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -/* -Package gorilla/css/scanner generates tokens for a CSS3 input. - -It follows the CSS3 specification located at: - - http://www.w3.org/TR/css3-syntax/ - -To use it, create a new scanner for a given CSS string and call Next() until -the token returned has type TokenEOF or TokenError: - - s := scanner.New(myCSS) - for { - token := s.Next() - if token.Type == scanner.TokenEOF || token.Type == scanner.TokenError { - break - } - // Do something with the token... - } - -Following the CSS3 specification, an error can only occur when the scanner -finds an unclosed quote or unclosed comment. In these cases the text becomes -"untokenizable". Everything else is tokenizable and it is up to a parser -to make sense of the token stream (or ignore nonsensical token sequences). - -Note: the scanner doesn't perform lexical analysis or, in other words, it -doesn't care about the token context. It is intended to be used by a -lexer or parser. -*/ -package scanner diff --git a/vendor/github.com/gorilla/css/scanner/scanner.go b/vendor/github.com/gorilla/css/scanner/scanner.go deleted file mode 100644 index 25a7c6576..000000000 --- a/vendor/github.com/gorilla/css/scanner/scanner.go +++ /dev/null @@ -1,360 +0,0 @@ -// Copyright 2012 The Gorilla Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package scanner - -import ( - "fmt" - "regexp" - "strings" - "unicode" - "unicode/utf8" -) - -// tokenType identifies the type of lexical tokens. -type tokenType int - -// String returns a string representation of the token type. -func (t tokenType) String() string { - return tokenNames[t] -} - -// Token represents a token and the corresponding string. -type Token struct { - Type tokenType - Value string - Line int - Column int -} - -// String returns a string representation of the token. -func (t *Token) String() string { - if len(t.Value) > 10 { - return fmt.Sprintf("%s (line: %d, column: %d): %.10q...", - t.Type, t.Line, t.Column, t.Value) - } - return fmt.Sprintf("%s (line: %d, column: %d): %q", - t.Type, t.Line, t.Column, t.Value) -} - -// All tokens ----------------------------------------------------------------- - -// The complete list of tokens in CSS3. -const ( - // Scanner flags. - TokenError tokenType = iota - TokenEOF - // From now on, only tokens from the CSS specification. - TokenIdent - TokenAtKeyword - TokenString - TokenHash - TokenNumber - TokenPercentage - TokenDimension - TokenURI - TokenUnicodeRange - TokenCDO - TokenCDC - TokenS - TokenComment - TokenFunction - TokenIncludes - TokenDashMatch - TokenPrefixMatch - TokenSuffixMatch - TokenSubstringMatch - TokenChar - TokenBOM -) - -// tokenNames maps tokenType's to their names. Used for conversion to string. -var tokenNames = map[tokenType]string{ - TokenError: "error", - TokenEOF: "EOF", - TokenIdent: "IDENT", - TokenAtKeyword: "ATKEYWORD", - TokenString: "STRING", - TokenHash: "HASH", - TokenNumber: "NUMBER", - TokenPercentage: "PERCENTAGE", - TokenDimension: "DIMENSION", - TokenURI: "URI", - TokenUnicodeRange: "UNICODE-RANGE", - TokenCDO: "CDO", - TokenCDC: "CDC", - TokenS: "S", - TokenComment: "COMMENT", - TokenFunction: "FUNCTION", - TokenIncludes: "INCLUDES", - TokenDashMatch: "DASHMATCH", - TokenPrefixMatch: "PREFIXMATCH", - TokenSuffixMatch: "SUFFIXMATCH", - TokenSubstringMatch: "SUBSTRINGMATCH", - TokenChar: "CHAR", - TokenBOM: "BOM", -} - -// Macros and productions ----------------------------------------------------- -// http://www.w3.org/TR/css3-syntax/#tokenization - -var macroRegexp = regexp.MustCompile(`\{[a-z]+\}`) - -// macros maps macro names to patterns to be expanded. -var macros = map[string]string{ - // must be escaped: `\.+*?()|[]{}^$` - "ident": `-?{nmstart}{nmchar}*`, - "name": `{nmchar}+`, - "nmstart": `[a-zA-Z_]|{nonascii}|{escape}`, - "nonascii": "[\u0080-\uD7FF\uE000-\uFFFD\U00010000-\U0010FFFF]", - "unicode": `\\[0-9a-fA-F]{1,6}{wc}?`, - "escape": "{unicode}|\\\\[\u0020-\u007E\u0080-\uD7FF\uE000-\uFFFD\U00010000-\U0010FFFF]", - "nmchar": `[a-zA-Z0-9_-]|{nonascii}|{escape}`, - "num": `[0-9]*\.[0-9]+|[0-9]+`, - "string": `"(?:{stringchar}|')*"|'(?:{stringchar}|")*'`, - "stringchar": `{urlchar}|[ ]|\\{nl}`, - "nl": `[\n\r\f]|\r\n`, - "w": `{wc}*`, - "wc": `[\t\n\f\r ]`, - - // urlchar should accept [(ascii characters minus those that need escaping)|{nonascii}|{escape}] - // ASCII characters range = `[\u0020-\u007e]` - // Skip space \u0020 = `[\u0021-\u007e]` - // Skip quotation mark \0022 = `[\u0021\u0023-\u007e]` - // Skip apostrophe \u0027 = `[\u0021\u0023-\u0026\u0028-\u007e]` - // Skip reverse solidus \u005c = `[\u0021\u0023-\u0026\u0028-\u005b\u005d\u007e]` - // Finally, the left square bracket (\u005b) and right (\u005d) needs escaping themselves - "urlchar": "[\u0021\u0023-\u0026\u0028-\\\u005b\\\u005d-\u007E]|{nonascii}|{escape}", -} - -// productions maps the list of tokens to patterns to be expanded. -var productions = map[tokenType]string{ - // Unused regexps (matched using other methods) are commented out. - TokenIdent: `{ident}`, - TokenAtKeyword: `@{ident}`, - TokenString: `{string}`, - TokenHash: `#{name}`, - TokenNumber: `{num}`, - TokenPercentage: `{num}%`, - TokenDimension: `{num}{ident}`, - TokenURI: `url\({w}(?:{string}|{urlchar}*?){w}\)`, - TokenUnicodeRange: `U\+[0-9A-F\?]{1,6}(?:-[0-9A-F]{1,6})?`, - //TokenCDO: `<!--`, - TokenCDC: `-->`, - TokenS: `{wc}+`, - TokenComment: `/\*[^\*]*[\*]+(?:[^/][^\*]*[\*]+)*/`, - TokenFunction: `{ident}\(`, - //TokenIncludes: `~=`, - //TokenDashMatch: `\|=`, - //TokenPrefixMatch: `\^=`, - //TokenSuffixMatch: `\$=`, - //TokenSubstringMatch: `\*=`, - //TokenChar: `[^"']`, - //TokenBOM: "\uFEFF", -} - -// matchers maps the list of tokens to compiled regular expressions. -// -// The map is filled on init() using the macros and productions defined in -// the CSS specification. -var matchers = map[tokenType]*regexp.Regexp{} - -// matchOrder is the order to test regexps when first-char shortcuts -// can't be used. -var matchOrder = []tokenType{ - TokenURI, - TokenFunction, - TokenUnicodeRange, - TokenIdent, - TokenDimension, - TokenPercentage, - TokenNumber, - TokenCDC, -} - -func init() { - // replace macros and compile regexps for productions. - replaceMacro := func(s string) string { - return "(?:" + macros[s[1:len(s)-1]] + ")" - } - for t, s := range productions { - for macroRegexp.MatchString(s) { - s = macroRegexp.ReplaceAllStringFunc(s, replaceMacro) - } - matchers[t] = regexp.MustCompile("^(?:" + s + ")") - } -} - -// Scanner -------------------------------------------------------------------- - -// New returns a new CSS scanner for the given input. -func New(input string) *Scanner { - // Normalize newlines. - // https://www.w3.org/TR/css-syntax-3/#input-preprocessing - input = strings.Replace(input, "\r\n", "\n", -1) - input = strings.Replace(input, "\r", "\n", -1) - input = strings.Replace(input, "\f", "\n", -1) - input = strings.Replace(input, "\u0000", "\ufffd", -1) - return &Scanner{ - input: input, - row: 1, - col: 1, - } -} - -// Scanner scans an input and emits tokens following the CSS3 specification. -type Scanner struct { - input string - pos int - row int - col int - err *Token -} - -// Next returns the next token from the input. -// -// At the end of the input the token type is TokenEOF. -// -// If the input can't be tokenized the token type is TokenError. This occurs -// in case of unclosed quotation marks or comments. -func (s *Scanner) Next() *Token { - if s.err != nil { - return s.err - } - if s.pos >= len(s.input) { - s.err = &Token{TokenEOF, "", s.row, s.col} - return s.err - } - if s.pos == 0 { - // Test BOM only once, at the beginning of the file. - if strings.HasPrefix(s.input, "\uFEFF") { - return s.emitSimple(TokenBOM, "\uFEFF") - } - } - // There's a lot we can guess based on the first byte so we'll take a - // shortcut before testing multiple regexps. - input := s.input[s.pos:] - switch input[0] { - case '\t', '\n', ' ': - // Whitespace. - return s.emitToken(TokenS, matchers[TokenS].FindString(input)) - case '.': - // Dot is too common to not have a quick check. - // We'll test if this is a Char; if it is followed by a number it is a - // dimension/percentage/number, and this will be matched later. - if len(input) > 1 && !unicode.IsDigit(rune(input[1])) { - return s.emitSimple(TokenChar, ".") - } - case '#': - // Another common one: Hash or Char. - if match := matchers[TokenHash].FindString(input); match != "" { - return s.emitToken(TokenHash, match) - } - return s.emitSimple(TokenChar, "#") - case '@': - // Another common one: AtKeyword or Char. - if match := matchers[TokenAtKeyword].FindString(input); match != "" { - return s.emitSimple(TokenAtKeyword, match) - } - return s.emitSimple(TokenChar, "@") - case ':', ',', ';', '%', '&', '+', '=', '>', '(', ')', '[', ']', '{', '}': - // More common chars. - return s.emitSimple(TokenChar, string(input[0])) - case '"', '\'': - // String or error. - match := matchers[TokenString].FindString(input) - if match != "" { - return s.emitToken(TokenString, match) - } - - s.err = &Token{TokenError, "unclosed quotation mark", s.row, s.col} - return s.err - case '/': - // Comment, error or Char. - if len(input) > 1 && input[1] == '*' { - match := matchers[TokenComment].FindString(input) - if match != "" { - return s.emitToken(TokenComment, match) - } else { - s.err = &Token{TokenError, "unclosed comment", s.row, s.col} - return s.err - } - } - return s.emitSimple(TokenChar, "/") - case '~': - // Includes or Char. - return s.emitPrefixOrChar(TokenIncludes, "~=") - case '|': - // DashMatch or Char. - return s.emitPrefixOrChar(TokenDashMatch, "|=") - case '^': - // PrefixMatch or Char. - return s.emitPrefixOrChar(TokenPrefixMatch, "^=") - case '$': - // SuffixMatch or Char. - return s.emitPrefixOrChar(TokenSuffixMatch, "$=") - case '*': - // SubstringMatch or Char. - return s.emitPrefixOrChar(TokenSubstringMatch, "*=") - case '<': - // CDO or Char. - return s.emitPrefixOrChar(TokenCDO, "<!--") - } - // Test all regexps, in order. - for _, token := range matchOrder { - if match := matchers[token].FindString(input); match != "" { - return s.emitToken(token, match) - } - } - // We already handled unclosed quotation marks and comments, - // so this can only be a Char. - r, width := utf8.DecodeRuneInString(input) - token := &Token{TokenChar, string(r), s.row, s.col} - s.col += width - s.pos += width - return token -} - -// updatePosition updates input coordinates based on the consumed text. -func (s *Scanner) updatePosition(text string) { - width := utf8.RuneCountInString(text) - lines := strings.Count(text, "\n") - s.row += lines - if lines == 0 { - s.col += width - } else { - s.col = utf8.RuneCountInString(text[strings.LastIndex(text, "\n"):]) - } - s.pos += len(text) // while col is a rune index, pos is a byte index -} - -// emitToken returns a Token for the string v and updates the scanner position. -func (s *Scanner) emitToken(t tokenType, v string) *Token { - token := &Token{t, v, s.row, s.col} - s.updatePosition(v) - return token -} - -// emitSimple returns a Token for the string v and updates the scanner -// position in a simplified manner. -// -// The string is known to have only ASCII characters and to not have a newline. -func (s *Scanner) emitSimple(t tokenType, v string) *Token { - token := &Token{t, v, s.row, s.col} - s.col += len(v) - s.pos += len(v) - return token -} - -// emitPrefixOrChar returns a Token for type t if the current position -// matches the given prefix. Otherwise it returns a Char token using the -// first character from the prefix. -// -// The prefix is known to have only ASCII characters and to not have a newline. -func (s *Scanner) emitPrefixOrChar(t tokenType, prefix string) *Token { - if strings.HasPrefix(s.input[s.pos:], prefix) { - return s.emitSimple(t, prefix) - } - return s.emitSimple(TokenChar, string(prefix[0])) -} diff --git a/vendor/github.com/gorilla/feeds/.editorconfig b/vendor/github.com/gorilla/feeds/.editorconfig deleted file mode 100644 index 2940ec92a..000000000 --- a/vendor/github.com/gorilla/feeds/.editorconfig +++ /dev/null @@ -1,20 +0,0 @@ -; https://editorconfig.org/ - -root = true - -[*] -insert_final_newline = true -charset = utf-8 -trim_trailing_whitespace = true -indent_style = space -indent_size = 2 - -[{Makefile,go.mod,go.sum,*.go,.gitmodules}] -indent_style = tab -indent_size = 4 - -[*.md] -indent_size = 4 -trim_trailing_whitespace = false - -eclint_indent_style = unset diff --git a/vendor/github.com/gorilla/feeds/.gitignore b/vendor/github.com/gorilla/feeds/.gitignore deleted file mode 100644 index 84039fec6..000000000 --- a/vendor/github.com/gorilla/feeds/.gitignore +++ /dev/null @@ -1 +0,0 @@ -coverage.coverprofile diff --git a/vendor/github.com/gorilla/feeds/LICENSE b/vendor/github.com/gorilla/feeds/LICENSE deleted file mode 100644 index ee0d53cef..000000000 --- a/vendor/github.com/gorilla/feeds/LICENSE +++ /dev/null @@ -1,28 +0,0 @@ -Copyright (c) 2023 The Gorilla Authors. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - diff --git a/vendor/github.com/gorilla/feeds/Makefile b/vendor/github.com/gorilla/feeds/Makefile deleted file mode 100644 index ac37ffd32..000000000 --- a/vendor/github.com/gorilla/feeds/Makefile +++ /dev/null @@ -1,34 +0,0 @@ -GO_LINT=$(shell which golangci-lint 2> /dev/null || echo '') -GO_LINT_URI=github.com/golangci/golangci-lint/cmd/golangci-lint@latest - -GO_SEC=$(shell which gosec 2> /dev/null || echo '') -GO_SEC_URI=github.com/securego/gosec/v2/cmd/gosec@latest - -GO_VULNCHECK=$(shell which govulncheck 2> /dev/null || echo '') -GO_VULNCHECK_URI=golang.org/x/vuln/cmd/govulncheck@latest - -.PHONY: golangci-lint -golangci-lint: - $(if $(GO_LINT), ,go install $(GO_LINT_URI)) - @echo "##### Running golangci-lint" - golangci-lint run -v - -.PHONY: gosec -gosec: - $(if $(GO_SEC), ,go install $(GO_SEC_URI)) - @echo "##### Running gosec" - gosec ./... - -.PHONY: govulncheck -govulncheck: - $(if $(GO_VULNCHECK), ,go install $(GO_VULNCHECK_URI)) - @echo "##### Running govulncheck" - govulncheck ./... - -.PHONY: verify -verify: golangci-lint gosec govulncheck - -.PHONY: test -test: - @echo "##### Running tests" - go test -race -cover -coverprofile=coverage.coverprofile -covermode=atomic -v ./... diff --git a/vendor/github.com/gorilla/feeds/README.md b/vendor/github.com/gorilla/feeds/README.md deleted file mode 100644 index 7d7137b46..000000000 --- a/vendor/github.com/gorilla/feeds/README.md +++ /dev/null @@ -1,198 +0,0 @@ -## gorilla/feeds - -[](https://codecov.io/github/gorilla/feeds) -[](https://godoc.org/github.com/gorilla/feeds) -[](https://sourcegraph.com/github.com/gorilla/feeds?badge) - - - -feeds is a web feed generator library for generating RSS, Atom and JSON feeds from Go -applications. - -### Goals - - * Provide a simple interface to create both Atom & RSS 2.0 feeds - * Full support for [Atom][atom], [RSS 2.0][rss], and [JSON Feed Version 1][jsonfeed] spec elements - * Ability to modify particulars for each spec - -[atom]: https://tools.ietf.org/html/rfc4287 -[rss]: http://www.rssboard.org/rss-specification -[jsonfeed]: https://jsonfeed.org/version/1.1 - -### Usage - -```go -package main - -import ( - "fmt" - "log" - "time" - "github.com/gorilla/feeds" -) - -func main() { - now := time.Now() - feed := &feeds.Feed{ - Title: "jmoiron.net blog", - Link: &feeds.Link{Href: "http://jmoiron.net/blog"}, - Description: "discussion about tech, footie, photos", - Author: &feeds.Author{Name: "Jason Moiron", Email: "jmoiron@jmoiron.net"}, - Created: now, - } - - feed.Items = []*feeds.Item{ - &feeds.Item{ - Title: "Limiting Concurrency in Go", - Link: &feeds.Link{Href: "http://jmoiron.net/blog/limiting-concurrency-in-go/"}, - Description: "A discussion on controlled parallelism in golang", - Author: &feeds.Author{Name: "Jason Moiron", Email: "jmoiron@jmoiron.net"}, - Created: now, - }, - &feeds.Item{ - Title: "Logic-less Template Redux", - Link: &feeds.Link{Href: "http://jmoiron.net/blog/logicless-template-redux/"}, - Description: "More thoughts on logicless templates", - Created: now, - }, - &feeds.Item{ - Title: "Idiomatic Code Reuse in Go", - Link: &feeds.Link{Href: "http://jmoiron.net/blog/idiomatic-code-reuse-in-go/"}, - Description: "How to use interfaces <em>effectively</em>", - Created: now, - }, - } - - atom, err := feed.ToAtom() - if err != nil { - log.Fatal(err) - } - - rss, err := feed.ToRss() - if err != nil { - log.Fatal(err) - } - - json, err := feed.ToJSON() - if err != nil { - log.Fatal(err) - } - - fmt.Println(atom, "\n", rss, "\n", json) -} -``` - -Outputs: - -```xml -<?xml version="1.0" encoding="UTF-8"?> -<feed xmlns="http://www.w3.org/2005/Atom"> - <title>jmoiron.net blog</title> - <link href="http://jmoiron.net/blog"></link> - <id>http://jmoiron.net/blog</id> - <updated>2013-01-16T03:26:01-05:00</updated> - <summary>discussion about tech, footie, photos</summary> - <entry> - <title>Limiting Concurrency in Go</title> - <link href="http://jmoiron.net/blog/limiting-concurrency-in-go/"></link> - <updated>2013-01-16T03:26:01-05:00</updated> - <id>tag:jmoiron.net,2013-01-16:/blog/limiting-concurrency-in-go/</id> - <summary type="html">A discussion on controlled parallelism in golang</summary> - <author> - <name>Jason Moiron</name> - <email>jmoiron@jmoiron.net</email> - </author> - </entry> - <entry> - <title>Logic-less Template Redux</title> - <link href="http://jmoiron.net/blog/logicless-template-redux/"></link> - <updated>2013-01-16T03:26:01-05:00</updated> - <id>tag:jmoiron.net,2013-01-16:/blog/logicless-template-redux/</id> - <summary type="html">More thoughts on logicless templates</summary> - <author></author> - </entry> - <entry> - <title>Idiomatic Code Reuse in Go</title> - <link href="http://jmoiron.net/blog/idiomatic-code-reuse-in-go/"></link> - <updated>2013-01-16T03:26:01-05:00</updated> - <id>tag:jmoiron.net,2013-01-16:/blog/idiomatic-code-reuse-in-go/</id> - <summary type="html">How to use interfaces <em>effectively</em></summary> - <author></author> - </entry> -</feed> - -<?xml version="1.0" encoding="UTF-8"?> -<rss version="2.0"> - <channel> - <title>jmoiron.net blog</title> - <link>http://jmoiron.net/blog</link> - <description>discussion about tech, footie, photos</description> - <managingEditor>jmoiron@jmoiron.net (Jason Moiron)</managingEditor> - <pubDate>2013-01-16T03:22:24-05:00</pubDate> - <item> - <title>Limiting Concurrency in Go</title> - <link>http://jmoiron.net/blog/limiting-concurrency-in-go/</link> - <description>A discussion on controlled parallelism in golang</description> - <pubDate>2013-01-16T03:22:24-05:00</pubDate> - </item> - <item> - <title>Logic-less Template Redux</title> - <link>http://jmoiron.net/blog/logicless-template-redux/</link> - <description>More thoughts on logicless templates</description> - <pubDate>2013-01-16T03:22:24-05:00</pubDate> - </item> - <item> - <title>Idiomatic Code Reuse in Go</title> - <link>http://jmoiron.net/blog/idiomatic-code-reuse-in-go/</link> - <description>How to use interfaces <em>effectively</em></description> - <pubDate>2013-01-16T03:22:24-05:00</pubDate> - </item> - </channel> -</rss> - -{ - "version": "https://jsonfeed.org/version/1.1", - "title": "jmoiron.net blog", - "home_page_url": "http://jmoiron.net/blog", - "description": "discussion about tech, footie, photos", - "author": { - "name": "Jason Moiron" - }, - "authors": [ - { - "name": "Jason Moiron" - } - ], - "items": [ - { - "id": "", - "url": "http://jmoiron.net/blog/limiting-concurrency-in-go/", - "title": "Limiting Concurrency in Go", - "summary": "A discussion on controlled parallelism in golang", - "date_published": "2013-01-16T03:22:24.530817846-05:00", - "author": { - "name": "Jason Moiron" - }, - "authors": [ - { - "name": "Jason Moiron" - } - ] - }, - { - "id": "", - "url": "http://jmoiron.net/blog/logicless-template-redux/", - "title": "Logic-less Template Redux", - "summary": "More thoughts on logicless templates", - "date_published": "2013-01-16T03:22:24.530817846-05:00" - }, - { - "id": "", - "url": "http://jmoiron.net/blog/idiomatic-code-reuse-in-go/", - "title": "Idiomatic Code Reuse in Go", - "summary": "How to use interfaces \u003cem\u003eeffectively\u003c/em\u003e", - "date_published": "2013-01-16T03:22:24.530817846-05:00" - } - ] -} -``` diff --git a/vendor/github.com/gorilla/feeds/atom.go b/vendor/github.com/gorilla/feeds/atom.go deleted file mode 100644 index 73de995c1..000000000 --- a/vendor/github.com/gorilla/feeds/atom.go +++ /dev/null @@ -1,178 +0,0 @@ -package feeds - -import ( - "encoding/xml" - "fmt" - "net/url" - "time" -) - -// Generates Atom feed as XML - -const ns = "http://www.w3.org/2005/Atom" - -type AtomPerson struct { - Name string `xml:"name,omitempty"` - Uri string `xml:"uri,omitempty"` - Email string `xml:"email,omitempty"` -} - -type AtomSummary struct { - XMLName xml.Name `xml:"summary"` - Content string `xml:",chardata"` - Type string `xml:"type,attr"` -} - -type AtomContent struct { - XMLName xml.Name `xml:"content"` - Content string `xml:",chardata"` - Type string `xml:"type,attr"` -} - -type AtomAuthor struct { - XMLName xml.Name `xml:"author"` - AtomPerson -} - -type AtomContributor struct { - XMLName xml.Name `xml:"contributor"` - AtomPerson -} - -type AtomEntry struct { - XMLName xml.Name `xml:"entry"` - Xmlns string `xml:"xmlns,attr,omitempty"` - Title string `xml:"title"` // required - Updated string `xml:"updated"` // required - Id string `xml:"id"` // required - Category string `xml:"category,omitempty"` - Content *AtomContent - Rights string `xml:"rights,omitempty"` - Source string `xml:"source,omitempty"` - Published string `xml:"published,omitempty"` - Contributor *AtomContributor - Links []AtomLink // required if no child 'content' elements - Summary *AtomSummary // required if content has src or content is base64 - Author *AtomAuthor // required if feed lacks an author -} - -// Multiple links with different rel can coexist -type AtomLink struct { - //Atom 1.0 <link rel="enclosure" type="audio/mpeg" title="MP3" href="http://www.example.org/myaudiofile.mp3" length="1234" /> - XMLName xml.Name `xml:"link"` - Href string `xml:"href,attr"` - Rel string `xml:"rel,attr,omitempty"` - Type string `xml:"type,attr,omitempty"` - Length string `xml:"length,attr,omitempty"` -} - -type AtomFeed struct { - XMLName xml.Name `xml:"feed"` - Xmlns string `xml:"xmlns,attr"` - Title string `xml:"title"` // required - Id string `xml:"id"` // required - Updated string `xml:"updated"` // required - Category string `xml:"category,omitempty"` - Icon string `xml:"icon,omitempty"` - Logo string `xml:"logo,omitempty"` - Rights string `xml:"rights,omitempty"` // copyright used - Subtitle string `xml:"subtitle,omitempty"` - Link *AtomLink - Author *AtomAuthor `xml:"author,omitempty"` - Contributor *AtomContributor - Entries []*AtomEntry `xml:"entry"` -} - -type Atom struct { - *Feed -} - -func newAtomEntry(i *Item) *AtomEntry { - id := i.Id - link := i.Link - if link == nil { - link = &Link{} - } - if len(id) == 0 { - // if there's no id set, try to create one, either from data or just a uuid - if len(link.Href) > 0 && (!i.Created.IsZero() || !i.Updated.IsZero()) { - dateStr := anyTimeFormat("2006-01-02", i.Updated, i.Created) - host, path := link.Href, "/invalid.html" - if url, err := url.Parse(link.Href); err == nil { - host, path = url.Host, url.Path - } - id = fmt.Sprintf("tag:%s,%s:%s", host, dateStr, path) - } else { - id = "urn:uuid:" + NewUUID().String() - } - } - var name, email string - if i.Author != nil { - name, email = i.Author.Name, i.Author.Email - } - - link_rel := link.Rel - if link_rel == "" { - link_rel = "alternate" - } - x := &AtomEntry{ - Title: i.Title, - Links: []AtomLink{{Href: link.Href, Rel: link_rel, Type: link.Type}}, - Id: id, - Updated: anyTimeFormat(time.RFC3339, i.Updated, i.Created), - } - - // if there's a description, assume it's html - if len(i.Description) > 0 { - x.Summary = &AtomSummary{Content: i.Description, Type: "html"} - } - - // if there's a content, assume it's html - if len(i.Content) > 0 { - x.Content = &AtomContent{Content: i.Content, Type: "html"} - } - - if i.Enclosure != nil && link_rel != "enclosure" { - x.Links = append(x.Links, AtomLink{Href: i.Enclosure.Url, Rel: "enclosure", Type: i.Enclosure.Type, Length: i.Enclosure.Length}) - } - - if len(name) > 0 || len(email) > 0 { - x.Author = &AtomAuthor{AtomPerson: AtomPerson{Name: name, Email: email}} - } - return x -} - -// create a new AtomFeed with a generic Feed struct's data -func (a *Atom) AtomFeed() *AtomFeed { - updated := anyTimeFormat(time.RFC3339, a.Updated, a.Created) - link := a.Link - if link == nil { - link = &Link{} - } - feed := &AtomFeed{ - Xmlns: ns, - Title: a.Title, - Link: &AtomLink{Href: link.Href, Rel: link.Rel}, - Subtitle: a.Description, - Id: link.Href, - Updated: updated, - Rights: a.Copyright, - } - if a.Author != nil { - feed.Author = &AtomAuthor{AtomPerson: AtomPerson{Name: a.Author.Name, Email: a.Author.Email}} - } - for _, e := range a.Items { - feed.Entries = append(feed.Entries, newAtomEntry(e)) - } - return feed -} - -// FeedXml returns an XML-Ready object for an Atom object -func (a *Atom) FeedXml() interface{} { - return a.AtomFeed() -} - -// FeedXml returns an XML-ready object for an AtomFeed object -func (a *AtomFeed) FeedXml() interface{} { - return a -} diff --git a/vendor/github.com/gorilla/feeds/doc.go b/vendor/github.com/gorilla/feeds/doc.go deleted file mode 100644 index 4e0759ccc..000000000 --- a/vendor/github.com/gorilla/feeds/doc.go +++ /dev/null @@ -1,73 +0,0 @@ -/* -Syndication (feed) generator library for golang. - -Installing - - go get github.com/gorilla/feeds - -Feeds provides a simple, generic Feed interface with a generic Item object as well as RSS, Atom and JSON Feed specific RssFeed, AtomFeed and JSONFeed objects which allow access to all of each spec's defined elements. - -Examples - -Create a Feed and some Items in that feed using the generic interfaces: - - import ( - "time" - . "github.com/gorilla/feeds" - ) - - now = time.Now() - - feed := &Feed{ - Title: "jmoiron.net blog", - Link: &Link{Href: "http://jmoiron.net/blog"}, - Description: "discussion about tech, footie, photos", - Author: &Author{Name: "Jason Moiron", Email: "jmoiron@jmoiron.net"}, - Created: now, - Copyright: "This work is copyright © Benjamin Button", - } - - feed.Items = []*Item{ - &Item{ - Title: "Limiting Concurrency in Go", - Link: &Link{Href: "http://jmoiron.net/blog/limiting-concurrency-in-go/"}, - Description: "A discussion on controlled parallelism in golang", - Author: &Author{Name: "Jason Moiron", Email: "jmoiron@jmoiron.net"}, - Created: now, - }, - &Item{ - Title: "Logic-less Template Redux", - Link: &Link{Href: "http://jmoiron.net/blog/logicless-template-redux/"}, - Description: "More thoughts on logicless templates", - Created: now, - }, - &Item{ - Title: "Idiomatic Code Reuse in Go", - Link: &Link{Href: "http://jmoiron.net/blog/idiomatic-code-reuse-in-go/"}, - Description: "How to use interfaces <em>effectively</em>", - Created: now, - }, - } - -From here, you can output Atom, RSS, or JSON Feed versions of this feed easily - - atom, err := feed.ToAtom() - rss, err := feed.ToRss() - json, err := feed.ToJSON() - -You can also get access to the underlying objects that feeds uses to export its XML - - atomFeed := (&Atom{Feed: feed}).AtomFeed() - rssFeed := (&Rss{Feed: feed}).RssFeed() - jsonFeed := (&JSON{Feed: feed}).JSONFeed() - -From here, you can modify or add each syndication's specific fields before outputting - - atomFeed.Subtitle = "plays the blues" - atom, err := ToXML(atomFeed) - rssFeed.Generator = "gorilla/feeds v1.0 (github.com/gorilla/feeds)" - rss, err := ToXML(rssFeed) - jsonFeed.NextUrl = "https://www.example.com/feed.json?page=2" - json, err := jsonFeed.ToJSON() -*/ -package feeds diff --git a/vendor/github.com/gorilla/feeds/feed.go b/vendor/github.com/gorilla/feeds/feed.go deleted file mode 100644 index 929c226c0..000000000 --- a/vendor/github.com/gorilla/feeds/feed.go +++ /dev/null @@ -1,146 +0,0 @@ -package feeds - -import ( - "encoding/json" - "encoding/xml" - "io" - "sort" - "time" -) - -type Link struct { - Href, Rel, Type, Length string -} - -type Author struct { - Name, Email string -} - -type Image struct { - Url, Title, Link string - Width, Height int -} - -type Enclosure struct { - Url, Length, Type string -} - -type Item struct { - Title string - Link *Link - Source *Link - Author *Author - Description string // used as description in rss, summary in atom - Id string // used as guid in rss, id in atom - IsPermaLink string // an optional parameter for guid in rss - Updated time.Time - Created time.Time - Enclosure *Enclosure - Content string -} - -type Feed struct { - Title string - Link *Link - Description string - Author *Author - Updated time.Time - Created time.Time - Id string - Subtitle string - Items []*Item - Copyright string - Image *Image -} - -// add a new Item to a Feed -func (f *Feed) Add(item *Item) { - f.Items = append(f.Items, item) -} - -// returns the first non-zero time formatted as a string or "" -func anyTimeFormat(format string, times ...time.Time) string { - for _, t := range times { - if !t.IsZero() { - return t.Format(format) - } - } - return "" -} - -// interface used by ToXML to get a object suitable for exporting XML. -type XmlFeed interface { - FeedXml() interface{} -} - -// turn a feed object (either a Feed, AtomFeed, or RssFeed) into xml -// returns an error if xml marshaling fails -func ToXML(feed XmlFeed) (string, error) { - x := feed.FeedXml() - data, err := xml.MarshalIndent(x, "", " ") - if err != nil { - return "", err - } - // strip empty line from default xml header - s := xml.Header[:len(xml.Header)-1] + string(data) - return s, nil -} - -// WriteXML writes a feed object (either a Feed, AtomFeed, or RssFeed) as XML into -// the writer. Returns an error if XML marshaling fails. -func WriteXML(feed XmlFeed, w io.Writer) error { - x := feed.FeedXml() - // write default xml header, without the newline - if _, err := w.Write([]byte(xml.Header[:len(xml.Header)-1])); err != nil { - return err - } - e := xml.NewEncoder(w) - e.Indent("", " ") - return e.Encode(x) -} - -// creates an Atom representation of this feed -func (f *Feed) ToAtom() (string, error) { - a := &Atom{f} - return ToXML(a) -} - -// WriteAtom writes an Atom representation of this feed to the writer. -func (f *Feed) WriteAtom(w io.Writer) error { - return WriteXML(&Atom{f}, w) -} - -// creates an Rss representation of this feed -func (f *Feed) ToRss() (string, error) { - r := &Rss{f} - return ToXML(r) -} - -// WriteRss writes an RSS representation of this feed to the writer. -func (f *Feed) WriteRss(w io.Writer) error { - return WriteXML(&Rss{f}, w) -} - -// ToJSON creates a JSON Feed representation of this feed -func (f *Feed) ToJSON() (string, error) { - j := &JSON{f} - return j.ToJSON() -} - -// WriteJSON writes an JSON representation of this feed to the writer. -func (f *Feed) WriteJSON(w io.Writer) error { - j := &JSON{f} - feed := j.JSONFeed() - - e := json.NewEncoder(w) - e.SetIndent("", " ") - return e.Encode(feed) -} - -// Sort sorts the Items in the feed with the given less function. -func (f *Feed) Sort(less func(a, b *Item) bool) { - lessFunc := func(i, j int) bool { - return less(f.Items[i], f.Items[j]) - } - sort.SliceStable(f.Items, lessFunc) -} diff --git a/vendor/github.com/gorilla/feeds/json.go b/vendor/github.com/gorilla/feeds/json.go deleted file mode 100644 index ae5deb76d..000000000 --- a/vendor/github.com/gorilla/feeds/json.go +++ /dev/null @@ -1,190 +0,0 @@ -package feeds - -import ( - "encoding/json" - "strings" - "time" -) - -const jsonFeedVersion = "https://jsonfeed.org/version/1.1" - -// JSONAuthor represents the author of the feed or of an individual item -// in the feed -type JSONAuthor struct { - Name string `json:"name,omitempty"` - Url string `json:"url,omitempty"` - Avatar string `json:"avatar,omitempty"` -} - -// JSONAttachment represents a related resource. Podcasts, for instance, would -// include an attachment that’s an audio or video file. -type JSONAttachment struct { - Url string `json:"url,omitempty"` - MIMEType string `json:"mime_type,omitempty"` - Title string `json:"title,omitempty"` - Size int32 `json:"size,omitempty"` - Duration time.Duration `json:"duration_in_seconds,omitempty"` -} - -// MarshalJSON implements the json.Marshaler interface. -// The Duration field is marshaled in seconds, all other fields are marshaled -// based upon the definitions in struct tags. -func (a *JSONAttachment) MarshalJSON() ([]byte, error) { - type EmbeddedJSONAttachment JSONAttachment - return json.Marshal(&struct { - Duration float64 `json:"duration_in_seconds,omitempty"` - *EmbeddedJSONAttachment - }{ - EmbeddedJSONAttachment: (*EmbeddedJSONAttachment)(a), - Duration: a.Duration.Seconds(), - }) -} - -// UnmarshalJSON implements the json.Unmarshaler interface. -// The Duration field is expected to be in seconds, all other field types -// match the struct definition. -func (a *JSONAttachment) UnmarshalJSON(data []byte) error { - type EmbeddedJSONAttachment JSONAttachment - var raw struct { - Duration float64 `json:"duration_in_seconds,omitempty"` - *EmbeddedJSONAttachment - } - raw.EmbeddedJSONAttachment = (*EmbeddedJSONAttachment)(a) - - err := json.Unmarshal(data, &raw) - if err != nil { - return err - } - - if raw.Duration > 0 { - nsec := int64(raw.Duration * float64(time.Second)) - raw.EmbeddedJSONAttachment.Duration = time.Duration(nsec) - } - - return nil -} - -// JSONItem represents a single entry/post for the feed. -type JSONItem struct { - Id string `json:"id"` - Url string `json:"url,omitempty"` - ExternalUrl string `json:"external_url,omitempty"` - Title string `json:"title,omitempty"` - ContentHTML string `json:"content_html,omitempty"` - ContentText string `json:"content_text,omitempty"` - Summary string `json:"summary,omitempty"` - Image string `json:"image,omitempty"` - BannerImage string `json:"banner_,omitempty"` - PublishedDate *time.Time `json:"date_published,omitempty"` - ModifiedDate *time.Time `json:"date_modified,omitempty"` - Author *JSONAuthor `json:"author,omitempty"` // deprecated in JSON Feed v1.1, keeping for backwards compatibility - Authors []*JSONAuthor `json:"authors,omitempty"` - Tags []string `json:"tags,omitempty"` - Attachments []JSONAttachment `json:"attachments,omitempty"` -} - -// JSONHub describes an endpoint that can be used to subscribe to real-time -// notifications from the publisher of this feed. -type JSONHub struct { - Type string `json:"type"` - Url string `json:"url"` -} - -// JSONFeed represents a syndication feed in the JSON Feed Version 1 format. -// Matching the specification found here: https://jsonfeed.org/version/1. -type JSONFeed struct { - Version string `json:"version"` - Title string `json:"title"` - Language string `json:"language,omitempty"` - HomePageUrl string `json:"home_page_url,omitempty"` - FeedUrl string `json:"feed_url,omitempty"` - Description string `json:"description,omitempty"` - UserComment string `json:"user_comment,omitempty"` - NextUrl string `json:"next_url,omitempty"` - Icon string `json:"icon,omitempty"` - Favicon string `json:"favicon,omitempty"` - Author *JSONAuthor `json:"author,omitempty"` // deprecated in JSON Feed v1.1, keeping for backwards compatibility - Authors []*JSONAuthor `json:"authors,omitempty"` - Expired *bool `json:"expired,omitempty"` - Hubs []*JSONHub `json:"hubs,omitempty"` - Items []*JSONItem `json:"items,omitempty"` -} - -// JSON is used to convert a generic Feed to a JSONFeed. -type JSON struct { - *Feed -} - -// ToJSON encodes f into a JSON string. Returns an error if marshalling fails. -func (f *JSON) ToJSON() (string, error) { - return f.JSONFeed().ToJSON() -} - -// ToJSON encodes f into a JSON string. Returns an error if marshalling fails. -func (f *JSONFeed) ToJSON() (string, error) { - data, err := json.MarshalIndent(f, "", " ") - if err != nil { - return "", err - } - - return string(data), nil -} - -// JSONFeed creates a new JSONFeed with a generic Feed struct's data. -func (f *JSON) JSONFeed() *JSONFeed { - feed := &JSONFeed{ - Version: jsonFeedVersion, - Title: f.Title, - Description: f.Description, - } - - if f.Link != nil { - feed.HomePageUrl = f.Link.Href - } - if f.Author != nil { - author := &JSONAuthor{ - Name: f.Author.Name, - } - feed.Author = author - feed.Authors = []*JSONAuthor{author} - } - for _, e := range f.Items { - feed.Items = append(feed.Items, newJSONItem(e)) - } - return feed -} - -func newJSONItem(i *Item) *JSONItem { - item := &JSONItem{ - Id: i.Id, - Title: i.Title, - Summary: i.Description, - - ContentHTML: i.Content, - } - - if i.Link != nil { - item.Url = i.Link.Href - } - if i.Source != nil { - item.ExternalUrl = i.Source.Href - } - if i.Author != nil { - author := &JSONAuthor{ - Name: i.Author.Name, - } - item.Author = author - item.Authors = []*JSONAuthor{author} - } - if !i.Created.IsZero() { - item.PublishedDate = &i.Created - } - if !i.Updated.IsZero() { - item.ModifiedDate = &i.Updated - } - if i.Enclosure != nil && strings.HasPrefix(i.Enclosure.Type, "image/") { - item.Image = i.Enclosure.Url - } - - return item -} diff --git a/vendor/github.com/gorilla/feeds/rss.go b/vendor/github.com/gorilla/feeds/rss.go deleted file mode 100644 index 9326cef8b..000000000 --- a/vendor/github.com/gorilla/feeds/rss.go +++ /dev/null @@ -1,183 +0,0 @@ -package feeds - -// rss support -// validation done according to spec here: -// http://cyber.law.harvard.edu/rss/rss.html - -import ( - "encoding/xml" - "fmt" - "time" -) - -// private wrapper around the RssFeed which gives us the <rss>..</rss> xml -type RssFeedXml struct { - XMLName xml.Name `xml:"rss"` - Version string `xml:"version,attr"` - ContentNamespace string `xml:"xmlns:content,attr"` - Channel *RssFeed -} - -type RssContent struct { - XMLName xml.Name `xml:"content:encoded"` - Content string `xml:",cdata"` -} - -type RssImage struct { - XMLName xml.Name `xml:"image"` - Url string `xml:"url"` - Title string `xml:"title"` - Link string `xml:"link"` - Width int `xml:"width,omitempty"` - Height int `xml:"height,omitempty"` -} - -type RssTextInput struct { - XMLName xml.Name `xml:"textInput"` - Title string `xml:"title"` - Description string `xml:"description"` - Name string `xml:"name"` - Link string `xml:"link"` -} - -type RssFeed struct { - XMLName xml.Name `xml:"channel"` - Title string `xml:"title"` // required - Link string `xml:"link"` // required - Description string `xml:"description"` // required - Language string `xml:"language,omitempty"` - Copyright string `xml:"copyright,omitempty"` - ManagingEditor string `xml:"managingEditor,omitempty"` // Author used - WebMaster string `xml:"webMaster,omitempty"` - PubDate string `xml:"pubDate,omitempty"` // created or updated - LastBuildDate string `xml:"lastBuildDate,omitempty"` // updated used - Category string `xml:"category,omitempty"` - Generator string `xml:"generator,omitempty"` - Docs string `xml:"docs,omitempty"` - Cloud string `xml:"cloud,omitempty"` - Ttl int `xml:"ttl,omitempty"` - Rating string `xml:"rating,omitempty"` - SkipHours string `xml:"skipHours,omitempty"` - SkipDays string `xml:"skipDays,omitempty"` - Image *RssImage - TextInput *RssTextInput - Items []*RssItem `xml:"item"` -} - -type RssItem struct { - XMLName xml.Name `xml:"item"` - Title string `xml:"title"` // required - Link string `xml:"link"` // required - Description string `xml:"description"` // required - Content *RssContent - Author string `xml:"author,omitempty"` - Category string `xml:"category,omitempty"` - Comments string `xml:"comments,omitempty"` - Enclosure *RssEnclosure - Guid *RssGuid // Id used - PubDate string `xml:"pubDate,omitempty"` // created or updated - Source string `xml:"source,omitempty"` -} - -type RssEnclosure struct { - //RSS 2.0 <enclosure url="http://example.com/file.mp3" length="123456789" type="audio/mpeg" /> - XMLName xml.Name `xml:"enclosure"` - Url string `xml:"url,attr"` - Length string `xml:"length,attr"` - Type string `xml:"type,attr"` -} - -type RssGuid struct { - //RSS 2.0 <guid isPermaLink="true">http://inessential.com/2002/09/01.php#a2</guid> - XMLName xml.Name `xml:"guid"` - Id string `xml:",chardata"` - IsPermaLink string `xml:"isPermaLink,attr,omitempty"` // "true", "false", or an empty string -} - -type Rss struct { - *Feed -} - -// create a new RssItem with a generic Item struct's data -func newRssItem(i *Item) *RssItem { - item := &RssItem{ - Title: i.Title, - Description: i.Description, - PubDate: anyTimeFormat(time.RFC1123Z, i.Created, i.Updated), - } - if i.Id != "" { - item.Guid = &RssGuid{Id: i.Id, IsPermaLink: i.IsPermaLink} - } - if i.Link != nil { - item.Link = i.Link.Href - } - if len(i.Content) > 0 { - item.Content = &RssContent{Content: i.Content} - } - if i.Source != nil { - item.Source = i.Source.Href - } - - // Define a closure - if i.Enclosure != nil && i.Enclosure.Type != "" && i.Enclosure.Length != "" { - item.Enclosure = &RssEnclosure{Url: i.Enclosure.Url, Type: i.Enclosure.Type, Length: i.Enclosure.Length} - } - - if i.Author != nil { - item.Author = i.Author.Name - } - return item -} - -// create a new RssFeed with a generic Feed struct's data -func (r *Rss) RssFeed() *RssFeed { - pub := anyTimeFormat(time.RFC1123Z, r.Created, r.Updated) - build := anyTimeFormat(time.RFC1123Z, r.Updated) - author := "" - if r.Author != nil { - author = r.Author.Email - if len(r.Author.Name) > 0 { - author = fmt.Sprintf("%s (%s)", r.Author.Email, r.Author.Name) - } - } - - var image *RssImage - if r.Image != nil { - image = &RssImage{Url: r.Image.Url, Title: r.Image.Title, Link: r.Image.Link, Width: r.Image.Width, Height: r.Image.Height} - } - - var href string - if r.Link != nil { - href = r.Link.Href - } - channel := &RssFeed{ - Title: r.Title, - Link: href, - Description: r.Description, - ManagingEditor: author, - PubDate: pub, - LastBuildDate: build, - Copyright: r.Copyright, - Image: image, - } - for _, i := range r.Items { - channel.Items = append(channel.Items, newRssItem(i)) - } - return channel -} - -// FeedXml returns an XML-Ready object for an Rss object -func (r *Rss) FeedXml() interface{} { - // only generate version 2.0 feeds for now - return r.RssFeed().FeedXml() - -} - -// FeedXml returns an XML-ready object for an RssFeed object -func (r *RssFeed) FeedXml() interface{} { - return &RssFeedXml{ - Version: "2.0", - Channel: r, - ContentNamespace: "http://purl.org/rss/1.0/modules/content/", - } -} diff --git a/vendor/github.com/gorilla/feeds/test.atom b/vendor/github.com/gorilla/feeds/test.atom deleted file mode 100644 index aa1521481..000000000 --- a/vendor/github.com/gorilla/feeds/test.atom +++ /dev/null @@ -1,92 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<feed xmlns:atom="http://www.w3.org/2005/Atom"> - <title><![CDATA[Lorem ipsum feed for an interval of 1 minutes]]></title> - <description><![CDATA[This is a constantly updating lorem ipsum feed]]></description> - <link>http://example.com/</link> - <generator>RSS for Node</generator> - <lastBuildDate>Tue, 30 Oct 2018 23:22:37 GMT</lastBuildDate> - <author><![CDATA[John Smith]]></author> - <pubDate>Tue, 30 Oct 2018 23:22:00 GMT</pubDate> - <copyright><![CDATA[Michael Bertolacci, licensed under a Creative Commons Attribution 3.0 Unported License.]]></copyright> - <ttl>60</ttl> - <entry> - <title><![CDATA[Lorem ipsum 2018-10-30T23:22:00+00:00]]></title> - <description><![CDATA[Exercitation ut Lorem sint proident.]]></description> - <link>http://example.com/test/1540941720</link> - <guid isPermaLink="true">http://example.com/test/1540941720</guid> - <dc:creator><![CDATA[John Smith]]></dc:creator> - <pubDate>Tue, 30 Oct 2018 23:22:00 GMT</pubDate> - </entry> - <entry> - <title><![CDATA[Lorem ipsum 2018-10-30T23:21:00+00:00]]></title> - <description><![CDATA[Ea est do quis fugiat exercitation.]]></description> - <link>http://example.com/test/1540941660</link> - <guid isPermaLink="true">http://example.com/test/1540941660</guid> - <dc:creator><![CDATA[John Smith]]></dc:creator> - <pubDate>Tue, 30 Oct 2018 23:21:00 GMT</pubDate> - </entry> - <entry> - <title><![CDATA[Lorem ipsum 2018-10-30T23:20:00+00:00]]></title> - <description><![CDATA[Ipsum velit cillum ad laborum sit nulla exercitation consequat sint veniam culpa veniam voluptate incididunt.]]></description> - <link>http://example.com/test/1540941600</link> - <guid isPermaLink="true">http://example.com/test/1540941600</guid> - <dc:creator><![CDATA[John Smith]]></dc:creator> - <pubDate>Tue, 30 Oct 2018 23:20:00 GMT</pubDate> - </entry> - <entry> - <title><![CDATA[Lorem ipsum 2018-10-30T23:19:00+00:00]]></title> - <description><![CDATA[Ullamco pariatur aliqua consequat ea veniam id qui incididunt laborum.]]></description> - <link>http://example.com/test/1540941540</link> - <guid isPermaLink="true">http://example.com/test/1540941540</guid> - <dc:creator><![CDATA[John Smith]]></dc:creator> - <pubDate>Tue, 30 Oct 2018 23:19:00 GMT</pubDate> - </entry> - <entry> - <title><![CDATA[Lorem ipsum 2018-10-30T23:18:00+00:00]]></title> - <description><![CDATA[Velit proident aliquip aliquip anim mollit voluptate laboris voluptate et occaecat occaecat laboris ea nulla.]]></description> - <link>http://example.com/test/1540941480</link> - <guid isPermaLink="true">http://example.com/test/1540941480</guid> - <dc:creator><![CDATA[John Smith]]></dc:creator> - <pubDate>Tue, 30 Oct 2018 23:18:00 GMT</pubDate> - </entry> - <entry> - <title><![CDATA[Lorem ipsum 2018-10-30T23:17:00+00:00]]></title> - <description><![CDATA[Do in quis mollit consequat id in minim laborum sint exercitation laborum elit officia.]]></description> - <link>http://example.com/test/1540941420</link> - <guid isPermaLink="true">http://example.com/test/1540941420</guid> - <dc:creator><![CDATA[John Smith]]></dc:creator> - <pubDate>Tue, 30 Oct 2018 23:17:00 GMT</pubDate> - </entry> - <entry> - <title><![CDATA[Lorem ipsum 2018-10-30T23:16:00+00:00]]></title> - <description><![CDATA[Irure id sint ullamco Lorem magna consectetur officia adipisicing duis incididunt.]]></description> - <link>http://example.com/test/1540941360</link> - <guid isPermaLink="true">http://example.com/test/1540941360</guid> - <dc:creator><![CDATA[John Smith]]></dc:creator> - <pubDate>Tue, 30 Oct 2018 23:16:00 GMT</pubDate> - </entry> - <entry> - <title><![CDATA[Lorem ipsum 2018-10-30T23:15:00+00:00]]></title> - <description><![CDATA[Sunt anim excepteur esse nisi commodo culpa laborum exercitation ad anim ex elit.]]></description> - <link>http://example.com/test/1540941300</link> - <guid isPermaLink="true">http://example.com/test/1540941300</guid> - <dc:creator><![CDATA[John Smith]]></dc:creator> - <pubDate>Tue, 30 Oct 2018 23:15:00 GMT</pubDate> - </entry> - <entry> - <title><![CDATA[Lorem ipsum 2018-10-30T23:14:00+00:00]]></title> - <description><![CDATA[Excepteur aliquip fugiat ex labore nisi.]]></description> - <link>http://example.com/test/1540941240</link> - <guid isPermaLink="true">http://example.com/test/1540941240</guid> - <dc:creator><![CDATA[John Smith]]></dc:creator> - <pubDate>Tue, 30 Oct 2018 23:14:00 GMT</pubDate> - </entry> - <entry> - <title><![CDATA[Lorem ipsum 2018-10-30T23:13:00+00:00]]></title> - <description><![CDATA[Id proident adipisicing proident pariatur aute pariatur pariatur dolor dolor in voluptate dolor.]]></description> - <link>http://example.com/test/1540941180</link> - <guid isPermaLink="true">http://example.com/test/1540941180</guid> - <dc:creator><![CDATA[John Smith]]></dc:creator> - <pubDate>Tue, 30 Oct 2018 23:13:00 GMT</pubDate> - </entry> -</feed>
\ No newline at end of file diff --git a/vendor/github.com/gorilla/feeds/test.rss b/vendor/github.com/gorilla/feeds/test.rss deleted file mode 100644 index 8d912aba5..000000000 --- a/vendor/github.com/gorilla/feeds/test.rss +++ /dev/null @@ -1,96 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<rss xmlns:dc="http://purl.org/dc/elements/1.1/" - xmlns:content="http://purl.org/rss/1.0/modules/content/" - xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"> - <channel> - <title><![CDATA[Lorem ipsum feed for an interval of 1 minutes]]></title> - <description><![CDATA[This is a constantly updating lorem ipsum feed]]></description> - <link>http://example.com/</link> - <generator>RSS for Node</generator> - <lastBuildDate>Tue, 30 Oct 2018 23:22:37 GMT</lastBuildDate> - <author><![CDATA[John Smith]]></author> - <pubDate>Tue, 30 Oct 2018 23:22:00 GMT</pubDate> - <copyright><![CDATA[Michael Bertolacci, licensed under a Creative Commons Attribution 3.0 Unported License.]]></copyright> - <ttl>60</ttl> - <item> - <title><![CDATA[Lorem ipsum 2018-10-30T23:22:00+00:00]]></title> - <description><![CDATA[Exercitation ut Lorem sint proident.]]></description> - <link>http://example.com/test/1540941720</link> - <guid isPermaLink="true">http://example.com/test/1540941720</guid> - <dc:creator><![CDATA[John Smith]]></dc:creator> - <pubDate>Tue, 30 Oct 2018 23:22:00 GMT</pubDate> - </item> - <item> - <title><![CDATA[Lorem ipsum 2018-10-30T23:21:00+00:00]]></title> - <description><![CDATA[Ea est do quis fugiat exercitation.]]></description> - <link>http://example.com/test/1540941660</link> - <guid isPermaLink="true">http://example.com/test/1540941660</guid> - <dc:creator><![CDATA[John Smith]]></dc:creator> - <pubDate>Tue, 30 Oct 2018 23:21:00 GMT</pubDate> - </item> - <item> - <title><![CDATA[Lorem ipsum 2018-10-30T23:20:00+00:00]]></title> - <description><![CDATA[Ipsum velit cillum ad laborum sit nulla exercitation consequat sint veniam culpa veniam voluptate incididunt.]]></description> - <link>http://example.com/test/1540941600</link> - <guid isPermaLink="true">http://example.com/test/1540941600</guid> - <dc:creator><![CDATA[John Smith]]></dc:creator> - <pubDate>Tue, 30 Oct 2018 23:20:00 GMT</pubDate> - </item> - <item> - <title><![CDATA[Lorem ipsum 2018-10-30T23:19:00+00:00]]></title> - <description><![CDATA[Ullamco pariatur aliqua consequat ea veniam id qui incididunt laborum.]]></description> - <link>http://example.com/test/1540941540</link> - <guid isPermaLink="true">http://example.com/test/1540941540</guid> - <dc:creator><![CDATA[John Smith]]></dc:creator> - <pubDate>Tue, 30 Oct 2018 23:19:00 GMT</pubDate> - </item> - <item> - <title><![CDATA[Lorem ipsum 2018-10-30T23:18:00+00:00]]></title> - <description><![CDATA[Velit proident aliquip aliquip anim mollit voluptate laboris voluptate et occaecat occaecat laboris ea nulla.]]></description> - <link>http://example.com/test/1540941480</link> - <guid isPermaLink="true">http://example.com/test/1540941480</guid> - <dc:creator><![CDATA[John Smith]]></dc:creator> - <pubDate>Tue, 30 Oct 2018 23:18:00 GMT</pubDate> - </item> - <item> - <title><![CDATA[Lorem ipsum 2018-10-30T23:17:00+00:00]]></title> - <description><![CDATA[Do in quis mollit consequat id in minim laborum sint exercitation laborum elit officia.]]></description> - <link>http://example.com/test/1540941420</link> - <guid isPermaLink="true">http://example.com/test/1540941420</guid> - <dc:creator><![CDATA[John Smith]]></dc:creator> - <pubDate>Tue, 30 Oct 2018 23:17:00 GMT</pubDate> - </item> - <item> - <title><![CDATA[Lorem ipsum 2018-10-30T23:16:00+00:00]]></title> - <description><![CDATA[Irure id sint ullamco Lorem magna consectetur officia adipisicing duis incididunt.]]></description> - <link>http://example.com/test/1540941360</link> - <guid isPermaLink="true">http://example.com/test/1540941360</guid> - <dc:creator><![CDATA[John Smith]]></dc:creator> - <pubDate>Tue, 30 Oct 2018 23:16:00 GMT</pubDate> - </item> - <item> - <title><![CDATA[Lorem ipsum 2018-10-30T23:15:00+00:00]]></title> - <description><![CDATA[Sunt anim excepteur esse nisi commodo culpa laborum exercitation ad anim ex elit.]]></description> - <link>http://example.com/test/1540941300</link> - <guid isPermaLink="true">http://example.com/test/1540941300</guid> - <dc:creator><![CDATA[John Smith]]></dc:creator> - <pubDate>Tue, 30 Oct 2018 23:15:00 GMT</pubDate> - </item> - <item> - <title><![CDATA[Lorem ipsum 2018-10-30T23:14:00+00:00]]></title> - <description><![CDATA[Excepteur aliquip fugiat ex labore nisi.]]></description> - <link>http://example.com/test/1540941240</link> - <guid isPermaLink="true">http://example.com/test/1540941240</guid> - <dc:creator><![CDATA[John Smith]]></dc:creator> - <pubDate>Tue, 30 Oct 2018 23:14:00 GMT</pubDate> - </item> - <item> - <title><![CDATA[Lorem ipsum 2018-10-30T23:13:00+00:00]]></title> - <description><![CDATA[Id proident adipisicing proident pariatur aute pariatur pariatur dolor dolor in voluptate dolor.]]></description> - <link>http://example.com/test/1540941180</link> - <guid isPermaLink="true">http://example.com/test/1540941180</guid> - <dc:creator><![CDATA[John Smith]]></dc:creator> - <pubDate>Tue, 30 Oct 2018 23:13:00 GMT</pubDate> - </item> - </channel> -</rss>
\ No newline at end of file diff --git a/vendor/github.com/gorilla/feeds/to-implement.md b/vendor/github.com/gorilla/feeds/to-implement.md deleted file mode 100644 index 45fd1e75e..000000000 --- a/vendor/github.com/gorilla/feeds/to-implement.md +++ /dev/null @@ -1,20 +0,0 @@ -[Full iTunes list](https://help.apple.com/itc/podcasts_connect/#/itcb54353390) - -[Example of ideal iTunes RSS feed](https://help.apple.com/itc/podcasts_connect/#/itcbaf351599) - -``` -<itunes:author> -<itunes:block> -<itunes:catergory> -<itunes:image> -<itunes:duration> -<itunes:explicit> -<itunes:isClosedCaptioned> -<itunes:order> -<itunes:complete> -<itunes:new-feed-url> -<itunes:owner> -<itunes:subtitle> -<itunes:summary> -<language> -```
\ No newline at end of file diff --git a/vendor/github.com/gorilla/feeds/uuid.go b/vendor/github.com/gorilla/feeds/uuid.go deleted file mode 100644 index 51bbafe13..000000000 --- a/vendor/github.com/gorilla/feeds/uuid.go +++ /dev/null @@ -1,27 +0,0 @@ -package feeds - -// relevant bits from https://github.com/abneptis/GoUUID/blob/master/uuid.go - -import ( - "crypto/rand" - "fmt" -) - -type UUID [16]byte - -// create a new uuid v4 -func NewUUID() *UUID { - u := &UUID{} - _, err := rand.Read(u[:16]) - if err != nil { - panic(err) - } - - u[8] = (u[8] | 0x80) & 0xBf - u[6] = (u[6] | 0x40) & 0x4f - return u -} - -func (u *UUID) String() string { - return fmt.Sprintf("%x-%x-%x-%x-%x", u[:4], u[4:6], u[6:8], u[8:10], u[10:]) -} diff --git a/vendor/github.com/gorilla/handlers/.editorconfig b/vendor/github.com/gorilla/handlers/.editorconfig deleted file mode 100644 index c6b74c3e0..000000000 --- a/vendor/github.com/gorilla/handlers/.editorconfig +++ /dev/null @@ -1,20 +0,0 @@ -; https://editorconfig.org/ - -root = true - -[*] -insert_final_newline = true -charset = utf-8 -trim_trailing_whitespace = true -indent_style = space -indent_size = 2 - -[{Makefile,go.mod,go.sum,*.go,.gitmodules}] -indent_style = tab -indent_size = 4 - -[*.md] -indent_size = 4 -trim_trailing_whitespace = false - -eclint_indent_style = unset
\ No newline at end of file diff --git a/vendor/github.com/gorilla/handlers/.gitignore b/vendor/github.com/gorilla/handlers/.gitignore deleted file mode 100644 index 577a89e81..000000000 --- a/vendor/github.com/gorilla/handlers/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -# Output of the go test coverage tool -coverage.coverprofile diff --git a/vendor/github.com/gorilla/handlers/LICENSE b/vendor/github.com/gorilla/handlers/LICENSE deleted file mode 100644 index bb9d80bc9..000000000 --- a/vendor/github.com/gorilla/handlers/LICENSE +++ /dev/null @@ -1,27 +0,0 @@ -Copyright (c) 2023 The Gorilla Authors. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/gorilla/handlers/Makefile b/vendor/github.com/gorilla/handlers/Makefile deleted file mode 100644 index 003b784f7..000000000 --- a/vendor/github.com/gorilla/handlers/Makefile +++ /dev/null @@ -1,34 +0,0 @@ -GO_LINT=$(shell which golangci-lint 2> /dev/null || echo '') -GO_LINT_URI=github.com/golangci/golangci-lint/cmd/golangci-lint@latest - -GO_SEC=$(shell which gosec 2> /dev/null || echo '') -GO_SEC_URI=github.com/securego/gosec/v2/cmd/gosec@latest - -GO_VULNCHECK=$(shell which govulncheck 2> /dev/null || echo '') -GO_VULNCHECK_URI=golang.org/x/vuln/cmd/govulncheck@latest - -.PHONY: verify -verify: sec govulncheck lint test - -.PHONY: lint -lint: - $(if $(GO_LINT), ,go install $(GO_LINT_URI)) - @echo "##### Running golangci-lint #####" - golangci-lint run -v - -.PHONY: sec -sec: - $(if $(GO_SEC), ,go install $(GO_SEC_URI)) - @echo "##### Running gosec #####" - gosec ./... - -.PHONY: govulncheck -govulncheck: - $(if $(GO_VULNCHECK), ,go install $(GO_VULNCHECK_URI)) - @echo "##### Running govulncheck #####" - govulncheck ./... - -.PHONY: test -test: - @echo "##### Running tests #####" - go test -race -cover -coverprofile=coverage.coverprofile -covermode=atomic -v ./... diff --git a/vendor/github.com/gorilla/handlers/README.md b/vendor/github.com/gorilla/handlers/README.md deleted file mode 100644 index 02555b264..000000000 --- a/vendor/github.com/gorilla/handlers/README.md +++ /dev/null @@ -1,56 +0,0 @@ -# gorilla/handlers - - -[](https://codecov.io/github/gorilla/handlers) -[](https://godoc.org/github.com/gorilla/handlers) -[](https://sourcegraph.com/github.com/gorilla/handlers?badge) - -Package handlers is a collection of handlers (aka "HTTP middleware") for use -with Go's `net/http` package (or any framework supporting `http.Handler`), including: - -* [**LoggingHandler**](https://godoc.org/github.com/gorilla/handlers#LoggingHandler) for logging HTTP requests in the Apache [Common Log - Format](http://httpd.apache.org/docs/2.2/logs.html#common). -* [**CombinedLoggingHandler**](https://godoc.org/github.com/gorilla/handlers#CombinedLoggingHandler) for logging HTTP requests in the Apache [Combined Log - Format](http://httpd.apache.org/docs/2.2/logs.html#combined) commonly used by - both Apache and nginx. -* [**CompressHandler**](https://godoc.org/github.com/gorilla/handlers#CompressHandler) for gzipping responses. -* [**ContentTypeHandler**](https://godoc.org/github.com/gorilla/handlers#ContentTypeHandler) for validating requests against a list of accepted - content types. -* [**MethodHandler**](https://godoc.org/github.com/gorilla/handlers#MethodHandler) for matching HTTP methods against handlers in a - `map[string]http.Handler` -* [**ProxyHeaders**](https://godoc.org/github.com/gorilla/handlers#ProxyHeaders) for populating `r.RemoteAddr` and `r.URL.Scheme` based on the - `X-Forwarded-For`, `X-Real-IP`, `X-Forwarded-Proto` and RFC7239 `Forwarded` - headers when running a Go server behind a HTTP reverse proxy. -* [**CanonicalHost**](https://godoc.org/github.com/gorilla/handlers#CanonicalHost) for re-directing to the preferred host when handling multiple - domains (i.e. multiple CNAME aliases). -* [**RecoveryHandler**](https://godoc.org/github.com/gorilla/handlers#RecoveryHandler) for recovering from unexpected panics. - -Other handlers are documented [on the Gorilla -website](https://www.gorillatoolkit.org/pkg/handlers). - -## Example - -A simple example using `handlers.LoggingHandler` and `handlers.CompressHandler`: - -```go -import ( - "net/http" - "github.com/gorilla/handlers" -) - -func main() { - r := http.NewServeMux() - - // Only log requests to our admin dashboard to stdout - r.Handle("/admin", handlers.LoggingHandler(os.Stdout, http.HandlerFunc(ShowAdminDashboard))) - r.HandleFunc("/", ShowIndex) - - // Wrap our server with our gzip handler to gzip compress all responses. - http.ListenAndServe(":8000", handlers.CompressHandler(r)) -} -``` - -## License - -BSD licensed. See the included LICENSE file for details. - diff --git a/vendor/github.com/gorilla/handlers/canonical.go b/vendor/github.com/gorilla/handlers/canonical.go deleted file mode 100644 index 7121f5307..000000000 --- a/vendor/github.com/gorilla/handlers/canonical.go +++ /dev/null @@ -1,73 +0,0 @@ -package handlers - -import ( - "net/http" - "net/url" - "strings" -) - -type canonical struct { - h http.Handler - domain string - code int -} - -// CanonicalHost is HTTP middleware that re-directs requests to the canonical -// domain. It accepts a domain and a status code (e.g. 301 or 302) and -// re-directs clients to this domain. The existing request path is maintained. -// -// Note: If the provided domain is considered invalid by url.Parse or otherwise -// returns an empty scheme or host, clients are not re-directed. -// -// Example: -// -// r := mux.NewRouter() -// canonical := handlers.CanonicalHost("http://www.gorillatoolkit.org", 302) -// r.HandleFunc("/route", YourHandler) -// -// log.Fatal(http.ListenAndServe(":7000", canonical(r))) -func CanonicalHost(domain string, code int) func(h http.Handler) http.Handler { - fn := func(h http.Handler) http.Handler { - return canonical{h, domain, code} - } - - return fn -} - -func (c canonical) ServeHTTP(w http.ResponseWriter, r *http.Request) { - dest, err := url.Parse(c.domain) - if err != nil { - // Call the next handler if the provided domain fails to parse. - c.h.ServeHTTP(w, r) - return - } - - if dest.Scheme == "" || dest.Host == "" { - // Call the next handler if the scheme or host are empty. - // Note that url.Parse won't fail on in this case. - c.h.ServeHTTP(w, r) - return - } - - if !strings.EqualFold(cleanHost(r.Host), dest.Host) { - // Re-build the destination URL - dest := dest.Scheme + "://" + dest.Host + r.URL.Path - if r.URL.RawQuery != "" { - dest += "?" + r.URL.RawQuery - } - http.Redirect(w, r, dest, c.code) - return - } - - c.h.ServeHTTP(w, r) -} - -// cleanHost cleans invalid Host headers by stripping anything after '/' or ' '. -// This is backported from Go 1.5 (in response to issue #11206) and attempts to -// mitigate malformed Host headers that do not match the format in RFC7230. -func cleanHost(in string) string { - if i := strings.IndexAny(in, " /"); i != -1 { - return in[:i] - } - return in -} diff --git a/vendor/github.com/gorilla/handlers/compress.go b/vendor/github.com/gorilla/handlers/compress.go deleted file mode 100644 index d6f589503..000000000 --- a/vendor/github.com/gorilla/handlers/compress.go +++ /dev/null @@ -1,143 +0,0 @@ -// Copyright 2013 The Gorilla Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package handlers - -import ( - "compress/flate" - "compress/gzip" - "io" - "net/http" - "strings" - - "github.com/felixge/httpsnoop" -) - -const acceptEncoding string = "Accept-Encoding" - -type compressResponseWriter struct { - compressor io.Writer - w http.ResponseWriter -} - -func (cw *compressResponseWriter) WriteHeader(c int) { - cw.w.Header().Del("Content-Length") - cw.w.WriteHeader(c) -} - -func (cw *compressResponseWriter) Write(b []byte) (int, error) { - h := cw.w.Header() - if h.Get("Content-Type") == "" { - h.Set("Content-Type", http.DetectContentType(b)) - } - h.Del("Content-Length") - - return cw.compressor.Write(b) -} - -func (cw *compressResponseWriter) ReadFrom(r io.Reader) (int64, error) { - return io.Copy(cw.compressor, r) -} - -type flusher interface { - Flush() error -} - -func (cw *compressResponseWriter) Flush() { - // Flush compressed data if compressor supports it. - if f, ok := cw.compressor.(flusher); ok { - _ = f.Flush() - } - // Flush HTTP response. - if f, ok := cw.w.(http.Flusher); ok { - f.Flush() - } -} - -// CompressHandler gzip compresses HTTP responses for clients that support it -// via the 'Accept-Encoding' header. -// -// Compressing TLS traffic may leak the page contents to an attacker if the -// page contains user input: http://security.stackexchange.com/a/102015/12208 -func CompressHandler(h http.Handler) http.Handler { - return CompressHandlerLevel(h, gzip.DefaultCompression) -} - -// CompressHandlerLevel gzip compresses HTTP responses with specified compression level -// for clients that support it via the 'Accept-Encoding' header. -// -// The compression level should be gzip.DefaultCompression, gzip.NoCompression, -// or any integer value between gzip.BestSpeed and gzip.BestCompression inclusive. -// gzip.DefaultCompression is used in case of invalid compression level. -func CompressHandlerLevel(h http.Handler, level int) http.Handler { - if level < gzip.DefaultCompression || level > gzip.BestCompression { - level = gzip.DefaultCompression - } - - const ( - gzipEncoding = "gzip" - flateEncoding = "deflate" - ) - - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - // detect what encoding to use - var encoding string - for _, curEnc := range strings.Split(r.Header.Get(acceptEncoding), ",") { - curEnc = strings.TrimSpace(curEnc) - if curEnc == gzipEncoding || curEnc == flateEncoding { - encoding = curEnc - break - } - } - - // always add Accept-Encoding to Vary to prevent intermediate caches corruption - w.Header().Add("Vary", acceptEncoding) - - // if we weren't able to identify an encoding we're familiar with, pass on the - // request to the handler and return - if encoding == "" { - h.ServeHTTP(w, r) - return - } - - if r.Header.Get("Upgrade") != "" { - h.ServeHTTP(w, r) - return - } - - // wrap the ResponseWriter with the writer for the chosen encoding - var encWriter io.WriteCloser - if encoding == gzipEncoding { - encWriter, _ = gzip.NewWriterLevel(w, level) - } else if encoding == flateEncoding { - encWriter, _ = flate.NewWriter(w, level) - } - defer encWriter.Close() - - w.Header().Set("Content-Encoding", encoding) - r.Header.Del(acceptEncoding) - - cw := &compressResponseWriter{ - w: w, - compressor: encWriter, - } - - w = httpsnoop.Wrap(w, httpsnoop.Hooks{ - Write: func(httpsnoop.WriteFunc) httpsnoop.WriteFunc { - return cw.Write - }, - WriteHeader: func(httpsnoop.WriteHeaderFunc) httpsnoop.WriteHeaderFunc { - return cw.WriteHeader - }, - Flush: func(httpsnoop.FlushFunc) httpsnoop.FlushFunc { - return cw.Flush - }, - ReadFrom: func(rff httpsnoop.ReadFromFunc) httpsnoop.ReadFromFunc { - return cw.ReadFrom - }, - }) - - h.ServeHTTP(w, r) - }) -} diff --git a/vendor/github.com/gorilla/handlers/cors.go b/vendor/github.com/gorilla/handlers/cors.go deleted file mode 100644 index 8af9c096e..000000000 --- a/vendor/github.com/gorilla/handlers/cors.go +++ /dev/null @@ -1,352 +0,0 @@ -package handlers - -import ( - "net/http" - "strconv" - "strings" -) - -// CORSOption represents a functional option for configuring the CORS middleware. -type CORSOption func(*cors) error - -type cors struct { - h http.Handler - allowedHeaders []string - allowedMethods []string - allowedOrigins []string - allowedOriginValidator OriginValidator - exposedHeaders []string - maxAge int - ignoreOptions bool - allowCredentials bool - optionStatusCode int -} - -// OriginValidator takes an origin string and returns whether or not that origin is allowed. -type OriginValidator func(string) bool - -var ( - defaultCorsOptionStatusCode = http.StatusOK - defaultCorsMethods = []string{http.MethodGet, http.MethodHead, http.MethodPost} - defaultCorsHeaders = []string{"Accept", "Accept-Language", "Content-Language", "Origin"} - // (WebKit/Safari v9 sends the Origin header by default in AJAX requests). -) - -const ( - corsOptionMethod string = http.MethodOptions - corsAllowOriginHeader string = "Access-Control-Allow-Origin" - corsExposeHeadersHeader string = "Access-Control-Expose-Headers" - corsMaxAgeHeader string = "Access-Control-Max-Age" - corsAllowMethodsHeader string = "Access-Control-Allow-Methods" - corsAllowHeadersHeader string = "Access-Control-Allow-Headers" - corsAllowCredentialsHeader string = "Access-Control-Allow-Credentials" - corsRequestMethodHeader string = "Access-Control-Request-Method" - corsRequestHeadersHeader string = "Access-Control-Request-Headers" - corsOriginHeader string = "Origin" - corsVaryHeader string = "Vary" - corsOriginMatchAll string = "*" -) - -func (ch *cors) ServeHTTP(w http.ResponseWriter, r *http.Request) { - origin := r.Header.Get(corsOriginHeader) - if !ch.isOriginAllowed(origin) { - if r.Method != corsOptionMethod || ch.ignoreOptions { - ch.h.ServeHTTP(w, r) - } - - return - } - - if r.Method == corsOptionMethod { - if ch.ignoreOptions { - ch.h.ServeHTTP(w, r) - return - } - - if _, ok := r.Header[corsRequestMethodHeader]; !ok { - w.WriteHeader(http.StatusBadRequest) - return - } - - method := r.Header.Get(corsRequestMethodHeader) - if !ch.isMatch(method, ch.allowedMethods) { - w.WriteHeader(http.StatusMethodNotAllowed) - return - } - - requestHeaders := strings.Split(r.Header.Get(corsRequestHeadersHeader), ",") - allowedHeaders := []string{} - for _, v := range requestHeaders { - canonicalHeader := http.CanonicalHeaderKey(strings.TrimSpace(v)) - if canonicalHeader == "" || ch.isMatch(canonicalHeader, defaultCorsHeaders) { - continue - } - - if !ch.isMatch(canonicalHeader, ch.allowedHeaders) { - w.WriteHeader(http.StatusForbidden) - return - } - - allowedHeaders = append(allowedHeaders, canonicalHeader) - } - - if len(allowedHeaders) > 0 { - w.Header().Set(corsAllowHeadersHeader, strings.Join(allowedHeaders, ",")) - } - - if ch.maxAge > 0 { - w.Header().Set(corsMaxAgeHeader, strconv.Itoa(ch.maxAge)) - } - - if !ch.isMatch(method, defaultCorsMethods) { - w.Header().Set(corsAllowMethodsHeader, method) - } - } else if len(ch.exposedHeaders) > 0 { - w.Header().Set(corsExposeHeadersHeader, strings.Join(ch.exposedHeaders, ",")) - } - - if ch.allowCredentials { - w.Header().Set(corsAllowCredentialsHeader, "true") - } - - if len(ch.allowedOrigins) > 1 { - w.Header().Set(corsVaryHeader, corsOriginHeader) - } - - returnOrigin := origin - if ch.allowedOriginValidator == nil && len(ch.allowedOrigins) == 0 { - returnOrigin = "*" - } else { - for _, o := range ch.allowedOrigins { - // A configuration of * is different than explicitly setting an allowed - // origin. Returning arbitrary origin headers in an access control allow - // origin header is unsafe and is not required by any use case. - if o == corsOriginMatchAll { - returnOrigin = "*" - break - } - } - } - w.Header().Set(corsAllowOriginHeader, returnOrigin) - - if r.Method == corsOptionMethod { - w.WriteHeader(ch.optionStatusCode) - return - } - ch.h.ServeHTTP(w, r) -} - -// CORS provides Cross-Origin Resource Sharing middleware. -// Example: -// -// import ( -// "net/http" -// -// "github.com/gorilla/handlers" -// "github.com/gorilla/mux" -// ) -// -// func main() { -// r := mux.NewRouter() -// r.HandleFunc("/users", UserEndpoint) -// r.HandleFunc("/projects", ProjectEndpoint) -// -// // Apply the CORS middleware to our top-level router, with the defaults. -// http.ListenAndServe(":8000", handlers.CORS()(r)) -// } -func CORS(opts ...CORSOption) func(http.Handler) http.Handler { - return func(h http.Handler) http.Handler { - ch := parseCORSOptions(opts...) - ch.h = h - return ch - } -} - -func parseCORSOptions(opts ...CORSOption) *cors { - ch := &cors{ - allowedMethods: defaultCorsMethods, - allowedHeaders: defaultCorsHeaders, - allowedOrigins: []string{}, - optionStatusCode: defaultCorsOptionStatusCode, - } - - for _, option := range opts { - _ = option(ch) //TODO: @bharat-rajani, return error to caller if not nil? - } - - return ch -} - -// -// Functional options for configuring CORS. -// - -// AllowedHeaders adds the provided headers to the list of allowed headers in a -// CORS request. -// This is an append operation so the headers Accept, Accept-Language, -// and Content-Language are always allowed. -// Content-Type must be explicitly declared if accepting Content-Types other than -// application/x-www-form-urlencoded, multipart/form-data, or text/plain. -func AllowedHeaders(headers []string) CORSOption { - return func(ch *cors) error { - for _, v := range headers { - normalizedHeader := http.CanonicalHeaderKey(strings.TrimSpace(v)) - if normalizedHeader == "" { - continue - } - - if !ch.isMatch(normalizedHeader, ch.allowedHeaders) { - ch.allowedHeaders = append(ch.allowedHeaders, normalizedHeader) - } - } - - return nil - } -} - -// AllowedMethods can be used to explicitly allow methods in the -// Access-Control-Allow-Methods header. -// This is a replacement operation so you must also -// pass GET, HEAD, and POST if you wish to support those methods. -func AllowedMethods(methods []string) CORSOption { - return func(ch *cors) error { - ch.allowedMethods = []string{} - for _, v := range methods { - normalizedMethod := strings.ToUpper(strings.TrimSpace(v)) - if normalizedMethod == "" { - continue - } - - if !ch.isMatch(normalizedMethod, ch.allowedMethods) { - ch.allowedMethods = append(ch.allowedMethods, normalizedMethod) - } - } - - return nil - } -} - -// AllowedOrigins sets the allowed origins for CORS requests, as used in the -// 'Allow-Access-Control-Origin' HTTP header. -// Note: Passing in a []string{"*"} will allow any domain. -func AllowedOrigins(origins []string) CORSOption { - return func(ch *cors) error { - for _, v := range origins { - if v == corsOriginMatchAll { - ch.allowedOrigins = []string{corsOriginMatchAll} - return nil - } - } - - ch.allowedOrigins = origins - return nil - } -} - -// AllowedOriginValidator sets a function for evaluating allowed origins in CORS requests, represented by the -// 'Allow-Access-Control-Origin' HTTP header. -func AllowedOriginValidator(fn OriginValidator) CORSOption { - return func(ch *cors) error { - ch.allowedOriginValidator = fn - return nil - } -} - -// OptionStatusCode sets a custom status code on the OPTIONS requests. -// Default behaviour sets it to 200 to reflect best practices. This is option is not mandatory -// and can be used if you need a custom status code (i.e 204). -// -// More informations on the spec: -// https://fetch.spec.whatwg.org/#cors-preflight-fetch -func OptionStatusCode(code int) CORSOption { - return func(ch *cors) error { - ch.optionStatusCode = code - return nil - } -} - -// ExposedHeaders can be used to specify headers that are available -// and will not be stripped out by the user-agent. -func ExposedHeaders(headers []string) CORSOption { - return func(ch *cors) error { - ch.exposedHeaders = []string{} - for _, v := range headers { - normalizedHeader := http.CanonicalHeaderKey(strings.TrimSpace(v)) - if normalizedHeader == "" { - continue - } - - if !ch.isMatch(normalizedHeader, ch.exposedHeaders) { - ch.exposedHeaders = append(ch.exposedHeaders, normalizedHeader) - } - } - - return nil - } -} - -// MaxAge determines the maximum age (in seconds) between preflight requests. A -// maximum of 10 minutes is allowed. An age above this value will default to 10 -// minutes. -func MaxAge(age int) CORSOption { - return func(ch *cors) error { - // Maximum of 10 minutes. - if age > 600 { - age = 600 - } - - ch.maxAge = age - return nil - } -} - -// IgnoreOptions causes the CORS middleware to ignore OPTIONS requests, instead -// passing them through to the next handler. This is useful when your application -// or framework has a pre-existing mechanism for responding to OPTIONS requests. -func IgnoreOptions() CORSOption { - return func(ch *cors) error { - ch.ignoreOptions = true - return nil - } -} - -// AllowCredentials can be used to specify that the user agent may pass -// authentication details along with the request. -func AllowCredentials() CORSOption { - return func(ch *cors) error { - ch.allowCredentials = true - return nil - } -} - -func (ch *cors) isOriginAllowed(origin string) bool { - if origin == "" { - return false - } - - if ch.allowedOriginValidator != nil { - return ch.allowedOriginValidator(origin) - } - - if len(ch.allowedOrigins) == 0 { - return true - } - - for _, allowedOrigin := range ch.allowedOrigins { - if allowedOrigin == origin || allowedOrigin == corsOriginMatchAll { - return true - } - } - - return false -} - -func (ch *cors) isMatch(needle string, haystack []string) bool { - for _, v := range haystack { - if v == needle { - return true - } - } - - return false -} diff --git a/vendor/github.com/gorilla/handlers/doc.go b/vendor/github.com/gorilla/handlers/doc.go deleted file mode 100644 index 944e5a8ae..000000000 --- a/vendor/github.com/gorilla/handlers/doc.go +++ /dev/null @@ -1,9 +0,0 @@ -/* -Package handlers is a collection of handlers (aka "HTTP middleware") for use -with Go's net/http package (or any framework supporting http.Handler). - -The package includes handlers for logging in standardised formats, compressing -HTTP responses, validating content types and other useful tools for manipulating -requests and responses. -*/ -package handlers diff --git a/vendor/github.com/gorilla/handlers/handlers.go b/vendor/github.com/gorilla/handlers/handlers.go deleted file mode 100644 index 9b92fce33..000000000 --- a/vendor/github.com/gorilla/handlers/handlers.go +++ /dev/null @@ -1,150 +0,0 @@ -// Copyright 2013 The Gorilla Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package handlers - -import ( - "bufio" - "fmt" - "net" - "net/http" - "sort" - "strings" -) - -// MethodHandler is an http.Handler that dispatches to a handler whose key in the -// MethodHandler's map matches the name of the HTTP request's method, eg: GET -// -// If the request's method is OPTIONS and OPTIONS is not a key in the map then -// the handler responds with a status of 200 and sets the Allow header to a -// comma-separated list of available methods. -// -// If the request's method doesn't match any of its keys the handler responds -// with a status of HTTP 405 "Method Not Allowed" and sets the Allow header to a -// comma-separated list of available methods. -type MethodHandler map[string]http.Handler - -func (h MethodHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) { - if handler, ok := h[req.Method]; ok { - handler.ServeHTTP(w, req) - } else { - allow := []string{} - for k := range h { - allow = append(allow, k) - } - sort.Strings(allow) - w.Header().Set("Allow", strings.Join(allow, ", ")) - if req.Method == http.MethodOptions { - w.WriteHeader(http.StatusOK) - } else { - http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) - } - } -} - -// responseLogger is wrapper of http.ResponseWriter that keeps track of its HTTP -// status code and body size. -type responseLogger struct { - w http.ResponseWriter - status int - size int -} - -func (l *responseLogger) Write(b []byte) (int, error) { - size, err := l.w.Write(b) - l.size += size - return size, err -} - -func (l *responseLogger) WriteHeader(s int) { - l.w.WriteHeader(s) - l.status = s -} - -func (l *responseLogger) Status() int { - return l.status -} - -func (l *responseLogger) Size() int { - return l.size -} - -func (l *responseLogger) Hijack() (net.Conn, *bufio.ReadWriter, error) { - conn, rw, err := l.w.(http.Hijacker).Hijack() - if err == nil && l.status == 0 { - // The status will be StatusSwitchingProtocols if there was no error and - // WriteHeader has not been called yet - l.status = http.StatusSwitchingProtocols - } - return conn, rw, err -} - -// isContentType validates the Content-Type header matches the supplied -// contentType. That is, its type and subtype match. -func isContentType(h http.Header, contentType string) bool { - ct := h.Get("Content-Type") - if i := strings.IndexRune(ct, ';'); i != -1 { - ct = ct[0:i] - } - return ct == contentType -} - -// ContentTypeHandler wraps and returns a http.Handler, validating the request -// content type is compatible with the contentTypes list. It writes a HTTP 415 -// error if that fails. -// -// Only PUT, POST, and PATCH requests are considered. -func ContentTypeHandler(h http.Handler, contentTypes ...string) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - if !(r.Method == http.MethodPut || r.Method == http.MethodPost || r.Method == http.MethodPatch) { - h.ServeHTTP(w, r) - return - } - - for _, ct := range contentTypes { - if isContentType(r.Header, ct) { - h.ServeHTTP(w, r) - return - } - } - http.Error(w, fmt.Sprintf("Unsupported content type %q; expected one of %q", - r.Header.Get("Content-Type"), - contentTypes), - http.StatusUnsupportedMediaType) - }) -} - -const ( - // HTTPMethodOverrideHeader is a commonly used - // http header to override a request method. - HTTPMethodOverrideHeader = "X-HTTP-Method-Override" - // HTTPMethodOverrideFormKey is a commonly used - // HTML form key to override a request method. - HTTPMethodOverrideFormKey = "_method" -) - -// HTTPMethodOverrideHandler wraps and returns a http.Handler which checks for -// the X-HTTP-Method-Override header or the _method form key, and overrides (if -// valid) request.Method with its value. -// -// This is especially useful for HTTP clients that don't support many http verbs. -// It isn't secure to override e.g a GET to a POST, so only POST requests are -// considered. Likewise, the override method can only be a "write" method: PUT, -// PATCH or DELETE. -// -// Form method takes precedence over header method. -func HTTPMethodOverrideHandler(h http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - if r.Method == http.MethodPost { - om := r.FormValue(HTTPMethodOverrideFormKey) - if om == "" { - om = r.Header.Get(HTTPMethodOverrideHeader) - } - if om == http.MethodPut || om == http.MethodPatch || om == http.MethodDelete { - r.Method = om - } - } - h.ServeHTTP(w, r) - }) -} diff --git a/vendor/github.com/gorilla/handlers/logging.go b/vendor/github.com/gorilla/handlers/logging.go deleted file mode 100644 index 2badb6fbf..000000000 --- a/vendor/github.com/gorilla/handlers/logging.go +++ /dev/null @@ -1,246 +0,0 @@ -// Copyright 2013 The Gorilla Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package handlers - -import ( - "io" - "net" - "net/http" - "net/url" - "strconv" - "time" - "unicode/utf8" - - "github.com/felixge/httpsnoop" -) - -// Logging - -// LogFormatterParams is the structure any formatter will be handed when time to log comes. -type LogFormatterParams struct { - Request *http.Request - URL url.URL - TimeStamp time.Time - StatusCode int - Size int -} - -// LogFormatter gives the signature of the formatter function passed to CustomLoggingHandler. -type LogFormatter func(writer io.Writer, params LogFormatterParams) - -// loggingHandler is the http.Handler implementation for LoggingHandlerTo and its -// friends - -type loggingHandler struct { - writer io.Writer - handler http.Handler - formatter LogFormatter -} - -func (h loggingHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) { - t := time.Now() - logger, w := makeLogger(w) - url := *req.URL - - h.handler.ServeHTTP(w, req) - if req.MultipartForm != nil { - err := req.MultipartForm.RemoveAll() - if err != nil { - return - } - } - - params := LogFormatterParams{ - Request: req, - URL: url, - TimeStamp: t, - StatusCode: logger.Status(), - Size: logger.Size(), - } - - h.formatter(h.writer, params) -} - -func makeLogger(w http.ResponseWriter) (*responseLogger, http.ResponseWriter) { - logger := &responseLogger{w: w, status: http.StatusOK} - return logger, httpsnoop.Wrap(w, httpsnoop.Hooks{ - Write: func(httpsnoop.WriteFunc) httpsnoop.WriteFunc { - return logger.Write - }, - WriteHeader: func(httpsnoop.WriteHeaderFunc) httpsnoop.WriteHeaderFunc { - return logger.WriteHeader - }, - }) -} - -const lowerhex = "0123456789abcdef" - -func appendQuoted(buf []byte, s string) []byte { - var runeTmp [utf8.UTFMax]byte - for width := 0; len(s) > 0; s = s[width:] { //nolint: wastedassign //TODO: why width starts from 0and reassigned as 1 - r := rune(s[0]) - width = 1 - if r >= utf8.RuneSelf { - r, width = utf8.DecodeRuneInString(s) - } - if width == 1 && r == utf8.RuneError { - buf = append(buf, `\x`...) - buf = append(buf, lowerhex[s[0]>>4]) - buf = append(buf, lowerhex[s[0]&0xF]) - continue - } - if r == rune('"') || r == '\\' { // always backslashed - buf = append(buf, '\\') - buf = append(buf, byte(r)) - continue - } - if strconv.IsPrint(r) { - n := utf8.EncodeRune(runeTmp[:], r) - buf = append(buf, runeTmp[:n]...) - continue - } - switch r { - case '\a': - buf = append(buf, `\a`...) - case '\b': - buf = append(buf, `\b`...) - case '\f': - buf = append(buf, `\f`...) - case '\n': - buf = append(buf, `\n`...) - case '\r': - buf = append(buf, `\r`...) - case '\t': - buf = append(buf, `\t`...) - case '\v': - buf = append(buf, `\v`...) - default: - switch { - case r < ' ': - buf = append(buf, `\x`...) - buf = append(buf, lowerhex[s[0]>>4]) - buf = append(buf, lowerhex[s[0]&0xF]) - case r > utf8.MaxRune: - r = 0xFFFD - fallthrough - case r < 0x10000: - buf = append(buf, `\u`...) - for s := 12; s >= 0; s -= 4 { - buf = append(buf, lowerhex[r>>uint(s)&0xF]) - } - default: - buf = append(buf, `\U`...) - for s := 28; s >= 0; s -= 4 { - buf = append(buf, lowerhex[r>>uint(s)&0xF]) - } - } - } - } - return buf -} - -// buildCommonLogLine builds a log entry for req in Apache Common Log Format. -// ts is the timestamp with which the entry should be logged. -// status and size are used to provide the response HTTP status and size. -func buildCommonLogLine(req *http.Request, url url.URL, ts time.Time, status int, size int) []byte { - username := "-" - if url.User != nil { - if name := url.User.Username(); name != "" { - username = name - } - } - - host, _, err := net.SplitHostPort(req.RemoteAddr) - if err != nil { - host = req.RemoteAddr - } - - uri := req.RequestURI - - // Requests using the CONNECT method over HTTP/2.0 must use - // the authority field (aka r.Host) to identify the target. - // Refer: https://httpwg.github.io/specs/rfc7540.html#CONNECT - if req.ProtoMajor == 2 && req.Method == "CONNECT" { - uri = req.Host - } - if uri == "" { - uri = url.RequestURI() - } - - buf := make([]byte, 0, 3*(len(host)+len(username)+len(req.Method)+len(uri)+len(req.Proto)+50)/2) - buf = append(buf, host...) - buf = append(buf, " - "...) - buf = append(buf, username...) - buf = append(buf, " ["...) - buf = append(buf, ts.Format("02/Jan/2006:15:04:05 -0700")...) - buf = append(buf, `] "`...) - buf = append(buf, req.Method...) - buf = append(buf, " "...) - buf = appendQuoted(buf, uri) - buf = append(buf, " "...) - buf = append(buf, req.Proto...) - buf = append(buf, `" `...) - buf = append(buf, strconv.Itoa(status)...) - buf = append(buf, " "...) - buf = append(buf, strconv.Itoa(size)...) - return buf -} - -// writeLog writes a log entry for req to w in Apache Common Log Format. -// ts is the timestamp with which the entry should be logged. -// status and size are used to provide the response HTTP status and size. -func writeLog(writer io.Writer, params LogFormatterParams) { - buf := buildCommonLogLine(params.Request, params.URL, params.TimeStamp, params.StatusCode, params.Size) - buf = append(buf, '\n') - _, _ = writer.Write(buf) -} - -// writeCombinedLog writes a log entry for req to w in Apache Combined Log Format. -// ts is the timestamp with which the entry should be logged. -// status and size are used to provide the response HTTP status and size. -func writeCombinedLog(writer io.Writer, params LogFormatterParams) { - buf := buildCommonLogLine(params.Request, params.URL, params.TimeStamp, params.StatusCode, params.Size) - buf = append(buf, ` "`...) - buf = appendQuoted(buf, params.Request.Referer()) - buf = append(buf, `" "`...) - buf = appendQuoted(buf, params.Request.UserAgent()) - buf = append(buf, '"', '\n') - _, _ = writer.Write(buf) -} - -// CombinedLoggingHandler return a http.Handler that wraps h and logs requests to out in -// Apache Combined Log Format. -// -// See http://httpd.apache.org/docs/2.2/logs.html#combined for a description of this format. -// -// LoggingHandler always sets the ident field of the log to -. -func CombinedLoggingHandler(out io.Writer, h http.Handler) http.Handler { - return loggingHandler{out, h, writeCombinedLog} -} - -// LoggingHandler return a http.Handler that wraps h and logs requests to out in -// Apache Common Log Format (CLF). -// -// See http://httpd.apache.org/docs/2.2/logs.html#common for a description of this format. -// -// LoggingHandler always sets the ident field of the log to - -// -// Example: -// -// r := mux.NewRouter() -// r.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { -// w.Write([]byte("This is a catch-all route")) -// }) -// loggedRouter := handlers.LoggingHandler(os.Stdout, r) -// http.ListenAndServe(":1123", loggedRouter) -func LoggingHandler(out io.Writer, h http.Handler) http.Handler { - return loggingHandler{out, h, writeLog} -} - -// CustomLoggingHandler provides a way to supply a custom log formatter -// while taking advantage of the mechanisms in this package. -func CustomLoggingHandler(out io.Writer, h http.Handler, f LogFormatter) http.Handler { - return loggingHandler{out, h, f} -} diff --git a/vendor/github.com/gorilla/handlers/proxy_headers.go b/vendor/github.com/gorilla/handlers/proxy_headers.go deleted file mode 100644 index 281d753e9..000000000 --- a/vendor/github.com/gorilla/handlers/proxy_headers.go +++ /dev/null @@ -1,120 +0,0 @@ -package handlers - -import ( - "net/http" - "regexp" - "strings" -) - -var ( - // De-facto standard header keys. - xForwardedFor = http.CanonicalHeaderKey("X-Forwarded-For") - xForwardedHost = http.CanonicalHeaderKey("X-Forwarded-Host") - xForwardedProto = http.CanonicalHeaderKey("X-Forwarded-Proto") - xForwardedScheme = http.CanonicalHeaderKey("X-Forwarded-Scheme") - xRealIP = http.CanonicalHeaderKey("X-Real-IP") -) - -var ( - // RFC7239 defines a new "Forwarded: " header designed to replace the - // existing use of X-Forwarded-* headers. - // e.g. Forwarded: for=192.0.2.60;proto=https;by=203.0.113.43. - forwarded = http.CanonicalHeaderKey("Forwarded") - // Allows for a sub-match of the first value after 'for=' to the next - // comma, semi-colon or space. The match is case-insensitive. - forRegex = regexp.MustCompile(`(?i)(?:for=)([^(;|,| )]+)`) - // Allows for a sub-match for the first instance of scheme (http|https) - // prefixed by 'proto='. The match is case-insensitive. - protoRegex = regexp.MustCompile(`(?i)(?:proto=)(https|http)`) -) - -// ProxyHeaders inspects common reverse proxy headers and sets the corresponding -// fields in the HTTP request struct. These are X-Forwarded-For and X-Real-IP -// for the remote (client) IP address, X-Forwarded-Proto or X-Forwarded-Scheme -// for the scheme (http|https), X-Forwarded-Host for the host and the RFC7239 -// Forwarded header, which may include both client IPs and schemes. -// -// NOTE: This middleware should only be used when behind a reverse -// proxy like nginx, HAProxy or Apache. Reverse proxies that don't (or are -// configured not to) strip these headers from client requests, or where these -// headers are accepted "as is" from a remote client (e.g. when Go is not behind -// a proxy), can manifest as a vulnerability if your application uses these -// headers for validating the 'trustworthiness' of a request. -func ProxyHeaders(h http.Handler) http.Handler { - fn := func(w http.ResponseWriter, r *http.Request) { - // Set the remote IP with the value passed from the proxy. - if fwd := getIP(r); fwd != "" { - r.RemoteAddr = fwd - } - - // Set the scheme (proto) with the value passed from the proxy. - if scheme := getScheme(r); scheme != "" { - r.URL.Scheme = scheme - } - // Set the host with the value passed by the proxy - if r.Header.Get(xForwardedHost) != "" { - r.Host = r.Header.Get(xForwardedHost) - } - // Call the next handler in the chain. - h.ServeHTTP(w, r) - } - - return http.HandlerFunc(fn) -} - -// getIP retrieves the IP from the X-Forwarded-For, X-Real-IP and RFC7239 -// Forwarded headers (in that order). -func getIP(r *http.Request) string { - var addr string - - switch { - case r.Header.Get(xForwardedFor) != "": - fwd := r.Header.Get(xForwardedFor) - // Only grab the first (client) address. Note that '192.168.0.1, - // 10.1.1.1' is a valid key for X-Forwarded-For where addresses after - // the first may represent forwarding proxies earlier in the chain. - s := strings.Index(fwd, ", ") - if s == -1 { - s = len(fwd) - } - addr = fwd[:s] - case r.Header.Get(xRealIP) != "": - addr = r.Header.Get(xRealIP) - case r.Header.Get(forwarded) != "": - // match should contain at least two elements if the protocol was - // specified in the Forwarded header. The first element will always be - // the 'for=' capture, which we ignore. In the case of multiple IP - // addresses (for=8.8.8.8, 8.8.4.4,172.16.1.20 is valid) we only - // extract the first, which should be the client IP. - if match := forRegex.FindStringSubmatch(r.Header.Get(forwarded)); len(match) > 1 { - // IPv6 addresses in Forwarded headers are quoted-strings. We strip - // these quotes. - addr = strings.Trim(match[1], `"`) - } - } - - return addr -} - -// getScheme retrieves the scheme from the X-Forwarded-Proto and RFC7239 -// Forwarded headers (in that order). -func getScheme(r *http.Request) string { - var scheme string - - // Retrieve the scheme from X-Forwarded-Proto. - if proto := r.Header.Get(xForwardedProto); proto != "" { - scheme = strings.ToLower(proto) - } else if proto = r.Header.Get(xForwardedScheme); proto != "" { - scheme = strings.ToLower(proto) - } else if proto = r.Header.Get(forwarded); proto != "" { - // match should contain at least two elements if the protocol was - // specified in the Forwarded header. The first element will always be - // the 'proto=' capture, which we ignore. In the case of multiple proto - // parameters (invalid) we only extract the first. - if match := protoRegex.FindStringSubmatch(proto); len(match) > 1 { - scheme = strings.ToLower(match[1]) - } - } - - return scheme -} diff --git a/vendor/github.com/gorilla/handlers/recovery.go b/vendor/github.com/gorilla/handlers/recovery.go deleted file mode 100644 index 0d4f955ec..000000000 --- a/vendor/github.com/gorilla/handlers/recovery.go +++ /dev/null @@ -1,98 +0,0 @@ -package handlers - -import ( - "log" - "net/http" - "runtime/debug" -) - -// RecoveryHandlerLogger is an interface used by the recovering handler to print logs. -type RecoveryHandlerLogger interface { - Println(...interface{}) -} - -type recoveryHandler struct { - handler http.Handler - logger RecoveryHandlerLogger - printStack bool -} - -// RecoveryOption provides a functional approach to define -// configuration for a handler; such as setting the logging -// whether or not to print stack traces on panic. -type RecoveryOption func(http.Handler) - -func parseRecoveryOptions(h http.Handler, opts ...RecoveryOption) http.Handler { - for _, option := range opts { - option(h) - } - - return h -} - -// RecoveryHandler is HTTP middleware that recovers from a panic, -// logs the panic, writes http.StatusInternalServerError, and -// continues to the next handler. -// -// Example: -// -// r := mux.NewRouter() -// r.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { -// panic("Unexpected error!") -// }) -// -// http.ListenAndServe(":1123", handlers.RecoveryHandler()(r)) -func RecoveryHandler(opts ...RecoveryOption) func(h http.Handler) http.Handler { - return func(h http.Handler) http.Handler { - r := &recoveryHandler{handler: h} - return parseRecoveryOptions(r, opts...) - } -} - -// RecoveryLogger is a functional option to override -// the default logger. -func RecoveryLogger(logger RecoveryHandlerLogger) RecoveryOption { - return func(h http.Handler) { - r := h.(*recoveryHandler) //nolint:errcheck //TODO: - // @bharat-rajani should return type-assertion error but would break the API? - r.logger = logger - } -} - -// PrintRecoveryStack is a functional option to enable -// or disable printing stack traces on panic. -func PrintRecoveryStack(shouldPrint bool) RecoveryOption { - return func(h http.Handler) { - r := h.(*recoveryHandler) //nolint:errcheck //TODO: - // @bharat-rajani should return type-assertion error but would break the API? - r.printStack = shouldPrint - } -} - -func (h recoveryHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) { - defer func() { - if err := recover(); err != nil { - w.WriteHeader(http.StatusInternalServerError) - h.log(err) - } - }() - - h.handler.ServeHTTP(w, req) -} - -func (h recoveryHandler) log(v ...interface{}) { - if h.logger != nil { - h.logger.Println(v...) - } else { - log.Println(v...) - } - - if h.printStack { - stack := string(debug.Stack()) - if h.logger != nil { - h.logger.Println(stack) - } else { - log.Println(stack) - } - } -} diff --git a/vendor/github.com/gorilla/securecookie/.editorconfig b/vendor/github.com/gorilla/securecookie/.editorconfig deleted file mode 100644 index 2940ec92a..000000000 --- a/vendor/github.com/gorilla/securecookie/.editorconfig +++ /dev/null @@ -1,20 +0,0 @@ -; https://editorconfig.org/ - -root = true - -[*] -insert_final_newline = true -charset = utf-8 -trim_trailing_whitespace = true -indent_style = space -indent_size = 2 - -[{Makefile,go.mod,go.sum,*.go,.gitmodules}] -indent_style = tab -indent_size = 4 - -[*.md] -indent_size = 4 -trim_trailing_whitespace = false - -eclint_indent_style = unset diff --git a/vendor/github.com/gorilla/securecookie/.gitignore b/vendor/github.com/gorilla/securecookie/.gitignore deleted file mode 100644 index 84039fec6..000000000 --- a/vendor/github.com/gorilla/securecookie/.gitignore +++ /dev/null @@ -1 +0,0 @@ -coverage.coverprofile diff --git a/vendor/github.com/gorilla/securecookie/LICENSE b/vendor/github.com/gorilla/securecookie/LICENSE deleted file mode 100644 index bb9d80bc9..000000000 --- a/vendor/github.com/gorilla/securecookie/LICENSE +++ /dev/null @@ -1,27 +0,0 @@ -Copyright (c) 2023 The Gorilla Authors. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/gorilla/securecookie/Makefile b/vendor/github.com/gorilla/securecookie/Makefile deleted file mode 100644 index 2b9008a26..000000000 --- a/vendor/github.com/gorilla/securecookie/Makefile +++ /dev/null @@ -1,39 +0,0 @@ -GO_LINT=$(shell which golangci-lint 2> /dev/null || echo '') -GO_LINT_URI=github.com/golangci/golangci-lint/cmd/golangci-lint@latest - -GO_SEC=$(shell which gosec 2> /dev/null || echo '') -GO_SEC_URI=github.com/securego/gosec/v2/cmd/gosec@latest - -GO_VULNCHECK=$(shell which govulncheck 2> /dev/null || echo '') -GO_VULNCHECK_URI=golang.org/x/vuln/cmd/govulncheck@latest - -.PHONY: golangci-lint -golangci-lint: - $(if $(GO_LINT), ,go install $(GO_LINT_URI)) - @echo "##### Running golangci-lint" - golangci-lint run -v - -.PHONY: gosec -gosec: - $(if $(GO_SEC), ,go install $(GO_SEC_URI)) - @echo "##### Running gosec" - gosec ./... - -.PHONY: govulncheck -govulncheck: - $(if $(GO_VULNCHECK), ,go install $(GO_VULNCHECK_URI)) - @echo "##### Running govulncheck" - govulncheck ./... - -.PHONY: verify -verify: golangci-lint gosec govulncheck - -.PHONY: test -test: - @echo "##### Running tests" - go test -race -cover -coverprofile=coverage.coverprofile -covermode=atomic -v ./... - -.PHONY: fuzz -fuzz: - @echo "##### Running fuzz tests" - go test -v -fuzz FuzzEncodeDecode -fuzztime 60s diff --git a/vendor/github.com/gorilla/securecookie/README.md b/vendor/github.com/gorilla/securecookie/README.md deleted file mode 100644 index c3b9815db..000000000 --- a/vendor/github.com/gorilla/securecookie/README.md +++ /dev/null @@ -1,144 +0,0 @@ -# gorilla/securecookie - - -[](https://codecov.io/github/gorilla/securecookie) -[](https://godoc.org/github.com/gorilla/securecookie) -[](https://sourcegraph.com/github.com/gorilla/securecookie?badge) - - - -securecookie encodes and decodes authenticated and optionally encrypted -cookie values. - -Secure cookies can't be forged, because their values are validated using HMAC. -When encrypted, the content is also inaccessible to malicious eyes. It is still -recommended that sensitive data not be stored in cookies, and that HTTPS be used -to prevent cookie [replay attacks](https://en.wikipedia.org/wiki/Replay_attack). - -## Examples - -To use it, first create a new SecureCookie instance: - -```go -// Hash keys should be at least 32 bytes long -var hashKey = []byte("very-secret") -// Block keys should be 16 bytes (AES-128) or 32 bytes (AES-256) long. -// Shorter keys may weaken the encryption used. -var blockKey = []byte("a-lot-secret") -var s = securecookie.New(hashKey, blockKey) -``` - -The hashKey is required, used to authenticate the cookie value using HMAC. -It is recommended to use a key with 32 or 64 bytes. - -The blockKey is optional, used to encrypt the cookie value -- set it to nil -to not use encryption. If set, the length must correspond to the block size -of the encryption algorithm. For AES, used by default, valid lengths are -16, 24, or 32 bytes to select AES-128, AES-192, or AES-256. - -Strong keys can be created using the convenience function -`GenerateRandomKey()`. Note that keys created using `GenerateRandomKey()` are not -automatically persisted. New keys will be created when the application is -restarted, and previously issued cookies will not be able to be decoded. - -Once a SecureCookie instance is set, use it to encode a cookie value: - -```go -func SetCookieHandler(w http.ResponseWriter, r *http.Request) { - value := map[string]string{ - "foo": "bar", - } - if encoded, err := s.Encode("cookie-name", value); err == nil { - cookie := &http.Cookie{ - Name: "cookie-name", - Value: encoded, - Path: "/", - Secure: true, - HttpOnly: true, - } - http.SetCookie(w, cookie) - } -} -``` - -Later, use the same SecureCookie instance to decode and validate a cookie -value: - -```go -func ReadCookieHandler(w http.ResponseWriter, r *http.Request) { - if cookie, err := r.Cookie("cookie-name"); err == nil { - value := make(map[string]string) - if err = s2.Decode("cookie-name", cookie.Value, &value); err == nil { - fmt.Fprintf(w, "The value of foo is %q", value["foo"]) - } - } -} -``` - -We stored a map[string]string, but secure cookies can hold any value that -can be encoded using `encoding/gob`. To store custom types, they must be -registered first using gob.Register(). For basic types this is not needed; -it works out of the box. An optional JSON encoder that uses `encoding/json` is -available for types compatible with JSON. - -### Key Rotation -Rotating keys is an important part of any security strategy. The `EncodeMulti` and -`DecodeMulti` functions allow for multiple keys to be rotated in and out. -For example, let's take a system that stores keys in a map: - -```go -// keys stored in a map will not be persisted between restarts -// a more persistent storage should be considered for production applications. -var cookies = map[string]*securecookie.SecureCookie{ - "previous": securecookie.New( - securecookie.GenerateRandomKey(64), - securecookie.GenerateRandomKey(32), - ), - "current": securecookie.New( - securecookie.GenerateRandomKey(64), - securecookie.GenerateRandomKey(32), - ), -} -``` - -Using the current key to encode new cookies: -```go -func SetCookieHandler(w http.ResponseWriter, r *http.Request) { - value := map[string]string{ - "foo": "bar", - } - if encoded, err := securecookie.EncodeMulti("cookie-name", value, cookies["current"]); err == nil { - cookie := &http.Cookie{ - Name: "cookie-name", - Value: encoded, - Path: "/", - } - http.SetCookie(w, cookie) - } -} -``` - -Later, decode cookies. Check against all valid keys: -```go -func ReadCookieHandler(w http.ResponseWriter, r *http.Request) { - if cookie, err := r.Cookie("cookie-name"); err == nil { - value := make(map[string]string) - err = securecookie.DecodeMulti("cookie-name", cookie.Value, &value, cookies["current"], cookies["previous"]) - if err == nil { - fmt.Fprintf(w, "The value of foo is %q", value["foo"]) - } - } -} -``` - -Rotate the keys. This strategy allows previously issued cookies to be valid until the next rotation: -```go -func Rotate(newCookie *securecookie.SecureCookie) { - cookies["previous"] = cookies["current"] - cookies["current"] = newCookie -} -``` - -## License - -BSD licensed. See the LICENSE file for details. diff --git a/vendor/github.com/gorilla/securecookie/doc.go b/vendor/github.com/gorilla/securecookie/doc.go deleted file mode 100644 index ae89408d9..000000000 --- a/vendor/github.com/gorilla/securecookie/doc.go +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright 2012 The Gorilla Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -/* -Package securecookie encodes and decodes authenticated and optionally -encrypted cookie values. - -Secure cookies can't be forged, because their values are validated using HMAC. -When encrypted, the content is also inaccessible to malicious eyes. - -To use it, first create a new SecureCookie instance: - - var hashKey = []byte("very-secret") - var blockKey = []byte("a-lot-secret") - var s = securecookie.New(hashKey, blockKey) - -The hashKey is required, used to authenticate the cookie value using HMAC. -It is recommended to use a key with 32 or 64 bytes. - -The blockKey is optional, used to encrypt the cookie value -- set it to nil -to not use encryption. If set, the length must correspond to the block size -of the encryption algorithm. For AES, used by default, valid lengths are -16, 24, or 32 bytes to select AES-128, AES-192, or AES-256. - -Strong keys can be created using the convenience function GenerateRandomKey(). - -Once a SecureCookie instance is set, use it to encode a cookie value: - - func SetCookieHandler(w http.ResponseWriter, r *http.Request) { - value := map[string]string{ - "foo": "bar", - } - if encoded, err := s.Encode("cookie-name", value); err == nil { - cookie := &http.Cookie{ - Name: "cookie-name", - Value: encoded, - Path: "/", - } - http.SetCookie(w, cookie) - } - } - -Later, use the same SecureCookie instance to decode and validate a cookie -value: - - func ReadCookieHandler(w http.ResponseWriter, r *http.Request) { - if cookie, err := r.Cookie("cookie-name"); err == nil { - value := make(map[string]string) - if err = s2.Decode("cookie-name", cookie.Value, &value); err == nil { - fmt.Fprintf(w, "The value of foo is %q", value["foo"]) - } - } - } - -We stored a map[string]string, but secure cookies can hold any value that -can be encoded using encoding/gob. To store custom types, they must be -registered first using gob.Register(). For basic types this is not needed; -it works out of the box. -*/ -package securecookie diff --git a/vendor/github.com/gorilla/securecookie/securecookie.go b/vendor/github.com/gorilla/securecookie/securecookie.go deleted file mode 100644 index 4d5ea860d..000000000 --- a/vendor/github.com/gorilla/securecookie/securecookie.go +++ /dev/null @@ -1,649 +0,0 @@ -// Copyright 2012 The Gorilla Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package securecookie - -import ( - "bytes" - "crypto/aes" - "crypto/cipher" - "crypto/hmac" - "crypto/rand" - "crypto/sha256" - "crypto/subtle" - "encoding/base64" - "encoding/gob" - "encoding/json" - "fmt" - "hash" - "io" - "strconv" - "strings" - "time" -) - -// Error is the interface of all errors returned by functions in this library. -type Error interface { - error - - // IsUsage returns true for errors indicating the client code probably - // uses this library incorrectly. For example, the client may have - // failed to provide a valid hash key, or may have failed to configure - // the Serializer adequately for encoding value. - IsUsage() bool - - // IsDecode returns true for errors indicating that a cookie could not - // be decoded and validated. Since cookies are usually untrusted - // user-provided input, errors of this type should be expected. - // Usually, the proper action is simply to reject the request. - IsDecode() bool - - // IsInternal returns true for unexpected errors occurring in the - // securecookie implementation. - IsInternal() bool - - // Cause, if it returns a non-nil value, indicates that this error was - // propagated from some underlying library. If this method returns nil, - // this error was raised directly by this library. - // - // Cause is provided principally for debugging/logging purposes; it is - // rare that application logic should perform meaningfully different - // logic based on Cause. See, for example, the caveats described on - // (MultiError).Cause(). - Cause() error -} - -// errorType is a bitmask giving the error type(s) of an cookieError value. -type errorType int - -const ( - usageError = errorType(1 << iota) - decodeError - internalError -) - -type cookieError struct { - typ errorType - msg string - cause error -} - -func (e cookieError) IsUsage() bool { return (e.typ & usageError) != 0 } -func (e cookieError) IsDecode() bool { return (e.typ & decodeError) != 0 } -func (e cookieError) IsInternal() bool { return (e.typ & internalError) != 0 } - -func (e cookieError) Cause() error { return e.cause } - -func (e cookieError) Error() string { - parts := []string{"securecookie: "} - if e.msg == "" { - parts = append(parts, "error") - } else { - parts = append(parts, e.msg) - } - if c := e.Cause(); c != nil { - parts = append(parts, " - caused by: ", c.Error()) - } - return strings.Join(parts, "") -} - -var ( - errGeneratingIV = cookieError{typ: internalError, msg: "failed to generate random iv"} - - errNoCodecs = cookieError{typ: usageError, msg: "no codecs provided"} - errHashKeyNotSet = cookieError{typ: usageError, msg: "hash key is not set"} - errBlockKeyNotSet = cookieError{typ: usageError, msg: "block key is not set"} - errEncodedValueTooLong = cookieError{typ: usageError, msg: "the value is too long"} - - errValueToDecodeTooLong = cookieError{typ: decodeError, msg: "the value is too long"} - errTimestampInvalid = cookieError{typ: decodeError, msg: "invalid timestamp"} - errTimestampTooNew = cookieError{typ: decodeError, msg: "timestamp is too new"} - errTimestampExpired = cookieError{typ: decodeError, msg: "expired timestamp"} - errDecryptionFailed = cookieError{typ: decodeError, msg: "the value could not be decrypted"} - errValueNotByte = cookieError{typ: decodeError, msg: "value not a []byte."} - errValueNotBytePtr = cookieError{typ: decodeError, msg: "value not a pointer to []byte."} - - // ErrMacInvalid indicates that cookie decoding failed because the HMAC - // could not be extracted and verified. Direct use of this error - // variable is deprecated; it is public only for legacy compatibility, - // and may be privatized in the future, as it is rarely useful to - // distinguish between this error and other Error implementations. - ErrMacInvalid = cookieError{typ: decodeError, msg: "the value is not valid"} -) - -// Codec defines an interface to encode and decode cookie values. -type Codec interface { - Encode(name string, value interface{}) (string, error) - Decode(name, value string, dst interface{}) error -} - -// New returns a new SecureCookie. -// -// hashKey is required, used to authenticate values using HMAC. Create it using -// GenerateRandomKey(). It is recommended to use a key with 32 or 64 bytes. -// -// blockKey is optional, used to encrypt values. Create it using -// GenerateRandomKey(). The key length must correspond to the key size -// of the encryption algorithm. For AES, used by default, valid lengths are -// 16, 24, or 32 bytes to select AES-128, AES-192, or AES-256. -// The default encoder used for cookie serialization is encoding/gob. -// -// Note that keys created using GenerateRandomKey() are not automatically -// persisted. New keys will be created when the application is restarted, and -// previously issued cookies will not be able to be decoded. -func New(hashKey, blockKey []byte) *SecureCookie { - s := &SecureCookie{ - hashKey: hashKey, - blockKey: blockKey, - hashFunc: sha256.New, - maxAge: 86400 * 30, - maxLength: 4096, - sz: GobEncoder{}, - } - if len(hashKey) == 0 { - s.err = errHashKeyNotSet - } - if blockKey != nil { - s.BlockFunc(aes.NewCipher) - } - return s -} - -// SecureCookie encodes and decodes authenticated and optionally encrypted -// cookie values. -type SecureCookie struct { - hashKey []byte - hashFunc func() hash.Hash - blockKey []byte - block cipher.Block - maxLength int - maxAge int64 - minAge int64 - err error - sz Serializer - // For testing purposes, the function that returns the current timestamp. - // If not set, it will use time.Now().UTC().Unix(). - timeFunc func() int64 -} - -// Serializer provides an interface for providing custom serializers for cookie -// values. -type Serializer interface { - Serialize(src interface{}) ([]byte, error) - Deserialize(src []byte, dst interface{}) error -} - -// GobEncoder encodes cookie values using encoding/gob. This is the simplest -// encoder and can handle complex types via gob.Register. -type GobEncoder struct{} - -// JSONEncoder encodes cookie values using encoding/json. Users who wish to -// encode complex types need to satisfy the json.Marshaller and -// json.Unmarshaller interfaces. -type JSONEncoder struct{} - -// NopEncoder does not encode cookie values, and instead simply accepts a []byte -// (as an interface{}) and returns a []byte. This is particularly useful when -// you encoding an object upstream and do not wish to re-encode it. -type NopEncoder struct{} - -// MaxLength restricts the maximum length, in bytes, for the cookie value. -// -// Default is 4096, which is the maximum value accepted by Internet Explorer. -func (s *SecureCookie) MaxLength(value int) *SecureCookie { - s.maxLength = value - return s -} - -// MaxAge restricts the maximum age, in seconds, for the cookie value. -// -// Default is 86400 * 30. Set it to 0 for no restriction. -func (s *SecureCookie) MaxAge(value int) *SecureCookie { - s.maxAge = int64(value) - return s -} - -// MinAge restricts the minimum age, in seconds, for the cookie value. -// -// Default is 0 (no restriction). -func (s *SecureCookie) MinAge(value int) *SecureCookie { - s.minAge = int64(value) - return s -} - -// HashFunc sets the hash function used to create HMAC. -// -// Default is crypto/sha256.New. -func (s *SecureCookie) HashFunc(f func() hash.Hash) *SecureCookie { - s.hashFunc = f - return s -} - -// BlockFunc sets the encryption function used to create a cipher.Block. -// -// Default is crypto/aes.New. -func (s *SecureCookie) BlockFunc(f func([]byte) (cipher.Block, error)) *SecureCookie { - if s.blockKey == nil { - s.err = errBlockKeyNotSet - } else if block, err := f(s.blockKey); err == nil { - s.block = block - } else { - s.err = cookieError{cause: err, typ: usageError} - } - return s -} - -// Encoding sets the encoding/serialization method for cookies. -// -// Default is encoding/gob. To encode special structures using encoding/gob, -// they must be registered first using gob.Register(). -func (s *SecureCookie) SetSerializer(sz Serializer) *SecureCookie { - s.sz = sz - - return s -} - -// Encode encodes a cookie value. -// -// It serializes, optionally encrypts, signs with a message authentication code, -// and finally encodes the value. -// -// The name argument is the cookie name. It is stored with the encoded value. -// The value argument is the value to be encoded. It can be any value that can -// be encoded using the currently selected serializer; see SetSerializer(). -// -// It is the client's responsibility to ensure that value, when encoded using -// the current serialization/encryption settings on s and then base64-encoded, -// is shorter than the maximum permissible length. -func (s *SecureCookie) Encode(name string, value interface{}) (string, error) { - if s.err != nil { - return "", s.err - } - if s.hashKey == nil { - s.err = errHashKeyNotSet - return "", s.err - } - var err error - var b []byte - // 1. Serialize. - if b, err = s.sz.Serialize(value); err != nil { - return "", cookieError{cause: err, typ: usageError} - } - // 2. Encrypt (optional). - if s.block != nil { - if b, err = encrypt(s.block, b); err != nil { - return "", cookieError{cause: err, typ: usageError} - } - } - b = encode(b) - // 3. Create MAC for "name|date|value". Extra pipe to be used later. - b = []byte(fmt.Sprintf("%s|%d|%s|", name, s.timestamp(), b)) - mac := createMac(hmac.New(s.hashFunc, s.hashKey), b[:len(b)-1]) - // Append mac, remove name. - b = append(b, mac...)[len(name)+1:] - // 4. Encode to base64. - b = encode(b) - // 5. Check length. - if s.maxLength != 0 && len(b) > s.maxLength { - return "", fmt.Errorf("%s: %d", errEncodedValueTooLong, len(b)) - } - // Done. - return string(b), nil -} - -// Decode decodes a cookie value. -// -// It decodes, verifies a message authentication code, optionally decrypts and -// finally deserializes the value. -// -// The name argument is the cookie name. It must be the same name used when -// it was stored. The value argument is the encoded cookie value. The dst -// argument is where the cookie will be decoded. It must be a pointer. -func (s *SecureCookie) Decode(name, value string, dst interface{}) error { - if s.err != nil { - return s.err - } - if s.hashKey == nil { - s.err = errHashKeyNotSet - return s.err - } - // 1. Check length. - if s.maxLength != 0 && len(value) > s.maxLength { - return fmt.Errorf("%s: %d", errValueToDecodeTooLong, len(value)) - } - // 2. Decode from base64. - b, err := decode([]byte(value)) - if err != nil { - return err - } - // 3. Verify MAC. Value is "date|value|mac". - parts := bytes.SplitN(b, []byte("|"), 3) - if len(parts) != 3 { - return ErrMacInvalid - } - h := hmac.New(s.hashFunc, s.hashKey) - b = append([]byte(name+"|"), b[:len(b)-len(parts[2])-1]...) - if err = verifyMac(h, b, parts[2]); err != nil { - return err - } - // 4. Verify date ranges. - var t1 int64 - if t1, err = strconv.ParseInt(string(parts[0]), 10, 64); err != nil { - return errTimestampInvalid - } - t2 := s.timestamp() - if s.minAge != 0 && t1 > t2-s.minAge { - return errTimestampTooNew - } - if s.maxAge != 0 && t1 < t2-s.maxAge { - return errTimestampExpired - } - // 5. Decrypt (optional). - b, err = decode(parts[1]) - if err != nil { - return err - } - if s.block != nil { - if b, err = decrypt(s.block, b); err != nil { - return err - } - } - // 6. Deserialize. - if err = s.sz.Deserialize(b, dst); err != nil { - return cookieError{cause: err, typ: decodeError} - } - // Done. - return nil -} - -// timestamp returns the current timestamp, in seconds. -// -// For testing purposes, the function that generates the timestamp can be -// overridden. If not set, it will return time.Now().UTC().Unix(). -func (s *SecureCookie) timestamp() int64 { - if s.timeFunc == nil { - return time.Now().UTC().Unix() - } - return s.timeFunc() -} - -// Authentication ------------------------------------------------------------- - -// createMac creates a message authentication code (MAC). -func createMac(h hash.Hash, value []byte) []byte { - h.Write(value) - return h.Sum(nil) -} - -// verifyMac verifies that a message authentication code (MAC) is valid. -func verifyMac(h hash.Hash, value []byte, mac []byte) error { - mac2 := createMac(h, value) - // Check that both MACs are of equal length, as subtle.ConstantTimeCompare - // does not do this prior to Go 1.4. - if len(mac) == len(mac2) && subtle.ConstantTimeCompare(mac, mac2) == 1 { - return nil - } - return ErrMacInvalid -} - -// Encryption ----------------------------------------------------------------- - -// encrypt encrypts a value using the given block in counter mode. -// -// A random initialization vector ( https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Initialization_vector_(IV) ) with the length of the -// block size is prepended to the resulting ciphertext. -func encrypt(block cipher.Block, value []byte) ([]byte, error) { - iv := GenerateRandomKey(block.BlockSize()) - if iv == nil { - return nil, errGeneratingIV - } - // Encrypt it. - stream := cipher.NewCTR(block, iv) - stream.XORKeyStream(value, value) - // Return iv + ciphertext. - return append(iv, value...), nil -} - -// decrypt decrypts a value using the given block in counter mode. -// -// The value to be decrypted must be prepended by a initialization vector -// ( https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Initialization_vector_(IV) ) with the length of the block size. -func decrypt(block cipher.Block, value []byte) ([]byte, error) { - size := block.BlockSize() - if len(value) > size { - // Extract iv. - iv := value[:size] - // Extract ciphertext. - value = value[size:] - // Decrypt it. - stream := cipher.NewCTR(block, iv) - stream.XORKeyStream(value, value) - return value, nil - } - return nil, errDecryptionFailed -} - -// Serialization -------------------------------------------------------------- - -// Serialize encodes a value using gob. -func (e GobEncoder) Serialize(src interface{}) ([]byte, error) { - buf := new(bytes.Buffer) - enc := gob.NewEncoder(buf) - if err := enc.Encode(src); err != nil { - return nil, cookieError{cause: err, typ: usageError} - } - return buf.Bytes(), nil -} - -// Deserialize decodes a value using gob. -func (e GobEncoder) Deserialize(src []byte, dst interface{}) error { - dec := gob.NewDecoder(bytes.NewBuffer(src)) - if err := dec.Decode(dst); err != nil { - return cookieError{cause: err, typ: decodeError} - } - return nil -} - -// Serialize encodes a value using encoding/json. -func (e JSONEncoder) Serialize(src interface{}) ([]byte, error) { - buf := new(bytes.Buffer) - enc := json.NewEncoder(buf) - if err := enc.Encode(src); err != nil { - return nil, cookieError{cause: err, typ: usageError} - } - return buf.Bytes(), nil -} - -// Deserialize decodes a value using encoding/json. -func (e JSONEncoder) Deserialize(src []byte, dst interface{}) error { - dec := json.NewDecoder(bytes.NewReader(src)) - if err := dec.Decode(dst); err != nil { - return cookieError{cause: err, typ: decodeError} - } - return nil -} - -// Serialize passes a []byte through as-is. -func (e NopEncoder) Serialize(src interface{}) ([]byte, error) { - if b, ok := src.([]byte); ok { - return b, nil - } - - return nil, errValueNotByte -} - -// Deserialize passes a []byte through as-is. -func (e NopEncoder) Deserialize(src []byte, dst interface{}) error { - if dat, ok := dst.(*[]byte); ok { - *dat = src - return nil - } - return errValueNotBytePtr -} - -// Encoding ------------------------------------------------------------------- - -// encode encodes a value using base64. -func encode(value []byte) []byte { - encoded := make([]byte, base64.URLEncoding.EncodedLen(len(value))) - base64.URLEncoding.Encode(encoded, value) - return encoded -} - -// decode decodes a cookie using base64. -func decode(value []byte) ([]byte, error) { - decoded := make([]byte, base64.URLEncoding.DecodedLen(len(value))) - b, err := base64.URLEncoding.Decode(decoded, value) - if err != nil { - return nil, cookieError{cause: err, typ: decodeError, msg: "base64 decode failed"} - } - return decoded[:b], nil -} - -// Helpers -------------------------------------------------------------------- - -// GenerateRandomKey creates a random key with the given length in bytes. -// On failure, returns nil. -// -// Note that keys created using `GenerateRandomKey()` are not automatically -// persisted. New keys will be created when the application is restarted, and -// previously issued cookies will not be able to be decoded. -// -// Callers should explicitly check for the possibility of a nil return, treat -// it as a failure of the system random number generator, and not continue. -func GenerateRandomKey(length int) []byte { - k := make([]byte, length) - if _, err := io.ReadFull(rand.Reader, k); err != nil { - return nil - } - return k -} - -// CodecsFromPairs returns a slice of SecureCookie instances. -// -// It is a convenience function to create a list of codecs for key rotation. Note -// that the generated Codecs will have the default options applied: callers -// should iterate over each Codec and type-assert the underlying *SecureCookie to -// change these. -// -// Example: -// -// codecs := securecookie.CodecsFromPairs( -// []byte("new-hash-key"), -// []byte("new-block-key"), -// []byte("old-hash-key"), -// []byte("old-block-key"), -// ) -// -// // Modify each instance. -// for _, s := range codecs { -// if cookie, ok := s.(*securecookie.SecureCookie); ok { -// cookie.MaxAge(86400 * 7) -// cookie.SetSerializer(securecookie.JSONEncoder{}) -// cookie.HashFunc(sha512.New512_256) -// } -// } -func CodecsFromPairs(keyPairs ...[]byte) []Codec { - codecs := make([]Codec, len(keyPairs)/2+len(keyPairs)%2) - for i := 0; i < len(keyPairs); i += 2 { - var blockKey []byte - if i+1 < len(keyPairs) { - blockKey = keyPairs[i+1] - } - codecs[i/2] = New(keyPairs[i], blockKey) - } - return codecs -} - -// EncodeMulti encodes a cookie value using a group of codecs. -// -// The codecs are tried in order. Multiple codecs are accepted to allow -// key rotation. -// -// On error, may return a MultiError. -func EncodeMulti(name string, value interface{}, codecs ...Codec) (string, error) { - if len(codecs) == 0 { - return "", errNoCodecs - } - - var errors MultiError - for _, codec := range codecs { - encoded, err := codec.Encode(name, value) - if err == nil { - return encoded, nil - } - errors = append(errors, err) - } - return "", errors -} - -// DecodeMulti decodes a cookie value using a group of codecs. -// -// The codecs are tried in order. Multiple codecs are accepted to allow -// key rotation. -// -// On error, may return a MultiError. -func DecodeMulti(name string, value string, dst interface{}, codecs ...Codec) error { - if len(codecs) == 0 { - return errNoCodecs - } - - var errors MultiError - for _, codec := range codecs { - err := codec.Decode(name, value, dst) - if err == nil { - return nil - } - errors = append(errors, err) - } - return errors -} - -// MultiError groups multiple errors. -type MultiError []error - -func (m MultiError) IsUsage() bool { return m.any(func(e Error) bool { return e.IsUsage() }) } -func (m MultiError) IsDecode() bool { return m.any(func(e Error) bool { return e.IsDecode() }) } -func (m MultiError) IsInternal() bool { return m.any(func(e Error) bool { return e.IsInternal() }) } - -// Cause returns nil for MultiError; there is no unique underlying cause in the -// general case. -// -// Note: we could conceivably return a non-nil Cause only when there is exactly -// one child error with a Cause. However, it would be brittle for client code -// to rely on the arity of causes inside a MultiError, so we have opted not to -// provide this functionality. Clients which really wish to access the Causes -// of the underlying errors are free to iterate through the errors themselves. -func (m MultiError) Cause() error { return nil } - -func (m MultiError) Error() string { - s, n := "", 0 - for _, e := range m { - if e != nil { - if n == 0 { - s = e.Error() - } - n++ - } - } - switch n { - case 0: - return "(0 errors)" - case 1: - return s - case 2: - return s + " (and 1 other error)" - } - return fmt.Sprintf("%s (and %d other errors)", s, n-1) -} - -// any returns true if any element of m is an Error for which pred returns true. -func (m MultiError) any(pred func(Error) bool) bool { - for _, e := range m { - if ourErr, ok := e.(Error); ok && pred(ourErr) { - return true - } - } - return false -} diff --git a/vendor/github.com/gorilla/sessions/.editorconfig b/vendor/github.com/gorilla/sessions/.editorconfig deleted file mode 100644 index 2940ec92a..000000000 --- a/vendor/github.com/gorilla/sessions/.editorconfig +++ /dev/null @@ -1,20 +0,0 @@ -; https://editorconfig.org/ - -root = true - -[*] -insert_final_newline = true -charset = utf-8 -trim_trailing_whitespace = true -indent_style = space -indent_size = 2 - -[{Makefile,go.mod,go.sum,*.go,.gitmodules}] -indent_style = tab -indent_size = 4 - -[*.md] -indent_size = 4 -trim_trailing_whitespace = false - -eclint_indent_style = unset diff --git a/vendor/github.com/gorilla/sessions/.gitignore b/vendor/github.com/gorilla/sessions/.gitignore deleted file mode 100644 index 84039fec6..000000000 --- a/vendor/github.com/gorilla/sessions/.gitignore +++ /dev/null @@ -1 +0,0 @@ -coverage.coverprofile diff --git a/vendor/github.com/gorilla/sessions/LICENSE b/vendor/github.com/gorilla/sessions/LICENSE deleted file mode 100644 index bb9d80bc9..000000000 --- a/vendor/github.com/gorilla/sessions/LICENSE +++ /dev/null @@ -1,27 +0,0 @@ -Copyright (c) 2023 The Gorilla Authors. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/gorilla/sessions/Makefile b/vendor/github.com/gorilla/sessions/Makefile deleted file mode 100644 index ac37ffd32..000000000 --- a/vendor/github.com/gorilla/sessions/Makefile +++ /dev/null @@ -1,34 +0,0 @@ -GO_LINT=$(shell which golangci-lint 2> /dev/null || echo '') -GO_LINT_URI=github.com/golangci/golangci-lint/cmd/golangci-lint@latest - -GO_SEC=$(shell which gosec 2> /dev/null || echo '') -GO_SEC_URI=github.com/securego/gosec/v2/cmd/gosec@latest - -GO_VULNCHECK=$(shell which govulncheck 2> /dev/null || echo '') -GO_VULNCHECK_URI=golang.org/x/vuln/cmd/govulncheck@latest - -.PHONY: golangci-lint -golangci-lint: - $(if $(GO_LINT), ,go install $(GO_LINT_URI)) - @echo "##### Running golangci-lint" - golangci-lint run -v - -.PHONY: gosec -gosec: - $(if $(GO_SEC), ,go install $(GO_SEC_URI)) - @echo "##### Running gosec" - gosec ./... - -.PHONY: govulncheck -govulncheck: - $(if $(GO_VULNCHECK), ,go install $(GO_VULNCHECK_URI)) - @echo "##### Running govulncheck" - govulncheck ./... - -.PHONY: verify -verify: golangci-lint gosec govulncheck - -.PHONY: test -test: - @echo "##### Running tests" - go test -race -cover -coverprofile=coverage.coverprofile -covermode=atomic -v ./... diff --git a/vendor/github.com/gorilla/sessions/README.md b/vendor/github.com/gorilla/sessions/README.md deleted file mode 100644 index 06119bbbe..000000000 --- a/vendor/github.com/gorilla/sessions/README.md +++ /dev/null @@ -1,95 +0,0 @@ -# sessions - - -[](https://codecov.io/github/gorilla/sessions) -[](https://godoc.org/github.com/gorilla/sessions) -[](https://sourcegraph.com/github.com/gorilla/sessions?badge) - - - -gorilla/sessions provides cookie and filesystem sessions and infrastructure for -custom session backends. - -The key features are: - -- Simple API: use it as an easy way to set signed (and optionally - encrypted) cookies. -- Built-in backends to store sessions in cookies or the filesystem. -- Flash messages: session values that last until read. -- Convenient way to switch session persistency (aka "remember me") and set - other attributes. -- Mechanism to rotate authentication and encryption keys. -- Multiple sessions per request, even using different backends. -- Interfaces and infrastructure for custom session backends: sessions from - different stores can be retrieved and batch-saved using a common API. - -Let's start with an example that shows the sessions API in a nutshell: - -```go - import ( - "net/http" - "github.com/gorilla/sessions" - ) - - // Note: Don't store your key in your source code. Pass it via an - // environmental variable, or flag (or both), and don't accidentally commit it - // alongside your code. Ensure your key is sufficiently random - i.e. use Go's - // crypto/rand or securecookie.GenerateRandomKey(32) and persist the result. - var store = sessions.NewCookieStore([]byte(os.Getenv("SESSION_KEY"))) - - func MyHandler(w http.ResponseWriter, r *http.Request) { - // Get a session. We're ignoring the error resulted from decoding an - // existing session: Get() always returns a session, even if empty. - session, _ := store.Get(r, "session-name") - // Set some session values. - session.Values["foo"] = "bar" - session.Values[42] = 43 - // Save it before we write to the response/return from the handler. - err := session.Save(r, w) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - } -``` - -First we initialize a session store calling `NewCookieStore()` and passing a -secret key used to authenticate the session. Inside the handler, we call -`store.Get()` to retrieve an existing session or create a new one. Then we set -some session values in session.Values, which is a `map[interface{}]interface{}`. -And finally we call `session.Save()` to save the session in the response. - -More examples are available [on the Gorilla -website](https://www.gorillatoolkit.org/pkg/sessions). - -## Store Implementations - -Other implementations of the `sessions.Store` interface: - -- [github.com/starJammer/gorilla-sessions-arangodb](https://github.com/starJammer/gorilla-sessions-arangodb) - ArangoDB -- [github.com/yosssi/boltstore](https://github.com/yosssi/boltstore) - Bolt -- [github.com/srinathgs/couchbasestore](https://github.com/srinathgs/couchbasestore) - Couchbase -- [github.com/denizeren/dynamostore](https://github.com/denizeren/dynamostore) - Dynamodb on AWS -- [github.com/savaki/dynastore](https://github.com/savaki/dynastore) - DynamoDB on AWS (Official AWS library) -- [github.com/bradleypeabody/gorilla-sessions-memcache](https://github.com/bradleypeabody/gorilla-sessions-memcache) - Memcache -- [github.com/dsoprea/go-appengine-sessioncascade](https://github.com/dsoprea/go-appengine-sessioncascade) - Memcache/Datastore/Context in AppEngine -- [github.com/kidstuff/mongostore](https://github.com/kidstuff/mongostore) - MongoDB -- [github.com/srinathgs/mysqlstore](https://github.com/srinathgs/mysqlstore) - MySQL -- [github.com/EnumApps/clustersqlstore](https://github.com/EnumApps/clustersqlstore) - MySQL Cluster -- [github.com/antonlindstrom/pgstore](https://github.com/antonlindstrom/pgstore) - PostgreSQL -- [github.com/boj/redistore](https://github.com/boj/redistore) - Redis -- [github.com/rbcervilla/redisstore](https://github.com/rbcervilla/redisstore) - Redis (Single, Sentinel, Cluster) -- [github.com/boj/rethinkstore](https://github.com/boj/rethinkstore) - RethinkDB -- [github.com/boj/riakstore](https://github.com/boj/riakstore) - Riak -- [github.com/michaeljs1990/sqlitestore](https://github.com/michaeljs1990/sqlitestore) - SQLite -- [github.com/wader/gormstore](https://github.com/wader/gormstore) - GORM (MySQL, PostgreSQL, SQLite) -- [github.com/gernest/qlstore](https://github.com/gernest/qlstore) - ql -- [github.com/quasoft/memstore](https://github.com/quasoft/memstore) - In-memory implementation for use in unit tests -- [github.com/lafriks/xormstore](https://github.com/lafriks/xormstore) - XORM (MySQL, PostgreSQL, SQLite, Microsoft SQL Server, TiDB) -- [github.com/GoogleCloudPlatform/firestore-gorilla-sessions](https://github.com/GoogleCloudPlatform/firestore-gorilla-sessions) - Cloud Firestore -- [github.com/stephenafamo/crdbstore](https://github.com/stephenafamo/crdbstore) - CockroachDB -- [github.com/ryicoh/tikvstore](github.com/ryicoh/tikvstore) - TiKV - -## License - -BSD licensed. See the LICENSE file for details. diff --git a/vendor/github.com/gorilla/sessions/cookie.go b/vendor/github.com/gorilla/sessions/cookie.go deleted file mode 100644 index 6612662cc..000000000 --- a/vendor/github.com/gorilla/sessions/cookie.go +++ /dev/null @@ -1,20 +0,0 @@ -//go:build !go1.11 -// +build !go1.11 - -package sessions - -import "net/http" - -// newCookieFromOptions returns an http.Cookie with the options set. -func newCookieFromOptions(name, value string, options *Options) *http.Cookie { - return &http.Cookie{ - Name: name, - Value: value, - Path: options.Path, - Domain: options.Domain, - MaxAge: options.MaxAge, - Secure: options.Secure, - HttpOnly: options.HttpOnly, - } - -} diff --git a/vendor/github.com/gorilla/sessions/cookie_go111.go b/vendor/github.com/gorilla/sessions/cookie_go111.go deleted file mode 100644 index 9b5882835..000000000 --- a/vendor/github.com/gorilla/sessions/cookie_go111.go +++ /dev/null @@ -1,21 +0,0 @@ -//go:build go1.11 -// +build go1.11 - -package sessions - -import "net/http" - -// newCookieFromOptions returns an http.Cookie with the options set. -func newCookieFromOptions(name, value string, options *Options) *http.Cookie { - return &http.Cookie{ - Name: name, - Value: value, - Path: options.Path, - Domain: options.Domain, - MaxAge: options.MaxAge, - Secure: options.Secure, - HttpOnly: options.HttpOnly, - SameSite: options.SameSite, - } - -} diff --git a/vendor/github.com/gorilla/sessions/doc.go b/vendor/github.com/gorilla/sessions/doc.go deleted file mode 100644 index 946bf5ca1..000000000 --- a/vendor/github.com/gorilla/sessions/doc.go +++ /dev/null @@ -1,207 +0,0 @@ -// Copyright 2012 The Gorilla Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -/* -Package sessions provides cookie and filesystem sessions and -infrastructure for custom session backends. - -The key features are: - - * Simple API: use it as an easy way to set signed (and optionally - encrypted) cookies. - * Built-in backends to store sessions in cookies or the filesystem. - * Flash messages: session values that last until read. - * Convenient way to switch session persistency (aka "remember me") and set - other attributes. - * Mechanism to rotate authentication and encryption keys. - * Multiple sessions per request, even using different backends. - * Interfaces and infrastructure for custom session backends: sessions from - different stores can be retrieved and batch-saved using a common API. - -Let's start with an example that shows the sessions API in a nutshell: - - import ( - "net/http" - "github.com/gorilla/sessions" - ) - - // Note: Don't store your key in your source code. Pass it via an - // environmental variable, or flag (or both), and don't accidentally commit it - // alongside your code. Ensure your key is sufficiently random - i.e. use Go's - // crypto/rand or securecookie.GenerateRandomKey(32) and persist the result. - // Ensure SESSION_KEY exists in the environment, or sessions will fail. - var store = sessions.NewCookieStore([]byte(os.Getenv("SESSION_KEY"))) - - func MyHandler(w http.ResponseWriter, r *http.Request) { - // Get a session. Get() always returns a session, even if empty. - session, err := store.Get(r, "session-name") - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - - // Set some session values. - session.Values["foo"] = "bar" - session.Values[42] = 43 - // Save it before we write to the response/return from the handler. - err = session.Save(r, w) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - } - -First we initialize a session store calling NewCookieStore() and passing a -secret key used to authenticate the session. Inside the handler, we call -store.Get() to retrieve an existing session or a new one. Then we set some -session values in session.Values, which is a map[interface{}]interface{}. -And finally we call session.Save() to save the session in the response. - -Note that in production code, we should check for errors when calling -session.Save(r, w), and either display an error message or otherwise handle it. - -Save must be called before writing to the response, otherwise the session -cookie will not be sent to the client. - -That's all you need to know for the basic usage. Let's take a look at other -options, starting with flash messages. - -Flash messages are session values that last until read. The term appeared with -Ruby On Rails a few years back. When we request a flash message, it is removed -from the session. To add a flash, call session.AddFlash(), and to get all -flashes, call session.Flashes(). Here is an example: - - func MyHandler(w http.ResponseWriter, r *http.Request) { - // Get a session. - session, err := store.Get(r, "session-name") - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - - // Get the previous flashes, if any. - if flashes := session.Flashes(); len(flashes) > 0 { - // Use the flash values. - } else { - // Set a new flash. - session.AddFlash("Hello, flash messages world!") - } - err = session.Save(r, w) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - } - -Flash messages are useful to set information to be read after a redirection, -like after form submissions. - -There may also be cases where you want to store a complex datatype within a -session, such as a struct. Sessions are serialised using the encoding/gob package, -so it is easy to register new datatypes for storage in sessions: - - import( - "encoding/gob" - "github.com/gorilla/sessions" - ) - - type Person struct { - FirstName string - LastName string - Email string - Age int - } - - type M map[string]interface{} - - func init() { - - gob.Register(&Person{}) - gob.Register(&M{}) - } - -As it's not possible to pass a raw type as a parameter to a function, gob.Register() -relies on us passing it a value of the desired type. In the example above we've passed -it a pointer to a struct and a pointer to a custom type representing a -map[string]interface. (We could have passed non-pointer values if we wished.) This will -then allow us to serialise/deserialise values of those types to and from our sessions. - -Note that because session values are stored in a map[string]interface{}, there's -a need to type-assert data when retrieving it. We'll use the Person struct we registered above: - - func MyHandler(w http.ResponseWriter, r *http.Request) { - session, err := store.Get(r, "session-name") - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - - // Retrieve our struct and type-assert it - val := session.Values["person"] - var person = &Person{} - if person, ok := val.(*Person); !ok { - // Handle the case that it's not an expected type - } - - // Now we can use our person object - } - -By default, session cookies last for a month. This is probably too long for -some cases, but it is easy to change this and other attributes during -runtime. Sessions can be configured individually or the store can be -configured and then all sessions saved using it will use that configuration. -We access session.Options or store.Options to set a new configuration. The -fields are basically a subset of http.Cookie fields. Let's change the -maximum age of a session to one week: - - session.Options = &sessions.Options{ - Path: "/", - MaxAge: 86400 * 7, - HttpOnly: true, - } - -Sometimes we may want to change authentication and/or encryption keys without -breaking existing sessions. The CookieStore supports key rotation, and to use -it you just need to set multiple authentication and encryption keys, in pairs, -to be tested in order: - - var store = sessions.NewCookieStore( - []byte("new-authentication-key"), - []byte("new-encryption-key"), - []byte("old-authentication-key"), - []byte("old-encryption-key"), - ) - -New sessions will be saved using the first pair. Old sessions can still be -read because the first pair will fail, and the second will be tested. This -makes it easy to "rotate" secret keys and still be able to validate existing -sessions. Note: for all pairs the encryption key is optional; set it to nil -or omit it and and encryption won't be used. - -Multiple sessions can be used in the same request, even with different -session backends. When this happens, calling Save() on each session -individually would be cumbersome, so we have a way to save all sessions -at once: it's sessions.Save(). Here's an example: - - var store = sessions.NewCookieStore([]byte("something-very-secret")) - - func MyHandler(w http.ResponseWriter, r *http.Request) { - // Get a session and set a value. - session1, _ := store.Get(r, "session-one") - session1.Values["foo"] = "bar" - // Get another session and set another value. - session2, _ := store.Get(r, "session-two") - session2.Values[42] = 43 - // Save all sessions. - err = sessions.Save(r, w) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - } - -This is possible because when we call Get() from a session store, it adds the -session to a common registry. Save() uses it to save all registered sessions. -*/ -package sessions diff --git a/vendor/github.com/gorilla/sessions/lex.go b/vendor/github.com/gorilla/sessions/lex.go deleted file mode 100644 index 4bbbe1096..000000000 --- a/vendor/github.com/gorilla/sessions/lex.go +++ /dev/null @@ -1,102 +0,0 @@ -// This file contains code adapted from the Go standard library -// https://github.com/golang/go/blob/39ad0fd0789872f9469167be7fe9578625ff246e/src/net/http/lex.go - -package sessions - -import "strings" - -var isTokenTable = [127]bool{ - '!': true, - '#': true, - '$': true, - '%': true, - '&': true, - '\'': true, - '*': true, - '+': true, - '-': true, - '.': true, - '0': true, - '1': true, - '2': true, - '3': true, - '4': true, - '5': true, - '6': true, - '7': true, - '8': true, - '9': true, - 'A': true, - 'B': true, - 'C': true, - 'D': true, - 'E': true, - 'F': true, - 'G': true, - 'H': true, - 'I': true, - 'J': true, - 'K': true, - 'L': true, - 'M': true, - 'N': true, - 'O': true, - 'P': true, - 'Q': true, - 'R': true, - 'S': true, - 'T': true, - 'U': true, - 'W': true, - 'V': true, - 'X': true, - 'Y': true, - 'Z': true, - '^': true, - '_': true, - '`': true, - 'a': true, - 'b': true, - 'c': true, - 'd': true, - 'e': true, - 'f': true, - 'g': true, - 'h': true, - 'i': true, - 'j': true, - 'k': true, - 'l': true, - 'm': true, - 'n': true, - 'o': true, - 'p': true, - 'q': true, - 'r': true, - 's': true, - 't': true, - 'u': true, - 'v': true, - 'w': true, - 'x': true, - 'y': true, - 'z': true, - '|': true, - '~': true, -} - -func isToken(r rune) bool { - i := int(r) - return i < len(isTokenTable) && isTokenTable[i] -} - -func isNotToken(r rune) bool { - return !isToken(r) -} - -func isCookieNameValid(raw string) bool { - if raw == "" { - return false - } - return strings.IndexFunc(raw, isNotToken) < 0 -} diff --git a/vendor/github.com/gorilla/sessions/options.go b/vendor/github.com/gorilla/sessions/options.go deleted file mode 100644 index d33d0761a..000000000 --- a/vendor/github.com/gorilla/sessions/options.go +++ /dev/null @@ -1,19 +0,0 @@ -//go:build !go1.11 -// +build !go1.11 - -package sessions - -// Options stores configuration for a session or session store. -// -// Fields are a subset of http.Cookie fields. -type Options struct { - Path string - Domain string - // MaxAge=0 means no Max-Age attribute specified and the cookie will be - // deleted after the browser session ends. - // MaxAge<0 means delete cookie immediately. - // MaxAge>0 means Max-Age attribute present and given in seconds. - MaxAge int - Secure bool - HttpOnly bool -} diff --git a/vendor/github.com/gorilla/sessions/options_go111.go b/vendor/github.com/gorilla/sessions/options_go111.go deleted file mode 100644 index af9cdf08d..000000000 --- a/vendor/github.com/gorilla/sessions/options_go111.go +++ /dev/null @@ -1,23 +0,0 @@ -//go:build go1.11 -// +build go1.11 - -package sessions - -import "net/http" - -// Options stores configuration for a session or session store. -// -// Fields are a subset of http.Cookie fields. -type Options struct { - Path string - Domain string - // MaxAge=0 means no Max-Age attribute specified and the cookie will be - // deleted after the browser session ends. - // MaxAge<0 means delete cookie immediately. - // MaxAge>0 means Max-Age attribute present and given in seconds. - MaxAge int - Secure bool - HttpOnly bool - // Defaults to http.SameSiteDefaultMode - SameSite http.SameSite -} diff --git a/vendor/github.com/gorilla/sessions/sessions.go b/vendor/github.com/gorilla/sessions/sessions.go deleted file mode 100644 index c052b2891..000000000 --- a/vendor/github.com/gorilla/sessions/sessions.go +++ /dev/null @@ -1,218 +0,0 @@ -// Copyright 2012 The Gorilla Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package sessions - -import ( - "context" - "encoding/gob" - "fmt" - "net/http" - "time" -) - -// Default flashes key. -const flashesKey = "_flash" - -// Session -------------------------------------------------------------------- - -// NewSession is called by session stores to create a new session instance. -func NewSession(store Store, name string) *Session { - return &Session{ - Values: make(map[interface{}]interface{}), - store: store, - name: name, - Options: new(Options), - } -} - -// Session stores the values and optional configuration for a session. -type Session struct { - // The ID of the session, generated by stores. It should not be used for - // user data. - ID string - // Values contains the user-data for the session. - Values map[interface{}]interface{} - Options *Options - IsNew bool - store Store - name string -} - -// Flashes returns a slice of flash messages from the session. -// -// A single variadic argument is accepted, and it is optional: it defines -// the flash key. If not defined "_flash" is used by default. -func (s *Session) Flashes(vars ...string) []interface{} { - var flashes []interface{} - key := flashesKey - if len(vars) > 0 { - key = vars[0] - } - if v, ok := s.Values[key]; ok { - // Drop the flashes and return it. - delete(s.Values, key) - flashes = v.([]interface{}) - } - return flashes -} - -// AddFlash adds a flash message to the session. -// -// A single variadic argument is accepted, and it is optional: it defines -// the flash key. If not defined "_flash" is used by default. -func (s *Session) AddFlash(value interface{}, vars ...string) { - key := flashesKey - if len(vars) > 0 { - key = vars[0] - } - var flashes []interface{} - if v, ok := s.Values[key]; ok { - flashes = v.([]interface{}) - } - s.Values[key] = append(flashes, value) -} - -// Save is a convenience method to save this session. It is the same as calling -// store.Save(request, response, session). You should call Save before writing to -// the response or returning from the handler. -func (s *Session) Save(r *http.Request, w http.ResponseWriter) error { - return s.store.Save(r, w, s) -} - -// Name returns the name used to register the session. -func (s *Session) Name() string { - return s.name -} - -// Store returns the session store used to register the session. -func (s *Session) Store() Store { - return s.store -} - -// Registry ------------------------------------------------------------------- - -// sessionInfo stores a session tracked by the registry. -type sessionInfo struct { - s *Session - e error -} - -// contextKey is the type used to store the registry in the context. -type contextKey int - -// registryKey is the key used to store the registry in the context. -const registryKey contextKey = 0 - -// GetRegistry returns a registry instance for the current request. -func GetRegistry(r *http.Request) *Registry { - var ctx = r.Context() - registry := ctx.Value(registryKey) - if registry != nil { - return registry.(*Registry) - } - newRegistry := &Registry{ - request: r, - sessions: make(map[string]sessionInfo), - } - *r = *r.WithContext(context.WithValue(ctx, registryKey, newRegistry)) - return newRegistry -} - -// Registry stores sessions used during a request. -type Registry struct { - request *http.Request - sessions map[string]sessionInfo -} - -// Get registers and returns a session for the given name and session store. -// -// It returns a new session if there are no sessions registered for the name. -func (s *Registry) Get(store Store, name string) (session *Session, err error) { - if !isCookieNameValid(name) { - return nil, fmt.Errorf("sessions: invalid character in cookie name: %s", name) - } - if info, ok := s.sessions[name]; ok { - session, err = info.s, info.e - } else { - session, err = store.New(s.request, name) - session.name = name - s.sessions[name] = sessionInfo{s: session, e: err} - } - session.store = store - return -} - -// Save saves all sessions registered for the current request. -func (s *Registry) Save(w http.ResponseWriter) error { - var errMulti MultiError - for name, info := range s.sessions { - session := info.s - if session.store == nil { - errMulti = append(errMulti, fmt.Errorf( - "sessions: missing store for session %q", name)) - } else if err := session.store.Save(s.request, w, session); err != nil { - errMulti = append(errMulti, fmt.Errorf( - "sessions: error saving session %q -- %v", name, err)) - } - } - if errMulti != nil { - return errMulti - } - return nil -} - -// Helpers -------------------------------------------------------------------- - -func init() { - gob.Register([]interface{}{}) -} - -// Save saves all sessions used during the current request. -func Save(r *http.Request, w http.ResponseWriter) error { - return GetRegistry(r).Save(w) -} - -// NewCookie returns an http.Cookie with the options set. It also sets -// the Expires field calculated based on the MaxAge value, for Internet -// Explorer compatibility. -func NewCookie(name, value string, options *Options) *http.Cookie { - cookie := newCookieFromOptions(name, value, options) - if options.MaxAge > 0 { - d := time.Duration(options.MaxAge) * time.Second - cookie.Expires = time.Now().Add(d) - } else if options.MaxAge < 0 { - // Set it to the past to expire now. - cookie.Expires = time.Unix(1, 0) - } - return cookie -} - -// Error ---------------------------------------------------------------------- - -// MultiError stores multiple errors. -// -// Borrowed from the App Engine SDK. -type MultiError []error - -func (m MultiError) Error() string { - s, n := "", 0 - for _, e := range m { - if e != nil { - if n == 0 { - s = e.Error() - } - n++ - } - } - switch n { - case 0: - return "(0 errors)" - case 1: - return s - case 2: - return s + " (and 1 other error)" - } - return fmt.Sprintf("%s (and %d other errors)", s, n-1) -} diff --git a/vendor/github.com/gorilla/sessions/store.go b/vendor/github.com/gorilla/sessions/store.go deleted file mode 100644 index aea37e4b5..000000000 --- a/vendor/github.com/gorilla/sessions/store.go +++ /dev/null @@ -1,291 +0,0 @@ -// Copyright 2012 The Gorilla Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package sessions - -import ( - "encoding/base32" - "net/http" - "os" - "path/filepath" - "sync" - - "github.com/gorilla/securecookie" -) - -// Store is an interface for custom session stores. -// -// See CookieStore and FilesystemStore for examples. -type Store interface { - // Get should return a cached session. - Get(r *http.Request, name string) (*Session, error) - - // New should create and return a new session. - // - // Note that New should never return a nil session, even in the case of - // an error if using the Registry infrastructure to cache the session. - New(r *http.Request, name string) (*Session, error) - - // Save should persist session to the underlying store implementation. - Save(r *http.Request, w http.ResponseWriter, s *Session) error -} - -// CookieStore ---------------------------------------------------------------- - -// NewCookieStore returns a new CookieStore. -// -// Keys are defined in pairs to allow key rotation, but the common case is -// to set a single authentication key and optionally an encryption key. -// -// The first key in a pair is used for authentication and the second for -// encryption. The encryption key can be set to nil or omitted in the last -// pair, but the authentication key is required in all pairs. -// -// It is recommended to use an authentication key with 32 or 64 bytes. -// The encryption key, if set, must be either 16, 24, or 32 bytes to select -// AES-128, AES-192, or AES-256 modes. -func NewCookieStore(keyPairs ...[]byte) *CookieStore { - cs := &CookieStore{ - Codecs: securecookie.CodecsFromPairs(keyPairs...), - Options: &Options{ - Path: "/", - MaxAge: 86400 * 30, - }, - } - - cs.MaxAge(cs.Options.MaxAge) - return cs -} - -// CookieStore stores sessions using secure cookies. -type CookieStore struct { - Codecs []securecookie.Codec - Options *Options // default configuration -} - -// Get returns a session for the given name after adding it to the registry. -// -// It returns a new session if the sessions doesn't exist. Access IsNew on -// the session to check if it is an existing session or a new one. -// -// It returns a new session and an error if the session exists but could -// not be decoded. -func (s *CookieStore) Get(r *http.Request, name string) (*Session, error) { - return GetRegistry(r).Get(s, name) -} - -// New returns a session for the given name without adding it to the registry. -// -// The difference between New() and Get() is that calling New() twice will -// decode the session data twice, while Get() registers and reuses the same -// decoded session after the first call. -func (s *CookieStore) New(r *http.Request, name string) (*Session, error) { - session := NewSession(s, name) - opts := *s.Options - session.Options = &opts - session.IsNew = true - var err error - if c, errCookie := r.Cookie(name); errCookie == nil { - err = securecookie.DecodeMulti(name, c.Value, &session.Values, - s.Codecs...) - if err == nil { - session.IsNew = false - } - } - return session, err -} - -// Save adds a single session to the response. -func (s *CookieStore) Save(r *http.Request, w http.ResponseWriter, - session *Session) error { - encoded, err := securecookie.EncodeMulti(session.Name(), session.Values, - s.Codecs...) - if err != nil { - return err - } - http.SetCookie(w, NewCookie(session.Name(), encoded, session.Options)) - return nil -} - -// MaxAge sets the maximum age for the store and the underlying cookie -// implementation. Individual sessions can be deleted by setting Options.MaxAge -// = -1 for that session. -func (s *CookieStore) MaxAge(age int) { - s.Options.MaxAge = age - - // Set the maxAge for each securecookie instance. - for _, codec := range s.Codecs { - if sc, ok := codec.(*securecookie.SecureCookie); ok { - sc.MaxAge(age) - } - } -} - -// FilesystemStore ------------------------------------------------------------ - -var fileMutex sync.RWMutex - -// NewFilesystemStore returns a new FilesystemStore. -// -// The path argument is the directory where sessions will be saved. If empty -// it will use os.TempDir(). -// -// See NewCookieStore() for a description of the other parameters. -func NewFilesystemStore(path string, keyPairs ...[]byte) *FilesystemStore { - if path == "" { - path = os.TempDir() - } - fs := &FilesystemStore{ - Codecs: securecookie.CodecsFromPairs(keyPairs...), - Options: &Options{ - Path: "/", - MaxAge: 86400 * 30, - }, - path: path, - } - - fs.MaxAge(fs.Options.MaxAge) - return fs -} - -// FilesystemStore stores sessions in the filesystem. -// -// It also serves as a reference for custom stores. -// -// This store is still experimental and not well tested. Feedback is welcome. -type FilesystemStore struct { - Codecs []securecookie.Codec - Options *Options // default configuration - path string -} - -// MaxLength restricts the maximum length of new sessions to l. -// If l is 0 there is no limit to the size of a session, use with caution. -// The default for a new FilesystemStore is 4096. -func (s *FilesystemStore) MaxLength(l int) { - for _, c := range s.Codecs { - if codec, ok := c.(*securecookie.SecureCookie); ok { - codec.MaxLength(l) - } - } -} - -// Get returns a session for the given name after adding it to the registry. -// -// See CookieStore.Get(). -func (s *FilesystemStore) Get(r *http.Request, name string) (*Session, error) { - return GetRegistry(r).Get(s, name) -} - -// New returns a session for the given name without adding it to the registry. -// -// See CookieStore.New(). -func (s *FilesystemStore) New(r *http.Request, name string) (*Session, error) { - session := NewSession(s, name) - opts := *s.Options - session.Options = &opts - session.IsNew = true - var err error - if c, errCookie := r.Cookie(name); errCookie == nil { - err = securecookie.DecodeMulti(name, c.Value, &session.ID, s.Codecs...) - if err == nil { - err = s.load(session) - if err == nil { - session.IsNew = false - } - } - } - return session, err -} - -var base32RawStdEncoding = base32.StdEncoding.WithPadding(base32.NoPadding) - -// Save adds a single session to the response. -// -// If the Options.MaxAge of the session is <= 0 then the session file will be -// deleted from the store path. With this process it enforces the properly -// session cookie handling so no need to trust in the cookie management in the -// web browser. -func (s *FilesystemStore) Save(r *http.Request, w http.ResponseWriter, - session *Session) error { - // Delete if max-age is <= 0 - if session.Options.MaxAge <= 0 { - if err := s.erase(session); err != nil && !os.IsNotExist(err) { - return err - } - http.SetCookie(w, NewCookie(session.Name(), "", session.Options)) - return nil - } - - if session.ID == "" { - // Because the ID is used in the filename, encode it to - // use alphanumeric characters only. - session.ID = base32RawStdEncoding.EncodeToString( - securecookie.GenerateRandomKey(32)) - } - if err := s.save(session); err != nil { - return err - } - encoded, err := securecookie.EncodeMulti(session.Name(), session.ID, - s.Codecs...) - if err != nil { - return err - } - http.SetCookie(w, NewCookie(session.Name(), encoded, session.Options)) - return nil -} - -// MaxAge sets the maximum age for the store and the underlying cookie -// implementation. Individual sessions can be deleted by setting Options.MaxAge -// = -1 for that session. -func (s *FilesystemStore) MaxAge(age int) { - s.Options.MaxAge = age - - // Set the maxAge for each securecookie instance. - for _, codec := range s.Codecs { - if sc, ok := codec.(*securecookie.SecureCookie); ok { - sc.MaxAge(age) - } - } -} - -// save writes encoded session.Values to a file. -func (s *FilesystemStore) save(session *Session) error { - encoded, err := securecookie.EncodeMulti(session.Name(), session.Values, - s.Codecs...) - if err != nil { - return err - } - filename := filepath.Join(s.path, "session_"+session.ID) - fileMutex.Lock() - defer fileMutex.Unlock() - return os.WriteFile(filename, []byte(encoded), 0600) -} - -// load reads a file and decodes its content into session.Values. -func (s *FilesystemStore) load(session *Session) error { - filename := filepath.Join(s.path, "session_"+session.ID) - fileMutex.RLock() - defer fileMutex.RUnlock() - fdata, err := os.ReadFile(filepath.Clean(filename)) - if err != nil { - return err - } - if err = securecookie.DecodeMulti(session.Name(), string(fdata), - &session.Values, s.Codecs...); err != nil { - return err - } - return nil -} - -// delete session file -func (s *FilesystemStore) erase(session *Session) error { - filename := filepath.Join(s.path, "session_"+session.ID) - - fileMutex.RLock() - defer fileMutex.RUnlock() - - err := os.Remove(filename) - return err -} diff --git a/vendor/github.com/gorilla/websocket/.gitignore b/vendor/github.com/gorilla/websocket/.gitignore deleted file mode 100644 index cd3fcd1ef..000000000 --- a/vendor/github.com/gorilla/websocket/.gitignore +++ /dev/null @@ -1,25 +0,0 @@ -# Compiled Object files, Static and Dynamic libs (Shared Objects) -*.o -*.a -*.so - -# Folders -_obj -_test - -# Architecture specific extensions/prefixes -*.[568vq] -[568vq].out - -*.cgo1.go -*.cgo2.c -_cgo_defun.c -_cgo_gotypes.go -_cgo_export.* - -_testmain.go - -*.exe - -.idea/ -*.iml diff --git a/vendor/github.com/gorilla/websocket/AUTHORS b/vendor/github.com/gorilla/websocket/AUTHORS deleted file mode 100644 index 1931f4006..000000000 --- a/vendor/github.com/gorilla/websocket/AUTHORS +++ /dev/null @@ -1,9 +0,0 @@ -# This is the official list of Gorilla WebSocket authors for copyright -# purposes. -# -# Please keep the list sorted. - -Gary Burd <gary@beagledreams.com> -Google LLC (https://opensource.google.com/) -Joachim Bauch <mail@joachim-bauch.de> - diff --git a/vendor/github.com/gorilla/websocket/LICENSE b/vendor/github.com/gorilla/websocket/LICENSE deleted file mode 100644 index 9171c9722..000000000 --- a/vendor/github.com/gorilla/websocket/LICENSE +++ /dev/null @@ -1,22 +0,0 @@ -Copyright (c) 2013 The Gorilla WebSocket Authors. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - - Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/gorilla/websocket/README.md b/vendor/github.com/gorilla/websocket/README.md deleted file mode 100644 index d33ed7fdd..000000000 --- a/vendor/github.com/gorilla/websocket/README.md +++ /dev/null @@ -1,33 +0,0 @@ -# Gorilla WebSocket - -[](https://godoc.org/github.com/gorilla/websocket) -[](https://circleci.com/gh/gorilla/websocket) - -Gorilla WebSocket is a [Go](http://golang.org/) implementation of the -[WebSocket](http://www.rfc-editor.org/rfc/rfc6455.txt) protocol. - - -### Documentation - -* [API Reference](https://pkg.go.dev/github.com/gorilla/websocket?tab=doc) -* [Chat example](https://github.com/gorilla/websocket/tree/master/examples/chat) -* [Command example](https://github.com/gorilla/websocket/tree/master/examples/command) -* [Client and server example](https://github.com/gorilla/websocket/tree/master/examples/echo) -* [File watch example](https://github.com/gorilla/websocket/tree/master/examples/filewatch) - -### Status - -The Gorilla WebSocket package provides a complete and tested implementation of -the [WebSocket](http://www.rfc-editor.org/rfc/rfc6455.txt) protocol. The -package API is stable. - -### Installation - - go get github.com/gorilla/websocket - -### Protocol Compliance - -The Gorilla WebSocket package passes the server tests in the [Autobahn Test -Suite](https://github.com/crossbario/autobahn-testsuite) using the application in the [examples/autobahn -subdirectory](https://github.com/gorilla/websocket/tree/master/examples/autobahn). - diff --git a/vendor/github.com/gorilla/websocket/client.go b/vendor/github.com/gorilla/websocket/client.go deleted file mode 100644 index 04fdafee1..000000000 --- a/vendor/github.com/gorilla/websocket/client.go +++ /dev/null @@ -1,434 +0,0 @@ -// Copyright 2013 The Gorilla WebSocket Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package websocket - -import ( - "bytes" - "context" - "crypto/tls" - "errors" - "fmt" - "io" - "io/ioutil" - "net" - "net/http" - "net/http/httptrace" - "net/url" - "strings" - "time" -) - -// ErrBadHandshake is returned when the server response to opening handshake is -// invalid. -var ErrBadHandshake = errors.New("websocket: bad handshake") - -var errInvalidCompression = errors.New("websocket: invalid compression negotiation") - -// NewClient creates a new client connection using the given net connection. -// The URL u specifies the host and request URI. Use requestHeader to specify -// the origin (Origin), subprotocols (Sec-WebSocket-Protocol) and cookies -// (Cookie). Use the response.Header to get the selected subprotocol -// (Sec-WebSocket-Protocol) and cookies (Set-Cookie). -// -// If the WebSocket handshake fails, ErrBadHandshake is returned along with a -// non-nil *http.Response so that callers can handle redirects, authentication, -// etc. -// -// Deprecated: Use Dialer instead. -func NewClient(netConn net.Conn, u *url.URL, requestHeader http.Header, readBufSize, writeBufSize int) (c *Conn, response *http.Response, err error) { - d := Dialer{ - ReadBufferSize: readBufSize, - WriteBufferSize: writeBufSize, - NetDial: func(net, addr string) (net.Conn, error) { - return netConn, nil - }, - } - return d.Dial(u.String(), requestHeader) -} - -// A Dialer contains options for connecting to WebSocket server. -// -// It is safe to call Dialer's methods concurrently. -type Dialer struct { - // NetDial specifies the dial function for creating TCP connections. If - // NetDial is nil, net.Dial is used. - NetDial func(network, addr string) (net.Conn, error) - - // NetDialContext specifies the dial function for creating TCP connections. If - // NetDialContext is nil, NetDial is used. - NetDialContext func(ctx context.Context, network, addr string) (net.Conn, error) - - // NetDialTLSContext specifies the dial function for creating TLS/TCP connections. If - // NetDialTLSContext is nil, NetDialContext is used. - // If NetDialTLSContext is set, Dial assumes the TLS handshake is done there and - // TLSClientConfig is ignored. - NetDialTLSContext func(ctx context.Context, network, addr string) (net.Conn, error) - - // Proxy specifies a function to return a proxy for a given - // Request. If the function returns a non-nil error, the - // request is aborted with the provided error. - // If Proxy is nil or returns a nil *URL, no proxy is used. - Proxy func(*http.Request) (*url.URL, error) - - // TLSClientConfig specifies the TLS configuration to use with tls.Client. - // If nil, the default configuration is used. - // If either NetDialTLS or NetDialTLSContext are set, Dial assumes the TLS handshake - // is done there and TLSClientConfig is ignored. - TLSClientConfig *tls.Config - - // HandshakeTimeout specifies the duration for the handshake to complete. - HandshakeTimeout time.Duration - - // ReadBufferSize and WriteBufferSize specify I/O buffer sizes in bytes. If a buffer - // size is zero, then a useful default size is used. The I/O buffer sizes - // do not limit the size of the messages that can be sent or received. - ReadBufferSize, WriteBufferSize int - - // WriteBufferPool is a pool of buffers for write operations. If the value - // is not set, then write buffers are allocated to the connection for the - // lifetime of the connection. - // - // A pool is most useful when the application has a modest volume of writes - // across a large number of connections. - // - // Applications should use a single pool for each unique value of - // WriteBufferSize. - WriteBufferPool BufferPool - - // Subprotocols specifies the client's requested subprotocols. - Subprotocols []string - - // EnableCompression specifies if the client should attempt to negotiate - // per message compression (RFC 7692). Setting this value to true does not - // guarantee that compression will be supported. Currently only "no context - // takeover" modes are supported. - EnableCompression bool - - // Jar specifies the cookie jar. - // If Jar is nil, cookies are not sent in requests and ignored - // in responses. - Jar http.CookieJar -} - -// Dial creates a new client connection by calling DialContext with a background context. -func (d *Dialer) Dial(urlStr string, requestHeader http.Header) (*Conn, *http.Response, error) { - return d.DialContext(context.Background(), urlStr, requestHeader) -} - -var errMalformedURL = errors.New("malformed ws or wss URL") - -func hostPortNoPort(u *url.URL) (hostPort, hostNoPort string) { - hostPort = u.Host - hostNoPort = u.Host - if i := strings.LastIndex(u.Host, ":"); i > strings.LastIndex(u.Host, "]") { - hostNoPort = hostNoPort[:i] - } else { - switch u.Scheme { - case "wss": - hostPort += ":443" - case "https": - hostPort += ":443" - default: - hostPort += ":80" - } - } - return hostPort, hostNoPort -} - -// DefaultDialer is a dialer with all fields set to the default values. -var DefaultDialer = &Dialer{ - Proxy: http.ProxyFromEnvironment, - HandshakeTimeout: 45 * time.Second, -} - -// nilDialer is dialer to use when receiver is nil. -var nilDialer = *DefaultDialer - -// DialContext creates a new client connection. Use requestHeader to specify the -// origin (Origin), subprotocols (Sec-WebSocket-Protocol) and cookies (Cookie). -// Use the response.Header to get the selected subprotocol -// (Sec-WebSocket-Protocol) and cookies (Set-Cookie). -// -// The context will be used in the request and in the Dialer. -// -// If the WebSocket handshake fails, ErrBadHandshake is returned along with a -// non-nil *http.Response so that callers can handle redirects, authentication, -// etcetera. The response body may not contain the entire response and does not -// need to be closed by the application. -func (d *Dialer) DialContext(ctx context.Context, urlStr string, requestHeader http.Header) (*Conn, *http.Response, error) { - if d == nil { - d = &nilDialer - } - - challengeKey, err := generateChallengeKey() - if err != nil { - return nil, nil, err - } - - u, err := url.Parse(urlStr) - if err != nil { - return nil, nil, err - } - - switch u.Scheme { - case "ws": - u.Scheme = "http" - case "wss": - u.Scheme = "https" - default: - return nil, nil, errMalformedURL - } - - if u.User != nil { - // User name and password are not allowed in websocket URIs. - return nil, nil, errMalformedURL - } - - req := &http.Request{ - Method: http.MethodGet, - URL: u, - Proto: "HTTP/1.1", - ProtoMajor: 1, - ProtoMinor: 1, - Header: make(http.Header), - Host: u.Host, - } - req = req.WithContext(ctx) - - // Set the cookies present in the cookie jar of the dialer - if d.Jar != nil { - for _, cookie := range d.Jar.Cookies(u) { - req.AddCookie(cookie) - } - } - - // Set the request headers using the capitalization for names and values in - // RFC examples. Although the capitalization shouldn't matter, there are - // servers that depend on it. The Header.Set method is not used because the - // method canonicalizes the header names. - req.Header["Upgrade"] = []string{"websocket"} - req.Header["Connection"] = []string{"Upgrade"} - req.Header["Sec-WebSocket-Key"] = []string{challengeKey} - req.Header["Sec-WebSocket-Version"] = []string{"13"} - if len(d.Subprotocols) > 0 { - req.Header["Sec-WebSocket-Protocol"] = []string{strings.Join(d.Subprotocols, ", ")} - } - for k, vs := range requestHeader { - switch { - case k == "Host": - if len(vs) > 0 { - req.Host = vs[0] - } - case k == "Upgrade" || - k == "Connection" || - k == "Sec-Websocket-Key" || - k == "Sec-Websocket-Version" || - k == "Sec-Websocket-Extensions" || - (k == "Sec-Websocket-Protocol" && len(d.Subprotocols) > 0): - return nil, nil, errors.New("websocket: duplicate header not allowed: " + k) - case k == "Sec-Websocket-Protocol": - req.Header["Sec-WebSocket-Protocol"] = vs - default: - req.Header[k] = vs - } - } - - if d.EnableCompression { - req.Header["Sec-WebSocket-Extensions"] = []string{"permessage-deflate; server_no_context_takeover; client_no_context_takeover"} - } - - if d.HandshakeTimeout != 0 { - var cancel func() - ctx, cancel = context.WithTimeout(ctx, d.HandshakeTimeout) - defer cancel() - } - - // Get network dial function. - var netDial func(network, add string) (net.Conn, error) - - switch u.Scheme { - case "http": - if d.NetDialContext != nil { - netDial = func(network, addr string) (net.Conn, error) { - return d.NetDialContext(ctx, network, addr) - } - } else if d.NetDial != nil { - netDial = d.NetDial - } - case "https": - if d.NetDialTLSContext != nil { - netDial = func(network, addr string) (net.Conn, error) { - return d.NetDialTLSContext(ctx, network, addr) - } - } else if d.NetDialContext != nil { - netDial = func(network, addr string) (net.Conn, error) { - return d.NetDialContext(ctx, network, addr) - } - } else if d.NetDial != nil { - netDial = d.NetDial - } - default: - return nil, nil, errMalformedURL - } - - if netDial == nil { - netDialer := &net.Dialer{} - netDial = func(network, addr string) (net.Conn, error) { - return netDialer.DialContext(ctx, network, addr) - } - } - - // If needed, wrap the dial function to set the connection deadline. - if deadline, ok := ctx.Deadline(); ok { - forwardDial := netDial - netDial = func(network, addr string) (net.Conn, error) { - c, err := forwardDial(network, addr) - if err != nil { - return nil, err - } - err = c.SetDeadline(deadline) - if err != nil { - c.Close() - return nil, err - } - return c, nil - } - } - - // If needed, wrap the dial function to connect through a proxy. - if d.Proxy != nil { - proxyURL, err := d.Proxy(req) - if err != nil { - return nil, nil, err - } - if proxyURL != nil { - dialer, err := proxy_FromURL(proxyURL, netDialerFunc(netDial)) - if err != nil { - return nil, nil, err - } - netDial = dialer.Dial - } - } - - hostPort, hostNoPort := hostPortNoPort(u) - trace := httptrace.ContextClientTrace(ctx) - if trace != nil && trace.GetConn != nil { - trace.GetConn(hostPort) - } - - netConn, err := netDial("tcp", hostPort) - if err != nil { - return nil, nil, err - } - if trace != nil && trace.GotConn != nil { - trace.GotConn(httptrace.GotConnInfo{ - Conn: netConn, - }) - } - - defer func() { - if netConn != nil { - netConn.Close() - } - }() - - if u.Scheme == "https" && d.NetDialTLSContext == nil { - // If NetDialTLSContext is set, assume that the TLS handshake has already been done - - cfg := cloneTLSConfig(d.TLSClientConfig) - if cfg.ServerName == "" { - cfg.ServerName = hostNoPort - } - tlsConn := tls.Client(netConn, cfg) - netConn = tlsConn - - if trace != nil && trace.TLSHandshakeStart != nil { - trace.TLSHandshakeStart() - } - err := doHandshake(ctx, tlsConn, cfg) - if trace != nil && trace.TLSHandshakeDone != nil { - trace.TLSHandshakeDone(tlsConn.ConnectionState(), err) - } - - if err != nil { - return nil, nil, err - } - } - - conn := newConn(netConn, false, d.ReadBufferSize, d.WriteBufferSize, d.WriteBufferPool, nil, nil) - - if err := req.Write(netConn); err != nil { - return nil, nil, err - } - - if trace != nil && trace.GotFirstResponseByte != nil { - if peek, err := conn.br.Peek(1); err == nil && len(peek) == 1 { - trace.GotFirstResponseByte() - } - } - - resp, err := http.ReadResponse(conn.br, req) - if err != nil { - if d.TLSClientConfig != nil { - for _, proto := range d.TLSClientConfig.NextProtos { - if proto != "http/1.1" { - return nil, nil, fmt.Errorf( - "websocket: protocol %q was given but is not supported;"+ - "sharing tls.Config with net/http Transport can cause this error: %w", - proto, err, - ) - } - } - } - return nil, nil, err - } - - if d.Jar != nil { - if rc := resp.Cookies(); len(rc) > 0 { - d.Jar.SetCookies(u, rc) - } - } - - if resp.StatusCode != 101 || - !tokenListContainsValue(resp.Header, "Upgrade", "websocket") || - !tokenListContainsValue(resp.Header, "Connection", "upgrade") || - resp.Header.Get("Sec-Websocket-Accept") != computeAcceptKey(challengeKey) { - // Before closing the network connection on return from this - // function, slurp up some of the response to aid application - // debugging. - buf := make([]byte, 1024) - n, _ := io.ReadFull(resp.Body, buf) - resp.Body = ioutil.NopCloser(bytes.NewReader(buf[:n])) - return nil, resp, ErrBadHandshake - } - - for _, ext := range parseExtensions(resp.Header) { - if ext[""] != "permessage-deflate" { - continue - } - _, snct := ext["server_no_context_takeover"] - _, cnct := ext["client_no_context_takeover"] - if !snct || !cnct { - return nil, resp, errInvalidCompression - } - conn.newCompressionWriter = compressNoContextTakeover - conn.newDecompressionReader = decompressNoContextTakeover - break - } - - resp.Body = ioutil.NopCloser(bytes.NewReader([]byte{})) - conn.subprotocol = resp.Header.Get("Sec-Websocket-Protocol") - - netConn.SetDeadline(time.Time{}) - netConn = nil // to avoid close in defer. - return conn, resp, nil -} - -func cloneTLSConfig(cfg *tls.Config) *tls.Config { - if cfg == nil { - return &tls.Config{} - } - return cfg.Clone() -} diff --git a/vendor/github.com/gorilla/websocket/compression.go b/vendor/github.com/gorilla/websocket/compression.go deleted file mode 100644 index 813ffb1e8..000000000 --- a/vendor/github.com/gorilla/websocket/compression.go +++ /dev/null @@ -1,148 +0,0 @@ -// Copyright 2017 The Gorilla WebSocket Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package websocket - -import ( - "compress/flate" - "errors" - "io" - "strings" - "sync" -) - -const ( - minCompressionLevel = -2 // flate.HuffmanOnly not defined in Go < 1.6 - maxCompressionLevel = flate.BestCompression - defaultCompressionLevel = 1 -) - -var ( - flateWriterPools [maxCompressionLevel - minCompressionLevel + 1]sync.Pool - flateReaderPool = sync.Pool{New: func() interface{} { - return flate.NewReader(nil) - }} -) - -func decompressNoContextTakeover(r io.Reader) io.ReadCloser { - const tail = - // Add four bytes as specified in RFC - "\x00\x00\xff\xff" + - // Add final block to squelch unexpected EOF error from flate reader. - "\x01\x00\x00\xff\xff" - - fr, _ := flateReaderPool.Get().(io.ReadCloser) - fr.(flate.Resetter).Reset(io.MultiReader(r, strings.NewReader(tail)), nil) - return &flateReadWrapper{fr} -} - -func isValidCompressionLevel(level int) bool { - return minCompressionLevel <= level && level <= maxCompressionLevel -} - -func compressNoContextTakeover(w io.WriteCloser, level int) io.WriteCloser { - p := &flateWriterPools[level-minCompressionLevel] - tw := &truncWriter{w: w} - fw, _ := p.Get().(*flate.Writer) - if fw == nil { - fw, _ = flate.NewWriter(tw, level) - } else { - fw.Reset(tw) - } - return &flateWriteWrapper{fw: fw, tw: tw, p: p} -} - -// truncWriter is an io.Writer that writes all but the last four bytes of the -// stream to another io.Writer. -type truncWriter struct { - w io.WriteCloser - n int - p [4]byte -} - -func (w *truncWriter) Write(p []byte) (int, error) { - n := 0 - - // fill buffer first for simplicity. - if w.n < len(w.p) { - n = copy(w.p[w.n:], p) - p = p[n:] - w.n += n - if len(p) == 0 { - return n, nil - } - } - - m := len(p) - if m > len(w.p) { - m = len(w.p) - } - - if nn, err := w.w.Write(w.p[:m]); err != nil { - return n + nn, err - } - - copy(w.p[:], w.p[m:]) - copy(w.p[len(w.p)-m:], p[len(p)-m:]) - nn, err := w.w.Write(p[:len(p)-m]) - return n + nn, err -} - -type flateWriteWrapper struct { - fw *flate.Writer - tw *truncWriter - p *sync.Pool -} - -func (w *flateWriteWrapper) Write(p []byte) (int, error) { - if w.fw == nil { - return 0, errWriteClosed - } - return w.fw.Write(p) -} - -func (w *flateWriteWrapper) Close() error { - if w.fw == nil { - return errWriteClosed - } - err1 := w.fw.Flush() - w.p.Put(w.fw) - w.fw = nil - if w.tw.p != [4]byte{0, 0, 0xff, 0xff} { - return errors.New("websocket: internal error, unexpected bytes at end of flate stream") - } - err2 := w.tw.w.Close() - if err1 != nil { - return err1 - } - return err2 -} - -type flateReadWrapper struct { - fr io.ReadCloser -} - -func (r *flateReadWrapper) Read(p []byte) (int, error) { - if r.fr == nil { - return 0, io.ErrClosedPipe - } - n, err := r.fr.Read(p) - if err == io.EOF { - // Preemptively place the reader back in the pool. This helps with - // scenarios where the application does not call NextReader() soon after - // this final read. - r.Close() - } - return n, err -} - -func (r *flateReadWrapper) Close() error { - if r.fr == nil { - return io.ErrClosedPipe - } - err := r.fr.Close() - flateReaderPool.Put(r.fr) - r.fr = nil - return err -} diff --git a/vendor/github.com/gorilla/websocket/conn.go b/vendor/github.com/gorilla/websocket/conn.go deleted file mode 100644 index 5161ef81f..000000000 --- a/vendor/github.com/gorilla/websocket/conn.go +++ /dev/null @@ -1,1238 +0,0 @@ -// Copyright 2013 The Gorilla WebSocket Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package websocket - -import ( - "bufio" - "encoding/binary" - "errors" - "io" - "io/ioutil" - "math/rand" - "net" - "strconv" - "strings" - "sync" - "time" - "unicode/utf8" -) - -const ( - // Frame header byte 0 bits from Section 5.2 of RFC 6455 - finalBit = 1 << 7 - rsv1Bit = 1 << 6 - rsv2Bit = 1 << 5 - rsv3Bit = 1 << 4 - - // Frame header byte 1 bits from Section 5.2 of RFC 6455 - maskBit = 1 << 7 - - maxFrameHeaderSize = 2 + 8 + 4 // Fixed header + length + mask - maxControlFramePayloadSize = 125 - - writeWait = time.Second - - defaultReadBufferSize = 4096 - defaultWriteBufferSize = 4096 - - continuationFrame = 0 - noFrame = -1 -) - -// Close codes defined in RFC 6455, section 11.7. -const ( - CloseNormalClosure = 1000 - CloseGoingAway = 1001 - CloseProtocolError = 1002 - CloseUnsupportedData = 1003 - CloseNoStatusReceived = 1005 - CloseAbnormalClosure = 1006 - CloseInvalidFramePayloadData = 1007 - ClosePolicyViolation = 1008 - CloseMessageTooBig = 1009 - CloseMandatoryExtension = 1010 - CloseInternalServerErr = 1011 - CloseServiceRestart = 1012 - CloseTryAgainLater = 1013 - CloseTLSHandshake = 1015 -) - -// The message types are defined in RFC 6455, section 11.8. -const ( - // TextMessage denotes a text data message. The text message payload is - // interpreted as UTF-8 encoded text data. - TextMessage = 1 - - // BinaryMessage denotes a binary data message. - BinaryMessage = 2 - - // CloseMessage denotes a close control message. The optional message - // payload contains a numeric code and text. Use the FormatCloseMessage - // function to format a close message payload. - CloseMessage = 8 - - // PingMessage denotes a ping control message. The optional message payload - // is UTF-8 encoded text. - PingMessage = 9 - - // PongMessage denotes a pong control message. The optional message payload - // is UTF-8 encoded text. - PongMessage = 10 -) - -// ErrCloseSent is returned when the application writes a message to the -// connection after sending a close message. -var ErrCloseSent = errors.New("websocket: close sent") - -// ErrReadLimit is returned when reading a message that is larger than the -// read limit set for the connection. -var ErrReadLimit = errors.New("websocket: read limit exceeded") - -// netError satisfies the net Error interface. -type netError struct { - msg string - temporary bool - timeout bool -} - -func (e *netError) Error() string { return e.msg } -func (e *netError) Temporary() bool { return e.temporary } -func (e *netError) Timeout() bool { return e.timeout } - -// CloseError represents a close message. -type CloseError struct { - // Code is defined in RFC 6455, section 11.7. - Code int - - // Text is the optional text payload. - Text string -} - -func (e *CloseError) Error() string { - s := []byte("websocket: close ") - s = strconv.AppendInt(s, int64(e.Code), 10) - switch e.Code { - case CloseNormalClosure: - s = append(s, " (normal)"...) - case CloseGoingAway: - s = append(s, " (going away)"...) - case CloseProtocolError: - s = append(s, " (protocol error)"...) - case CloseUnsupportedData: - s = append(s, " (unsupported data)"...) - case CloseNoStatusReceived: - s = append(s, " (no status)"...) - case CloseAbnormalClosure: - s = append(s, " (abnormal closure)"...) - case CloseInvalidFramePayloadData: - s = append(s, " (invalid payload data)"...) - case ClosePolicyViolation: - s = append(s, " (policy violation)"...) - case CloseMessageTooBig: - s = append(s, " (message too big)"...) - case CloseMandatoryExtension: - s = append(s, " (mandatory extension missing)"...) - case CloseInternalServerErr: - s = append(s, " (internal server error)"...) - case CloseTLSHandshake: - s = append(s, " (TLS handshake error)"...) - } - if e.Text != "" { - s = append(s, ": "...) - s = append(s, e.Text...) - } - return string(s) -} - -// IsCloseError returns boolean indicating whether the error is a *CloseError -// with one of the specified codes. -func IsCloseError(err error, codes ...int) bool { - if e, ok := err.(*CloseError); ok { - for _, code := range codes { - if e.Code == code { - return true - } - } - } - return false -} - -// IsUnexpectedCloseError returns boolean indicating whether the error is a -// *CloseError with a code not in the list of expected codes. -func IsUnexpectedCloseError(err error, expectedCodes ...int) bool { - if e, ok := err.(*CloseError); ok { - for _, code := range expectedCodes { - if e.Code == code { - return false - } - } - return true - } - return false -} - -var ( - errWriteTimeout = &netError{msg: "websocket: write timeout", timeout: true, temporary: true} - errUnexpectedEOF = &CloseError{Code: CloseAbnormalClosure, Text: io.ErrUnexpectedEOF.Error()} - errBadWriteOpCode = errors.New("websocket: bad write message type") - errWriteClosed = errors.New("websocket: write closed") - errInvalidControlFrame = errors.New("websocket: invalid control frame") -) - -func newMaskKey() [4]byte { - n := rand.Uint32() - return [4]byte{byte(n), byte(n >> 8), byte(n >> 16), byte(n >> 24)} -} - -func hideTempErr(err error) error { - if e, ok := err.(net.Error); ok && e.Temporary() { - err = &netError{msg: e.Error(), timeout: e.Timeout()} - } - return err -} - -func isControl(frameType int) bool { - return frameType == CloseMessage || frameType == PingMessage || frameType == PongMessage -} - -func isData(frameType int) bool { - return frameType == TextMessage || frameType == BinaryMessage -} - -var validReceivedCloseCodes = map[int]bool{ - // see http://www.iana.org/assignments/websocket/websocket.xhtml#close-code-number - - CloseNormalClosure: true, - CloseGoingAway: true, - CloseProtocolError: true, - CloseUnsupportedData: true, - CloseNoStatusReceived: false, - CloseAbnormalClosure: false, - CloseInvalidFramePayloadData: true, - ClosePolicyViolation: true, - CloseMessageTooBig: true, - CloseMandatoryExtension: true, - CloseInternalServerErr: true, - CloseServiceRestart: true, - CloseTryAgainLater: true, - CloseTLSHandshake: false, -} - -func isValidReceivedCloseCode(code int) bool { - return validReceivedCloseCodes[code] || (code >= 3000 && code <= 4999) -} - -// BufferPool represents a pool of buffers. The *sync.Pool type satisfies this -// interface. The type of the value stored in a pool is not specified. -type BufferPool interface { - // Get gets a value from the pool or returns nil if the pool is empty. - Get() interface{} - // Put adds a value to the pool. - Put(interface{}) -} - -// writePoolData is the type added to the write buffer pool. This wrapper is -// used to prevent applications from peeking at and depending on the values -// added to the pool. -type writePoolData struct{ buf []byte } - -// The Conn type represents a WebSocket connection. -type Conn struct { - conn net.Conn - isServer bool - subprotocol string - - // Write fields - mu chan struct{} // used as mutex to protect write to conn - writeBuf []byte // frame is constructed in this buffer. - writePool BufferPool - writeBufSize int - writeDeadline time.Time - writer io.WriteCloser // the current writer returned to the application - isWriting bool // for best-effort concurrent write detection - - writeErrMu sync.Mutex - writeErr error - - enableWriteCompression bool - compressionLevel int - newCompressionWriter func(io.WriteCloser, int) io.WriteCloser - - // Read fields - reader io.ReadCloser // the current reader returned to the application - readErr error - br *bufio.Reader - // bytes remaining in current frame. - // set setReadRemaining to safely update this value and prevent overflow - readRemaining int64 - readFinal bool // true the current message has more frames. - readLength int64 // Message size. - readLimit int64 // Maximum message size. - readMaskPos int - readMaskKey [4]byte - handlePong func(string) error - handlePing func(string) error - handleClose func(int, string) error - readErrCount int - messageReader *messageReader // the current low-level reader - - readDecompress bool // whether last read frame had RSV1 set - newDecompressionReader func(io.Reader) io.ReadCloser -} - -func newConn(conn net.Conn, isServer bool, readBufferSize, writeBufferSize int, writeBufferPool BufferPool, br *bufio.Reader, writeBuf []byte) *Conn { - - if br == nil { - if readBufferSize == 0 { - readBufferSize = defaultReadBufferSize - } else if readBufferSize < maxControlFramePayloadSize { - // must be large enough for control frame - readBufferSize = maxControlFramePayloadSize - } - br = bufio.NewReaderSize(conn, readBufferSize) - } - - if writeBufferSize <= 0 { - writeBufferSize = defaultWriteBufferSize - } - writeBufferSize += maxFrameHeaderSize - - if writeBuf == nil && writeBufferPool == nil { - writeBuf = make([]byte, writeBufferSize) - } - - mu := make(chan struct{}, 1) - mu <- struct{}{} - c := &Conn{ - isServer: isServer, - br: br, - conn: conn, - mu: mu, - readFinal: true, - writeBuf: writeBuf, - writePool: writeBufferPool, - writeBufSize: writeBufferSize, - enableWriteCompression: true, - compressionLevel: defaultCompressionLevel, - } - c.SetCloseHandler(nil) - c.SetPingHandler(nil) - c.SetPongHandler(nil) - return c -} - -// setReadRemaining tracks the number of bytes remaining on the connection. If n -// overflows, an ErrReadLimit is returned. -func (c *Conn) setReadRemaining(n int64) error { - if n < 0 { - return ErrReadLimit - } - - c.readRemaining = n - return nil -} - -// Subprotocol returns the negotiated protocol for the connection. -func (c *Conn) Subprotocol() string { - return c.subprotocol -} - -// Close closes the underlying network connection without sending or waiting -// for a close message. -func (c *Conn) Close() error { - return c.conn.Close() -} - -// LocalAddr returns the local network address. -func (c *Conn) LocalAddr() net.Addr { - return c.conn.LocalAddr() -} - -// RemoteAddr returns the remote network address. -func (c *Conn) RemoteAddr() net.Addr { - return c.conn.RemoteAddr() -} - -// Write methods - -func (c *Conn) writeFatal(err error) error { - err = hideTempErr(err) - c.writeErrMu.Lock() - if c.writeErr == nil { - c.writeErr = err - } - c.writeErrMu.Unlock() - return err -} - -func (c *Conn) read(n int) ([]byte, error) { - p, err := c.br.Peek(n) - if err == io.EOF { - err = errUnexpectedEOF - } - c.br.Discard(len(p)) - return p, err -} - -func (c *Conn) write(frameType int, deadline time.Time, buf0, buf1 []byte) error { - <-c.mu - defer func() { c.mu <- struct{}{} }() - - c.writeErrMu.Lock() - err := c.writeErr - c.writeErrMu.Unlock() - if err != nil { - return err - } - - c.conn.SetWriteDeadline(deadline) - if len(buf1) == 0 { - _, err = c.conn.Write(buf0) - } else { - err = c.writeBufs(buf0, buf1) - } - if err != nil { - return c.writeFatal(err) - } - if frameType == CloseMessage { - c.writeFatal(ErrCloseSent) - } - return nil -} - -func (c *Conn) writeBufs(bufs ...[]byte) error { - b := net.Buffers(bufs) - _, err := b.WriteTo(c.conn) - return err -} - -// WriteControl writes a control message with the given deadline. The allowed -// message types are CloseMessage, PingMessage and PongMessage. -func (c *Conn) WriteControl(messageType int, data []byte, deadline time.Time) error { - if !isControl(messageType) { - return errBadWriteOpCode - } - if len(data) > maxControlFramePayloadSize { - return errInvalidControlFrame - } - - b0 := byte(messageType) | finalBit - b1 := byte(len(data)) - if !c.isServer { - b1 |= maskBit - } - - buf := make([]byte, 0, maxFrameHeaderSize+maxControlFramePayloadSize) - buf = append(buf, b0, b1) - - if c.isServer { - buf = append(buf, data...) - } else { - key := newMaskKey() - buf = append(buf, key[:]...) - buf = append(buf, data...) - maskBytes(key, 0, buf[6:]) - } - - d := 1000 * time.Hour - if !deadline.IsZero() { - d = deadline.Sub(time.Now()) - if d < 0 { - return errWriteTimeout - } - } - - timer := time.NewTimer(d) - select { - case <-c.mu: - timer.Stop() - case <-timer.C: - return errWriteTimeout - } - defer func() { c.mu <- struct{}{} }() - - c.writeErrMu.Lock() - err := c.writeErr - c.writeErrMu.Unlock() - if err != nil { - return err - } - - c.conn.SetWriteDeadline(deadline) - _, err = c.conn.Write(buf) - if err != nil { - return c.writeFatal(err) - } - if messageType == CloseMessage { - c.writeFatal(ErrCloseSent) - } - return err -} - -// beginMessage prepares a connection and message writer for a new message. -func (c *Conn) beginMessage(mw *messageWriter, messageType int) error { - // Close previous writer if not already closed by the application. It's - // probably better to return an error in this situation, but we cannot - // change this without breaking existing applications. - if c.writer != nil { - c.writer.Close() - c.writer = nil - } - - if !isControl(messageType) && !isData(messageType) { - return errBadWriteOpCode - } - - c.writeErrMu.Lock() - err := c.writeErr - c.writeErrMu.Unlock() - if err != nil { - return err - } - - mw.c = c - mw.frameType = messageType - mw.pos = maxFrameHeaderSize - - if c.writeBuf == nil { - wpd, ok := c.writePool.Get().(writePoolData) - if ok { - c.writeBuf = wpd.buf - } else { - c.writeBuf = make([]byte, c.writeBufSize) - } - } - return nil -} - -// NextWriter returns a writer for the next message to send. The writer's Close -// method flushes the complete message to the network. -// -// There can be at most one open writer on a connection. NextWriter closes the -// previous writer if the application has not already done so. -// -// All message types (TextMessage, BinaryMessage, CloseMessage, PingMessage and -// PongMessage) are supported. -func (c *Conn) NextWriter(messageType int) (io.WriteCloser, error) { - var mw messageWriter - if err := c.beginMessage(&mw, messageType); err != nil { - return nil, err - } - c.writer = &mw - if c.newCompressionWriter != nil && c.enableWriteCompression && isData(messageType) { - w := c.newCompressionWriter(c.writer, c.compressionLevel) - mw.compress = true - c.writer = w - } - return c.writer, nil -} - -type messageWriter struct { - c *Conn - compress bool // whether next call to flushFrame should set RSV1 - pos int // end of data in writeBuf. - frameType int // type of the current frame. - err error -} - -func (w *messageWriter) endMessage(err error) error { - if w.err != nil { - return err - } - c := w.c - w.err = err - c.writer = nil - if c.writePool != nil { - c.writePool.Put(writePoolData{buf: c.writeBuf}) - c.writeBuf = nil - } - return err -} - -// flushFrame writes buffered data and extra as a frame to the network. The -// final argument indicates that this is the last frame in the message. -func (w *messageWriter) flushFrame(final bool, extra []byte) error { - c := w.c - length := w.pos - maxFrameHeaderSize + len(extra) - - // Check for invalid control frames. - if isControl(w.frameType) && - (!final || length > maxControlFramePayloadSize) { - return w.endMessage(errInvalidControlFrame) - } - - b0 := byte(w.frameType) - if final { - b0 |= finalBit - } - if w.compress { - b0 |= rsv1Bit - } - w.compress = false - - b1 := byte(0) - if !c.isServer { - b1 |= maskBit - } - - // Assume that the frame starts at beginning of c.writeBuf. - framePos := 0 - if c.isServer { - // Adjust up if mask not included in the header. - framePos = 4 - } - - switch { - case length >= 65536: - c.writeBuf[framePos] = b0 - c.writeBuf[framePos+1] = b1 | 127 - binary.BigEndian.PutUint64(c.writeBuf[framePos+2:], uint64(length)) - case length > 125: - framePos += 6 - c.writeBuf[framePos] = b0 - c.writeBuf[framePos+1] = b1 | 126 - binary.BigEndian.PutUint16(c.writeBuf[framePos+2:], uint16(length)) - default: - framePos += 8 - c.writeBuf[framePos] = b0 - c.writeBuf[framePos+1] = b1 | byte(length) - } - - if !c.isServer { - key := newMaskKey() - copy(c.writeBuf[maxFrameHeaderSize-4:], key[:]) - maskBytes(key, 0, c.writeBuf[maxFrameHeaderSize:w.pos]) - if len(extra) > 0 { - return w.endMessage(c.writeFatal(errors.New("websocket: internal error, extra used in client mode"))) - } - } - - // Write the buffers to the connection with best-effort detection of - // concurrent writes. See the concurrency section in the package - // documentation for more info. - - if c.isWriting { - panic("concurrent write to websocket connection") - } - c.isWriting = true - - err := c.write(w.frameType, c.writeDeadline, c.writeBuf[framePos:w.pos], extra) - - if !c.isWriting { - panic("concurrent write to websocket connection") - } - c.isWriting = false - - if err != nil { - return w.endMessage(err) - } - - if final { - w.endMessage(errWriteClosed) - return nil - } - - // Setup for next frame. - w.pos = maxFrameHeaderSize - w.frameType = continuationFrame - return nil -} - -func (w *messageWriter) ncopy(max int) (int, error) { - n := len(w.c.writeBuf) - w.pos - if n <= 0 { - if err := w.flushFrame(false, nil); err != nil { - return 0, err - } - n = len(w.c.writeBuf) - w.pos - } - if n > max { - n = max - } - return n, nil -} - -func (w *messageWriter) Write(p []byte) (int, error) { - if w.err != nil { - return 0, w.err - } - - if len(p) > 2*len(w.c.writeBuf) && w.c.isServer { - // Don't buffer large messages. - err := w.flushFrame(false, p) - if err != nil { - return 0, err - } - return len(p), nil - } - - nn := len(p) - for len(p) > 0 { - n, err := w.ncopy(len(p)) - if err != nil { - return 0, err - } - copy(w.c.writeBuf[w.pos:], p[:n]) - w.pos += n - p = p[n:] - } - return nn, nil -} - -func (w *messageWriter) WriteString(p string) (int, error) { - if w.err != nil { - return 0, w.err - } - - nn := len(p) - for len(p) > 0 { - n, err := w.ncopy(len(p)) - if err != nil { - return 0, err - } - copy(w.c.writeBuf[w.pos:], p[:n]) - w.pos += n - p = p[n:] - } - return nn, nil -} - -func (w *messageWriter) ReadFrom(r io.Reader) (nn int64, err error) { - if w.err != nil { - return 0, w.err - } - for { - if w.pos == len(w.c.writeBuf) { - err = w.flushFrame(false, nil) - if err != nil { - break - } - } - var n int - n, err = r.Read(w.c.writeBuf[w.pos:]) - w.pos += n - nn += int64(n) - if err != nil { - if err == io.EOF { - err = nil - } - break - } - } - return nn, err -} - -func (w *messageWriter) Close() error { - if w.err != nil { - return w.err - } - return w.flushFrame(true, nil) -} - -// WritePreparedMessage writes prepared message into connection. -func (c *Conn) WritePreparedMessage(pm *PreparedMessage) error { - frameType, frameData, err := pm.frame(prepareKey{ - isServer: c.isServer, - compress: c.newCompressionWriter != nil && c.enableWriteCompression && isData(pm.messageType), - compressionLevel: c.compressionLevel, - }) - if err != nil { - return err - } - if c.isWriting { - panic("concurrent write to websocket connection") - } - c.isWriting = true - err = c.write(frameType, c.writeDeadline, frameData, nil) - if !c.isWriting { - panic("concurrent write to websocket connection") - } - c.isWriting = false - return err -} - -// WriteMessage is a helper method for getting a writer using NextWriter, -// writing the message and closing the writer. -func (c *Conn) WriteMessage(messageType int, data []byte) error { - - if c.isServer && (c.newCompressionWriter == nil || !c.enableWriteCompression) { - // Fast path with no allocations and single frame. - - var mw messageWriter - if err := c.beginMessage(&mw, messageType); err != nil { - return err - } - n := copy(c.writeBuf[mw.pos:], data) - mw.pos += n - data = data[n:] - return mw.flushFrame(true, data) - } - - w, err := c.NextWriter(messageType) - if err != nil { - return err - } - if _, err = w.Write(data); err != nil { - return err - } - return w.Close() -} - -// SetWriteDeadline sets the write deadline on the underlying network -// connection. After a write has timed out, the websocket state is corrupt and -// all future writes will return an error. A zero value for t means writes will -// not time out. -func (c *Conn) SetWriteDeadline(t time.Time) error { - c.writeDeadline = t - return nil -} - -// Read methods - -func (c *Conn) advanceFrame() (int, error) { - // 1. Skip remainder of previous frame. - - if c.readRemaining > 0 { - if _, err := io.CopyN(ioutil.Discard, c.br, c.readRemaining); err != nil { - return noFrame, err - } - } - - // 2. Read and parse first two bytes of frame header. - // To aid debugging, collect and report all errors in the first two bytes - // of the header. - - var errors []string - - p, err := c.read(2) - if err != nil { - return noFrame, err - } - - frameType := int(p[0] & 0xf) - final := p[0]&finalBit != 0 - rsv1 := p[0]&rsv1Bit != 0 - rsv2 := p[0]&rsv2Bit != 0 - rsv3 := p[0]&rsv3Bit != 0 - mask := p[1]&maskBit != 0 - c.setReadRemaining(int64(p[1] & 0x7f)) - - c.readDecompress = false - if rsv1 { - if c.newDecompressionReader != nil { - c.readDecompress = true - } else { - errors = append(errors, "RSV1 set") - } - } - - if rsv2 { - errors = append(errors, "RSV2 set") - } - - if rsv3 { - errors = append(errors, "RSV3 set") - } - - switch frameType { - case CloseMessage, PingMessage, PongMessage: - if c.readRemaining > maxControlFramePayloadSize { - errors = append(errors, "len > 125 for control") - } - if !final { - errors = append(errors, "FIN not set on control") - } - case TextMessage, BinaryMessage: - if !c.readFinal { - errors = append(errors, "data before FIN") - } - c.readFinal = final - case continuationFrame: - if c.readFinal { - errors = append(errors, "continuation after FIN") - } - c.readFinal = final - default: - errors = append(errors, "bad opcode "+strconv.Itoa(frameType)) - } - - if mask != c.isServer { - errors = append(errors, "bad MASK") - } - - if len(errors) > 0 { - return noFrame, c.handleProtocolError(strings.Join(errors, ", ")) - } - - // 3. Read and parse frame length as per - // https://tools.ietf.org/html/rfc6455#section-5.2 - // - // The length of the "Payload data", in bytes: if 0-125, that is the payload - // length. - // - If 126, the following 2 bytes interpreted as a 16-bit unsigned - // integer are the payload length. - // - If 127, the following 8 bytes interpreted as - // a 64-bit unsigned integer (the most significant bit MUST be 0) are the - // payload length. Multibyte length quantities are expressed in network byte - // order. - - switch c.readRemaining { - case 126: - p, err := c.read(2) - if err != nil { - return noFrame, err - } - - if err := c.setReadRemaining(int64(binary.BigEndian.Uint16(p))); err != nil { - return noFrame, err - } - case 127: - p, err := c.read(8) - if err != nil { - return noFrame, err - } - - if err := c.setReadRemaining(int64(binary.BigEndian.Uint64(p))); err != nil { - return noFrame, err - } - } - - // 4. Handle frame masking. - - if mask { - c.readMaskPos = 0 - p, err := c.read(len(c.readMaskKey)) - if err != nil { - return noFrame, err - } - copy(c.readMaskKey[:], p) - } - - // 5. For text and binary messages, enforce read limit and return. - - if frameType == continuationFrame || frameType == TextMessage || frameType == BinaryMessage { - - c.readLength += c.readRemaining - // Don't allow readLength to overflow in the presence of a large readRemaining - // counter. - if c.readLength < 0 { - return noFrame, ErrReadLimit - } - - if c.readLimit > 0 && c.readLength > c.readLimit { - c.WriteControl(CloseMessage, FormatCloseMessage(CloseMessageTooBig, ""), time.Now().Add(writeWait)) - return noFrame, ErrReadLimit - } - - return frameType, nil - } - - // 6. Read control frame payload. - - var payload []byte - if c.readRemaining > 0 { - payload, err = c.read(int(c.readRemaining)) - c.setReadRemaining(0) - if err != nil { - return noFrame, err - } - if c.isServer { - maskBytes(c.readMaskKey, 0, payload) - } - } - - // 7. Process control frame payload. - - switch frameType { - case PongMessage: - if err := c.handlePong(string(payload)); err != nil { - return noFrame, err - } - case PingMessage: - if err := c.handlePing(string(payload)); err != nil { - return noFrame, err - } - case CloseMessage: - closeCode := CloseNoStatusReceived - closeText := "" - if len(payload) >= 2 { - closeCode = int(binary.BigEndian.Uint16(payload)) - if !isValidReceivedCloseCode(closeCode) { - return noFrame, c.handleProtocolError("bad close code " + strconv.Itoa(closeCode)) - } - closeText = string(payload[2:]) - if !utf8.ValidString(closeText) { - return noFrame, c.handleProtocolError("invalid utf8 payload in close frame") - } - } - if err := c.handleClose(closeCode, closeText); err != nil { - return noFrame, err - } - return noFrame, &CloseError{Code: closeCode, Text: closeText} - } - - return frameType, nil -} - -func (c *Conn) handleProtocolError(message string) error { - data := FormatCloseMessage(CloseProtocolError, message) - if len(data) > maxControlFramePayloadSize { - data = data[:maxControlFramePayloadSize] - } - c.WriteControl(CloseMessage, data, time.Now().Add(writeWait)) - return errors.New("websocket: " + message) -} - -// NextReader returns the next data message received from the peer. The -// returned messageType is either TextMessage or BinaryMessage. -// -// There can be at most one open reader on a connection. NextReader discards -// the previous message if the application has not already consumed it. -// -// Applications must break out of the application's read loop when this method -// returns a non-nil error value. Errors returned from this method are -// permanent. Once this method returns a non-nil error, all subsequent calls to -// this method return the same error. -func (c *Conn) NextReader() (messageType int, r io.Reader, err error) { - // Close previous reader, only relevant for decompression. - if c.reader != nil { - c.reader.Close() - c.reader = nil - } - - c.messageReader = nil - c.readLength = 0 - - for c.readErr == nil { - frameType, err := c.advanceFrame() - if err != nil { - c.readErr = hideTempErr(err) - break - } - - if frameType == TextMessage || frameType == BinaryMessage { - c.messageReader = &messageReader{c} - c.reader = c.messageReader - if c.readDecompress { - c.reader = c.newDecompressionReader(c.reader) - } - return frameType, c.reader, nil - } - } - - // Applications that do handle the error returned from this method spin in - // tight loop on connection failure. To help application developers detect - // this error, panic on repeated reads to the failed connection. - c.readErrCount++ - if c.readErrCount >= 1000 { - panic("repeated read on failed websocket connection") - } - - return noFrame, nil, c.readErr -} - -type messageReader struct{ c *Conn } - -func (r *messageReader) Read(b []byte) (int, error) { - c := r.c - if c.messageReader != r { - return 0, io.EOF - } - - for c.readErr == nil { - - if c.readRemaining > 0 { - if int64(len(b)) > c.readRemaining { - b = b[:c.readRemaining] - } - n, err := c.br.Read(b) - c.readErr = hideTempErr(err) - if c.isServer { - c.readMaskPos = maskBytes(c.readMaskKey, c.readMaskPos, b[:n]) - } - rem := c.readRemaining - rem -= int64(n) - c.setReadRemaining(rem) - if c.readRemaining > 0 && c.readErr == io.EOF { - c.readErr = errUnexpectedEOF - } - return n, c.readErr - } - - if c.readFinal { - c.messageReader = nil - return 0, io.EOF - } - - frameType, err := c.advanceFrame() - switch { - case err != nil: - c.readErr = hideTempErr(err) - case frameType == TextMessage || frameType == BinaryMessage: - c.readErr = errors.New("websocket: internal error, unexpected text or binary in Reader") - } - } - - err := c.readErr - if err == io.EOF && c.messageReader == r { - err = errUnexpectedEOF - } - return 0, err -} - -func (r *messageReader) Close() error { - return nil -} - -// ReadMessage is a helper method for getting a reader using NextReader and -// reading from that reader to a buffer. -func (c *Conn) ReadMessage() (messageType int, p []byte, err error) { - var r io.Reader - messageType, r, err = c.NextReader() - if err != nil { - return messageType, nil, err - } - p, err = ioutil.ReadAll(r) - return messageType, p, err -} - -// SetReadDeadline sets the read deadline on the underlying network connection. -// After a read has timed out, the websocket connection state is corrupt and -// all future reads will return an error. A zero value for t means reads will -// not time out. -func (c *Conn) SetReadDeadline(t time.Time) error { - return c.conn.SetReadDeadline(t) -} - -// SetReadLimit sets the maximum size in bytes for a message read from the peer. If a -// message exceeds the limit, the connection sends a close message to the peer -// and returns ErrReadLimit to the application. -func (c *Conn) SetReadLimit(limit int64) { - c.readLimit = limit -} - -// CloseHandler returns the current close handler -func (c *Conn) CloseHandler() func(code int, text string) error { - return c.handleClose -} - -// SetCloseHandler sets the handler for close messages received from the peer. -// The code argument to h is the received close code or CloseNoStatusReceived -// if the close message is empty. The default close handler sends a close -// message back to the peer. -// -// The handler function is called from the NextReader, ReadMessage and message -// reader Read methods. The application must read the connection to process -// close messages as described in the section on Control Messages above. -// -// The connection read methods return a CloseError when a close message is -// received. Most applications should handle close messages as part of their -// normal error handling. Applications should only set a close handler when the -// application must perform some action before sending a close message back to -// the peer. -func (c *Conn) SetCloseHandler(h func(code int, text string) error) { - if h == nil { - h = func(code int, text string) error { - message := FormatCloseMessage(code, "") - c.WriteControl(CloseMessage, message, time.Now().Add(writeWait)) - return nil - } - } - c.handleClose = h -} - -// PingHandler returns the current ping handler -func (c *Conn) PingHandler() func(appData string) error { - return c.handlePing -} - -// SetPingHandler sets the handler for ping messages received from the peer. -// The appData argument to h is the PING message application data. The default -// ping handler sends a pong to the peer. -// -// The handler function is called from the NextReader, ReadMessage and message -// reader Read methods. The application must read the connection to process -// ping messages as described in the section on Control Messages above. -func (c *Conn) SetPingHandler(h func(appData string) error) { - if h == nil { - h = func(message string) error { - err := c.WriteControl(PongMessage, []byte(message), time.Now().Add(writeWait)) - if err == ErrCloseSent { - return nil - } else if e, ok := err.(net.Error); ok && e.Temporary() { - return nil - } - return err - } - } - c.handlePing = h -} - -// PongHandler returns the current pong handler -func (c *Conn) PongHandler() func(appData string) error { - return c.handlePong -} - -// SetPongHandler sets the handler for pong messages received from the peer. -// The appData argument to h is the PONG message application data. The default -// pong handler does nothing. -// -// The handler function is called from the NextReader, ReadMessage and message -// reader Read methods. The application must read the connection to process -// pong messages as described in the section on Control Messages above. -func (c *Conn) SetPongHandler(h func(appData string) error) { - if h == nil { - h = func(string) error { return nil } - } - c.handlePong = h -} - -// NetConn returns the underlying connection that is wrapped by c. -// Note that writing to or reading from this connection directly will corrupt the -// WebSocket connection. -func (c *Conn) NetConn() net.Conn { - return c.conn -} - -// UnderlyingConn returns the internal net.Conn. This can be used to further -// modifications to connection specific flags. -// Deprecated: Use the NetConn method. -func (c *Conn) UnderlyingConn() net.Conn { - return c.conn -} - -// EnableWriteCompression enables and disables write compression of -// subsequent text and binary messages. This function is a noop if -// compression was not negotiated with the peer. -func (c *Conn) EnableWriteCompression(enable bool) { - c.enableWriteCompression = enable -} - -// SetCompressionLevel sets the flate compression level for subsequent text and -// binary messages. This function is a noop if compression was not negotiated -// with the peer. See the compress/flate package for a description of -// compression levels. -func (c *Conn) SetCompressionLevel(level int) error { - if !isValidCompressionLevel(level) { - return errors.New("websocket: invalid compression level") - } - c.compressionLevel = level - return nil -} - -// FormatCloseMessage formats closeCode and text as a WebSocket close message. -// An empty message is returned for code CloseNoStatusReceived. -func FormatCloseMessage(closeCode int, text string) []byte { - if closeCode == CloseNoStatusReceived { - // Return empty message because it's illegal to send - // CloseNoStatusReceived. Return non-nil value in case application - // checks for nil. - return []byte{} - } - buf := make([]byte, 2+len(text)) - binary.BigEndian.PutUint16(buf, uint16(closeCode)) - copy(buf[2:], text) - return buf -} diff --git a/vendor/github.com/gorilla/websocket/doc.go b/vendor/github.com/gorilla/websocket/doc.go deleted file mode 100644 index 8db0cef95..000000000 --- a/vendor/github.com/gorilla/websocket/doc.go +++ /dev/null @@ -1,227 +0,0 @@ -// Copyright 2013 The Gorilla WebSocket Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package websocket implements the WebSocket protocol defined in RFC 6455. -// -// Overview -// -// The Conn type represents a WebSocket connection. A server application calls -// the Upgrader.Upgrade method from an HTTP request handler to get a *Conn: -// -// var upgrader = websocket.Upgrader{ -// ReadBufferSize: 1024, -// WriteBufferSize: 1024, -// } -// -// func handler(w http.ResponseWriter, r *http.Request) { -// conn, err := upgrader.Upgrade(w, r, nil) -// if err != nil { -// log.Println(err) -// return -// } -// ... Use conn to send and receive messages. -// } -// -// Call the connection's WriteMessage and ReadMessage methods to send and -// receive messages as a slice of bytes. This snippet of code shows how to echo -// messages using these methods: -// -// for { -// messageType, p, err := conn.ReadMessage() -// if err != nil { -// log.Println(err) -// return -// } -// if err := conn.WriteMessage(messageType, p); err != nil { -// log.Println(err) -// return -// } -// } -// -// In above snippet of code, p is a []byte and messageType is an int with value -// websocket.BinaryMessage or websocket.TextMessage. -// -// An application can also send and receive messages using the io.WriteCloser -// and io.Reader interfaces. To send a message, call the connection NextWriter -// method to get an io.WriteCloser, write the message to the writer and close -// the writer when done. To receive a message, call the connection NextReader -// method to get an io.Reader and read until io.EOF is returned. This snippet -// shows how to echo messages using the NextWriter and NextReader methods: -// -// for { -// messageType, r, err := conn.NextReader() -// if err != nil { -// return -// } -// w, err := conn.NextWriter(messageType) -// if err != nil { -// return err -// } -// if _, err := io.Copy(w, r); err != nil { -// return err -// } -// if err := w.Close(); err != nil { -// return err -// } -// } -// -// Data Messages -// -// The WebSocket protocol distinguishes between text and binary data messages. -// Text messages are interpreted as UTF-8 encoded text. The interpretation of -// binary messages is left to the application. -// -// This package uses the TextMessage and BinaryMessage integer constants to -// identify the two data message types. The ReadMessage and NextReader methods -// return the type of the received message. The messageType argument to the -// WriteMessage and NextWriter methods specifies the type of a sent message. -// -// It is the application's responsibility to ensure that text messages are -// valid UTF-8 encoded text. -// -// Control Messages -// -// The WebSocket protocol defines three types of control messages: close, ping -// and pong. Call the connection WriteControl, WriteMessage or NextWriter -// methods to send a control message to the peer. -// -// Connections handle received close messages by calling the handler function -// set with the SetCloseHandler method and by returning a *CloseError from the -// NextReader, ReadMessage or the message Read method. The default close -// handler sends a close message to the peer. -// -// Connections handle received ping messages by calling the handler function -// set with the SetPingHandler method. The default ping handler sends a pong -// message to the peer. -// -// Connections handle received pong messages by calling the handler function -// set with the SetPongHandler method. The default pong handler does nothing. -// If an application sends ping messages, then the application should set a -// pong handler to receive the corresponding pong. -// -// The control message handler functions are called from the NextReader, -// ReadMessage and message reader Read methods. The default close and ping -// handlers can block these methods for a short time when the handler writes to -// the connection. -// -// The application must read the connection to process close, ping and pong -// messages sent from the peer. If the application is not otherwise interested -// in messages from the peer, then the application should start a goroutine to -// read and discard messages from the peer. A simple example is: -// -// func readLoop(c *websocket.Conn) { -// for { -// if _, _, err := c.NextReader(); err != nil { -// c.Close() -// break -// } -// } -// } -// -// Concurrency -// -// Connections support one concurrent reader and one concurrent writer. -// -// Applications are responsible for ensuring that no more than one goroutine -// calls the write methods (NextWriter, SetWriteDeadline, WriteMessage, -// WriteJSON, EnableWriteCompression, SetCompressionLevel) concurrently and -// that no more than one goroutine calls the read methods (NextReader, -// SetReadDeadline, ReadMessage, ReadJSON, SetPongHandler, SetPingHandler) -// concurrently. -// -// The Close and WriteControl methods can be called concurrently with all other -// methods. -// -// Origin Considerations -// -// Web browsers allow Javascript applications to open a WebSocket connection to -// any host. It's up to the server to enforce an origin policy using the Origin -// request header sent by the browser. -// -// The Upgrader calls the function specified in the CheckOrigin field to check -// the origin. If the CheckOrigin function returns false, then the Upgrade -// method fails the WebSocket handshake with HTTP status 403. -// -// If the CheckOrigin field is nil, then the Upgrader uses a safe default: fail -// the handshake if the Origin request header is present and the Origin host is -// not equal to the Host request header. -// -// The deprecated package-level Upgrade function does not perform origin -// checking. The application is responsible for checking the Origin header -// before calling the Upgrade function. -// -// Buffers -// -// Connections buffer network input and output to reduce the number -// of system calls when reading or writing messages. -// -// Write buffers are also used for constructing WebSocket frames. See RFC 6455, -// Section 5 for a discussion of message framing. A WebSocket frame header is -// written to the network each time a write buffer is flushed to the network. -// Decreasing the size of the write buffer can increase the amount of framing -// overhead on the connection. -// -// The buffer sizes in bytes are specified by the ReadBufferSize and -// WriteBufferSize fields in the Dialer and Upgrader. The Dialer uses a default -// size of 4096 when a buffer size field is set to zero. The Upgrader reuses -// buffers created by the HTTP server when a buffer size field is set to zero. -// The HTTP server buffers have a size of 4096 at the time of this writing. -// -// The buffer sizes do not limit the size of a message that can be read or -// written by a connection. -// -// Buffers are held for the lifetime of the connection by default. If the -// Dialer or Upgrader WriteBufferPool field is set, then a connection holds the -// write buffer only when writing a message. -// -// Applications should tune the buffer sizes to balance memory use and -// performance. Increasing the buffer size uses more memory, but can reduce the -// number of system calls to read or write the network. In the case of writing, -// increasing the buffer size can reduce the number of frame headers written to -// the network. -// -// Some guidelines for setting buffer parameters are: -// -// Limit the buffer sizes to the maximum expected message size. Buffers larger -// than the largest message do not provide any benefit. -// -// Depending on the distribution of message sizes, setting the buffer size to -// a value less than the maximum expected message size can greatly reduce memory -// use with a small impact on performance. Here's an example: If 99% of the -// messages are smaller than 256 bytes and the maximum message size is 512 -// bytes, then a buffer size of 256 bytes will result in 1.01 more system calls -// than a buffer size of 512 bytes. The memory savings is 50%. -// -// A write buffer pool is useful when the application has a modest number -// writes over a large number of connections. when buffers are pooled, a larger -// buffer size has a reduced impact on total memory use and has the benefit of -// reducing system calls and frame overhead. -// -// Compression EXPERIMENTAL -// -// Per message compression extensions (RFC 7692) are experimentally supported -// by this package in a limited capacity. Setting the EnableCompression option -// to true in Dialer or Upgrader will attempt to negotiate per message deflate -// support. -// -// var upgrader = websocket.Upgrader{ -// EnableCompression: true, -// } -// -// If compression was successfully negotiated with the connection's peer, any -// message received in compressed form will be automatically decompressed. -// All Read methods will return uncompressed bytes. -// -// Per message compression of messages written to a connection can be enabled -// or disabled by calling the corresponding Conn method: -// -// conn.EnableWriteCompression(false) -// -// Currently this package does not support compression with "context takeover". -// This means that messages must be compressed and decompressed in isolation, -// without retaining sliding window or dictionary state across messages. For -// more details refer to RFC 7692. -// -// Use of compression is experimental and may result in decreased performance. -package websocket diff --git a/vendor/github.com/gorilla/websocket/join.go b/vendor/github.com/gorilla/websocket/join.go deleted file mode 100644 index c64f8c829..000000000 --- a/vendor/github.com/gorilla/websocket/join.go +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright 2019 The Gorilla WebSocket Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package websocket - -import ( - "io" - "strings" -) - -// JoinMessages concatenates received messages to create a single io.Reader. -// The string term is appended to each message. The returned reader does not -// support concurrent calls to the Read method. -func JoinMessages(c *Conn, term string) io.Reader { - return &joinReader{c: c, term: term} -} - -type joinReader struct { - c *Conn - term string - r io.Reader -} - -func (r *joinReader) Read(p []byte) (int, error) { - if r.r == nil { - var err error - _, r.r, err = r.c.NextReader() - if err != nil { - return 0, err - } - if r.term != "" { - r.r = io.MultiReader(r.r, strings.NewReader(r.term)) - } - } - n, err := r.r.Read(p) - if err == io.EOF { - err = nil - r.r = nil - } - return n, err -} diff --git a/vendor/github.com/gorilla/websocket/json.go b/vendor/github.com/gorilla/websocket/json.go deleted file mode 100644 index dc2c1f641..000000000 --- a/vendor/github.com/gorilla/websocket/json.go +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright 2013 The Gorilla WebSocket Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package websocket - -import ( - "encoding/json" - "io" -) - -// WriteJSON writes the JSON encoding of v as a message. -// -// Deprecated: Use c.WriteJSON instead. -func WriteJSON(c *Conn, v interface{}) error { - return c.WriteJSON(v) -} - -// WriteJSON writes the JSON encoding of v as a message. -// -// See the documentation for encoding/json Marshal for details about the -// conversion of Go values to JSON. -func (c *Conn) WriteJSON(v interface{}) error { - w, err := c.NextWriter(TextMessage) - if err != nil { - return err - } - err1 := json.NewEncoder(w).Encode(v) - err2 := w.Close() - if err1 != nil { - return err1 - } - return err2 -} - -// ReadJSON reads the next JSON-encoded message from the connection and stores -// it in the value pointed to by v. -// -// Deprecated: Use c.ReadJSON instead. -func ReadJSON(c *Conn, v interface{}) error { - return c.ReadJSON(v) -} - -// ReadJSON reads the next JSON-encoded message from the connection and stores -// it in the value pointed to by v. -// -// See the documentation for the encoding/json Unmarshal function for details -// about the conversion of JSON to a Go value. -func (c *Conn) ReadJSON(v interface{}) error { - _, r, err := c.NextReader() - if err != nil { - return err - } - err = json.NewDecoder(r).Decode(v) - if err == io.EOF { - // One value is expected in the message. - err = io.ErrUnexpectedEOF - } - return err -} diff --git a/vendor/github.com/gorilla/websocket/mask.go b/vendor/github.com/gorilla/websocket/mask.go deleted file mode 100644 index d0742bf2a..000000000 --- a/vendor/github.com/gorilla/websocket/mask.go +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright 2016 The Gorilla WebSocket Authors. All rights reserved. Use of -// this source code is governed by a BSD-style license that can be found in the -// LICENSE file. - -//go:build !appengine -// +build !appengine - -package websocket - -import "unsafe" - -const wordSize = int(unsafe.Sizeof(uintptr(0))) - -func maskBytes(key [4]byte, pos int, b []byte) int { - // Mask one byte at a time for small buffers. - if len(b) < 2*wordSize { - for i := range b { - b[i] ^= key[pos&3] - pos++ - } - return pos & 3 - } - - // Mask one byte at a time to word boundary. - if n := int(uintptr(unsafe.Pointer(&b[0]))) % wordSize; n != 0 { - n = wordSize - n - for i := range b[:n] { - b[i] ^= key[pos&3] - pos++ - } - b = b[n:] - } - - // Create aligned word size key. - var k [wordSize]byte - for i := range k { - k[i] = key[(pos+i)&3] - } - kw := *(*uintptr)(unsafe.Pointer(&k)) - - // Mask one word at a time. - n := (len(b) / wordSize) * wordSize - for i := 0; i < n; i += wordSize { - *(*uintptr)(unsafe.Pointer(uintptr(unsafe.Pointer(&b[0])) + uintptr(i))) ^= kw - } - - // Mask one byte at a time for remaining bytes. - b = b[n:] - for i := range b { - b[i] ^= key[pos&3] - pos++ - } - - return pos & 3 -} diff --git a/vendor/github.com/gorilla/websocket/mask_safe.go b/vendor/github.com/gorilla/websocket/mask_safe.go deleted file mode 100644 index 36250ca7c..000000000 --- a/vendor/github.com/gorilla/websocket/mask_safe.go +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2016 The Gorilla WebSocket Authors. All rights reserved. Use of -// this source code is governed by a BSD-style license that can be found in the -// LICENSE file. - -//go:build appengine -// +build appengine - -package websocket - -func maskBytes(key [4]byte, pos int, b []byte) int { - for i := range b { - b[i] ^= key[pos&3] - pos++ - } - return pos & 3 -} diff --git a/vendor/github.com/gorilla/websocket/prepared.go b/vendor/github.com/gorilla/websocket/prepared.go deleted file mode 100644 index c854225e9..000000000 --- a/vendor/github.com/gorilla/websocket/prepared.go +++ /dev/null @@ -1,102 +0,0 @@ -// Copyright 2017 The Gorilla WebSocket Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package websocket - -import ( - "bytes" - "net" - "sync" - "time" -) - -// PreparedMessage caches on the wire representations of a message payload. -// Use PreparedMessage to efficiently send a message payload to multiple -// connections. PreparedMessage is especially useful when compression is used -// because the CPU and memory expensive compression operation can be executed -// once for a given set of compression options. -type PreparedMessage struct { - messageType int - data []byte - mu sync.Mutex - frames map[prepareKey]*preparedFrame -} - -// prepareKey defines a unique set of options to cache prepared frames in PreparedMessage. -type prepareKey struct { - isServer bool - compress bool - compressionLevel int -} - -// preparedFrame contains data in wire representation. -type preparedFrame struct { - once sync.Once - data []byte -} - -// NewPreparedMessage returns an initialized PreparedMessage. You can then send -// it to connection using WritePreparedMessage method. Valid wire -// representation will be calculated lazily only once for a set of current -// connection options. -func NewPreparedMessage(messageType int, data []byte) (*PreparedMessage, error) { - pm := &PreparedMessage{ - messageType: messageType, - frames: make(map[prepareKey]*preparedFrame), - data: data, - } - - // Prepare a plain server frame. - _, frameData, err := pm.frame(prepareKey{isServer: true, compress: false}) - if err != nil { - return nil, err - } - - // To protect against caller modifying the data argument, remember the data - // copied to the plain server frame. - pm.data = frameData[len(frameData)-len(data):] - return pm, nil -} - -func (pm *PreparedMessage) frame(key prepareKey) (int, []byte, error) { - pm.mu.Lock() - frame, ok := pm.frames[key] - if !ok { - frame = &preparedFrame{} - pm.frames[key] = frame - } - pm.mu.Unlock() - - var err error - frame.once.Do(func() { - // Prepare a frame using a 'fake' connection. - // TODO: Refactor code in conn.go to allow more direct construction of - // the frame. - mu := make(chan struct{}, 1) - mu <- struct{}{} - var nc prepareConn - c := &Conn{ - conn: &nc, - mu: mu, - isServer: key.isServer, - compressionLevel: key.compressionLevel, - enableWriteCompression: true, - writeBuf: make([]byte, defaultWriteBufferSize+maxFrameHeaderSize), - } - if key.compress { - c.newCompressionWriter = compressNoContextTakeover - } - err = c.WriteMessage(pm.messageType, pm.data) - frame.data = nc.buf.Bytes() - }) - return pm.messageType, frame.data, err -} - -type prepareConn struct { - buf bytes.Buffer - net.Conn -} - -func (pc *prepareConn) Write(p []byte) (int, error) { return pc.buf.Write(p) } -func (pc *prepareConn) SetWriteDeadline(t time.Time) error { return nil } diff --git a/vendor/github.com/gorilla/websocket/proxy.go b/vendor/github.com/gorilla/websocket/proxy.go deleted file mode 100644 index e0f466b72..000000000 --- a/vendor/github.com/gorilla/websocket/proxy.go +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright 2017 The Gorilla WebSocket Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package websocket - -import ( - "bufio" - "encoding/base64" - "errors" - "net" - "net/http" - "net/url" - "strings" -) - -type netDialerFunc func(network, addr string) (net.Conn, error) - -func (fn netDialerFunc) Dial(network, addr string) (net.Conn, error) { - return fn(network, addr) -} - -func init() { - proxy_RegisterDialerType("http", func(proxyURL *url.URL, forwardDialer proxy_Dialer) (proxy_Dialer, error) { - return &httpProxyDialer{proxyURL: proxyURL, forwardDial: forwardDialer.Dial}, nil - }) -} - -type httpProxyDialer struct { - proxyURL *url.URL - forwardDial func(network, addr string) (net.Conn, error) -} - -func (hpd *httpProxyDialer) Dial(network string, addr string) (net.Conn, error) { - hostPort, _ := hostPortNoPort(hpd.proxyURL) - conn, err := hpd.forwardDial(network, hostPort) - if err != nil { - return nil, err - } - - connectHeader := make(http.Header) - if user := hpd.proxyURL.User; user != nil { - proxyUser := user.Username() - if proxyPassword, passwordSet := user.Password(); passwordSet { - credential := base64.StdEncoding.EncodeToString([]byte(proxyUser + ":" + proxyPassword)) - connectHeader.Set("Proxy-Authorization", "Basic "+credential) - } - } - - connectReq := &http.Request{ - Method: http.MethodConnect, - URL: &url.URL{Opaque: addr}, - Host: addr, - Header: connectHeader, - } - - if err := connectReq.Write(conn); err != nil { - conn.Close() - return nil, err - } - - // Read response. It's OK to use and discard buffered reader here becaue - // the remote server does not speak until spoken to. - br := bufio.NewReader(conn) - resp, err := http.ReadResponse(br, connectReq) - if err != nil { - conn.Close() - return nil, err - } - - if resp.StatusCode != 200 { - conn.Close() - f := strings.SplitN(resp.Status, " ", 2) - return nil, errors.New(f[1]) - } - return conn, nil -} diff --git a/vendor/github.com/gorilla/websocket/server.go b/vendor/github.com/gorilla/websocket/server.go deleted file mode 100644 index bb3359743..000000000 --- a/vendor/github.com/gorilla/websocket/server.go +++ /dev/null @@ -1,365 +0,0 @@ -// Copyright 2013 The Gorilla WebSocket Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package websocket - -import ( - "bufio" - "errors" - "io" - "net/http" - "net/url" - "strings" - "time" -) - -// HandshakeError describes an error with the handshake from the peer. -type HandshakeError struct { - message string -} - -func (e HandshakeError) Error() string { return e.message } - -// Upgrader specifies parameters for upgrading an HTTP connection to a -// WebSocket connection. -// -// It is safe to call Upgrader's methods concurrently. -type Upgrader struct { - // HandshakeTimeout specifies the duration for the handshake to complete. - HandshakeTimeout time.Duration - - // ReadBufferSize and WriteBufferSize specify I/O buffer sizes in bytes. If a buffer - // size is zero, then buffers allocated by the HTTP server are used. The - // I/O buffer sizes do not limit the size of the messages that can be sent - // or received. - ReadBufferSize, WriteBufferSize int - - // WriteBufferPool is a pool of buffers for write operations. If the value - // is not set, then write buffers are allocated to the connection for the - // lifetime of the connection. - // - // A pool is most useful when the application has a modest volume of writes - // across a large number of connections. - // - // Applications should use a single pool for each unique value of - // WriteBufferSize. - WriteBufferPool BufferPool - - // Subprotocols specifies the server's supported protocols in order of - // preference. If this field is not nil, then the Upgrade method negotiates a - // subprotocol by selecting the first match in this list with a protocol - // requested by the client. If there's no match, then no protocol is - // negotiated (the Sec-Websocket-Protocol header is not included in the - // handshake response). - Subprotocols []string - - // Error specifies the function for generating HTTP error responses. If Error - // is nil, then http.Error is used to generate the HTTP response. - Error func(w http.ResponseWriter, r *http.Request, status int, reason error) - - // CheckOrigin returns true if the request Origin header is acceptable. If - // CheckOrigin is nil, then a safe default is used: return false if the - // Origin request header is present and the origin host is not equal to - // request Host header. - // - // A CheckOrigin function should carefully validate the request origin to - // prevent cross-site request forgery. - CheckOrigin func(r *http.Request) bool - - // EnableCompression specify if the server should attempt to negotiate per - // message compression (RFC 7692). Setting this value to true does not - // guarantee that compression will be supported. Currently only "no context - // takeover" modes are supported. - EnableCompression bool -} - -func (u *Upgrader) returnError(w http.ResponseWriter, r *http.Request, status int, reason string) (*Conn, error) { - err := HandshakeError{reason} - if u.Error != nil { - u.Error(w, r, status, err) - } else { - w.Header().Set("Sec-Websocket-Version", "13") - http.Error(w, http.StatusText(status), status) - } - return nil, err -} - -// checkSameOrigin returns true if the origin is not set or is equal to the request host. -func checkSameOrigin(r *http.Request) bool { - origin := r.Header["Origin"] - if len(origin) == 0 { - return true - } - u, err := url.Parse(origin[0]) - if err != nil { - return false - } - return equalASCIIFold(u.Host, r.Host) -} - -func (u *Upgrader) selectSubprotocol(r *http.Request, responseHeader http.Header) string { - if u.Subprotocols != nil { - clientProtocols := Subprotocols(r) - for _, serverProtocol := range u.Subprotocols { - for _, clientProtocol := range clientProtocols { - if clientProtocol == serverProtocol { - return clientProtocol - } - } - } - } else if responseHeader != nil { - return responseHeader.Get("Sec-Websocket-Protocol") - } - return "" -} - -// Upgrade upgrades the HTTP server connection to the WebSocket protocol. -// -// The responseHeader is included in the response to the client's upgrade -// request. Use the responseHeader to specify cookies (Set-Cookie). To specify -// subprotocols supported by the server, set Upgrader.Subprotocols directly. -// -// If the upgrade fails, then Upgrade replies to the client with an HTTP error -// response. -func (u *Upgrader) Upgrade(w http.ResponseWriter, r *http.Request, responseHeader http.Header) (*Conn, error) { - const badHandshake = "websocket: the client is not using the websocket protocol: " - - if !tokenListContainsValue(r.Header, "Connection", "upgrade") { - return u.returnError(w, r, http.StatusBadRequest, badHandshake+"'upgrade' token not found in 'Connection' header") - } - - if !tokenListContainsValue(r.Header, "Upgrade", "websocket") { - return u.returnError(w, r, http.StatusBadRequest, badHandshake+"'websocket' token not found in 'Upgrade' header") - } - - if r.Method != http.MethodGet { - return u.returnError(w, r, http.StatusMethodNotAllowed, badHandshake+"request method is not GET") - } - - if !tokenListContainsValue(r.Header, "Sec-Websocket-Version", "13") { - return u.returnError(w, r, http.StatusBadRequest, "websocket: unsupported version: 13 not found in 'Sec-Websocket-Version' header") - } - - if _, ok := responseHeader["Sec-Websocket-Extensions"]; ok { - return u.returnError(w, r, http.StatusInternalServerError, "websocket: application specific 'Sec-WebSocket-Extensions' headers are unsupported") - } - - checkOrigin := u.CheckOrigin - if checkOrigin == nil { - checkOrigin = checkSameOrigin - } - if !checkOrigin(r) { - return u.returnError(w, r, http.StatusForbidden, "websocket: request origin not allowed by Upgrader.CheckOrigin") - } - - challengeKey := r.Header.Get("Sec-Websocket-Key") - if !isValidChallengeKey(challengeKey) { - return u.returnError(w, r, http.StatusBadRequest, "websocket: not a websocket handshake: 'Sec-WebSocket-Key' header must be Base64 encoded value of 16-byte in length") - } - - subprotocol := u.selectSubprotocol(r, responseHeader) - - // Negotiate PMCE - var compress bool - if u.EnableCompression { - for _, ext := range parseExtensions(r.Header) { - if ext[""] != "permessage-deflate" { - continue - } - compress = true - break - } - } - - h, ok := w.(http.Hijacker) - if !ok { - return u.returnError(w, r, http.StatusInternalServerError, "websocket: response does not implement http.Hijacker") - } - var brw *bufio.ReadWriter - netConn, brw, err := h.Hijack() - if err != nil { - return u.returnError(w, r, http.StatusInternalServerError, err.Error()) - } - - if brw.Reader.Buffered() > 0 { - netConn.Close() - return nil, errors.New("websocket: client sent data before handshake is complete") - } - - var br *bufio.Reader - if u.ReadBufferSize == 0 && bufioReaderSize(netConn, brw.Reader) > 256 { - // Reuse hijacked buffered reader as connection reader. - br = brw.Reader - } - - buf := bufioWriterBuffer(netConn, brw.Writer) - - var writeBuf []byte - if u.WriteBufferPool == nil && u.WriteBufferSize == 0 && len(buf) >= maxFrameHeaderSize+256 { - // Reuse hijacked write buffer as connection buffer. - writeBuf = buf - } - - c := newConn(netConn, true, u.ReadBufferSize, u.WriteBufferSize, u.WriteBufferPool, br, writeBuf) - c.subprotocol = subprotocol - - if compress { - c.newCompressionWriter = compressNoContextTakeover - c.newDecompressionReader = decompressNoContextTakeover - } - - // Use larger of hijacked buffer and connection write buffer for header. - p := buf - if len(c.writeBuf) > len(p) { - p = c.writeBuf - } - p = p[:0] - - p = append(p, "HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: "...) - p = append(p, computeAcceptKey(challengeKey)...) - p = append(p, "\r\n"...) - if c.subprotocol != "" { - p = append(p, "Sec-WebSocket-Protocol: "...) - p = append(p, c.subprotocol...) - p = append(p, "\r\n"...) - } - if compress { - p = append(p, "Sec-WebSocket-Extensions: permessage-deflate; server_no_context_takeover; client_no_context_takeover\r\n"...) - } - for k, vs := range responseHeader { - if k == "Sec-Websocket-Protocol" { - continue - } - for _, v := range vs { - p = append(p, k...) - p = append(p, ": "...) - for i := 0; i < len(v); i++ { - b := v[i] - if b <= 31 { - // prevent response splitting. - b = ' ' - } - p = append(p, b) - } - p = append(p, "\r\n"...) - } - } - p = append(p, "\r\n"...) - - // Clear deadlines set by HTTP server. - netConn.SetDeadline(time.Time{}) - - if u.HandshakeTimeout > 0 { - netConn.SetWriteDeadline(time.Now().Add(u.HandshakeTimeout)) - } - if _, err = netConn.Write(p); err != nil { - netConn.Close() - return nil, err - } - if u.HandshakeTimeout > 0 { - netConn.SetWriteDeadline(time.Time{}) - } - - return c, nil -} - -// Upgrade upgrades the HTTP server connection to the WebSocket protocol. -// -// Deprecated: Use websocket.Upgrader instead. -// -// Upgrade does not perform origin checking. The application is responsible for -// checking the Origin header before calling Upgrade. An example implementation -// of the same origin policy check is: -// -// if req.Header.Get("Origin") != "http://"+req.Host { -// http.Error(w, "Origin not allowed", http.StatusForbidden) -// return -// } -// -// If the endpoint supports subprotocols, then the application is responsible -// for negotiating the protocol used on the connection. Use the Subprotocols() -// function to get the subprotocols requested by the client. Use the -// Sec-Websocket-Protocol response header to specify the subprotocol selected -// by the application. -// -// The responseHeader is included in the response to the client's upgrade -// request. Use the responseHeader to specify cookies (Set-Cookie) and the -// negotiated subprotocol (Sec-Websocket-Protocol). -// -// The connection buffers IO to the underlying network connection. The -// readBufSize and writeBufSize parameters specify the size of the buffers to -// use. Messages can be larger than the buffers. -// -// If the request is not a valid WebSocket handshake, then Upgrade returns an -// error of type HandshakeError. Applications should handle this error by -// replying to the client with an HTTP error response. -func Upgrade(w http.ResponseWriter, r *http.Request, responseHeader http.Header, readBufSize, writeBufSize int) (*Conn, error) { - u := Upgrader{ReadBufferSize: readBufSize, WriteBufferSize: writeBufSize} - u.Error = func(w http.ResponseWriter, r *http.Request, status int, reason error) { - // don't return errors to maintain backwards compatibility - } - u.CheckOrigin = func(r *http.Request) bool { - // allow all connections by default - return true - } - return u.Upgrade(w, r, responseHeader) -} - -// Subprotocols returns the subprotocols requested by the client in the -// Sec-Websocket-Protocol header. -func Subprotocols(r *http.Request) []string { - h := strings.TrimSpace(r.Header.Get("Sec-Websocket-Protocol")) - if h == "" { - return nil - } - protocols := strings.Split(h, ",") - for i := range protocols { - protocols[i] = strings.TrimSpace(protocols[i]) - } - return protocols -} - -// IsWebSocketUpgrade returns true if the client requested upgrade to the -// WebSocket protocol. -func IsWebSocketUpgrade(r *http.Request) bool { - return tokenListContainsValue(r.Header, "Connection", "upgrade") && - tokenListContainsValue(r.Header, "Upgrade", "websocket") -} - -// bufioReaderSize size returns the size of a bufio.Reader. -func bufioReaderSize(originalReader io.Reader, br *bufio.Reader) int { - // This code assumes that peek on a reset reader returns - // bufio.Reader.buf[:0]. - // TODO: Use bufio.Reader.Size() after Go 1.10 - br.Reset(originalReader) - if p, err := br.Peek(0); err == nil { - return cap(p) - } - return 0 -} - -// writeHook is an io.Writer that records the last slice passed to it vio -// io.Writer.Write. -type writeHook struct { - p []byte -} - -func (wh *writeHook) Write(p []byte) (int, error) { - wh.p = p - return len(p), nil -} - -// bufioWriterBuffer grabs the buffer from a bufio.Writer. -func bufioWriterBuffer(originalWriter io.Writer, bw *bufio.Writer) []byte { - // This code assumes that bufio.Writer.buf[:1] is passed to the - // bufio.Writer's underlying writer. - var wh writeHook - bw.Reset(&wh) - bw.WriteByte(0) - bw.Flush() - - bw.Reset(originalWriter) - - return wh.p[:cap(wh.p)] -} diff --git a/vendor/github.com/gorilla/websocket/tls_handshake.go b/vendor/github.com/gorilla/websocket/tls_handshake.go deleted file mode 100644 index a62b68ccb..000000000 --- a/vendor/github.com/gorilla/websocket/tls_handshake.go +++ /dev/null @@ -1,21 +0,0 @@ -//go:build go1.17 -// +build go1.17 - -package websocket - -import ( - "context" - "crypto/tls" -) - -func doHandshake(ctx context.Context, tlsConn *tls.Conn, cfg *tls.Config) error { - if err := tlsConn.HandshakeContext(ctx); err != nil { - return err - } - if !cfg.InsecureSkipVerify { - if err := tlsConn.VerifyHostname(cfg.ServerName); err != nil { - return err - } - } - return nil -} diff --git a/vendor/github.com/gorilla/websocket/tls_handshake_116.go b/vendor/github.com/gorilla/websocket/tls_handshake_116.go deleted file mode 100644 index e1b2b44f6..000000000 --- a/vendor/github.com/gorilla/websocket/tls_handshake_116.go +++ /dev/null @@ -1,21 +0,0 @@ -//go:build !go1.17 -// +build !go1.17 - -package websocket - -import ( - "context" - "crypto/tls" -) - -func doHandshake(ctx context.Context, tlsConn *tls.Conn, cfg *tls.Config) error { - if err := tlsConn.Handshake(); err != nil { - return err - } - if !cfg.InsecureSkipVerify { - if err := tlsConn.VerifyHostname(cfg.ServerName); err != nil { - return err - } - } - return nil -} diff --git a/vendor/github.com/gorilla/websocket/util.go b/vendor/github.com/gorilla/websocket/util.go deleted file mode 100644 index 31a5dee64..000000000 --- a/vendor/github.com/gorilla/websocket/util.go +++ /dev/null @@ -1,298 +0,0 @@ -// Copyright 2013 The Gorilla WebSocket Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package websocket - -import ( - "crypto/rand" - "crypto/sha1" - "encoding/base64" - "io" - "net/http" - "strings" - "unicode/utf8" -) - -var keyGUID = []byte("258EAFA5-E914-47DA-95CA-C5AB0DC85B11") - -func computeAcceptKey(challengeKey string) string { - h := sha1.New() - h.Write([]byte(challengeKey)) - h.Write(keyGUID) - return base64.StdEncoding.EncodeToString(h.Sum(nil)) -} - -func generateChallengeKey() (string, error) { - p := make([]byte, 16) - if _, err := io.ReadFull(rand.Reader, p); err != nil { - return "", err - } - return base64.StdEncoding.EncodeToString(p), nil -} - -// Token octets per RFC 2616. -var isTokenOctet = [256]bool{ - '!': true, - '#': true, - '$': true, - '%': true, - '&': true, - '\'': true, - '*': true, - '+': true, - '-': true, - '.': true, - '0': true, - '1': true, - '2': true, - '3': true, - '4': true, - '5': true, - '6': true, - '7': true, - '8': true, - '9': true, - 'A': true, - 'B': true, - 'C': true, - 'D': true, - 'E': true, - 'F': true, - 'G': true, - 'H': true, - 'I': true, - 'J': true, - 'K': true, - 'L': true, - 'M': true, - 'N': true, - 'O': true, - 'P': true, - 'Q': true, - 'R': true, - 'S': true, - 'T': true, - 'U': true, - 'W': true, - 'V': true, - 'X': true, - 'Y': true, - 'Z': true, - '^': true, - '_': true, - '`': true, - 'a': true, - 'b': true, - 'c': true, - 'd': true, - 'e': true, - 'f': true, - 'g': true, - 'h': true, - 'i': true, - 'j': true, - 'k': true, - 'l': true, - 'm': true, - 'n': true, - 'o': true, - 'p': true, - 'q': true, - 'r': true, - 's': true, - 't': true, - 'u': true, - 'v': true, - 'w': true, - 'x': true, - 'y': true, - 'z': true, - '|': true, - '~': true, -} - -// skipSpace returns a slice of the string s with all leading RFC 2616 linear -// whitespace removed. -func skipSpace(s string) (rest string) { - i := 0 - for ; i < len(s); i++ { - if b := s[i]; b != ' ' && b != '\t' { - break - } - } - return s[i:] -} - -// nextToken returns the leading RFC 2616 token of s and the string following -// the token. -func nextToken(s string) (token, rest string) { - i := 0 - for ; i < len(s); i++ { - if !isTokenOctet[s[i]] { - break - } - } - return s[:i], s[i:] -} - -// nextTokenOrQuoted returns the leading token or quoted string per RFC 2616 -// and the string following the token or quoted string. -func nextTokenOrQuoted(s string) (value string, rest string) { - if !strings.HasPrefix(s, "\"") { - return nextToken(s) - } - s = s[1:] - for i := 0; i < len(s); i++ { - switch s[i] { - case '"': - return s[:i], s[i+1:] - case '\\': - p := make([]byte, len(s)-1) - j := copy(p, s[:i]) - escape := true - for i = i + 1; i < len(s); i++ { - b := s[i] - switch { - case escape: - escape = false - p[j] = b - j++ - case b == '\\': - escape = true - case b == '"': - return string(p[:j]), s[i+1:] - default: - p[j] = b - j++ - } - } - return "", "" - } - } - return "", "" -} - -// equalASCIIFold returns true if s is equal to t with ASCII case folding as -// defined in RFC 4790. -func equalASCIIFold(s, t string) bool { - for s != "" && t != "" { - sr, size := utf8.DecodeRuneInString(s) - s = s[size:] - tr, size := utf8.DecodeRuneInString(t) - t = t[size:] - if sr == tr { - continue - } - if 'A' <= sr && sr <= 'Z' { - sr = sr + 'a' - 'A' - } - if 'A' <= tr && tr <= 'Z' { - tr = tr + 'a' - 'A' - } - if sr != tr { - return false - } - } - return s == t -} - -// tokenListContainsValue returns true if the 1#token header with the given -// name contains a token equal to value with ASCII case folding. -func tokenListContainsValue(header http.Header, name string, value string) bool { -headers: - for _, s := range header[name] { - for { - var t string - t, s = nextToken(skipSpace(s)) - if t == "" { - continue headers - } - s = skipSpace(s) - if s != "" && s[0] != ',' { - continue headers - } - if equalASCIIFold(t, value) { - return true - } - if s == "" { - continue headers - } - s = s[1:] - } - } - return false -} - -// parseExtensions parses WebSocket extensions from a header. -func parseExtensions(header http.Header) []map[string]string { - // From RFC 6455: - // - // Sec-WebSocket-Extensions = extension-list - // extension-list = 1#extension - // extension = extension-token *( ";" extension-param ) - // extension-token = registered-token - // registered-token = token - // extension-param = token [ "=" (token | quoted-string) ] - // ;When using the quoted-string syntax variant, the value - // ;after quoted-string unescaping MUST conform to the - // ;'token' ABNF. - - var result []map[string]string -headers: - for _, s := range header["Sec-Websocket-Extensions"] { - for { - var t string - t, s = nextToken(skipSpace(s)) - if t == "" { - continue headers - } - ext := map[string]string{"": t} - for { - s = skipSpace(s) - if !strings.HasPrefix(s, ";") { - break - } - var k string - k, s = nextToken(skipSpace(s[1:])) - if k == "" { - continue headers - } - s = skipSpace(s) - var v string - if strings.HasPrefix(s, "=") { - v, s = nextTokenOrQuoted(skipSpace(s[1:])) - s = skipSpace(s) - } - if s != "" && s[0] != ',' && s[0] != ';' { - continue headers - } - ext[k] = v - } - if s != "" && s[0] != ',' { - continue headers - } - result = append(result, ext) - if s == "" { - continue headers - } - s = s[1:] - } - } - return result -} - -// isValidChallengeKey checks if the argument meets RFC6455 specification. -func isValidChallengeKey(s string) bool { - // From RFC6455: - // - // A |Sec-WebSocket-Key| header field with a base64-encoded (see - // Section 4 of [RFC4648]) value that, when decoded, is 16 bytes in - // length. - - if s == "" { - return false - } - decoded, err := base64.StdEncoding.DecodeString(s) - return err == nil && len(decoded) == 16 -} diff --git a/vendor/github.com/gorilla/websocket/x_net_proxy.go b/vendor/github.com/gorilla/websocket/x_net_proxy.go deleted file mode 100644 index 2e668f6b8..000000000 --- a/vendor/github.com/gorilla/websocket/x_net_proxy.go +++ /dev/null @@ -1,473 +0,0 @@ -// Code generated by golang.org/x/tools/cmd/bundle. DO NOT EDIT. -//go:generate bundle -o x_net_proxy.go golang.org/x/net/proxy - -// Package proxy provides support for a variety of protocols to proxy network -// data. -// - -package websocket - -import ( - "errors" - "io" - "net" - "net/url" - "os" - "strconv" - "strings" - "sync" -) - -type proxy_direct struct{} - -// Direct is a direct proxy: one that makes network connections directly. -var proxy_Direct = proxy_direct{} - -func (proxy_direct) Dial(network, addr string) (net.Conn, error) { - return net.Dial(network, addr) -} - -// A PerHost directs connections to a default Dialer unless the host name -// requested matches one of a number of exceptions. -type proxy_PerHost struct { - def, bypass proxy_Dialer - - bypassNetworks []*net.IPNet - bypassIPs []net.IP - bypassZones []string - bypassHosts []string -} - -// NewPerHost returns a PerHost Dialer that directs connections to either -// defaultDialer or bypass, depending on whether the connection matches one of -// the configured rules. -func proxy_NewPerHost(defaultDialer, bypass proxy_Dialer) *proxy_PerHost { - return &proxy_PerHost{ - def: defaultDialer, - bypass: bypass, - } -} - -// Dial connects to the address addr on the given network through either -// defaultDialer or bypass. -func (p *proxy_PerHost) Dial(network, addr string) (c net.Conn, err error) { - host, _, err := net.SplitHostPort(addr) - if err != nil { - return nil, err - } - - return p.dialerForRequest(host).Dial(network, addr) -} - -func (p *proxy_PerHost) dialerForRequest(host string) proxy_Dialer { - if ip := net.ParseIP(host); ip != nil { - for _, net := range p.bypassNetworks { - if net.Contains(ip) { - return p.bypass - } - } - for _, bypassIP := range p.bypassIPs { - if bypassIP.Equal(ip) { - return p.bypass - } - } - return p.def - } - - for _, zone := range p.bypassZones { - if strings.HasSuffix(host, zone) { - return p.bypass - } - if host == zone[1:] { - // For a zone ".example.com", we match "example.com" - // too. - return p.bypass - } - } - for _, bypassHost := range p.bypassHosts { - if bypassHost == host { - return p.bypass - } - } - return p.def -} - -// AddFromString parses a string that contains comma-separated values -// specifying hosts that should use the bypass proxy. Each value is either an -// IP address, a CIDR range, a zone (*.example.com) or a host name -// (localhost). A best effort is made to parse the string and errors are -// ignored. -func (p *proxy_PerHost) AddFromString(s string) { - hosts := strings.Split(s, ",") - for _, host := range hosts { - host = strings.TrimSpace(host) - if len(host) == 0 { - continue - } - if strings.Contains(host, "/") { - // We assume that it's a CIDR address like 127.0.0.0/8 - if _, net, err := net.ParseCIDR(host); err == nil { - p.AddNetwork(net) - } - continue - } - if ip := net.ParseIP(host); ip != nil { - p.AddIP(ip) - continue - } - if strings.HasPrefix(host, "*.") { - p.AddZone(host[1:]) - continue - } - p.AddHost(host) - } -} - -// AddIP specifies an IP address that will use the bypass proxy. Note that -// this will only take effect if a literal IP address is dialed. A connection -// to a named host will never match an IP. -func (p *proxy_PerHost) AddIP(ip net.IP) { - p.bypassIPs = append(p.bypassIPs, ip) -} - -// AddNetwork specifies an IP range that will use the bypass proxy. Note that -// this will only take effect if a literal IP address is dialed. A connection -// to a named host will never match. -func (p *proxy_PerHost) AddNetwork(net *net.IPNet) { - p.bypassNetworks = append(p.bypassNetworks, net) -} - -// AddZone specifies a DNS suffix that will use the bypass proxy. A zone of -// "example.com" matches "example.com" and all of its subdomains. -func (p *proxy_PerHost) AddZone(zone string) { - if strings.HasSuffix(zone, ".") { - zone = zone[:len(zone)-1] - } - if !strings.HasPrefix(zone, ".") { - zone = "." + zone - } - p.bypassZones = append(p.bypassZones, zone) -} - -// AddHost specifies a host name that will use the bypass proxy. -func (p *proxy_PerHost) AddHost(host string) { - if strings.HasSuffix(host, ".") { - host = host[:len(host)-1] - } - p.bypassHosts = append(p.bypassHosts, host) -} - -// A Dialer is a means to establish a connection. -type proxy_Dialer interface { - // Dial connects to the given address via the proxy. - Dial(network, addr string) (c net.Conn, err error) -} - -// Auth contains authentication parameters that specific Dialers may require. -type proxy_Auth struct { - User, Password string -} - -// FromEnvironment returns the dialer specified by the proxy related variables in -// the environment. -func proxy_FromEnvironment() proxy_Dialer { - allProxy := proxy_allProxyEnv.Get() - if len(allProxy) == 0 { - return proxy_Direct - } - - proxyURL, err := url.Parse(allProxy) - if err != nil { - return proxy_Direct - } - proxy, err := proxy_FromURL(proxyURL, proxy_Direct) - if err != nil { - return proxy_Direct - } - - noProxy := proxy_noProxyEnv.Get() - if len(noProxy) == 0 { - return proxy - } - - perHost := proxy_NewPerHost(proxy, proxy_Direct) - perHost.AddFromString(noProxy) - return perHost -} - -// proxySchemes is a map from URL schemes to a function that creates a Dialer -// from a URL with such a scheme. -var proxy_proxySchemes map[string]func(*url.URL, proxy_Dialer) (proxy_Dialer, error) - -// RegisterDialerType takes a URL scheme and a function to generate Dialers from -// a URL with that scheme and a forwarding Dialer. Registered schemes are used -// by FromURL. -func proxy_RegisterDialerType(scheme string, f func(*url.URL, proxy_Dialer) (proxy_Dialer, error)) { - if proxy_proxySchemes == nil { - proxy_proxySchemes = make(map[string]func(*url.URL, proxy_Dialer) (proxy_Dialer, error)) - } - proxy_proxySchemes[scheme] = f -} - -// FromURL returns a Dialer given a URL specification and an underlying -// Dialer for it to make network requests. -func proxy_FromURL(u *url.URL, forward proxy_Dialer) (proxy_Dialer, error) { - var auth *proxy_Auth - if u.User != nil { - auth = new(proxy_Auth) - auth.User = u.User.Username() - if p, ok := u.User.Password(); ok { - auth.Password = p - } - } - - switch u.Scheme { - case "socks5": - return proxy_SOCKS5("tcp", u.Host, auth, forward) - } - - // If the scheme doesn't match any of the built-in schemes, see if it - // was registered by another package. - if proxy_proxySchemes != nil { - if f, ok := proxy_proxySchemes[u.Scheme]; ok { - return f(u, forward) - } - } - - return nil, errors.New("proxy: unknown scheme: " + u.Scheme) -} - -var ( - proxy_allProxyEnv = &proxy_envOnce{ - names: []string{"ALL_PROXY", "all_proxy"}, - } - proxy_noProxyEnv = &proxy_envOnce{ - names: []string{"NO_PROXY", "no_proxy"}, - } -) - -// envOnce looks up an environment variable (optionally by multiple -// names) once. It mitigates expensive lookups on some platforms -// (e.g. Windows). -// (Borrowed from net/http/transport.go) -type proxy_envOnce struct { - names []string - once sync.Once - val string -} - -func (e *proxy_envOnce) Get() string { - e.once.Do(e.init) - return e.val -} - -func (e *proxy_envOnce) init() { - for _, n := range e.names { - e.val = os.Getenv(n) - if e.val != "" { - return - } - } -} - -// SOCKS5 returns a Dialer that makes SOCKSv5 connections to the given address -// with an optional username and password. See RFC 1928 and RFC 1929. -func proxy_SOCKS5(network, addr string, auth *proxy_Auth, forward proxy_Dialer) (proxy_Dialer, error) { - s := &proxy_socks5{ - network: network, - addr: addr, - forward: forward, - } - if auth != nil { - s.user = auth.User - s.password = auth.Password - } - - return s, nil -} - -type proxy_socks5 struct { - user, password string - network, addr string - forward proxy_Dialer -} - -const proxy_socks5Version = 5 - -const ( - proxy_socks5AuthNone = 0 - proxy_socks5AuthPassword = 2 -) - -const proxy_socks5Connect = 1 - -const ( - proxy_socks5IP4 = 1 - proxy_socks5Domain = 3 - proxy_socks5IP6 = 4 -) - -var proxy_socks5Errors = []string{ - "", - "general failure", - "connection forbidden", - "network unreachable", - "host unreachable", - "connection refused", - "TTL expired", - "command not supported", - "address type not supported", -} - -// Dial connects to the address addr on the given network via the SOCKS5 proxy. -func (s *proxy_socks5) Dial(network, addr string) (net.Conn, error) { - switch network { - case "tcp", "tcp6", "tcp4": - default: - return nil, errors.New("proxy: no support for SOCKS5 proxy connections of type " + network) - } - - conn, err := s.forward.Dial(s.network, s.addr) - if err != nil { - return nil, err - } - if err := s.connect(conn, addr); err != nil { - conn.Close() - return nil, err - } - return conn, nil -} - -// connect takes an existing connection to a socks5 proxy server, -// and commands the server to extend that connection to target, -// which must be a canonical address with a host and port. -func (s *proxy_socks5) connect(conn net.Conn, target string) error { - host, portStr, err := net.SplitHostPort(target) - if err != nil { - return err - } - - port, err := strconv.Atoi(portStr) - if err != nil { - return errors.New("proxy: failed to parse port number: " + portStr) - } - if port < 1 || port > 0xffff { - return errors.New("proxy: port number out of range: " + portStr) - } - - // the size here is just an estimate - buf := make([]byte, 0, 6+len(host)) - - buf = append(buf, proxy_socks5Version) - if len(s.user) > 0 && len(s.user) < 256 && len(s.password) < 256 { - buf = append(buf, 2 /* num auth methods */, proxy_socks5AuthNone, proxy_socks5AuthPassword) - } else { - buf = append(buf, 1 /* num auth methods */, proxy_socks5AuthNone) - } - - if _, err := conn.Write(buf); err != nil { - return errors.New("proxy: failed to write greeting to SOCKS5 proxy at " + s.addr + ": " + err.Error()) - } - - if _, err := io.ReadFull(conn, buf[:2]); err != nil { - return errors.New("proxy: failed to read greeting from SOCKS5 proxy at " + s.addr + ": " + err.Error()) - } - if buf[0] != 5 { - return errors.New("proxy: SOCKS5 proxy at " + s.addr + " has unexpected version " + strconv.Itoa(int(buf[0]))) - } - if buf[1] == 0xff { - return errors.New("proxy: SOCKS5 proxy at " + s.addr + " requires authentication") - } - - // See RFC 1929 - if buf[1] == proxy_socks5AuthPassword { - buf = buf[:0] - buf = append(buf, 1 /* password protocol version */) - buf = append(buf, uint8(len(s.user))) - buf = append(buf, s.user...) - buf = append(buf, uint8(len(s.password))) - buf = append(buf, s.password...) - - if _, err := conn.Write(buf); err != nil { - return errors.New("proxy: failed to write authentication request to SOCKS5 proxy at " + s.addr + ": " + err.Error()) - } - - if _, err := io.ReadFull(conn, buf[:2]); err != nil { - return errors.New("proxy: failed to read authentication reply from SOCKS5 proxy at " + s.addr + ": " + err.Error()) - } - - if buf[1] != 0 { - return errors.New("proxy: SOCKS5 proxy at " + s.addr + " rejected username/password") - } - } - - buf = buf[:0] - buf = append(buf, proxy_socks5Version, proxy_socks5Connect, 0 /* reserved */) - - if ip := net.ParseIP(host); ip != nil { - if ip4 := ip.To4(); ip4 != nil { - buf = append(buf, proxy_socks5IP4) - ip = ip4 - } else { - buf = append(buf, proxy_socks5IP6) - } - buf = append(buf, ip...) - } else { - if len(host) > 255 { - return errors.New("proxy: destination host name too long: " + host) - } - buf = append(buf, proxy_socks5Domain) - buf = append(buf, byte(len(host))) - buf = append(buf, host...) - } - buf = append(buf, byte(port>>8), byte(port)) - - if _, err := conn.Write(buf); err != nil { - return errors.New("proxy: failed to write connect request to SOCKS5 proxy at " + s.addr + ": " + err.Error()) - } - - if _, err := io.ReadFull(conn, buf[:4]); err != nil { - return errors.New("proxy: failed to read connect reply from SOCKS5 proxy at " + s.addr + ": " + err.Error()) - } - - failure := "unknown error" - if int(buf[1]) < len(proxy_socks5Errors) { - failure = proxy_socks5Errors[buf[1]] - } - - if len(failure) > 0 { - return errors.New("proxy: SOCKS5 proxy at " + s.addr + " failed to connect: " + failure) - } - - bytesToDiscard := 0 - switch buf[3] { - case proxy_socks5IP4: - bytesToDiscard = net.IPv4len - case proxy_socks5IP6: - bytesToDiscard = net.IPv6len - case proxy_socks5Domain: - _, err := io.ReadFull(conn, buf[:1]) - if err != nil { - return errors.New("proxy: failed to read domain length from SOCKS5 proxy at " + s.addr + ": " + err.Error()) - } - bytesToDiscard = int(buf[0]) - default: - return errors.New("proxy: got unknown address type " + strconv.Itoa(int(buf[3])) + " from SOCKS5 proxy at " + s.addr) - } - - if cap(buf) < bytesToDiscard { - buf = make([]byte, bytesToDiscard) - } else { - buf = buf[:bytesToDiscard] - } - if _, err := io.ReadFull(conn, buf); err != nil { - return errors.New("proxy: failed to read address from SOCKS5 proxy at " + s.addr + ": " + err.Error()) - } - - // Also need to discard the port number - if _, err := io.ReadFull(conn, buf[:2]); err != nil { - return errors.New("proxy: failed to read port from SOCKS5 proxy at " + s.addr + ": " + err.Error()) - } - - return nil -} |