com.tasktop.c2c.server.web.proxy.HttpProxy.java Source code

Java tutorial

Introduction

Here is the source code for com.tasktop.c2c.server.web.proxy.HttpProxy.java

Source

/*******************************************************************************
 * Copyright (c) 2010, 2012 Tasktop Technologies
 * Copyright (c) 2010, 2011 SpringSource, a division of VMware
 * 
 * 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:
 *     Tasktop Technologies - initial API and implementation
 ******************************************************************************/
package com.tasktop.c2c.server.web.proxy;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Enumeration;
import java.util.regex.Pattern;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.httpclient.DefaultHttpMethodRetryHandler;
import org.apache.commons.httpclient.Header;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpMethod;
import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
import org.apache.commons.httpclient.cookie.CookiePolicy;
import org.apache.commons.httpclient.methods.DeleteMethod;
import org.apache.commons.httpclient.methods.EntityEnclosingMethod;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.HeadMethod;
import org.apache.commons.httpclient.methods.InputStreamRequestEntity;
import org.apache.commons.httpclient.methods.OptionsMethod;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.methods.PutMethod;
import org.apache.commons.httpclient.methods.RequestEntity;
import org.apache.commons.httpclient.methods.TraceMethod;
import org.apache.commons.httpclient.params.HttpMethodParams;
import org.springframework.stereotype.Component;

@Component
public class HttpProxy extends WebProxy {
    private static Pattern targetUrlPattern = Pattern.compile("https?://.+");

    private HttpClient httpClient;

    private HttpMethodProvider httpMethodProvider = new HttpMethodProvider() {

        @Override
        public HttpMethod getMethod(String httpMethod, String uri) {
            if (httpMethod.equals("GET")) {
                return new GetMethod(uri);
            } else if (httpMethod.equals("DELETE")) {
                return new DeleteMethod(uri);
            } else if (httpMethod.equals("HEAD")) {
                return new HeadMethod(uri);
            } else if (httpMethod.equals("OPTIONS")) {
                return new OptionsMethod(uri);
            } else if (httpMethod.equals("POST")) {
                return new PostMethod(uri);
            } else if (httpMethod.equals("PUT")) {
                return new PutMethod(uri);
            } else if (httpMethod.equals("TRACE")) {
                return new TraceMethod(uri);
            }
            throw new IllegalArgumentException("Invalid HTTP method: " + httpMethod);
        }
    };

    public HttpProxy() {
        httpClient = new HttpClient(new MultiThreadedHttpConnectionManager());
        httpClient.getParams().setCookiePolicy(CookiePolicy.IGNORE_COOKIES);
        httpClient.getHttpConnectionManager().getParams().setSoTimeout(60 * 1000);
        httpClient.getParams().setParameter(HttpMethodParams.RETRY_HANDLER,
                new DefaultHttpMethodRetryHandler(0, false));
    }

    @Override
    public boolean canProxyRequest(String targetUrl, HttpServletRequest request) {
        return targetUrlPattern.matcher(targetUrl).matches();
    }

    @Override
    protected void proxy(String targetUrl, final HttpServletRequest request, final HttpServletResponse response)
            throws IOException {

        final HttpMethod proxyRequest = createProxyRequest(targetUrl, request);

        if (proxyRequest instanceof EntityEnclosingMethod) {
            EntityEnclosingMethod entityEnclosingMethod = (EntityEnclosingMethod) proxyRequest;
            RequestEntity requestEntity = new InputStreamRequestEntity(request.getInputStream(),
                    request.getContentLength(), request.getContentType());
            entityEnclosingMethod.setRequestEntity(requestEntity);
        }
        int code = httpClient.executeMethod(proxyRequest);
        response.setStatus(code);
        copyProxyReponse(proxyRequest, response);

    }

    private String uriEncode(String url) {
        return url.replace(" ", "%20");
    }

    private HttpMethod createProxyRequest(String targetUrl, HttpServletRequest request) throws IOException {
        URI targetUri;
        try {
            targetUri = new URI(uriEncode(targetUrl));
        } catch (URISyntaxException e) {
            throw new RuntimeException(e);
        }

        HttpMethod commonsHttpMethod = httpMethodProvider.getMethod(request.getMethod(), targetUri.toString());

        commonsHttpMethod.setFollowRedirects(false);

        Enumeration<String> headerNames = request.getHeaderNames();
        while (headerNames.hasMoreElements()) {
            String headerName = headerNames.nextElement();
            Enumeration<String> headerVals = request.getHeaders(headerName);
            while (headerVals.hasMoreElements()) {
                String headerValue = headerVals.nextElement();
                headerValue = headerFilter.processRequestHeader(headerName, headerValue);
                if (headerValue != null) {
                    commonsHttpMethod.addRequestHeader(new Header(headerName, headerValue));
                }

            }
        }

        return commonsHttpMethod;
    }

    void copyProxyReponse(HttpMethod proxyResponse, HttpServletResponse response) throws IOException {
        copyProxyHeaders(proxyResponse.getResponseHeaders(), response);
        response.setContentLength(getResponseContentLength(proxyResponse));
        copy(proxyResponse.getResponseBodyAsStream(), response.getOutputStream());
        if (proxyResponse.getStatusLine() != null) {
            int statCode = proxyResponse.getStatusCode();
            response.setStatus(statCode);
        }
    }

    public int getResponseContentLength(HttpMethod httpMethod) {
        Header[] headers = httpMethod.getResponseHeaders("Content-Length");
        if (headers.length == 0) {
            return -1;
        }

        for (int i = headers.length - 1; i >= 0; i--) {
            Header header = headers[i];
            try {
                return Integer.parseInt(header.getValue());
            } catch (NumberFormatException e) {

            }
            // See if we can have better luck with another header, if present
        }
        return -1;
    }

    private void copyProxyHeaders(Header[] headers, HttpServletResponse response) {
        for (Header h : headers) {
            String header = h.getName();
            String valR = headerFilter.processResponseHeader(header, h.getValue());
            if (valR != null) {
                response.addHeader(header, valR);
            }
        }
    }

    private static int RESPONSE_BUFFER_SIZE = 10 * 1024;

    private void copy(InputStream inputStream, OutputStream outputStream) throws IOException {
        if (inputStream == null) {
            return;
        }
        byte[] buffer = new byte[RESPONSE_BUFFER_SIZE];
        int numRead;
        while ((numRead = inputStream.read(buffer)) > 0) {
            outputStream.write(buffer, 0, numRead);
        }

    }

    public void setHttpClient(HttpClient client) {
        this.httpClient = client;
    }

    public void setHttpMethodProvider(HttpMethodProvider httpMethodProvider) {
        this.httpMethodProvider = httpMethodProvider;
    }

}