Backend API. Server-side code: this runs in a Codename One backend, not in the app on the device.

public final class Http2

  1. Object
  2. Http2

One HTTP/2 connection, on nghttp2.

The framing is not implemented here and should not be: HPACK alone is a static table, a dynamic table with eviction and Huffman coding, and flow control, stream state, CONTINUATION reassembly and GOAWAY are all their own problems. nghttp2 owns those. This class owns the shape of the boundary.

Java PULLS from the session rather than being called back into. nghttp2 is callback-driven, but a C callback that reaches into the VM has to survive dead-code elimination and must not run while the collector is moving; the callbacks instead accumulate completed requests and this class takes them.

Nested types

class Http2.StreamOne request, once the client has finished sending it.

Fields

public static final String ALPN = "h2"The ALPN identifier.

Methods

public static Http2 create() throws IOExceptionA new server session, with the SETTINGS preface already queued.
public void receive(byte[] buffer, int offset, int length) throws IOExceptionFeeds received bytes to the session.
public Http2.Stream nextRequest()The next completed request, or null.
public boolean respond(int streamId, int status, String contentType, List extraHeaders, byte[] body) throws IOException
  • extraHeaders: “name: value” strings.
public static void setMaxBodyBytes(long limit)The ceiling for outstanding response bodies across the process.
public static void setMaxFileBodies(int limit)The ceiling for outstanding FILE-backed bodies across the process.
public boolean respondFile(int streamId, int status, String contentType, List extraHeaders, int fd, long offset, long length) throws IOExceptionResponds with a range of an open file, without reading it into the heap.
public byte[] drain() throws IOExceptionRuns the session’s output side and returns the bytes to put on the wire.
public int[] closedStreams()The streams that have closed since the last call, as (stream id, HTTP/2 error code) pairs; null when none have.
public boolean isAlive()False once the session is finished and the connection can be closed.
public long pendingBodyBytes()Heap held by response bodies that have been submitted and not yet fully written, which is NOT what drain() empties: that buffer is what nghttp2 has already serialised.
public static int pendingBodyFiles()File-backed response bodies outstanding across the PROCESS, not this session.
public static long pendingBodyBytesAll()Response-body heap outstanding across the PROCESS rather than this session.
public void close()

Inherited methods

Field details

ALPN

public static final String ALPN = "h2"
The ALPN identifier. There is no upgrade handshake for h2 over TLS.

Method details

create

public static Http2 create() throws IOException
A new server session, with the SETTINGS preface already queued.

receive

public void receive(byte[] buffer, int offset, int length) throws IOException
Feeds received bytes to the session.

nextRequest

public Http2.Stream nextRequest()
The next completed request, or null. A stream is complete only when END_STREAM arrives – on the HEADERS frame for a request with no body, on the last DATA frame otherwise.

respond

public boolean respond(int streamId, int status, String contentType, List extraHeaders, byte[] body) throws IOException
  • extraHeaders: “name: value” strings. Connection-specific headers are dropped, because HTTP/2 forbids them, and names are lower-cased, because a capital letter is a protocol error the peer resets the stream over.

setMaxBodyBytes

public static void setMaxBodyBytes(long limit)

The ceiling for outstanding response bodies across the process.

Set once, and enforced natively where the memory is actually taken.

setMaxFileBodies

public static void setMaxFileBodies(int limit)

The ceiling for outstanding FILE-backed bodies across the process.

Enforced natively for the same reason as the byte ceiling: the slot has to be taken in the same step as the descriptor, or every worker finishing at once passes the check before any of them counts.

respondFile

public boolean respondFile(int streamId, int status, String contentType, List extraHeaders, int fd, long offset, long length) throws IOException

Responds with a range of an open file, without reading it into the heap.

HTTP/2 cannot use sendfile – the bytes have to become DATA frames – but that is not a reason to materialise the whole file first. Reading it in cost the file’s size in Java plus the same again in the native copy, so a large enough public file turned one request into an OutOfMemoryError, which the handler’s catch (Exception) does not catch. The provider reads each frame straight out of the descriptor instead, so the memory is one frame regardless of size, and nghttp2’s flow control decides the pace.

The descriptor is owned by the session from here: it is closed when the stream reaches EOF, when it is reset early, and when the session is torn down.

drain

public byte[] drain() throws IOException
Runs the session’s output side and returns the bytes to put on the wire. Empty when there is nothing pending.

closedStreams

public int[] closedStreams()
The streams that have closed since the last call, as (stream id, HTTP/2 error code) pairs; null when none have. Code 0 is a stream whose response was sent in full; anything else is one reset before it was. A reset the PEER sent with NO_ERROR is reported as -1, not 0: it closes with code 0 too, and is no proof the response arrived. The server ends a request’s span here, since a body the peer’s flow-control window holds back is sent turns after it was submitted.

isAlive

public boolean isAlive()
False once the session is finished and the connection can be closed.

pendingBodyBytes

public long pendingBodyBytes()
Heap held by response bodies that have been submitted and not yet fully written, which is NOT what drain() empties: that buffer is what nghttp2 has already serialised. nghttp2 pulls from a submitted body only as the peer’s flow-control window allows, so a client that stops sending WINDOW_UPDATE leaves every body it asked for sitting here. A caller that keeps submitting has to look at this figure rather than at what it just handed over, because a flush that could write nothing frees nothing.

pendingBodyFiles

public static int pendingBodyFiles()
File-backed response bodies outstanding across the PROCESS, not this session. Such a body holds a descriptor and no heap, so it is invisible to pendingBodyBytes, and descriptors are a process resource: bounding them per connection still multiplies by the connection count, and exhausting them stops the process opening sockets or files at all.

pendingBodyBytesAll

public static long pendingBodyBytesAll()
Response-body heap outstanding across the PROCESS rather than this session. The per-session figure says what one connection holds; a limit on that is a limit per connection, and the connection ceiling is in the thousands, so it bounds nothing about the machine.

close

public void close()