The previous posts exposed you to OpenIG: use cases and an initial configuration example. Before going further, I would like to introduce the underlying concepts that you should understand.
HTTP Exchanges Requests and Responses
OpenIG is a specialized HTTP reverse-proxy: it only deals with HTTP messages. The purpose of OpenIG is to give a complete control over the messages flowing through itself (incoming requests and outgoing responses).
In order to ease handling of the whole message processing (request and response),
OpenIG uses the concept of
Exchange: it’s a simple way to link a
Response together. It also contains a
Session instance that can be used to
store session-scoped properties. The
Exchange itself is a
Map so it’s a natural
container for request-scoped properties.
When a request comes through OpenIG, an
Exchange object is created and populated
with an initial
Request and a
Request is the OpenIG model for an incoming HTTP message, it captures both
the message’s entity and all of its headers. It also has dedicated accessors for
message’s target URI, cookies and form/query parameters.
Response is the complementary model object for outgoing HTTP messages. In
addition to the entity and headers accessors,
Response provides setter for
the HTTP status code (
20x -> ok,
30x -> redirect,
50x -> server error, …).
Now we have a model of the message’s content, what can we do to apply transformations to it?
OpenIG offers a simple, but powerful, API to process exchanges:
Handlerthat are responsible to produce a
Responseobject into the
Filterthat can intercept the flowing
Exchange(incoming and outgoing)
What do the doc says about
Called to request the handler respond to the request.
A handler that doesn’t hand-off an exchange to another handler downstream is responsible for creating the response in the exchange object.
Hmmm, an example would help, right ?
OpenIG offers a rich set of Handlers, the most significative one would be the
This is a highly used component usually ending
Exchange’s processing that
simply forward the
Request to the required URI and wraps the returned HTTP
message into the
In other words, it acts as a client to the protected resource (hence the name).
Again, what do the doc says about
Filters the request and/or response of an exchange.
Initially, exchange.request contains the request to be filtered. To pass the request to the next filter or handler in the chain, the filter calls next.handle(exchange). After this call, exchange.response contains the response that can be filtered.
This method may elect not to pass the request to the next filter or handler, and instead handle the request itself. It can achieve this by merely avoiding a call to next.handle(exchange) and creating its own response object the exchange. The filter is also at liberty to replace a response with another of its own after the call to next.handle(exchange).
This is easier to understand I think, everyone is used to interceptors nowadays…
The traditional example of a
Filter is the
CaptureFilter: this filter simply
prints the content of the incoming request, then call the next handler in chain
and finally prints the outgoing response’s content.
Filters are contained inside a special
Handler called a
Chain. The chain
is responsible to sequentially invoke each of the filter declared in its
configuration, before handing the flow to its terminal
All together: a Chain example
If you have your OpenIG up and running, please shut it down and replace
its configuration file (
config.json) with the following content:
Compared to previous, this configuration will enhance the response message
with an additional HTTP header named
The message flow is depicted in the following diagram:
Filter can intercept both the
Request and the
Reponse flows. In this
HeaderFilter is configured to only act on the response flow (because
the outgoing message is a handy way to observe a filter in action from an
OpenIG provides a low-level HTTP model API that let you alter HTTP messages in many ways. The message processing is handled through some kind of pipeline composed of handlers and filters.
All the processing logic you want to apply to your messages finally depends on the way you compose your handlers and filters together.
In the next post we’ll see how to debug your configurations.