Package com.subgraph.vega.internal.http.proxy

Source Code of com.subgraph.vega.internal.http.proxy.ProxyRequestHandler

/*******************************************************************************
* 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.URI;
import java.net.URISyntaxException;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.apache.http.HttpEntity;
import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.HttpException;
import org.apache.http.HttpHost;
import org.apache.http.HttpMessage;
import org.apache.http.HttpRequest;
import org.apache.http.HttpResponse;
import org.apache.http.ProtocolException;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.client.utils.URIUtils;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.message.BasicHttpResponse;
import org.apache.http.protocol.HTTP;
import org.apache.http.protocol.HttpContext;
import org.apache.http.protocol.HttpRequestHandler;
import org.apache.http.util.EntityUtils;

import com.subgraph.vega.api.http.requests.IHttpRequestEngine;
import com.subgraph.vega.api.http.requests.IHttpRequestTask;
import com.subgraph.vega.api.http.requests.IHttpResponse;
import com.subgraph.vega.api.http.requests.RequestEngineException;
import com.subgraph.vega.http.requests.custom.VegaHttpEntityEnclosingUriRequest;
import com.subgraph.vega.http.requests.custom.VegaHttpUriRequest;

public class ProxyRequestHandler implements HttpRequestHandler {

  /**
   * Hop-by-hop headers to be removed by this proxy.
   */
  private final static String[] HOP_BY_HOP_HEADERS = {
    // Hop-by-hop headers specified in RFC2616 section 13.5.1.
    HTTP.CONN_DIRECTIVE, // "Connection"
    HTTP.CONN_KEEP_ALIVE, // "Keep-Alive"
    "Proxy-Authenticate",
    "Proxy-Authorization",
    "TE",
    "Trailers",
    HTTP.TRANSFER_ENCODING, // "Transfer-Encoding"
    "Upgrade",

    // Not part of the RFC but should not be forwarded; see http://homepage.ntlworld.com/jonathan.deboynepollard/FGA/web-proxy-connection-header.html
    "Proxy-Connection",
  };

  private final Logger logger;
  private final HttpProxyListener httpProxy;
  private final IHttpRequestEngine requestEngine;

  ProxyRequestHandler(HttpProxyListener httpProxy, Logger logger, IHttpRequestEngine requestEngine) {
    this.httpProxy = httpProxy;
    this.logger = logger;
    this.requestEngine = requestEngine;
  }

  @Override
  public void handle(HttpRequest request, HttpResponse response, HttpContext context) throws HttpException, IOException {
    final ProxyTransaction transaction = new ProxyTransaction(requestEngine, context);
    context.setAttribute(HttpProxyListener.PROXY_HTTP_TRANSACTION, transaction);

    try {
      if (handleRequest(transaction, request) == false) {
        response.setStatusCode(503);
        transaction.signalComplete(false);
        return;
      }

      final HttpUriRequest uriRequest = transaction.getRequest();
      final IHttpRequestTask requestTask = requestEngine.sendRequest(uriRequest);
      transaction.setRequestTask(requestTask);
      transaction.signalForward();
      IHttpResponse r = null;
      try {
        r = requestTask.get(false);
      } finally {
        transaction.setRequestTask(null);
      }
      if(r == null) {
        response.setStatusCode(503);
        transaction.signalComplete(false);
        return;
      }

      if (handleResponse(transaction, r) == false) {
        response.setStatusCode(503);
        transaction.signalComplete(true);
        return;
      }
     
      HttpResponse httpResponse = copyResponse(r.getRawResponse());
      removeHeaders(httpResponse);
      response.setStatusLine(httpResponse.getStatusLine());
      response.setHeaders(httpResponse.getAllHeaders());
      response.setEntity(httpResponse.getEntity());
      transaction.signalForward();
    } catch (InterruptedException e) {
      logger.log(Level.WARNING, "Error processing request: " + e.getMessage(), e);
      response.setStatusCode(503);
    } catch (RequestEngineException e) {
      logger.log(Level.WARNING, "Error processing request: " + e.getMessage());
      response.setStatusCode(502);
    } catch (ProtocolException e) {
      logger.log(Level.WARNING, "Error processing request: " + e.getMessage(), e);
      response.setStatusCode(400);
    } catch (Exception e) {
      logger.log(Level.WARNING, "Error processing request: " + e.getMessage(), e);
      response.setStatusCode(500);
    } finally {
      transaction.signalComplete(false);
    }
  }

  private HttpEntity copyEntity(HttpEntity entity) {
    try {
      if(entity == null) {
        return null;
      }
      final ByteArrayEntity newEntity = new ByteArrayEntity(EntityUtils.toByteArray(entity));
      newEntity.setContentEncoding(entity.getContentEncoding());
      newEntity.setContentType(entity.getContentType());
      return newEntity;
    } catch (IOException e) {
      return null;
    }
  }

  private HttpUriRequest copyToUriRequest(HttpRequest request) throws ProtocolException {
    URI uri;
    final String hostStr = removePath(request.getRequestLine().getUri());
    try {
      uri = new URI(hostStr);
    } catch (URISyntaxException e) {
        throw new ProtocolException("Invalid URI: " + hostStr, e);
    }
    // ensuring we have scheme and host also prevents the proxy from connecting back to itself
    if (uri.getScheme() == null) {
      throw new ProtocolException("No scheme in proxy request URI");
    }
    if (uri.getHost() == null) {
      throw new ProtocolException("No host in proxy request URI");
    }
   
    final HttpHost host = URIUtils.extractHost(uri);
    final HttpUriRequest uriRequest = createRequestCopy(host, request);
    uriRequest.setParams(request.getParams());
    uriRequest.setHeaders(request.getAllHeaders());
    return uriRequest;
  }
 
  private String removeSchemeAndHost(String line) {
    final int idx = findPathStart(line);
    if(idx == -1) {
      return "";
    } else {
      return line.substring(idx);
    }
  }
 
  private String removePath(String line) {
    final int idx = findPathStart(line);
    if(idx == -1) {
      return line;
    } else {
      return line.substring(0, idx);
    }
  }
 
 
  private int findPathStart(String line) {
    int idx = line.indexOf("://");
    if(idx == -1 || ((idx + 3) >= line.length())) {
      return 0;
    } else {
      idx += 3;
    }
    while(line.charAt(idx) == '/') idx++;
    return line.indexOf('/', idx);
  }

  private HttpUriRequest createRequestCopy(HttpHost host, HttpRequest request) {
    final String method = request.getRequestLine().getMethod();
    final String uriLine = removeSchemeAndHost(request.getRequestLine().getUri());
    if(request instanceof HttpEntityEnclosingRequest) {
      final VegaHttpEntityEnclosingUriRequest r = new VegaHttpEntityEnclosingUriRequest(host, method, uriLine);
      r.setEntity(copyEntity(((HttpEntityEnclosingRequest) request).getEntity()));
      return r;
    }
    return new VegaHttpUriRequest(host, method, uriLine);
  }
 
  private HttpResponse copyResponse(HttpResponse originalResponse) {
    HttpResponse r = new BasicHttpResponse(originalResponse.getStatusLine());
    r.setHeaders(originalResponse.getAllHeaders());
    r.setEntity(originalResponse.getEntity());
    return r;
  }

  private void removeHeaders(HttpMessage message) {
    for(String hdr: HOP_BY_HOP_HEADERS) {
      message.removeHeaders(hdr);
    }
  }

  private boolean handleRequest(ProxyTransaction transaction, HttpRequest request) throws InterruptedException, ProtocolException {
    removeHeaders(request);
    transaction.setRequest(copyToUriRequest(request));
    if (httpProxy.handleTransaction(transaction) == true) {
      return transaction.getForward();
    } else {
      return true;
    }
  }

  private boolean handleResponse(ProxyTransaction transaction, IHttpResponse response) throws InterruptedException {
    transaction.setResponse(response);
    if (httpProxy.handleTransaction(transaction) == true) {
      return transaction.getForward();
    } else {
      return true;
    }
  }
}
TOP

Related Classes of com.subgraph.vega.internal.http.proxy.ProxyRequestHandler

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.