Documentation
¶
Overview ¶
Package adapterutil holds the framework-agnostic helpers shared by every mAPI-ng web adapter (gin today; echo/chi/beego/net-http next). Each adapter's job is the same — after a request completes, extract exemplar breadcrumbs, a final status, and byte counts — so the parts that don't touch a framework's types live here once, single-sourced, rather than being copy-pasted per adapter. It imports only the stdlib plus the core client (for NoStatusReason); the core never imports this package, so there is no cycle.
Index ¶
- func ClampNonNegative(n int64) int64
- func ParseTraceparent(header string) (traceID, spanID string)
- func ReclassifyNoStatus(ctx context.Context, status int) (int, maping.NoStatusReason)
- type ResponseWriter
- func (w *ResponseWriter) BytesWritten() int64
- func (w *ResponseWriter) Flush()
- func (w *ResponseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error)
- func (w *ResponseWriter) ReadFrom(src io.Reader) (int64, error)
- func (w *ResponseWriter) Status() int
- func (w *ResponseWriter) Unwrap() http.ResponseWriter
- func (w *ResponseWriter) Write(b []byte) (int, error)
- func (w *ResponseWriter) WriteHeader(code int)
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func ClampNonNegative ¶
ClampNonNegative folds a negative byte count (unknown ContentLength is -1, an unwritten body Size is -1) to 0.
func ParseTraceparent ¶
ParseTraceparent extracts the trace id and span id from a W3C traceparent header (RFC: "version-traceid-spanid-flags", e.g. "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01"). It is deliberately hand-rolled so the client stays free of any OpenTelemetry dependency. Both ids are returned empty unless the header is well-formed: exactly four dash- separated parts, a 32-hex trace id and a 16-hex span id, neither all-zero (the spec's "invalid" sentinel). Best-effort: any deviation yields empties.
func ReclassifyNoStatus ¶
ReclassifyNoStatus decides whether a completed request should be reported as NO_STATUS. It reclassifies only on a real abort signal — the request context canceled (client disconnect) or its deadline fired — before the response finished: it returns (0, reason), mapping a fired deadline vs. a plain cancellation, with anything else recorded as OTHER. A live context (no cause) is left as the written status and NoStatusUnspecified, so an ordinary empty-body handler is never misreported as NO_STATUS. Panics are converted to a 500 by the host's recovery middleware, so they surface as a status, not here.
Types ¶
type ResponseWriter ¶
type ResponseWriter struct {
http.ResponseWriter
// contains filtered or unexported fields
}
ResponseWriter wraps an http.ResponseWriter to capture the two things an adapter needs after a stdlib request completes — the final status code and the total bytes written — which net/http otherwise discards. Frameworks like Gin track these on their own writer; a bare net/http handler does not, so the wrapper stands in.
Capabilities (Flusher/Hijacker/ReaderFrom) are preserved by DELEGATION rather than by conditional interface assertion, so a library that type-asserts the writer keeps working. Unconditional delegation is safe because the only case the wrapper "claims" a capability the underlying lacks is a transport that could not perform the operation anyway (e.g. hijacking an HTTP/2 conn): the delegate then degrades to http.ErrNotSupported (Hijack), a no-op (Flush), or a plain io.Copy (ReadFrom) — never a panic or silent data loss. Unwrap exposes the real writer for http.ResponseController and any caller that needs more.
func WrapResponseWriter ¶
func WrapResponseWriter(w http.ResponseWriter) *ResponseWriter
WrapResponseWriter returns a ResponseWriter capturing status and byte count. Status defaults to http.StatusOK — net/http's implicit status when a handler writes a body without calling WriteHeader.
func (*ResponseWriter) BytesWritten ¶
func (w *ResponseWriter) BytesWritten() int64
BytesWritten returns the total bytes forwarded through Write and ReadFrom.
func (*ResponseWriter) Flush ¶
func (w *ResponseWriter) Flush()
Flush forwards to the underlying http.Flusher, or no-ops when the transport cannot flush (SSE without buffering support).
func (*ResponseWriter) Hijack ¶
func (w *ResponseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error)
Hijack forwards to the underlying http.Hijacker, or returns http.ErrNotSupported when the transport cannot be hijacked (websockets over HTTP/2).
func (*ResponseWriter) ReadFrom ¶
func (w *ResponseWriter) ReadFrom(src io.Reader) (int64, error)
ReadFrom delegates to the underlying io.ReaderFrom when present (preserving sendfile), otherwise falls back to io.Copy. Either way the copied bytes are counted, so RespBytes stays correct with or without the fast path.
func (*ResponseWriter) Status ¶
func (w *ResponseWriter) Status() int
Status returns the captured status code (http.StatusOK if none was written).
func (*ResponseWriter) Unwrap ¶
func (w *ResponseWriter) Unwrap() http.ResponseWriter
Unwrap returns the embedded writer (Go 1.20+ convention) so http.ResponseController reaches the real writer.
func (*ResponseWriter) Write ¶
func (w *ResponseWriter) Write(b []byte) (int, error)
Write marks the header written (the default status is already 200), forwards the bytes, and counts what the underlying writer accepted.
func (*ResponseWriter) WriteHeader ¶
func (w *ResponseWriter) WriteHeader(code int)
WriteHeader records the code on the first call only, then forwards. Later calls forward but do not overwrite the captured status, matching net/http's "superfluous WriteHeader" behavior.