Functions to develop new connectors.
The following module is provided as a set of helper functions to
define new connectors. As a normal user of Netcgi
, you should
not use this module.
The goal of this module is to factor out common routines to easily set up new connectors. Here is the normal flow of operations:
stderr
output is not appropriate
(e.g. ot is not redirected to the server log), you need to
override #log_error
.#cgi_query_string
(in case of GET) or from an input
channel (in case of POST). Netcgi_common.cgi_with_args handles
this for you: it requires a Netchannels.in_obj_channel from
which the arguments are read (only used in the case of POST).To see this schema in use, we recommend you have a look to the implementation of the CGI connector because it is very simple.
Hit the limit max_arguments
See Netcgi.rw_cgi_argument.
The cookie implementation has been moved to Nethttp.Cookie. New code should directly call the functions defined there.
The expiration time of the cookie, in seconds. None
means
that the cookie will be discarded when the browser exits.
This information is not returned by the browser.
Tells whether the cookie is secure. This information is not returned by the browser.
Returns the comment associated to the cookie or ""
if it
does not exists. This information is not returned by the
browser.
Returns the comment URL associated to the cookie or ""
if it
does not exists. This information is not returned by the
browser.
set http_header cookies
sets the cookies
in http_header
using version 0 or version 1 depending on whether version 1
fields are used. For better browser compatibility, if
"Set-cookie2" (RFC 2965) is issued, then a "Set-cookie"
precedes (declaring the same cookie with a limited number of
options).
Deprecated name. Use Nethttp.Header.set_set_cookie_ct.
Decode the cookie header, may they be version 0 or 1.
Deprecated name. Use Nethttp.Header.get_cookie_ct.
#
tmp_directory
| : string | ; | |||
#
tmp_prefix
| : string | ; | |||
#
permitted_http_methods
| : [ | `GET | `HEAD | `POST | `DELETE | `PUT ] list | ; | |||
#
permitted_input_content_types
| : string list | ; | |||
#
input_content_length_limit
| : int | ; | |||
#
max_arguments
| : int | ; | |||
#
workarounds
| : [ | `MSIE_Content_type_bug | `Backslash_bug | `Work_around_MSIE_Content_type_bug | `Work_around_backslash_bug ] list | ; | |||
#
default_exn_handler
| : bool | ; |
fix_MSIE_Content_type_bug ct
transforms the content-type
string ct
to fix the MSIE Content-Type bug.
is_MSIE user_agent
tells whether the user_agent
is Microsoft
Internet Explorer. Useful to know when to apply
Netcgi_common.fix_MSIE_Content_type_bug.
true
iff the output headers have not been sent.
#send_output_header
must set it to false once it did its
job.
Return the parameter properties
.
HTTP
if the HTTPS property is not understood.
For special header structures, override this method and
maybe #send_output_header
.
You may want to override this with your custom logging method.
By default, #log_error msg
adds a timestamp to msg
and
sends th result to stderr
.
new cgi_environment ~config ~properties ~input_header out_obj
generates a Netcgi.cgi_environment object, from the arguments.
The creation of such an object does not raise any exception.
The method #out_channel
of the created environment returns
out_obj
.
config.workarounds
. If
`MSIE_Content_type_bug
is present, a fix will be applied to
input_header
.
("REQUEST_METHOD", "POST")
, ("SERVER_PROTOCOL",
"HTTP/1.1")
. Note that "CONTENT_TYPE" and "CONTENT_LENGTH" are
part of the input header. It is highly recommended to use
[root:Netcgi_common].update_props_inheader to build this list.
input_header
are lowercase in order to apply a fix to the MSIE Content-Type
bug. Also remember that the separator is '-', not '_'. Both
requirements will be stafisfied if you use
[root:Netcgi_common].update_props_inheader to build input_header
.#send_output_header
sents it directly to out_obj
. This has
several advantages:environment
object can process the header; for example
it can fix header fields.See Netcgi.query_string_spec.
The following environment properties must be available for this method to work properly (please make sure your connector provides them; the CGI spec make them compulsory anyway):
cgi_server_name
cgi_server_port
cgi_script_name
cgi_path_info
cgi env op meth args
constructs Netcgi.cgi objects. The
environment #out_channel
is wrapped into a transactional channel
or a discarding channel according to op
(`Direct
or
`Transactional
) and request_method
(`HEAD
requests must only
return a header). For standard cases, when POST and PUT arguments
are available through a Netchannels.in_obj_channel
, we recommend
you use Netcgi_common.cgi_with_args that will parse the
arguments for you and check preconditions.
Remark: You may think that the argument meth
is superfluous as
it can be deduced from env#cgi_request_method
. While it is true
for `DELETE
, `GET
, `HEAD
and `POST
, the `PUT
takes a
Netcgi_common.cgi_argument parameter. Setting correctly this
parameter and decoding env#cgi_request_method
is done for you by
Netcgi_common.cgi_with_args.
cgi_with_args (new cgi) env out op ?put_arg in_chan
constructs
a Netcgi.cgi object. However, new cgi
can be replaced by
any function, so it is easy to use this to construct extensions
of the cgi
class (as needed by some connectors). The
arguments of the cgi object are taken from the environment env
(for HEAD, GET, DELETE) or from the in_chan
(for POST, PUT)
and processed according to arg_store
.
HTTP
if the data does not conform the standards or it not
allowed.
Exception raised by various functions of this library to return to the user agent an appropriate error page with the specified http-status (this exception must be caught by the connector and a default answer sent).
The string is a description of the cause of the error.
This exception is for use by connectors only, users should deal
with the exceptions in their code by generating a response with
the usual #set_header
and #out_channel
of Netcgi.cgi.
exn_handler_default env ~exn_handler ~finally run_cgi
will
basically execute exn_handler env run_cgi
. Provided that the
environment config default_exn_handler
is set to true
(the
default), any exception e
not caught by the user provided
exn_handler
(or that is raised by it) will be passed to the
default handler of OCamlNet which will rollback the current
output, produce a page describing the exception e
, and close
the output channel of env
. Note that the default handler
treats HTTP
exceptions specially -- for example, the response
to HTTP(`Method_not_allowed,...)
includes an "Allow" header
(as mandated by HTTP/1.1);...
Note that, regardless of the value of default_exn_handler
, the
Exit
exception is always caught and treated like an
acceptable early termination (thus produces no error page).
Whether run_cgi
terminates normally or by an exception,
finally()
is executed last.
Sometimes, you want that some "special" exceptions (for example
exceptions internal to the connector) CANNOT to be caught by
exn_handler
. In this case, run_cgi()
catches the exception,
say e
, and returns it as Some e
. The exception e
will "go
through" exn_handler_default
, it will not even be passed to
the default handler. Therefore, you must take care that it is
handled by the surrounding code or your connector may die
without an error message. Of course, run_cgi
must return
None
if no "special" exception is raised.
REMARK: Stricly speaking, exn_handler env run_cgi
is obviously
not possible because the return type of run_cgi
is not unit
but you can ignore that to understand what this function does.
error_page env status fields msg detail
: Logs an error message and
outputs an error page via env
.
status
is the status of the error page, e.g. `Internal_server_error
.
fields
are put into the response header of the error page.
msg
occurs in the log message and in the error page, and should
be a concise description without linefeeds. detail
is only
printed to the error page, and may be longer than this, and may
also include HTML markup.
The following functions are used in several connectors and are gouped here for convenience.
update_props_inheader (name, value) (props, inheader)
returns
(props, inheader)
to which the new parameter name
-value
has been added -- to props
or inheader
, depending on name
.
Unless you know what you are going, you must use this
function to classify parameters as it also performs some
standardisation.
rm_htspace is_space s low up
returns the substring s.[low
.. up - 1]
stripped of possible heading and trailing spaces
identified by the function is_space
.
Invalid_argument
if low < 0
or up > String.length s
split_rev is_delim s
split s
at each character is_delim
and returns the list of substrings in reverse order. Several
consecutive delimiters are treated as a single one. The
substrings do not share s
memory.
is_prefix pre s
checks whether pre
is a prefix of s
.