claude code review changes

This commit is contained in:
2026-02-20 17:05:34 +05:30
parent 136957d75d
commit f1c5b9587b
9 changed files with 151 additions and 130 deletions

2
.gitignore vendored
View File

@@ -1,3 +1,5 @@
.claude
# Profiling files # Profiling files
.prof .prof

View File

@@ -109,7 +109,6 @@ func CORS(opts CORSOption) func(http.Handler) http.Handler {
ch.setAllowedMethods(opts.AllowedMethods) ch.setAllowedMethods(opts.AllowedMethods)
ch.setExposedHeaders(opts.ExposedHeaders) ch.setExposedHeaders(opts.ExposedHeaders)
ch.setMaxAge(opts.MaxAge) ch.setMaxAge(opts.MaxAge)
ch.maxAge = opts.MaxAge
ch.allowCredentials = opts.AllowCredentials ch.allowCredentials = opts.AllowCredentials
return ch return ch

View File

@@ -56,7 +56,7 @@ type (
} }
TransportSecurity struct { TransportSecurity struct {
// Age in seconts // Age in seconds
MaxAge uint MaxAge uint
IncludeSubDomains bool IncludeSubDomains bool
Preload bool Preload bool
@@ -111,108 +111,124 @@ const (
// Helmet headers to secure server response // Helmet headers to secure server response
func Helmet(opt HelmetOption) func(http.Handler) http.Handler { func Helmet(opt HelmetOption) func(http.Handler) http.Handler {
// Precompute all static header values once at middleware creation time.
headers := buildHelmetHeaders(opt)
return func(h http.Handler) http.Handler { return func(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Add("Content-Security-Policy", opt.ContentSecurityPolicy.value()) for _, kv := range headers {
w.Header().Add(kv.key, kv.value)
}
w.Header().Del("X-Powered-By")
h.ServeHTTP(w, r)
})
}
}
// Opener-Policy type headerKV struct {
if opt.CrossOriginOpenerPolicy == "" { key string
w.Header().Add("Cross-Origin-Opener-Policy", string(OpenerSameOrigin)) value string
} else { }
w.Header().Add("Cross-Origin-Opener-Policy", string(opt.CrossOriginOpenerPolicy))
func buildHelmetHeaders(opt HelmetOption) []headerKV {
var headers []headerKV
add := func(key, value string) {
headers = append(headers, headerKV{key: key, value: value})
} }
// Resource-Policy // Content-Security-Policy
if opt.CrossOriginResourcePolicy == "" { add("Content-Security-Policy", opt.ContentSecurityPolicy.value())
w.Header().Add("Cross-Origin-Resource-Policy", string(ResourceSameOrigin))
// Cross-Origin-Opener-Policy
if opt.CrossOriginOpenerPolicy == "" {
add("Cross-Origin-Opener-Policy", string(OpenerSameOrigin))
} else { } else {
w.Header().Add("Cross-Origin-Resource-Policy", string(opt.CrossOriginResourcePolicy)) add("Cross-Origin-Opener-Policy", string(opt.CrossOriginOpenerPolicy))
}
// Cross-Origin-Resource-Policy
if opt.CrossOriginResourcePolicy == "" {
add("Cross-Origin-Resource-Policy", string(ResourceSameOrigin))
} else {
add("Cross-Origin-Resource-Policy", string(opt.CrossOriginResourcePolicy))
} }
// Referrer-Policy // Referrer-Policy
rpCount := len(opt.ReferrerPolicy) if len(opt.ReferrerPolicy) > 0 {
if rpCount > 0 { refP := make([]string, len(opt.ReferrerPolicy))
refP := make([]string, rpCount)
for i, r := range opt.ReferrerPolicy { for i, r := range opt.ReferrerPolicy {
refP[i] = string(r) refP[i] = string(r)
} }
w.Header().Add("Referrer-Policy", string(NoReferrer)) add("Referrer-Policy", strings.Join(refP, ","))
} else { } else {
// default no referer add("Referrer-Policy", string(NoReferrer))
w.Header().Add("Referrer-Policy", string(NoReferrer))
} }
// Origin-Agent-Cluster // Origin-Agent-Cluster
if opt.OriginAgentCluster { if opt.OriginAgentCluster {
w.Header().Add("Origin-Agent-Cluster", "?1") add("Origin-Agent-Cluster", "?1")
} }
// Strict-Transport-Security // Strict-Transport-Security
if opt.StrictTransportSecurity != nil { if opt.StrictTransportSecurity != nil {
var sb strings.Builder var sb strings.Builder
if opt.StrictTransportSecurity.MaxAge == 0 { maxAge := opt.StrictTransportSecurity.MaxAge
opt.StrictTransportSecurity.MaxAge = YearDuration if maxAge == 0 {
maxAge = YearDuration
} }
sb.WriteString(fmt.Sprintf("max-age=%d", opt.StrictTransportSecurity.MaxAge)) sb.WriteString(fmt.Sprintf("max-age=%d", maxAge))
if opt.StrictTransportSecurity.IncludeSubDomains { if opt.StrictTransportSecurity.IncludeSubDomains {
sb.WriteString("; includeSubDomains") sb.WriteString("; includeSubDomains")
} }
if opt.StrictTransportSecurity.Preload { if opt.StrictTransportSecurity.Preload {
sb.WriteString("; preload") sb.WriteString("; preload")
} }
w.Header().Add("Strict-Transport-Security", sb.String()) add("Strict-Transport-Security", sb.String())
} }
// X-Content-Type-Options
if !opt.DisableSniffMimeType { if !opt.DisableSniffMimeType {
// MIME types advertised in the Content-Current headers should be followed and not be changed add("X-Content-Type-Options", "nosniff")
w.Header().Add("X-Content-Type-Options", "nosniff")
} }
// X-DNS-Prefetch-Control
if opt.DisableDNSPrefetch { if opt.DisableDNSPrefetch {
w.Header().Add("X-DNS-Prefetch-Control", "off") add("X-DNS-Prefetch-Control", "off")
} else { } else {
w.Header().Add("X-DNS-Prefetch-Control", "on") add("X-DNS-Prefetch-Control", "on")
} }
// X-Download-Options
if !opt.DisableXDownload { if !opt.DisableXDownload {
// Instructs Internet Explorer not to open the file directly but to offer it for download first. add("X-Download-Options", "noopen")
w.Header().Add("X-Download-Options", "noopen")
} }
// indicate whether a browser should be allowed to render a page in iframe | frame | embed | object // X-Frame-Options
if opt.XFrameOption == "" { if opt.XFrameOption == "" {
w.Header().Add("X-Frame-Options", string(XFrameSameOrigin)) add("X-Frame-Options", string(XFrameSameOrigin))
} else { } else {
w.Header().Add("X-Frame-Options", string(opt.XFrameOption)) add("X-Frame-Options", string(opt.XFrameOption))
} }
// X-Permitted-Cross-Domain-Policies
if opt.CrossDomainPolicies == "" { if opt.CrossDomainPolicies == "" {
w.Header().Add("X-Permitted-Cross-Domain-Policies", string(CDPNone)) add("X-Permitted-Cross-Domain-Policies", string(CDPNone))
} else { } else {
w.Header().Add("X-Permitted-Cross-Domain-Policies", string(opt.CrossDomainPolicies)) add("X-Permitted-Cross-Domain-Policies", string(opt.CrossDomainPolicies))
} }
w.Header().Del("X-Powered-By") // X-Xss-Protection
if opt.XssProtection { if opt.XssProtection {
// feature of IE, Chrome and Safari that stops pages from loading when they detect reflected add("X-Xss-Protection", "1; mode=block")
// cross-site scripting (XSS) attacks.
w.Header().Add("X-Xss-Protection", "1; mode=block")
} else { } else {
// Following a decision by Google Chrome developers to disable Auditor, add("X-Xss-Protection", "0")
// developers should be able to disable the auditor for older browsers and set it to 0.
// The X-XSS-PROTECTION header was found to have a multitude of issues, instead of helping the
// developers protect their application.
w.Header().Add("X-Xss-Protection", "0")
} }
h.ServeHTTP(w, r) return headers
})
}
} }
func (csp *CSP) value() string { func (csp *CSP) value() string {

View File

@@ -64,6 +64,10 @@ func init() {
// where "random" is a base62 random string that uniquely identifies this go // where "random" is a base62 random string that uniquely identifies this go
// process, and where the last number is an atomically incremented request // process, and where the last number is an atomically incremented request
// counter. // counter.
// maxRequestIDLen is the maximum length of an incoming request ID header
// to prevent log injection or memory abuse from malicious clients.
const maxRequestIDLen = 200
func RequestID(next http.Handler) http.Handler { func RequestID(next http.Handler) http.Handler {
fn := func(w http.ResponseWriter, r *http.Request) { fn := func(w http.ResponseWriter, r *http.Request) {
ctx := r.Context() ctx := r.Context()
@@ -71,6 +75,8 @@ func RequestID(next http.Handler) http.Handler {
if requestID == "" { if requestID == "" {
myid := reqid.Add(1) myid := reqid.Add(1)
requestID = fmt.Sprintf("%s-%06d", prefix, myid) requestID = fmt.Sprintf("%s-%06d", prefix, myid)
} else if len(requestID) > maxRequestIDLen {
requestID = requestID[:maxRequestIDLen]
} }
ctx = context.WithValue(ctx, RequestIDKey, requestID) ctx = context.WithValue(ctx, RequestIDKey, requestID)
next.ServeHTTP(w, r.WithContext(ctx)) next.ServeHTTP(w, r.WithContext(ctx))

20
mux.go
View File

@@ -23,6 +23,22 @@ func New() *Mux {
mux: http.NewServeMux(), mux: http.NewServeMux(),
routes: new(RouteList), routes: new(RouteList),
} }
// Catch-all OPTIONS handler.
// Pass it through all middlewares and drain oversized bodies.
m.OPTIONS("/", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Length", "0")
if r.ContentLength != 0 {
// Read up to 4KB of OPTIONS body (as mentioned in the
// spec as being reserved for future use), but anything
// over that is considered a waste of server resources
// (or an attack) and we abort and close the connection,
// courtesy of MaxBytesReader's EOF behavior.
mb := http.MaxBytesReader(w, r.Body, 4<<10)
_, _ = io.Copy(io.Discard, mb)
}
})
return m return m
} }
@@ -147,8 +163,8 @@ func (m *Mux) ServeHTTP(w http.ResponseWriter, req *http.Request) {
func (m *Mux) PrintRoutes(w io.Writer) { func (m *Mux) PrintRoutes(w io.Writer) {
for _, route := range m.routes.All() { for _, route := range m.routes.All() {
w.Write([]byte(route)) _, _ = w.Write([]byte(route))
w.Write([]byte("\n")) _, _ = w.Write([]byte("\n"))
} }
} }

View File

@@ -306,10 +306,8 @@ func BenchmarkRouterSimple(b *testing.B) {
source := rand.NewSource(time.Now().UnixNano()) source := rand.NewSource(time.Now().UnixNano())
r := rand.New(source) r := rand.New(source)
// Generate a random integer between 0 and 99 (inclusive)
rn := r.Intn(10000)
for b.Loop() { for b.Loop() {
rn := r.Intn(10000)
req, _ := http.NewRequest(http.MethodGet, "/"+strconv.Itoa(rn), nil) req, _ := http.NewRequest(http.MethodGet, "/"+strconv.Itoa(rn), nil)
w := httptest.NewRecorder() w := httptest.NewRecorder()
m.ServeHTTP(w, req) m.ServeHTTP(w, req)

View File

@@ -27,7 +27,7 @@ func (m *Mux) Resource(pattern string, fn func(res *Resource), mw ...func(http.H
} }
if strings.TrimSpace(pattern) == "" { if strings.TrimSpace(pattern) == "" {
panic("mux: Resource() requires a patter to work") panic("mux: Resource() requires a pattern to work")
} }
if fn == nil { if fn == nil {
@@ -215,11 +215,9 @@ func (res *Resource) Use(middlewares ...func(http.Handler) http.Handler) {
} }
func suffixIt(str, suffix string) string { func suffixIt(str, suffix string) string {
var p strings.Builder if strings.HasSuffix(str, "/") {
p.WriteString(str) return str + suffix
if !strings.HasSuffix(str, "/") {
p.WriteString("/")
} }
p.WriteString(suffix)
return p.String() return str + "/" + suffix
} }

View File

@@ -33,7 +33,7 @@ func (s *RouteList) Get(index int) (string, error) {
defer s.mu.RUnlock() defer s.mu.RUnlock()
if index < 0 || index >= len(s.routes) { if index < 0 || index >= len(s.routes) {
return "0", fmt.Errorf("index out of bounds") return "", fmt.Errorf("index out of bounds")
} }
return s.routes[index], nil return s.routes[index], nil
} }
@@ -47,5 +47,7 @@ func (s *RouteList) All() []string {
s.mu.RLock() s.mu.RLock()
defer s.mu.RUnlock() defer s.mu.RUnlock()
return s.routes out := make([]string, len(s.routes))
copy(out, s.routes)
return out
} }

View File

@@ -3,7 +3,6 @@ package mux
import ( import (
"context" "context"
"errors" "errors"
"io"
"log" "log"
"log/slog" "log/slog"
"net" "net"
@@ -26,21 +25,6 @@ func (m *Mux) Serve(cb ServeCB) {
rootCtx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM) rootCtx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM)
defer stop() defer stop()
// catch all options
// lets get it thorugh all middlewares
m.OPTIONS("/", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Length", "0")
if r.ContentLength != 0 {
// Read up to 4KB of OPTIONS body (as mentioned in the
// spec as being reserved for future use), but anything
// over that is considered a waste of server resources
// (or an attack) and we abort and close the connection,
// courtesy of MaxBytesReader's EOF behavior.
mb := http.MaxBytesReader(w, r.Body, 4<<10)
io.Copy(io.Discard, mb)
}
})
srvCtx, cancelSrvCtx := context.WithCancel(context.Background()) srvCtx, cancelSrvCtx := context.WithCancel(context.Background())
srv := &http.Server{ srv := &http.Server{
Handler: m, Handler: m,
@@ -51,7 +35,7 @@ func (m *Mux) Serve(cb ServeCB) {
go func() { go func() {
if err := cb(srv); !errors.Is(err, http.ErrServerClosed) { if err := cb(srv); !errors.Is(err, http.ErrServerClosed) {
panic(err) log.Fatalf("server error: %v", err)
} }
}() }()
@@ -60,7 +44,7 @@ func (m *Mux) Serve(cb ServeCB) {
stop() stop()
m.IsShuttingDown.Store(true) m.IsShuttingDown.Store(true)
slog.Info("received interrupt singal, shutting down") slog.Info("received interrupt signal, shutting down")
time.Sleep(drainDelay) time.Sleep(drainDelay)
slog.Info("readiness check propagated, now waiting for ongoing requests to finish.") slog.Info("readiness check propagated, now waiting for ongoing requests to finish.")
@@ -74,5 +58,5 @@ func (m *Mux) Serve(cb ServeCB) {
time.Sleep(shutdownHardDelay) time.Sleep(shutdownHardDelay)
} }
slog.Info("seerver shut down gracefully") slog.Info("server shut down gracefully")
} }