aboutsummaryrefslogtreecommitdiff
path: root/httputil/negotiate.go
diff options
context:
space:
mode:
Diffstat (limited to 'httputil/negotiate.go')
-rw-r--r--httputil/negotiate.go79
1 files changed, 79 insertions, 0 deletions
diff --git a/httputil/negotiate.go b/httputil/negotiate.go
new file mode 100644
index 0000000..6af3e4c
--- /dev/null
+++ b/httputil/negotiate.go
@@ -0,0 +1,79 @@
1// Copyright 2013 The Go Authors. All rights reserved.
2//
3// Use of this source code is governed by a BSD-style
4// license that can be found in the LICENSE file or at
5// https://developers.google.com/open-source/licenses/bsd.
6
7package httputil
8
9import (
10 "github.com/golang/gddo/httputil/header"
11 "net/http"
12 "strings"
13)
14
15// NegotiateContentEncoding returns the best offered content encoding for the
16// request's Accept-Encoding header. If two offers match with equal weight and
17// then the offer earlier in the list is preferred. If no offers are
18// acceptable, then "" is returned.
19func NegotiateContentEncoding(r *http.Request, offers []string) string {
20 bestOffer := "identity"
21 bestQ := -1.0
22 specs := header.ParseAccept(r.Header, "Accept-Encoding")
23 for _, offer := range offers {
24 for _, spec := range specs {
25 if spec.Q > bestQ &&
26 (spec.Value == "*" || spec.Value == offer) {
27 bestQ = spec.Q
28 bestOffer = offer
29 }
30 }
31 }
32 if bestQ == 0 {
33 bestOffer = ""
34 }
35 return bestOffer
36}
37
38// NegotiateContentType returns the best offered content type for the request's
39// Accept header. If two offers match with equal weight, then the more specific
40// offer is preferred. For example, text/* trumps */*. If two offers match
41// with equal weight and specificity, then the offer earlier in the list is
42// preferred. If no offers match, then defaultOffer is returned.
43func NegotiateContentType(r *http.Request, offers []string, defaultOffer string) string {
44 bestOffer := defaultOffer
45 bestQ := -1.0
46 bestWild := 3
47 specs := header.ParseAccept(r.Header, "Accept")
48 for _, offer := range offers {
49 for _, spec := range specs {
50 switch {
51 case spec.Q == 0.0:
52 // ignore
53 case spec.Q < bestQ:
54 // better match found
55 case spec.Value == "*/*":
56 if spec.Q > bestQ || bestWild > 2 {
57 bestQ = spec.Q
58 bestWild = 2
59 bestOffer = offer
60 }
61 case strings.HasSuffix(spec.Value, "/*"):
62 if strings.HasPrefix(offer, spec.Value[:len(spec.Value)-1]) &&
63 (spec.Q > bestQ || bestWild > 1) {
64 bestQ = spec.Q
65 bestWild = 1
66 bestOffer = offer
67 }
68 default:
69 if spec.Value == offer &&
70 (spec.Q > bestQ || bestWild > 0) {
71 bestQ = spec.Q
72 bestWild = 0
73 bestOffer = offer
74 }
75 }
76 }
77 }
78 return bestOffer
79}