Class HttpBodies

java.lang.Object
org.microproxy.http.HttpBodies

public final class HttpBodies extends Object
Reads and rewrites the bodies of buffered messages (FullHttpMessage) in filters, taking care of Content-Encoding and charsets so filters don't have to.

 if (o instanceof FullHttpResponse res && HttpBodies.isText(res) && HttpBodies.canDecode(res)) {
     String html = HttpBodies.text(res);
     HttpBodies.setText(res, html.replace("</body>", "<script src=/x.js></script></body>"));
 }
 

gzip, x-gzip, deflate (zlib-wrapped or raw) and br (with a bundled copy of the pure-Java Brotli codec jaybrotli) can be decoded, and so can zstd when the optional zstd-decoder module is on the class path. Others, such as dictionary codings (dcb, dcz), are reported by canDecode(org.microproxy.http.HttpMessage), and restrictAcceptEncoding(org.microproxy.http.HttpRequest) keeps servers from choosing them. Decoding is capped (64 MiB by default) to defuse compression bombs. Rewriting a body re-applies the original coding (Brotli at quality 5; zstd bodies are re-encoded as gzip, since there is no pure-Java zstd encoder) and drops validators (ETag, Content-MD5) that no longer match; Content-Length is fixed when the message is written.

  • Field Summary

    Fields
    Modifier and Type
    Field
    Description
    static final int
    The Brotli quality (0 to 11) that encode(java.lang.String, byte[]) and rewritten br bodies use, with jaybrotli's default strategies: on HTML and JSON of 10 KB to 1 MB it runs at about 10 to 35 MB/s, and its output is mostly 1 to 14% smaller than gzip's default level (at worst 2% larger).
    static final Set<String>
    Content codings this class can decode: gzip, x-gzip, deflate and br, plus zstd when the zstd-decoder module is on the class path.
    static final int
    Default cap on decoded body size.
  • Method Summary

    Modifier and Type
    Method
    Description
    static boolean
    Whether every content coding of message can be decoded.
    static Charset
    charset(HttpMessage message, Charset fallback)
    The charset parameter of Content-Type, or fallback when absent, unknown or malformed.
    static List<String>
    The content codings applied to message, outermost last (identity omitted).
    static byte[]
    decode(String coding, byte[] data, int max)
    Removes one content coding from data, as decoded(FullHttpMessage, int) does for each coding of a message.
    static byte[]
    The body with all content codings removed.
    static byte[]
    decoded(FullHttpMessage message, int maxDecodedBytes)
    Removes all content codings with a limit on each decompression stage.
    static byte[]
    decodedPrefix(FullHttpMessage message, int maxBytes)
    The first maxBytes of the body with all content codings removed, for previews and logs: unlike decoded(FullHttpMessage, int), a longer decoded body is cut short rather than an error, and only that much is ever decoded.
    static byte[]
    encode(String coding, byte[] data)
    Applies one content coding to data: gzip (or x-gzip), deflate (zlib-wrapped) or br (at BROTLI_QUALITY), the codings this class can produce.
    static boolean
    Whether the media type is textual: text/*, JSON, XML, JavaScript or form data.
    static String
    The media type of Content-Type in lower case, without parameters, or "".
    static void
    Decodes the body and removes Content-Encoding, so later filters see plain bytes.
    static void
    Removes content codings this class cannot decode (e.g.
    static void
    setDecoded(FullHttpMessage message, byte[] decodedBody)
    Replaces the body with decodedBody, re-applying the message's content codings, and removes validators that described the old body.
    static void
    setText(FullHttpMessage message, String text)
    Replaces the body with text in the message's charset (UTF-8 when none is declared).
    static String
    The decoded body as text, in the message's charset (UTF-8 when none is declared).

    Methods inherited from class java.lang.Object

    clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
  • Field Details

    • DEFAULT_MAX_DECODED_BYTES

      public static final int DEFAULT_MAX_DECODED_BYTES
      Default cap on decoded body size.
      See Also:
    • DECODABLE

      public static final Set<String> DECODABLE
      Content codings this class can decode: gzip, x-gzip, deflate and br, plus zstd when the zstd-decoder module is on the class path.
    • BROTLI_QUALITY

      public static final int BROTLI_QUALITY
      The Brotli quality (0 to 11) that encode(java.lang.String, byte[]) and rewritten br bodies use, with jaybrotli's default strategies: on HTML and JSON of 10 KB to 1 MB it runs at about 10 to 35 MB/s, and its output is mostly 1 to 14% smaller than gzip's default level (at worst 2% larger). Qualities 4 and 6 come out within 1% of it; the higher qualities and the alternative strategies trade too much speed for what they save.
      See Also:
  • Method Details

    • contentEncodings

      public static List<String> contentEncodings(HttpMessage message)
      The content codings applied to message, outermost last (identity omitted).
      Parameters:
      message - the message whose body and headers are inspected
      Returns:
      the lower-case content codings in application order, excluding identity
    • canDecode

      public static boolean canDecode(HttpMessage message)
      Whether every content coding of message can be decoded.
      Parameters:
      message - the message whose body and headers are inspected
      Returns:
      whether all declared content codings are supported
    • decoded

      public static byte[] decoded(FullHttpMessage message) throws IOException
      The body with all content codings removed.
      Parameters:
      message - the message whose body and headers are inspected
      Returns:
      the body bytes after all content codings are removed
      Throws:
      IOException - if a coding is unsupported, corrupt, or exceeds the default decoding limit
    • decoded

      public static byte[] decoded(FullHttpMessage message, int maxDecodedBytes) throws IOException
      Removes all content codings with a limit on each decompression stage.
      Parameters:
      message - the message whose body and headers are inspected
      maxDecodedBytes - the maximum output size in bytes for each decompression stage
      Returns:
      the body bytes after all content codings are removed
      Throws:
      IOException - if a coding is unsupported, corrupt, or exceeds the decoding limit
    • decodedPrefix

      public static byte[] decodedPrefix(FullHttpMessage message, int maxBytes) throws IOException
      The first maxBytes of the body with all content codings removed, for previews and logs: unlike decoded(FullHttpMessage, int), a longer decoded body is cut short rather than an error, and only that much is ever decoded.
      Parameters:
      message - the message whose body and headers are inspected
      maxBytes - the maximum prefix length; nonpositive values produce an empty result
      Returns:
      up to maxBytes decoded body bytes
      Throws:
      IOException - if a coding is unsupported or the decoded prefix cannot be read
    • setDecoded

      public static void setDecoded(FullHttpMessage message, byte[] decodedBody) throws IOException
      Replaces the body with decodedBody, re-applying the message's content codings, and removes validators that described the old body.
      Parameters:
      message - the message to update
      decodedBody - the replacement bytes before applying content codings
      Throws:
      IOException - if a content coding is unsupported or encoding fails
    • removeContentEncoding

      public static void removeContentEncoding(FullHttpMessage message) throws IOException
      Decodes the body and removes Content-Encoding, so later filters see plain bytes.
      Parameters:
      message - the message to decode and update
      Throws:
      IOException - if a coding is unsupported, corrupt, or exceeds the default decoding limit
    • restrictAcceptEncoding

      public static void restrictAcceptEncoding(HttpRequest request)
      Removes content codings this class cannot decode (e.g. dcb) from the request's Accept-Encoding, keeping quality values, so the server picks one that filters can read. Leaves identity when nothing else remains.
      Parameters:
      request - the request whose accepted codings are restricted
    • text

      public static String text(FullHttpMessage message) throws IOException
      The decoded body as text, in the message's charset (UTF-8 when none is declared).
      Parameters:
      message - the message whose body and headers are inspected
      Returns:
      the decoded body interpreted in the declared charset, or UTF-8 by default
      Throws:
      IOException - if a coding is unsupported, corrupt, or exceeds the default decoding limit
    • setText

      public static void setText(FullHttpMessage message, String text) throws IOException
      Replaces the body with text in the message's charset (UTF-8 when none is declared).
      Parameters:
      message - the message to update
      text - the replacement text before charset encoding and content coding
      Throws:
      IOException - if a content coding is unsupported or encoding fails
    • charset

      public static Charset charset(HttpMessage message, Charset fallback)
      The charset parameter of Content-Type, or fallback when absent, unknown or malformed.
      Parameters:
      message - the message whose Content-Type is inspected
      fallback - the charset to use when the parameter cannot be resolved
      Returns:
      the declared charset, or fallback if unavailable
    • mediaType

      public static String mediaType(HttpMessage message)
      The media type of Content-Type in lower case, without parameters, or "".
      Parameters:
      message - the message whose Content-Type is inspected
      Returns:
      the lower-case media type without parameters, or an empty string if absent
    • isText

      public static boolean isText(HttpMessage message)
      Whether the media type is textual: text/*, JSON, XML, JavaScript or form data.
      Parameters:
      message - the message whose media type is inspected
      Returns:
      whether the media type is recognized as textual
    • decode

      public static byte[] decode(String coding, byte[] data, int max) throws IOException
      Removes one content coding from data, as decoded(FullHttpMessage, int) does for each coding of a message. Also used for gRPC messages, which are compressed one by one with the coding their grpc-encoding names.
      Parameters:
      coding - the coding, in lower case: gzip, x-gzip, deflate (zlib-wrapped or raw), br, or zstd when the module is present
      data - the encoded bytes
      max - the maximum decoded size in bytes
      Returns:
      the decoded bytes
      Throws:
      IOException - if the coding is unsupported, the data corrupt, or the result larger than max
    • encode

      public static byte[] encode(String coding, byte[] data) throws IOException
      Applies one content coding to data: gzip (or x-gzip), deflate (zlib-wrapped) or br (at BROTLI_QUALITY), the codings this class can produce.
      Parameters:
      coding - the coding, in lower case
      data - the bytes to encode
      Returns:
      the encoded bytes
      Throws:
      IOException - if the coding is not one of those