(* $Id: nethttpd_reactor.mli 1411 2010-02-14 19:49:46Z 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 Nethttpd; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*)
(** {1 The reactive encapsulation of the HTTP daemon}
*
* This is a user-friendlier encapsulation of the HTTP daemon. It uses a
* "pull model": One pulls HTTP requests from the "reactor" one after the
* other. Request/response pairs have a common environment that represents
* the input and output facilities. Input and output are realised by
* [Netchannels], and the implementation details are completely hidden.
*
* This encapsulation can be easily used in a multi-threaded environment
* when for every arriving HTTP connection a separate thread is used.
*)
open Nethttp
open Nethttpd_types
class type http_processor_config =
object
(* This config is also used for engines *)
inherit Nethttpd_kernel.http_protocol_config
method config_timeout_next_request : float
(** Timeout in seconds to wait for the next request after the previous one
* has been completely received. (-1) means no timeout.
*)
method config_timeout : float
(** General timeout for network I/O (per I/O primitive).
(-1) means no timeout. *)
method config_cgi : Netcgi.config
(** The CGI configuration to use in the Netcgi environment *)
method config_error_response : error_response_params -> string
(** Get HTML error text for the HTTP status code. Must return a generic
* text for unknown codes.
*)
method config_log_error : request_info -> string -> unit
(** [config_log_error info msg]: Log the message [msg]. Information
about the request can be taken from [info]. The request may
only be partially available - be prepared that [info] methods
raise [Not_found].
*)
method config_log_access : full_info -> unit
(** Logs the access after the request/response cycle is complete.
The [cgi_properties] are from the environment. As there
is no automatic way of recording the last, finally used version of
this list, it is required that users call [log_props] of the extended
environment whenever the properties are updated. This is done by
all [Nethttpd] modules.
*)
end
val default_http_processor_config : http_processor_config
(** Default configuration: Extends
{!Nethttpd_kernel.default_http_protocol_config} with
- [config_timeout_next_request = 15.0]
- [config_timeout = 300.0]
- [config_cgi = ]{!Netcgi.default_config}
- [config_error_response =] {!Nethttpd_util.std_error_response}
- [config_log_error]: Uses {!Nethttpd_util.std_error_log_string}
to write a log message via {!Netlog}.
- [config_log_access]: is a no-op
*)
class modify_http_processor_config :
?modify_http_protocol_config:
(Nethttpd_kernel.http_protocol_config ->
Nethttpd_kernel.http_protocol_config) ->
?config_timeout_next_request:float ->
?config_timeout:float ->
?config_cgi:Netcgi.config ->
?config_error_response:(error_response_params -> string) ->
?config_log_error:(request_info -> string -> unit) ->
?config_log_access:(full_info -> unit) ->
http_processor_config -> http_processor_config
(** Modifies the passed config object as specified by the optional
arguments.
[modify_http_protocol_config]: This function can be used to modify the
parts of the config object that are inherited from [http_protocol_config].
For example:
{[
let new_cfg =
new modify_http_processor_config
~modify_http_protocol_config:
(new Nethttpd_kernel.modify_http_protocol_config
~config_suppress_broken_pipe:true)
~config_timeout:15.0
old_cfg
]}
*)
class type http_reactor_config =
object
inherit http_processor_config
method config_reactor_synch : [ `Connection | `Close | `Flush | `Write ]
(** Specifies when to synchronize output, i.e. force that all channel data are
* actually transmitted to the client:
* - [`Connection] means only at the end of the connection. This means that the
* channels of all pending requests may be buffered - needs a huge amount of
* memory
* - [`Close] means only when closing the output channel (after every response).
* This means that the whole response may be buffered - needs a lot of memory.
* - [`Flush] means only when the [flush] method is called. This is a good idea
* when one can control that.
* - [`Write] means every time the internal output buffer overflows. This is the
* recommended setting in general.
*)
end
val default_http_reactor_config : http_reactor_config
(** Default configuration: Extends
{!Nethttpd_reactor.default_http_processor_config} with
- [config_reactor_synch = `Write]
*)
class modify_http_reactor_config :
?modify_http_protocol_config:
(Nethttpd_kernel.http_protocol_config ->
Nethttpd_kernel.http_protocol_config) ->
?modify_http_processor_config:
(http_processor_config -> http_processor_config) ->
?config_reactor_synch:[ `Connection | `Close | `Flush | `Write ] ->
http_reactor_config -> http_reactor_config
(** Modifies the passed config object as specified by the optional
arguments.
[modify_http_protocol_config] and [modify_http_processor_config]:
These functions can be used to modify the
parts of the config object that are inherited from [http_protocol_config]
and [http_processor_config], respectively:
For example:
{[
let new_cfg =
new modify_http_reactor_config
~modify_http_protocol_config:
(new Nethttpd_kernel.modify_http_protocol_config
~config_suppress_broken_pipe:true)
~modify_http_processor_config:
(new Nethttpd_reactor.modify_http_processor_config
~config_timeout:15.0)
old_cfg
]}
*)
class type internal_environment =
object
inherit extended_environment
method unlock : unit -> unit
method req_method : http_method
method response : Nethttpd_kernel.http_response
method log_access : unit -> unit
end
(** For private use only *)
class http_environment : #http_processor_config ->
string -> string -> protocol -> http_header ->
Unix.sockaddr -> Unix.sockaddr ->
Netchannels.in_obj_channel -> int64 ref ->
Netchannels.out_obj_channel -> output_state ref ->
Nethttpd_kernel.http_response -> (unit -> unit) ->
bool ref -> int64 ->
internal_environment
(** For private use only *)
class type http_reactive_request =
object
method environment : extended_environment
(** The Netcgi environment representing the request header, the response header, and
* the channels to receive the request body and to send the response body.
* The channels are locked until either [accept_body] or [reject_body] have been
* called - using the channels before raises exceptions.
*
* This environment is not fully CGI-compatible. In particular, the following
* differences exist:
* - There is no [cgi_path_info] and no [cgi_path_translated].
* - The user is always unauthenticated.
* - The [Status] response header works as in CGI. The [Location] header, however,
* must be a full URL when set (only browser redirects)
* - When the request body is transmitted by chunked encoding, the header
* [Content-Length] is not set. In CGI this is interpreted as missing body.
* It is unlikely that clients send requests with chunked encoding, as this
* may cause interoperability problems anyway.
*
*)
method accept_body : unit -> unit
(** Call this method to unlock the body channels. In terms of HTTP, this sends the
* "100 Continue" response when necessary. One can reply with a positive or
* negative message.
*)
method reject_body : unit -> unit
(** Call this method to unlock the body channels. In terms of HTTP, this prevents
* sending the "100 Continue" response. Any arriving request body is silently
* discarded. One should immediately reply with an error mesage.
*)
method finish_request : unit -> unit
(** Reads the rest of the body (if any), and discards that data *)
method finish : unit -> unit
(** This method should be called after the request has been fully processed.
* It takes care that the HTTP protocol is fulfilled, and the next request
* can be properly detected and parsed. If the request body has not been
* fully read, this is now done, and its data are dropped. If the response
* is incomplete, it is completed. If the error is not recoverable, a "Server
* Error" is generated.
*)
end
(** The [http_reactor] allows one to pull the next request from a connected
* client, and to deliver the response to the protocol engine.
*)
class http_reactor : #http_reactor_config -> Unix.file_descr ->
object
method next_request : unit -> http_reactive_request option
(** Tries to read the next request. When the header of the request is successfully
* read, the method returns the request object (see above). It is connected
* with the socket and can read the request body.
*
* After receiving the request, one must either call [accept_body] when the
* request is acceptable and one want to reply afer evaluating the body, or
* invoke [reject_body] when the request can be denied without looking at the
* body. One must also call [accept_body] when there is not any body (it
* is a no-op then). The HTTP protocol explicitly forbids to perform the request
* when [reject_body] has been invoked ("[The origin server] MUST NOT
* perform the requested method if it returns a final status code").
*
* The response must be written to the Netcgi environment. Depending on
* [config_reactor_synch] the response is immediately transmitted to the
* client or at some specified time in the future (untransmitted data is buffered
* in this case).
*
* While transmitting output, the reactor is able to read the next request
* in the background when the limits for the pipeline size allows that.
*
* While receiving input, the reactor is able to write untransmitted response
* data in the background.
*
* It is {b an error} to call [next_request] again before the previous request
* is completely processed (you can ensure this by calling [finish]).
* In this case the HTTP connection is immediately shut down.
*
* The method [next_request] returns [None] when all requests of the
* connection are processed.
*)
method close : unit -> unit
(** Closes the file descriptor with a reliable method. This method must be
* called after [next_request] returned [None]. It can also be called at any
* time to shut down the connection prematurely (this means a lingering close,
* and may cost some time).
*)
end
val process_connection :
#http_reactor_config -> Unix.file_descr -> 'a http_service -> unit
(** Processes all HTTP requests in turn arriving at the file descriptor, and
* calls the service provider for every request. Finally, the descriptor is
* closed.
*
* All stages of HTTP processing, as defined by the service provider, are
* executed in the current thread.
*
* Any exceptions are caught and logged. The connection is immediately closed
* in this case.
*)
(** {1 Debugging} *)
module Debug : sig
val enable : bool ref
(** Enables {!Netlog}-style debugging of this module
*)
end
(**/**)
(* Internal: *)
val logged_error_response :
Unix.sockaddr ->
Unix.sockaddr ->
(string*string) option ->
int64 ->
bool ->
http_status ->
http_header option ->
string option ->
extended_environment option ->
Nethttpd_kernel.http_response option ->
http_processor_config ->
unit