bhttp

package module
v0.3.3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 19, 2025 License: MIT Imports: 11 Imported by: 3

README

bhttpv2

Predecessor of bhttp, ideas features

  • The middleware will have different signature as "leaf" http handlers
  • "leaf" http handlers take a custom (typed) context, a bhttp.ResponseWriter, a http.request and return an error
  • the custom "leaf" handler context is constructed from the regular context.Context just before the leaf handler is called, share this logic and error handling
  • middleware only take the bhttp.ResponseWriter, a http.request (that carries the regular context.Context) and can handle the error
  • named routes and route reversing

Documentation

Overview

Package bhttp provides buffered HTTP response handling.

Index

Constants

This section is empty.

Variables

View Source
var ErrBufferFull = errors.New("buffer is full")

ErrBufferFull is returned when the write call will cause the buffer to be filled beyond its limit.

Functions

func StdContextInit added in v0.3.1

func StdContextInit(r *http.Request) (context.Context, error)

StdContextInit is a context initializer that just pulls the context from the http.Request.

func ToStd added in v0.3.0

func ToStd(h BareHandler, bufLimit int, logs Logger) http.Handler

ToStd converts a bare handler into a standard library http.Handler. The implementation creates a buffered response writer and flushes it implicitly after serving the request.

Types

type BareHandler added in v0.3.0

type BareHandler interface {
	ServeBareBHTTP(w ResponseWriter, r *http.Request) error
}

BareHandler describes how middleware servers HTTP requests. In this library the signature for handling middleware BareHandler is different from the signature of "leaf" handlers: Handler.

func ToBare added in v0.3.0

func ToBare[C Context](h Handler[C], contextInit ContextInitFunc[C]) BareHandler

ToBare converts a typed context handler 'h' into a bare buffered handler.

func Wrap added in v0.3.0

func Wrap[C Context](h Handler[C], contextInit ContextInitFunc[C], m ...Middleware) BareHandler

Wrap takes the inner handler h and wraps it with middleware. The order is that of the Gorilla and Chi router. That is: the middleware provided first is called first and is the "outer" most wrapping, the middleware provided last will be the "inner most" wrapping (closest to the handler).

type BareHandlerFunc added in v0.3.0

type BareHandlerFunc func(ResponseWriter, *http.Request) error

BareHandlerFunc allow casting a function to an implementation of Handler.

func (BareHandlerFunc) ServeBareBHTTP added in v0.3.0

func (f BareHandlerFunc) ServeBareBHTTP(w ResponseWriter, r *http.Request) error

ServeBareBHTTP implements the Handler interface.

type Code added in v0.3.2

type Code int

Code is an error code that mirrors the http status codes. It can be used to create errors to pass around across middleware layers to handle errors structurally.

const (
	CodeUnknown                      Code = 0
	CodeBadRequest                   Code = http.StatusBadRequest                   // RFC 9110, 15.5.1
	CodeUnauthorized                 Code = http.StatusUnauthorized                 // RFC 9110, 15.5.2
	CodePaymentRequired              Code = http.StatusPaymentRequired              // RFC 9110, 15.5.3
	CodeForbidden                    Code = http.StatusForbidden                    // RFC 9110, 15.5.4
	CodeNotFound                     Code = http.StatusNotFound                     // RFC 9110, 15.5.5
	CodeMethodNotAllowed             Code = http.StatusMethodNotAllowed             // RFC 9110, 15.5.6
	CodeNotAcceptable                Code = http.StatusNotAcceptable                // RFC 9110, 15.5.7
	CodeProxyAuthRequired            Code = http.StatusProxyAuthRequired            // RFC 9110, 15.5.8
	CodeRequestTimeout               Code = http.StatusRequestTimeout               // RFC 9110, 15.5.9
	CodeConflict                     Code = http.StatusConflict                     // RFC 9110, 15.5.10
	CodeGone                         Code = http.StatusGone                         // RFC 9110, 15.5.11
	CodeLengthRequired               Code = http.StatusLengthRequired               // RFC 9110, 15.5.12
	CodePreconditionFailed           Code = http.StatusPreconditionFailed           // RFC 9110, 15.5.13
	CodeRequestEntityTooLarge        Code = http.StatusRequestEntityTooLarge        // RFC 9110, 15.5.14
	CodeRequestURITooLong            Code = http.StatusRequestURITooLong            // RFC 9110, 15.5.15
	CodeUnsupportedMediaType         Code = http.StatusUnsupportedMediaType         // RFC 9110, 15.5.16
	CodeRequestedRangeNotSatisfiable Code = http.StatusRequestedRangeNotSatisfiable // RFC 9110, 15.5.17
	CodeExpectationFailed            Code = http.StatusExpectationFailed            // RFC 9110, 15.5.18
	CodeTeapot                       Code = http.StatusTeapot                       // RFC 9110, 15.5.19 (Unused)
	CodeMisdirectedRequest           Code = http.StatusMisdirectedRequest           // RFC 9110, 15.5.20
	CodeUnprocessableEntity          Code = http.StatusUnprocessableEntity          // RFC 9110, 15.5.21
	CodeLocked                       Code = http.StatusLocked                       // RFC 4918, 11.3
	CodeFailedDependency             Code = http.StatusFailedDependency             // RFC 4918, 11.4
	CodeTooEarly                     Code = http.StatusTooEarly                     // RFC 8470, 5.2.
	CodeUpgradeRequired              Code = http.StatusUpgradeRequired              // RFC 9110, 15.5.22
	CodePreconditionRequired         Code = http.StatusPreconditionRequired         // RFC 6585, 3
	CodeTooManyRequests              Code = http.StatusTooManyRequests              // RFC 6585, 4
	CodeRequestHeaderFieldsTooLarge  Code = http.StatusRequestHeaderFieldsTooLarge  // RFC 6585, 5
	CodeUnavailableForLegalReasons   Code = http.StatusUnavailableForLegalReasons   // RFC 7725, 3

	CodeInternalServerError           Code = http.StatusInternalServerError           // RFC 9110, 15.6.1
	CodeNotImplemented                Code = http.StatusNotImplemented                // RFC 9110, 15.6.2
	CodeBadGateway                    Code = http.StatusBadGateway                    // RFC 9110, 15.6.3
	CodeServiceUnavailable            Code = http.StatusServiceUnavailable            // RFC 9110, 15.6.4
	CodeGatewayTimeout                Code = http.StatusGatewayTimeout                // RFC 9110, 15.6.5
	CodeHTTPVersionNotSupported       Code = http.StatusHTTPVersionNotSupported       // RFC 9110, 15.6.6
	CodeVariantAlsoNegotiates         Code = http.StatusVariantAlsoNegotiates         // RFC 2295, 8.1
	CodeInsufficientStorage           Code = http.StatusInsufficientStorage           // RFC 4918, 11.5
	CodeLoopDetected                  Code = http.StatusLoopDetected                  // RFC 5842, 7.2
	CodeNotExtended                   Code = http.StatusNotExtended                   // RFC 2774, 7
	CodeNetworkAuthenticationRequired Code = http.StatusNetworkAuthenticationRequired // RFC 6585, 6
)

func CodeOf added in v0.3.2

func CodeOf(err error) Code

CodeOf returns the error's status code if it is or wraps an *Error and CodeUnknown otherwise.

type Context

type Context interface{ context.Context }

Context constraint for "leaf" nodes.

type ContextInitFunc added in v0.2.0

type ContextInitFunc[C Context] func(*http.Request) (C, error)

ContextInitFunc describe functions that turn requests into a typed context for our "leaf" handlers.

type Error added in v0.3.2

type Error struct {
	// contains filtered or unexported fields
}

Error describes an http error.

func NewError added in v0.3.2

func NewError(c Code, underlying error) *Error

NewError inits a new error given the error code.

func (*Error) Code added in v0.3.2

func (e *Error) Code() Code

func (*Error) Error added in v0.3.2

func (e *Error) Error() string

type Handler

type Handler[C Context] interface {
	ServeBHTTP(ctx C, w ResponseWriter, r *http.Request) error
}

Handler mirrors http.Handler but it supports typed context values and a buffered response allow returning error.

type HandlerFunc

type HandlerFunc[C Context] func(C, ResponseWriter, *http.Request) error

HandlerFunc allow casting a function to imple Handler.

func (HandlerFunc[C]) ServeBHTTP

func (f HandlerFunc[C]) ServeBHTTP(ctx C, w ResponseWriter, r *http.Request) error

ServeBHTTP implements the Handler interface.

type Logger

type Logger interface {
	LogUnhandledServeError(err error)
	LogImplicitFlushError(err error)
}

Logger can be implemented to get informed about important states.

func NewStdLogger added in v0.3.0

func NewStdLogger(l *log.Logger) Logger

type Middleware

type Middleware func(BareHandler) BareHandler

Middleware for cross-cutting concerns with buffered responses.

type ResponseBuffer

type ResponseBuffer struct {
	// contains filtered or unexported fields
}

ResponseBuffer is a http.ResponseWriter implementation that buffers writes up to configurable amount of bytes. This allows the implementation of handlers that can error halfway and return a completely different response instead of what was written before the error occurred.

func (*ResponseBuffer) FlushBuffer added in v0.3.0

func (w *ResponseBuffer) FlushBuffer() error

FlushBuffer flushes data to the underlying writer without calling .Flush on it by proxy. This is provided separately from FlushError to allow for emulating the original ResponseWriter behaviour more correctly.

func (*ResponseBuffer) FlushError

func (w *ResponseBuffer) FlushError() error

FlushError any buffered bytes to the underlying response writer and resets the buffer. After flush has been called the response data should be considered sent and in-transport to the client.

func (*ResponseBuffer) Free

func (w *ResponseBuffer) Free()

Free resets all members of the ResponseBuffer and puts it back in the sync pool to allow it to be re-used for a possible next initilization. It should be called after the handling has completed and the buffer should not be used after.

func (*ResponseBuffer) Header

func (w *ResponseBuffer) Header() http.Header

Header allows users to modify the headers (and trailers) sent to the client. The headers are not actually flushed to the underlying writer until a write or flush is being triggered.

func (*ResponseBuffer) Reset

func (w *ResponseBuffer) Reset()

Reset provides the differentiating feature from a regular ResponseWriter: it allows changing the response completely even if some data has been written already. This behaviour cannot be guaranteed if flush has been called explicitly so in that case it will panic.

func (*ResponseBuffer) Unwrap

func (w *ResponseBuffer) Unwrap() http.ResponseWriter

Unwrap returns the underlying response writer. This is expected by the http.ResponseController to allow it to call appropriate optional interface implementations.

func (*ResponseBuffer) Write

func (w *ResponseBuffer) Write(buf []byte) (int, error)

Write appends the contents of p to the buffered response, growing the internal buffer as needed. If the write will cause the buffer be larger then the configure limit it will return ErrBufferFull.

func (*ResponseBuffer) WriteHeader

func (w *ResponseBuffer) WriteHeader(statusCode int)

WriteHeader will cause headers to be flushed to the underlying writer while calling WriteHeader on the underlying writer with the given status code.

type ResponseWriter

type ResponseWriter interface {
	http.ResponseWriter
	Reset()
	Free()
	FlushBuffer() error
}

ResponseWriter implements the http.ResponseWriter but the underlying bytes are buffered. This allows middleware to reset the writer and formulate a completely new response.

func NewResponseWriter added in v0.3.0

func NewResponseWriter(resp http.ResponseWriter, limit int) ResponseWriter

NewResponseWriter inits a buffered response writer. It has a configurable limit after which the writing will return an error. This is to protect unchecked handlers from claiming too much memory. Limit can be set to -1 to disable this check.

type Reverser

type Reverser struct {
	// contains filtered or unexported fields
}

Reverser keeps track of named patterns and allows building URLS.

func NewReverser

func NewReverser() *Reverser

NewReverser inits the reverser.

func (Reverser) Named

func (r Reverser) Named(name, str string) string

Named is a convenience method that panics if naming the pattern fails.

func (Reverser) NamedPattern

func (r Reverser) NamedPattern(name, str string) (string, error)

NamedPattern will parse 's' as a path pattern while returning it as well.

func (Reverser) Reverse

func (r Reverser) Reverse(name string, vals ...string) (string, error)

Reverse reverses the named pattern into a url.

type ServeMux

type ServeMux[C Context] struct {
	// contains filtered or unexported fields
}

func NewCustomServeMux added in v0.3.0

func NewCustomServeMux[C Context](
	contextInit ContextInitFunc[C],
	bufLimit int,
	logger Logger,
	baseMux *http.ServeMux,
	reverser *Reverser,
) *ServeMux[C]

NewCustomServeMux creates a mux that allows full customization of the context type and how it is initialized for each handler from the request.

func NewServeMux

func NewServeMux() *ServeMux[context.Context]

NewServeMux creates a http.Handler implementation that is akin to the http.ServeMux but allows named routes and buffered responses. It does no use a custom (typed) context, see NewCustomServeMux for that.

func (*ServeMux[C]) Handle

func (m *ServeMux[C]) Handle(pattern string, handler Handler[C], name ...string)

Handle handles the request given a handler.

func (*ServeMux[C]) HandleFunc

func (m *ServeMux[C]) HandleFunc(pattern string, handler HandlerFunc[C], name ...string)

HandleFunc handles the request given the pattern using a function.

func (*ServeMux[C]) Reverse

func (m *ServeMux[C]) Reverse(name string, vals ...string) (string, error)

Reverse returns the url based on the name and parameter values.

func (*ServeMux[C]) ServeHTTP

func (m *ServeMux[C]) ServeHTTP(w http.ResponseWriter, r *http.Request)

ServeHTTP makes the server mux implement the http.Handler interface.

func (*ServeMux[C]) Use

func (m *ServeMux[C]) Use(mw ...Middleware)

Use allows providing of middleware.

type TestLogger added in v0.3.0

type TestLogger struct {
	NumLogUnhandledServeError int64
	NumLogImplicitFlushError  int64
	// contains filtered or unexported fields
}

func NewTestLogger added in v0.3.0

func NewTestLogger(tb testing.TB) *TestLogger

func (*TestLogger) LogImplicitFlushError added in v0.3.0

func (l *TestLogger) LogImplicitFlushError(err error)

func (*TestLogger) LogUnhandledServeError added in v0.3.0

func (l *TestLogger) LogUnhandledServeError(err error)

Directories

Path Synopsis
internal
Package main provides development automation.
Package main provides development automation.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL