// Path: core/src/main/java/io/groundhog/base/URIScheme.java
// @Immutable
// public enum URIScheme {
//   HTTP("http", 80),
//   HTTPS("https", 443);
// 
//   private final String scheme;
//   private final int defaultPort;
// 
//   private URIScheme(String scheme, int defaultPort) {
//     this.scheme = scheme;
//     this.defaultPort = defaultPort;
//   }
// 
//   public String scheme() {
//     return scheme;
//   }
// 
//   public int defaultPort() {
//     return defaultPort;
//   }
// 
//   public static URIScheme fromPort(int port) {
//     Optional<URIScheme> uriScheme = fromPortInternal(port);
//     checkArgument(uriScheme.isPresent(), "No matching protocol scheme for port " + port);
//     return uriScheme.get();
//   }
// 
//   public static URIScheme fromPortOrDefault(int port, URIScheme defaultScheme) {
//     return fromPortInternal(port).or(defaultScheme);
//   }
// 
//   private static Optional<URIScheme> fromPortInternal(int port) {
//     checkArgument(port > 0, "port must be greater than zero");
//     for (URIScheme scheme : values()) {
//       if (scheme.defaultPort() == port) {
//         return Optional.of(scheme);
//       }
//     }
//     return Optional.absent();
//   }
// }
// 
// Path: core/src/main/java/io/groundhog/capture/CaptureWriter.java
// public interface CaptureWriter extends Service {
//   /**
//    * Write a request asynchronously.
//    *
//    * @param captureRequest the captured request to be written
//    */
//   public void writeAsync(CaptureRequest captureRequest);
// 
//   /**
//    * Write a file upload. The write operation may block.
//    *
//    * @param fileUpload the {@link io.netty.handler.codec.http.multipart.FileUpload}
//    * @param startedDateTime the time in milliseconds of the request that this upload is for
//    */
//   public void writeUpload(FileUpload fileUpload, long startedDateTime) throws IOException;
// }


import io.groundhog.base.URIScheme;
import io.groundhog.capture.CaptureWriter;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Optional;
import com.google.common.net.HostAndPort;
import com.google.common.util.concurrent.AbstractIdleService;
import com.google.inject.Inject;
import com.google.inject.name.Named;
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.codec.http.HttpObject;
import io.netty.handler.codec.http.HttpRequest;
import org.littleshoot.proxy.*;
import org.littleshoot.proxy.extras.SelfSignedSslEngineSource;
import org.littleshoot.proxy.impl.DefaultHttpProxyServer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.net.ssl.SSLEngine;
import java.net.InetSocketAddress;
import java.util.Queue;
import static com.google.common.base.Preconditions.checkNotNull;
/*
 * Copyright 2013-2014 the original author or authors.
 *
 * 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
 *
 *   whttp://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 io.groundhog.proxy;





/**
 * A capturing proxy server.
 *
 * @author Danny Thomas
 * @since 1.0
 */
public final class ProxyServer extends AbstractIdleService {
  private static final Logger LOG = LoggerFactory.getLogger(ProxyServer.class);

  private final CaptureWriter captureWriter;
  private final CaptureFilterSourceFactory filterSourceFactory;
  private final HostAndPort listenHttp;
  private final Optional<HostAndPort> listenHttps;
  private final HostAndPort targetHttp;
  private final Optional<HostAndPort> targetHttps;

  @Inject
// Path: core/src/main/java/io/groundhog/base/URIScheme.java
// @Immutable
// public enum URIScheme {
//   HTTP("http", 80),
//   HTTPS("https", 443);
// 
//   private final String scheme;
//   private final int defaultPort;
// 
//   private URIScheme(String scheme, int defaultPort) {
//     this.scheme = scheme;
//     this.defaultPort = defaultPort;
//   }
// 
//   public String scheme() {
//     return scheme;
//   }
// 
//   public int defaultPort() {
//     return defaultPort;
//   }
// 
//   public static URIScheme fromPort(int port) {
//     Optional<URIScheme> uriScheme = fromPortInternal(port);
//     checkArgument(uriScheme.isPresent(), "No matching protocol scheme for port " + port);
//     return uriScheme.get();
//   }
// 
//   public static URIScheme fromPortOrDefault(int port, URIScheme defaultScheme) {
//     return fromPortInternal(port).or(defaultScheme);
//   }
// 
//   private static Optional<URIScheme> fromPortInternal(int port) {
//     checkArgument(port > 0, "port must be greater than zero");
//     for (URIScheme scheme : values()) {
//       if (scheme.defaultPort() == port) {
//         return Optional.of(scheme);
//       }
//     }
//     return Optional.absent();
//   }
// }
// 
// Path: core/src/main/java/io/groundhog/capture/CaptureWriter.java
// public interface CaptureWriter extends Service {
//   /**
//    * Write a request asynchronously.
//    *
//    * @param captureRequest the captured request to be written
//    */
//   public void writeAsync(CaptureRequest captureRequest);
// 
//   /**
//    * Write a file upload. The write operation may block.
//    *
//    * @param fileUpload the {@link io.netty.handler.codec.http.multipart.FileUpload}
//    * @param startedDateTime the time in milliseconds of the request that this upload is for
//    */
//   public void writeUpload(FileUpload fileUpload, long startedDateTime) throws IOException;
// }


// Path: proxy/src/main/java/io/groundhog/proxy/ProxyServer.java
import io.groundhog.base.URIScheme;
import io.groundhog.capture.CaptureWriter;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Optional;
import com.google.common.net.HostAndPort;
import com.google.common.util.concurrent.AbstractIdleService;
import com.google.inject.Inject;
import com.google.inject.name.Named;
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.codec.http.HttpObject;
import io.netty.handler.codec.http.HttpRequest;
import org.littleshoot.proxy.*;
import org.littleshoot.proxy.extras.SelfSignedSslEngineSource;
import org.littleshoot.proxy.impl.DefaultHttpProxyServer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.net.ssl.SSLEngine;
import java.net.InetSocketAddress;
import java.util.Queue;
import static com.google.common.base.Preconditions.checkNotNull;

/*
 * Copyright 2013-2014 the original author or authors.
 *
 * 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
 *
 *   whttp://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 io.groundhog.proxy;





/**
 * A capturing proxy server.
 *
 * @author Danny Thomas
 * @since 1.0
 */
public final class ProxyServer extends AbstractIdleService {
  private static final Logger LOG = LoggerFactory.getLogger(ProxyServer.class);

  private final CaptureWriter captureWriter;
  private final CaptureFilterSourceFactory filterSourceFactory;
  private final HostAndPort listenHttp;
  private final Optional<HostAndPort> listenHttps;
  private final HostAndPort targetHttp;
  private final Optional<HostAndPort> targetHttps;

  @Inject
  ProxyServer(CaptureWriter captureWriter,