Documentation
¶
Index ¶
- Constants
- func DrainBody(r *http.Request)
- func EchoError(ctx context.Context, c *echo.Context, code int, message string, err error) error
- func ExtractRegionFromRequest(r *http.Request, defaultRegion string) string
- func ExtractServiceFromRequest(r *http.Request) string
- func GetOperation(ctx context.Context) string
- func GetResource(ctx context.Context) string
- func ReadBody(r *http.Request) ([]byte, error)
- func RequestIDMiddleware() echo.MiddlewareFunc
- func SanitizeHeaderString(s string) string
- func SetOperation(ctx context.Context, operation string) context.Context
- func SetOperationAndResource(ctx context.Context, operation, resource string) context.Context
- func SetResource(ctx context.Context, resource string) context.Context
- func WriteDynamoDBResponse(ctx context.Context, w http.ResponseWriter, code int, payload any)
- func WriteError(ctx context.Context, w http.ResponseWriter, r *http.Request, err error, ...)
- func WriteJSON(ctx context.Context, w http.ResponseWriter, code int, payload any)
- func WriteS3ErrorResponse(ctx context.Context, w http.ResponseWriter, r *http.Request, s3Err any, ...)
- func WriteXML(ctx context.Context, w http.ResponseWriter, code int, payload any)
- type OperationKey
- type ResponseWriter
- type SigV4Error
- type SigV4Validator
Constants ¶
const MaxRequestBodyBytes int64 = 16 * 1024 * 1024
MaxRequestBodyBytes caps every body read through ReadBody. AWS API request payloads top out at 6 MiB (Lambda synchronous invoke) or 5 GiB streamed (S3 PutObject, which uses its own streaming path and does not call ReadBody). 16 MiB leaves headroom for unusually large API requests while preventing unbounded memory growth from attacker-controlled bodies.
Variables ¶
This section is empty.
Functions ¶
func DrainBody ¶
DrainBody reads and discards the request body. This is important for HTTP keep-alive, as the server needs to know the request body has been fully consumed before reusing the connection.
func ExtractRegionFromRequest ¶
ExtractRegionFromRequest extracts the AWS region from an HTTP request. It checks the SigV4 Authorization header credential scope first, then the X-Amz-Region header, then falls back to defaultRegion.
func ExtractServiceFromRequest ¶
ExtractServiceFromRequest extracts the AWS service name from the SigV4 Authorization header credential scope (AKID/date/region/service/aws4_request). Returns an empty string if the service name cannot be determined.
func GetOperation ¶
GetOperation retrieves the operation name from context, or "Unknown" if not set.
func GetResource ¶
GetResource retrieves the resource identifier from context, or "" if not set.
func ReadBody ¶
ReadBody reads the request body and returns it as a byte slice. It handles cases where r.Body might be nil (e.g. in some test environments). It re-seeds the request body so it can be read multiple times and ensures the original request body is closed. It uses a custom ReadCloser to avoid redundant reads and allocations if called multiple times. The body is capped at MaxRequestBodyBytes; reads that exceed the cap return an `*http.MaxBytesError` (use errors.As to detect and translate to a 413 response). Because this helper has no access to the originating ResponseWriter, it cannot auto-write the 413 itself — callers must handle the size-cap error and respond appropriately.
func RequestIDMiddleware ¶
func RequestIDMiddleware() echo.MiddlewareFunc
RequestIDMiddleware returns an Echo middleware that injects an x-amz-request-id header (a new UUID) into every HTTP response.
func SanitizeHeaderString ¶
SanitizeHeaderString removes all characters except alphanumeric, hyphens, underscores, and periods. This breaks the taint for static analysis tools like CodeQL which flag raw header values in logs.
func SetOperation ¶
SetOperation returns a new context with the operation name updated. This follows the idiomatic context pattern - immutable values.
func SetOperationAndResource ¶
SetOperationAndResource returns a new context with both operation and resource set. This is a convenience function to set both at once without intermediate contexts.
func SetResource ¶
SetResource returns a new context with the resource identifier updated. This follows the idiomatic context pattern - immutable values.
func WriteDynamoDBResponse ¶
WriteDynamoDBResponse writes a DynamoDB-style JSON response with CRC32 checksum. Sets Content-Type to "application/x-amz-json-1.0" and X-Amz-Crc32.
func WriteError ¶
WriteError writes an error response with structured logging. Uses the logger from ctx to record the error with context. Drains the request body to ensure connection reuse.
func WriteJSON ¶
WriteJSON marshals the payload to JSON, sets standard headers, and writes the response. Sets Content-Type to "application/json" and Content-Length.
func WriteS3ErrorResponse ¶
func WriteS3ErrorResponse(ctx context.Context, w http.ResponseWriter, r *http.Request, s3Err any, code int)
WriteS3ErrorResponse writes an S3-compatible XML error response. Drains the request body and writes the error as XML.
Types ¶
type OperationKey ¶
type OperationKey struct{}
OperationKey is a type-safe context key for storing operation metadata.
type ResponseWriter ¶
type ResponseWriter struct {
http.ResponseWriter
// contains filtered or unexported fields
}
ResponseWriter wraps http.ResponseWriter and tracks the HTTP status code. Use this when you need to inspect the status after WriteHeader is called.
func NewResponseWriter ¶
func NewResponseWriter(w http.ResponseWriter) *ResponseWriter
NewResponseWriter creates a ResponseWriter that wraps the given http.ResponseWriter.
func (*ResponseWriter) StatusCode ¶
func (w *ResponseWriter) StatusCode() int
StatusCode returns the HTTP status code that was written.
func (*ResponseWriter) Write ¶
func (w *ResponseWriter) Write(b []byte) (int, error)
Write sets status to http.StatusOK if not already set, then delegates to wrapped ResponseWriter.
func (*ResponseWriter) WriteHeader ¶
func (w *ResponseWriter) WriteHeader(code int)
WriteHeader writes the status code and delegates to the wrapped ResponseWriter.
type SigV4Error ¶
SigV4Error is the AWS error returned when validation fails. The Code field drives the X-Amzn-Errortype header / error code clients expect.
type SigV4Validator ¶
type SigV4Validator struct {
// contains filtered or unexported fields
}
SigV4Validator cryptographically verifies AWS Signature Version 4 on incoming requests. It is OFF by default; the caller opts in via NewSigV4Validator and the EchoMiddleware. When enabled, requests whose recomputed signature does not match the Authorization header are rejected with the AWS-accurate error.
Verification re-derives the signing key from a single configured secret key (the access-key-id in the request is informational only — gopherstack is a single-tenant simulator). This mirrors how AWS validates: only the secret is secret; everything else is reconstructed from the request.
func NewSigV4Validator ¶
func NewSigV4Validator(secretKey string) *SigV4Validator
NewSigV4Validator builds a validator that checks signatures against secretKey. A blank secretKey is treated as "test" — the common AWS dummy credential — so the default localstack-style client (AWS_SECRET_ACCESS_KEY=test) validates.
func (*SigV4Validator) EchoMiddleware ¶
func (v *SigV4Validator) EchoMiddleware() echo.MiddlewareFunc
EchoMiddleware returns Echo middleware that validates SigV4 on every request. Requests without an Authorization header are passed through unchanged (many gopherstack internal/health/dashboard calls are unsigned); only requests that present a SigV4 Authorization header are verified. This keeps anonymous and presigned-URL flows working while still rejecting tampered signed requests.
func (*SigV4Validator) Verify ¶
func (v *SigV4Validator) Verify(r *http.Request) *SigV4Error
Verify recomputes the SigV4 signature for r and compares it to the signature in the Authorization header. It returns nil on a match, or a *SigV4Error describing the AWS-accurate rejection otherwise. Verify reads and restores the request body so downstream handlers still see it.