Skip to content

Handler

[Source]

This is the interface through which HTTP requests are delivered to application code and through which HTTP responses are sent to the underlying connection.

Instances of a Handler are executed in the context of the Session actor so most of them should be passing data on to a processing actor.

Each Session must have a unique instance of the handler. The application code does not necessarily know when an Session is created, so the application must provide an instance of HandlerFactory that will be called at the appropriate time.

Receiving Requests

When an Request is received on an Session actor, the corresponding Handler.apply method is called with the request and a RequestID. The Request contains the information extracted from HTTP Headers and the Request Line, but it does not contain any body data. It is sent to Handler.apply before the body is fully received.

If the request has a body, its raw data is sent to the Handler.chunk method together with the RequestID of the request it belongs to.

Once all body data is received, Handler.finished is called with the RequestID of the request it belongs to. Now is the time to act on the full body data, if it hasn't been processed yet.

The RequestID must be kept around for sending the response for this request. This way the session can ensure, all responses are sent in the same order as they have been received, which is required for HTTP pipelining. This way processing responses can be passed to other actors and processing can take arbitrary times. The Session will take care of sending the responses in the correct order.

It is guaranteed that the call sequence is always:

  • exactly once: apply(request_n, requestid_n)
  • zero or more times: chunk(data, requestid_n)
  • exactly once: finished(requestid_n)

And so on for requestid_(n + 1). Only after finished has been called for a RequestID, the next request will be received by the Handler instance, there will be no interleaving. So it is save to keep state for the given request in a Handler between calls to apply and finished.

Failures and Cancelling

If a Session experienced faulty requests, the Handler is notified via Handler.failed.

If the underlying connection to a Session has been closed, the Handler is notified via Handler.closed.

Sending Responses

A handler is instantiated using a HandlerFactory, which passes an instance of Session to be used in constructing a handler.

A Session is required to be able to send responses. See the docs for Session for ways to send responses.

Example Handler:

use "http"
use "valbytes"

class MyHandler is Handler
  let _session: Session

  var _path: String = ""
  var _body: ByteArrays = ByteArrays

  new create(session: Session) =>
    _session = session

  fun ref apply(request: Request val, request_id: RequestID): Any =>
    _path = request.uri().path

  fun ref chunk(data: ByteSeq val, request_id: RequestID) =>
    _body = _body + data

  fun ref finished(request_id: RequestID) =>
    _session.send_raw(
      Responses.builder()
        .set_status(StatusOk)
        .add_header("Content-Length", (_body.size() + _path.size() + 13).string())
        .add_header("Content-Type", "text/plain")
        .finish_headers()
        .add_chunk("received ")
        .add_chunk((_body = ByteArrays).array())
        .add_chunk(" at ")
        .add_chunk(_path)
        .build(),
      request_id
    )
    _session.send_finished(request_id)
interface ref Handler

Public Functions

apply

[Source]

fun ref apply(
  request: Request val,
  request_id: USize val)
: Any tag

Parameters

Returns


chunk

[Source]

Notification of incoming body data. The body belongs to the most recent Request delivered by an apply notification.

fun ref chunk(
  data: (String val | Array[U8 val] val),
  request_id: USize val)
: None val

Parameters

Returns


finished

[Source]

Notification that no more body chunks are coming. Delivery of this HTTP message is complete.

fun ref finished(
  request_id: USize val)
: None val

Parameters

Returns


cancelled

[Source]

Notification that sending a response has been cancelled locally, e.g. by closing the server or manually cancelling a single request.

fun ref cancelled(
  request_id: USize val)
: None val

Parameters

Returns


failed

[Source]

Notification about failure parsing HTTP requests.

fun ref failed(
  reason: ((TooLarge val | UnknownMethod val | InvalidURI val | 
    InvalidVersion val | InvalidContentLength val | InvalidTransferCoding val | 
    InvalidChunk val) & _RequestParseError val),
  request_id: USize val)
: None val

Parameters

Returns


closed

[Source]

Notification that the underlying connection has been closed.

fun ref closed()
: None val

Returns


throttled

[Source]

Notification that the session temporarily can not accept more data.

fun ref throttled()
: None val

Returns


unthrottled

[Source]

Notification that the session can resume accepting data.

fun ref unthrottled()
: None val

Returns