mirror of
				https://github.com/go-gitea/gitea
				synced 2025-10-31 03:18:24 +00:00 
			
		
		
		
	* update github.com/alecthomas/chroma v0.8.0 -> v0.8.1 * github.com/blevesearch/bleve v1.0.10 -> v1.0.12 * editorconfig-core-go v2.1.1 -> v2.3.7 * github.com/gliderlabs/ssh v0.2.2 -> v0.3.1 * migrate editorconfig.ParseBytes to Parse * github.com/shurcooL/vfsgen to 0d455de96546 * github.com/go-git/go-git/v5 v5.1.0 -> v5.2.0 * github.com/google/uuid v1.1.1 -> v1.1.2 * github.com/huandu/xstrings v1.3.0 -> v1.3.2 * github.com/klauspost/compress v1.10.11 -> v1.11.1 * github.com/markbates/goth v1.61.2 -> v1.65.0 * github.com/mattn/go-sqlite3 v1.14.0 -> v1.14.4 * github.com/mholt/archiver v3.3.0 -> v3.3.2 * github.com/microcosm-cc/bluemonday 4f7140c49acb -> v1.0.4 * github.com/minio/minio-go v7.0.4 -> v7.0.5 * github.com/olivere/elastic v7.0.9 -> v7.0.20 * github.com/urfave/cli v1.20.0 -> v1.22.4 * github.com/prometheus/client_golang v1.1.0 -> v1.8.0 * github.com/xanzy/go-gitlab v0.37.0 -> v0.38.1 * mvdan.cc/xurls v2.1.0 -> v2.2.0 Co-authored-by: Lauris BH <lauris@nix.lv>
		
			
				
	
	
		
			193 lines
		
	
	
		
			4.4 KiB
		
	
	
	
		
			Go
		
	
	
	
		
			Vendored
		
	
	
	
			
		
		
	
	
			193 lines
		
	
	
		
			4.4 KiB
		
	
	
	
		
			Go
		
	
	
	
		
			Vendored
		
	
	
	
| package brotli
 | |
| 
 | |
| import (
 | |
| 	"compress/gzip"
 | |
| 	"io"
 | |
| 	"net/http"
 | |
| 	"strings"
 | |
| )
 | |
| 
 | |
| // HTTPCompressor chooses a compression method (brotli, gzip, or none) based on
 | |
| // the Accept-Encoding header, sets the Content-Encoding header, and returns a
 | |
| // WriteCloser that implements that compression. The Close method must be called
 | |
| // before the current HTTP handler returns.
 | |
| //
 | |
| // Due to https://github.com/golang/go/issues/31753, the response will not be
 | |
| // compressed unless you set a Content-Type header before you call
 | |
| // HTTPCompressor.
 | |
| func HTTPCompressor(w http.ResponseWriter, r *http.Request) io.WriteCloser {
 | |
| 	if w.Header().Get("Content-Type") == "" {
 | |
| 		return nopCloser{w}
 | |
| 	}
 | |
| 
 | |
| 	if w.Header().Get("Vary") == "" {
 | |
| 		w.Header().Set("Vary", "Accept-Encoding")
 | |
| 	}
 | |
| 
 | |
| 	encoding := negotiateContentEncoding(r, []string{"br", "gzip"})
 | |
| 	switch encoding {
 | |
| 	case "br":
 | |
| 		w.Header().Set("Content-Encoding", "br")
 | |
| 		return NewWriter(w)
 | |
| 	case "gzip":
 | |
| 		w.Header().Set("Content-Encoding", "gzip")
 | |
| 		return gzip.NewWriter(w)
 | |
| 	}
 | |
| 	return nopCloser{w}
 | |
| }
 | |
| 
 | |
| // 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 := 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
 | |
| }
 | |
| 
 | |
| // 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 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:]
 | |
| }
 | |
| 
 | |
| // 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
 | |
| 	}
 | |
| }
 |