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.