diff --git a/browserup-proxy-mitm/src/main/java/com/browserup/bup/util/HttpUtil.java b/browserup-proxy-mitm/src/main/java/com/browserup/bup/util/HttpUtil.java index 55f0f2d81..e2f70bce3 100644 --- a/browserup-proxy-mitm/src/main/java/com/browserup/bup/util/HttpUtil.java +++ b/browserup-proxy-mitm/src/main/java/com/browserup/bup/util/HttpUtil.java @@ -2,6 +2,7 @@ import com.google.common.net.HostAndPort; import io.netty.handler.codec.http.HttpHeaderNames; +import io.netty.handler.codec.http.HttpMethod; import io.netty.handler.codec.http.HttpRequest; import java.net.URI; @@ -32,12 +33,7 @@ public static String getHostFromRequest(HttpRequest httpRequest) { } } - // if there was no host in the URI, attempt to grab the host from the Host header - if (host == null || host.isEmpty()) { - host = parseHostHeader(httpRequest, false); - } - - return host; + return parseHost(host, httpRequest, false); } /** @@ -48,15 +44,16 @@ public static String getHostFromRequest(HttpRequest httpRequest) { * @return host and port of the request */ public static String getHostAndPortFromRequest(HttpRequest httpRequest) { + String host = null; if (startsWithHttpOrHttps(httpRequest.uri())) { try { - return getHostAndPortFromUri(httpRequest.uri()); + host = getHostAndPortFromUri(httpRequest.uri()); } catch (URISyntaxException e) { // the URI could not be parsed, so return the host and port in the Host header } } - return parseHostHeader(httpRequest, true); + return parseHost(host, httpRequest, true); } /** @@ -97,6 +94,20 @@ public static String getHostAndPortFromUri(String uriString) throws URISyntaxExc } } + private static String parseHost(String host, HttpRequest httpRequest, boolean includePort) { + // if there was no host in the URI, attempt to grab the host from the Host header + if (isEmpty(host)) { + host = parseHostHeader(httpRequest, includePort); + } + + // if there was not a Host header, and the method is CONNECT, use that as the host + if (isEmpty(host)) { + host = hostFromConnect(httpRequest, includePort); + } + + return host; + } + /** * Retrieves the host and, optionally, the port from the specified request's Host header. * @@ -120,4 +131,26 @@ private static String parseHostHeader(HttpRequest httpRequest, boolean includePo return null; } } + + /** + * Retrieves the host and, optionally, the port from the specified request's URI if the method is CONNECT. + * + * @param httpRequest HTTP request + * @param includePort when true, include the port + * @return the host and, optionally, the port specified in the request's URI + */ + private static String hostFromConnect(HttpRequest httpRequest, boolean includePort) { + if (HttpMethod.CONNECT.equals(httpRequest.method())) { + if (includePort) { + return httpRequest.uri(); + } + HostAndPort parsedHostAndPort = HostAndPort.fromString(httpRequest.uri()); + return parsedHostAndPort.getHost(); + } + return null; + } + + private static boolean isEmpty(String str) { + return str == null || str.isEmpty(); + } } diff --git a/browserup-proxy-mitm/src/test/java/com/browserup/bup/mitm/integration/LittleProxyIntegrationTest.java b/browserup-proxy-mitm/src/test/java/com/browserup/bup/mitm/integration/LittleProxyIntegrationTest.java index 56364425b..6f466a080 100644 --- a/browserup-proxy-mitm/src/test/java/com/browserup/bup/mitm/integration/LittleProxyIntegrationTest.java +++ b/browserup-proxy-mitm/src/test/java/com/browserup/bup/mitm/integration/LittleProxyIntegrationTest.java @@ -6,6 +6,8 @@ import io.netty.handler.codec.http.HttpResponse; import com.browserup.bup.mitm.manager.ImpersonatingMitmManager; import org.apache.http.HttpHost; +import org.apache.http.HttpVersion; +import org.apache.http.ProtocolVersion; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpGet; import org.apache.http.conn.ssl.SSLConnectionSocketFactory; @@ -37,6 +39,16 @@ public class LittleProxyIntegrationTest { @Test public void testLittleProxyMitm() throws IOException, InterruptedException { + testLittleProxyMitm(null); + } + + @Test + public void testLittleProxyMitmHttp1_0() throws IOException, InterruptedException { + testLittleProxyMitm(HttpVersion.HTTP_1_0); + } + + private void testLittleProxyMitm(ProtocolVersion protocolVersion) throws IOException, InterruptedException + { final AtomicBoolean interceptedGetRequest = new AtomicBoolean(); final AtomicBoolean interceptedGetResponse = new AtomicBoolean(); @@ -79,7 +91,9 @@ public HttpObject serverToProxyResponse(HttpObject httpObject) { .start(); try (CloseableHttpClient httpClient = getNewHttpClient(proxyServer.getListenAddress().getPort())) { - try (CloseableHttpResponse response = httpClient.execute(new HttpGet("https://www.google.com"))) { + HttpGet httpGet = new HttpGet("https://www.google.com"); + httpGet.setProtocolVersion(protocolVersion); + try (CloseableHttpResponse response = httpClient.execute(httpGet)) { assertEquals("Expected to receive an HTTP 200 from http://www.google.com", 200, response.getStatusLine().getStatusCode()); EntityUtils.consume(response.getEntity());