Skip to main content

dox_http_native 3.0.0 copy "dox_http_native: ^3.0.0" to clipboard
dox_http_native: ^3.0.0 copied to clipboard

Fast native HTTP/1.1 server for Dart and the Dox framework. Rust (hyper) parses HTTP, your handlers stay in Dart. Implements the dart:io HttpServer API.

dox_http_native #

Native HTTP/1.1 server for Dart. It is the default HTTP server of Dox.

pub package license: MIT

Part of Dox, a web backend framework for Dart, like Laravel. Source code: github.com/dartondox/dox-http-native.

Install #

You usually do not add this package. dox_core depends on it and uses it by default. Add it only to use the server without Dox:

dart pub add dox_http_native

To see what is ready and what may still change, read Status and roadmap.

How it works #

  • Rust (hyper) owns the sockets and parses HTTP/1.1.
  • Your handlers stay in Dart.
  • It implements the dart:io HttpServer, HttpRequest and HttpResponse API. Code written for dart:io works unchanged.

The native library #

A build hook (hook/build.dart) gets the Rust library. It tries these in order:

  1. A path you set in your app pubspec.yaml (hooks: user_defines: dox_http_native: lib_path: ...).
  2. A local build in native/target/release, for the same OS and CPU.
  3. A ready-built library from the GitHub release, checked with sha256. There are builds for macOS (arm64, x64), Linux (x64, arm64) and Windows (x64).
  4. A build from source with cargo, when Rust is installed.

Outside the pub cache (this repo, or a path or git dependency), step 4 runs before step 3. The source there may be newer than the release.

So on these systems you do not need Rust. Use dart run, dart test or dart build cli. dart compile exe does not run build hooks.

Use it #

import 'dart:io';

import 'package:dox_http_native/dox_http_native.dart';

void main() async {
  NativeHttpServer server = await NativeHttpServer.bind(3000);
  server.listen((HttpRequest req) {
    req.response.write('Hello World');
    req.response.close();
  });
}

Dox always runs on this server. When the native library does not load, Dox stops at start and prints why (eg. an ABI mismatch) and how to fix it.

WebSocket #

server.listen((HttpRequest req) async {
  if (!NativeWebSocket.isUpgradeRequest(req)) return; // a normal request
  WebSocket ws = await NativeWebSocket.upgrade(
    req,
    protocol: 'chat', // optional subprotocol
    maxMessageSize: 1024 * 1024,
  );
  ws.listen((dynamic message) => ws.add('echo: $message'));
});

How it works:

  • Rust marks a request that can upgrade. Your Dart code runs first, like for any request: routing, middleware, the Origin check. Answer with a normal response (eg. 403) to refuse it.
  • NativeWebSocket.upgrade accepts it. Rust (tokio-tungstenite) sends the 101 and speaks the WebSocket protocol: ping and pong, the close handshake and the UTF-8 check of text.
  • A message or frame over maxMessageSize bytes closes the socket with 1009. Dart never gets it.
  • Compression (permessage-deflate) is never agreed.
  • Dart gets whole messages: a String for text, a Uint8List for binary. They come in the same batches as requests.
  • NativeWebSocket implements the dart:io WebSocket API.

Features #

  • Each isolate can bind the same port (SO_REUSEPORT on Linux, one shared socket on macOS).
  • Each isolate has its own Rust network thread. DOX_HTTP_THREAD=shared puts them on one thread.
  • 400 for bad requests, 431 for headers over 16 KB, 413 for bodies over maxBodySize (maxMultipartSize for a multipart form). A too big Content-Length with Expect: 100-continue gets 413 before the body is sent. Any other too big body is read and dropped first, so the client sees the 413.
  • 408 when the client sends no body bytes for bodyTimeout (idle time, default 120 seconds). A slow but steady upload is fine.
  • bind(port, address: '127.0.0.1') listens on one host. With no address it listens on all interfaces.
  • close() is graceful: no new connections, open requests get their answer, then it completes. close(force: true) closes every connection at once.
  • WebSocket upgrade with NativeWebSocket.upgrade, see above. detachSocket is not supported.
  • On a graceful close(), every open WebSocket gets close code 1001 (going away).
  • Streaming: a small body is sent in one piece on close. When addStream passes 64 KB, the answer starts and the rest of the body goes out in parts. A big file never sits in memory.

Documentation #

License #

MIT. See LICENSE.

1
likes
0
points
2.99k
downloads

Publisher

verified publisherdartondox.dev

Weekly Downloads

Fast native HTTP/1.1 server for Dart and the Dox framework. Rust (hyper) parses HTTP, your handlers stay in Dart. Implements the dart:io HttpServer API.

Homepage
Repository (GitHub)
View/report issues

License

unknown (license)

Dependencies

code_assets, crypto, hooks

More

Packages that depend on dox_http_native