Class ProxyUtils

java.lang.Object
org.littleshoot.proxy.impl.ProxyUtils

public class ProxyUtils extends Object
Utilities for the proxy.
  • Field Details

    • SHOULD_NOT_PROXY_HOP_BY_HOP_HEADERS

      private static final Set<String> SHOULD_NOT_PROXY_HOP_BY_HOP_HEADERS
      Hop-by-hop headers that should be removed when proxying, as defined by the HTTP 1.1 spec, section 13.5.1 (https://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html#sec13.5.1). Transfer-Encoding is NOT included in this list, since LittleProxy does not typically modify the transfer encoding. See also shouldRemoveHopByHopHeader(String). Header names are stored as lowercase to make case-insensitive comparisons easier.
    • LOG

      private static final org.slf4j.Logger LOG
    • GMT

      private static final TimeZone GMT
    • COMMA_SEPARATED_HEADER_VALUE_SPLITTER

      private static final com.google.common.base.Splitter COMMA_SEPARATED_HEADER_VALUE_SPLITTER
      Splits comma-separated header values (such as Connection) into their individual tokens.
    • PATTERN_RFC1123

      private static final String PATTERN_RFC1123
      Date format pattern used to parse HTTP date headers in RFC 1123 format.
      See Also:
    • HTTP_PREFIX

      private static final Pattern HTTP_PREFIX
  • Constructor Details

    • ProxyUtils

      public ProxyUtils()
  • Method Details

    • stripHost

      public static String stripHost(String uri)
      Strips the host from a URI string. This will turn "https://host.com/path" into "/path".
      Parameters:
      uri - The URI to transform.
      Returns:
      A string with the URI stripped.
    • formatDate

      public static String formatDate(Date date)
      Formats the given date according to the RFC 1123 pattern.
      Parameters:
      date - The date to format.
      Returns:
      An RFC 1123 formatted date string.
      See Also:
    • formatDate

      public static String formatDate(Date date, String pattern)
      Formats the given date according to the specified pattern. The pattern must conform to that used by the simple date format class.
      Parameters:
      date - The date to format.
      pattern - The pattern to use for formatting the date.
      Returns:
      A formatted date string.
      Throws:
      IllegalArgumentException - If the given date pattern is invalid.
      See Also:
    • isLastChunk

      public static boolean isLastChunk(HttpObject httpObject)
      If an HttpObject implements the market interface LastHttpContent, it represents the last chunk of a transfer.
      See Also:
    • isChunked

      public static boolean isChunked(HttpObject httpObject)
      If an HttpObject is not the last chunk, then that means there are other chunks that will follow.
      See Also:
    • parseHostAndPort

      public static String parseHostAndPort(HttpRequest httpRequest)
      Parses the host and port an HTTP request is being sent to.
      Parameters:
      httpRequest - The request.
      Returns:
      The host and port string.
    • parseHostAndPort

      public static String parseHostAndPort(String uri)
      Parses the host and port an HTTP request is being sent to.
      Parameters:
      uri - The URI.
      Returns:
      The host and port string.
    • copyMutableResponseFields

      public static HttpResponse copyMutableResponseFields(HttpResponse original)
      Make a copy of the response including all mutable fields.
      Parameters:
      original - The original response to copy from.
      Returns:
      The copy with all mutable fields from the original.
    • addVia

      public static void addVia(HttpMessage httpMessage, String alias)
      Adds the Via header to specify that the message has passed through the proxy. The specified alias will be appended to the Via header line. The alias may be the hostname of the machine proxying the request, or a pseudonym. From RFC 7230, section 5.7.1:
               The received-by portion of the field value is normally the host and
               optional port number of a recipient server or client that
               subsequently forwarded the message.  However, if the real host is
               considered to be sensitive information, a sender MAY replace it with
               a pseudonym.
       
      Parameters:
      httpMessage - HTTP message to add the Via header to
      alias - the alias to provide in the Via header for this proxy
    • isTrue

      public static boolean isTrue(String val)
      Returns true if the specified string is either "true" or "on" ignoring case.
      Parameters:
      val - The string in question.
      Returns:
      true if the specified string is either "true" or "on" ignoring case, otherwise false.
    • isFalse

      public static boolean isFalse(String val)
      Returns true if the specified string is either "false" or "off" ignoring case.
      Parameters:
      val - The string in question.
      Returns:
      true if the specified string is either "false" or "off" ignoring case, otherwise false.
    • extractBooleanDefaultFalse

      public static boolean extractBooleanDefaultFalse(Properties props, String key)
    • extractBooleanDefaultTrue

      public static boolean extractBooleanDefaultTrue(Properties props, String key)
    • extractInt

      public static int extractInt(Properties props, String key)
    • extractInt

      public static int extractInt(Properties props, String key, int defaultValue)
    • isCONNECT

      public static boolean isCONNECT(HttpObject httpObject)
    • isHEAD

      public static boolean isHEAD(HttpRequest httpRequest)
      Returns true if the specified HttpRequest is a HEAD request.
      Parameters:
      httpRequest - http request
      Returns:
      true if request is a HEAD, otherwise false
    • checkTrueOrFalse

      private static boolean checkTrueOrFalse(String val, String str1, String str2)
    • isContentAlwaysEmpty

      public static boolean isContentAlwaysEmpty(HttpMessage msg)
      Returns true if the HTTP message cannot contain an entity body, according to the HTTP spec. This code is taken directly from HttpObjectDecoder.isContentAlwaysEmpty(HttpMessage).
      Parameters:
      msg - HTTP message
      Returns:
      true if the HTTP message is always empty, false if the message may have entity content.
    • isResponseSelfTerminating

      public static boolean isResponseSelfTerminating(HttpResponse response)
      Returns true if the HTTP response from the server is expected to indicate its own message length/end-of-message. Returns false if the server is expected to indicate the end of the HTTP entity by closing the connection.

      This method is based on the allowed message length indicators in the HTTP specification, section 4.4:

               4.4 Message Length
               The transfer-length of a message is the length of the message-body as it appears in the message; that is, after any transfer-codings have been applied. When a message-body is included with a message, the transfer-length of that body is determined by one of the following (in order of precedence):
      
               1.Any response message which "MUST NOT" include a message-body (such as the 1xx, 204, and 304 responses and any response to a HEAD request) is always terminated by the first empty line after the header fields, regardless of the entity-header fields present in the message.
               2.If a Transfer-Encoding header field (section 14.41) is present and has any value other than "identity", then the transfer-length is defined by use of the "chunked" transfer-coding (section 3.6), unless the message is terminated by closing the connection.
               3.If a Content-Length header field (section 14.13) is present, its decimal value in OCTETs represents both the entity-length and the transfer-length. The Content-Length header field MUST NOT be sent if these two lengths are different (i.e., if a Transfer-Encoding
               header field is present). If a message is received with both a Transfer-Encoding header field and a Content-Length header field, the latter MUST be ignored.
               [LP note: multipart/byteranges support has been removed from the HTTP 1.1 spec by RFC 7230, section A.2. Since it is seldom used, LittleProxy does not check for it.]
               5.By the server closing the connection. (Closing the connection cannot be used to indicate the end of a request body, since that would leave no possibility for the server to send back a response.)
       
      The rules for Transfer-Encoding are clarified in RFC 7230, section 3.3.1 and 3.3.3 (3):
               If any transfer coding other than
               chunked is applied to a response payload body, the sender MUST either
               apply chunked as the final transfer coding or terminate the message
               by closing the connection.
       
      Parameters:
      response - the HTTP response object
      Returns:
      true if the message will indicate its own message length, or false if the server is expected to indicate the message length by closing the connection
    • getAllCommaSeparatedHeaderValues

      public static List<String> getAllCommaSeparatedHeaderValues(AsciiString headerName, HttpMessage httpMessage)
      Retrieves all comma-separated values for headers with the specified name on the HttpMessage. Any whitespace (spaces or tabs) surrounding the values will be removed. Empty values (e.g. two consecutive commas, or a value followed by a comma and no other value) will be removed; they will not appear as empty elements in the returned list. If the message contains repeated headers, their values will be added to the returned list in the order in which the headers appear. For example, if a message has headers like:
           Transfer-Encoding: gzip,deflate
           Transfer-Encoding: chunked
       
      This method will return a list of three values: "gzip", "deflate", "chunked".

      Placing values on multiple header lines is allowed under certain circumstances in RFC 2616 section 4.2, and in RFC 7230 section 3.2.2 quoted here:

           A sender MUST NOT generate multiple header fields with the same field
           name in a message unless either the entire field value for that
           header field is defined as a comma-separated list [i.e., #(values)]
           or the header field is a well-known exception (as noted below).
      
           A recipient MAY combine multiple header fields with the same field
           name into one "field-name: field-value" pair, without changing the
           semantics of the message, by appending each subsequent field value to
           the combined field value in order, separated by a comma.  The order
           in which header fields with the same field name are received is
           therefore significant to the interpretation of the combined field
           value; a proxy MUST NOT change the order of these field values when
           forwarding a message.
       
      Parameters:
      headerName - the name of the header for which values will be retrieved
      httpMessage - the HTTP message whose header values will be retrieved
      Returns:
      a list of single header values, or an empty list if the header was not present in the message or contained no values
    • duplicateHttpResponse

      public static HttpResponse duplicateHttpResponse(HttpResponse originalResponse)
      Duplicates the status line and headers of an HttpResponse object. Does not duplicate any content associated with that response.
      Parameters:
      originalResponse - HttpResponse to be duplicated
      Returns:
      a new HttpResponse with the same status line and headers
    • getHostName

      public static String getHostName()
      Attempts to resolve the local machine's hostname.
      Returns:
      the local machine's hostname, or null if a hostname cannot be determined
    • shouldRemoveHopByHopHeader

      public static boolean shouldRemoveHopByHopHeader(String headerName)
      Determines if the specified header should be removed from the proxied response because it is a hop-by-hop header, as defined by the HTTP 1.1 spec in section 13.5.1. The comparison is case-insensitive, so "Connection" will be treated the same as "connection" or "CONNECTION". From https://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html#sec13.5.1 :
             The following HTTP/1.1 headers are hop-by-hop headers:
              - Connection
              - Keep-Alive
              - Proxy-Authenticate
              - Proxy-Authorization
              - TE
              - Trailers [LittleProxy note: actual header name is Trailer]
              - Transfer-Encoding [LittleProxy note: this header is not normally removed when proxying, since the proxy does not re-chunk
                                  responses. The exception is when an HttpObjectAggregator is enabled, which aggregates chunked content and removes
                                  the 'Transfer-Encoding: chunked' header itself.]
              - Upgrade
      
             All other headers defined by HTTP/1.1 are end-to-end headers.
       
      Parameters:
      headerName - the header name
      Returns:
      true if this header is a hop-by-hop header and should be removed when proxying, otherwise false
    • stripHopByHopHeaders

      public static void stripHopByHopHeaders(HttpHeaders headers)
      Removes all headers that should not be forwarded. See RFC 2616 13.5.1 End-to-end and Hop-by-hop Headers.
      Parameters:
      headers - The headers to modify
    • splitCommaSeparatedHeaderValues

      public static List<String> splitCommaSeparatedHeaderValues(String headerValue)
      Splits comma-separated header values into tokens. For example, if the value of the Connection header is "Transfer-Encoding, close", this method will return "Transfer-Encoding" and "close". This method strips trims any optional whitespace from the tokens. Unlike getAllCommaSeparatedHeaderValues(AsciiString, HttpMessage), this method only operates on a single header value, rather than all instances of the header in a message.
      Parameters:
      headerValue - the un-tokenized header value (must not be null)
      Returns:
      all tokens within the header value, or an empty list if there are no values
    • isUdtAvailable

      public static boolean isUdtAvailable()
      Determines if UDT is available on the classpath.
      Returns:
      true if UDT is available
    • createFullHttpResponse

      public static FullHttpResponse createFullHttpResponse(HttpVersion httpVersion, HttpResponseStatus status, String body)
      Creates a new FullHttpResponse with the specified String as the body contents (encoded using UTF-8).
      Parameters:
      httpVersion - HTTP version of the response
      status - HTTP status code
      body - body to include in the FullHttpResponse; will be UTF-8 encoded
      Returns:
      new http response object
    • createFullHttpResponse

      public static FullHttpResponse createFullHttpResponse(HttpVersion httpVersion, HttpResponseStatus status)
      Creates a new FullHttpResponse with no body content
      Parameters:
      httpVersion - HTTP version of the response
      status - HTTP status code
      Returns:
      new http response object
    • createFullHttpResponse

      public static FullHttpResponse createFullHttpResponse(HttpVersion httpVersion, HttpResponseStatus status, String contentType, ByteBuf body, int contentLength)
      Creates a new FullHttpResponse with the specified body.
      Parameters:
      httpVersion - HTTP version of the response
      status - HTTP status code
      contentType - the Content-Type of the body
      body - body to include in the FullHttpResponse; if null
      contentLength - number of bytes to send in the Content-Length header; should equal the number of bytes in the ByteBuf
      Returns:
      new http response object
    • removeSdchEncoding

      public static void removeSdchEncoding(HttpHeaders headers)
      Given an HttpHeaders instance, removes 'sdch' from the 'Accept-Encoding' header list (if it exists) and returns the modified instance. Removes all occurrences of 'sdch' from the 'Accept-Encoding' header.
      Parameters:
      headers - The headers to modify.
    • isSwitchingToWebSocketProtocol

      public static boolean isSwitchingToWebSocketProtocol(HttpResponse response)
      Tests whether the given response indicates that the connection is switching to the WebSocket protocol.
      Parameters:
      response - the response to check.
      Returns:
      true if switching to the WebSocket protocol; false otherwise;
    • isSwitchingToWebSocketProtocol

      public static boolean isSwitchingToWebSocketProtocol(HttpRequest request)
      Tests whether the given request indicates that the connection is switching to the WebSocket protocol.
      Parameters:
      request - the request to check.
      Returns:
      true if switching to the WebSocket protocol; false otherwise;