PickContentType sets the response's "Content-Type" header. If "Accept" headers are not present in the request, the first element of the "allow" slice is used. If "Accept" headers are present, the first (ordered by "q" value) media type in the "allow" slice is chosen. If there are no common media t
(w http.ResponseWriter, r *http.Request, allow []string)
| 38 | // in the "allow" slice is chosen. If there are no common media types, "415 |
| 39 | // Unsupported Media Type" is written and ErrMediaType is reported. |
| 40 | func pickContentType(w http.ResponseWriter, r *http.Request, allow []string) error { |
| 41 | // There's no canonical algorithm for this, it's all server-dependent |
| 42 | // behavior. Our algorithm is: |
| 43 | // |
| 44 | // - Parse the Accept header(s) as MIME media types joined by commas. |
| 45 | // - Stable sort according to the "q" parameter, defaulting to 1.0 if |
| 46 | // omitted (as specified) |
| 47 | // - Pick the first match. |
| 48 | // |
| 49 | // BUG(hank) Content type negotiation does an O(n*m) comparison driven on |
| 50 | // user input, which may be a DoS issue. |
| 51 | as, ok := r.Header["Accept"] |
| 52 | if !ok { |
| 53 | w.Header().Set("content-type", allow[0]) |
| 54 | return nil |
| 55 | } |
| 56 | var acceptable []accept |
| 57 | for _, part := range as { |
| 58 | for _, s := range strings.Split(part, ",") { |
| 59 | a := accept{} |
| 60 | mt, p, err := mime.ParseMediaType(strings.TrimSpace(s)) |
| 61 | if err != nil { |
| 62 | return err |
| 63 | } |
| 64 | a.Q = 1.0 |
| 65 | if qs, ok := p["q"]; ok { |
| 66 | a.Q, _ = strconv.ParseFloat(qs, 64) |
| 67 | } |
| 68 | typ := strings.Split(mt, "/") |
| 69 | a.Type = typ[0] |
| 70 | a.Subtype = typ[1] |
| 71 | acceptable = append(acceptable, a) |
| 72 | } |
| 73 | } |
| 74 | if len(acceptable) == 0 { |
| 75 | w.Header().Set("content-type", allow[0]) |
| 76 | return nil |
| 77 | } |
| 78 | sort.SliceStable(acceptable, func(i, j int) bool { return acceptable[i].Q > acceptable[j].Q }) |
| 79 | for _, l := range acceptable { |
| 80 | for _, a := range allow { |
| 81 | if l.Match(a) { |
| 82 | w.Header().Set("content-type", a) |
| 83 | return nil |
| 84 | } |
| 85 | } |
| 86 | } |
| 87 | w.WriteHeader(http.StatusUnsupportedMediaType) |
| 88 | return ErrMediaType |
| 89 | } |
| 90 | |
| 91 | // ErrMediaType is returned if no common media types can be found for a given |
| 92 | // request. |
no test coverage detected