Class Http3FrameReader

java.lang.Object
io.github.mahmoudimus.http3.Http3FrameReader

public final class Http3FrameReader extends Object
Reads HTTP/3 frames from one QUIC stream's bytes, one call per frame, validating everything that can be checked from a frame on its own (RFC 9114 §7). Meant to be driven by one (virtual) thread per stream; it buffers nothing itself, so give it a BufferedInputStream or similar. Not thread-safe.

 Http3FrameReader reader = new Http3FrameReader(requestStreamInput);
 Http3StreamValidator validator = Http3StreamValidator.forRequestStream(streamId, Role.SERVER);
 for (Http3Frame frame; (frame = reader.readFrame()) != null; ) {
     validator.onFrame(frame);
     switch (frame) {
         case Http3Frame.Headers h -> fields = qpack.decode(streamId, h.fieldSection());
         case Http3Frame.Data d -> body.write(d.data());
         default -> {}
     }
 }
 validator.onEndOfStream();
 

What it enforces:

  • A payload of at most setMaxFramePayloadSize(int) bytes (default 64 KiB), checked before anything is allocated; a longer one is a connection error H3_EXCESSIVE_LOAD. DATA is the exception: HTTP/3 gives DATA frame boundaries no meaning, so a longer DATA frame is returned as consecutive Http3Frame.Data pieces of at most that size, and memory per frame stays bounded by the limit either way.
  • Payloads that hold exactly their fields (CANCEL_PUSH, GOAWAY, MAX_PUSH_ID, SETTINGS, PUSH_PROMISE), and frames cut short by the end of the stream: connection error H3_FRAME_ERROR.
  • The HTTP/2 frame types that HTTP/3 forbids (0x02, 0x06, 0x08, 0x09): connection error H3_FRAME_UNEXPECTED.
  • SETTINGS: no identifier twice, none of the HTTP/2-only identifiers, and valid values for the defined ones (connection error H3_SETTINGS_ERROR).

Frames of unknown and reserved types are returned as Http3Frame.Unknown, so they can be relayed, unless setDeliverUnknownFrames(boolean) turns that off; then they are skipped without allocating their payload. Which frames may appear on which stream, and in what order, is Http3StreamValidator's job.

Every error is a connection error, and the reader must not be used after one.

  • Field Details

    • DEFAULT_MAX_FRAME_PAYLOAD_SIZE

      public static final int DEFAULT_MAX_FRAME_PAYLOAD_SIZE
      The default limit on a frame payload, 64 KiB.
      See Also:
  • Constructor Details

    • Http3FrameReader

      public Http3FrameReader(InputStream in)
      A reader for one stream.
      Parameters:
      in - the stream's bytes; give it a buffered stream
  • Method Details

    • of

      public static Http3FrameReader of(ByteBuffer buf)
      A reader over the remaining bytes of a buffer, which it consumes.
      Parameters:
      buf - the bytes
      Returns:
      the reader
    • setMaxFramePayloadSize

      public void setMaxFramePayloadSize(int maxFramePayloadSize)
      The largest payload accepted (and the largest piece a long DATA frame is returned in).
      Parameters:
      maxFramePayloadSize - the limit in bytes, 1 to 2^31-9
    • maxFramePayloadSize

      public int maxFramePayloadSize()
      The largest payload accepted.
      Returns:
      the limit in bytes
    • setDeliverUnknownFrames

      public void setDeliverUnknownFrames(boolean deliverUnknownFrames)
      Return frames of unknown and reserved types as Http3Frame.Unknown (the default) or skip them.
      Parameters:
      deliverUnknownFrames - whether to return them
    • readStreamType

      public long readStreamType() throws IOException
      Reads the stream type that starts every unidirectional stream (RFC 9114 §6.2); see Http3StreamType. Call it once, before the first readFrame().
      Returns:
      the type, or -1 if the stream ended before all of it arrived (which a receiver must tolerate)
      Throws:
      IOException - if reading fails
    • readFrame

      public Http3Frame readFrame() throws IOException
      Reads the next frame.
      Returns:
      the frame, or null if the stream ended cleanly between frames
      Throws:
      Http3Exception - if the frame breaks the protocol or a limit, or the stream ends inside it
      IOException
    • parse

      public static Http3Frame parse(ByteBuffer buf, int maxFramePayloadSize) throws Http3Exception
      Parses one whole frame at the buffer's position, for callers that collect a stream's bytes in a buffer. The limit applies to every frame type here, DATA included; read long DATA frames with a reader over a stream instead.
      Parameters:
      buf - the stream's bytes so far
      maxFramePayloadSize - the largest payload accepted
      Returns:
      the frame, with the position moved past it; or null, with the position unchanged, if the buffer holds only part of it
      Throws:
      Http3Exception - as readFrame(), and H3_EXCESSIVE_LOAD for a DATA frame longer than maxFramePayloadSize