Warning: Reason support is experimental. We are looking for beta-tester and contributors.

Module Ocsigen_extensions

module Ocsigen_extensions : sig..end

Writing extensions for Ocsigen


include Ocsigen_command
module Ocsigen_request_info : 
  module type of Ocsigen_request_info
with type request_info = Ocsigen_request_info.request_info
and type file_info = Ocsigen_request_info.file_info
and type ifrange = Ocsigen_request_info.ifrange
exception Ocsigen_http_error of (Ocsigen_cookies.cookieset * int)
exception Bad_config_tag_for_extension of string

Xml tag not recognized by an extension (usually not a real error)

exception Error_in_config_file of string

Error in a <site> tag inside the main ocsigen.conf file

exception Error_in_user_config_file of string

Option incorrect in a userconf file

val badconfig : ('a, unit, string, 'b) Pervasives.format4 -> 'a

Convenient function for raising Error_in_config_file exceptions with a sprintf-formatted argument.

type virtual_hosts = (string * Netstring_pcre.regexp * int option) list

Type of the result of parsing the field hostfiler in the configuration file. Inside the list, the first argument is the host itself (which is a glob-like pattern that can contains *), a regexp parsing this pattern, and optionnaly a port.

val hash_virtual_hosts : virtual_hosts -> int
val equal_virtual_hosts : 
  virtual_hosts ->
  virtual_hosts -> bool
val host_match : 
  virtual_hosts:virtual_hosts ->
  host:string option -> port:int -> bool
type do_not_serve = {
  do_not_serve_regexps: string list;  do_not_serve_files: string list;  do_not_serve_extensions: string list;}

Configuration to hide/forbid local files

exception IncorrectRegexpes of do_not_serve
val do_not_serve_to_regexp : do_not_serve -> Netstring_pcre.regexp

Compile a do_not_serve structure into a regexp. Raises IncorrectRegexpes if the compilation fails. The result is memoized for subsequent calls with the same argument

val join_do_not_serve : 
  do_not_serve ->
  do_not_serve -> do_not_serve
type config_info = {
  default_hostname: string;  default_httpport: int;  default_httpsport: int;  default_protocol_is_https: bool;  mime_assoc: Ocsigen_charset_mime.mime_assoc;  charset_assoc: Ocsigen_charset_mime.charset_assoc;  default_directory_index: string list;  list_directory_content: bool;  follow_symlinks: follow_symlink;  do_not_serve_404: do_not_serve;  do_not_serve_403: do_not_serve;  uploaddir: string option;  maxuploadfilesize: int64 option;}

Configuration options, passed to (and modified by) extensions

type client = Ocsigen_http_com.connection

A value of this type represents the client who did the request.

val client_id : client -> int

Returns the id number of the connection

val client_connection : client -> Ocsigen_http_com.connection

Returns the connection

type ifrange = Ocsigen_request_info.ifrange  =  | IR_No | IR_Ifunmodsince of float | IR_ifmatch of string
type file_info = Ocsigen_request_info.file_info  = {
  tmp_filename: string;  filesize: int64;  raw_original_filename: string;  original_basename: string;  file_content_type: ((string * string) * (string * string) list) option;}
type request_info = Ocsigen_request_info.request_info
type request = {
  request_info: request_info;  request_config: config_info;}
exception Ocsigen_Is_a_directory of 
  (Ocsigen_request_info.request_info -> Neturl.url)
type answer =  | Ext_do_nothing(* <<div class="odocwiki_info"|~I don~'t want to do anything
>> *) | Ext_found of (unit -> Ocsigen_http_frame.result Lwt.t)(* <<div class="odocwiki_info"|"~O~K stop! ~I will take the page~.
      ~You can start the following request of the same pipelined connection~.
      ~Here is the function to generate the page"~.
      ~The extension must return ~Ext~_found as soon as possible
      when it is sure it is safe to start next request~.
      ~Usually as soon as you know that the result will be ~Ext~_found~.
      ~But in some case~, for example proxies~, you don~'t want the request of
      one connection to be handled in different order~.
      ~In that case~, wait to be sure that the new request will not
      overtake this one~.
>> *) | Ext_found_stop of (unit -> Ocsigen_http_frame.result Lwt.t)(* <<div class="odocwiki_info"|~Found but do not try next extensions
>> *) | Ext_next of int(* <<div class="odocwiki_info"|~Page not found~. ~Try next extension~.
                        ~The integer is the ~H~T~T~P error code~.
                        ~It is usally ~4~0~4~, but may be for ex ~4~0~3 ~(forbidden~)
                        if you want another extension to try after a ~4~0~3~.
                        ~Same as ~Ext~_continue~_with but does not change
                        the request~.
>> *) | Ext_stop_site of (Ocsigen_cookies.cookieset * int)(* <<div class="odocwiki_info"|~Error~. ~Do not try next extension~, but
      try next site~.
      ~The integer is the ~H~T~T~P error code~, usally ~4~0~3~.
>> *) | Ext_stop_host of (Ocsigen_cookies.cookieset * int)(* <<div class="odocwiki_info"|~Error~. ~Do not try next extension~,
      do not try next site~,
      but try next host~.
      ~The integer is the ~H~T~T~P error code~, usally ~4~0~3~.
>> *) | Ext_stop_all of (Ocsigen_cookies.cookieset * int)(* <<div class="odocwiki_info"|~Error~. ~Do not try next extension ~(even filters~)~,
      do not try next site~,
      do not try next host~,
      do not ~.
      ~The integer is the ~H~T~T~P error code~, usally ~4~0~3~.
>> *) | Ext_continue_with of (request * Ocsigen_cookies.cookieset * int)(* <<div class="odocwiki_info"|~Used to modify the request before giving it to next extension~.
      ~The extension returns the request~_info ~(possibly modified~)
      and a set of cookies if it wants to set or cookies
      ~(<<span class="odocwiki_inlinecode"|!~Ocsigen~_cookies~.~Cookies~.empty>> for no cookies~)~.
      ~You must add these cookies yourself in request~_info if you
      want them to be seen by subsequent extensions~,
      for example using <<a_api | val Ocsigen_http_frame.compute_new_ri_cookies >>~.
      ~The integer is usually equal to the error code received
      from preceding extension ~(but you may want to modify it~)~.
>> *) | Ext_retry_with of request * Ocsigen_cookies.cookieset(* <<div class="odocwiki_info"|~Used to retry all the extensions with a new request~_info~.
      ~The extension returns the request~_info ~(possibly modified~)
      and a set of cookies if it wants to set or cookies
      ~(<<span class="odocwiki_inlinecode"|!~Ocsigen~_cookies~.~Cookies~.empty>> for no cookies~)~.
      ~You must add these cookies yourself in request~_info if you
      want them to be seen by subsequent extensions~,
      for example using <<a_api | val Ocsigen_http_frame.compute_new_ri_cookies >>~.
>> *) | Ext_sub_result of extension2(* <<div class="odocwiki_info"|~Used if your extension want to define option that may contain
      other options from other extensions~.
      ~In that case~, while parsing the configuration file~, call
      the parsing function ~(of type <<span class="odocwiki_inlinecode"|parse~_fun>>~)~,
      that will return something of type <<span class="odocwiki_inlinecode"|extension~2>>~.
>> *) | Ext_found_continue_with of 
    (unit ->
     (Ocsigen_http_frame.result * request) Lwt.t)
(* <<div class="odocwiki_info"|~Same as <<span class="odocwiki_inlinecode"|~Ext~_found>> but may modify the request~. >> *)
 | Ext_found_continue_with' of (Ocsigen_http_frame.result * request)(* <<div class="odocwiki_info"|~Same as <<span class="odocwiki_inlinecode"|~Ext~_found~_continue~_with>> but does not allow to delay the computation of the page~. ~You should probably not use it~, but for output filters~. >> *)
type request_state =  | Req_not_found of (int * request) | Req_found of (request * Ocsigen_http_frame.result)
type extension2 = 
  (unit -> unit) ->
  Ocsigen_cookies.cookieset ->
  request_state -> (answer * Ocsigen_cookies.cookieset) Lwt.t
type extension = request_state -> answer Lwt.t

For each <site> tag in the configuration file, you can set the extensions you want. Each extension is implemented as a function, taking the charset found in configuration file, the current state of the request, and returning an answer. If no page has been generated so far (Req_not_found), it receive the error code given by the previous extension (default 404), and the request information. If a page has been generated by previous extensions (case Req_found), the extension may want to modify the result (filters).

type parse_fun = Simplexmlparser.xml list -> extension2
type parse_host

Type of the functions parsing the content of a <host> tag

type userconf_info = {
  localfiles_root: string;}

Information received by extensions accepting userconf files.

The parameter localfiles_root is an absolute path to the directory that the user is allowed to serve. This is used by staticmod, to disallow the user from allowing access to outside of this directory

type parse_config = 
  virtual_hosts ->
  config_info -> parse_config_aux

parse_config is the type of the functions parsing a <site> tag (and returning an extension). Those are functions taking

  • the name of the virtual <host>

that will be called for each <host>, and that will generate a function taking:

  • the path attribute of a <site> tag

that will be called for each <site>, and that will generate a function taking:

  • an item of the config file

that will be called on each tag inside <site> and:

  • raise Bad_config_tag_for_extension if it does not recognize that tag
  • return something of type extension (filter or page generator)

parse_config_user is the type of functions parsing a site tag inside an userconf file. They take one more parameter, of type userconf_info

type parse_config_user = userconf_info -> parse_config
type parse_config_aux = 
  Ocsigen_lib.Url.path ->
  parse_host ->
  parse_fun ->
  Simplexmlparser.xml -> extension
val register_extension : 
  name:string ->
  ?fun_site:parse_config ->
  ?user_fun_site:parse_config_user ->
  ?begin_init:(unit -> unit) ->
  ?end_init:(unit -> unit) ->
  ?init_fun:(Simplexmlparser.xml list -> unit) ->
  ?exn_handler:(exn -> string) -> ?respect_pipeline:bool -> unit -> unit

For each extension generating pages, we register its name and six functions:

  • a function fun_site of type parse_config. This function will be responsible for handling the options of the configuration files that are recognized by the extension, and potentially generating a page.
  • a function user_fun_site of type parse_user_config which has the same role as fun_site, but inside userconf files. Specify nothing if your extension is disallowed in userconf files. Otherwise, compared to fun_site, you can selectively disallow some options, as user_fun_site must define only safe options (for example it is not safe to allow such options to load a cmo specified by a user, or to execute a program, as this program will be executed by ocsigen's user). Note that user_fun_site will be called for every request, whereas the fun_site is called only when starting or reloading the server.
  • a function begin_init that will be called at the beginning of the initialisation phase of each site, and each time the config file is reloaded.
  • a function end_init that will be called at the end of the initialisation phase of each site
  • a function init_fun that will be called just before registering the extension, taking as parameter the configuration options between <extension> and </extension>. This allows to give configuration options to extensions. If no function is supplied, the extension is supposed to accept no option (and loading will fail if an option is supplied) See <<a_api module="Ocsigen_extensions.Configuration" | val process_elements >> for the easy construction of such a function.
  • a function exn_handler that will create an error message from the exceptions that may be raised during the initialisation phase, and raise again all other exceptions

Moreover, if the optional parameter ?respect_pipeline is true, the extension will ask the server to respect the order of the pipeline. That means that it will wait to be sure that the previous request from the same connection has been taken by an extension before giving a request to an extension. Use this to write proxies extensions, when you want to be able to pipeline the requests you to another server. It is false by default.

module Configuration : sig..end

This modules contains types and constructor for the description of XML configurations and the accordingly parsing.

val get_hostname : request -> string

Returns the hostname to be used for absolute links or redirections. It is either the Host header or the hostname set in the configuration file.

val get_port : request -> int

Returns the port to be used for absolute links or redirections. It is either:

  • the port the server is listening at
  • or the port in the Host header
  • or the default port set in the configuration file.
val new_url_of_directory_request : 
  request ->
  request_info -> Neturl.url

new_url_of_directory_request create a redirection and generating a new url for the client (depending on the server configuration and request)

val ri_of_url : 
  ?full_rewrite:bool ->
  string ->
  request_info -> request_info

Parsing URLs. This allows to modify the URL in the request_info. (to be used for example with Ext_retry_with or Ext_continue_with)

User directories

Exception raised when an non-existing user is found

exception NoSuchUser
type ud_string

The type for string that may contain a $u(...)

val parse_user_dir : string -> ud_string
val replace_user_dir : 
  Netstring_pcre.regexp ->
  ud_string -> string -> string

raises Not_found is the directory does not exist

exception Not_concerned

Regular expressions for redirections

val find_redirection : 
  Netstring_pcre.regexp ->
  bool ->
  string ->
  bool ->
  string option -> int -> string option -> string -> string -> string
val make_parse_config : 
  Ocsigen_lib.Url.path ->
  parse_config_aux -> parse_fun
val parse_config_item : parse_config
val parse_user_site_item : parse_config_user
val set_hosts : 
  (virtual_hosts * config_info *
   extension2)
  list -> unit
val get_hosts : 
  unit ->
  (virtual_hosts * config_info *
   extension2)
  list
val compute_result : 
  ?previous_cookies:Ocsigen_cookies.cookieset ->
  ?awake_next_request:bool ->
  request_info -> Ocsigen_http_frame.result Lwt.t

Compute the result to be sent to the client, by trying all extensions according the configuration file.

val get_number_of_connected : unit -> int

Profiling

val get_number_of_connected : unit -> int
val incr_connected : int -> unit

Server internal functions:

val decr_connected : unit -> unit Lwt.t
val wait_fewer_connected : int -> unit Lwt.t
val during_initialisation : unit -> bool
val start_initialisation : unit -> unit
val end_initialisation : unit -> unit
val get_numberofreloads : unit -> int
val get_init_exn_handler : unit -> exn -> string
val set_config : Simplexmlparser.xml list -> unit
val client_of_connection : Ocsigen_http_com.connection -> client
val get_server_address : request_info -> Unix.inet_addr * int
val sockets : Lwt_unix.file_descr list Pervasives.ref
val sslsockets : Lwt_unix.file_descr list Pervasives.ref