Up

module Nethttpd_reactor

: sig

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.

#
class type http_processor_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 : Nethttpd_types.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 : Nethttpd_types.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 : Nethttpd_types.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.

#
val default_http_processor_config : http_processor_config

Default configuration: Extends Nethttpd_kernel.default_http_protocol_config with

#
class modify_http_processor_config : ?modify_http_protocol_config:(Nethttpd_kernel.http_protocol_config -> Nethttpd_kernel.http_protocol_config) option -> ?config_timeout_next_request:float option -> ?config_timeout:float option -> ?config_cgi:Netcgi.config option -> ?config_error_response:(Nethttpd_types.error_response_params -> string) option -> ?config_log_error:(Nethttpd_types.request_info -> string -> unit) option -> ?config_log_access:(Nethttpd_types.full_info -> unit) option -> 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 =
#
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.
#
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) option -> ?modify_http_processor_config:(http_processor_config -> http_processor_config) option -> ?config_reactor_synch:[
| `Connection
| `Close
| `Flush
| `Write
] option -> 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 =
#
method unlock : unit -> unit
#
method req_method : Nethttp.http_method
#
method response : Nethttpd_kernel.http_response
#
method log_access : unit -> unit

For private use only

#
class type http_reactive_request =
#
method environment : Nethttpd_types.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.

#
class http_reactor : http_reactor_config -> Unix.file_descr ->
#
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 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).

The http_reactor allows one to pull the next request from a connected client, and to deliver the response to the protocol engine.

#
val process_connection : http_reactor_config -> Unix.file_descr -> 'a Nethttpd_types.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.

Debugging

#
module Debug : sig
#
val enable : bool Pervasives.ref

Enables [root:Netlog]-style debugging of this module

end
end