(* $Id: nethttpd_kernel.mli 1063 2006-12-17 20:54:34Z gerd $
*
*)
(*
* Copyright 2005 Baretta s.r.l. and Gerd Stolpmann
*
* This file is part of Nethttpd.
*
* Nethttpd is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Nethttpd is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with WDialog; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*)
(** {1 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.
*)
(* HTTP protocol kernel for daemon *)
open Nethttp
open Nethttpd_types
type fatal_error =
[ `Broken_pipe
| `Message_too_long
| `Timeout
| `Unix_error of Unix.error
| `Server_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.
*
* 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.
*)
val string_of_fatal_error : fatal_error -> string
(** Convert error to a string, for logging *)
type bad_request_error =
[ `Bad_header_field of string
| `Bad_header
| `Bad_trailer
| `Bad_request_line
| `Request_line_too_long
| `Protocol_not_supported
| `Unexpected_eof
| `Format_error of string
]
(** 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 -> http_status
(** Returns the best response code for the error *)
type data_chunk = string * 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 =
[ `Identity
| `Chunked
]
type resp_token =
[ `Resp_info_line of (status_line * http_header)
| `Resp_status_line of status_line
| `Resp_header of http_header
| `Resp_body of data_chunk
| `Resp_trailer of http_trailer
| `Resp_end
| `Resp_action of (unit -> unit)
]
(** 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 =
[ `Inhibited | `Queued | `Active | `Processed | `Error | `Dropped ]
(** 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_wire_data of data_chunk
| `Resp_end
]
(** 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 =
[`Ignore | `Ocamlnet | `Ocamlnet_and of string | `As of string ]
(** See config *)
(** Encapsultation of the HTTP response for a single request *)
class type http_response =
object
(** Represents the action of sending the response
*
* This class has an internal
* queue of response tokens that are not yet processed. One can easily add
* new tokens to the end of the queue ([send]).
*
* The class is responsible for determining the transfer encoding:
* - When the HTTP version is 1.0, the encoding is always "identity", and the
* connection will be closed after the response.
* - When the HTTP version is 1.1, and there is a Content-length header,
* the encoding will be selected as "identity". It is checked whether the
* body has really this length. If too short, it is suggested to close
* the connection. If too long, the extra part of the message is silently
* dropped.
* - When the HTTP version is 1.1, and there is no Content-length header,
* the encoding will be selected as "chunked".
*
* Currently, the [TE] request header is not taken into account. The trailer
* is always empty.
*
* The following headers are set (or removed) by this class:
* - [Transfer-Encoding]
* - [Trailer]
* - [Date]
* - [Connection]
* - [Upgrade]
* - [Server] (it is appended to this field)
*
* Responses for HEAD requests have the special behaviour that the body is silently
* dropped. The calculation of header fields is not affected by this. This means
* that HEAD can be easily implemented by doing the same as for GET.
*
* Responses for other requests that must not include a body must set
* [Content-Length] to 0.
*)
(** These methods can be called by the content provider: *)
method state : resp_state
(** Reports the state. The initial state is [`Inhibited] *)
method bidirectional_phase : bool
(** The bidrectional phase starts after "100 Continue" has been sent to the
* client, and stops when the response body begins. The bidirectional phase
* is special for the calculation of timeout values (input determines the timeout
* although the response has started).
*)
method send : resp_token -> unit
(** Add token to the end of the send queue *)
method send_queue_empty : bool
(** Return whether the send queue is empty. When the state is [`Inhibited], this
* method fakes an empty queue.
*)
method protocol : protocol
(** The HTTP version of the response. This is currently always HTTP/1.1, but maybe
* we need to fake lower versions for buggy clients. Let's see what comes.
*)
method close_connection : bool
(** Returns whether the connection should be closed after this response.
* This flag should be evaluated when the [`Resp_end] front token has been
* reached.
*)
method transfer_encoding : transfer_coding
(** Returns the selected transfer encoding. This is valid after the header
* has been passed to this object with [send].
*)
method front_token : front_token
(** The first token of the queue, represented as [data_chunk]. Raises
* [Send_queue_empty] when there is currently no front token, or the state
* is [`Inhibited].
* If there is a front token, it will never have length 0.
*
* Note that [Unix_error] exceptions can be raised when [`Resp_action]
* tokens are processed.
*)
method set_callback : (unit -> unit) -> unit
(** The function will be called when either [set_state] changes the state,
* or when the send queue becomes empty. Note that the callback must never
* fail, it is called in situations that make it hard to recover from errors.
*)
(** These methods must only be called by the HTTP protocol processor: *)
method set_state : resp_state -> unit
(** Sets the state *)
method advance : int -> unit
(** Tell this object that [n] bytes of the front token could be really
* sent using [Unix.write]. If this means that the whole front token
* has been sent, the next token is pulled from the queue and is made
* the new front token.