com.subgraph.vega.internal.http.proxy.HttpProxy.java Source code

Java tutorial

Introduction

Here is the source code for com.subgraph.vega.internal.http.proxy.HttpProxy.java

Source

/*******************************************************************************
 * Copyright (c) 2011 Subgraph.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 * 
 * Contributors:
 *     Subgraph - initial API and implementation
 ******************************************************************************/
package com.subgraph.vega.internal.http.proxy;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.apache.http.impl.DefaultConnectionReuseStrategy;
import org.apache.http.impl.DefaultHttpResponseFactory;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.CoreConnectionPNames;
import org.apache.http.params.HttpParams;
import org.apache.http.protocol.BasicHttpProcessor;
import org.apache.http.protocol.HttpRequestHandlerRegistry;
import org.apache.http.protocol.ResponseConnControl;

import com.subgraph.vega.api.http.proxy.IHttpInterceptProxy;
import com.subgraph.vega.api.http.proxy.IHttpInterceptProxyEventHandler;
import com.subgraph.vega.api.http.requests.IHttpRequestEngine;
import com.subgraph.vega.internal.http.proxy.ssl.SSLContextRepository;

public class HttpProxy implements IHttpInterceptProxy {
    static final String PROXY_CONTEXT_REQUEST = "proxy.request";
    static final String PROXY_CONTEXT_RESPONSE = "proxy.response";
    static final String PROXY_HTTP_HOST = "proxy.host";
    static final String PROXY_HTTP_TRANSACTION = "proxy.transaction";

    private final Logger logger = Logger.getLogger("proxy");

    private final ProxyTransactionManipulator transactionManipulator;
    private final HttpInterceptor interceptor;
    private final List<IHttpInterceptProxyEventHandler> eventHandlers;
    private final int listenPort;
    private ServerSocket serverSocket;
    private HttpParams params;
    private VegaHttpService httpService;
    private ExecutorService executor = Executors.newCachedThreadPool();
    private Thread proxyThread;
    private final List<ConnectionTask> connectionList;

    public HttpProxy(int listenPort, ProxyTransactionManipulator transactionManipulator,
            HttpInterceptor interceptor, IHttpRequestEngine requestEngine,
            SSLContextRepository sslContextRepository) {
        this.eventHandlers = new ArrayList<IHttpInterceptProxyEventHandler>();
        this.transactionManipulator = transactionManipulator;
        this.interceptor = interceptor;
        this.listenPort = listenPort;
        this.params = new BasicHttpParams();
        this.params.setIntParameter(CoreConnectionPNames.SO_TIMEOUT, 0)
                .setIntParameter(CoreConnectionPNames.SOCKET_BUFFER_SIZE, 8 * 1024)
                //      .setBooleanParameter(CoreConnectionPNames.STALE_CONNECTION_CHECK, false)
                .setBooleanParameter(CoreConnectionPNames.TCP_NODELAY, true);

        BasicHttpProcessor inProcessor = new BasicHttpProcessor();
        inProcessor.addInterceptor(new ResponseConnControl());
        inProcessor.addInterceptor(new ResponseContentCustom());

        HttpRequestHandlerRegistry registry = new HttpRequestHandlerRegistry();
        registry.register("*", new ProxyRequestHandler(this, logger, requestEngine));

        httpService = new VegaHttpService(inProcessor, new DefaultConnectionReuseStrategy(),
                new DefaultHttpResponseFactory(), registry, params, sslContextRepository);

        connectionList = new ArrayList<ConnectionTask>();
    }

    @Override
    public void startProxy() {
        try {
            logger.info("Listening on port " + listenPort);
            serverSocket = new ServerSocket(listenPort);
            proxyThread = new Thread(createProxyLoopRunnable());
            proxyThread.start();
        } catch (IOException e) {
            logger.log(Level.WARNING, "IO error creating listening socket: " + e.getMessage(), e);
        }
    }

    private Runnable createProxyLoopRunnable() {
        return new Runnable() {
            @Override
            public void run() {
                proxyAcceptLoop();
            }
        };
    }

    private void proxyAcceptLoop() {
        while (!Thread.interrupted()) {
            Socket s;
            try {
                s = serverSocket.accept();
            } catch (IOException e) {
                if (!Thread.interrupted()) {
                    logger.log(Level.WARNING, "IO error processing incoming connection: " + e.getMessage(), e);
                }
                break;
            }

            logger.fine("Connection accepted from " + s.getRemoteSocketAddress());
            VegaHttpServerConnection c = new VegaHttpServerConnection(params);
            try {
                c.bind(s, params);
            } catch (IOException e) {
                logger.log(Level.WARNING, "Unexpected error: " + e.getMessage(), e);
                continue;
            }

            final ConnectionTask task = new ConnectionTask(httpService, c, HttpProxy.this);
            synchronized (connectionList) {
                connectionList.add(task);
            }
            executor.execute(task);
        }

        synchronized (connectionList) {
            for (ConnectionTask task : connectionList) {
                task.shutdown();
            }
        }

        executor.shutdownNow();
    }

    @Override
    public void stopProxy() {
        proxyThread.interrupt();
        try {
            // close the socket to interrupt accept() in proxyAcceptLoop()
            serverSocket.close();
        } catch (IOException e) {
            logger.log(Level.WARNING, "Unexpected exception closing server socket: " + e.getMessage(), e);
        }
    }

    @Override
    public int getListenPort() {
        return listenPort;
    }

    @Override
    public void registerEventHandler(IHttpInterceptProxyEventHandler handler) {
        synchronized (eventHandlers) {
            eventHandlers.add(handler);
        }
    }

    @Override
    public void unregisterEventHandler(IHttpInterceptProxyEventHandler handler) {
        synchronized (eventHandlers) {
            eventHandlers.remove(handler);
        }
    }

    public boolean handleTransaction(ProxyTransaction transaction) throws InterruptedException {
        if (transaction.hasResponse() == false) {
            transactionManipulator.process(transaction.getRequest());
        } else {
            transactionManipulator.process(transaction.getResponse().getRawResponse());
        }

        boolean rv = interceptor.handleTransaction(transaction);
        if (rv == true) {
            transaction.await();
        }
        return rv;
    }

    void completeRequest(ProxyTransaction transaction) {
        synchronized (eventHandlers) {
            for (IHttpInterceptProxyEventHandler h : eventHandlers)
                h.handleRequest(transaction);
        }
    }

    public void notifyClose(ConnectionTask task) {
        synchronized (connectionList) {
            connectionList.remove(task);
        }
    }

}