Package org.microproxy.quic
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.
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
FieldsModifier and TypeFieldDescriptionstatic final longWhatframeLength(byte[], int, int)returns while the bytes do not yet say how long the next message is. -
Method Summary
Modifier and TypeMethodDescriptionstatic MessageFramerLines 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 ofpayload(byte[]): the payload with its length prefix, or with the delimiter after it.longframeLength(byte[] data, int offset, int length) The length of the message that starts atdata[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 thanQuicFraming.maxMessageSize()at once; a delimited one when it finds the delimiter.static MessageFramerlines()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).static MessageFramerA built-in framer by name:u16,u32,varint,lf(alsolineandnewline) orcrlf.default byte[]payload(byte[] message) What the hooks see of a whole message: the message without its length prefix or delimiter.static MessageFrameru16()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.static MessageFrameru32()A four-byte big-endian length prefix: payloads up to 232 - 1 bytes, bounded byQuicFraming.maxMessageSize().static MessageFramervarint()A QUIC variable-length integer (RFC 9000 section 16) as the length prefix: one, two, four or eight bytes.
-
Field Details
-
NEED_MORE
static final long NEED_MOREWhatframeLength(byte[], int, int)returns while the bytes do not yet say how long the next message is.- See Also:
-
-
Method Details
-
frameLength
long frameLength(byte[] data, int offset, int length) The length of the message that starts atdata[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 thanQuicFraming.maxMessageSize()at once; a delimited one when it finds the delimiter.- Parameters:
data- the bytes kept for the stream directionoffset- where the next message startslength- how many bytes there are fromoffset(at least one)- Returns:
- the message's length, at least 1, which may be more than
lengthwhile the rest is still to come; orNEED_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 asframeLength(byte[], int, int)said- Returns:
- the payload
-
frame
default byte[] frame(byte[] payload) The message for a payload, the reverse ofpayload(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
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
A four-byte big-endian length prefix: payloads up to 232 - 1 bytes, bounded byQuicFraming.maxMessageSize().- Returns:
- the framer
-
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
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
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
A built-in framer by name:u16,u32,varint,lf(alsolineandnewline) orcrlf.- Parameters:
name- the name (any case)- Returns:
- the framer
- Throws:
IllegalArgumentException- for another name
-