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

public final class HttpServer

  1. Object
  2. HttpServer

An HTTP/1.1 server built around a reactor and a bounded worker pool.

The split is the whole design. A parked ParparVM thread costs about 243KB on musl (see vm/benchmarks ThreadCost), so ten thousand connections cannot each have one. Here an IDLE connection is a descriptor the reactor watches, and only a connection with a request in flight occupies a worker. Workers are bounded, so overload sheds as queueing rather than as memory exhaustion.

Once a worker owns a connection its descriptor is switched to BLOCKING mode, so request parsing is a straight read loop rather than a resumable state machine. That spends a worker per in-flight request to avoid a large amount of complexity, and in-flight requests are the thing there are few of.

Nested types

class HttpServer.RequestWhat a handler receives.
class HttpServer.PartOne part of a multipart/form-data request body: a form field, or an uploaded file when it has a filename.
class HttpServer.ResponseWhat a handler returns.
interface HttpServer.Handler
interface HttpServer.WebSocketHandlerChooses the websocket endpoint for an upgrade request, or null when this router does not serve that path.
interface HttpServer.WebSocketRoutesWhere websocket routes come from.
interface HttpServer.WebSocketRegistryWhat a WebSocketRoutes callback puts its endpoints into.

Methods

public static HttpServer start(String host, int port, int backlog, int workerCount, HttpServer.Handler handler) throws IOException
public static HttpServer start(String host, int port, int backlog, int workerCount, HttpServer.Handler handler, Tls tls) throws IOException
  • tls: terminate TLS here, or null to serve plaintext (correct behind a load balancer that already terminated it)
public static HttpServer start(String host, int port, int backlog, int workerCount, HttpServer.Handler handler, Tls tls, HttpServer.WebSocketRoutes webSockets) throws IOException
  • webSockets: asked for its routes before the listener accepts anything
public boolean isSecure()Whether this server speaks TLS, so a client of it must use https.
public int getPort()
public int getOpenConnections()Connections currently open.
public int getActiveRequests()Requests being handled right now.
public Map getMetrics()A snapshot for a health or metrics endpoint.
public void awaitTermination()Blocks until the server has fully stopped, draining included.
public void stop(int drainMillis)Stops accepting, lets in-flight requests finish, then closes what is left.
public void stop()Stops with a default drain window.

Inherited methods

Method details

start

public static HttpServer start(String host, int port, int backlog, int workerCount, HttpServer.Handler handler) throws IOException

start

public static HttpServer start(String host, int port, int backlog, int workerCount, HttpServer.Handler handler, Tls tls) throws IOException
  • tls: terminate TLS here, or null to serve plaintext (correct behind a load balancer that already terminated it)

start

public static HttpServer start(String host, int port, int backlog, int workerCount, HttpServer.Handler handler, Tls tls, HttpServer.WebSocketRoutes webSockets) throws IOException
  • webSockets: asked for its routes before the listener accepts anything

The callback runs here rather than on the returned server because this method binds the listener and starts the poller threads before it returns: a client arriving in that window would find no websocket routes at all, and its upgrade would fall through to the ordinary handler and be answered as HTTP. There is no way to express that mistake through this signature.

isSecure

public boolean isSecure()
Whether this server speaks TLS, so a client of it must use https.

getPort

public int getPort()

getOpenConnections

public int getOpenConnections()
Connections currently open.

getActiveRequests

public int getActiveRequests()
Requests being handled right now. This is what saturation looks like.

getMetrics

public Map getMetrics()
A snapshot for a health or metrics endpoint. “draining” is what a load balancer needs to see to take this instance out of rotation before it stops answering.

awaitTermination

public void awaitTermination()

Blocks until the server has fully stopped, draining included.

A caller’s main() must do this or something equivalent: the reactor and the workers run on threads ParparVM creates DETACHED, so when main returns the process exits and takes them with it – silently, with status 0, which from outside looks exactly like a server that refuses connections.

Waiting on the reactor THREAD is not enough, and that was a real bug: stop() clears the running flag, the loop returns on its next timeout, main wakes up and the process ends while a worker is still writing a response. This waits on the drain finishing instead.

stop

public void stop(int drainMillis)

Stops accepting, lets in-flight requests finish, then closes what is left.

The order matters. Closing the listener first means no new work arrives while the pool drains; draining before closing connections means a request already being served gets to produce its response instead of having the socket pulled out from under it, which is what a client sees as a truncated reply.

stop

public void stop()
Stops with a default drain window.