// PrefersHTML returns true if the request was made by something that looks like a browser, or can receive HTML func PrefersHTML(req *http.Request) bool { accepts := goautoneg.ParseAccept(req.Header.Get("Accept")) acceptsHTML := false acceptsJSON := false for _, accept := range accepts { if accept.Type == "text" && accept.SubType == "html" { acceptsHTML = true } else if accept.Type == "application" && accept.SubType == "json" { acceptsJSON = true } } // If HTML is accepted, return true if acceptsHTML { return true } // If JSON was specifically requested, return false // This gives browsers a way to make requests and add an "Accept" header to request JSON if acceptsJSON { return false } // In Intranet/Compatibility mode, IE sends an Accept header that does not contain "text/html". if strings.HasPrefix(req.UserAgent(), "Mozilla") { return true } return false }
func chooseEncoder(req *http.Request) (encoder, string) { accepts := goautoneg.ParseAccept(req.Header.Get(acceptHeader)) for _, accept := range accepts { switch { case accept.Type == "application" && accept.SubType == "vnd.google.protobuf" && accept.Params["proto"] == "io.prometheus.client.MetricFamily": switch accept.Params["encoding"] { case "delimited": return text.WriteProtoDelimited, DelimitedTelemetryContentType case "text": return text.WriteProtoText, ProtoTextTelemetryContentType case "compact-text": return text.WriteProtoCompactText, ProtoCompactTextTelemetryContentType default: continue } case accept.Type == "text" && accept.SubType == "plain" && (accept.Params["version"] == "0.0.4" || accept.Params["version"] == ""): return text.MetricFamilyToText, TextTelemetryContentType default: continue } } return text.MetricFamilyToText, TextTelemetryContentType }
// If we know the location of the asset server, redirect to it when / is requested // and the Accept header supports text/html func assetServerRedirect(handler http.Handler, assetPublicURL string) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { if req.URL.Path == "/" { accepts := goautoneg.ParseAccept(req.Header.Get("Accept")) for _, accept := range accepts { if accept.Type == "text" && accept.SubType == "html" { http.Redirect(w, req, assetPublicURL, http.StatusFound) return } } } // Dispatch to the next handler handler.ServeHTTP(w, req) }) }
// Negotiate returns the Content-Type based on the given Accept header. // If no appropriate accepted type is found, FmtText is returned. func Negotiate(h http.Header) Format { for _, ac := range goautoneg.ParseAccept(h.Get(hdrAccept)) { // Check for protocol buffer if ac.Type == ProtoType && ac.SubType == ProtoSubType && ac.Params["proto"] == ProtoProtocol { switch ac.Params["encoding"] { case "delimited": return FmtProtoDelim case "text": return FmtProtoText case "compact-text": return FmtProtoCompact } } // Check for text format. ver := ac.Params["version"] if ac.Type == "text" && ac.SubType == "plain" && (ver == TextVersion || ver == "") { return FmtText } } return FmtText }
// negotiate the most appropriate content type given the accept header and a list of // alternatives. func negotiate(header string, alternatives []string) (goautoneg.Accept, bool) { alternates := make([][]string, 0, len(alternatives)) for _, alternate := range alternatives { alternates = append(alternates, strings.SplitN(alternate, "/", 2)) } for _, clause := range goautoneg.ParseAccept(header) { for _, alternate := range alternates { if clause.Type == alternate[0] && clause.SubType == alternate[1] { return clause, true } if clause.Type == alternate[0] && clause.SubType == "*" { clause.SubType = alternate[1] return clause, true } if clause.Type == "*" && clause.SubType == "*" { clause.Type = alternate[0] clause.SubType = alternate[1] return clause, true } } } return goautoneg.Accept{}, false }
// negotiateMediaTypeOptions returns the most appropriate content type given the accept header and // a list of alternatives along with the accepted media type parameters. func negotiateMediaTypeOptions(header string, accepted []acceptedMediaType, endpoint endpointRestrictions) (mediaTypeOptions, bool) { if len(header) == 0 && len(accepted) > 0 { return mediaTypeOptions{ accepted: &accepted[0], }, true } clauses := goautoneg.ParseAccept(header) for _, clause := range clauses { for i := range accepted { accepts := &accepted[i] switch { case clause.Type == accepts.Type && clause.SubType == accepts.SubType, clause.Type == accepts.Type && clause.SubType == "*", clause.Type == "*" && clause.SubType == "*": // TODO: should we prefer the first type with no unrecognized options? Do we need to ignore unrecognized // parameters. return acceptMediaTypeOptions(clause.Params, accepts, endpoint) } } } return mediaTypeOptions{}, false }