diff --git a/internal/handler/cargo.go b/internal/handler/cargo.go index 79fb750..4cf8591 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 9b2de80..fbbd7a4 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 bee5694..cef814b 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 7a0a0e9..722e8f8 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 b7cdeb5..a471330 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 95b0b4c..0e9e3eb 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 b48f4fc..42d26e7 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 50bba0c..8fc5039 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 3b703be..cc7e33f 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 05a58a9..6f4ceaf 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 f91ba58..994c259 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 f3bcb93..15d2891 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 265603f..166b944 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 0fb139b..7df6240 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 303a9e6..9d449ba 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 b1d7e72..03d178f 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 f4cf9e7..e06a3cc 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 545407e..9acc881 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})