Runtime View¶
Request-Response Roundtrip¶
Any incoming TCP connection is wrapped into a Netty channel (io.netty.channel.Channel
) and incoming bytes are handled by a chain of ChannelInboundHandlers
. For connections resulting in bytes written back to the channel, the write attempts accordingly are passed along a chain of ChannelOutboundHandlers
. To gain a deeper understanding about Netty’s asynchronous non-blocking I/O model, please refer to the documentation at https://netty.io/.
Inbound TCP streams that contain HTTP requests, are effectively handled by Zuul, where they are passed along chains of inbound filters and outbound filters. Between both chains, the final request is actually processed, usually by performing a proxy request against an upstream/origin server. This processing is performed by an endpoint filter.
Proxy requests are performed using Netty again on the HTTP and network layers.
Server Request Processing¶
This section describes, how incoming HTTP requests are processed by handlers of the underlying Zuul and Netty frameworks and handlers added by OX. It describes the various io.netty.channel.ChannelHandler
implementations that perform actual work during this process. The term Channel
denotes a low-level socket connection between client and server. A ChannelHandler
reacts to events that happen on such channels. The most relevant events are:
inbound data is available for reading
outbound data was written
a user-defined event was fired
Channel handlers are implemented as chains, where each handler optionally performs its work based on an event and then calls the next handler in the chain to perform its own work. To preserve state between different handlers, multiple invocations of the same handler or different events of the same handler, a ChannelContext
instance is passed along with the actual event object.
Server Channel Handlers¶
The following chain of inbound and outbound channel handlers is processed for each incoming HTTP request. The yellow boxes denote plain Netty handlers while the red ones denote Zuul handlers.
- IdleStateHandler
Schedules tasks to periodically check whether a configured idle time value was exceeded, resulting in an event.
Inbound: Tracks time of last complete message read event on the channel.
Outbound: Tracks time of last channel write event.
Triggered Events:
io.netty.handler.timeout.IdleStateEvent
Handled Events: –
- CloseOnIdleStateHandler
Closes idle channels.
Inbound: –
Outbound: –
Triggered Events: –
Handled Events:
io.netty.handler.timeout.IdleStateEvent
- PassportStateServerHandler
Passport maintenance to track channel lifecycles. See https://github.com/Netflix/zuul/wiki/Core-Features#request-passport.
Inbound: Tracked states:
SERVER_CH_ACTIVE
SERVER_CH_INACTIVE
SERVER_CH_EXCEPTION
Outbound: Tracked states:
SERVER_CH_CLOSE
SERVER_CH_DISCONNECT
SERVER_CH_EXCEPTION
Triggered Events: –
Handled Events:
io.netty.handler.timeout.IdleStateEvent
: Tracked asSERVER_CH_IDLE_TIMEOUT
- SourceAddressChannelHandler
Stores actual IP address and port of client and server sides of the channel within the channel context.
Inbound: –
Outbound: –
Triggered Events: –
Handled Events: –
- ServerChannelMetrics
Collects monitoring metrics on the channel level:
server.connections.current
server.connections.connect
server.connections.errors
server.connections.close
server.connections.idle.timeout
server.connections.throttled
Inbound: –
Outbound: –
Triggered Events: –
Handled Events:
MaxInboundConnectionsHandler.CONNECTION_THROTTLED_EVENT
io.netty.handler.timeout.IdleStateEvent
- PerEventLoopMetricsChannelHandler
Collects monitoring metrics on the event loop level:
server.eventloop.http.requests.current
server.eventloop.connections.current
Inbound: –
Outbound: –
Triggered Events: –
Handled Events:
HttpLifecycleChannelHandler.StartEvent
: increment current HTTP requestsHttpLifecycleChannelHandler.CompleteEvent
: decrement current HTTP requests
- ElbProxyProtocolChannelHandler
Decodes PROXY protocol and if applicable stores the contained client and server IP addresses and ports within the channel context. This effectively overrides the values stored by
SourceAddressChannelHandler
.Inbound: Check for PROXY protocol and process its metadata.
Outbound: –
Triggered Events: –
Handled Events: –
- MaxInboundConnectionsHandler
Closes any incoming new connections if current count is above a configured threshold. For throttled connections, this is stored within the passport.
Inbound: –
Outbound: –
Triggered Events:
MaxInboundConnectionsHandler.CONNECTION_THROTTLED_EVENT
Handled Events: –
- SslHandler
Performs TLS handshake on incoming connections and ensures according wrapping of input/output byte buffers. See JavaDoc of
io.netty.handler.ssl.SslHandler
for details.Inbound: –
Outbound: –
Triggered Events:
SslHandshakeCompletionEvent
Handled Events: –
- SslHandshakeInfoHandler
Stores info about the client and server’s SSL certificates in the context, after a successful handshake.
Inbound: –
Outbound: –
Triggered Events: –
Handled Events:
SslHandshakeCompletionEvent
- HttpServerCodec
De-/encodes the in-/outbound byte streams to/from HTTP domain objects.
Inbound: Decode byte stream into
io.netty.handler.codec.http.HttpRequest
.Outbound: Encode
io.netty.handler.codec.http.HttpResponse
into byte stream.Triggered Events: –
Handled Events: –
- Http1ConnectionCloseHandler
Manages HTTP keep-alive lifecycle of inbound connections.
Inbound: –
Outbound: Adds
Connection: close
response header if channel is supposed to be closed after the current request was handled. In addition it actively closes the channel after the last packet has been sent.Triggered Events: –
Handled Events: –
- PassportStateHttpServerHandler
Passport maintenance to track HTTP request lifecycle events. See https://github.com/Netflix/zuul/wiki/Core-Features#request-passport.
Inbound: Tracked states:
IN_REQ_HEADERS_RECEIVED
IN_REQ_CONTENT_RECEIVED
IN_REQ_LAST_CONTENT_RECEIVED
Outbound: Tracked states:
OUT_RESP_HEADERS_SENDING
OUT_RESP_HEADERS_SENT
OUT_RESP_HEADERS_ERROR_SENDING
OUT_RESP_CONTENT_SENDING
OUT_RESP_CONTENT_SENT
OUT_RESP_CONTENT_ERROR_SENDING
OUT_RESP_LAST_CONTENT_SENDING
OUT_RESP_LAST_CONTENT_SENT
OUT_RESP_LAST_CONTENT_ERROR_SENDING
Triggered Events: –
Handled Events:
HttpLifecycleChannelHandler.CompleteEvent
: Reset channel passport
- HttpRequestReadTimeoutHandler
Fires timeout event if configured read timeout is exceeded while waiting for data of an incoming HTTP message. The handler does NOT close a timed out connection!
Sets
IN_REQ_READ_TIMEOUT
state in passport for timed out requests. Also incrementsserver.http.request.read.timeout
monitoring counter.Inbound: Tracks time since last chunk of data was read.
Outbound: –
Triggered Events:
HttpRequestReadTimeoutEvent
Handled Events: –
- HttpServerLifecycleChannelHandler
Triggers HTTP request lifecycle events for the Zuul layer.
Inbound: Fires event as soon as an incoming HTTP request along with all headers is available.
Outbound: Fires event as soon as an HTTP response was fully sent.
Triggered Events:
com.netflix.netty.common.HttpLifecycleChannelHandler.StartEvent
com.netflix.netty.common.HttpLifecycleChannelHandler.CompleteEvent
Handled Events: –
- HttpBodySizeRecordingChannelHandler
Records body sizes of HTTP requests and responses and stores them as attributes within the channel context.
Inbound: Records request body size.
Outbound: Records response body size.
Triggered Events: –
Handled Events:
HttpLifecycleChannelHandler.CompleteEvent
: Resets channel context
- HttpMetricsChannelHandler
Collects monitoring metrics on the HTTP request level:
server.http.requests.current
server.http.requests.pipelining.dropped
Inbound: –
Outbound: –
Triggered Events: –
Handled Events:
HttpServerLifecycleChannelHandler.StartEvent
HttpServerLifecycleChannelHandler.CompleteEventEvent
HttpServerLifecycleChannelHandler.RejectedPipeliningEvent
- AccessLogChannelHandler
Performs HTTP access logging for handled requests.
Inbound: Tracks start time (as soon as request headers are parsed) and request body size and stores it in channel context.
Outbound: Tracks response body size and stores it in channel context.
Triggered Events: –
Handled Events:
HttpServerLifecycleChannelHandler.CompleteEvent
: Combines tracked data with other channel attributes and writes access log entry.
- StripUntrustedProxyHeadersHandler
Based on configuration removes
X-Forwarded-*
headers from incoming requests.Inbound: Strips headers.
Outbound: –
Triggered Events: –
Handled Events: –
- LoggingHandler
Netty debug handler that logs any channel event according to a configured log level threshold.
Inbound: –
Outbound: –
Triggered Events: –
Handled Events: –
- ClientRequestReceiver
Converts Netty HTTP request object into a Zuul domain object and passes it further down the channel pipeline.
Inbound: As soon as an
io.netty.handler.codec.http.HttpRequest
instance is available, it is converted into acom.netflix.zuul.message.http.HttpRequestMessage
instance.Outbound: Tracks I/O errors during response writing
Triggered Events: –
Handled Events:
HttpServerLifecycleChannelHandler.CompleteEventEvent
- PassportLoggingHandler
Logs the passport (https://github.com/Netflix/zuul/wiki/Core-Features#request-passport) for completed requests. Typically this results in
DEBUG
logs. But if request or response processing took longer than a configured time, this is logged onINFO
level.Inbound: –
Outbound: –
Triggered Events: –
Handled Events:
HttpLifecycleChannelHandler.CompleteEvent
- ZuulFilterChainHandler
This is the actual bridge between Netty events and the Zuul proxy engine.
Inbound:
com.netflix.zuul.message.http.HttpRequestMessage
are taken and handed over to the Zuul request filter chain.Outbound: –
Triggered Events: –
Handled Events:
HttpLifecycleChannelHandler.CompleteEvent
: Reports processing completion to proxy endpoint.HttpRequestReadTimeoutEvent
: Responds with HTTP 408io.netty.handler.timeout.IdleStateEvent
: Responds with HTTP 504RequestCancelledEvent
: Track cancelled statusHttpLifecycleChannelHandler.RejectedPipeliningEvent
: Responds with HTTP 400
- ClientResponseWriter
Reacts to Zuul HTTP responses passed along the channel pipeline and converts them into Netty domain objects.
Inbound: If the Zuul proxy engine is done with a request and has a response ready in the form of
com.netflix.zuul.message.http.HttpResponseMessage
, it is actually passed along the Netty channel pipeline as a read event. This handler converts those instances intoio.netty.handler.codec.http.HttpResponse
instances. It then effectively interrupts the read handler chain for this request and instead initiates the write handler chain by writing the Netty HTTP response object onto it.Outbound: –
Triggered Events: –
Handled Events:
HttpServerLifecycleChannelHandler.StartEvent
HttpServerLifecycleChannelHandler.CompleteEventEvent
: If the channel is to be closed because of aConnection: close
response header, this handler does so. Otherwise it restarts the read handler chain on this channel to process the next request.
- ServerStatusHeaderHandler
Does nothing currently.
- Http1ConnectionExpiryHandler
Tracks the number of requests per channel so that it can be marked as closed and be effectively closed by
Http1ConnectionCloseHandler
andClientResponseWriter
.Inbound: –
Outbound: Marks channel to be closed if max. number of requests per channel was reached.
Triggered Events: –
Handled Events: –
HTTP Request Handling¶
Any HTTP request that successfully passed the inbound channel handlers is finally available as a com.netflix.zuul.message.http.HttpRequestMessage
object. This object is passed on to the Zuul request filter chain, where it is handled. Handling means, the request is either forwarded (“proxied”) to an origin server or handled by an endpoint filter directly. In any case it leads to the creation of an com.netflix.zuul.message.http.HttpResponseMessage
object, which is then passed forward to the server channel outbound handlers.
App Suite Proxy Engine¶
TODO
Client Request Processing¶
This section describes, how HTTP requests are
transformed and forwarded to an origin server and its response then transformed and written to the client or
handled by App Suite Proxy directly, resulting in a generated HTTP response