Skip to content
Sönke Ludwig edited this page Nov 5, 2017 · 1 revision

Design contraints

  • baseline API with no dynamic per-request memory allocations
  • layered on top is a (more or less) 0.8.1 compatible high level API, using structs instead of classes to enable a scoped API without requiring all users to add scope to their request handlers
  • keep a straight forward API (i.e. no indirect abstractions "IRequestWriter" or something like that)
  • support letting a connection "sleep" (no task allocated while waiting for the next request)
    • one task per request/response (mostly important for HTTP/2)
  • per-request memory must be safely managed (scoped and .dup'ed as soon as the user tries to escape it, either explicitly or implicitly)
  • HTTP/2 support must be developed within the existing license/copyright boundaries
  • no stream proxy objects or dynamic dispatch by default - all combinations of encryption/encoding/compression streams must be instantiated as static types
    • need to keep in mind how to minimize the amount of template bloat this produces

Possible API usage approaches

Linear-type like server request handling

This would be a possible approach for a low-level API with the goal of being as safe/robust, while avoiding any non-stack allocations.

  1. process request URL and method
  2. process request headers
  3. read request body
  4. write response code
  5. write response headers
  6. write response body
struct HTTPInterchange {
	struct HeaderReader {
		@disable this(this);
		BodyReader readHeaders(alias on_header)();
	}

	struct BodyReader {
		@disable this(this);
		ResponseWriter readBody(alias on_data)();
	}

	struct ResponseWriter {
		@disable this(this);
		HeaderWriter writeResponse(HTTPStatus status);
	}

	struct HeaderWriter {
		@disable this(this);

	}

	HeaderReader readRequest(alias on_request)();
}

void handler(HTTPInterchange req)
{
	req
		.readRequest((method, scope uri) {

		})
		.readHeaders((scope name, scope value) {

		})
		.readBody((scope data) {

		})
		.writeResponse(HTTPStatus.ok)
		.writeHeader("Set-Cookie", "foo=bar")
		.writeHeader("Content-Type", "text/plain")
		.writeBody((dst) {
			dst.write("Hello, World!");
		});
}

// return HTTPServerResponse object?
// multi-match router? what happens if first route has consumed the request, but didn't write a response?

A drawback of this approach is that each API call would have to determine the static stream type all over again (e.g. ChunkedOutputStream(TLSStream(TCPConnection))).

Clone this wiki locally