(* $Id: nethttpd_plex.mli 2195 2015-01-01 12:23:39Z gerd $ *) (** {1 Netplex support} *) (** The important function is [nethttpd_factory], see below. The other functions are only needed for special effects. An example is explained here: {!Netplex_intro.webserver} *) type config_log_error = Nethttpd_types.request_info -> string -> unit type config_log_access = Nethttpd_types.full_info -> unit type config_error_response = Nethttpd_types.error_response_params -> string (** Three type abbreviations for logging functions *) val std_log_error : Netplex_types.container -> config_log_error (** Returns a function that logs errors using the [log_subch] method of the passed container *) val std_log_access : ?debug:bool -> Netplex_types.container -> config_log_access (** Returns a function that logs accesses using the [log_subch] method of the passed container If [debug] is set, additional debug log messages are printed that dump the whole access (incl. header and all available information) *) val std_error_response : config_error_response (** A sample error response function *) val restrict_file_service_config : Netplex_types.config_file -> Netplex_types.address -> unit (** Restricts the subsections and paremeters in the [service] configuration section of type "file" to the allowed ones. *) val read_file_service_config : Netplex_types.config_file -> Netplex_types.address -> string -> Nethttpd_services.file_service (** [read_file_service_config cfg addr uri_path]: Reads the [service] configuration section of type "file" from config file [cfg] at address [addr]. [uri_path] is the default value put into the [file_uri] component of the returned record if no "uri" configuration parameter exists. (In other words, this is the path of the enclosing "uri" section, or "/" if there is only a "host" section.) All other parameters are only taken from the configuration section. See below at [nethttpd_factory] how a file service needs to be configured. *) val restrict_dynamic_service_config : Netplex_types.config_file -> Netplex_types.address -> unit (** Restricts the subsections and paremeters in the [service] configuration section of type "dynamic" to the allowed ones. *) val read_dynamic_service_config : (string * (Netplex_types.config_file -> Netplex_types.address -> string -> 'a Nethttpd_services.dynamic_service ) ) list -> Netplex_types.config_file -> Netplex_types.address -> string -> 'a Nethttpd_services.dynamic_service (** [read_dynamic_service_config handlers cfg addr uri_path]: Reads the [service] configuration section of type "dynamic" from config file [cfg] at address [addr]. The alist [handlers] defines the available handlers. Every handler [h] is called like [h cfg addr uri_path]. [uri_path] is like in [read_file_service_config], i.e. the path of the enclosing "uri" section, or "/" by default. The [h] function has to return the dynamic service to use, which is also returned by [read_dynamic_service_config]. See below at [nethttpd_factory] how a dynamic service needs to be configured. *) type encap = [ `Reactor | `Engine ] val nethttpd_processor : ?hooks:Netplex_types.processor_hooks -> ?encap:encap -> (Netplex_types.container -> #Nethttpd_reactor.http_reactor_config) -> 'a Nethttpd_types.http_service -> Netplex_types.processor (** [netplex_processor mk_config http_service]: Creates a Netplex processor * for Nethttpd. * * [mk_config] determines the nethttpd config for a container. * This is especially useful for setting the logging functions. * * The resulting processor must be turned into a full Netplex service * by [Netplex_sockserv.create_socket_service] which can then be added * by calling the controller's method [add_service]. * * [hooks]: One can pass a Netplex hook object to set the hooks of the * processor. * * [encap]: Selects the encapsulation, [`Reactor] or [`Engine]. * The default is [`Reactor]. Each encapsulation has specific strengths * and weaknesses: * - [`Reactor] is simpler code. Also, the request and response bodies * need not to be buffered up, and are directly connected with the * underlying socket (low memory requirement). The disadvantage is * that a reactor processes TCP connections serially (important to know * when there is only a single Unix process) * - [`Engine]: The request body needs to be completely buffered up. * If pipelining is enabled, the response bodies are also buffered * (FIXME). * The advantage of this encapsulation is that the engine can * process multiple TCP connections simultaneously, even in a * single process/thread. *) type ('a,'b) service_factory = (string * 'a Nethttpd_services.dynamic_service) list -> Netplex_types.config_file -> Netplex_types.address -> string -> 'b Nethttpd_types.http_service constraint 'b = [ `Dynamic_service of 'a Nethttpd_services.dynamic_service | `File_service of Nethttpd_services.file_service ] (** The service factory function is called when a [service] configuration section of a certain type needs to be read. The function has args [handlers], [cfg], [addr], and [uri_path]. It needs to return the [http_service]. Such a function is usually [read_file_service_config], or [read_dynamic_service_config], or a derivative, whose return value is turned into a [http_service]. This can be done with {!Nethttpd_services.file_service} and {!Nethttpd_services.dynamic_service}. *) val default_services : (string * ('a,'b) service_factory) list (** The default services *) type httpd_factory = { httpd_factory : 'a . (Netplex_types.container -> Nethttpd_reactor.http_reactor_config) -> 'a Nethttpd_types.http_service -> Netplex_types.processor } (** The type of the [nethttpd_processor] function *) val nethttpd_factory : ?name:string -> ?hooks:Netplex_types.processor_hooks -> ?encap:encap -> ?config_cgi:Netcgi.config -> ?handlers:(string * 'a Nethttpd_services.dynamic_service) list -> ?services:(string * ('a,'b) service_factory) list -> ?log_error:(Netplex_types.container -> config_log_error) -> ?log_access:(?debug:bool -> Netplex_types.container -> config_log_access) -> ?error_response:config_error_response -> ?processor_factory:httpd_factory -> ?tls:(module Netsys_crypto_types.TLS_PROVIDER) -> unit -> Netplex_types.processor_factory (** Factory for a web server component. * * {b Configuration file.} See below. * * The [services] optional argument can be used to change the service * types understood. If not passed, it defaults to [default_services]. * The default includes "file" and "dynamic". * * {b Arguments.} * * - [name]: The processor name. Defaults to "nethttpd". This name can * be referenced by the "type" parameters in the [processor] section * of the config file. * - [hooks]: One can pass a Netplex hook object to set the hooks of the * processor. (This argument is ignored if a [processor_factory] is * passed to this function.) * - [encap]: See {!Nethttpd_plex.nethttpd_processor}. (This argument is * ignored if a [processor_factory] is * passed to this function.) * - [config_cgi]: The CGI configuration to use * - [handlers]: a list of handler function. These functions can be * referenced from a [service] section in the config file where * [type="dynamic"] (see example above). Defaults to the empty list. * - [services]: A list of service handlers that can be used * by [service] sections in the config files. Defaults to * {!Nethttpd_plex.default_services} which defines "file" and "dynamic". * - [log_error]: The error logger. Defaults to * {!Nethttpd_plex.std_log_error}. * - [log_access]: The access logger. Defaults to * {!Nethttpd_plex.std_log_access}. * - [error_response]: a handler which is invoked to generate error * responses. Defaults to {!Nethttpd_plex.std_error_response}. * - [processor_factory]: the function creating the processor. * Default is [nethttpd_processor]. * - [tls]: the TLS provider to use. By default, * {!Netsys_crypto.current_tls_opt} is used. *) (** {2 Configuration files} The configuration file understood by [nethttpd_factory] looks like: {[ processor { type = "nethttpd"; (* or what is passed as "name" arg *) timeout = 300.0; timeout_next_request = 15.0; access_log = "enabled"; suppress_broken_pipe = true; host { pref_name = "myhost"; (* optional *) pref_port = 80; (* optional *) names = "myhost:80 yourhost:81"; (* use *:0 for any name *) uri { path = "/the/path"; method { allow = "GET POST"; (* or: deny = "..." *) service { type = "..."; ... } } } uri { ... } } host { ... } } ]} The [access_log] parameter can be set to [off], [enabled], or [debug]. The default is [off]. Access messages go to the "access" subchannel of the component logger. If [enabled], one line is printed with the most important data. If [debug] is set, all access data are printed. If [suppress_broken_pipe] the error "Broken pipe" is not logged in the error log. This error occurs frequently, and may be regarded as a normal condition. The sections [host], [uri] and [method] can be nested to any depth. However, on every nesting level only one of these section types must be used. For example, if a [host] section already contains [uri] subsections, it is not allowed to add [method] subsections. Furthermore, the outermost section must be [host]. The [service] section may be one of (at least if the [services] parameter is not overridden): {[ service { type = "file"; docroot = "/a/path/in/the/filesystem"; uri = "/the/uri/prefix/corresponding/to/docroot"; media_types_file = "/etc/mime.types"; media_type { type = "application/foo"; suffix = "foo" } default_media_type = "text/plain"; enable_gzip = true; (* see doc in nethttpd_services.mli *) index_files = "index.html"; enable_listings = true; hide_from_listings = "README"; (* list of PCRE regexps *) } ]} Note that [uri] is taken from the surrounding [uri] section (or assumed to be "/" if there is none) if omitted. {[ service { type = "dynamic"; handler = "name_of_handler"; } ]} Binds the passed handler here. Any of [host], [uri], and [method] sections may contain one or several [access] sections (which are AND-connected): {[ access { type = "host"; allow = "host1 host2 ..."; (* or deny = "host1 host2 ..."; *) } ]} Other access control methods are not yet available. *) (** {2:tls Configuring TLS} First of all, there needs to be a TLS provider. See {!Tls} for more information how to get one. If the TLS provider is initialized, you can have a [tls] subsection inside [processor], like: {[ processor { ... tls { x509 { trust { crt_file = "ca.pem"; } key { crt_file = "server.crt"; key_file = "server.key"; } } } } ]} All of the files, [ca.pem], [server.crt] and [server.key] need to be PEM-encoded. You can have several [key] sub-sections when you want to do name-based virtual hosting. Note, however, that this relies on the SNI extension of the TLS protocol, and not all clients support this extension. Further parameters inside [tls]: - [algorithms]: This is a string describing the cipher suites and protocol options that are in effect. This string is provider-specific. (GnuTLS calls this string the "priority string".) Example: {[ tls { ... algorithms = "SECURE-128 !ARCFOUR-128"; } ]} - [dh_params]: This sub-section may set DH parameters. Example: {[ tls { ... dh_params { pkcs3_file = "/path/to/pkcs3_file"; } } ]} - [peer_auth]: This string parameter may enable client certificates. Set it to "required" to enforce such a certificate. {[ tls { ... peer_auth = "required"; } ]} *)