| // 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 |
| } |