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

org.littleshoot.proxy.DefaultRelayPipelineFactory Maven / Gradle / Ivy

package org.littleshoot.proxy;

import static org.jboss.netty.channel.Channels.pipeline;

import java.util.Map;

import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.channel.ChannelPipelineFactory;
import org.jboss.netty.channel.group.ChannelGroup;
import org.jboss.netty.handler.codec.http.HttpChunkAggregator;
import org.jboss.netty.handler.codec.http.HttpContentDecompressor;
import org.jboss.netty.handler.codec.http.HttpMethod;
import org.jboss.netty.handler.codec.http.HttpRequest;
import org.jboss.netty.handler.codec.http.HttpResponseDecoder;
import org.jboss.netty.handler.timeout.IdleStateHandler;
import org.jboss.netty.util.HashedWheelTimer;
import org.jboss.netty.util.Timer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class DefaultRelayPipelineFactory implements ChannelPipelineFactory {
    private static final Logger LOG = 
        LoggerFactory.getLogger(DefaultRelayPipelineFactory.class);
    private static final Timer TIMER = new HashedWheelTimer();
    
    private final String hostAndPort;
    private final HttpRequest httpRequest;
    private final RelayListener relayListener;
    private final Channel browserToProxyChannel;

    private final ChannelGroup channelGroup;
    private final Map filters;
    private final HttpRequestFilter requestFilter;
    private String chainProxyHostAndPort;
    private final boolean filtersOff;

    
    public DefaultRelayPipelineFactory(final String hostAndPort, 
        final HttpRequest httpRequest, final RelayListener relayListener, 
        final Channel browserToProxyChannel,
        final ChannelGroup channelGroup, final Map filters, 
        final HttpRequestFilter requestFilter, 
        final String chainProxyHostAndPort) {
        this.hostAndPort = hostAndPort;
        this.httpRequest = httpRequest;
        this.relayListener = relayListener;
        this.browserToProxyChannel = browserToProxyChannel;
        
        this.channelGroup = channelGroup;
        this.filters = filters;
        this.requestFilter = requestFilter;
        this.chainProxyHostAndPort = chainProxyHostAndPort;
        
        this.filtersOff = filters.isEmpty();
    }
    

    public ChannelPipeline getPipeline() throws Exception {
        // Create a default pipeline implementation.
        final ChannelPipeline pipeline = pipeline();
        
        // We always include the request and response decoders
        // regardless of whether or not this is a URL we're 
        // filtering responses for. The reason is that we need to
        // follow connection closing rules based on the response
        // headers and HTTP version. 
        //
        // We also importantly need to follow the cache directives
        // in the HTTP response.
        pipeline.addLast("decoder", 
            new HttpResponseDecoder(8192, 8192*2, 8192*2));
        
        LOG.debug("Querying for host and port: {}", hostAndPort);
        final boolean shouldFilter;
        final HttpFilter filter;
        if (filtersOff) {
            shouldFilter = false;
            filter = null;
        } else {
            filter = filters.get(hostAndPort);
            if (filter == null) {
                LOG.info("Filter not found in: {}", filters);
                shouldFilter = false;
            }
            else {
                LOG.debug("Using filter: {}", filter);
                shouldFilter = filter.shouldFilterResponses(httpRequest);
            }
            LOG.debug("Filtering: "+shouldFilter);
        }
        
        // We decompress and aggregate chunks for responses from 
        // sites we're applying rules to.
        if (shouldFilter) {
            pipeline.addLast("inflater", 
                new HttpContentDecompressor());
            pipeline.addLast("aggregator",            
                new HttpChunkAggregator(filter.getMaxResponseSize()));//2048576));
        }
        
        // The trick here is we need to determine whether or not
        // to cache responses based on the full URI of the request.
        // This request encoder will only get the URI without the
        // host, so we just have to be aware of that and construct
        // the original.
        final HttpRelayingHandler handler;
        if (shouldFilter) {
            handler = new HttpRelayingHandler(browserToProxyChannel, 
                channelGroup, filter, relayListener, hostAndPort);
        } else {
            handler = new HttpRelayingHandler(browserToProxyChannel, 
                channelGroup, relayListener, hostAndPort);
        }
        
        final ProxyHttpRequestEncoder encoder = 
            new ProxyHttpRequestEncoder(handler, requestFilter, 
                chainProxyHostAndPort);
        pipeline.addLast("encoder", encoder);
        
        // We close idle connections to remote servers after the
        // specified timeouts in seconds. If we're sending data, the
        // write timeout should be reasonably low. If we're reading
        // data, however, the read timeout is more relevant.
        final int readTimeoutSeconds;
        final int writeTimeoutSeconds;
        if (httpRequest.getMethod().equals(HttpMethod.POST) ||
            httpRequest.getMethod().equals(HttpMethod.PUT)) {
            readTimeoutSeconds = 0;
            writeTimeoutSeconds = 40;
        } else {
            readTimeoutSeconds = 40;
            writeTimeoutSeconds = 0;
        }
        pipeline.addLast("idle", 
            new IdleStateHandler(TIMER, readTimeoutSeconds, 
                writeTimeoutSeconds, 0));
        pipeline.addLast("idleAware", new IdleAwareHandler());
        pipeline.addLast("handler", handler);
        return pipeline;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy