# Module Nethttpd_kernel

    module Nethttpd_kernel: sig .. end

## The protocol kernel of the HTTP daemon

This module mainly defines the `http_protocol` class which implements the exchange of messages with a HTTP client. The request messages are represented as sequence of `req_token` values. The response is encapsulated in a separate `http_response` class. The contents of the response are represented as sequence of `resp_token` values.

    type fatal_error = [ `Broken_pipe
           | `Broken_pipe_ignore
           | `Message_too_long
           | `Server_error
           | `TLS_error of string * string
           | `Timeout
           | `Unix_error of Unix.error ]

These are the serious protocol violations after that the daemon stops any further processing.

Note that ``Timeout` refers to a timeout in the middle of a request. ``Broken_pipe_ignore` is the "harmless" version of ``Broken_pipe` (see `config_suppress_broken_pipe`).

Long messages are fatal because it is suspected that they are denial of service attacks. The kernel generates ``Message_too_long` only for long headers, not for long bodies.

Fatal server errors can happen when exceptions are not properly handled. As last resort the HTTP daemon closes the connection without notifying the client.

``TLS_error` means any error on the TLS level. The two strings identify the problem as for `Netsys_tls.Error`.

    val string_of_fatal_error : fatal_error -> string

Convert error to a string, for logging

    type bad_request_error = [ `Bad_header
           | `Bad_header_field of string
           | `Bad_request_line
           | `Bad_trailer
           | `Format_error of string
           | `Protocol_not_supported
           | `Request_line_too_long
           | `Unexpected_eof ]

A bad request is a violation where the current request cannot be decoded, and it is not possible to accept further requests over the current connection.

    val string_of_bad_request_error : bad_request_error -> string

Convert error to a string, for logging

    val status_of_bad_request_error : bad_request_error -> Nethttp.http_status

Returns the best response code for the error

    type data_chunk = Stdlib.Bytes.t * int * int

A `data_chunk` is a substring of a string. The substring is described by the triple `(s, pos, len)` where `s` is the container, `pos` is the position where the substring begins, and `len` its length.

    type status_line = int * string

= (code, phrase)

    type transfer_coding = [ `Chunked | `Identity ]

    type resp_token = [ `Resp_action of unit -> unit
           | `Resp_body of data_chunk
           | `Resp_end
           | `Resp_header of Nethttp.http_header
           | `Resp_info_line of status_line * Nethttp.http_header
           | `Resp_status_line of status_line
           | `Resp_trailer of Nethttp.http_trailer ]

The `resp_token` represents a textual part of the response to send:

- ``Resp_info_line` is an informational status line (code=100..199). There can be several informational lines, and they can be accompanied with their own headers. Such lines are only sent to HTTP/1.1 clients.
- ``Resp_status_line` is the final status line to send (code >= 200)
- ``Resp_header` is the whole response header to send
- ``Resp_body` is the next part of the response body to send.
- ``Resp_trailer` is the whole response trailer to send (currently ignored)
- ``Resp_action` is special because it does not directly represent a token to send. The argument is a function which is called when the token is the next token on the active event queue. The function is also called when the event queue is dropped because of an error (the state of the response object indicates this). The function must not raise exceptions except `Unix_error`, and it must not block.

    val resp_100_continue : resp_token

The predefined token for the "100 Continue" response

    type resp_state = [ `Active | `Dropped | `Error | `Inhibited | `Processed | `Queued ]

The response state:

- ``Inhibited` = it is not yet allowed to start the response
- ``Queued` = the response waits on the queue for activation
- ``Active` = the response is currently being transmitted
- ``Processed` = the response has been completely sent
- ``Error` = an error occurred during the transmission of this response
- ``Dropped` = an earlier response forced to close the connection, and this response is dequeued

    type front_token = [ `Resp_end | `Resp_wire_data of data_chunk ]

Tokens generated by `http_response`:

- ``Resp_wire_data` are data tokens.
- ``Resp_end` indicates the end of the response.

    exception Send_queue_empty

    type announcement = [ `As of string | `Ignore | `Ocamlnet | `Ocamlnet_and of string ]

See config

    class type http_response = object .. end

Encapsultation of the HTTP response for a single request

    class http_response_impl : ?close:bool -> ?suppress_body:bool -> int64 -> Nethttp.protocol -> announcement -> http_response

Exported for debugging and testing only

    val send_static_response : http_response ->
           Nethttp.http_status -> Nethttp.http_header option -> Stdlib.Bytes.t -> unit

Sends the string argument as response body, together with the given status and the header (optional). Response header fields are set as follows:

- The `Content-Length` is set to the length of the string.
- The `Content-Type` is set to "text/html" unless given by the header. If the header object is passed in, these modifications are done directly in this object as side effect.

    val send_file_response : http_response ->
           Nethttp.http_status ->
           Nethttp.http_header option -> Unix.file_descr -> int64 -> unit

Sends the contents of a file as response body, together with the given status and the header (optional). The descriptor must be a file descriptor (that cannot block). The int64 number is the length of the body. Response header fields are set as follows:

- The `Content-Length` is set to the length of the string.
- The `Content-Type` is set to "text/html" unless given by the header.

Note that `Content-Range` is not set automatically, even if the file is only partially transferred.

If the header object is passed in, these modifications are done directly in this object as side effect.

The function does not send the file immediately, but rather sets the `http_response` object up that the next chunk of the file is added when the send queue becomes empty. This file will be closed when the transfer is done.

    type request_line = Nethttp.http_method * Nethttp.protocol

The method (including the URI), and the HTTP version

    type req_token = [ `Bad_request_error of
               bad_request_error * http_response
           | `Eof
           | `Fatal_error of fatal_error
           | `Req_body of data_chunk
           | `Req_end
           | `Req_expect_100_continue
           | `Req_header of
               request_line * Nethttp.http_header *
               http_response
           | `Req_trailer of Nethttp.http_trailer
           | `Timeout ]

A `req_token` represents a textual part of the received request:

- ``Req_header` is the full received header. Together with the header, the corresponding `http_response` object is returned which must be used to transmit the response.
- ``Req_expect_100_continue` is generated when the client expects that the server sends a "100 Continue" response (or a final status code) now. One should add ``Resp_info_line resp_100_continue` to the send queue if the header is acceptable, or otherwise generate an error response. In any case, the rest of the request must be read until ``Req_end`.
- ``Req_body` is a part of the request body. The transfer-coding, if any, is already decoded.
- ``Req_trailer` is the received trailer
- ``Req_end` indicates the end of the request (the next request may begin immediately).
- ``Eof` indicates the end of the stream
- ``Bad_request_error` indicates that the request violated the HTTP protocol in a serious way and cannot be decoded. It is required to send a "400 Bad Request" response. The following token will be ``Eof`.
- ``Fatal_error` indicates that the connection crashed. The following token will be ``Eof`.
- ``Timeout` means that nothing has been received for a certain amount of time, and the protocol is in a state that the next request can begin. The following token will be ``Eof`.

Note that it is always allowed to `send` tokens to the client. The protocol implementation takes care that the response is transmitted at the right point in time.

    val string_of_req_token : req_token -> string

For debugging

    exception Recv_queue_empty

    class type http_protocol_config = object .. end

Configuration values for the HTTP kernel

    val default_http_protocol_config : http_protocol_config

Default config:

- `config_max_reqline_length = 32768`
- `config_max_header_length = 65536`
- `config_max_trailer_length = 32768`
- `config_limit_pipeline_length = 5`
- `config_limit_pipeline_size = 65536`
- `config_announce_server = `Ocamlnet`
- `config_suppress_broken_pipe = false`
- `config_tls = None`

    class modify_http_protocol_config : ?config_max_reqline_length:int -> ?config_max_header_length:int -> ?config_max_trailer_length:int -> ?config_limit_pipeline_length:int -> ?config_limit_pipeline_size:int -> ?config_announce_server:announcement -> ?config_suppress_broken_pipe:bool -> ?config_tls:Netsys_crypto_types.tls_config option -> http_protocol_config -> http_protocol_config

Modifies the passed config object as specified by the optional arguments

    class type http_protocol_hooks = object .. end

Allows it to set hooks for `Nethttpd_kernel.http_protocol`

    class http_protocol : #http_protocol_config -> Unix.file_descr -> object .. end

The core event loop of the HTTP daemon

    class lingering_close : ?preclose:unit -> unit -> Unix.file_descr -> object .. end

Closes a file descriptor using the "lingering close" algorithm.

## Debugging

    module Debug: sig .. end