Documentation ¶
Overview ¶
Context and layers.
A layer is a keystone of extensibility of httransform. You can think about them as stacks of callbacks.
One diagram worth 1000 words:
HTTP interface Layer 1 Layer 2 +----------------+ ************** ************** | | * * * * ============== ---> | HTTP request | ===> * OnRequest * ===> * OnRequest * ===> = = | | * * * * = = +----------------+ ************** ************** = Executor = | | * * * * = = <--- | HTTP response | <=== * OnResponse * <=== * OnResponse * <=== = = | | * * * * ============== +----------------+ ************** **************
As you see, the request goes through the all layers forward and backward. This is a contract of this package. So, if you have a layers A and B, a request path is A(onRequest) -> B(onRequest) -> Executor -> B(onResponse) -> A(onResponse) -> client. So, that's why it worth to think about layers as about 'stacks'.
Let's check what happens if some layer returns an error:
HTTP interface Layer 1 Layer 2 +----------------+ ************** ************** | | * * * * ============== ---> | HTTP request | ===> * OnRequest * ===> X * OnRequest * = = | | * * | * * = = +----------------+ ************** | ************** = Executor = | | * * | * * = = <--- | HTTP response | <=== * OnResponse * <=== + * OnResponse * = = | | * * * * ============== +----------------+ ************** **************
So, we guarantee that error will pass through the same layers which were already processed a request.
Executor can also return an error. But it is its responsibility to put this error into a response.
Index ¶
- Constants
- func ReleaseContext(ctx *Context)
- type Context
- func (c *Context) Cancel()
- func (c *Context) Deadline() (time.Time, bool)
- func (c *Context) Delete(key string)
- func (c *Context) Done() <-chan struct{}
- func (c *Context) Err() error
- func (c *Context) Error(err error)
- func (c *Context) Get(key string) interface{}
- func (c *Context) Hijack(netlocConn net.Conn, hijacker RequestHijacker)
- func (c *Context) Hijacked() bool
- func (c *Context) Init(fasthttpCtx *fasthttp.RequestCtx, connectTo string, eventStream events.Stream, ...) error
- func (c *Context) LocalAddr() net.Addr
- func (c *Context) RemoteAddr() net.Addr
- func (c *Context) Request() *fasthttp.Request
- func (c *Context) Reset()
- func (c *Context) Respond(msg string, statusCode int)
- func (c *Context) Response() *fasthttp.Response
- func (c *Context) Set(key string, value interface{})
- func (c *Context) Value(key interface{}) interface{}
- type HeadersLayer
- type Layer
- type ProxyHeadersLayer
- type RequestHijacker
- type TimeoutLayer
Constants ¶
const TimeoutLayerKeyCancel = "timeout_layer__cancel"
TimeoutLayerKeyCancel defines a key which is used in context to store some internal data.
Variables ¶
This section is empty.
Functions ¶
func ReleaseContext ¶
func ReleaseContext(ctx *Context)
ReleaseContext returns a context back to the pool.
Types ¶
type Context ¶
type Context struct { // ConnectTo contains an endpoint we have to connect to as a next // hop. For example, if you have TLS tunnel, you have 2 addresses: // one from CONNECT method, another one - from a tunneled request. ConnectTo string // RequestID is some unique identifier of the request. RequestID string // User is a username of a client which is doing a request. It // is returned from auth.Interface. If you do not have setup // authentication, it is an empty string. User string // EventStream is an instance of event stream to use. EventStream events.Stream // RequestType is a bitset related to different characteristics of the // request. RequestType events.RequestType // RequestHeaders is a headers of the request. // // If you need to do something with headers, please work with this // field. Underlying request is case sensitive so it would be really // awkward to do anything with it. // // Underlying fasthttp.Request headers are going to be dropped // before sending a request and repopulated from this one. // // If you implement a middleware, you should update this set only on // OnRequest chain flow. Please do not update them in any OnResponse // handler. RequestHeaders headers.Headers // ResponseHeaders is a headers of the response. // // If you need to do something with headers, please work with this // field. Underlying request is case sensitive so it would be really // awkward to do anything with it. // // Underlying fasthttp.Response headers are going to be dropped before // sending a response and repopulated from this one. // // If you implement a middleware, you should update this set only on // OnResponse chain flow. Please do not update them in any OnRequest // handler. ResponseHeaders headers.Headers // contains filtered or unexported fields }
Context is a data structure which we pass along the request. It contains requests, responses, different metadata. You can attach some free-form data there.
func AcquireContext ¶
func AcquireContext() *Context
AcquireContext returns a new context from the pool.
func (*Context) Done ¶
func (c *Context) Done() <-chan struct{}
Done conforms a context.Context interface.
func (*Context) Hijack ¶
func (c *Context) Hijack(netlocConn net.Conn, hijacker RequestHijacker)
Hijack setups a hijacker for the request if necessary. Usually you need it if you want to process upgraded connections such as websockets.
netlocConn is a connection to a target website. It is closed when you exit a hijacker function.
func (*Context) Init ¶
func (c *Context) Init(fasthttpCtx *fasthttp.RequestCtx, connectTo string, eventStream events.Stream, user string, requestType events.RequestType) error
Init initializes a Context based on given parameters.
fasthttpCtx is a parent context which produced this one, connectTo is a host:port of the remote endpoint we need to connect to on a first-hop (think about CONNECT method). The rest of parameters are trivial.
func (*Context) RemoteAddr ¶
RemoteAddr returns an instance of remote address of the client.
func (*Context) Reset ¶
func (c *Context) Reset()
Reset resets a state of the given context. It also cancels it if necessary.
func (*Context) Respond ¶
Respond is just a shortcut for the fast response. This response is just a plain text with a status code.
type HeadersLayer ¶
type HeadersLayer struct { // These headers are set via ctx.RequestHeaders.Set method. RequestSet []headers.Header // These headers are set via ctx.RequestHeaders.SetExact method. RequestSetExact []headers.Header // These headers are removed via ctx.RequestHeaders.Remove method. RequestRemove []string // These headers are removed via ctx.RequestHeaders.RemoveExact method. RequestRemoveExact []string // These headers are set via ctx.ResponseHeaders.Set method if we see // no failures. ResponseOkSet []headers.Header // These headers are set via ctx.ResponseHeaders.SetExact method if we // see no failures. ResponseOkSetExact []headers.Header // These headers are removed via ctx.ResponseHeaders.Remove method if we // see no failures. ResponseOkRemove []string // These headers are removed via ctx.ResponseHeaders.RemoveExact method // if we see no failures. ResponseOkRemoveExact []string // These headers are set via ctx.ResponseHeaders.Set method if we see // failures. ResponseErrSet []headers.Header // These headers are set via ctx.ResponseHeaders.SetExact method if we // see failures. ResponseErrSetExact []headers.Header // These headers are removed via ctx.ResponseHeaders.Remove method if we // see failures. ResponseErrRemove []string // These headers are removed via ctx.ResponseHeaders.RemoveExact method // if we see failures. ResponseErrRemoveExact []string }
HeadersLayer defines a general layer which adds / modifies and removes headers.
func (*HeadersLayer) OnRequest ¶
func (h *HeadersLayer) OnRequest(ctx *Context) error
OnRequest is to conform Layer interface.
func (*HeadersLayer) OnResponse ¶
func (h *HeadersLayer) OnResponse(ctx *Context, err error) error
OnResponse is to conform Layer interface.
type Layer ¶
type Layer interface { // OnRequest is going to be executed when your request goes towards // an executor. // // If you return an error from this method, the whole chain is going // to be aborted and this error will go backwards via stack. OnRequest(*Context) error // OnResponse is going to be executed when your response goes from // executor or error has happened. // // If this middleware has generated that error, it will be a first // which OnResponse is going to be callled. You need to return an // error from this method. Usually you need to return a propagated // error but sometimes you can override it adding some context and // return a new one. OnResponse(*Context, error) error }
Layer is a middleware which processes a request and a response.
You can think about layers as stacks: you go through the list forward and on response or error you go backwards. There is a guarantee that if you passed through OnRequest function call, your OnResponse is also be called.
func NewFilterSubnetsLayer ¶
NewFilterSubnetsLayer filters out requests which should not be passed further. You can use it to protect an access to your private networks.
For example, you can block requests to 127.0.0.1/8, 10.0.0.0/8.
This layer does DNS queries and uses their results to understand if it worth to proceed or not.
type ProxyHeadersLayer ¶
type ProxyHeadersLayer struct{}
ProxyHeadersLayer is simplified version of HeadersLayer with 0 configuration but created only to wipe out some proxy headers from requests and responses.
func (ProxyHeadersLayer) OnRequest ¶
func (p ProxyHeadersLayer) OnRequest(ctx *Context) error
OnRequest is to conform Layer interface.
func (ProxyHeadersLayer) OnResponse ¶
func (p ProxyHeadersLayer) OnResponse(ctx *Context, err error) error
OnResponse is to conform Layer interface.
type RequestHijacker ¶
RequestHijacker is a function signature you can use for internal hijacking. You function will have both ends: a client connection and a netloc connection.
type TimeoutLayer ¶
type TimeoutLayer struct { // Timeout defines a hard time limit of the request. Timeout time.Duration }
TimeoutLayer defines a layer which control a time of execution of the request. So, if you want to limit an execution time by 1 minute, this is a right place to do.
The only flaw is that IF we stopped to process a response and started to pump it back, this middleware does not control that.
func (TimeoutLayer) OnRequest ¶
func (t TimeoutLayer) OnRequest(ctx *Context) error
OnRequest conforms Layer interface.
func (TimeoutLayer) OnResponse ¶
func (t TimeoutLayer) OnResponse(ctx *Context, err error) error
OnResponse conforms Layer interface.