From da66a125a9f796247cba9e13f6cf72a5de34f0ef Mon Sep 17 00:00:00 2001 From: Andrew Nesbitt Date: Wed, 2 Sep 2026 13:16:23 +0100 Subject: [PATCH] Use header constants across the handler package goconst tripped on main after #259 landed on top of #280: five composite-literal occurrences each of "Content-Length" and "Content-Type" across container.go, container_manifest.go, container_tags.go, handler.go, and swift.go crossed the min-occurrences: 5 threshold. Neither PR hit it alone. Add headerContentType and headerContentLength beside headerAcceptEncoding and use them throughout the package rather than only at the flagged sites, so the next handler that adds one does not re-trip the check. --- internal/handler/cargo.go | 4 ++-- internal/handler/composer.go | 6 +++--- internal/handler/conda.go | 4 ++-- internal/handler/container.go | 12 ++++++------ internal/handler/container_manifest.go | 8 ++++---- internal/handler/container_tags.go | 8 ++++---- internal/handler/debian.go | 2 +- internal/handler/gem.go | 2 +- internal/handler/gradle.go | 6 +++--- internal/handler/handler.go | 20 ++++++++++++-------- internal/handler/helm.go | 2 +- internal/handler/hex.go | 6 +++--- internal/handler/npm.go | 4 ++-- internal/handler/nuget.go | 8 ++++---- internal/handler/pub.go | 4 ++-- internal/handler/pypi.go | 6 +++--- internal/handler/rpm.go | 2 +- internal/handler/swift.go | 18 +++++++++--------- 18 files changed, 63 insertions(+), 59 deletions(-) diff --git a/internal/handler/cargo.go b/internal/handler/cargo.go index 79fb7509..4cf8591e 100644 --- a/internal/handler/cargo.go +++ b/internal/handler/cargo.go @@ -80,7 +80,7 @@ func (h *CargoHandler) handleConfig(w http.ResponseWriter, r *http.Request) { DL: h.proxyURL + "/cargo/crates/{crate}/{version}/download", } - w.Header().Set("Content-Type", "application/json") + w.Header().Set(headerContentType, "application/json") _ = json.NewEncoder(w).Encode(config) } @@ -112,7 +112,7 @@ func (h *CargoHandler) handleIndex(w http.ResponseWriter, r *http.Request) { contentType = "text/plain; charset=utf-8" } - w.Header().Set("Content-Type", contentType) + w.Header().Set(headerContentType, contentType) w.WriteHeader(http.StatusOK) h.applyCooldownFiltering(w, body) } diff --git a/internal/handler/composer.go b/internal/handler/composer.go index 9b2de807..fbbd7a4e 100644 --- a/internal/handler/composer.go +++ b/internal/handler/composer.go @@ -77,7 +77,7 @@ func (h *ComposerHandler) handleServiceIndex(w http.ResponseWriter, r *http.Requ "providers-lazy-url": h.proxyURL + "/composer/p2/%package%.json", } - w.Header().Set("Content-Type", "application/json") + w.Header().Set(headerContentType, "application/json") _ = json.NewEncoder(w).Encode(index) } @@ -113,12 +113,12 @@ func (h *ComposerHandler) handlePackageMetadata(w http.ResponseWriter, r *http.R rewritten, err := h.rewriteMetadata(body) if err != nil { h.proxy.Logger.Warn("failed to rewrite metadata, proxying original", "error", err) - w.Header().Set("Content-Type", "application/json") + w.Header().Set(headerContentType, "application/json") _, _ = w.Write(body) return } - w.Header().Set("Content-Type", "application/json") + w.Header().Set(headerContentType, "application/json") _, _ = w.Write(rewritten) } diff --git a/internal/handler/conda.go b/internal/handler/conda.go index bee5694c..cef814b5 100644 --- a/internal/handler/conda.go +++ b/internal/handler/conda.go @@ -174,12 +174,12 @@ func (h *CondaHandler) handleRepodata(w http.ResponseWriter, r *http.Request) { filtered, err := h.applyCooldownFiltering(body) if err != nil { h.proxy.Logger.Warn("failed to filter repodata, proxying original", "error", err) - w.Header().Set("Content-Type", "application/json") + w.Header().Set(headerContentType, "application/json") _, _ = w.Write(body) return } - w.Header().Set("Content-Type", "application/json") + w.Header().Set(headerContentType, "application/json") _, _ = w.Write(filtered) } diff --git a/internal/handler/container.go b/internal/handler/container.go index 7a0a0e9f..722e8f8a 100644 --- a/internal/handler/container.go +++ b/internal/handler/container.go @@ -126,9 +126,9 @@ func (h *ContainerHandler) handleBlobDownload(w http.ResponseWriter, r *http.Req if cached != nil { w.Header().Set("Docker-Content-Digest", digest) if cached.ContentType != "" { - w.Header().Set("Content-Type", cached.ContentType) + w.Header().Set(headerContentType, cached.ContentType) } else { - w.Header().Set("Content-Type", "application/octet-stream") + w.Header().Set(headerContentType, "application/octet-stream") } serveArtifact(w, r.Method, cached) return @@ -162,9 +162,9 @@ func (h *ContainerHandler) handleBlobDownload(w http.ResponseWriter, r *http.Req w.Header().Set("Docker-Content-Digest", digest) if result.ContentType != "" { - w.Header().Set("Content-Type", result.ContentType) + w.Header().Set(headerContentType, result.ContentType) } else { - w.Header().Set("Content-Type", "application/octet-stream") + w.Header().Set(headerContentType, "application/octet-stream") } ServeArtifact(w, result) } @@ -232,7 +232,7 @@ func (h *ContainerHandler) proxyBlobHead(w http.ResponseWriter, r *http.Request, } defer func() { _ = resp.Body.Close() }() - for _, header := range []string{"Content-Type", "Content-Length", "Docker-Content-Digest"} { + for _, header := range []string{headerContentType, headerContentLength, "Docker-Content-Digest"} { if v := resp.Header.Get(header); v != "" { w.Header().Set(header, v) } @@ -261,7 +261,7 @@ func (h *ContainerHandler) registryForName(name string) (registryURL, upstreamNa // containerError writes an OCI-compliant error response. func (h *ContainerHandler) containerError(w http.ResponseWriter, status int, code, message string) { - w.Header().Set("Content-Type", "application/json") + w.Header().Set(headerContentType, "application/json") w.WriteHeader(status) _ = json.NewEncoder(w).Encode(map[string]any{ "errors": []map[string]string{ diff --git a/internal/handler/container_manifest.go b/internal/handler/container_manifest.go index b7cdeb54..a471330c 100644 --- a/internal/handler/container_manifest.go +++ b/internal/handler/container_manifest.go @@ -95,7 +95,7 @@ func (h *ContainerHandler) serveManifest(w http.ResponseWriter, r *http.Request, } manifest := &cachedContainerManifest{ body: body, - contentType: resp.Header.Get("Content-Type"), + contentType: resp.Header.Get(headerContentType), contentDigest: resp.Header.Get("Docker-Content-Digest"), etag: resp.Header.Get("ETag"), size: int64(len(body)), @@ -228,9 +228,9 @@ func (h *ContainerHandler) storeContainerManifest(ctx context.Context, cacheKey func writeContainerManifest(w http.ResponseWriter, method string, manifest *cachedContainerManifest, stale bool) { if manifest.contentType != "" { - w.Header().Set("Content-Type", manifest.contentType) + w.Header().Set(headerContentType, manifest.contentType) } - w.Header().Set("Content-Length", strconv.FormatInt(manifest.size, 10)) + w.Header().Set(headerContentLength, strconv.FormatInt(manifest.size, 10)) if manifest.contentDigest != "" { w.Header().Set("Docker-Content-Digest", manifest.contentDigest) } @@ -383,7 +383,7 @@ func containerAcceptQuality(params map[string]string) float64 { } func copyContainerManifestHeaders(destination, source http.Header) { - for _, header := range []string{"Content-Type", "Content-Length", "Docker-Content-Digest", "ETag", "WWW-Authenticate"} { + for _, header := range []string{headerContentType, headerContentLength, "Docker-Content-Digest", "ETag", "WWW-Authenticate"} { if value := source.Get(header); value != "" { destination.Set(header, value) } diff --git a/internal/handler/container_tags.go b/internal/handler/container_tags.go index 95b0b4ca..0e9e3eba 100644 --- a/internal/handler/container_tags.go +++ b/internal/handler/container_tags.go @@ -86,7 +86,7 @@ func (h *ContainerHandler) serveTagsList(w http.ResponseWriter, r *http.Request, } tags := &cachedContainerTags{ body: body, - contentType: resp.Header.Get("Content-Type"), + contentType: resp.Header.Get(headerContentType), etag: resp.Header.Get("ETag"), link: h.rewriteContainerTagsLink(strings.Join(resp.Header.Values("Link"), ", "), registryURL, r.URL.Path), size: int64(len(body)), @@ -169,8 +169,8 @@ func (h *ContainerHandler) storeContainerTags(ctx context.Context, cacheKey stri } func writeContainerTags(w http.ResponseWriter, tags *cachedContainerTags, stale bool) { - w.Header().Set("Content-Type", tags.contentType) - w.Header().Set("Content-Length", strconv.FormatInt(tags.size, 10)) + w.Header().Set(headerContentType, tags.contentType) + w.Header().Set(headerContentLength, strconv.FormatInt(tags.size, 10)) if tags.etag != "" { w.Header().Set("ETag", tags.etag) } @@ -185,7 +185,7 @@ func writeContainerTags(w http.ResponseWriter, tags *cachedContainerTags, stale } func copyContainerTagsHeaders(destination, source http.Header) { - for _, header := range []string{"Content-Type", "Content-Length", "ETag", "Link", "WWW-Authenticate"} { + for _, header := range []string{headerContentType, headerContentLength, "ETag", "Link", "WWW-Authenticate"} { if value := source.Get(header); value != "" { destination.Set(header, value) } diff --git a/internal/handler/debian.go b/internal/handler/debian.go index b48f4fcc..42d26e7a 100644 --- a/internal/handler/debian.go +++ b/internal/handler/debian.go @@ -88,7 +88,7 @@ func (h *DebianHandler) handlePackageDownload(w http.ResponseWriter, r *http.Req return } - w.Header().Set("Content-Type", "application/vnd.debian.binary-package") + w.Header().Set(headerContentType, "application/vnd.debian.binary-package") ServeArtifact(w, result) } diff --git a/internal/handler/gem.go b/internal/handler/gem.go index 50bba0c2..8fc50399 100644 --- a/internal/handler/gem.go +++ b/internal/handler/gem.go @@ -182,7 +182,7 @@ func (h *GemHandler) fetchCompactIndex(r *http.Request, name string) (*http.Resp // writeFilteredIndex writes the compact index response with cooldown-filtered versions removed. func (h *GemHandler) writeFilteredIndex(w http.ResponseWriter, resp *http.Response, name string, filtered map[string]bool) { for k, vv := range resp.Header { - if strings.EqualFold(k, "Content-Length") { + if strings.EqualFold(k, headerContentLength) { continue // length will change after filtering } for _, v := range vv { diff --git a/internal/handler/gradle.go b/internal/handler/gradle.go index 3b703be0..cc7e33f6 100644 --- a/internal/handler/gradle.go +++ b/internal/handler/gradle.go @@ -93,7 +93,7 @@ func (h *GradleBuildCacheHandler) cacheStoragePath(key string) string { func (h *GradleBuildCacheHandler) handleGetOrHead(w http.ResponseWriter, r *http.Request, key string) { storagePath := h.cacheStoragePath(key) - w.Header().Set("Content-Type", gradleBuildCacheContentType) + w.Header().Set(headerContentType, gradleBuildCacheContentType) if r.Method == http.MethodHead { existsStart := time.Now() @@ -118,7 +118,7 @@ func (h *GradleBuildCacheHandler) handleGetOrHead(w http.ResponseWriter, r *http if err != nil { metrics.RecordStorageError("read") } else if size >= 0 { - w.Header().Set("Content-Length", strconv.FormatInt(size, 10)) + w.Header().Set(headerContentLength, strconv.FormatInt(size, 10)) } w.WriteHeader(http.StatusOK) @@ -171,7 +171,7 @@ func (h *GradleBuildCacheHandler) handlePut(w http.ResponseWriter, r *http.Reque return } - w.Header().Set("Content-Length", "0") + w.Header().Set(headerContentLength, "0") w.Header().Set("ETag", `"`+hash+`"`) w.WriteHeader(http.StatusCreated) diff --git a/internal/handler/handler.go b/internal/handler/handler.go index 05a58a94..6f4ceaf1 100644 --- a/internal/handler/handler.go +++ b/internal/handler/handler.go @@ -91,7 +91,11 @@ func packagePURLStrings(ecosystem, name, version string) (string, string, error) const contentTypeJSON = "application/json" -const headerAcceptEncoding = "Accept-Encoding" +const ( + headerAcceptEncoding = "Accept-Encoding" + headerContentType = "Content-Type" + headerContentLength = "Content-Length" +) // defaultMetadataMaxSize is used when Proxy.MetadataMaxSize is unset. const defaultMetadataMaxSize = 100 << 20 @@ -453,10 +457,10 @@ func serveArtifact(w http.ResponseWriter, method string, result *CacheResult) { } if result.ContentType != "" { - w.Header().Set("Content-Type", result.ContentType) + w.Header().Set(headerContentType, result.ContentType) } if result.Size > 0 || (method == http.MethodHead && result.Size == 0) { - w.Header().Set("Content-Length", strconv.FormatInt(result.Size, 10)) + w.Header().Set(headerContentLength, strconv.FormatInt(result.Size, 10)) } if result.Hash != "" { w.Header().Set("ETag", `"`+result.Hash+`"`) @@ -537,7 +541,7 @@ func (p *Proxy) ProxyFile(w http.ResponseWriter, r *http.Request, upstreamURL st // JSONError writes a JSON error response. func JSONError(w http.ResponseWriter, status int, message string) { - w.Header().Set("Content-Type", contentTypeJSON) + w.Header().Set(headerContentType, contentTypeJSON) w.WriteHeader(status) _, _ = fmt.Fprintf(w, `{"error":%q}`, message) } @@ -711,7 +715,7 @@ func (p *Proxy) fetchUpstreamMetadata(ctx context.Context, upstreamURL string, e return nil, "", "", zeroTime, fmt.Errorf("reading response: %w", err) } - contentType := resp.Header.Get("Content-Type") + contentType := resp.Header.Get(headerContentType) if contentType == "" { contentType = contentTypeJSON } @@ -826,8 +830,8 @@ func (p *Proxy) writeMetadataCachedResponse(w http.ResponseWriter, r *http.Reque } } - w.Header().Set("Content-Type", contentType) - w.Header().Set("Content-Length", strconv.Itoa(len(body))) + w.Header().Set(headerContentType, contentType) + w.Header().Set(headerContentLength, strconv.Itoa(len(body))) if cm.etag != "" { w.Header().Set("ETag", cm.etag) } @@ -870,7 +874,7 @@ func (p *Proxy) proxyMetadataStream(w http.ResponseWriter, r *http.Request, upst } defer func() { _ = resp.Body.Close() }() - for _, header := range []string{"Content-Type", "Content-Length", "Last-Modified", "ETag"} { + for _, header := range []string{headerContentType, headerContentLength, "Last-Modified", "ETag"} { if v := resp.Header.Get(header); v != "" { w.Header().Set(header, v) } diff --git a/internal/handler/helm.go b/internal/handler/helm.go index f91ba58d..994c2594 100644 --- a/internal/handler/helm.go +++ b/internal/handler/helm.go @@ -136,7 +136,7 @@ func (h *HelmHandler) serveChart(w http.ResponseWriter, r *http.Request, reposit } if result.ContentType == "" { - w.Header().Set("Content-Type", "application/gzip") + w.Header().Set(headerContentType, "application/gzip") } ServeArtifact(w, result) } diff --git a/internal/handler/hex.go b/internal/handler/hex.go index f3bcb932..15d28915 100644 --- a/internal/handler/hex.go +++ b/internal/handler/hex.go @@ -135,7 +135,7 @@ func (h *HexHandler) handlePackages(w http.ResponseWriter, r *http.Request) { if len(filteredVersions) == 0 { // No versions to filter or couldn't get timestamps, pass through - w.Header().Set("Content-Type", protoResp.Header.Get("Content-Type")) + w.Header().Set(headerContentType, protoResp.Header.Get(headerContentType)) w.Header().Set("Content-Encoding", "gzip") _, _ = w.Write(body) return @@ -144,13 +144,13 @@ func (h *HexHandler) handlePackages(w http.ResponseWriter, r *http.Request) { filtered, err := h.filterSignedPackage(body, filteredVersions) if err != nil { h.proxy.Logger.Warn("failed to filter hex package, proxying original", "error", err) - w.Header().Set("Content-Type", protoResp.Header.Get("Content-Type")) + w.Header().Set(headerContentType, protoResp.Header.Get(headerContentType)) w.Header().Set("Content-Encoding", "gzip") _, _ = w.Write(body) return } - w.Header().Set("Content-Type", "application/octet-stream") + w.Header().Set(headerContentType, "application/octet-stream") w.Header().Set("Content-Encoding", "gzip") _, _ = w.Write(filtered) } diff --git a/internal/handler/npm.go b/internal/handler/npm.go index 265603f1..166b944e 100644 --- a/internal/handler/npm.go +++ b/internal/handler/npm.go @@ -98,13 +98,13 @@ func (h *NPMHandler) handlePackageMetadata(w http.ResponseWriter, r *http.Reques if err != nil { // If rewriting fails, just proxy the original h.proxy.Logger.Warn("failed to rewrite metadata, proxying original", "error", err) - w.Header().Set("Content-Type", contentTypeJSON) + w.Header().Set(headerContentType, contentTypeJSON) w.WriteHeader(http.StatusOK) _, _ = w.Write(body) return } - w.Header().Set("Content-Type", contentTypeJSON) + w.Header().Set(headerContentType, contentTypeJSON) w.WriteHeader(http.StatusOK) _, _ = w.Write(rewritten) } diff --git a/internal/handler/nuget.go b/internal/handler/nuget.go index 0fb139bc..7df62408 100644 --- a/internal/handler/nuget.go +++ b/internal/handler/nuget.go @@ -85,12 +85,12 @@ func (h *NuGetHandler) handleServiceIndex(w http.ResponseWriter, r *http.Request rewritten, err := h.rewriteServiceIndex(body) if err != nil { h.proxy.Logger.Warn("failed to rewrite service index, proxying original", "error", err) - w.Header().Set("Content-Type", "application/json") + w.Header().Set(headerContentType, "application/json") _, _ = w.Write(body) return } - w.Header().Set("Content-Type", "application/json") + w.Header().Set(headerContentType, "application/json") _, _ = w.Write(rewritten) } @@ -188,12 +188,12 @@ func (h *NuGetHandler) handleRegistration(w http.ResponseWriter, r *http.Request filtered, err := h.applyCooldownFiltering(body) if err != nil { h.proxy.Logger.Warn("failed to filter registration, proxying original", "error", err) - w.Header().Set("Content-Type", "application/json") + w.Header().Set(headerContentType, "application/json") _, _ = w.Write(body) return } - w.Header().Set("Content-Type", "application/json") + w.Header().Set(headerContentType, "application/json") _, _ = w.Write(filtered) } diff --git a/internal/handler/pub.go b/internal/handler/pub.go index 303a9e60..9d449bae 100644 --- a/internal/handler/pub.go +++ b/internal/handler/pub.go @@ -110,13 +110,13 @@ func (h *PubHandler) handlePackageMetadata(w http.ResponseWriter, r *http.Reques rewritten, err := h.rewriteMetadata(name, body) if err != nil { h.proxy.Logger.Warn("failed to rewrite metadata, proxying original", "error", err) - w.Header().Set("Content-Type", "application/json") + w.Header().Set(headerContentType, "application/json") w.WriteHeader(http.StatusOK) _, _ = w.Write(body) return } - w.Header().Set("Content-Type", "application/json") + w.Header().Set(headerContentType, "application/json") w.WriteHeader(http.StatusOK) _, _ = w.Write(rewritten) } diff --git a/internal/handler/pypi.go b/internal/handler/pypi.go index b1d7e729..03d178f1 100644 --- a/internal/handler/pypi.go +++ b/internal/handler/pypi.go @@ -130,7 +130,7 @@ func (h *PyPIHandler) handleSimplePackage(w http.ResponseWriter, r *http.Request rewritten = h.rewriteSimpleHTML(body, filteredVersions) } - w.Header().Set("Content-Type", contentType) + w.Header().Set(headerContentType, contentType) ensureVaryAccept(w.Header()) w.WriteHeader(http.StatusOK) _, _ = w.Write(rewritten) @@ -401,12 +401,12 @@ func (h *PyPIHandler) proxyAndRewriteJSON(w http.ResponseWriter, r *http.Request rewritten, err := h.rewriteJSONMetadata(body) if err != nil { h.proxy.Logger.Warn("failed to rewrite metadata, proxying original", "error", err) - w.Header().Set("Content-Type", "application/json") + w.Header().Set(headerContentType, "application/json") _, _ = w.Write(body) return } - w.Header().Set("Content-Type", "application/json") + w.Header().Set(headerContentType, "application/json") _, _ = w.Write(rewritten) } diff --git a/internal/handler/rpm.go b/internal/handler/rpm.go index f4cf9e77..e06a3cc1 100644 --- a/internal/handler/rpm.go +++ b/internal/handler/rpm.go @@ -94,7 +94,7 @@ func (h *RPMHandler) handlePackageDownload(w http.ResponseWriter, r *http.Reques return } - w.Header().Set("Content-Type", "application/x-rpm") + w.Header().Set(headerContentType, "application/x-rpm") ServeArtifact(w, result) } diff --git a/internal/handler/swift.go b/internal/handler/swift.go index 545407e4..9acc8813 100644 --- a/internal/handler/swift.go +++ b/internal/handler/swift.go @@ -219,9 +219,9 @@ func (h *SwiftHandler) handleSourceArchiveHead( return } setSwiftArchiveHeaders(w.Header(), name, version, "", archiveInfo) - w.Header().Set("Content-Type", "application/zip") + w.Header().Set(headerContentType, "application/zip") if size >= 0 { - w.Header().Set("Content-Length", strconv.FormatInt(size, 10)) + w.Header().Set(headerContentLength, strconv.FormatInt(size, 10)) } w.WriteHeader(http.StatusOK) } @@ -260,7 +260,7 @@ func (h *SwiftHandler) probeSourceArchive(ctx context.Context, upstreamURL, acce } size := int64(-1) - if contentLength := resp.Header.Get("Content-Length"); contentLength != "" { + if contentLength := resp.Header.Get(headerContentLength); contentLength != "" { if parsed, parseErr := strconv.ParseInt(contentLength, 10, 64); parseErr == nil { size = parsed } @@ -296,7 +296,7 @@ func (h *SwiftHandler) fetchMetadataWithHeaders( if err != nil { return nil, "", nil, fmt.Errorf("reading upstream metadata: %w", err) } - contentType := resp.Header.Get("Content-Type") + contentType := resp.Header.Get(headerContentType) if contentType == "" { contentType = contentTypeJSON } @@ -430,8 +430,8 @@ func (h *SwiftHandler) proxySwiftResource(w http.ResponseWriter, r *http.Request func copySwiftResponseHeaders(dst, src http.Header) { for _, name := range []string{ - "Cache-Control", "Content-Disposition", "Content-Language", "Content-Length", - "Content-Type", "Content-Version", "Digest", "ETag", "Last-Modified", + "Cache-Control", "Content-Disposition", "Content-Language", headerContentLength, + headerContentType, "Content-Version", "Digest", "ETag", "Last-Modified", "Retry-After", "Vary", "Warning", "X-Swift-Package-Signature", "X-Swift-Package-Signature-Format", } { @@ -564,14 +564,14 @@ func writeSwiftMetadata(w http.ResponseWriter, r *http.Request, body []byte, con } digest := sha256.Sum256(body) etag := fmt.Sprintf(`"%x"`, digest) - w.Header().Set("Content-Type", contentType) + w.Header().Set(headerContentType, contentType) w.Header().Set("Content-Version", swiftContentVersion) w.Header().Set("ETag", etag) if r.Header.Get("If-None-Match") == etag { w.WriteHeader(http.StatusNotModified) return } - w.Header().Set("Content-Length", strconv.Itoa(len(body))) + w.Header().Set(headerContentLength, strconv.Itoa(len(body))) w.WriteHeader(http.StatusOK) if r.Method != http.MethodHead { _, _ = w.Write(body) @@ -597,7 +597,7 @@ func (h *SwiftHandler) writeArtifactError(w http.ResponseWriter, err error) { } func writeSwiftProblem(w http.ResponseWriter, status int, detail string) { - w.Header().Set("Content-Type", "application/problem+json") + w.Header().Set(headerContentType, "application/problem+json") w.Header().Set("Content-Version", swiftContentVersion) w.WriteHeader(status) _ = json.NewEncoder(w).Encode(map[string]string{"detail": detail})