mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-10-26 12:27:06 +00:00 
			
		
		
		
	Dump: add output format tar and output to stdout (#10376)
* Dump: Use mholt/archive/v3 to support tar including many compressions Signed-off-by: Philipp Homann <homann.philipp@googlemail.com> * Dump: Allow dump output to stdout Signed-off-by: Philipp Homann <homann.philipp@googlemail.com> * Dump: Fixed bug present since #6677 where SessionConfig.Provider is never "file" Signed-off-by: Philipp Homann <homann.philipp@googlemail.com> * Dump: never pack RepoRootPath, LFS.ContentPath and LogRootPath when they are below AppDataPath Signed-off-by: Philipp Homann <homann.philipp@googlemail.com> * Dump: also dump LFS (fixes #10058) Signed-off-by: Philipp Homann <homann.philipp@googlemail.com> * Dump: never dump CustomPath if CustomPath is a subdir of or equal to AppDataPath (fixes #10365) Signed-off-by: Philipp Homann <homann.philipp@googlemail.com> * Use log.Info instead of fmt.Fprintf Signed-off-by: Philipp Homann <homann.philipp@googlemail.com> * import ordering * make fmt Co-authored-by: zeripath <art27@cantab.net> Co-authored-by: techknowlogick <techknowlogick@gitea.io> Co-authored-by: Matti R <matti@mdranta.net>
This commit is contained in:
		
							
								
								
									
										27
									
								
								vendor/github.com/golang/gddo/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								vendor/github.com/golang/gddo/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,27 @@ | ||||
| Copyright (c) 2013 The Go 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. | ||||
							
								
								
									
										95
									
								
								vendor/github.com/golang/gddo/httputil/buster.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										95
									
								
								vendor/github.com/golang/gddo/httputil/buster.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,95 @@ | ||||
| // Copyright 2013 The Go Authors. All rights reserved. | ||||
| // | ||||
| // Use of this source code is governed by a BSD-style | ||||
| // license that can be found in the LICENSE file or at | ||||
| // https://developers.google.com/open-source/licenses/bsd. | ||||
|  | ||||
| package httputil | ||||
|  | ||||
| import ( | ||||
| 	"io" | ||||
| 	"io/ioutil" | ||||
| 	"net/http" | ||||
| 	"net/url" | ||||
| 	"strings" | ||||
| 	"sync" | ||||
| ) | ||||
|  | ||||
| type busterWriter struct { | ||||
| 	headerMap http.Header | ||||
| 	status    int | ||||
| 	io.Writer | ||||
| } | ||||
|  | ||||
| func (bw *busterWriter) Header() http.Header { | ||||
| 	return bw.headerMap | ||||
| } | ||||
|  | ||||
| func (bw *busterWriter) WriteHeader(status int) { | ||||
| 	bw.status = status | ||||
| } | ||||
|  | ||||
| // CacheBusters maintains a cache of cache busting tokens for static resources served by Handler. | ||||
| type CacheBusters struct { | ||||
| 	Handler http.Handler | ||||
|  | ||||
| 	mu     sync.Mutex | ||||
| 	tokens map[string]string | ||||
| } | ||||
|  | ||||
| func sanitizeTokenRune(r rune) rune { | ||||
| 	if r <= ' ' || r >= 127 { | ||||
| 		return -1 | ||||
| 	} | ||||
| 	// Convert percent encoding reserved characters to '-'. | ||||
| 	if strings.ContainsRune("!#$&'()*+,/:;=?@[]", r) { | ||||
| 		return '-' | ||||
| 	} | ||||
| 	return r | ||||
| } | ||||
|  | ||||
| // Get returns the cache busting token for path. If the token is not already | ||||
| // cached, Get issues a HEAD request on handler and uses the response ETag and | ||||
| // Last-Modified headers to compute a token. | ||||
| func (cb *CacheBusters) Get(path string) string { | ||||
| 	cb.mu.Lock() | ||||
| 	if cb.tokens == nil { | ||||
| 		cb.tokens = make(map[string]string) | ||||
| 	} | ||||
| 	token, ok := cb.tokens[path] | ||||
| 	cb.mu.Unlock() | ||||
| 	if ok { | ||||
| 		return token | ||||
| 	} | ||||
|  | ||||
| 	w := busterWriter{ | ||||
| 		Writer:    ioutil.Discard, | ||||
| 		headerMap: make(http.Header), | ||||
| 	} | ||||
| 	r := &http.Request{URL: &url.URL{Path: path}, Method: "HEAD"} | ||||
| 	cb.Handler.ServeHTTP(&w, r) | ||||
|  | ||||
| 	if w.status == 200 { | ||||
| 		token = w.headerMap.Get("Etag") | ||||
| 		if token == "" { | ||||
| 			token = w.headerMap.Get("Last-Modified") | ||||
| 		} | ||||
| 		token = strings.Trim(token, `" `) | ||||
| 		token = strings.Map(sanitizeTokenRune, token) | ||||
| 	} | ||||
|  | ||||
| 	cb.mu.Lock() | ||||
| 	cb.tokens[path] = token | ||||
| 	cb.mu.Unlock() | ||||
|  | ||||
| 	return token | ||||
| } | ||||
|  | ||||
| // AppendQueryParam appends the token as a query parameter to path. | ||||
| func (cb *CacheBusters) AppendQueryParam(path string, name string) string { | ||||
| 	token := cb.Get(path) | ||||
| 	if token == "" { | ||||
| 		return path | ||||
| 	} | ||||
| 	return path + "?" + name + "=" + token | ||||
| } | ||||
							
								
								
									
										298
									
								
								vendor/github.com/golang/gddo/httputil/header/header.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										298
									
								
								vendor/github.com/golang/gddo/httputil/header/header.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,298 @@ | ||||
| // Copyright 2013 The Go Authors. All rights reserved. | ||||
| // | ||||
| // Use of this source code is governed by a BSD-style | ||||
| // license that can be found in the LICENSE file or at | ||||
| // https://developers.google.com/open-source/licenses/bsd. | ||||
|  | ||||
| // Package header provides functions for parsing HTTP headers. | ||||
| package header | ||||
|  | ||||
| import ( | ||||
| 	"net/http" | ||||
| 	"strings" | ||||
| 	"time" | ||||
| ) | ||||
|  | ||||
| // Octet types from RFC 2616. | ||||
| var octetTypes [256]octetType | ||||
|  | ||||
| type octetType byte | ||||
|  | ||||
| const ( | ||||
| 	isToken octetType = 1 << iota | ||||
| 	isSpace | ||||
| ) | ||||
|  | ||||
| func init() { | ||||
| 	// OCTET      = <any 8-bit sequence of data> | ||||
| 	// CHAR       = <any US-ASCII character (octets 0 - 127)> | ||||
| 	// CTL        = <any US-ASCII control character (octets 0 - 31) and DEL (127)> | ||||
| 	// CR         = <US-ASCII CR, carriage return (13)> | ||||
| 	// LF         = <US-ASCII LF, linefeed (10)> | ||||
| 	// SP         = <US-ASCII SP, space (32)> | ||||
| 	// HT         = <US-ASCII HT, horizontal-tab (9)> | ||||
| 	// <">        = <US-ASCII double-quote mark (34)> | ||||
| 	// CRLF       = CR LF | ||||
| 	// LWS        = [CRLF] 1*( SP | HT ) | ||||
| 	// TEXT       = <any OCTET except CTLs, but including LWS> | ||||
| 	// separators = "(" | ")" | "<" | ">" | "@" | "," | ";" | ":" | "\" | <"> | ||||
| 	//              | "/" | "[" | "]" | "?" | "=" | "{" | "}" | SP | HT | ||||
| 	// token      = 1*<any CHAR except CTLs or separators> | ||||
| 	// qdtext     = <any TEXT except <">> | ||||
|  | ||||
| 	for c := 0; c < 256; c++ { | ||||
| 		var t octetType | ||||
| 		isCtl := c <= 31 || c == 127 | ||||
| 		isChar := 0 <= c && c <= 127 | ||||
| 		isSeparator := strings.IndexRune(" \t\"(),/:;<=>?@[]\\{}", rune(c)) >= 0 | ||||
| 		if strings.IndexRune(" \t\r\n", rune(c)) >= 0 { | ||||
| 			t |= isSpace | ||||
| 		} | ||||
| 		if isChar && !isCtl && !isSeparator { | ||||
| 			t |= isToken | ||||
| 		} | ||||
| 		octetTypes[c] = t | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // Copy returns a shallow copy of the header. | ||||
| func Copy(header http.Header) http.Header { | ||||
| 	h := make(http.Header) | ||||
| 	for k, vs := range header { | ||||
| 		h[k] = vs | ||||
| 	} | ||||
| 	return h | ||||
| } | ||||
|  | ||||
| var timeLayouts = []string{"Mon, 02 Jan 2006 15:04:05 GMT", time.RFC850, time.ANSIC} | ||||
|  | ||||
| // ParseTime parses the header as time. The zero value is returned if the | ||||
| // header is not present or there is an error parsing the | ||||
| // header. | ||||
| func ParseTime(header http.Header, key string) time.Time { | ||||
| 	if s := header.Get(key); s != "" { | ||||
| 		for _, layout := range timeLayouts { | ||||
| 			if t, err := time.Parse(layout, s); err == nil { | ||||
| 				return t.UTC() | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	return time.Time{} | ||||
| } | ||||
|  | ||||
| // ParseList parses a comma separated list of values. Commas are ignored in | ||||
| // quoted strings. Quoted values are not unescaped or unquoted. Whitespace is | ||||
| // trimmed. | ||||
| func ParseList(header http.Header, key string) []string { | ||||
| 	var result []string | ||||
| 	for _, s := range header[http.CanonicalHeaderKey(key)] { | ||||
| 		begin := 0 | ||||
| 		end := 0 | ||||
| 		escape := false | ||||
| 		quote := false | ||||
| 		for i := 0; i < len(s); i++ { | ||||
| 			b := s[i] | ||||
| 			switch { | ||||
| 			case escape: | ||||
| 				escape = false | ||||
| 				end = i + 1 | ||||
| 			case quote: | ||||
| 				switch b { | ||||
| 				case '\\': | ||||
| 					escape = true | ||||
| 				case '"': | ||||
| 					quote = false | ||||
| 				} | ||||
| 				end = i + 1 | ||||
| 			case b == '"': | ||||
| 				quote = true | ||||
| 				end = i + 1 | ||||
| 			case octetTypes[b]&isSpace != 0: | ||||
| 				if begin == end { | ||||
| 					begin = i + 1 | ||||
| 					end = begin | ||||
| 				} | ||||
| 			case b == ',': | ||||
| 				if begin < end { | ||||
| 					result = append(result, s[begin:end]) | ||||
| 				} | ||||
| 				begin = i + 1 | ||||
| 				end = begin | ||||
| 			default: | ||||
| 				end = i + 1 | ||||
| 			} | ||||
| 		} | ||||
| 		if begin < end { | ||||
| 			result = append(result, s[begin:end]) | ||||
| 		} | ||||
| 	} | ||||
| 	return result | ||||
| } | ||||
|  | ||||
| // ParseValueAndParams parses a comma separated list of values with optional | ||||
| // semicolon separated name-value pairs. Content-Type and Content-Disposition | ||||
| // headers are in this format. | ||||
| func ParseValueAndParams(header http.Header, key string) (value string, params map[string]string) { | ||||
| 	params = make(map[string]string) | ||||
| 	s := header.Get(key) | ||||
| 	value, s = expectTokenSlash(s) | ||||
| 	if value == "" { | ||||
| 		return | ||||
| 	} | ||||
| 	value = strings.ToLower(value) | ||||
| 	s = skipSpace(s) | ||||
| 	for strings.HasPrefix(s, ";") { | ||||
| 		var pkey string | ||||
| 		pkey, s = expectToken(skipSpace(s[1:])) | ||||
| 		if pkey == "" { | ||||
| 			return | ||||
| 		} | ||||
| 		if !strings.HasPrefix(s, "=") { | ||||
| 			return | ||||
| 		} | ||||
| 		var pvalue string | ||||
| 		pvalue, s = expectTokenOrQuoted(s[1:]) | ||||
| 		if pvalue == "" { | ||||
| 			return | ||||
| 		} | ||||
| 		pkey = strings.ToLower(pkey) | ||||
| 		params[pkey] = pvalue | ||||
| 		s = skipSpace(s) | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // AcceptSpec describes an Accept* header. | ||||
| type AcceptSpec struct { | ||||
| 	Value string | ||||
| 	Q     float64 | ||||
| } | ||||
|  | ||||
| // ParseAccept parses Accept* headers. | ||||
| func ParseAccept(header http.Header, key string) (specs []AcceptSpec) { | ||||
| loop: | ||||
| 	for _, s := range header[key] { | ||||
| 		for { | ||||
| 			var spec AcceptSpec | ||||
| 			spec.Value, s = expectTokenSlash(s) | ||||
| 			if spec.Value == "" { | ||||
| 				continue loop | ||||
| 			} | ||||
| 			spec.Q = 1.0 | ||||
| 			s = skipSpace(s) | ||||
| 			if strings.HasPrefix(s, ";") { | ||||
| 				s = skipSpace(s[1:]) | ||||
| 				if !strings.HasPrefix(s, "q=") { | ||||
| 					continue loop | ||||
| 				} | ||||
| 				spec.Q, s = expectQuality(s[2:]) | ||||
| 				if spec.Q < 0.0 { | ||||
| 					continue loop | ||||
| 				} | ||||
| 			} | ||||
| 			specs = append(specs, spec) | ||||
| 			s = skipSpace(s) | ||||
| 			if !strings.HasPrefix(s, ",") { | ||||
| 				continue loop | ||||
| 			} | ||||
| 			s = skipSpace(s[1:]) | ||||
| 		} | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func skipSpace(s string) (rest string) { | ||||
| 	i := 0 | ||||
| 	for ; i < len(s); i++ { | ||||
| 		if octetTypes[s[i]]&isSpace == 0 { | ||||
| 			break | ||||
| 		} | ||||
| 	} | ||||
| 	return s[i:] | ||||
| } | ||||
|  | ||||
| func expectToken(s string) (token, rest string) { | ||||
| 	i := 0 | ||||
| 	for ; i < len(s); i++ { | ||||
| 		if octetTypes[s[i]]&isToken == 0 { | ||||
| 			break | ||||
| 		} | ||||
| 	} | ||||
| 	return s[:i], s[i:] | ||||
| } | ||||
|  | ||||
| func expectTokenSlash(s string) (token, rest string) { | ||||
| 	i := 0 | ||||
| 	for ; i < len(s); i++ { | ||||
| 		b := s[i] | ||||
| 		if (octetTypes[b]&isToken == 0) && b != '/' { | ||||
| 			break | ||||
| 		} | ||||
| 	} | ||||
| 	return s[:i], s[i:] | ||||
| } | ||||
|  | ||||
| func expectQuality(s string) (q float64, rest string) { | ||||
| 	switch { | ||||
| 	case len(s) == 0: | ||||
| 		return -1, "" | ||||
| 	case s[0] == '0': | ||||
| 		q = 0 | ||||
| 	case s[0] == '1': | ||||
| 		q = 1 | ||||
| 	default: | ||||
| 		return -1, "" | ||||
| 	} | ||||
| 	s = s[1:] | ||||
| 	if !strings.HasPrefix(s, ".") { | ||||
| 		return q, s | ||||
| 	} | ||||
| 	s = s[1:] | ||||
| 	i := 0 | ||||
| 	n := 0 | ||||
| 	d := 1 | ||||
| 	for ; i < len(s); i++ { | ||||
| 		b := s[i] | ||||
| 		if b < '0' || b > '9' { | ||||
| 			break | ||||
| 		} | ||||
| 		n = n*10 + int(b) - '0' | ||||
| 		d *= 10 | ||||
| 	} | ||||
| 	return q + float64(n)/float64(d), s[i:] | ||||
| } | ||||
|  | ||||
| func expectTokenOrQuoted(s string) (value string, rest string) { | ||||
| 	if !strings.HasPrefix(s, "\"") { | ||||
| 		return expectToken(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 "", "" | ||||
| } | ||||
							
								
								
									
										25
									
								
								vendor/github.com/golang/gddo/httputil/httputil.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								vendor/github.com/golang/gddo/httputil/httputil.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,25 @@ | ||||
| // Copyright 2013 The Go Authors. All rights reserved. | ||||
| // | ||||
| // Use of this source code is governed by a BSD-style | ||||
| // license that can be found in the LICENSE file or at | ||||
| // https://developers.google.com/open-source/licenses/bsd. | ||||
|  | ||||
| // Package httputil is a toolkit for the Go net/http package. | ||||
| package httputil | ||||
|  | ||||
| import ( | ||||
| 	"net" | ||||
| 	"net/http" | ||||
| ) | ||||
|  | ||||
| // StripPort removes the port specification from an address. | ||||
| func StripPort(s string) string { | ||||
| 	if h, _, err := net.SplitHostPort(s); err == nil { | ||||
| 		s = h | ||||
| 	} | ||||
| 	return s | ||||
| } | ||||
|  | ||||
| // Error defines a type for a function that accepts a ResponseWriter for | ||||
| // a Request with the HTTP status code and error. | ||||
| type Error func(w http.ResponseWriter, r *http.Request, status int, err error) | ||||
							
								
								
									
										79
									
								
								vendor/github.com/golang/gddo/httputil/negotiate.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										79
									
								
								vendor/github.com/golang/gddo/httputil/negotiate.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,79 @@ | ||||
| // Copyright 2013 The Go Authors. All rights reserved. | ||||
| // | ||||
| // Use of this source code is governed by a BSD-style | ||||
| // license that can be found in the LICENSE file or at | ||||
| // https://developers.google.com/open-source/licenses/bsd. | ||||
|  | ||||
| package httputil | ||||
|  | ||||
| import ( | ||||
| 	"github.com/golang/gddo/httputil/header" | ||||
| 	"net/http" | ||||
| 	"strings" | ||||
| ) | ||||
|  | ||||
| // NegotiateContentEncoding returns the best offered content encoding for the | ||||
| // request's Accept-Encoding header. If two offers match with equal weight and | ||||
| // then the offer earlier in the list is preferred. If no offers are | ||||
| // acceptable, then "" is returned. | ||||
| func NegotiateContentEncoding(r *http.Request, offers []string) string { | ||||
| 	bestOffer := "identity" | ||||
| 	bestQ := -1.0 | ||||
| 	specs := header.ParseAccept(r.Header, "Accept-Encoding") | ||||
| 	for _, offer := range offers { | ||||
| 		for _, spec := range specs { | ||||
| 			if spec.Q > bestQ && | ||||
| 				(spec.Value == "*" || spec.Value == offer) { | ||||
| 				bestQ = spec.Q | ||||
| 				bestOffer = offer | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	if bestQ == 0 { | ||||
| 		bestOffer = "" | ||||
| 	} | ||||
| 	return bestOffer | ||||
| } | ||||
|  | ||||
| // NegotiateContentType returns the best offered content type for the request's | ||||
| // Accept header. If two offers match with equal weight, then the more specific | ||||
| // offer is preferred.  For example, text/* trumps */*. If two offers match | ||||
| // with equal weight and specificity, then the offer earlier in the list is | ||||
| // preferred. If no offers match, then defaultOffer is returned. | ||||
| func NegotiateContentType(r *http.Request, offers []string, defaultOffer string) string { | ||||
| 	bestOffer := defaultOffer | ||||
| 	bestQ := -1.0 | ||||
| 	bestWild := 3 | ||||
| 	specs := header.ParseAccept(r.Header, "Accept") | ||||
| 	for _, offer := range offers { | ||||
| 		for _, spec := range specs { | ||||
| 			switch { | ||||
| 			case spec.Q == 0.0: | ||||
| 				// ignore | ||||
| 			case spec.Q < bestQ: | ||||
| 				// better match found | ||||
| 			case spec.Value == "*/*": | ||||
| 				if spec.Q > bestQ || bestWild > 2 { | ||||
| 					bestQ = spec.Q | ||||
| 					bestWild = 2 | ||||
| 					bestOffer = offer | ||||
| 				} | ||||
| 			case strings.HasSuffix(spec.Value, "/*"): | ||||
| 				if strings.HasPrefix(offer, spec.Value[:len(spec.Value)-1]) && | ||||
| 					(spec.Q > bestQ || bestWild > 1) { | ||||
| 					bestQ = spec.Q | ||||
| 					bestWild = 1 | ||||
| 					bestOffer = offer | ||||
| 				} | ||||
| 			default: | ||||
| 				if spec.Value == offer && | ||||
| 					(spec.Q > bestQ || bestWild > 0) { | ||||
| 					bestQ = spec.Q | ||||
| 					bestWild = 0 | ||||
| 					bestOffer = offer | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	return bestOffer | ||||
| } | ||||
							
								
								
									
										58
									
								
								vendor/github.com/golang/gddo/httputil/respbuf.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								vendor/github.com/golang/gddo/httputil/respbuf.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,58 @@ | ||||
| // Copyright 2013 The Go Authors. All rights reserved. | ||||
| // | ||||
| // Use of this source code is governed by a BSD-style | ||||
| // license that can be found in the LICENSE file or at | ||||
| // https://developers.google.com/open-source/licenses/bsd. | ||||
|  | ||||
| package httputil | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"net/http" | ||||
| 	"strconv" | ||||
| ) | ||||
|  | ||||
| // ResponseBuffer is the current response being composed by its owner. | ||||
| // It implements http.ResponseWriter and io.WriterTo. | ||||
| type ResponseBuffer struct { | ||||
| 	buf    bytes.Buffer | ||||
| 	status int | ||||
| 	header http.Header | ||||
| } | ||||
|  | ||||
| // Write implements the http.ResponseWriter interface. | ||||
| func (rb *ResponseBuffer) Write(p []byte) (int, error) { | ||||
| 	return rb.buf.Write(p) | ||||
| } | ||||
|  | ||||
| // WriteHeader implements the http.ResponseWriter interface. | ||||
| func (rb *ResponseBuffer) WriteHeader(status int) { | ||||
| 	rb.status = status | ||||
| } | ||||
|  | ||||
| // Header implements the http.ResponseWriter interface. | ||||
| func (rb *ResponseBuffer) Header() http.Header { | ||||
| 	if rb.header == nil { | ||||
| 		rb.header = make(http.Header) | ||||
| 	} | ||||
| 	return rb.header | ||||
| } | ||||
|  | ||||
| // WriteTo implements the io.WriterTo interface. | ||||
| func (rb *ResponseBuffer) WriteTo(w http.ResponseWriter) error { | ||||
| 	for k, v := range rb.header { | ||||
| 		w.Header()[k] = v | ||||
| 	} | ||||
| 	if rb.buf.Len() > 0 { | ||||
| 		w.Header().Set("Content-Length", strconv.Itoa(rb.buf.Len())) | ||||
| 	} | ||||
| 	if rb.status != 0 { | ||||
| 		w.WriteHeader(rb.status) | ||||
| 	} | ||||
| 	if rb.buf.Len() > 0 { | ||||
| 		if _, err := w.Write(rb.buf.Bytes()); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
							
								
								
									
										265
									
								
								vendor/github.com/golang/gddo/httputil/static.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										265
									
								
								vendor/github.com/golang/gddo/httputil/static.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,265 @@ | ||||
| // Copyright 2013 The Go Authors. All rights reserved. | ||||
| // | ||||
| // Use of this source code is governed by a BSD-style | ||||
| // license that can be found in the LICENSE file or at | ||||
| // https://developers.google.com/open-source/licenses/bsd. | ||||
|  | ||||
| package httputil | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"crypto/sha1" | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"github.com/golang/gddo/httputil/header" | ||||
| 	"io" | ||||
| 	"io/ioutil" | ||||
| 	"mime" | ||||
| 	"net/http" | ||||
| 	"os" | ||||
| 	"path" | ||||
| 	"path/filepath" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
| 	"sync" | ||||
| 	"time" | ||||
| ) | ||||
|  | ||||
| // StaticServer serves static files. | ||||
| type StaticServer struct { | ||||
| 	// Dir specifies the location of the directory containing the files to serve. | ||||
| 	Dir string | ||||
|  | ||||
| 	// MaxAge specifies the maximum age for the cache control and expiration | ||||
| 	// headers. | ||||
| 	MaxAge time.Duration | ||||
|  | ||||
| 	// Error specifies the function used to generate error responses. If Error | ||||
| 	// is nil, then http.Error is used to generate error responses. | ||||
| 	Error Error | ||||
|  | ||||
| 	// MIMETypes is a map from file extensions to MIME types. | ||||
| 	MIMETypes map[string]string | ||||
|  | ||||
| 	mu    sync.Mutex | ||||
| 	etags map[string]string | ||||
| } | ||||
|  | ||||
| func (ss *StaticServer) resolve(fname string) string { | ||||
| 	if path.IsAbs(fname) { | ||||
| 		panic("Absolute path not allowed when creating a StaticServer handler") | ||||
| 	} | ||||
| 	dir := ss.Dir | ||||
| 	if dir == "" { | ||||
| 		dir = "." | ||||
| 	} | ||||
| 	fname = filepath.FromSlash(fname) | ||||
| 	return filepath.Join(dir, fname) | ||||
| } | ||||
|  | ||||
| func (ss *StaticServer) mimeType(fname string) string { | ||||
| 	ext := path.Ext(fname) | ||||
| 	var mimeType string | ||||
| 	if ss.MIMETypes != nil { | ||||
| 		mimeType = ss.MIMETypes[ext] | ||||
| 	} | ||||
| 	if mimeType == "" { | ||||
| 		mimeType = mime.TypeByExtension(ext) | ||||
| 	} | ||||
| 	if mimeType == "" { | ||||
| 		mimeType = "application/octet-stream" | ||||
| 	} | ||||
| 	return mimeType | ||||
| } | ||||
|  | ||||
| func (ss *StaticServer) openFile(fname string) (io.ReadCloser, int64, string, error) { | ||||
| 	f, err := os.Open(fname) | ||||
| 	if err != nil { | ||||
| 		return nil, 0, "", err | ||||
| 	} | ||||
| 	fi, err := f.Stat() | ||||
| 	if err != nil { | ||||
| 		f.Close() | ||||
| 		return nil, 0, "", err | ||||
| 	} | ||||
| 	const modeType = os.ModeDir | os.ModeSymlink | os.ModeNamedPipe | os.ModeSocket | os.ModeDevice | ||||
| 	if fi.Mode()&modeType != 0 { | ||||
| 		f.Close() | ||||
| 		return nil, 0, "", errors.New("not a regular file") | ||||
| 	} | ||||
| 	return f, fi.Size(), ss.mimeType(fname), nil | ||||
| } | ||||
|  | ||||
| // FileHandler returns a handler that serves a single file. The file is | ||||
| // specified by a slash separated path relative to the static server's Dir | ||||
| // field. | ||||
| func (ss *StaticServer) FileHandler(fileName string) http.Handler { | ||||
| 	id := fileName | ||||
| 	fileName = ss.resolve(fileName) | ||||
| 	return &staticHandler{ | ||||
| 		ss:   ss, | ||||
| 		id:   func(_ string) string { return id }, | ||||
| 		open: func(_ string) (io.ReadCloser, int64, string, error) { return ss.openFile(fileName) }, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // DirectoryHandler returns a handler that serves files from a directory tree. | ||||
| // The directory is specified by a slash separated path relative to the static | ||||
| // server's Dir field. | ||||
| func (ss *StaticServer) DirectoryHandler(prefix, dirName string) http.Handler { | ||||
| 	if !strings.HasSuffix(prefix, "/") { | ||||
| 		prefix += "/" | ||||
| 	} | ||||
| 	idBase := dirName | ||||
| 	dirName = ss.resolve(dirName) | ||||
| 	return &staticHandler{ | ||||
| 		ss: ss, | ||||
| 		id: func(p string) string { | ||||
| 			if !strings.HasPrefix(p, prefix) { | ||||
| 				return "." | ||||
| 			} | ||||
| 			return path.Join(idBase, p[len(prefix):]) | ||||
| 		}, | ||||
| 		open: func(p string) (io.ReadCloser, int64, string, error) { | ||||
| 			if !strings.HasPrefix(p, prefix) { | ||||
| 				return nil, 0, "", errors.New("request url does not match directory prefix") | ||||
| 			} | ||||
| 			p = p[len(prefix):] | ||||
| 			return ss.openFile(filepath.Join(dirName, filepath.FromSlash(p))) | ||||
| 		}, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // FilesHandler returns a handler that serves the concatentation of the | ||||
| // specified files. The files are specified by slash separated paths relative | ||||
| // to the static server's Dir field. | ||||
| func (ss *StaticServer) FilesHandler(fileNames ...string) http.Handler { | ||||
|  | ||||
| 	// todo: cache concatenated files on disk and serve from there. | ||||
|  | ||||
| 	mimeType := ss.mimeType(fileNames[0]) | ||||
| 	var buf []byte | ||||
| 	var openErr error | ||||
|  | ||||
| 	for _, fileName := range fileNames { | ||||
| 		p, err := ioutil.ReadFile(ss.resolve(fileName)) | ||||
| 		if err != nil { | ||||
| 			openErr = err | ||||
| 			buf = nil | ||||
| 			break | ||||
| 		} | ||||
| 		buf = append(buf, p...) | ||||
| 	} | ||||
|  | ||||
| 	id := strings.Join(fileNames, " ") | ||||
|  | ||||
| 	return &staticHandler{ | ||||
| 		ss: ss, | ||||
| 		id: func(_ string) string { return id }, | ||||
| 		open: func(p string) (io.ReadCloser, int64, string, error) { | ||||
| 			return ioutil.NopCloser(bytes.NewReader(buf)), int64(len(buf)), mimeType, openErr | ||||
| 		}, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| type staticHandler struct { | ||||
| 	id   func(fname string) string | ||||
| 	open func(p string) (io.ReadCloser, int64, string, error) | ||||
| 	ss   *StaticServer | ||||
| } | ||||
|  | ||||
| func (h *staticHandler) error(w http.ResponseWriter, r *http.Request, status int, err error) { | ||||
| 	http.Error(w, http.StatusText(status), status) | ||||
| } | ||||
|  | ||||
| func (h *staticHandler) etag(p string) (string, error) { | ||||
| 	id := h.id(p) | ||||
|  | ||||
| 	h.ss.mu.Lock() | ||||
| 	if h.ss.etags == nil { | ||||
| 		h.ss.etags = make(map[string]string) | ||||
| 	} | ||||
| 	etag := h.ss.etags[id] | ||||
| 	h.ss.mu.Unlock() | ||||
|  | ||||
| 	if etag != "" { | ||||
| 		return etag, nil | ||||
| 	} | ||||
|  | ||||
| 	// todo: if a concurrent goroutine is calculating the hash, then wait for | ||||
| 	// it instead of computing it again here. | ||||
|  | ||||
| 	rc, _, _, err := h.open(p) | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
|  | ||||
| 	defer rc.Close() | ||||
|  | ||||
| 	w := sha1.New() | ||||
| 	_, err = io.Copy(w, rc) | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
|  | ||||
| 	etag = fmt.Sprintf(`"%x"`, w.Sum(nil)) | ||||
|  | ||||
| 	h.ss.mu.Lock() | ||||
| 	h.ss.etags[id] = etag | ||||
| 	h.ss.mu.Unlock() | ||||
|  | ||||
| 	return etag, nil | ||||
| } | ||||
|  | ||||
| func (h *staticHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { | ||||
| 	p := path.Clean(r.URL.Path) | ||||
| 	if p != r.URL.Path { | ||||
| 		http.Redirect(w, r, p, 301) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	etag, err := h.etag(p) | ||||
| 	if err != nil { | ||||
| 		h.error(w, r, http.StatusNotFound, err) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	maxAge := h.ss.MaxAge | ||||
| 	if maxAge == 0 { | ||||
| 		maxAge = 24 * time.Hour | ||||
| 	} | ||||
| 	if r.FormValue("v") != "" { | ||||
| 		maxAge = 365 * 24 * time.Hour | ||||
| 	} | ||||
|  | ||||
| 	cacheControl := fmt.Sprintf("public, max-age=%d", maxAge/time.Second) | ||||
|  | ||||
| 	for _, e := range header.ParseList(r.Header, "If-None-Match") { | ||||
| 		if e == etag { | ||||
| 			w.Header().Set("Cache-Control", cacheControl) | ||||
| 			w.Header().Set("Etag", etag) | ||||
| 			w.WriteHeader(http.StatusNotModified) | ||||
| 			return | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	rc, cl, ct, err := h.open(p) | ||||
| 	if err != nil { | ||||
| 		h.error(w, r, http.StatusNotFound, err) | ||||
| 		return | ||||
| 	} | ||||
| 	defer rc.Close() | ||||
|  | ||||
| 	w.Header().Set("Cache-Control", cacheControl) | ||||
| 	w.Header().Set("Etag", etag) | ||||
| 	if ct != "" { | ||||
| 		w.Header().Set("Content-Type", ct) | ||||
| 	} | ||||
| 	if cl != 0 { | ||||
| 		w.Header().Set("Content-Length", strconv.FormatInt(cl, 10)) | ||||
| 	} | ||||
| 	w.WriteHeader(http.StatusOK) | ||||
| 	if r.Method != "HEAD" { | ||||
| 		io.Copy(w, rc) | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										87
									
								
								vendor/github.com/golang/gddo/httputil/transport.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										87
									
								
								vendor/github.com/golang/gddo/httputil/transport.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,87 @@ | ||||
| // Copyright 2015 The Go Authors. All rights reserved. | ||||
| // | ||||
| // Use of this source code is governed by a BSD-style | ||||
| // license that can be found in the LICENSE file or at | ||||
| // https://developers.google.com/open-source/licenses/bsd. | ||||
|  | ||||
| // This file implements a http.RoundTripper that authenticates | ||||
| // requests issued against api.github.com endpoint. | ||||
|  | ||||
| package httputil | ||||
|  | ||||
| import ( | ||||
| 	"net/http" | ||||
| 	"net/url" | ||||
| ) | ||||
|  | ||||
| // AuthTransport is an implementation of http.RoundTripper that authenticates | ||||
| // with the GitHub API. | ||||
| // | ||||
| // When both a token and client credentials are set, the latter is preferred. | ||||
| type AuthTransport struct { | ||||
| 	UserAgent          string | ||||
| 	GithubToken        string | ||||
| 	GithubClientID     string | ||||
| 	GithubClientSecret string | ||||
| 	Base               http.RoundTripper | ||||
| } | ||||
|  | ||||
| // RoundTrip implements the http.RoundTripper interface. | ||||
| func (t *AuthTransport) RoundTrip(req *http.Request) (*http.Response, error) { | ||||
| 	var reqCopy *http.Request | ||||
| 	if t.UserAgent != "" { | ||||
| 		reqCopy = copyRequest(req) | ||||
| 		reqCopy.Header.Set("User-Agent", t.UserAgent) | ||||
| 	} | ||||
| 	if req.URL.Host == "api.github.com" && req.URL.Scheme == "https" { | ||||
| 		switch { | ||||
| 		case t.GithubClientID != "" && t.GithubClientSecret != "": | ||||
| 			if reqCopy == nil { | ||||
| 				reqCopy = copyRequest(req) | ||||
| 			} | ||||
| 			if reqCopy.URL.RawQuery == "" { | ||||
| 				reqCopy.URL.RawQuery = "client_id=" + t.GithubClientID + "&client_secret=" + t.GithubClientSecret | ||||
| 			} else { | ||||
| 				reqCopy.URL.RawQuery += "&client_id=" + t.GithubClientID + "&client_secret=" + t.GithubClientSecret | ||||
| 			} | ||||
| 		case t.GithubToken != "": | ||||
| 			if reqCopy == nil { | ||||
| 				reqCopy = copyRequest(req) | ||||
| 			} | ||||
| 			reqCopy.Header.Set("Authorization", "token "+t.GithubToken) | ||||
| 		} | ||||
| 	} | ||||
| 	if reqCopy != nil { | ||||
| 		return t.base().RoundTrip(reqCopy) | ||||
| 	} | ||||
| 	return t.base().RoundTrip(req) | ||||
| } | ||||
|  | ||||
| // CancelRequest cancels an in-flight request by closing its connection. | ||||
| func (t *AuthTransport) CancelRequest(req *http.Request) { | ||||
| 	type canceler interface { | ||||
| 		CancelRequest(req *http.Request) | ||||
| 	} | ||||
| 	if cr, ok := t.base().(canceler); ok { | ||||
| 		cr.CancelRequest(req) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (t *AuthTransport) base() http.RoundTripper { | ||||
| 	if t.Base != nil { | ||||
| 		return t.Base | ||||
| 	} | ||||
| 	return http.DefaultTransport | ||||
| } | ||||
|  | ||||
| func copyRequest(req *http.Request) *http.Request { | ||||
| 	req2 := new(http.Request) | ||||
| 	*req2 = *req | ||||
| 	req2.URL = new(url.URL) | ||||
| 	*req2.URL = *req.URL | ||||
| 	req2.Header = make(http.Header, len(req.Header)) | ||||
| 	for k, s := range req.Header { | ||||
| 		req2.Header[k] = append([]string(nil), s...) | ||||
| 	} | ||||
| 	return req2 | ||||
| } | ||||
		Reference in New Issue
	
	Block a user
	 PhilippHomann
					PhilippHomann