From e3507b7d0278786ba7b9fa93dc98aa88e1d5b2c2 Mon Sep 17 00:00:00 2001 From: Craig Andrews Date: Mon, 26 Apr 2021 17:42:42 -0400 Subject: [PATCH] Use the CONNECT method URI as host fallback When a request is made for proxy interception using the `CONNECT` method but not including a `host` header, then a `NullPointerException` is thrown in `com.browserup.bup.mitm.manager.ImpersonatingMitmManager.getHostnameImpersonatingSslContext(String, SSLSession)` because the `hostnameToImpersonate` is null. As a fallback, use the CONNECT URI as a host. --- .../java/com/browserup/bup/util/HttpUtil.java | 41 ++++++++++++++++++- 1 file changed, 39 insertions(+), 2 deletions(-) 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 e4744ffd1..4f6ac40f5 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 @@ -7,6 +7,7 @@ import com.google.common.net.HostAndPort; import io.netty.handler.codec.http.HttpHeaderNames; import io.netty.handler.codec.http.HttpHeaders; +import io.netty.handler.codec.http.HttpMethod; import io.netty.handler.codec.http.HttpRequest; import java.net.URI; @@ -42,6 +43,11 @@ public static String getHostFromRequest(HttpRequest httpRequest) { host = parseHostHeader(httpRequest, false); } + // if there was not a Host header, and the method is CONNECT, use that as the host + if (host == null || host.isEmpty()) { + host = hostFromConnect(httpRequest, false); + } + return host; } @@ -53,15 +59,26 @@ 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); + // 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, true); + } + + // if there was not Host header, and the method is CONNECT, use that as the host + if (host == null || host.isEmpty()) { + host = hostFromConnect(httpRequest, true); + } + + return host; } /** @@ -125,4 +142,24 @@ 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(); + } else { + HostAndPort parsedHostAndPort = HostAndPort.fromString(httpRequest.uri()); + return parsedHostAndPort.getHost(); + } + } else { + return null; + } + } }