Interface MessageFramer

Functional Interface:
This is a functional interface and can therefore be used as the assignment target for a lambda expression or method reference.

@FunctionalInterface public interface MessageFramer
Finds the messages of a protocol in the bytes of a QUIC stream, so that QuicInterceptor.streamMessage(org.microproxy.quic.QuicMessage, org.microproxy.quic.QuicStreamContext) sees whole messages rather than whatever each read returned (see QuicFraming, which chooses a framer for each connection).

The proxy keeps the bytes of each direction of a stream that do not make a whole message yet, and asks frameLength(byte[], int, int) how long the message at their start is: once that is known and all of it has arrived, the message is cut off, its payload(byte[]) goes to the hook, and what the hook returns goes on as frame(byte[])(payload), so a length prefix is computed again for an edited payload. A framer that is only a lambda gives the hook whole messages and sends what it returns as it is.


 // Messages that end with a zero byte, given to the hook with it.
 MessageFramer zeroTerminated = (data, offset, length) -> {
     for (int i = 0; i < length; i++) if (data[offset + i] == 0) return i + 1;
     return MessageFramer.NEED_MORE;
 };
 

Framers are called from many threads at once, one stream direction each, and must keep no state between calls.

  • Field Summary

    Fields
    Modifier and Type
    Field
    Description
    static final long
    What frameLength(byte[], int, int) returns while the bytes do not yet say how long the next message is.
  • Method Summary

    Modifier and Type
    Method
    Description
    Lines that end with a carriage return and a line feed: the payload is the line without them, and they are added after each payload sent.
    default byte[]
    frame(byte[] payload)
    The message for a payload, the reverse of payload(byte[]): the payload with its length prefix, or with the delimiter after it.
    long
    frameLength(byte[] data, int offset, int length)
    The length of the message that starts at data[offset], its prefix or delimiter included, as soon as the bytes say it: a length-prefixed framer knows it from the prefix alone, before the rest of the message has arrived, which lets the proxy refuse a message larger than QuicFraming.maxMessageSize() at once; a delimited one when it finds the delimiter.
    Lines that end with a line feed: the payload is the line without it, and a line feed is added after each payload sent (a carriage return before it stays in the payload).
    named(String name)
    A built-in framer by name: u16, u32, varint, lf (also line and newline) or crlf.
    default byte[]
    payload(byte[] message)
    What the hooks see of a whole message: the message without its length prefix or delimiter.
    u16()
    A two-byte big-endian length prefix, as DNS over QUIC (RFC 9250 section 4.2) and DNS over TCP frame their messages: payloads up to 65535 bytes.
    u32()
    A four-byte big-endian length prefix: payloads up to 232 - 1 bytes, bounded by QuicFraming.maxMessageSize().
    A QUIC variable-length integer (RFC 9000 section 16) as the length prefix: one, two, four or eight bytes.
  • Field Details

  • Method Details

    • frameLength

      long frameLength(byte[] data, int offset, int length)
      The length of the message that starts at data[offset], its prefix or delimiter included, as soon as the bytes say it: a length-prefixed framer knows it from the prefix alone, before the rest of the message has arrived, which lets the proxy refuse a message larger than QuicFraming.maxMessageSize() at once; a delimited one when it finds the delimiter.
      Parameters:
      data - the bytes kept for the stream direction
      offset - where the next message starts
      length - how many bytes there are from offset (at least one)
      Returns:
      the message's length, at least 1, which may be more than length while the rest is still to come; or NEED_MORE
      Throws:
      IllegalArgumentException - if the bytes cannot start a message of the protocol: the proxy then resets the stream, as for a message that is too large
    • payload

      default byte[] payload(byte[] message)
      What the hooks see of a whole message: the message without its length prefix or delimiter. The default is the message itself.
      Parameters:
      message - a whole message, as long as frameLength(byte[], int, int) said
      Returns:
      the payload
    • frame

      default byte[] frame(byte[] payload)
      The message for a payload, the reverse of payload(byte[]): the payload with its length prefix, or with the delimiter after it. The default is the payload itself.
      Parameters:
      payload - the payload
      Returns:
      the bytes to send
      Throws:
      IllegalArgumentException - if the payload cannot be framed, such as one longer than a two-byte prefix can say
    • u16

      static MessageFramer u16()
      A two-byte big-endian length prefix, as DNS over QUIC (RFC 9250 section 4.2) and DNS over TCP frame their messages: payloads up to 65535 bytes.
      Returns:
      the framer
    • u32

      static MessageFramer u32()
      A four-byte big-endian length prefix: payloads up to 232 - 1 bytes, bounded by QuicFraming.maxMessageSize().
      Returns:
      the framer
    • varint

      static MessageFramer varint()
      A QUIC variable-length integer (RFC 9000 section 16) as the length prefix: one, two, four or eight bytes. Payloads are framed with the shortest encoding.
      Returns:
      the framer
    • lines

      static MessageFramer lines()
      Lines that end with a line feed: the payload is the line without it, and a line feed is added after each payload sent (a carriage return before it stays in the payload).
      Returns:
      the framer
    • crlfLines

      static MessageFramer crlfLines()
      Lines that end with a carriage return and a line feed: the payload is the line without them, and they are added after each payload sent. A line feed alone does not end a line.
      Returns:
      the framer
    • named

      static MessageFramer named(String name)
      A built-in framer by name: u16, u32, varint, lf (also line and newline) or crlf.
      Parameters:
      name - the name (any case)
      Returns:
      the framer
      Throws:
      IllegalArgumentException - for another name