All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.reactivex.netty.protocol.http.server.HttpServerInterceptorChain Maven / Gradle / Ivy

There is a newer version: 0.5.3-rc.2
Show newest version
/*
 * Copyright 2016 Netflix, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

package io.reactivex.netty.protocol.http.server;

import io.netty.buffer.ByteBuf;
import rx.annotations.Beta;

/**
 * A utility to create an interceptor chain to be used with a {@link HttpServer} to modify behavior of requests
 * processed by that server.
 *
 * 

What are interceptors?

* * Interceptors can be used to achieve use-cases that involve instrumentation related to any behavior of the requests, * they can even be used to short-circuit the rest of the chain or to provide canned responses. In order to achieve such * widely different use-cases, an interceptor is modelled as a simple function that takes one {@link RequestHandler} * and returns another {@link RequestHandler} instance. With this low level abstraction, any use-case pertaining to * connection instrumentation can be achieved. * *

Interceptor chain anatomy

*
        -------        -------        -------        -------        -------
       |       |      |       |      |       |      |       |      |       |
       |       | ---> |       | ---> |       | ---> |       | ---> |       |
       |       |      |       |      |       |      |       |      |       |
        -------        -------        -------        -------        -------
      Interceptor    Interceptor    Interceptor    Interceptor      Request
           1              2              3              4           Handler
 
* * An interceptor chain always starts with an interceptor and ends with a {@link RequestHandler} and any number of * other interceptors can exist between the start and end.

* * A chain can be created by using the various {@code start*()} methods available in this class, eg: * {@link #start()}, {@link #startRaw()}.

* * After starting a chain, any number of other interceptors can be added by using the various {@code next*()} methods * available in this class, eg: {@link #next(Interceptor)}, {@link #nextWithTransform(TransformingInterceptor)}, * {@link #nextWithRequestTransform(TransformingInterceptor)} and * {@link #nextWithResponseTransform(TransformingInterceptor)}

* * After adding the required interceptors, by providing a {@link RequestHandler} via the * {@link #end(RequestHandler)} method, the chain can be ended and the returned {@link RequestHandler} can be used * with any {@link HttpServer}

* * So, a typical interaction with this class would look like:

* * {@code * HttpServer.newServer().start(HttpServerInterceptorChain.start(first).next(second).next(third).end(handler)) * } * *

Simple Interceptor

* * For interceptors that do not change the types of objects read or written to the underlying request/response, the * interface {@link HttpServerInterceptorChain.Interceptor} defines the interceptor contract. * *

Modifying the type of data read/written to the request/response

* * Sometimes, it is required to change the type of objects read from a request or written to a response handled by * a {@link HttpServer}. For such cases, the interface {@link HttpServerInterceptorChain.TransformingInterceptor} * defines the interceptor contract. Since, this included 4 generic arguments to the interceptor, this is not the base * type for all interceptors and should be used only when the types of the request/response are actually to be * changed. * *

Execution order

*
      -------        -------         -------        -------        -------        -------        -------
     |       |      |       |       |       |      |       |      |       |      |       |      |       |
     |       | ---> |       | --->  |       | ---> |       | ---> |       | ---> |       | ---> |       |
     |       |      |       |       |       |      |       |      |       |      |       |      |       |
      -------        -------         -------        -------        -------        -------        -------
       Http          Request      Interceptor    Interceptor    Interceptor    Interceptor        Request
      Server         Handler           1              2              3              4             Handler
                   (Internal)                                                                     (User)
 
* * The above diagram depicts the execution order of interceptors. The first request handler (internal) is created by * this class and as is returned by {@link #end(RequestHandler)} method by providing a {@link RequestHandler} that * does the actual processing of the connection. {@link HttpServer} with which this interceptor chain is used, will * invoke the internal request handler provided by this class.

* * The interceptors are invoked in the order that they are added to this chain. * * @param The type of objects received as content from a request to this server. * @param The type of objects written as content from a response from this server. * @param The type of objects received as content from a request to this server after applying these interceptors. * @param The type of objects written as content from a response from this server after applying these * interceptors. */ @Beta public final class HttpServerInterceptorChain { private final TransformingInterceptor interceptor; private HttpServerInterceptorChain(TransformingInterceptor interceptor) { this.interceptor = interceptor; } /** * Add the next interceptor to this chain. * * @param next Next interceptor to add. * * @return A new interceptor chain with the interceptors currently existing and the passed interceptor added to the * end. */ public HttpServerInterceptorChain next(final Interceptor next) { return new HttpServerInterceptorChain<>(new TransformingInterceptor() { @Override public RequestHandler intercept(RequestHandler handler) { return interceptor.intercept(next.intercept(handler)); } }); } /** * Add the next interceptor to this chain, which changes the type of objects read from the request accepted by * the associated {@link HttpServer}. * * @param next Next interceptor to add. * * @return A new interceptor chain with the interceptors currently existing and the passed interceptor added to the * end. */ public HttpServerInterceptorChain nextWithRequestTransform(final TransformingInterceptor next) { return new HttpServerInterceptorChain<>(new TransformingInterceptor() { @Override public RequestHandler intercept(RequestHandler handler) { return interceptor.intercept(next.intercept(handler)); } }); } /** * Add the next interceptor to this chain, which changes the type of objects written to the response sent by * the associated {@link HttpServer}. * * @param next Next interceptor to add. * * @return A new interceptor chain with the interceptors current existing and the passed interceptor added to the * end. */ public HttpServerInterceptorChain nextWithResponseTransform(final TransformingInterceptor next) { return new HttpServerInterceptorChain<>(new TransformingInterceptor() { @Override public RequestHandler intercept(RequestHandler handler) { return interceptor.intercept(next.intercept(handler)); } }); } /** * Add the next interceptor to this chain, which changes the type of objects read read from the request and written * to the response sent by the associated {@link HttpServer}. * * @param next Next interceptor to add. * * @return A new interceptor chain with the interceptors current existing and the passed interceptor added to the * end. */ public HttpServerInterceptorChain nextWithTransform(final TransformingInterceptor next) { return new HttpServerInterceptorChain<>(new TransformingInterceptor() { @Override public RequestHandler intercept(RequestHandler handler) { return interceptor.intercept(next.intercept(handler)); } }); } /** * Terminates this chain with the passed {@link RequestHandler} and returns a {@link RequestHandler} to be * used by a {@link HttpServer} * * @param handler Request handler to use. * * @return A request handler that wires the interceptor chain, to be used with {@link HttpServer} instead of * directly using the passed {@code handler} */ public RequestHandler end(RequestHandler handler) { return interceptor.intercept(handler); } /** * Starts a new interceptor chain. * * @return A new interceptor chain. */ public static HttpServerInterceptorChain start() { return new HttpServerInterceptorChain<>(new TransformingInterceptor() { @Override public RequestHandler intercept(RequestHandler handler) { return handler; } }); } /** * Starts a new interceptor chain with {@link ByteBuf} read and written from request and to responses. * * @return A new interceptor chain. */ public static HttpServerInterceptorChain startRaw() { return new HttpServerInterceptorChain<>(new TransformingInterceptor() { @Override public RequestHandler intercept(RequestHandler handler) { return handler; } }); } /** * An interceptor that preserves the type of content of request and response. * * @param The type of objects received as content from a request to this server. * @param The type of objects written as content from a response from this server. */ public interface Interceptor { /** * Intercepts and optionally changes the passed {@code RequestHandler}. * * @param handler Handler to intercept. * * @return Handler to use after this transformation. */ RequestHandler intercept(RequestHandler handler); } /** * An interceptor that changes the type of content of request and response. * * @param The type of objects received as content from a request to this server. * @param The type of objects written as content from a response from this server. * @param The type of objects received as content from a request to this server after applying this * interceptor. * @param The type of objects written as content from a response from this server after applying this * interceptor. */ public interface TransformingInterceptor { /** * Intercepts and changes the passed {@code RequestHandler}. * * @param handler Handler to intercept. * * @return Handler to use after this transformation. */ RequestHandler intercept(RequestHandler handler); } }