Repository: prometheus/prometheus
File: model/textparse/interface.go (Go)

Code before:
	// for the same sample. It returns false once all exemplars are
	// retrieved (including the case where no exemplars exist at all).
	Exemplar(l *exemplar.Exemplar) bool

	// CreatedTimestamp returns the created timestamp (in milliseconds) for the
	// current sample. It returns nil if it is unknown e.g. if it wasn't set,
	// if the scrape protocol or metric type does not support created timestamps.
	// Assume the CreatedTimestamp returned pointer is only valid until
	// the Next iteration.
	CreatedTimestamp() *int64

	// Next advances the parser to the next sample.
	// It returns (EntryInvalid, io.EOF) if no samples were read.
	Next() (Entry, error)
}

// Helper function to returns the mediaType of a required parser checking contentType
// first and falling back to fallbackType if necessary.
// As fallbackType comes from the parse `fallback_scrape_protocol` config option it
// is assumed to be a valid/supported mediaType.
func newHelper(contentType, fallbackType string) (string, error) {
	if contentType == "" {
		if fallbackType == "" {
			return "", errors.New("Non-compliant scraper sending blank Content-Type and no fallback_scrape_protocol specified for target")
		}
		// We don't set the error here so that we're kind and mirror v2 behaviour
		return fallbackType, nil
	}

	// We have a contentType, parse it
	mediaType, _, err := mime.ParseMediaType(contentType)
	if err != nil {
		if fallbackType == "" {
			retErr := errors.New("Cannot parse Content-Type and no fallback_scrape_protocol for target")
			return "", errors.Join(retErr, err)
		}
		retErr := errors.New("Could not parse received Content-Type, using fallback_scrape_protocol for target")
		return fallbackType, errors.Join(retErr, err)
	}

	// We have a valid media type, either we recognise it and can use it
	// or we have to error
	switch mediaType {
	case "application/openmetrics-text", "application/vnd.google.protobuf", "text/plain":
		return mediaType, nil
	}
	// We're here because we have no regonised mediaType
	if fallbackType == "" {
		return "", errors.New("Scraper sending unrecognisable Content-Type and no fallback_scrape_protocol specified for target")
	}
	return fallbackType, errors.New("Content-Type not recognised mediaType, using fallback_scrape_protocol for target")

Review comment (suggestion):
Not sure if we should do this. Let's be explicit and consistent.
(I also hope that even very naive HTTP servers will return `text/plain` by default and therefore not even trigger this error.)

Code after:
	// exemplar. It can be called repeatedly to retrieve multiple exemplars
	// for the same sample. It returns false once all exemplars are
	// retrieved (including the case where no exemplars exist at all).
	Exemplar(l *exemplar.Exemplar) bool

	// CreatedTimestamp returns the created timestamp (in milliseconds) for the
	// current sample. It returns nil if it is unknown e.g. if it wasn't set,
	// if the scrape protocol or metric type does not support created timestamps.
	// Assume the CreatedTimestamp returned pointer is only valid until
	// the Next iteration.
	CreatedTimestamp() *int64

	// Next advances the parser to the next sample.
	// It returns (EntryInvalid, io.EOF) if no samples were read.
	Next() (Entry, error)
}

// extractMediaType returns the mediaType of a required parser. It tries first to
// extract a valid and supported mediaType from contentType. If that fails,
// the provided fallbackType (possibly an empty string) is returned, together with
// an error. fallbackType is used as-is without further validation.
func extractMediaType(contentType, fallbackType string) (string, error) {
	if contentType == "" {
		if fallbackType == "" {
			return "", errors.New("non-compliant scrape target sending blank Content-Type and no fallback_scrape_protocol specified for target")
		}
		return fallbackType, fmt.Errorf("non-compliant scrape target sending blank Content-Type, using fallback_scrape_protocol %q", fallbackType)
	}

	// We have a contentType, parse it.
	mediaType, _, err := mime.ParseMediaType(contentType)
	if err != nil {
		if fallbackType == "" {
			retErr := fmt.Errorf("cannot parse Content-Type %q and no fallback_scrape_protocol for target", contentType)
			return "", errors.Join(retErr, err)
		}
		retErr := fmt.Errorf("could not parse received Content-Type %q, using fallback_scrape_protocol %q", contentType, fallbackType)
		return fallbackType, errors.Join(retErr, err)
	}

	// We have a valid media type, either we recognise it and can use it
	// or we have to error.
	switch mediaType {
	case "application/openmetrics-text", "application/vnd.google.protobuf", "text/plain":
		return mediaType, nil
	}
	// We're here because we have no recognised mediaType.
	if fallbackType == "" {
		return "", fmt.Errorf("received unsupported Content-Type %q and no fallback_scrape_protocol specified for target", contentType)
	}
	return fallbackType, fmt.Errorf("received unsupported Content-Type %q, using fallback_scrape_protocol %q", contentType, fallbackType)