/** * Returns true if this message's Content-Type header indicates that it contains a textual data type. See {@link BrowserMobHttpUtil#hasTextualContent(String)}. * * @return true if the Content-Type header is a textual type, otherwise false */ public boolean isText() { return BrowserMobHttpUtil.hasTextualContent(getContentType()); } }
/** * Retrieves the binary contents of this message. This method caches the contents, so repeated calls to this method should not incur a * penalty; however, modifications to the message contents outside of this class will result in stale data returned from this method. * * @return binary contents of the entity body */ public byte[] getBinaryContents() { // avoid re-extracting the contents if this method is called repeatedly if (binaryContents == null) { binaryContents = HttpObjectUtil.extractBinaryHttpEntityBody(httpMessage); } return binaryContents; }
/** * Replaces the contents of the wrapped HttpMessage with the specified text contents, encoding them in the character set specified by the * message's Content-Type header. Note that this method does not update the Content-Type header, so if the content type will change as a * result of this call, the Content-Type header should be updated before calling this method. * * @param newContents new message contents */ public void setTextContents(String newContents) { HttpObjectUtil.replaceTextHttpEntityBody(httpMessage, newContents); // replaced the contents, so clear the local cache textContents = null; binaryContents = null; }
/** * 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); }
@Override public void filterResponse(HttpResponse response, HttpMessageContents contents, HttpMessageInfo messageInfo) { for (ResponseFilterRule rule: ruleList) { if(rule.getEnable()) { if (contents.isText() && messageInfo.getUrl().contains(rule.getUrl())) { String originContent = contents.getTextContents(); if (originContent != null) { contents.setTextContents(contents.getTextContents().replaceAll( rule.getReplaceRegex(), rule.getReplaceContent())); } } } } } });
@Override public void filterResponse(HttpResponse response, HttpMessageContents contents, HttpMessageInfo messageInfo) { if (contents.getBinaryContents().length > threshold) { log.warning("Too large response " + messageInfo.getUrl() + ": " + contents.getBinaryContents().length + " bytes"); if (log.isLoggable(Level.FINEST)) { log.finest("Response content: " + contents.getTextContents()); } } } }
@Override public HttpResponse clientToProxyRequest(HttpObject httpObject) { // only filter when the original HttpRequest comes through. the RequestFilterAdapter is not designed to filter // any subsequent HttpContents. if (httpObject instanceof HttpRequest) { HttpRequest httpRequest = (HttpRequest) httpObject; HttpMessageContents contents; if (httpObject instanceof FullHttpMessage) { FullHttpMessage httpContent = (FullHttpMessage) httpObject; contents = new HttpMessageContents(httpContent); } else { // the HTTP object is not a FullHttpMessage, which means that message contents are not available on this request and cannot be modified. contents = null; } HttpMessageInfo messageInfo = new HttpMessageInfo(originalRequest, ctx, isHttps(), getFullUrl(httpRequest), getOriginalUrl()); HttpResponse response = requestFilter.filterRequest(httpRequest, contents, messageInfo); if (response != null) { return response; } } return null; }
/** * 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(); } }
/** * Retrieves the character set of the entity body. If the Content-Type is not a textual type, this value is meaningless. * If no character set is specified, this method will return the default ISO-8859-1 character set. If the Content-Type * specifies a character set, but the character set is not supported on this platform, this method throws an * {@link java.nio.charset.UnsupportedCharsetException}. * * @return the entity body's character set * @throws java.nio.charset.UnsupportedCharsetException if the character set declared in the message is not supported on this platform */ public Charset getCharset() throws java.nio.charset.UnsupportedCharsetException { String contentTypeHeader = getContentType(); Charset charset = null; try { charset = BrowserMobHttpUtil.readCharsetInContentTypeHeader(contentTypeHeader); } catch (UnsupportedCharsetException e) { java.nio.charset.UnsupportedCharsetException cause = e.getUnsupportedCharsetExceptionCause(); log.error("Character set specified in Content-Type header is not supported on this platform. Content-Type header: {}", contentTypeHeader, cause); throw cause; } if (charset == null) { return BrowserMobHttpUtil.DEFAULT_HTTP_CHARSET; } return charset; }
/** * Extracts the binary contents from an HTTP message. * * @param httpContent HTTP content object to extract the entity body from * @return binary contents of the HTTP message */ public static byte[] extractBinaryHttpEntityBody(HttpContent httpContent) { return BrowserMobHttpUtil.extractReadableBytes(httpContent.content()); } }
@Override public X509Certificate[] get() { try { // the file may contain UTF-8 characters, but the PEM-encoded certificate data itself must be US-ASCII String allCAs = ClasspathResourceUtil.classpathResourceToString(DEFAULT_TRUSTED_CA_RESOURCE, StandardCharsets.UTF_8); return readX509CertificatesFromPem(allCAs); } catch (UncheckedIOException e) { log.warn("Unable to load built-in trusted CAs; no built-in CAs will be trusted", e); return new X509Certificate[0]; } } });
/** * Derives the charset from the Content-Type header in the HttpMessage. If the Content-Type header is not present or does not contain * a character set, this method returns the ISO-8859-1 character set. See {@link BrowserMobHttpUtil#readCharsetInContentTypeHeader(String)} * for more details. * * @param httpMessage HTTP message to extract charset from * @return the charset associated with the HTTP message, or the default charset if none is present * @throws UnsupportedCharsetException if there is a charset specified in the content-type header, but it is not supported */ public static Charset getCharsetFromMessage(HttpMessage httpMessage) throws UnsupportedCharsetException { String contentTypeHeader = HttpHeaders.getHeader(httpMessage, HttpHeaders.Names.CONTENT_TYPE); Charset charset = BrowserMobHttpUtil.readCharsetInContentTypeHeader(contentTypeHeader); if (charset == null) { return BrowserMobHttpUtil.DEFAULT_HTTP_CHARSET; } return charset; }
@Override public void chainedProxyAuthorization(String username, String password, AuthType authType) { switch (authType) { case BASIC: chainedProxyCredentials = BrowserMobHttpUtil.base64EncodeBasicCredentials(username, password); break; default: throw new UnsupportedOperationException("AuthType " + authType + " is not supported for Proxy Authorization"); } }
/** * Replaces the contents of the wrapped HttpMessage with the specified binary contents. Note that this method does not update the * Content-Type header, so if the content type will change as a result of this call, the Content-Type header should be updated before * calling this method. * * @param newBinaryContents new message contents */ public void setBinaryContents(byte[] newBinaryContents) { HttpObjectUtil.replaceBinaryHttpEntityBody(httpMessage, newBinaryContents); // replaced the contents, so clear the local cache binaryContents = null; textContents = null; }
/** * Retrieves the contents of this message as a String, decoded according to the message's Content-Type header. This method caches * the contents, so repeated calls to this method should not incur a penalty; however, modifications to the message contents * outside of this class will result in stale data returned from this method. * * @return String representation of the entity body * @throws java.nio.charset.UnsupportedCharsetException if the character set declared in the message is not supported on this platform */ public String getTextContents() throws java.nio.charset.UnsupportedCharsetException { // avoid re-extracting the contents if this method is called repeatedly if (textContents == null) { textContents = HttpObjectUtil.extractHttpEntityBody(httpMessage); } return textContents; }
@Override public HttpResponse filterRequest(HttpRequest request, HttpMessageContents contents, HttpMessageInfo messageInfo) { if (contents.getBinaryContents().length > threshold) { log.warning("Too large request " + messageInfo.getUrl() + ": " + contents.getBinaryContents().length + " bytes"); if (log.isLoggable(Level.FINEST)) { log.finest("Request content: " + contents.getTextContents()); } } return null; } }
@Override public HttpObject serverToProxyResponse(HttpObject httpObject) { // only filter when the original HttpResponse comes through. the ResponseFilterAdapter is not designed to filter // any subsequent HttpContents. if (httpObject instanceof HttpResponse) { HttpResponse httpResponse = (HttpResponse) httpObject; HttpMessageContents contents; if (httpObject instanceof FullHttpMessage) { FullHttpMessage httpContent = (FullHttpMessage) httpObject; contents = new HttpMessageContents(httpContent); } else { // the HTTP object is not a FullHttpMessage, which means that message contents will not be available on this response and cannot be modified. contents = null; } HttpMessageInfo messageInfo = new HttpMessageInfo(originalRequest, ctx, isHttps(), getFullUrl(modifiedHttpRequest), getOriginalUrl()); responseFilter.filterResponse(httpResponse, contents, messageInfo); } return super.serverToProxyResponse(httpObject); }
protected void storeRequestContent(HttpContent httpContent) { ByteBuf bufferedContent = httpContent.content(); byte[] content = BrowserMobHttpUtil.extractReadableBytes(bufferedContent); try { requestContents.write(content); } catch (IOException e) { // can't happen } }
@Override public void autoAuthorization(String domain, String username, String password, AuthType authType) { switch (authType) { case BASIC: // base64 encode the "username:password" string String base64EncodedCredentials = BrowserMobHttpUtil.base64EncodeBasicCredentials(username, password); basicAuthCredentials.put(domain, base64EncodedCredentials); break; default: throw new UnsupportedOperationException("AuthType " + authType + " is not supported for HTTP Authorization"); } }
protected void storeResponseContent(HttpContent httpContent) { ByteBuf bufferedContent = httpContent.content(); byte[] content = BrowserMobHttpUtil.extractReadableBytes(bufferedContent); try { rawResponseContents.write(content); } catch (IOException e) { // can't happen } }