/** * Retrieves the raw (unescaped) path + query string from the specified request. The returned path will not include * the scheme, host, or port. * * @param httpRequest HTTP request * @return the unescaped path + query string from the HTTP request * @throws URISyntaxException if the path could not be parsed (due to invalid characters in the URI, etc.) */ public static String getRawPathAndParamsFromRequest(HttpRequest httpRequest) throws URISyntaxException { // if this request's URI contains a full URI (including scheme, host, etc.), strip away the non-path components if (HttpUtil.startsWithHttpOrHttps(httpRequest.getUri())) { return getRawPathAndParamsFromUri(httpRequest.getUri()); } else { // to provide consistent validation behavior for URIs that contain a scheme and those that don't, attempt to parse // the URI, even though we discard the parsed URI object new URI(httpRequest.getUri()); return httpRequest.getUri(); } }
protected void decompressContents() { if (contentEncoding.equalsIgnoreCase(HttpHeaders.Values.GZIP) || contentEncoding.equalsIgnoreCase(HttpHeaders.Values.DEFLATE)) { try { fullResponseContents = BrowserMobHttpUtil.decompressContents(getRawResponseContents(),contentEncoding); decompressionSuccessful = true; } catch (RuntimeException e) { log.warn("Failed to decompress response with encoding type " + contentEncoding + " when decoding request from " + originalRequest.getUri(), e); } } else{ log.warn("Cannot decode unsupported content encoding type {}", contentEncoding); } }
/** * Identify the host of an HTTP request. This method uses the URI of the request if possible, otherwise it attempts to find the host * in the request headers. * * @param httpRequest HTTP request to parse the host from * @return the host the request is connecting to, or null if no host can be found */ public static String getHostFromRequest(HttpRequest httpRequest) { // try to use the URI from the request first, if the URI starts with http:// or https://. checking for http/https avoids confusing // java's URI class when the request is for a malformed URL like '//some-resource'. String host = null; if (startsWithHttpOrHttps(httpRequest.getUri())) { try { URI uri = new URI(httpRequest.getUri()); host = uri.getHost(); } catch (URISyntaxException e) { } } // 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; }
@Override protected void channelRead0(ChannelHandlerContext ctx, HttpRequest msg) throws Exception { CommandContext commandContext = HttpCommandDecoder.decode(msg); // return 404 when fail to construct command context if (commandContext == null) { log.warn("can not found commandContext url: " + msg.getUri()); FullHttpResponse response = http404(); ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE); } else { commandContext.setRemote(ctx.channel()); try { String result = commandExecutor.execute(commandContext); FullHttpResponse response = http200(result); ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE); } catch (NoSuchCommandException ex) { log.error("can not find commandContext: " + commandContext, ex); FullHttpResponse response = http404(); ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE); } catch (Exception qosEx) { log.error("execute commandContext: " + commandContext + " got exception", qosEx); FullHttpResponse response = http500(qosEx.getMessage()); ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE); } } }
@Override protected void channelRead0(ChannelHandlerContext ctx, HttpRequest msg) throws Exception { CommandContext commandContext = HttpCommandDecoder.decode(msg); // return 404 when fail to construct command context if (commandContext == null) { log.warn("can not found commandContext url: " + msg.getUri()); FullHttpResponse response = http404(); ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE); } else { commandContext.setRemote(ctx.channel()); try { String result = commandExecutor.execute(commandContext); FullHttpResponse response = http200(result); ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE); } catch (NoSuchCommandException ex) { log.error("can not find commandContext: " + commandContext, ex); FullHttpResponse response = http404(); ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE); } catch (Exception qosEx) { log.error("execute commandContext: " + commandContext + " got exception", qosEx); FullHttpResponse response = http500(qosEx.getMessage()); ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE); } } }
/** * Gets the host and port from the specified request. Returns the host and port from the request URI if available, * otherwise retrieves the host and port from the Host header. * * @param httpRequest HTTP request * @return host and port of the request */ public static String getHostAndPortFromRequest(HttpRequest httpRequest) { if (startsWithHttpOrHttps(httpRequest.getUri())) { try { return getHostAndPortFromUri(httpRequest.getUri()); } catch (URISyntaxException e) { // the URI could not be parsed, so return the host and port in the Host header } } return parseHostHeader(httpRequest, true); }
protected void captureQueryParameters(HttpRequest httpRequest) { // capture query parameters. it is safe to assume the query string is UTF-8, since it "should" be in US-ASCII (a subset of UTF-8), // but sometimes does include UTF-8 characters. QueryStringDecoder queryStringDecoder = new QueryStringDecoder(httpRequest.getUri(), StandardCharsets.UTF_8); try { for (Map.Entry<String, List<String>> entry : queryStringDecoder.parameters().entrySet()) { for (String value : entry.getValue()) { harEntry.getRequest().getQueryString().add(new HarNameValuePair(entry.getKey(), value)); } } } catch (IllegalArgumentException e) { // QueryStringDecoder will throw an IllegalArgumentException if it cannot interpret a query string. rather than cause the entire request to // fail by propagating the exception, simply skip the query parameter capture. harEntry.setComment("Unable to decode query parameters on URI: " + httpRequest.getUri()); log.info("Unable to decode query parameters on URI: " + httpRequest.getUri(), e); } }
String hostNoDefaultPort = BrowserMobHttpUtil.removeMatchingPort(modifiedRequest.getUri(), 443); return "https://" + hostNoDefaultPort; if (HttpUtil.startsWithHttpOrHttps(modifiedRequest.getUri())) { return modifiedRequest.getUri(); String path = modifiedRequest.getUri(); String url; if (isHttps()) {
/** * Populates the serverIpAddress field of the harEntry using the internal hostname->IP address cache. * * @param httpRequest HTTP request to take the hostname from */ protected void populateAddressFromCache(HttpRequest httpRequest) { String serverHost = getHost(httpRequest); if (serverHost != null && !serverHost.isEmpty()) { String resolvedAddress = ResolvedHostnameCacheFilter.getPreviouslyResolvedAddressForHost(serverHost); if (resolvedAddress != null) { harEntry.setServerIPAddress(resolvedAddress); } else { // the resolvedAddress may be null if the ResolvedHostnameCacheFilter has expired the entry (which is unlikely), // or in the far more common case that the proxy is using a chained proxy to connect to connect to the // remote host. since the chained proxy handles IP address resolution, the IP address in the HAR must be blank. log.trace("Unable to find cached IP address for host: {}. IP address in HAR entry will be blank.", serverHost); } } else { log.warn("Unable to identify host from request uri: {}", httpRequest.getUri()); } }
private void populateServerIpAddress(HarEntry harEntry) { // populate the server IP address if it was resolved as part of this request. otherwise, populate the IP address from the cache. if (resolvedAddress != null) { harEntry.setServerIPAddress(resolvedAddress.getHostAddress()); } else { String serverHost = HttpUtil.getHostFromRequest(modifiedHttpRequest); if (serverHost != null && !serverHost.isEmpty()) { String resolvedAddress = ResolvedHostnameCacheFilter.getPreviouslyResolvedAddressForHost(serverHost); if (resolvedAddress != null) { harEntry.setServerIPAddress(resolvedAddress); } else { // the resolvedAddress may be null if the ResolvedHostnameCacheFilter has expired the entry (which is unlikely), // or in the far more common case that the proxy is using a chained proxy to connect to connect to the // remote host. since the chained proxy handles IP address resolution, the IP address in the HAR must be blank. log.trace("Unable to find cached IP address for host: {}. IP address in HAR entry will be blank.", serverHost); } } else { log.warn("Unable to identify host from request uri: {}", modifiedHttpRequest.getUri()); } } }
public static CommandContext decode(HttpRequest request) { CommandContext commandContext = null; if (request != null) { QueryStringDecoder queryStringDecoder = new QueryStringDecoder(request.getUri()); String path = queryStringDecoder.path(); String[] array = path.split("/");
public static CommandContext decode(HttpRequest request) { CommandContext commandContext = null; if (request != null) { QueryStringDecoder queryStringDecoder = new QueryStringDecoder(request.getUri()); String path = queryStringDecoder.path(); String[] array = path.split("/");
public HttpsOriginalHostCaptureFilter(HttpRequest originalRequest, ChannelHandlerContext ctx) { super(originalRequest, ctx); // if this is an HTTP CONNECT, set the isHttps attribute on the ChannelHandlerConect and capture the hostname from the original request. // capturing the original host (and the remapped/modified host in clientToProxyRequest() below) guarantees that we will // have the "true" host, rather than relying on the Host header in subsequent requests (which may be absent or spoofed by malicious clients). if (ProxyUtils.isCONNECT(originalRequest)) { Attribute<String> originalHostAttr = ctx.attr(AttributeKey.<String>valueOf(HttpsAwareFiltersAdapter.ORIGINAL_HOST_ATTRIBUTE_NAME)); String hostAndPort = originalRequest.getUri(); originalHostAttr.set(hostAndPort); Attribute<Boolean> isHttpsAttr = ctx.attr(AttributeKey.<Boolean>valueOf(HttpsAwareFiltersAdapter.IS_HTTPS_ATTRIBUTE_NAME)); isHttpsAttr.set(true); } } }
@Override public HttpResponse clientToProxyRequest(HttpObject httpObject) { if (httpObject instanceof HttpRequest) { HttpRequest httpRequest = (HttpRequest) httpObject; if (ProxyUtils.isCONNECT(httpRequest)) { Attribute<String> hostname = ctx.attr(AttributeKey.<String>valueOf(HttpsAwareFiltersAdapter.HOST_ATTRIBUTE_NAME)); String hostAndPort = httpRequest.getUri(); // CONNECT requests contain the port, even when using the default port. a sensible default is to remove the // default port, since in most cases it is not explicitly specified and its presence (in a HAR file, for example) // would be unexpected. String hostNoDefaultPort = BrowserMobHttpUtil.removeMatchingPort(hostAndPort, 443); hostname.set(hostNoDefaultPort); } } return null; } }
protected void captureRequestHeaderSize(HttpRequest httpRequest) { String requestLine = httpRequest.getMethod().toString() + ' ' + httpRequest.getUri() + ' ' + httpRequest.getProtocolVersion().toString(); // +2 => CRLF after status line, +4 => header/data separation long requestHeadersSize = requestLine.length() + 6; HttpHeaders headers = httpRequest.headers(); requestHeadersSize += BrowserMobHttpUtil.getHeaderSize(headers); harEntry.getRequest().setHeadersSize(requestHeadersSize); }
sessionUuidAttr.get().toString(), httpRequest.headers().toString()); if (httpRequest.getMethod().equals(HttpMethod.POST)) { String uri = httpRequest.getUri(); AbstractCommand cp = (AbstractCommand) commandFactory.getCommandProcessor(uri); cp.setSessionUuid(sessionUuidAttr.get());
@Override public HttpResponse clientToProxyRequest(HttpObject httpObject) { if (proxyServer.isStopped()) { log.warn("Aborting request to {} because proxy is stopped", originalRequest.getUri()); HttpResponse abortedResponse = new DefaultFullHttpResponse(originalRequest.getProtocolVersion(), HttpResponseStatus.SERVICE_UNAVAILABLE); HttpHeaders.setContentLength(abortedResponse, 0L); return abortedResponse; } for (HttpFilters filter : filters) { try { HttpResponse filterResponse = filter.clientToProxyRequest(httpObject); if (filterResponse != null) { // if we are short-circuiting the response to an HttpRequest, update ModifiedRequestAwareFilter instances // with this (possibly) modified HttpRequest before returning the short-circuit response if (httpObject instanceof HttpRequest) { updateFiltersWithModifiedResponse((HttpRequest) httpObject); } return filterResponse; } } catch (RuntimeException e) { log.warn("Filter in filter chain threw exception. Filter method may have been aborted.", e); } } // if this httpObject is the HTTP request, set the modified request object on all ModifiedRequestAwareFilter // instances, so they have access to all modifications the request filters made while filtering if (httpObject instanceof HttpRequest) { updateFiltersWithModifiedResponse((HttpRequest) httpObject); } return null; }
log.warn("No content type specified in request to {}. Content will be treated as {}", httpRequest.getUri(), BrowserMobHttpUtil.UNKNOWN_CONTENT_TYPE); contentType = BrowserMobHttpUtil.UNKNOWN_CONTENT_TYPE; charset = BrowserMobHttpUtil.readCharsetInContentTypeHeader(contentType); } catch (UnsupportedCharsetException e) { log.warn("Found unsupported character set in Content-Type header '{}' in HTTP request to {}. Content will not be captured in HAR.", contentType, httpRequest.getUri(), e); return; log.debug("No charset specified; using charset {} to decode contents to {}", charset, httpRequest.getUri());
log.warn("No content type specified in response from {}. Content will be treated as {}", originalRequest.getUri(), BrowserMobHttpUtil.UNKNOWN_CONTENT_TYPE); contentType = BrowserMobHttpUtil.UNKNOWN_CONTENT_TYPE; charset = BrowserMobHttpUtil.readCharsetInContentTypeHeader(contentType); } catch (UnsupportedCharsetException e) { log.warn("Found unsupported character set in Content-Type header '{}' in HTTP response from {}. Content will not be captured in HAR.", contentType, originalRequest.getUri(), e); return; log.debug("No charset specified; using charset {} to decode contents from {}", charset, originalRequest.getUri());
String uriFromRequest = httpRequest.getUri(); if (HttpUtil.startsWithHttpOrHttps(uriFromRequest)) { httpRequest.setUri(rewrittenUrl);