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

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

/*******************************************************************************
* 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.Socket;

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLHandshakeException;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;

import org.apache.http.ConnectionReuseStrategy;
import org.apache.http.HttpEntity;
import org.apache.http.HttpException;
import org.apache.http.HttpHost;
import org.apache.http.HttpRequest;
import org.apache.http.HttpResponse;
import org.apache.http.HttpResponseFactory;
import org.apache.http.HttpStatus;
import org.apache.http.ProtocolVersion;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.params.HttpParams;
import org.apache.http.protocol.HttpContext;
import org.apache.http.protocol.HttpProcessor;
import org.apache.http.protocol.HttpRequestHandlerResolver;
import org.apache.http.protocol.HttpService;
import org.apache.http.util.EncodingUtils;

import com.subgraph.vega.internal.http.proxy.ssl.SSLContextRepository;

/**
* Specialized HttpService which handles SSL connections.
*/
public class VegaHttpService {
  private final static int DEFAULT_SSL_PORT = 443;

  private final HttpResponseFactory responseFactory;
  private final HttpProcessor processor;
  private final HttpService delegatedHttpService;
  private final SSLContextRepository sslContextRepository;
  private final boolean sslEnabled;

  public VegaHttpService(HttpProcessor proc, ConnectionReuseStrategy connStrategy, HttpResponseFactory responseFactory, HttpRequestHandlerResolver handlerResolver, HttpParams params, SSLContextRepository sslContextRepository) {
    this.delegatedHttpService = new HttpService(proc, connStrategy, responseFactory, handlerResolver, params);
    this.sslContextRepository = sslContextRepository;
    this.sslEnabled = (sslContextRepository != null);
    this.responseFactory = responseFactory;
    this.processor = proc;
  }

  public void handleRequest(final VegaHttpServerConnection conn, final HttpContext context) throws IOException, HttpException {
    if(!sslEnabled) {
      delegatedHttpService.handleRequest(conn, context);
      return;
    }

    final HttpRequest peekRequest = conn.peekRequestHeader();

    if(isCertificateDownload(peekRequest)) {
      conn.dropCachedPeekRequest();
      sendCertificateDownloadResponse(conn, context);
    } else if(isConnectMethodRequest(peekRequest)) {
      conn.dropCachedPeekRequest();
      handleConnect(conn, peekRequest, context);
    } else {
      delegatedHttpService.handleRequest(conn, context);
    }
  }

  private void handleConnect(VegaHttpServerConnection conn, HttpRequest request, HttpContext context) throws IOException, HttpException {
    final HttpHost host = createHostForConnectUri(request.getRequestLine().getUri());
    final SSLSocket sslSocket = createSSLSocketForHost(host, conn.getSocket());

    sendResponseOk(conn, context);
    conn.rebindWithSSL(sslSocket, host);

    try {
      sslSocket.startHandshake();
    } catch (SSLHandshakeException e) {
      conn.close();
      return;
    }
    delegatedHttpService.handleRequest(conn, context);
  }

  private HttpHost createHostForConnectUri(String uri) {
    final String[] parts = uri.split(":");
    final String hostname = parts[0].toLowerCase();
    final int port = (parts.length < 2) ? (DEFAULT_SSL_PORT) : (stringToSSLPort(parts[1]));
    return new HttpHost(hostname, port, "https");
  }

  private int stringToSSLPort(String s) {
    if(s == null || s.isEmpty())
      return DEFAULT_SSL_PORT;
    try {
      return Integer.parseInt(s);
    } catch (NumberFormatException e) {
      return DEFAULT_SSL_PORT;
    }
  }

  private void sendCertificateDownloadResponse(VegaHttpServerConnection connection, HttpContext context) throws HttpException, IOException {
    final String pem = sslContextRepository.getCaCertificatePem();
    final byte[] body = EncodingUtils.getAsciiBytes(pem);
    ByteArrayEntity entity = new ByteArrayEntity(body);
    entity.setContentType("application/x-x509-ca-cert; charset=US-ASCII");
    sendResponseOk(connection, context, entity);
  }

  private void sendResponseOk(VegaHttpServerConnection connection, HttpContext context) throws HttpException, IOException {
    sendResponseOk(connection, context, null);
  }

  private void sendResponseOk(VegaHttpServerConnection connection, HttpContext context, HttpEntity entity) throws HttpException, IOException {
    final ProtocolVersion version = new ProtocolVersion("HTTP", 1, 0);
    final HttpResponse response = responseFactory.newHttpResponse(version, HttpStatus.SC_OK, context);
    if(entity != null)
      response.setEntity(entity);
    processor.process(response, context);
    connection.sendResponseHeader(response);
    connection.sendResponseEntity(response);
    connection.flush();
  }

  private SSLSocket createSSLSocketForHost(HttpHost host, Socket socket) throws IOException {
    final SSLContext ctx = sslContextRepository.getContextForName(host.getHostName());
    if(ctx == null) {
      throw new IOException("Failed to create SSLContext for host "+ host.getHostName());
    }
    SSLSocketFactory sslSocketFactory = ctx.getSocketFactory();
    SSLSocket sslSocket = (SSLSocket) sslSocketFactory.createSocket(socket, host.getHostName(), host.getPort(), true);
    sslSocket.setUseClientMode(false);
    return sslSocket;
  }

  private boolean isConnectMethodRequest(HttpRequest request) {
    final String method = request.getRequestLine().getMethod();
    return (method != null && method.equalsIgnoreCase("CONNECT"));
  }

  private boolean isCertificateDownload(HttpRequest request) {
    return request.getRequestLine().getUri().toLowerCase().equals("http://vega/ca.crt");
  }
}
TOP

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

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.