// Copyright 2014 Google Inc. All Rights Reserved.
//
// 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 com.google.enterprise.adaptor;

import com.google.common.collect.ImmutableSortedSet;
import com.google.common.collect.Sets;

import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.Authenticator;
import java.net.HttpURLConnection;
import java.net.InetSocketAddress;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * An HTTP reverse proxy. This class uses HttpURLConnection internally, so the
 * default {@link Authenticator} must be {@code null} for proper operation. The
 * implementation is known to drop the response body for 401 responses to POST
 * requests.
 */
class ReverseProxyHandler implements HttpHandler {
  // The Hop-by-hop headers that are connection-local, as defined by RFC 2616
  // Section 13.5.1. As mentioned in the section, additional headers can be
  // specified in the Connection header.
  private static final Set<String> PREDEFINED_HOP_BY_HOP_HEADERS
      = ImmutableSortedSet.orderedBy(String.CASE_INSENSITIVE_ORDER).add(
          "Connection",
          "Host", // Because this is a reverse proxy.
          "Keep-Alive",
          "Proxy-Authenticate",
          "Proxy-Authorization",
          "TE",
          "Trailers",
          "Transfer-Encoding",
          "Upgrade").build();

  private static final Logger log
      = Logger.getLogger(HttpExchanges.class.getName());

  private final URI destinationBase;

  public ReverseProxyHandler(URI destinationBase) {
    if (destinationBase == null) {
      throw new NullPointerException();
    }
    this.destinationBase = destinationBase;
    if (destinationBase.getScheme() == null || destinationBase.getHost() == null
        || destinationBase.getPath() == null) {
      throw new IllegalArgumentException(
          "destinationBase must contain a scheme, host, and path");
    }
  }

  @Override
  public void handle(HttpExchange ex) throws IOException {
    URI dest = computeProxyDestination(ex);

    // Set up request
    HttpURLConnection conn = (HttpURLConnection) dest.toURL().openConnection();
    conn.setRequestMethod(ex.getRequestMethod());
    conn.setAllowUserInteraction(false);
    conn.setInstanceFollowRedirects(false);
    // This adds Cache-Control: no-cache and Pragma: no-cache if those headers
    // keys aren't already there. It is unfortunate that it modifies the
    // request, however, the presense of these headers shouldn't have an impact
    // because they are targeted to proxy servers, not the application server.
    // See RFC 2616 Section 14.9.1 and 14.32.
    conn.setUseCaches(false);
    // HttpUrlConnection will add Accept and User-Agent headers if they aren't
    // already there. Luckily they are almost always there.
    copyRequestHeaders(ex, conn);
    conn.addRequestProperty("X-Forwarded-For", getClientIp(ex));

    // As defined in RFC 2616 Section 4.3
    boolean hasRequestBody
        = ex.getRequestHeaders().containsKey("Content-Length")
        || ex.getRequestHeaders().containsKey("Transfer-Encoding");

    conn.setDoOutput(hasRequestBody);
    // Input is required for getResponseCode()
    conn.setDoInput(true);

    if (hasRequestBody) {
      String strContentLength
          = ex.getRequestHeaders().getFirst("Content-Length");
      long contentLength = -1;
      if (strContentLength != null) {
        try {
          contentLength = Long.parseLong(strContentLength);
        } catch (NumberFormatException e) {
          // Keep contentLength = -1
        }
      }
      // Enable streaming mode on the connection to prevent entire request body
      // from being buffered. Streaming mode also disables automatic
      // authentication.
      if (contentLength < 0) {
        conn.setChunkedStreamingMode(-1);
      } else {
        // TODO(ejona): remove cast once we depend on Java 7.
        conn.setFixedLengthStreamingMode((int) contentLength);
      }
    } else {
      // It is essential that no authentication happens. Unfortunately for
      // requests with no body (like GET), it seems impossible to detect if
      // authentication could be or was performed and impossible to prevent it
      // for a particular request.
      //
      // Thus, we disable authentication globally, which could easily break
      // other code's assumptions. However, the hope is that the other code will
      // begin breaking and we have a chance at discovering the incompatibility
      // between the two pieces of code, instead of silently offering content to
      // requesters that they are not authenticated for.
      Authenticator.setDefault(null);
    }

    // Actually issue the request, and copy the data back
    conn.connect();
    if (hasRequestBody) {
      try {
        IOHelper.copyStream(ex.getRequestBody(), conn.getOutputStream());
        ex.getRequestBody().close();
        conn.getOutputStream().close();
      } catch (IOException e) {
        // TODO(ejona): determine if there is a more graceful way to clean up
        conn.disconnect();
        throw e;
      }
    }

    InputStream inputStream = conn.getResponseCode() >= 400
        ? conn.getErrorStream() : conn.getInputStream();
    // InputStream is null when responseCode == 401 and doing streaming, because
    // HttpURLConnection does not consider its state "connected". Unfortunately,
    // that means that we will lose the content for 401 responses for POST.
    if (conn.getResponseCode() == 401 && inputStream == null) {
      inputStream = new ByteArrayInputStream(new byte[0]);
    }

    // As defined in RFC 2616 Section 4.3
    boolean hasResponseBody = !("HEAD".equalsIgnoreCase(ex.getRequestMethod())
        || conn.getResponseCode() / 100 == 1 // 1xx Informational
        || conn.getResponseCode() == 204 // No Content
        || conn.getResponseCode() == 304); // Not Modified

    try {
      copyResponseHeaders(conn, ex);

      if (!hasResponseBody) {
        ex.sendResponseHeaders(conn.getResponseCode(), -1);
      } else {
        int contentLength = conn.getContentLength();
        if (contentLength <= 0) {
          // If the content length was unknown (-1) or if it was zero, then we
          // are forced to use chunked transfer encoding.
          contentLength = 0;
        }
        ex.sendResponseHeaders(conn.getResponseCode(), contentLength);
        IOHelper.copyStream(inputStream, ex.getResponseBody());
      }
      // Don't close in a finally because that would be a successful response.
      // If there is an error we want the server to kill the connection, which
      // informs the client that something went wrong.
      ex.close();
    } finally {
      inputStream.close();
    }
  }

  /**
   * Compute the URI the proxy should send a request to, to proxy the provided
   * request.
   */
  private URI computeProxyDestination(HttpExchange ex) {
    URI req = HttpExchanges.getRequestUri(ex);
    final String basePath = ex.getHttpContext().getPath();
    if (!req.getPath().startsWith(basePath)) {
      throw new AssertionError();
    }
    String lastPartOfPath = req.getPath().substring(basePath.length());
    try {
      return new URI(destinationBase.getScheme(),
          destinationBase.getAuthority(),
          destinationBase.getPath() + lastPartOfPath, req.getQuery(),
          req.getFragment());
    } catch (URISyntaxException e) {
      throw new AssertionError(e);
    }
  }

  /**
   * Compute the equivalent URI to this proxy provided a possible URI pointing
   * to the destination server.
   *
   * <p>Redirects and similar require absolute URIs, so the destination server
   * is forced to expose its hostname and IP. We could pass the original
   * Host in the request (a la Apache's ProxyPreserveHost), but that is not
   * sufficent because it can't specify the path. So instead, we rewrite
   * such response headers when they match the destinationUri so they point to
   * the proxy instead of the destination (a la Apache's ProxyPassReverse).
   */
  private String computeReverseProxyDestination(HttpExchange ex,
      String location) {
    URI uri = null;
    try {
      uri = new URI(location);
    } catch (URISyntaxException e) {
      log.log(Level.INFO, "Could not parse value from header: " + location, e);
      return location;
    }
    URI base = destinationBase;
    // Check if the value starts with destinationBase. Use URI so that we
    // can correctly take case into consideration as appropriate.
    if (!(base.getScheme().equalsIgnoreCase(uri.getScheme())
        && base.getHost().equalsIgnoreCase(uri.getHost())
        && base.getPort() == uri.getPort()
        && uri.getPath() != null
        // This is correctly case-sensitive.
        && uri.getPath().startsWith(base.getPath()))) {
      return location;
    }
    String lastPartOfPath = uri.getPath().substring(base.getPath().length());
    URI requestUri = HttpExchanges.getRequestUri(ex);
    try {
      return new URI(requestUri.getScheme(), requestUri.getAuthority(),
          ex.getHttpContext().getPath() + lastPartOfPath, uri.getQuery(),
          uri.getFragment()).toASCIIString();
    } catch (URISyntaxException e) {
      throw new AssertionError(e);
    }
  }

  private void copyRequestHeaders(HttpExchange from, HttpURLConnection to) {
    Set<String> requestHopByHopHeaders
        = getHopByHopHeaders(from.getRequestHeaders().get("Connection"));
    for (Map.Entry<String, List<String>> me
        : from.getRequestHeaders().entrySet()) {
      if (requestHopByHopHeaders.contains(me.getKey())) {
        continue;
      }
      for (String value : me.getValue()) {
        to.addRequestProperty(me.getKey(), value);
      }
    }
  }

  private void copyResponseHeaders(HttpURLConnection from, HttpExchange to) {
    Set<String> responseHopByHopHeaders
        = getHopByHopHeaders(from.getHeaderFields().get("Connection"));
    // HttpURLConnection.getHeaderFields() reverses the order of repeated
    // headers' values, so we avoid it. Specifically,
    // sun.net.www.MessageHeader.filterAndAddHeaders() loops through the
    // headers in reverse order while building the map.
    for (int i = 0;; i++) {
      String key = from.getHeaderFieldKey(i);
      String value = from.getHeaderField(i);
      if (value == null) {
        break; // Reached end
      }
      if (key == null) {
        continue; // Value is the HTTP status line, which we want to skip
      }
      if (responseHopByHopHeaders.contains(key)) {
        continue;
      }
      if ("Location".equalsIgnoreCase(key)
          || "Content-Location".equalsIgnoreCase(key)
          || "URI".equalsIgnoreCase(key)) {
        value = computeReverseProxyDestination(to, value);
      }
      to.getResponseHeaders().add(key, value);
    }
  }

  private String getClientIp(HttpExchange ex) {
    InetSocketAddress clientAddr = ex.getRemoteAddress();
    if (clientAddr.isUnresolved()) {
      log.log(Level.WARNING, "Could not determine client's IP");
      return "unknown";
    }
    return clientAddr.getAddress().getHostAddress();
  }

  private Set<String> getHopByHopHeaders(List<String> connectionValues) {
    List<String> rawConnectionHeaders
        = HttpExchanges.splitHeaderValues(connectionValues);
    if (rawConnectionHeaders == null) {
      rawConnectionHeaders = Collections.emptyList();
    }
    Set<String> connectionHeaders
        = ImmutableSortedSet.orderedBy(String.CASE_INSENSITIVE_ORDER)
        .addAll(rawConnectionHeaders).build();
    return Sets.union(PREDEFINED_HOP_BY_HOP_HEADERS, connectionHeaders);
  }
}
