Backend API. Server-side code: this runs in a Codename One backend, not in the app on the device.
public final class HttpServer
- Object
- 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.Request | What a handler receives. |
class HttpServer.Part | One part of a multipart/form-data request body: a form field, or an uploaded file when it has a filename. |
class HttpServer.Response | What a handler returns. |
interface HttpServer.Handler | |
interface HttpServer.WebSocketHandler | Chooses the websocket endpoint for an upgrade request, or null when this router does not serve that path. |
interface HttpServer.WebSocketRoutes | Where websocket routes come from. |
interface HttpServer.WebSocketRegistry | What a WebSocketRoutes callback puts its endpoints into. |
Methods
Inherited methods
Method details
start
public static HttpServer start(String host, int port, int backlog, int workerCount, HttpServer.Handler handler)
throws IOExceptionThrows
start
public static HttpServer start(String host, int port, int backlog, int workerCount, HttpServer.Handler handler, Tls tls)
throws IOExceptiontls: terminate TLS here, or null to serve plaintext (correct behind a load balancer that already terminated it)
Throws
start
public static HttpServer start(String host, int port, int backlog, int workerCount, HttpServer.Handler handler, Tls tls, HttpServer.WebSocketRoutes webSockets)
throws IOExceptionwebSockets: 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.
Throws
isSecure
public boolean isSecure()getPort
public int getPort()getOpenConnections
public int getOpenConnections()getActiveRequests
public int getActiveRequests()getMetrics
public Map getMetrics()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()