...
1
39 package goautoneg
40
41 import (
42 "sort"
43 "strconv"
44 "strings"
45 )
46
47
48 type Accept struct {
49 Type, SubType string
50 Q float64
51 Params map[string]string
52 }
53
54
55 type accept_slice []Accept
56
57 func (accept accept_slice) Len() int {
58 slice := []Accept(accept)
59 return len(slice)
60 }
61
62 func (accept accept_slice) Less(i, j int) bool {
63 slice := []Accept(accept)
64 ai, aj := slice[i], slice[j]
65 if ai.Q > aj.Q {
66 return true
67 }
68 if ai.Type != "*" && aj.Type == "*" {
69 return true
70 }
71 if ai.SubType != "*" && aj.SubType == "*" {
72 return true
73 }
74 return false
75 }
76
77 func (accept accept_slice) Swap(i, j int) {
78 slice := []Accept(accept)
79 slice[i], slice[j] = slice[j], slice[i]
80 }
81
82
83
84 func ParseAccept(header string) (accept []Accept) {
85 parts := strings.Split(header, ",")
86 accept = make([]Accept, 0, len(parts))
87 for _, part := range parts {
88 part := strings.Trim(part, " ")
89
90 a := Accept{}
91 a.Params = make(map[string]string)
92 a.Q = 1.0
93
94 mrp := strings.Split(part, ";")
95
96 media_range := mrp[0]
97 sp := strings.Split(media_range, "/")
98 a.Type = strings.Trim(sp[0], " ")
99
100 switch {
101 case len(sp) == 1 && a.Type == "*":
102 a.SubType = "*"
103 case len(sp) == 2:
104 a.SubType = strings.Trim(sp[1], " ")
105 default:
106 continue
107 }
108
109 if len(mrp) == 1 {
110 accept = append(accept, a)
111 continue
112 }
113
114 for _, param := range mrp[1:] {
115 sp := strings.SplitN(param, "=", 2)
116 if len(sp) != 2 {
117 continue
118 }
119 token := strings.Trim(sp[0], " ")
120 if token == "q" {
121 a.Q, _ = strconv.ParseFloat(sp[1], 32)
122 } else {
123 a.Params[token] = strings.Trim(sp[1], " ")
124 }
125 }
126
127 accept = append(accept, a)
128 }
129
130 slice := accept_slice(accept)
131 sort.Sort(slice)
132
133 return
134 }
135
136
137
138 func Negotiate(header string, alternatives []string) (content_type string) {
139 asp := make([][]string, 0, len(alternatives))
140 for _, ctype := range alternatives {
141 asp = append(asp, strings.SplitN(ctype, "/", 2))
142 }
143 for _, clause := range ParseAccept(header) {
144 for i, ctsp := range asp {
145 if clause.Type == ctsp[0] && clause.SubType == ctsp[1] {
146 content_type = alternatives[i]
147 return
148 }
149 if clause.Type == ctsp[0] && clause.SubType == "*" {
150 content_type = alternatives[i]
151 return
152 }
153 if clause.Type == "*" && clause.SubType == "*" {
154 content_type = alternatives[i]
155 return
156 }
157 }
158 }
159 return
160 }
161
View as plain text