IoWebServer class final

An HTTP server on dart:io's HttpServer, made by IoWebServerFactory.

start binds the socket (with TLS when settings have ssl), and every request goes to handler as a ServerHttpRequest and ServerHttpResponse. A port in use is a PortInUseException, any other failure to listen a WebServerException. Some requests are answered before the handler, with a problem (application/problem+json):

  • a method that HttpMethod does not list: 501;
  • with server.ssl.client-auth=need, no client certificate: 403;
  • a malformed Host header, an HTTP/1.1 request without one, or an absolute target (GET http://a.example/ HTTP/1.1) whose host is not the Host header's: 400, as Tomcat answers;
  • an encoded /, \ or NUL in the path (%2F, %5C, %00): 400, as Tomcat answers by default, so ..%2F..%2Fsecret never reaches a path variable;
  • a . or .. segment that is left once matrix parameters are cut off (/files/..;x/secret): 400, so .. never reaches a path variable either;
  • a % escape in the path or the query that is malformed or not UTF-8 (/%FF, /%C0%AF, ?id=%FF): 400, as Tomcat answers.

dart:io keeps only the last of two Host headers, so a request with two is served for the last one (Tomcat answers 400). It also parses the request target before the server sees it, and keeps no raw form: a raw \ becomes /, so ..\ segments are resolved (/files/..\..\secret arrives as /secret), and raw bytes past ASCII are read as Latin-1 (Tomcat answers 400 to both). The router and the security rules see the same path, but a proxy in front that checks paths must refuse \ itself.

A request body that sends nothing for server.connection-timeout (60 s, Tomcat's connectionTimeout) while it is read fails with a 408 problem, and the connection closes after the answer. A body nobody reads is read and dropped after the answer: up to 2 MB, for at most 5 seconds, so the connection can serve the next request (as Tomcat's max-swallow-size); a longer or slower one closes the connection. An idle connection closes after the same timeout. There is no limit on the number of connections (Tomcat's max-connections, 8192): put a proxy in front, or rely on the system's limit of open files.

When a handler fails after the response was committed (the status and headers are out), the connection is dropped without finishing the response (no final chunk), as Tomcat does, so the client sees a broken response rather than a complete one.

A response header whose name or value dart:io cannot send (a non-ASCII character, a line break) fails before anything is sent: the header is dropped and the error answered as usual (a 500 problem). stop follows server.shutdown: gracefully, running requests may finish within the timeout; event streams and WebSocket sessions are closed at once in both modes.

dart:io itself accepts a request with both Content-Length and Transfer-Encoding: chunked (it reads the body as chunked), where RFC 9112 asks a server to refuse it; behind a proxy that reads such a request differently, requests can be smuggled. Put a proxy in front that refuses them (most do).

The Server header is not sent, nor X-XSS-Protection; dart:io's X-Frame-Options: SAMEORIGIN and X-Content-Type-Options: nosniff stay. dart:io's default Content-Type: text/plain; charset=utf-8 is not sent either: an answer whose type the application did not set has none, as with Tomcat. An answer that has no body by its status (1xx, 204, 304) gets no Content-Length and no Transfer-Encoding (RFC 9110 §8.6), a 304 or 1xx no Content-Type, and what is written to it is dropped, as Tomcat does.

The starter's lifecycle bean starts and stops it with the context; applications do not create one directly.

Implemented types

Constructors

IoWebServer(HttpHandler handler, ServerProperties settings)
A server that hands requests to handler and listens as settings say.

Properties

handler → HttpHandler
Answers every request; in the application, the dispatcherHandler.
final
hashCode → int
The hash code for this object.
no setterinherited
port → int
The port the server listens on (the real one when server.port is 0), or -1 before it started.
no setteroverride
runtimeType → Type
A representation of the runtime type of the object.
no setterinherited
settings → ServerProperties
The server.* settings: address, port, TLS, compression, shutdown.
final

Methods

noSuchMethod(Invocation invocation) → dynamic
Invoked when a nonexistent method or property is accessed.
inherited
start() → Future<void>
Binds the socket and starts answering requests; completes once the server listens. Throws a PortInUseException when the port is taken, a WebServerException for other failures.
override
stop({Duration? timeout}) → Future<void>
Stops the server. With server.shutdown=graceful it stops accepting connections and lets running requests finish for up to timeout (30 seconds when null), then closes what is left; open event streams and WebSocket sessions are closed at once.
override
toString() → String
A string representation of this object.
inherited

Operators

operator ==(Object other) → bool
The equality operator.
inherited