Docs GODI Archive
Projects Blog Link DB

Search GODI:


More options
File lib/ocaml/pkg-lib/nethttpd-for-netcgi1/nethttpd_kernel.mli GODI Package godi-ocamlnet
Library nethttpd-for-netcgi1
 
   Nethttpd_kernel.html    nethttpd_kernel.cmi_pretty    nethttpd_kernel.mli    nethttpd_kernel.cmi_pretty    nethttpd_kernel.mli    Sources  
(* $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.