From e5ac9d8e57fa8a22bc18185573207d71087a2027 Mon Sep 17 00:00:00 2001 From: Aliaksandr Valialkin Date: Tue, 9 Nov 2021 18:03:50 +0200 Subject: [PATCH] all: consistently return `application/json` content-type without `charset=utf-8` The `application/json` content-type has utf-8 encoding by default. See https://stackoverflow.com/questions/9254891/what-does-content-type-application-json-charset-utf-8-really-mean Updates https://github.com/VictoriaMetrics/VictoriaMetrics/pull/897 --- app/vmagent/main.go | 16 ++++++++-------- app/vmalert/datasource/vm.go | 2 +- app/vmalert/notifier/alertmanager.go | 2 +- app/vmalert/web.go | 6 +++--- app/vminsert/main.go | 10 +++++----- app/vmselect/graphite/metrics_api.go | 2 +- app/vmselect/graphite/tags_api.go | 10 +++++----- app/vmselect/main.go | 12 ++++++------ app/vmselect/prometheus/prometheus.go | 20 ++++++++++---------- app/vmstorage/main.go | 8 ++++---- lib/influxutils/influxutils.go | 2 +- 11 files changed, 45 insertions(+), 45 deletions(-) diff --git a/app/vmagent/main.go b/app/vmagent/main.go index 8e46d4624..7079c6b08 100644 --- a/app/vmagent/main.go +++ b/app/vmagent/main.go @@ -236,26 +236,26 @@ func requestHandler(w http.ResponseWriter, r *http.Request) bool { return true } // See https://docs.datadoghq.com/api/latest/metrics/#submit-metrics - w.Header().Set("Content-Type", "application/json; charset=utf-8") + w.Header().Set("Content-Type", "application/json") w.WriteHeader(202) fmt.Fprintf(w, `{"status":"ok"}`) return true case "/datadog/api/v1/validate": datadogValidateRequests.Inc() // See https://docs.datadoghq.com/api/latest/authentication/#validate-api-key - w.Header().Set("Content-Type", "application/json; charset=utf-8") + w.Header().Set("Content-Type", "application/json") fmt.Fprintf(w, `{"valid":true}`) return true case "/datadog/api/v1/check_run": datadogCheckRunRequests.Inc() // See https://docs.datadoghq.com/api/latest/service-checks/#submit-a-service-check - w.Header().Set("Content-Type", "application/json; charset=utf-8") + w.Header().Set("Content-Type", "application/json") w.WriteHeader(202) fmt.Fprintf(w, `{"status":"ok"}`) return true case "/datadog/intake/": datadogIntakeRequests.Inc() - w.Header().Set("Content-Type", "application/json; charset=utf-8") + w.Header().Set("Content-Type", "application/json") fmt.Fprintf(w, `{}`) return true case "/targets": @@ -277,7 +277,7 @@ func requestHandler(w http.ResponseWriter, r *http.Request) bool { return true case "/api/v1/targets": promscrapeAPIV1TargetsRequests.Inc() - w.Header().Set("Content-Type", "application/json; charset=utf-8") + w.Header().Set("Content-Type", "application/json") state := r.FormValue("state") promscrape.WriteAPIV1Targets(w, state) return true @@ -391,19 +391,19 @@ func processMultitenantRequest(w http.ResponseWriter, r *http.Request, path stri case "datadog/api/v1/validate": datadogValidateRequests.Inc() // See https://docs.datadoghq.com/api/latest/authentication/#validate-api-key - w.Header().Set("Content-Type", "application/json; charset=utf-8") + w.Header().Set("Content-Type", "application/json") fmt.Fprintf(w, `{"valid":true}`) return true case "datadog/api/v1/check_run": datadogCheckRunRequests.Inc() // See https://docs.datadoghq.com/api/latest/service-checks/#submit-a-service-check - w.Header().Set("Content-Type", "application/json; charset=utf-8") + w.Header().Set("Content-Type", "application/json") w.WriteHeader(202) fmt.Fprintf(w, `{"status":"ok"}`) return true case "datadog/intake/": datadogIntakeRequests.Inc() - w.Header().Set("Content-Type", "application/json; charset=utf-8") + w.Header().Set("Content-Type", "application/json") fmt.Fprintf(w, `{}`) return true default: diff --git a/app/vmalert/datasource/vm.go b/app/vmalert/datasource/vm.go index 304d88cec..c900ed2f6 100644 --- a/app/vmalert/datasource/vm.go +++ b/app/vmalert/datasource/vm.go @@ -150,7 +150,7 @@ func (s *VMStorage) newRequestPOST() (*http.Request, error) { if err != nil { return nil, err } - req.Header.Set("Content-Type", "application/json; charset=utf-8") + req.Header.Set("Content-Type", "application/json") if s.authCfg != nil { if auth := s.authCfg.GetAuthHeader(); auth != "" { req.Header.Set("Authorization", auth) diff --git a/app/vmalert/notifier/alertmanager.go b/app/vmalert/notifier/alertmanager.go index 36b75cfbb..cf132f828 100644 --- a/app/vmalert/notifier/alertmanager.go +++ b/app/vmalert/notifier/alertmanager.go @@ -32,7 +32,7 @@ func (am *AlertManager) Send(ctx context.Context, alerts []Alert) error { if err != nil { return err } - req.Header.Set("Content-Type", "application/json; charset=utf-8") + req.Header.Set("Content-Type", "application/json") req = req.WithContext(ctx) if am.basicAuthPass != "" { req.SetBasicAuth(am.basicAuthUser, am.basicAuthPass) diff --git a/app/vmalert/web.go b/app/vmalert/web.go index e1034dab7..5100d0e36 100644 --- a/app/vmalert/web.go +++ b/app/vmalert/web.go @@ -68,7 +68,7 @@ func (rh *requestHandler) handler(w http.ResponseWriter, r *http.Request) bool { httpserver.Errorf(w, r, "%s", err) return true } - w.Header().Set("Content-Type", "application/json; charset=utf-8") + w.Header().Set("Content-Type", "application/json") w.Write(data) return true case "/api/v1/alerts": @@ -77,7 +77,7 @@ func (rh *requestHandler) handler(w http.ResponseWriter, r *http.Request) bool { httpserver.Errorf(w, r, "%s", err) return true } - w.Header().Set("Content-Type", "application/json; charset=utf-8") + w.Header().Set("Content-Type", "application/json") w.Write(data) return true case "/-/reload": @@ -102,7 +102,7 @@ func (rh *requestHandler) handler(w http.ResponseWriter, r *http.Request) bool { httpserver.Errorf(w, r, "failed to marshal alert: %s", err) return true } - w.Header().Set("Content-Type", "application/json; charset=utf-8") + w.Header().Set("Content-Type", "application/json") w.Write(data) return true } diff --git a/app/vminsert/main.go b/app/vminsert/main.go index 735395a8e..acd9779a9 100644 --- a/app/vminsert/main.go +++ b/app/vminsert/main.go @@ -165,26 +165,26 @@ func RequestHandler(w http.ResponseWriter, r *http.Request) bool { return true } // See https://docs.datadoghq.com/api/latest/metrics/#submit-metrics - w.Header().Set("Content-Type", "application/json; charset=utf-8") + w.Header().Set("Content-Type", "application/json") w.WriteHeader(202) fmt.Fprintf(w, `{"status":"ok"}`) return true case "/datadog/api/v1/validate": datadogValidateRequests.Inc() // See https://docs.datadoghq.com/api/latest/authentication/#validate-api-key - w.Header().Set("Content-Type", "application/json; charset=utf-8") + w.Header().Set("Content-Type", "application/json") fmt.Fprintf(w, `{"valid":true}`) return true case "/datadog/api/v1/check_run": datadogCheckRunRequests.Inc() // See https://docs.datadoghq.com/api/latest/service-checks/#submit-a-service-check - w.Header().Set("Content-Type", "application/json; charset=utf-8") + w.Header().Set("Content-Type", "application/json") w.WriteHeader(202) fmt.Fprintf(w, `{"status":"ok"}`) return true case "/datadog/intake/": datadogIntakeRequests.Inc() - w.Header().Set("Content-Type", "application/json; charset=utf-8") + w.Header().Set("Content-Type", "application/json") fmt.Fprintf(w, `{}`) return true case "/prometheus/targets", "/targets": @@ -193,7 +193,7 @@ func RequestHandler(w http.ResponseWriter, r *http.Request) bool { return true case "/prometheus/api/v1/targets", "/api/v1/targets": promscrapeAPIV1TargetsRequests.Inc() - w.Header().Set("Content-Type", "application/json; charset=utf-8") + w.Header().Set("Content-Type", "application/json") state := r.FormValue("state") promscrape.WriteAPIV1Targets(w, state) return true diff --git a/app/vmselect/graphite/metrics_api.go b/app/vmselect/graphite/metrics_api.go index 1a720edb2..7788fab3b 100644 --- a/app/vmselect/graphite/metrics_api.go +++ b/app/vmselect/graphite/metrics_api.go @@ -456,7 +456,7 @@ const maxRegexpCacheSize = 10000 func getContentType(jsonp string) string { if jsonp == "" { - return "application/json; charset=utf-8" + return "application/json" } return "text/javascript; charset=utf-8" } diff --git a/app/vmselect/graphite/tags_api.go b/app/vmselect/graphite/tags_api.go index 3344cb6ae..165076429 100644 --- a/app/vmselect/graphite/tags_api.go +++ b/app/vmselect/graphite/tags_api.go @@ -62,7 +62,7 @@ func TagsDelSeriesHandler(startTime time.Time, w http.ResponseWriter, r *http.Re totalDeleted += n } - w.Header().Set("Content-Type", "application/json; charset=utf-8") + w.Header().Set("Content-Type", "application/json") if totalDeleted > 0 { fmt.Fprintf(w, "true") } else { @@ -141,7 +141,7 @@ func registerMetrics(startTime time.Time, w http.ResponseWriter, r *http.Request // Return response contentType := "text/plain; charset=utf-8" if isJSONResponse { - contentType = "application/json; charset=utf-8" + contentType = "application/json" } w.Header().Set("Content-Type", contentType) WriteTagsTagMultiSeriesResponse(w, canonicalPaths, isJSONResponse) @@ -362,7 +362,7 @@ func TagsFindSeriesHandler(startTime time.Time, w http.ResponseWriter, r *http.R paths = paths[:limit] } - w.Header().Set("Content-Type", "application/json; charset=utf-8") + w.Header().Set("Content-Type", "application/json") bw := bufferedwriter.Get(w) defer bufferedwriter.Put(bw) WriteTagsFindSeriesResponse(bw, paths) @@ -418,7 +418,7 @@ func TagValuesHandler(startTime time.Time, tagName string, w http.ResponseWriter return err } - w.Header().Set("Content-Type", "application/json; charset=utf-8") + w.Header().Set("Content-Type", "application/json") bw := bufferedwriter.Get(w) defer bufferedwriter.Put(bw) WriteTagValuesResponse(bw, tagName, tagValues) @@ -449,7 +449,7 @@ func TagsHandler(startTime time.Time, w http.ResponseWriter, r *http.Request) er return err } - w.Header().Set("Content-Type", "application/json; charset=utf-8") + w.Header().Set("Content-Type", "application/json") bw := bufferedwriter.Get(w) defer bufferedwriter.Put(bw) WriteTagsResponse(bw, labels) diff --git a/app/vmselect/main.go b/app/vmselect/main.go index 3c705dcbb..406ee198a 100644 --- a/app/vmselect/main.go +++ b/app/vmselect/main.go @@ -200,7 +200,7 @@ func RequestHandler(w http.ResponseWriter, r *http.Request) bool { } if strings.HasPrefix(path, "/functions") { graphiteFunctionsRequests.Inc() - w.Header().Set("Content-Type", "application/json; charset=utf-8") + w.Header().Set("Content-Type", "application/json") fmt.Fprintf(w, "%s", `{}`) return true } @@ -404,25 +404,25 @@ func RequestHandler(w http.ResponseWriter, r *http.Request) bool { case "/api/v1/rules", "/rules": // Return dumb placeholder for https://prometheus.io/docs/prometheus/latest/querying/api/#rules rulesRequests.Inc() - w.Header().Set("Content-Type", "application/json; charset=utf-8") + w.Header().Set("Content-Type", "application/json") fmt.Fprintf(w, "%s", `{"status":"success","data":{"groups":[]}}`) return true case "/api/v1/alerts", "/alerts": // Return dumb placeholder for https://prometheus.io/docs/prometheus/latest/querying/api/#alerts alertsRequests.Inc() - w.Header().Set("Content-Type", "application/json; charset=utf-8") + w.Header().Set("Content-Type", "application/json") fmt.Fprintf(w, "%s", `{"status":"success","data":{"alerts":[]}}`) return true case "/api/v1/metadata": // Return dumb placeholder for https://prometheus.io/docs/prometheus/latest/querying/api/#querying-metric-metadata metadataRequests.Inc() - w.Header().Set("Content-Type", "application/json; charset=utf-8") + w.Header().Set("Content-Type", "application/json") fmt.Fprintf(w, "%s", `{"status":"success","data":{}}`) return true case "/api/v1/query_exemplars": // Return dumb placeholder for https://prometheus.io/docs/prometheus/latest/querying/api/#querying-exemplars queryExemplarsRequests.Inc() - w.Header().Set("Content-Type", "application/json; charset=utf-8") + w.Header().Set("Content-Type", "application/json") fmt.Fprintf(w, "%s", `{"status":"success","data":null}`) return true case "/api/v1/admin/tsdb/delete_series": @@ -459,7 +459,7 @@ func isGraphiteTagsPath(path string) bool { func sendPrometheusError(w http.ResponseWriter, r *http.Request, err error) { logger.Warnf("error in %q: %s", httpserver.GetRequestURI(r), err) - w.Header().Set("Content-Type", "application/json; charset=utf-8") + w.Header().Set("Content-Type", "application/json") statusCode := http.StatusUnprocessableEntity var esc *httpserver.ErrorWithStatusCode if errors.As(err, &esc) { diff --git a/app/vmselect/prometheus/prometheus.go b/app/vmselect/prometheus/prometheus.go index 93323658d..41ada99e2 100644 --- a/app/vmselect/prometheus/prometheus.go +++ b/app/vmselect/prometheus/prometheus.go @@ -533,7 +533,7 @@ func LabelValuesHandler(startTime time.Time, labelName string, w http.ResponseWr } } - w.Header().Set("Content-Type", "application/json; charset=utf-8") + w.Header().Set("Content-Type", "application/json") bw := bufferedwriter.Get(w) defer bufferedwriter.Put(bw) WriteLabelValuesResponse(bw, labelValues) @@ -622,7 +622,7 @@ func LabelsCountHandler(startTime time.Time, w http.ResponseWriter, r *http.Requ if err != nil { return fmt.Errorf(`cannot obtain label entries: %w`, err) } - w.Header().Set("Content-Type", "application/json; charset=utf-8") + w.Header().Set("Content-Type", "application/json") bw := bufferedwriter.Get(w) defer bufferedwriter.Put(bw) WriteLabelsCountResponse(bw, labelEntries) @@ -690,7 +690,7 @@ func TSDBStatusHandler(startTime time.Time, w http.ResponseWriter, r *http.Reque return fmt.Errorf("cannot obtain tsdb status with matches for date=%d, topN=%d: %w", date, topN, err) } } - w.Header().Set("Content-Type", "application/json; charset=utf-8") + w.Header().Set("Content-Type", "application/json") bw := bufferedwriter.Get(w) defer bufferedwriter.Put(bw) WriteTSDBStatusResponse(bw, status) @@ -784,7 +784,7 @@ func LabelsHandler(startTime time.Time, w http.ResponseWriter, r *http.Request) } } - w.Header().Set("Content-Type", "application/json; charset=utf-8") + w.Header().Set("Content-Type", "application/json") bw := bufferedwriter.Get(w) defer bufferedwriter.Put(bw) WriteLabelsResponse(bw, labels) @@ -860,7 +860,7 @@ func SeriesCountHandler(startTime time.Time, w http.ResponseWriter, r *http.Requ if err != nil { return fmt.Errorf("cannot obtain series count: %w", err) } - w.Header().Set("Content-Type", "application/json; charset=utf-8") + w.Header().Set("Content-Type", "application/json") bw := bufferedwriter.Get(w) defer bufferedwriter.Put(bw) WriteSeriesCountResponse(bw, n) @@ -911,7 +911,7 @@ func SeriesHandler(startTime time.Time, w http.ResponseWriter, r *http.Request) if err != nil { return fmt.Errorf("cannot fetch time series for %q: %w", sq, err) } - w.Header().Set("Content-Type", "application/json; charset=utf-8") + w.Header().Set("Content-Type", "application/json") bw := bufferedwriter.Get(w) defer bufferedwriter.Put(bw) resultsCh := make(chan *quicktemplate.ByteBuffer) @@ -936,7 +936,7 @@ func SeriesHandler(startTime time.Time, w http.ResponseWriter, r *http.Request) return fmt.Errorf("cannot fetch data for %q: %w", sq, err) } - w.Header().Set("Content-Type", "application/json; charset=utf-8") + w.Header().Set("Content-Type", "application/json") bw := bufferedwriter.Get(w) defer bufferedwriter.Put(bw) resultsCh := make(chan *quicktemplate.ByteBuffer) @@ -1070,7 +1070,7 @@ func QueryHandler(startTime time.Time, w http.ResponseWriter, r *http.Request) e } } - w.Header().Set("Content-Type", "application/json; charset=utf-8") + w.Header().Set("Content-Type", "application/json") bw := bufferedwriter.Get(w) defer bufferedwriter.Put(bw) WriteQueryResponse(bw, result) @@ -1163,7 +1163,7 @@ func queryRangeHandler(startTime time.Time, w http.ResponseWriter, query string, // See https://github.com/VictoriaMetrics/VictoriaMetrics/issues/153 result = removeEmptyValuesAndTimeseries(result) - w.Header().Set("Content-Type", "application/json; charset=utf-8") + w.Header().Set("Content-Type", "application/json") bw := bufferedwriter.Get(w) defer bufferedwriter.Put(bw) WriteQueryRangeResponse(bw, result) @@ -1343,7 +1343,7 @@ func QueryStatsHandler(startTime time.Time, w http.ResponseWriter, r *http.Reque return fmt.Errorf("cannot parse `maxLifetime` arg: %w", err) } maxLifetime := time.Duration(maxLifetimeMsecs) * time.Millisecond - w.Header().Set("Content-Type", "application/json; charset=utf-8") + w.Header().Set("Content-Type", "application/json") bw := bufferedwriter.Get(w) defer bufferedwriter.Put(bw) querystats.WriteJSONQueryStats(bw, topN, maxLifetime) diff --git a/app/vmstorage/main.go b/app/vmstorage/main.go index 1f3c2d654..98aca0127 100644 --- a/app/vmstorage/main.go +++ b/app/vmstorage/main.go @@ -304,7 +304,7 @@ func RequestHandler(w http.ResponseWriter, r *http.Request) bool { switch path { case "/create": - w.Header().Set("Content-Type", "application/json; charset=utf-8") + w.Header().Set("Content-Type", "application/json") snapshotPath, err := Storage.CreateSnapshot() if err != nil { err = fmt.Errorf("cannot create snapshot: %w", err) @@ -318,7 +318,7 @@ func RequestHandler(w http.ResponseWriter, r *http.Request) bool { } return true case "/list": - w.Header().Set("Content-Type", "application/json; charset=utf-8") + w.Header().Set("Content-Type", "application/json") snapshots, err := Storage.ListSnapshots() if err != nil { err = fmt.Errorf("cannot list snapshots: %w", err) @@ -335,7 +335,7 @@ func RequestHandler(w http.ResponseWriter, r *http.Request) bool { fmt.Fprintf(w, `]}`) return true case "/delete": - w.Header().Set("Content-Type", "application/json; charset=utf-8") + w.Header().Set("Content-Type", "application/json") snapshotName := r.FormValue("snapshot") if err := Storage.DeleteSnapshot(snapshotName); err != nil { err = fmt.Errorf("cannot delete snapshot %q: %w", snapshotName, err) @@ -345,7 +345,7 @@ func RequestHandler(w http.ResponseWriter, r *http.Request) bool { fmt.Fprintf(w, `{"status":"ok"}`) return true case "/delete_all": - w.Header().Set("Content-Type", "application/json; charset=utf-8") + w.Header().Set("Content-Type", "application/json") snapshots, err := Storage.ListSnapshots() if err != nil { err = fmt.Errorf("cannot list snapshots: %w", err) diff --git a/lib/influxutils/influxutils.go b/lib/influxutils/influxutils.go index f441ddd49..0350b0102 100644 --- a/lib/influxutils/influxutils.go +++ b/lib/influxutils/influxutils.go @@ -16,7 +16,7 @@ func WriteDatabaseNames(w http.ResponseWriter) { // Emulate fake response for influx query. // This is required for TSBS benchmark and some Telegraf plugins. // See https://github.com/VictoriaMetrics/VictoriaMetrics/issues/1124 - w.Header().Set("Content-Type", "application/json; charset=utf-8") + w.Header().Set("Content-Type", "application/json") dbNames := *influxDatabaseNames if len(dbNames) == 0 { dbNames = []string{"_internal"}