ch.unifr.pai.twice.widgets.mpproxy.server.JettyProxy.java Source code

Java tutorial

Introduction

Here is the source code for ch.unifr.pai.twice.widgets.mpproxy.server.JettyProxy.java

Source

// ========================================================================
// $Id: ProxyServlet.java 5263 2009-06-26 09:42:21Z gregw $
// Copyright 2004-2004 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// 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 ch.unifr.pai.twice.widgets.mpproxy.server;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.InetSocketAddress;
import java.net.MalformedURLException;
import java.net.Socket;
import java.net.URL;
import java.net.URLConnection;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.zip.GZIPInputStream;

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

import org.apache.commons.io.IOUtils;

import ch.unifr.pai.twice.widgets.mpproxy.shared.Rewriter;

/**
 * Proxy Servlet.
 * <p>
 * Forward requests to another server either as a standard web proxy (as defined
 * by RFC2616) or as a transparent proxy.
 * 
 */
public class JettyProxy {

    protected HashSet<String> _DontProxyHeaders = new HashSet<String>();
    {
        _DontProxyHeaders.add("proxy-connection");
        _DontProxyHeaders.add("connection");
        _DontProxyHeaders.add("keep-alive");
        _DontProxyHeaders.add("transfer-encoding");
        _DontProxyHeaders.add("te");
        _DontProxyHeaders.add("trailer");
        _DontProxyHeaders.add("proxy-authorization");
        _DontProxyHeaders.add("proxy-authenticate");
        _DontProxyHeaders.add("upgrade");
        _DontProxyHeaders.add("content-length");
    }
    boolean c = true;

    public ProcessResult loadFromProxy(HttpServletRequest request, HttpServletResponse response, String uri,
            String servletPath, String proxyPath) throws ServletException, IOException {
        //System.out.println("LOAD "+uri); 
        //System.out.println("LOAD "+proxyPath);

        if ("CONNECT".equalsIgnoreCase(request.getMethod())) {
            handleConnect(request, response);

        } else {
            URL url = new URL(uri);

            URLConnection connection = url.openConnection();
            connection.setAllowUserInteraction(false);

            // Set method
            HttpURLConnection http = null;
            if (connection instanceof HttpURLConnection) {
                http = (HttpURLConnection) connection;
                http.setRequestMethod(request.getMethod());
                http.setInstanceFollowRedirects(false);
            }

            // check connection header
            String connectionHdr = request.getHeader("Connection");
            if (connectionHdr != null) {
                connectionHdr = connectionHdr.toLowerCase();
                if (connectionHdr.equals("keep-alive") || connectionHdr.equals("close"))
                    connectionHdr = null;
            }

            // copy headers
            boolean xForwardedFor = false;
            boolean hasContent = false;
            Enumeration enm = request.getHeaderNames();
            while (enm.hasMoreElements()) {
                // TODO could be better than this!
                String hdr = (String) enm.nextElement();
                String lhdr = hdr.toLowerCase();

                if (_DontProxyHeaders.contains(lhdr))
                    continue;
                if (connectionHdr != null && connectionHdr.indexOf(lhdr) >= 0)
                    continue;

                if ("content-type".equals(lhdr))
                    hasContent = true;

                Enumeration vals = request.getHeaders(hdr);
                while (vals.hasMoreElements()) {
                    String val = (String) vals.nextElement();
                    if (val != null) {
                        connection.addRequestProperty(hdr, val);
                        xForwardedFor |= "X-Forwarded-For".equalsIgnoreCase(hdr);
                    }
                }
            }

            // Proxy headers
            connection.setRequestProperty("Via", "1.1 (jetty)");
            if (!xForwardedFor)
                connection.addRequestProperty("X-Forwarded-For", request.getRemoteAddr());

            // a little bit of cache control
            String cache_control = request.getHeader("Cache-Control");
            if (cache_control != null
                    && (cache_control.indexOf("no-cache") >= 0 || cache_control.indexOf("no-store") >= 0))
                connection.setUseCaches(false);

            // customize Connection

            try {
                connection.setDoInput(true);

                // do input thang!
                InputStream in = request.getInputStream();
                if (hasContent) {
                    connection.setDoOutput(true);
                    IOUtils.copy(in, connection.getOutputStream());
                }

                // Connect
                connection.connect();
            } catch (Exception e) {
                e.printStackTrace();
            }

            InputStream proxy_in = null;

            // handler status codes etc.
            int code = 500;
            if (http != null) {
                proxy_in = http.getErrorStream();

                code = http.getResponseCode();
                response.setStatus(code, http.getResponseMessage());
            }

            if (proxy_in == null) {
                try {
                    proxy_in = connection.getInputStream();
                } catch (Exception e) {
                    e.printStackTrace();
                    proxy_in = http.getErrorStream();
                }
            }

            // clear response defaults.
            response.setHeader("Date", null);
            response.setHeader("Server", null);

            // set response headers
            int h = 0;
            String hdr = connection.getHeaderFieldKey(h);
            String val = connection.getHeaderField(h);
            while (hdr != null || val != null) {
                String lhdr = hdr != null ? hdr.toLowerCase() : null;
                if (hdr != null && val != null && !_DontProxyHeaders.contains(lhdr)) {
                    if (hdr.equalsIgnoreCase("Location")) {
                        val = Rewriter.translateCleanUrl(val, servletPath, proxyPath);
                    }
                    response.addHeader(hdr, val);

                }

                h++;
                hdr = connection.getHeaderFieldKey(h);
                val = connection.getHeaderField(h);

            }

            boolean isGzipped = connection.getContentEncoding() != null
                    && connection.getContentEncoding().contains("gzip");
            response.addHeader("Via", "1.1 (jetty)");
            // boolean process = connection.getContentType() == null
            // || connection.getContentType().isEmpty()
            // || connection.getContentType().contains("html");
            boolean process = connection.getContentType() != null && connection.getContentType().contains("text");
            if (proxy_in != null) {
                if (!process) {
                    IOUtils.copy(proxy_in, response.getOutputStream());
                    proxy_in.close();
                } else {
                    InputStream in;
                    if (isGzipped && proxy_in != null && proxy_in.available() > 0) {
                        in = new GZIPInputStream(proxy_in);
                    } else {
                        in = proxy_in;
                    }
                    ByteArrayOutputStream byteArrOS = new ByteArrayOutputStream();
                    IOUtils.copy(in, byteArrOS);
                    in.close();
                    if (in != proxy_in)
                        proxy_in.close();
                    String charset = response.getCharacterEncoding();
                    if (charset == null || charset.isEmpty()) {
                        charset = "ISO-8859-1";
                    }
                    String originalContent = new String(byteArrOS.toByteArray(), charset);
                    byteArrOS.close();
                    return new ProcessResult(originalContent, connection.getContentType(), charset, isGzipped);
                }
            }

        }
        return null;
    }

    /* ------------------------------------------------------------ */
    /**
     * Resolve requested URL to the Proxied URL
     * 
     * @param scheme
     *            The scheme of the received request.
     * @param serverName
     *            The server encoded in the received request(which may be from
     *            an absolute URL in the request line).
     * @param serverPort
     *            The server port of the received request (which may be from an
     *            absolute URL in the request line).
     * @param uri
     *            The URI of the received request.
     * @return The URL to which the request should be proxied.
     * @throws MalformedURLException
     */
    protected URL proxyHttpURL(String scheme, String serverName, int serverPort, String uri)
            throws MalformedURLException {
        return new URL(scheme, serverName, serverPort, uri);

    }

    /* ------------------------------------------------------------ */
    public void handleConnect(HttpServletRequest request, HttpServletResponse response) throws IOException {
        String uri = request.getRequestURI();

        String port = "";
        String host = "";

        int c = uri.indexOf(':');
        if (c >= 0) {
            port = uri.substring(c + 1);
            host = uri.substring(0, c);
            if (host.indexOf('/') > 0)
                host = host.substring(host.indexOf('/') + 1);
        }

        InetSocketAddress inetAddress = new InetSocketAddress(host, Integer.parseInt(port));

        // if
        // (isForbidden(HttpMessage.__SSL_SCHEME,addrPort.getHost(),addrPort.getPort(),false))
        // {
        // sendForbid(request,response,uri);
        // }
        // else
        {
            InputStream in = request.getInputStream();
            final OutputStream out = response.getOutputStream();

            final Socket socket = new Socket(inetAddress.getAddress(), inetAddress.getPort());

            response.setStatus(200);
            response.setHeader("Connection", "close");
            response.flushBuffer();

            //         try {
            //            Thread copy = new Thread(new Runnable() {
            //               public void run() {
            //                  try {
            IOUtils.copy(socket.getInputStream(), out);
            //                  } catch (IOException e) {
            //                     e.printStackTrace();
            //                  }
            //               }
            //            });
            //            copy.start();
            IOUtils.copy(in, socket.getOutputStream());
            //            copy.join();
            //            copy.join(10000);
            //         }
            //         catch (InterruptedException e) {
            //            e.printStackTrace();
            //         }
        }
    }

    public static class ProcessResult {
        String content;
        String contentType;
        String charset;
        boolean gzipped;

        public ProcessResult(String content, String contentType, String charset, boolean gzipped) {
            this.content = content;
            this.contentType = contentType;
            this.charset = charset;
            this.gzipped = gzipped;
        }

        public String getCharset() {
            return charset;
        }

        public String getContent() {
            return content;
        }

        public boolean isGzipped() {
            return gzipped;
        }

        public String getContentType() {
            return contentType;
        }
    }
}