mirror of
https://github.com/git-pkgs/proxy.git
synced 2026-08-23 12:24:57 -04:00
* Bump go tool golangci-lint to v2.13.1
The .golangci.yml goconst.ignore-tests setting was added in v2.12.0
(golangci/golangci-lint#6480). On the previously pinned v2.10.1,
config verify fails with "additional properties 'ignore-tests' not
allowed" and the setting is silently ignored at run time, so goconst
counts test-file literals toward min-occurrences.
* Apply gofmt and CutSuffix simplification
- gofmt -w internal/server/health_test.go
- Replace HasSuffix+TrimSuffix with CutSuffix in ParseSize
* Remove dead code and migrate tests off legacy Filesystem storage
Migrate the three test call sites of storage.NewFilesystem to
storage.OpenBucket("file://...") and drop the deprecated
StorageConfig.Path field from test configs, then delete code that
deadcode reports as unreachable from cmd/proxy:
- internal/storage/filesystem.go and its tests
- storage.HashingReader
- enrichment.Service.BulkCheckVulnerabilities and NormalizeLicense
- server.ActiveRequestsMiddleware (no-op body; the real tracking
is the inline r.Use at server.go:226)
- mirror.RegistrySource (unimplemented stub)
metrics.UpdateCircuitBreakerState and RecordCircuitBreakerTrip are
kept because #275 wires them.
Update the CONTRIBUTING.md storage section to reflect blob.go.
94 lines
2.5 KiB
Go
94 lines
2.5 KiB
Go
package server
|
|
|
|
import (
|
|
"context"
|
|
"net/http"
|
|
"strings"
|
|
"sync/atomic"
|
|
"time"
|
|
|
|
"github.com/git-pkgs/proxy/internal/accesslog"
|
|
"github.com/git-pkgs/proxy/internal/metrics"
|
|
"github.com/go-chi/chi/v5/middleware"
|
|
)
|
|
|
|
var requestCounter atomic.Uint64
|
|
|
|
// RequestIDMiddleware adds a sequential request ID to the context and response headers.
|
|
// IDs are formatted as [001], [002], etc. for easy log correlation.
|
|
func RequestIDMiddleware(next http.Handler) http.Handler {
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
_ = requestCounter.Add(1)
|
|
requestID := middleware.GetReqID(r.Context())
|
|
|
|
// Store formatted ID in context
|
|
ctx := accesslog.WithRequestID(r.Context(), requestID)
|
|
|
|
// Add to response header for client tracking
|
|
w.Header().Set("X-Request-ID", requestID)
|
|
|
|
next.ServeHTTP(w, r.WithContext(ctx))
|
|
})
|
|
}
|
|
|
|
// GetRequestID retrieves the request ID from context.
|
|
func GetRequestID(ctx context.Context) string {
|
|
return accesslog.RequestID(ctx)
|
|
}
|
|
|
|
// LoggerMiddleware logs HTTP requests with request ID correlation.
|
|
func (s *Server) LoggerMiddleware(next http.Handler) http.Handler {
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
start := time.Now()
|
|
requestID := GetRequestID(r.Context())
|
|
|
|
rw := &responseWriter{ResponseWriter: w, status: http.StatusOK}
|
|
next.ServeHTTP(rw, r)
|
|
duration := time.Since(start)
|
|
|
|
s.logger.Info("request",
|
|
"request_id", requestID,
|
|
"method", r.Method,
|
|
"path", r.URL.Path,
|
|
"status", rw.status,
|
|
"duration", duration,
|
|
"remote", r.RemoteAddr)
|
|
|
|
if r.URL.Path != "/metrics" {
|
|
metrics.RecordRequest(requestEcosystem(r.URL.Path), rw.status, duration)
|
|
}
|
|
|
|
if s.accessLog != nil {
|
|
if err := s.accessLog.Write(accesslog.Entry{
|
|
Event: accesslog.EventRequest,
|
|
RequestID: requestID,
|
|
Method: r.Method,
|
|
Path: r.URL.EscapedPath(),
|
|
StatusCode: rw.status,
|
|
DurationMS: duration.Milliseconds(),
|
|
RemoteAddr: r.RemoteAddr,
|
|
}); err != nil {
|
|
s.logger.Error("failed to write access log", "error", err)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
func requestEcosystem(path string) string {
|
|
segment, _, _ := strings.Cut(strings.TrimPrefix(path, "/"), "/")
|
|
switch segment {
|
|
case "npm", "cargo", "hex", "pub", "pypi", "maven", "gradle", "nuget",
|
|
"conan", "conda", "cran", "julia", "debian", "rpm":
|
|
return segment
|
|
case "gem":
|
|
return "rubygems"
|
|
case "go":
|
|
return "golang"
|
|
case "composer":
|
|
return "packagist"
|
|
case "v2":
|
|
return "oci"
|
|
default:
|
|
return "other"
|
|
}
|
|
}
|