Skip to main content

pkg/gateway/server/middleware/middleware.go

Source

Overview

What:

A collection of HTTP middleware functions used by the gateway server.

The middleware in this file covers common cross-cutting concerns:

  • request/trace ID propagation to responses
  • baseline security headers
  • request body size limits
  • per-client rate limiting
  • CORS enforcement
  • structured request logging and protocol metrics integration (including upgraded connections)

Why:

Middleware is the "seam" where the gateway enforces platform policy consistently for every request.

This package keeps the middleware logic decoupled from specific implementations by expressing its dependencies as small interfaces and function types (logger, problem writer, ID generators, rate-limit allow/key functions, protocol metric callbacks).

That design makes it easier to:

  • unit test the middleware in isolation
  • swap implementations (e.g., different logging backend)
  • compose a server pipeline without creating import cycles

How:

Each exported middleware constructor returns a standard wrapper: func(http.Handler) http.Handler.

Callers (typically pkg/gateway/server) build a chain by composing these wrappers. Many middleware functions are intentionally nil-safe: if a required dependency is not provided, they return an identity wrapper (or the next handler) to keep server wiring simple.

The Logging middleware uses a custom ResponseWriter wrapper to:

  • capture status code and bytes written
  • support Flush/Push passthrough
  • intercept Hijack() so upgraded connections can be wrapped and tracked on close

Notes:

Be careful about logging sensitive data. This middleware logs request path and metadata, not bodies. Body size limits use both Content-Length checks and http.MaxBytesReader for enforcement.

Contents

Imports

import block 1

pkg/gateway/server/middleware/middleware.go#L3
import (
"bufio"
"context"
"errors"
"fmt"
"net"
"net/http"
"strings"
"sync"
"time"

"github.com/rs/cors"
)

Types

type block 1

pkg/gateway/server/middleware/middleware.go#L18
type Logger interface {
Infow(msg string, keysAndValues ...any)
Warnw(msg string, keysAndValues ...any)
Errorw(msg string, keysAndValues ...any)
}

Logger

What: Minimal logger interface required by middleware.

Why: Avoids importing the full logging package and prevents dependency cycles.

How: Implemented by pkg/log.Logger adapters and passed into Logging.

Notes: Uses Zap-style *w methods (message plus key/value fields).

type block 2

pkg/gateway/server/middleware/middleware.go#L25
type ProblemWriter func(w http.ResponseWriter, status int, title, detail, traceID, instance string)

ProblemWriter

What: Function that writes a problem+json response.

Why: Centralizes error response formatting so middleware can emit consistent error bodies.

How: Called by BodyLimit, RateLimit, and CORS when provided; otherwise those middleware fall back to http.Error.

type block 3

pkg/gateway/server/middleware/middleware.go#L28
type EnsureIDs func(*http.Request) (*http.Request, string, string)

EnsureIDs

What: Function type that ensures a request has request/trace identifiers.

Why: ID generation/extraction is owned by higher-level middleware or tracing systems, not by this package.

How: Returns an updated request (if needed) plus request ID and trace ID strings.

type block 4

pkg/gateway/server/middleware/middleware.go#L31
type TraceIDFromContext func(context.Context) string

TraceIDFromContext

What: Extractor that reads a trace ID from a context.

Why: Logging and problem responses often want trace IDs for correlation, but the storage mechanism is owned elsewhere.

How: Called by Logging and by error middleware to include trace IDs when available.

type block 5

pkg/gateway/server/middleware/middleware.go#L34
type RequestIDFromContext func(context.Context) string

RequestIDFromContext

What: Extractor that reads a request ID from a context.

Why: Logging should not know how IDs are stored in context.

How: Called by Logging to add requestId field when non-empty.

type block 6

pkg/gateway/server/middleware/middleware.go#L37
type ClientAddress func(*http.Request) string

ClientAddress

What: Extractor that resolves a client address string from an HTTP request.

Why: Logging should record a stable client identifier without hardcoding a specific proxy/header strategy.

How: Used by Logging to optionally append a remoteAddr field.

Notes: Implementations typically consult X-Forwarded-For and X-Real-IP in addition to RemoteAddr.

type block 7

pkg/gateway/server/middleware/middleware.go#L40
type TrackFunc func(*http.Request) func(status int, elapsed time.Duration)

TrackFunc

What: Callback that returns a per-request metric recording function.

Why: Allows middleware to time requests and record metrics without importing Prometheus packages.

How: Called at request start; the returned function is called at request end with status and elapsed duration.

type block 8

pkg/gateway/server/middleware/middleware.go#L43
type HijackedFunc func(*http.Request) (func(), func(net.Conn) net.Conn)

HijackedFunc

What: Callback used to integrate upgraded-connection tracking and wrapping into the logging middleware.

Why: Upgraded connections need lifetime hooks (close callbacks) and sometimes need connection wrapping (timeouts, tracking, limits).

How: Called from loggingResponseWriter.Hijack() and returns an on-close callback plus an optional net.Conn wrapper.

Notes: The wrapper is applied before the on-close tracking wrapper.

type block 9

pkg/gateway/server/middleware/middleware.go#L46
type AllowFunc func(key string, now time.Time) bool

AllowFunc

What: Function type that decides whether a rate-limit key is allowed at a given time.

Why: Decouples middleware from any specific rate limiter implementation.

How: Called by RateLimit with a derived key and a timestamp.

type block 10

pkg/gateway/server/middleware/middleware.go#L49
type ClientKey func(*http.Request) string

ClientKey

What: Function type that derives a rate-limit key from a request.

Why: Allows the rate limiting policy to choose between IP-based keys, API keys, JWT subjects, etc.

How: Used by RateLimit before calling AllowFunc.

type block 11

pkg/gateway/server/middleware/middleware.go#L249
type loggingResponseWriter struct {
http.ResponseWriter
status int
bytes int
hijackTracker func() (func(), func(net.Conn) net.Conn)
hijackOnce sync.Once
}

loggingResponseWriter

What: An http.ResponseWriter wrapper that captures status/bytes and supports hijack tracking.

Why: The standard interface does not expose status codes or byte counts, and upgraded connections need lifecycle hooks.

How: Embeds the underlying writer and intercepts WriteHeader, Write, and Hijack.

type block 12

pkg/gateway/server/middleware/middleware.go#L319
type trackingConn struct {
net.Conn
onClose func()
once sync.Once
timeout time.Duration
}

trackingConn

What: Connection wrapper used to invoke an on-close callback once.

Why: Connection lifetime metrics and accounting require a reliable "closed" signal.

How: Wraps a net.Conn, delegates most operations, and calls onClose via sync.Once in Close().

Notes: Also includes optional read/write deadline enforcement when timeout is set.

Functions and Methods

RequestMetadata

What: Ensures every request has stable IDs and echoes them back in response headers.

Why: Request/trace IDs are foundational for debugging, log correlation, and distributed tracing.

How: Calls the injected EnsureIDs function to obtain a possibly-updated request and IDs, then sets X-Request-Id and X-Trace-Id headers before calling the next handler.

Notes: If ensure is nil, this middleware becomes a no-op wrapper.

pkg/gateway/server/middleware/middleware.go#L52
func RequestMetadata(ensure EnsureIDs) func(http.Handler) http.Handler {
if ensure == nil {
return func(next http.Handler) http.Handler { return next }
}

return func(next http.Handler) http.Handler {
if next == nil {
return http.HandlerFunc(func(http.ResponseWriter, *http.Request) {})
}
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
req, requestID, traceID := ensure(r)
w.Header().Set("X-Request-Id", requestID)
if traceID != "" {
w.Header().Set("X-Trace-Id", traceID)
}
next.ServeHTTP(w, req)
})
}
}

Walkthrough

The list below documents the statements inside the function body, including nested blocks and inline closures.

  • L53: if ensure == nil { return func(next http.Handler) http.Handler { return next } }
    • What: Branches conditionally.
    • Why: Short-circuits early when a precondition is not met or an error/edge case is detected.
    • How: Evaluates the condition and executes the matching branch.
    • Nested steps:
      • L54: return func(next http.Handler) http.Handler { return next }
        • What: Returns from the current function.
        • Why: Ends the current execution path and hands control back to the caller.
        • How: Executes a return statement (possibly returning values).
        • Nested steps:
          • L54: func(next http.Handler) http.Handler { return next }
            • What: Defines an inline function (closure).
            • Why: Encapsulates callback logic and may capture variables from the surrounding scope.
            • How: Declares a func literal and uses it as a value (for example, as an HTTP handler or callback).
            • Nested steps:
              • L54: return next
                • What: Returns from the current function.
                • Why: Ends the current execution path and hands control back to the caller.
                • How: Executes a return statement (possibly returning values).
  • L57: return func(next http.Handler) http.Handler { if next == nil { return http.HandlerFunc(func(http.ResponseWriter, *http.Request) {}) } retur…
    • What: Returns from the current function.
    • Why: Ends the current execution path and hands control back to the caller.
    • How: Executes a return statement (possibly returning values).
    • Nested steps:
      • L57: func(next http.Handler) http.Handler { if next == nil { return http.HandlerFunc(func(http.ResponseWriter, *http.Request) {}) } return http.…
        • What: Defines an inline function (closure).
        • Why: Encapsulates callback logic and may capture variables from the surrounding scope.
        • How: Declares a func literal and uses it as a value (for example, as an HTTP handler or callback).
        • Nested steps:
          • L58: if next == nil { return http.HandlerFunc(func(http.ResponseWriter, *http.Request) {}) }
            • What: Branches conditionally.
            • Why: Short-circuits early when a precondition is not met or an error/edge case is detected.
            • How: Evaluates the condition and executes the matching branch.
            • Nested steps:
              • L59: return http.HandlerFunc(func(http.ResponseWriter, *http.Request) {})
                • What: Returns from the current function.
                • Why: Ends the current execution path and hands control back to the caller.
                • How: Executes a return statement (possibly returning values).
                • Nested steps:
                  • L59: func(http.ResponseWriter, *http.Request) {}
                    • What: Defines an inline function (closure).
                    • Why: Encapsulates callback logic and may capture variables from the surrounding scope.
                    • How: Declares a func literal and uses it as a value (for example, as an HTTP handler or callback).
          • L61: return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { req, requestID, traceID := ensure(r) w.Header().Set("X-Request-Id", …
            • What: Returns from the current function.
            • Why: Ends the current execution path and hands control back to the caller.
            • How: Executes a return statement (possibly returning values).
            • Nested steps:
              • L61: func(w http.ResponseWriter, r *http.Request) { req, requestID, traceID := ensure(r) w.Header().Set("X-Request-Id", requestID) if traceID !=…
                • What: Defines an inline function (closure).
                • Why: Encapsulates callback logic and may capture variables from the surrounding scope.
                • How: Declares a func literal and uses it as a value (for example, as an HTTP handler or callback).
                • Nested steps:
                  • L62: req, requestID, traceID := ensure(r)
                    • What: Defines req, requestID, traceID.
                    • Why: Keeps intermediate state available for later steps in the function.
                    • How: Evaluates the right-hand side expressions and stores results in the left-hand variables.
                  • L63: w.Header().Set("X-Request-Id", requestID)
                    • What: Calls w.Header().Set.
                    • Why: Performs side effects or delegates work to a helper.
                    • How: Executes the expression statement.
                  • L64: if traceID != "" { w.Header().Set("X-Trace-Id", traceID) }
                    • What: Branches conditionally.
                    • Why: Handles different execution paths based on runtime state.
                    • How: Evaluates the condition and executes the matching branch.
                    • Nested steps:
                      • L65: w.Header().Set("X-Trace-Id", traceID)
                        • What: Calls w.Header().Set.
                        • Why: Performs side effects or delegates work to a helper.
                        • How: Executes the expression statement.
                  • L67: next.ServeHTTP(w, req)
                    • What: Calls next.ServeHTTP.
                    • Why: Performs side effects or delegates work to a helper.
                    • How: Executes the expression statement.

SecurityHeaders

What: Adds baseline security hardening headers to all responses.

Why: Many responses are proxied, but the gateway still acts as the edge and should provide consistent browser hardening defaults.

How: Sets headers like X-Content-Type-Options, X-Frame-Options, Referrer-Policy, and Permissions-Policy before calling the next handler.

Notes: These headers are conservative defaults. If you need CSP/HSTS, add them at a higher layer with environment-specific configuration.

pkg/gateway/server/middleware/middleware.go#L73
func SecurityHeaders() func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
if next == nil {
return http.HandlerFunc(func(http.ResponseWriter, *http.Request) {})
}
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
headers := w.Header()
headers.Set("X-Content-Type-Options", "nosniff")
headers.Set("X-Frame-Options", "DENY")
headers.Set("Referrer-Policy", "no-referrer")
headers.Set("Permissions-Policy", "geolocation=(), microphone=(), camera=()")
next.ServeHTTP(w, r)
})
}
}

Walkthrough

The list below documents the statements inside the function body, including nested blocks and inline closures.

  • L74: return func(next http.Handler) http.Handler { if next == nil { return http.HandlerFunc(func(http.ResponseWriter, *http.Request) {}) } retur…
    • What: Returns from the current function.
    • Why: Ends the current execution path and hands control back to the caller.
    • How: Executes a return statement (possibly returning values).
    • Nested steps:
      • L74: func(next http.Handler) http.Handler { if next == nil { return http.HandlerFunc(func(http.ResponseWriter, *http.Request) {}) } return http.…
        • What: Defines an inline function (closure).
        • Why: Encapsulates callback logic and may capture variables from the surrounding scope.
        • How: Declares a func literal and uses it as a value (for example, as an HTTP handler or callback).
        • Nested steps:
          • L75: if next == nil { return http.HandlerFunc(func(http.ResponseWriter, *http.Request) {}) }
            • What: Branches conditionally.
            • Why: Short-circuits early when a precondition is not met or an error/edge case is detected.
            • How: Evaluates the condition and executes the matching branch.
            • Nested steps:
              • L76: return http.HandlerFunc(func(http.ResponseWriter, *http.Request) {})
                • What: Returns from the current function.
                • Why: Ends the current execution path and hands control back to the caller.
                • How: Executes a return statement (possibly returning values).
                • Nested steps:
                  • L76: func(http.ResponseWriter, *http.Request) {}
                    • What: Defines an inline function (closure).
                    • Why: Encapsulates callback logic and may capture variables from the surrounding scope.
                    • How: Declares a func literal and uses it as a value (for example, as an HTTP handler or callback).
          • L78: return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { headers := w.Header() headers.Set("X-Content-Type-Options", "nosniff…
            • What: Returns from the current function.
            • Why: Ends the current execution path and hands control back to the caller.
            • How: Executes a return statement (possibly returning values).
            • Nested steps:
              • L78: func(w http.ResponseWriter, r *http.Request) { headers := w.Header() headers.Set("X-Content-Type-Options", "nosniff") headers.Set("X-Frame-…
                • What: Defines an inline function (closure).
                • Why: Encapsulates callback logic and may capture variables from the surrounding scope.
                • How: Declares a func literal and uses it as a value (for example, as an HTTP handler or callback).
                • Nested steps:
                  • L79: headers := w.Header()
                    • What: Defines headers.
                    • Why: Keeps intermediate state available for later steps in the function.
                    • How: Evaluates the right-hand side expressions and stores results in the left-hand variables.
                  • L80: headers.Set("X-Content-Type-Options", "nosniff")
                    • What: Calls headers.Set.
                    • Why: Performs side effects or delegates work to a helper.
                    • How: Executes the expression statement.
                  • L81: headers.Set("X-Frame-Options", "DENY")
                    • What: Calls headers.Set.
                    • Why: Performs side effects or delegates work to a helper.
                    • How: Executes the expression statement.
                  • L82: headers.Set("Referrer-Policy", "no-referrer")
                    • What: Calls headers.Set.
                    • Why: Performs side effects or delegates work to a helper.
                    • How: Executes the expression statement.
                  • L83: headers.Set("Permissions-Policy", "geolocation=(), microphone=(), camera=()")
                    • What: Calls headers.Set.
                    • Why: Performs side effects or delegates work to a helper.
                    • How: Executes the expression statement.
                  • L84: next.ServeHTTP(w, r)
                    • What: Calls next.ServeHTTP.
                    • Why: Performs side effects or delegates work to a helper.
                    • How: Executes the expression statement.

BodyLimit

What: Enforces a maximum request body size.

Why: Protects the gateway from accidental or malicious large payloads that can consume memory and upstream bandwidth.

How: Rejects requests with Content-Length above the limit with 413; otherwise wraps r.Body with http.MaxBytesReader so reads cannot exceed the limit.

Notes: If Content-Length is unknown (-1), the MaxBytesReader path is the enforcement mechanism.

pkg/gateway/server/middleware/middleware.go#L90
func BodyLimit(limit int64, trace TraceIDFromContext, write ProblemWriter) func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
if next == nil {
return http.HandlerFunc(func(http.ResponseWriter, *http.Request) {})
}
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.ContentLength > limit {
tid := ""
if trace != nil {
tid = trace(r.Context())
}
if write != nil {
write(w, http.StatusRequestEntityTooLarge, "Payload Too Large", fmt.Sprintf("Request body exceeds %d bytes", limit), tid, r.URL.Path)
return
}
http.Error(w, http.StatusText(http.StatusRequestEntityTooLarge), http.StatusRequestEntityTooLarge)
return
}
if r.Body != nil {
r.Body = http.MaxBytesReader(w, r.Body, limit)
}
next.ServeHTTP(w, r)
})
}
}

Walkthrough

The list below documents the statements inside the function body, including nested blocks and inline closures.

  • L91: return func(next http.Handler) http.Handler { if next == nil { return http.HandlerFunc(func(http.ResponseWriter, *http.Request) {}) } retur…
    • What: Returns from the current function.
    • Why: Ends the current execution path and hands control back to the caller.
    • How: Executes a return statement (possibly returning values).
    • Nested steps:
      • L91: func(next http.Handler) http.Handler { if next == nil { return http.HandlerFunc(func(http.ResponseWriter, *http.Request) {}) } return http.…
        • What: Defines an inline function (closure).
        • Why: Encapsulates callback logic and may capture variables from the surrounding scope.
        • How: Declares a func literal and uses it as a value (for example, as an HTTP handler or callback).
        • Nested steps:
          • L92: if next == nil { return http.HandlerFunc(func(http.ResponseWriter, *http.Request) {}) }
            • What: Branches conditionally.
            • Why: Short-circuits early when a precondition is not met or an error/edge case is detected.
            • How: Evaluates the condition and executes the matching branch.
            • Nested steps:
              • L93: return http.HandlerFunc(func(http.ResponseWriter, *http.Request) {})
                • What: Returns from the current function.
                • Why: Ends the current execution path and hands control back to the caller.
                • How: Executes a return statement (possibly returning values).
                • Nested steps:
                  • L93: func(http.ResponseWriter, *http.Request) {}
                    • What: Defines an inline function (closure).
                    • Why: Encapsulates callback logic and may capture variables from the surrounding scope.
                    • How: Declares a func literal and uses it as a value (for example, as an HTTP handler or callback).
          • L95: return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if r.ContentLength > limit { tid := "" if trace != nil { tid = trace…
            • What: Returns from the current function.
            • Why: Ends the current execution path and hands control back to the caller.
            • How: Executes a return statement (possibly returning values).
            • Nested steps:
              • L95: func(w http.ResponseWriter, r *http.Request) { if r.ContentLength > limit { tid := "" if trace != nil { tid = trace(r.Context()) } if write…
                • What: Defines an inline function (closure).
                • Why: Encapsulates callback logic and may capture variables from the surrounding scope.
                • How: Declares a func literal and uses it as a value (for example, as an HTTP handler or callback).
                • Nested steps:
                  • L96: if r.ContentLength > limit { tid := "" if trace != nil { tid = trace(r.Context()) } if write != nil { write(w, http.StatusRequestEntityTooL…
                    • What: Branches conditionally.
                    • Why: Short-circuits early when a precondition is not met or an error/edge case is detected.
                    • How: Evaluates the condition and executes the matching branch.
                    • Nested steps:
                      • L97: tid := ""
                        • What: Defines tid.
                        • Why: Keeps intermediate state available for later steps in the function.
                        • How: Evaluates the right-hand side expressions and stores results in the left-hand variables.
                      • L98: if trace != nil { tid = trace(r.Context()) }
                        • What: Branches conditionally.
                        • Why: Handles different execution paths based on runtime state.
                        • How: Evaluates the condition and executes the matching branch.
                        • Nested steps:
                          • L99: tid = trace(r.Context())
                            • What: Assigns tid.
                            • Why: Keeps intermediate state available for later steps in the function.
                            • How: Evaluates the right-hand side expressions and stores results in the left-hand variables.
                      • L101: if write != nil { write(w, http.StatusRequestEntityTooLarge, "Payload Too Large", fmt.Sprintf("Request body exceeds %d bytes", limit), tid,…
                        • What: Branches conditionally.
                        • Why: Short-circuits early when a precondition is not met or an error/edge case is detected.
                        • How: Evaluates the condition and executes the matching branch.
                        • Nested steps:
                          • L102: write(w, http.StatusRequestEntityTooLarge, "Payload Too Large", fmt.Sprintf("Request body exceeds %d bytes", limit), tid, r.URL.Path)
                            • What: Calls write.
                            • Why: Performs side effects or delegates work to a helper.
                            • How: Executes the expression statement.
                          • L103: return
                            • What: Returns from the current function.
                            • Why: Ends the current execution path and hands control back to the caller.
                            • How: Executes a return statement (possibly returning values).
                      • L105: http.Error(w, http.StatusText(http.StatusRequestEntityTooLarge), http.StatusRequestEntityTooLarge)
                        • What: Calls http.Error.
                        • Why: Performs side effects or delegates work to a helper.
                        • How: Executes the expression statement.
                      • L106: return
                        • What: Returns from the current function.
                        • Why: Ends the current execution path and hands control back to the caller.
                        • How: Executes a return statement (possibly returning values).
                  • L108: if r.Body != nil { r.Body = http.MaxBytesReader(w, r.Body, limit) }
                    • What: Branches conditionally.
                    • Why: Handles different execution paths based on runtime state.
                    • How: Evaluates the condition and executes the matching branch.
                    • Nested steps:
                      • L109: r.Body = http.MaxBytesReader(w, r.Body, limit)
                        • What: Assigns r.Body.
                        • Why: Keeps intermediate state available for later steps in the function.
                        • How: Evaluates the right-hand side expressions and stores results in the left-hand variables.
                  • L111: next.ServeHTTP(w, r)
                    • What: Calls next.ServeHTTP.
                    • Why: Performs side effects or delegates work to a helper.
                    • How: Executes the expression statement.

RateLimit

What: Enforces per-client rate limiting.

Why: Provides a safety valve against abusive clients and protects upstream services from burst load.

How: Uses a provided AllowFunc (rate-limit decision) and ClientKey (key derivation). OPTIONS requests bypass the limiter. Exceeded limits return 429 with a problem response when available.

Notes: The middleware is deliberately generic; the actual limiter implementation lives elsewhere.

pkg/gateway/server/middleware/middleware.go#L117
func RateLimit(allow AllowFunc, key ClientKey, now func() time.Time, trace TraceIDFromContext, write ProblemWriter) func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
if next == nil || allow == nil || key == nil || now == nil {
return next
}
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Method == http.MethodOptions {
next.ServeHTTP(w, r)
return
}
client := key(r)
if allow(client, now()) {
next.ServeHTTP(w, r)
return
}
if write != nil {
tid := ""
if trace != nil {
tid = trace(r.Context())
}
write(w, http.StatusTooManyRequests, "Too Many Requests", "Rate limit exceeded", tid, r.URL.Path)
} else {
http.Error(w, http.StatusText(http.StatusTooManyRequests), http.StatusTooManyRequests)
}
})
}
}

Walkthrough

The list below documents the statements inside the function body, including nested blocks and inline closures.

  • L118: return func(next http.Handler) http.Handler { if next == nil || allow == nil || key == nil || now == nil { return next } return http.Handle…
    • What: Returns from the current function.
    • Why: Ends the current execution path and hands control back to the caller.
    • How: Executes a return statement (possibly returning values).
    • Nested steps:
      • L118: func(next http.Handler) http.Handler { if next == nil || allow == nil || key == nil || now == nil { return next } return http.HandlerFunc(f…
        • What: Defines an inline function (closure).
        • Why: Encapsulates callback logic and may capture variables from the surrounding scope.
        • How: Declares a func literal and uses it as a value (for example, as an HTTP handler or callback).
        • Nested steps:
          • L119: if next == nil || allow == nil || key == nil || now == nil { return next }
            • What: Branches conditionally.
            • Why: Short-circuits early when a precondition is not met or an error/edge case is detected.
            • How: Evaluates the condition and executes the matching branch.
            • Nested steps:
              • L120: return next
                • What: Returns from the current function.
                • Why: Ends the current execution path and hands control back to the caller.
                • How: Executes a return statement (possibly returning values).
          • L122: return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if r.Method == http.MethodOptions { next.ServeHTTP(w, r) return } cl…
            • What: Returns from the current function.
            • Why: Ends the current execution path and hands control back to the caller.
            • How: Executes a return statement (possibly returning values).
            • Nested steps:
              • L122: func(w http.ResponseWriter, r *http.Request) { if r.Method == http.MethodOptions { next.ServeHTTP(w, r) return } client := key(r) if allow(…
                • What: Defines an inline function (closure).
                • Why: Encapsulates callback logic and may capture variables from the surrounding scope.
                • How: Declares a func literal and uses it as a value (for example, as an HTTP handler or callback).
                • Nested steps:
                  • L123: if r.Method == http.MethodOptions { next.ServeHTTP(w, r) return }
                    • What: Branches conditionally.
                    • Why: Short-circuits early when a precondition is not met or an error/edge case is detected.
                    • How: Evaluates the condition and executes the matching branch.
                    • Nested steps:
                      • L124: next.ServeHTTP(w, r)
                        • What: Calls next.ServeHTTP.
                        • Why: Performs side effects or delegates work to a helper.
                        • How: Executes the expression statement.
                      • L125: return
                        • What: Returns from the current function.
                        • Why: Ends the current execution path and hands control back to the caller.
                        • How: Executes a return statement (possibly returning values).
                  • L127: client := key(r)
                    • What: Defines client.
                    • Why: Keeps intermediate state available for later steps in the function.
                    • How: Evaluates the right-hand side expressions and stores results in the left-hand variables.
                  • L128: if allow(client, now()) { next.ServeHTTP(w, r) return }
                    • What: Branches conditionally.
                    • Why: Short-circuits early when a precondition is not met or an error/edge case is detected.
                    • How: Evaluates the condition and executes the matching branch.
                    • Nested steps:
                      • L129: next.ServeHTTP(w, r)
                        • What: Calls next.ServeHTTP.
                        • Why: Performs side effects or delegates work to a helper.
                        • How: Executes the expression statement.
                      • L130: return
                        • What: Returns from the current function.
                        • Why: Ends the current execution path and hands control back to the caller.
                        • How: Executes a return statement (possibly returning values).
                  • L132: if write != nil { tid := "" if trace != nil { tid = trace(r.Context()) } write(w, http.StatusTooManyRequests, "Too Many Requests", "Rate li…
                    • What: Branches conditionally.
                    • Why: Handles different execution paths based on runtime state.
                    • How: Evaluates the condition and executes the matching branch.
                    • Nested steps:
                      • L133: tid := ""
                        • What: Defines tid.
                        • Why: Keeps intermediate state available for later steps in the function.
                        • How: Evaluates the right-hand side expressions and stores results in the left-hand variables.
                      • L134: if trace != nil { tid = trace(r.Context()) }
                        • What: Branches conditionally.
                        • Why: Handles different execution paths based on runtime state.
                        • How: Evaluates the condition and executes the matching branch.
                        • Nested steps:
                          • L135: tid = trace(r.Context())
                            • What: Assigns tid.
                            • Why: Keeps intermediate state available for later steps in the function.
                            • How: Evaluates the right-hand side expressions and stores results in the left-hand variables.
                      • L137: write(w, http.StatusTooManyRequests, "Too Many Requests", "Rate limit exceeded", tid, r.URL.Path)
                        • What: Calls write.
                        • Why: Performs side effects or delegates work to a helper.
                        • How: Executes the expression statement.
                      • L139: http.Error(w, http.StatusText(http.StatusTooManyRequests), http.StatusTooManyRequests)
                        • What: Calls http.Error.
                        • Why: Performs side effects or delegates work to a helper.
                        • How: Executes the expression statement.

CORS

What: Applies CORS policy using the provided *cors.Cors configuration.

Why: Browsers enforce CORS, and the gateway needs to provide a centralized origin policy across all proxied endpoints.

How: Wraps the next handler with handler.Handler(next) and pre-checks OriginAllowed so disallowed origins can return a consistent 403 problem response.

Notes: The explicit origin check exists so operators get clear feedback instead of relying on default cors library behaviour.

pkg/gateway/server/middleware/middleware.go#L146
func CORS(handler *cors.Cors, trace TraceIDFromContext, write ProblemWriter) func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
if handler == nil || next == nil {
return next
}
corsHandler := handler.Handler(next)
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
origin := strings.TrimSpace(r.Header.Get("Origin"))
if origin != "" && !handler.OriginAllowed(r) {
if write != nil {
tid := ""
if trace != nil {
tid = trace(r.Context())
}
write(w, http.StatusForbidden, "Not allowed by CORS", fmt.Sprintf("Origin %s is not allowed", origin), tid, r.URL.Path)
} else {
http.Error(w, http.StatusText(http.StatusForbidden), http.StatusForbidden)
}
return
}
corsHandler.ServeHTTP(w, r)
})
}
}

Walkthrough

The list below documents the statements inside the function body, including nested blocks and inline closures.

  • L147: return func(next http.Handler) http.Handler { if handler == nil || next == nil { return next } corsHandler := handler.Handler(next) return …
    • What: Returns from the current function.
    • Why: Ends the current execution path and hands control back to the caller.
    • How: Executes a return statement (possibly returning values).
    • Nested steps:
      • L147: func(next http.Handler) http.Handler { if handler == nil || next == nil { return next } corsHandler := handler.Handler(next) return http.Ha…
        • What: Defines an inline function (closure).
        • Why: Encapsulates callback logic and may capture variables from the surrounding scope.
        • How: Declares a func literal and uses it as a value (for example, as an HTTP handler or callback).
        • Nested steps:
          • L148: if handler == nil || next == nil { return next }
            • What: Branches conditionally.
            • Why: Short-circuits early when a precondition is not met or an error/edge case is detected.
            • How: Evaluates the condition and executes the matching branch.
            • Nested steps:
              • L149: return next
                • What: Returns from the current function.
                • Why: Ends the current execution path and hands control back to the caller.
                • How: Executes a return statement (possibly returning values).
          • L151: corsHandler := handler.Handler(next)
            • What: Defines corsHandler.
            • Why: Keeps intermediate state available for later steps in the function.
            • How: Evaluates the right-hand side expressions and stores results in the left-hand variables.
          • L152: return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { origin := strings.TrimSpace(r.Header.Get("Origin")) if origin != "" …
            • What: Returns from the current function.
            • Why: Ends the current execution path and hands control back to the caller.
            • How: Executes a return statement (possibly returning values).
            • Nested steps:
              • L152: func(w http.ResponseWriter, r *http.Request) { origin := strings.TrimSpace(r.Header.Get("Origin")) if origin != "" && !handler.OriginAllowe…
                • What: Defines an inline function (closure).
                • Why: Encapsulates callback logic and may capture variables from the surrounding scope.
                • How: Declares a func literal and uses it as a value (for example, as an HTTP handler or callback).
                • Nested steps:
                  • L153: origin := strings.TrimSpace(r.Header.Get("Origin"))
                    • What: Defines origin.
                    • Why: Keeps intermediate state available for later steps in the function.
                    • How: Evaluates the right-hand side expressions and stores results in the left-hand variables.
                  • L154: if origin != "" && !handler.OriginAllowed(r) { if write != nil { tid := "" if trace != nil { tid = trace(r.Context()) } write(w, http.Statu…
                    • What: Branches conditionally.
                    • Why: Short-circuits early when a precondition is not met or an error/edge case is detected.
                    • How: Evaluates the condition and executes the matching branch.
                    • Nested steps:
                      • L155: if write != nil { tid := "" if trace != nil { tid = trace(r.Context()) } write(w, http.StatusForbidden, "Not allowed by CORS", fmt.Sprintf(…
                        • What: Branches conditionally.
                        • Why: Handles different execution paths based on runtime state.
                        • How: Evaluates the condition and executes the matching branch.
                        • Nested steps:
                          • L156: tid := ""
                            • What: Defines tid.
                            • Why: Keeps intermediate state available for later steps in the function.
                            • How: Evaluates the right-hand side expressions and stores results in the left-hand variables.
                          • L157: if trace != nil { tid = trace(r.Context()) }
                            • What: Branches conditionally.
                            • Why: Handles different execution paths based on runtime state.
                            • How: Evaluates the condition and executes the matching branch.
                          • L160: write(w, http.StatusForbidden, "Not allowed by CORS", fmt.Sprintf("Origin %s is not allowed", origin), tid, r.URL.Path)
                            • What: Calls write.
                            • Why: Performs side effects or delegates work to a helper.
                            • How: Executes the expression statement.
                          • L162: http.Error(w, http.StatusText(http.StatusForbidden), http.StatusForbidden)
                            • What: Calls http.Error.
                            • Why: Performs side effects or delegates work to a helper.
                            • How: Executes the expression statement.
                      • L164: return
                        • What: Returns from the current function.
                        • Why: Ends the current execution path and hands control back to the caller.
                        • How: Executes a return statement (possibly returning values).
                  • L166: corsHandler.ServeHTTP(w, r)
                    • What: Calls corsHandler.ServeHTTP.
                    • Why: Performs side effects or delegates work to a helper.
                    • How: Executes the expression statement.

Logging

What: Emits structured logs for each HTTP request and optionally integrates protocol metrics tracking.

Why:

Request logs are the primary operational visibility mechanism for the gateway. Integrating protocol metrics here keeps metrics emission aligned with request lifecycle and avoids duplicating timing logic.

How:

  • Records start time and builds a trackFn by calling track(r) (if provided).
  • Wraps the ResponseWriter with loggingResponseWriter to capture status and bytes.
  • Calls next.ServeHTTP.
  • Computes elapsed duration and calls trackFn(status, duration).
  • Logs a message with standard fields (method, path, status, durationMs, bytesWritten) and optional requestId/traceId/remoteAddr.

When hijacked is provided, the response writer's Hijack() path calls it to obtain:

  • an on-close callback (for metrics)
  • an optional net.Conn wrapper (for deadline enforcement or additional tracking)

Notes:

Logging level is chosen by status code (5xx error, 4xx warn, otherwise info). Avoid adding headers or bodies to logs unless they are explicitly scrubbed.

pkg/gateway/server/middleware/middleware.go#L172
func Logging(
logger Logger,
track TrackFunc,
hijacked HijackedFunc,
requestID RequestIDFromContext,
traceID TraceIDFromContext,
clientAddr ClientAddress,
) func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
if next == nil || logger == nil {
return next
}

return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
start := time.Now()

trackFn := func(int, time.Duration) {}
if track != nil {
if fn := track(r); fn != nil {
trackFn = fn
}
}

var hijackTracker func() (func(), func(net.Conn) net.Conn)
if hijacked != nil {
hijackTracker = func() (func(), func(net.Conn) net.Conn) {
return hijacked(r)
}
}

writer := newLoggingResponseWriter(w, hijackTracker)
next.ServeHTTP(writer, r)

duration := time.Since(start)
status := writer.status
if status == 0 {
status = http.StatusOK
}

trackFn(status, duration)

fields := []any{
"method", r.Method,
"path", r.URL.Path,
"status", status,
"durationMs", float64(duration.Microseconds()) / 1000.0,
"bytesWritten", writer.bytes,
}

if requestID != nil {
if rid := requestID(r.Context()); rid != "" {
fields = append(fields, "requestId", rid)
}
}
if traceID != nil {
if tid := traceID(r.Context()); tid != "" {
fields = append(fields, "traceId", tid)
}
}
if clientAddr != nil {
if remote := clientAddr(r); remote != "" {
fields = append(fields, "remoteAddr", remote)
}
}

switch {
case status >= 500:
logger.Errorw("http request completed", fields...)
case status >= 400:
logger.Warnw("http request completed", fields...)
default:
logger.Infow("http request completed", fields...)
}
})
}
}

Walkthrough

Expand walkthrough (44 steps)

The list below documents the statements inside the function body, including nested blocks and inline closures.

  • L180: return func(next http.Handler) http.Handler { if next == nil || logger == nil { return next } return http.HandlerFunc(func(w http.ResponseW…
    • What: Returns from the current function.
    • Why: Ends the current execution path and hands control back to the caller.
    • How: Executes a return statement (possibly returning values).
    • Nested steps:
      • L180: func(next http.Handler) http.Handler { if next == nil || logger == nil { return next } return http.HandlerFunc(func(w http.ResponseWriter, …
        • What: Defines an inline function (closure).
        • Why: Encapsulates callback logic and may capture variables from the surrounding scope.
        • How: Declares a func literal and uses it as a value (for example, as an HTTP handler or callback).
        • Nested steps:
          • L181: if next == nil || logger == nil { return next }
            • What: Branches conditionally.
            • Why: Short-circuits early when a precondition is not met or an error/edge case is detected.
            • How: Evaluates the condition and executes the matching branch.
            • Nested steps:
              • L182: return next
                • What: Returns from the current function.
                • Why: Ends the current execution path and hands control back to the caller.
                • How: Executes a return statement (possibly returning values).
          • L185: return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { start := time.Now() trackFn := func(int, time.Duration) {} if track …
            • What: Returns from the current function.
            • Why: Ends the current execution path and hands control back to the caller.
            • How: Executes a return statement (possibly returning values).
            • Nested steps:
              • L185: func(w http.ResponseWriter, r *http.Request) { start := time.Now() trackFn := func(int, time.Duration) {} if track != nil { if fn := track(…
                • What: Defines an inline function (closure).
                • Why: Encapsulates callback logic and may capture variables from the surrounding scope.
                • How: Declares a func literal and uses it as a value (for example, as an HTTP handler or callback).
                • Nested steps:
                  • L186: start := time.Now()
                    • What: Defines start.
                    • Why: Keeps intermediate state available for later steps in the function.
                    • How: Evaluates the right-hand side expressions and stores results in the left-hand variables.
                  • L188: trackFn := func(int, time.Duration) {}
                    • What: Defines trackFn.
                    • Why: Keeps intermediate state available for later steps in the function.
                    • How: Evaluates the right-hand side expressions and stores results in the left-hand variables.
                    • Nested steps:
                      • L188: func(int, time.Duration) {}
                        • What: Defines an inline function (closure).
                        • Why: Encapsulates callback logic and may capture variables from the surrounding scope.
                        • How: Declares a func literal and uses it as a value (for example, as an HTTP handler or callback).
                  • L189: if track != nil { if fn := track(r); fn != nil { trackFn = fn } }
                    • What: Branches conditionally.
                    • Why: Handles different execution paths based on runtime state.
                    • How: Evaluates the condition and executes the matching branch.
                    • Nested steps:
                      • L190: if fn := track(r); fn != nil { trackFn = fn }
                        • What: Branches conditionally.
                        • Why: Handles different execution paths based on runtime state.
                        • How: Evaluates the condition and executes the matching branch.
                        • Nested steps:
                          • L190: fn := track(r)
                            • What: Defines fn.
                            • Why: Keeps intermediate state available for later steps in the function.
                            • How: Evaluates the right-hand side expressions and stores results in the left-hand variables.
                          • L191: trackFn = fn
                            • What: Assigns trackFn.
                            • Why: Keeps intermediate state available for later steps in the function.
                            • How: Evaluates the right-hand side expressions and stores results in the left-hand variables.
                  • L195: var hijackTracker func() (func(), func(net.Conn) net.Conn)
                    • What: Declares local names.
                    • Why: Introduces variables or types used later in the function.
                    • How: Executes a Go declaration statement inside the function body.
                  • L196: if hijacked != nil { hijackTracker = func() (func(), func(net.Conn) net.Conn) { return hijacked(r) } }
                    • What: Branches conditionally.
                    • Why: Handles different execution paths based on runtime state.
                    • How: Evaluates the condition and executes the matching branch.
                    • Nested steps:
                      • L197: hijackTracker = func() (func(), func(net.Conn) net.Conn) { return hijacked(r) }
                        • What: Assigns hijackTracker.
                        • Why: Keeps intermediate state available for later steps in the function.
                        • How: Evaluates the right-hand side expressions and stores results in the left-hand variables.
                        • Nested steps:
                          • L197: func() (func(), func(net.Conn) net.Conn) { return hijacked(r) }
                            • What: Defines an inline function (closure).
                            • Why: Encapsulates callback logic and may capture variables from the surrounding scope.
                            • How: Declares a func literal and uses it as a value (for example, as an HTTP handler or callback).
                  • L202: writer := newLoggingResponseWriter(w, hijackTracker)
                    • What: Defines writer.
                    • Why: Keeps intermediate state available for later steps in the function.
                    • How: Evaluates the right-hand side expressions and stores results in the left-hand variables.
                  • L203: next.ServeHTTP(writer, r)
                    • What: Calls next.ServeHTTP.
                    • Why: Performs side effects or delegates work to a helper.
                    • How: Executes the expression statement.
                  • L205: duration := time.Since(start)
                    • What: Defines duration.
                    • Why: Keeps intermediate state available for later steps in the function.
                    • How: Evaluates the right-hand side expressions and stores results in the left-hand variables.
                  • L206: status := writer.status
                    • What: Defines status.
                    • Why: Keeps intermediate state available for later steps in the function.
                    • How: Evaluates the right-hand side expressions and stores results in the left-hand variables.
                  • L207: if status == 0 { status = http.StatusOK }
                    • What: Branches conditionally.
                    • Why: Handles different execution paths based on runtime state.
                    • How: Evaluates the condition and executes the matching branch.
                    • Nested steps:
                      • L208: status = http.StatusOK
                        • What: Assigns status.
                        • Why: Keeps intermediate state available for later steps in the function.
                        • How: Evaluates the right-hand side expressions and stores results in the left-hand variables.
                  • L211: trackFn(status, duration)
                    • What: Calls trackFn.
                    • Why: Performs side effects or delegates work to a helper.
                    • How: Executes the expression statement.
                  • L213: fields := []any{ "method", r.Method, "path", r.URL.Path, "status", status, "durationMs", float64(duration.Microseconds()) / 1000.0, "bytesW…
                    • What: Defines fields.
                    • Why: Keeps intermediate state available for later steps in the function.
                    • How: Evaluates the right-hand side expressions and stores results in the left-hand variables.
                  • L221: if requestID != nil { if rid := requestID(r.Context()); rid != "" { fields = append(fields, "requestId", rid) } }
                    • What: Branches conditionally.
                    • Why: Handles different execution paths based on runtime state.
                    • How: Evaluates the condition and executes the matching branch.
                    • Nested steps:
                      • L222: if rid := requestID(r.Context()); rid != "" { fields = append(fields, "requestId", rid) }
                        • What: Branches conditionally.
                        • Why: Handles different execution paths based on runtime state.
                        • How: Evaluates the condition and executes the matching branch.
                        • Nested steps:
                          • L222: rid := requestID(r.Context())
                            • What: Defines rid.
                            • Why: Keeps intermediate state available for later steps in the function.
                            • How: Evaluates the right-hand side expressions and stores results in the left-hand variables.
                          • L223: fields = append(fields, "requestId", rid)
                            • What: Assigns fields.
                            • Why: Keeps intermediate state available for later steps in the function.
                            • How: Evaluates the right-hand side expressions and stores results in the left-hand variables.
                  • L226: if traceID != nil { if tid := traceID(r.Context()); tid != "" { fields = append(fields, "traceId", tid) } }
                    • What: Branches conditionally.
                    • Why: Handles different execution paths based on runtime state.
                    • How: Evaluates the condition and executes the matching branch.
                    • Nested steps:
                      • L227: if tid := traceID(r.Context()); tid != "" { fields = append(fields, "traceId", tid) }
                        • What: Branches conditionally.
                        • Why: Handles different execution paths based on runtime state.
                        • How: Evaluates the condition and executes the matching branch.
                        • Nested steps:
                          • L227: tid := traceID(r.Context())
                            • What: Defines tid.
                            • Why: Keeps intermediate state available for later steps in the function.
                            • How: Evaluates the right-hand side expressions and stores results in the left-hand variables.
                          • L228: fields = append(fields, "traceId", tid)
                            • What: Assigns fields.
                            • Why: Keeps intermediate state available for later steps in the function.
                            • How: Evaluates the right-hand side expressions and stores results in the left-hand variables.
                  • L231: if clientAddr != nil { if remote := clientAddr(r); remote != "" { fields = append(fields, "remoteAddr", remote) } }
                    • What: Branches conditionally.
                    • Why: Handles different execution paths based on runtime state.
                    • How: Evaluates the condition and executes the matching branch.
                    • Nested steps:
                      • L232: if remote := clientAddr(r); remote != "" { fields = append(fields, "remoteAddr", remote) }
                        • What: Branches conditionally.
                        • Why: Handles different execution paths based on runtime state.
                        • How: Evaluates the condition and executes the matching branch.
                        • Nested steps:
                          • L232: remote := clientAddr(r)
                            • What: Defines remote.
                            • Why: Keeps intermediate state available for later steps in the function.
                            • How: Evaluates the right-hand side expressions and stores results in the left-hand variables.
                          • L233: fields = append(fields, "remoteAddr", remote)
                            • What: Assigns fields.
                            • Why: Keeps intermediate state available for later steps in the function.
                            • How: Evaluates the right-hand side expressions and stores results in the left-hand variables.
                  • L237: switch { case status >= 500: logger.Errorw("http request completed", fields...) case status >= 400: logger.Warnw("http request completed", …
                    • What: Selects a branch from multiple cases.
                    • Why: Keeps multi-case branching readable and explicit.
                    • How: Evaluates the switch expression and executes the first matching case.
                    • Nested steps:
                      • L238: case status >= 500:
                        • What: Selects a switch case.
                        • Why: Makes multi-branch control flow explicit and readable.
                        • How: Runs this case body when the switch value matches (or when default is selected).
                        • Nested steps:
                          • L239: logger.Errorw("http request completed", fields...)
                            • What: Calls logger.Errorw.
                            • Why: Performs side effects or delegates work to a helper.
                            • How: Executes the expression statement.
                      • L240: case status >= 400:
                        • What: Selects a switch case.
                        • Why: Makes multi-branch control flow explicit and readable.
                        • How: Runs this case body when the switch value matches (or when default is selected).
                        • Nested steps:
                          • L241: logger.Warnw("http request completed", fields...)
                            • What: Calls logger.Warnw.
                            • Why: Performs side effects or delegates work to a helper.
                            • How: Executes the expression statement.
                      • L242: default:
                        • What: Selects a switch case.
                        • Why: Makes multi-branch control flow explicit and readable.
                        • How: Runs this case body when the switch value matches (or when default is selected).
                        • Nested steps:
                          • L243: logger.Infow("http request completed", fields...)
                            • What: Calls logger.Infow.
                            • Why: Performs side effects or delegates work to a helper.
                            • How: Executes the expression statement.

newLoggingResponseWriter

What: Constructs a loggingResponseWriter wrapper.

Why: Centralizes the initialization defaults (status = 200) and dependency injection for hijack tracking.

How: Stores the underlying response writer and the optional hijack tracker function.

pkg/gateway/server/middleware/middleware.go#L257
func newLoggingResponseWriter(w http.ResponseWriter, tracker func() (func(), func(net.Conn) net.Conn)) *loggingResponseWriter {
return &loggingResponseWriter{
ResponseWriter: w,
status: http.StatusOK,
hijackTracker: tracker,
}
}

Walkthrough

The list below documents the statements inside the function body, including nested blocks and inline closures.

  • L258: return &loggingResponseWriter{ ResponseWriter: w, status: http.StatusOK, hijackTracker: tracker, }
    • What: Returns from the current function.
    • Why: Ends the current execution path and hands control back to the caller.
    • How: Executes a return statement (possibly returning values).

(*loggingResponseWriter).WriteHeader

What: Captures the status code while delegating header writes.

Why: Status code is needed for both logs and metrics.

How: Stores the status code then calls the underlying WriteHeader.

pkg/gateway/server/middleware/middleware.go#L265
func (w *loggingResponseWriter) WriteHeader(status int) {
w.status = status
w.ResponseWriter.WriteHeader(status)
}

Walkthrough

The list below documents the statements inside the function body, including nested blocks and inline closures.

  • L266: w.status = status
    • What: Assigns w.status.
    • Why: Keeps intermediate state available for later steps in the function.
    • How: Evaluates the right-hand side expressions and stores results in the left-hand variables.
  • L267: w.ResponseWriter.WriteHeader(status)
    • What: Calls w.ResponseWriter.WriteHeader.
    • Why: Performs side effects or delegates work to a helper.
    • How: Executes the expression statement.

(*loggingResponseWriter).Write

What: Captures bytes written while delegating response writes.

Why: Byte counts are useful for operational logs and for debugging unexpectedly large responses.

How: Ensures a default status exists, calls the underlying Write, and accumulates the byte count.

pkg/gateway/server/middleware/middleware.go#L270
func (w *loggingResponseWriter) Write(b []byte) (int, error) {
if w.status == 0 {
w.status = http.StatusOK
}
n, err := w.ResponseWriter.Write(b)
w.bytes += n
return n, err
}

Walkthrough

The list below documents the statements inside the function body, including nested blocks and inline closures.

  • L271: if w.status == 0 { w.status = http.StatusOK }
    • What: Branches conditionally.
    • Why: Handles different execution paths based on runtime state.
    • How: Evaluates the condition and executes the matching branch.
    • Nested steps:
      • L272: w.status = http.StatusOK
        • What: Assigns w.status.
        • Why: Keeps intermediate state available for later steps in the function.
        • How: Evaluates the right-hand side expressions and stores results in the left-hand variables.
  • L274: n, err := w.ResponseWriter.Write(b)
    • What: Defines n, err.
    • Why: Keeps intermediate state available for later steps in the function.
    • How: Evaluates the right-hand side expressions and stores results in the left-hand variables.
  • L275: w.bytes += n
    • What: Assigns w.bytes.
    • Why: Keeps intermediate state available for later steps in the function.
    • How: Evaluates the right-hand side expressions and stores results in the left-hand variables.
  • L276: return n, err
    • What: Returns from the current function.
    • Why: Ends the current execution path and hands control back to the caller.
    • How: Executes a return statement (possibly returning values).

(*loggingResponseWriter).Flush

What: Implements http.Flusher when the underlying writer supports it.

Why: Some responses (streaming/SSE) require flush support; the wrapper should not break that behaviour.

How: Type-asserts to http.Flusher and delegates.

pkg/gateway/server/middleware/middleware.go#L279
func (w *loggingResponseWriter) Flush() {
if flusher, ok := w.ResponseWriter.(http.Flusher); ok {
flusher.Flush()
}
}

Walkthrough

The list below documents the statements inside the function body, including nested blocks and inline closures.

  • L280: if flusher, ok := w.ResponseWriter.(http.Flusher); ok { flusher.Flush() }
    • What: Branches conditionally.
    • Why: Handles different execution paths based on runtime state.
    • How: Evaluates the condition and executes the matching branch.
    • Nested steps:
      • L280: flusher, ok := w.ResponseWriter.(http.Flusher)
        • What: Defines flusher, ok.
        • Why: Keeps intermediate state available for later steps in the function.
        • How: Evaluates the right-hand side expressions and stores results in the left-hand variables.
      • L281: flusher.Flush()
        • What: Calls flusher.Flush.
        • Why: Performs side effects or delegates work to a helper.
        • How: Executes the expression statement.

(*loggingResponseWriter).Hijack

What: Implements http.Hijacker and integrates upgraded-connection tracking.

Why: Websockets and other upgrades require hijacking; the gateway also wants to track upgraded connection lifetime for metrics and limits.

How: Delegates to the underlying http.Hijacker, then (optionally) calls the configured hijack tracker once to obtain an on-close callback and a connection wrapper; wraps the returned net.Conn accordingly.

Notes: If the underlying writer does not support hijacking, returns an explicit error.

pkg/gateway/server/middleware/middleware.go#L285
func (w *loggingResponseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
hijacker, ok := w.ResponseWriter.(http.Hijacker)
if !ok {
return nil, nil, errors.New("hijacker not supported")
}
conn, rw, err := hijacker.Hijack()
if err != nil {
return nil, nil, err
}

if w.hijackTracker != nil {
var closer func()
var wrapper func(net.Conn) net.Conn
w.hijackOnce.Do(func() {
closer, wrapper = w.hijackTracker()
})
if wrapper != nil {
conn = wrapper(conn)
}
if closer != nil {
conn = &trackingConn{Conn: conn, onClose: closer}
}
}

return conn, rw, nil
}

Walkthrough

The list below documents the statements inside the function body, including nested blocks and inline closures.

  • L286: hijacker, ok := w.ResponseWriter.(http.Hijacker)
    • What: Defines hijacker, ok.
    • Why: Keeps intermediate state available for later steps in the function.
    • How: Evaluates the right-hand side expressions and stores results in the left-hand variables.
  • L287: if !ok { return nil, nil, errors.New("hijacker not supported") }
    • What: Branches conditionally.
    • Why: Short-circuits early when a precondition is not met or an error/edge case is detected.
    • How: Evaluates the condition and executes the matching branch.
    • Nested steps:
      • L288: return nil, nil, errors.New("hijacker not supported")
        • What: Returns from the current function.
        • Why: Ends the current execution path and hands control back to the caller.
        • How: Executes a return statement (possibly returning values).
  • L290: conn, rw, err := hijacker.Hijack()
    • What: Defines conn, rw, err.
    • Why: Keeps intermediate state available for later steps in the function.
    • How: Evaluates the right-hand side expressions and stores results in the left-hand variables.
  • L291: if err != nil { return nil, nil, err }
    • What: Branches conditionally.
    • Why: Short-circuits early when a precondition is not met or an error/edge case is detected.
    • How: Evaluates the condition and executes the matching branch.
    • Nested steps:
      • L292: return nil, nil, err
        • What: Returns from the current function.
        • Why: Ends the current execution path and hands control back to the caller.
        • How: Executes a return statement (possibly returning values).
  • L295: if w.hijackTracker != nil { var closer func() var wrapper func(net.Conn) net.Conn w.hijackOnce.Do(func() { closer, wrapper = w.hijackTracke…
    • What: Branches conditionally.
    • Why: Handles different execution paths based on runtime state.
    • How: Evaluates the condition and executes the matching branch.
    • Nested steps:
      • L296: var closer func()
        • What: Declares local names.
        • Why: Introduces variables or types used later in the function.
        • How: Executes a Go declaration statement inside the function body.
      • L297: var wrapper func(net.Conn) net.Conn
        • What: Declares local names.
        • Why: Introduces variables or types used later in the function.
        • How: Executes a Go declaration statement inside the function body.
      • L298: w.hijackOnce.Do(func() { closer, wrapper = w.hijackTracker() })
        • What: Calls w.hijackOnce.Do.
        • Why: Performs side effects or delegates work to a helper.
        • How: Executes the expression statement.
        • Nested steps:
          • L298: func() { closer, wrapper = w.hijackTracker() }
            • What: Defines an inline function (closure).
            • Why: Encapsulates callback logic and may capture variables from the surrounding scope.
            • How: Declares a func literal and uses it as a value (for example, as an HTTP handler or callback).
            • Nested steps:
              • L299: closer, wrapper = w.hijackTracker()
                • What: Assigns closer, wrapper.
                • Why: Keeps intermediate state available for later steps in the function.
                • How: Evaluates the right-hand side expressions and stores results in the left-hand variables.
      • L301: if wrapper != nil { conn = wrapper(conn) }
        • What: Branches conditionally.
        • Why: Handles different execution paths based on runtime state.
        • How: Evaluates the condition and executes the matching branch.
        • Nested steps:
          • L302: conn = wrapper(conn)
            • What: Assigns conn.
            • Why: Keeps intermediate state available for later steps in the function.
            • How: Evaluates the right-hand side expressions and stores results in the left-hand variables.
      • L304: if closer != nil { conn = &trackingConn{Conn: conn, onClose: closer} }
        • What: Branches conditionally.
        • Why: Handles different execution paths based on runtime state.
        • How: Evaluates the condition and executes the matching branch.
        • Nested steps:
          • L305: conn = &trackingConn{Conn: conn, onClose: closer}
            • What: Assigns conn.
            • Why: Keeps intermediate state available for later steps in the function.
            • How: Evaluates the right-hand side expressions and stores results in the left-hand variables.
  • L309: return conn, rw, nil
    • What: Returns from the current function.
    • Why: Ends the current execution path and hands control back to the caller.
    • How: Executes a return statement (possibly returning values).

(*loggingResponseWriter).Push

What: Implements http.Pusher when the underlying writer supports it.

Why: Preserves HTTP/2 server push support when enabled by downstream handlers (rare for the gateway, but safe to support).

How: Delegates to http.Pusher.Push or returns http.ErrNotSupported.

pkg/gateway/server/middleware/middleware.go#L312
func (w *loggingResponseWriter) Push(target string, opts *http.PushOptions) error {
if pusher, ok := w.ResponseWriter.(http.Pusher); ok {
return pusher.Push(target, opts)
}
return http.ErrNotSupported
}

Walkthrough

The list below documents the statements inside the function body, including nested blocks and inline closures.

  • L313: if pusher, ok := w.ResponseWriter.(http.Pusher); ok { return pusher.Push(target, opts) }
    • What: Branches conditionally.
    • Why: Short-circuits early when a precondition is not met or an error/edge case is detected.
    • How: Evaluates the condition and executes the matching branch.
    • Nested steps:
      • L313: pusher, ok := w.ResponseWriter.(http.Pusher)
        • What: Defines pusher, ok.
        • Why: Keeps intermediate state available for later steps in the function.
        • How: Evaluates the right-hand side expressions and stores results in the left-hand variables.
      • L314: return pusher.Push(target, opts)
        • What: Returns from the current function.
        • Why: Ends the current execution path and hands control back to the caller.
        • How: Executes a return statement (possibly returning values).
  • L316: return http.ErrNotSupported
    • What: Returns from the current function.
    • Why: Ends the current execution path and hands control back to the caller.
    • How: Executes a return statement (possibly returning values).

(*trackingConn).Close

What: Closes the underlying connection and runs the on-close callback once.

Why: Upgraded connections can outlive the HTTP request; metrics/accounting must decrement when the connection actually closes.

How: Delegates to Conn.Close, then uses sync.Once to invoke onClose a single time.

pkg/gateway/server/middleware/middleware.go#L326
func (c *trackingConn) Close() error {
err := c.Conn.Close()
c.once.Do(func() {
if c.onClose != nil {
c.onClose()
}
})
return err
}

Walkthrough

The list below documents the statements inside the function body, including nested blocks and inline closures.

  • L327: err := c.Conn.Close()
    • What: Defines err.
    • Why: Keeps intermediate state available for later steps in the function.
    • How: Evaluates the right-hand side expressions and stores results in the left-hand variables.
  • L328: c.once.Do(func() { if c.onClose != nil { c.onClose() } })
    • What: Calls c.once.Do.
    • Why: Performs side effects or delegates work to a helper.
    • How: Executes the expression statement.
    • Nested steps:
      • L328: func() { if c.onClose != nil { c.onClose() } }
        • What: Defines an inline function (closure).
        • Why: Encapsulates callback logic and may capture variables from the surrounding scope.
        • How: Declares a func literal and uses it as a value (for example, as an HTTP handler or callback).
        • Nested steps:
          • L329: if c.onClose != nil { c.onClose() }
            • What: Branches conditionally.
            • Why: Handles different execution paths based on runtime state.
            • How: Evaluates the condition and executes the matching branch.
            • Nested steps:
              • L330: c.onClose()
                • What: Calls c.onClose.
                • Why: Performs side effects or delegates work to a helper.
                • How: Executes the expression statement.
  • L333: return err
    • What: Returns from the current function.
    • Why: Ends the current execution path and hands control back to the caller.
    • How: Executes a return statement (possibly returning values).

(*trackingConn).Read

What: Reads from the underlying connection with optional deadline enforcement.

Why: Deadline enforcement can protect the gateway from idle upgraded connections when configured.

How: If timeout is non-zero, sets a read deadline before calling Conn.Read.

Notes: This wrapper is currently constructed with a zero timeout in this package; provide a custom wrapper via HijackedFunc for idle enforcement.

pkg/gateway/server/middleware/middleware.go#L336
func (c *trackingConn) Read(b []byte) (int, error) {
if c.timeout > 0 {
_ = c.Conn.SetReadDeadline(time.Now().Add(c.timeout))
}
return c.Conn.Read(b)
}

Walkthrough

The list below documents the statements inside the function body, including nested blocks and inline closures.

  • L337: if c.timeout > 0 { _ = c.Conn.SetReadDeadline(time.Now().Add(c.timeout)) }
    • What: Branches conditionally.
    • Why: Handles different execution paths based on runtime state.
    • How: Evaluates the condition and executes the matching branch.
    • Nested steps:
      • L338: _ = c.Conn.SetReadDeadline(time.Now().Add(c.timeout))
        • What: Assigns _.
        • Why: Keeps intermediate state available for later steps in the function.
        • How: Evaluates the right-hand side expressions and stores results in the left-hand variables.
  • L340: return c.Conn.Read(b)
    • What: Returns from the current function.
    • Why: Ends the current execution path and hands control back to the caller.
    • How: Executes a return statement (possibly returning values).

(*trackingConn).Write

What: Writes to the underlying connection with optional deadline enforcement.

Why: Mirrors the read path for symmetry and supports enforcing write-side timeouts when configured.

How: If timeout is non-zero, sets a write deadline before calling Conn.Write.

Notes: This wrapper is currently constructed with a zero timeout in this package; provide a custom wrapper via HijackedFunc for idle enforcement.

pkg/gateway/server/middleware/middleware.go#L343
func (c *trackingConn) Write(b []byte) (int, error) {
if c.timeout > 0 {
_ = c.Conn.SetWriteDeadline(time.Now().Add(c.timeout))
}
return c.Conn.Write(b)
}

Walkthrough

The list below documents the statements inside the function body, including nested blocks and inline closures.

  • L344: if c.timeout > 0 { _ = c.Conn.SetWriteDeadline(time.Now().Add(c.timeout)) }
    • What: Branches conditionally.
    • Why: Handles different execution paths based on runtime state.
    • How: Evaluates the condition and executes the matching branch.
    • Nested steps:
      • L345: _ = c.Conn.SetWriteDeadline(time.Now().Add(c.timeout))
        • What: Assigns _.
        • Why: Keeps intermediate state available for later steps in the function.
        • How: Evaluates the right-hand side expressions and stores results in the left-hand variables.
  • L347: return c.Conn.Write(b)
    • What: Returns from the current function.
    • Why: Ends the current execution path and hands control back to the caller.
    • How: Executes a return statement (possibly returning values).

Start Here

Architecture

Guides

Reference

Neighboring source