Library
Module
Module type
Parameter
Class
Class type
An IO module Mehari implementation for Unix and Windows using Lwt. Contains also extra features based on Unix filesystem such as CGI.
include Mehari_mirage.S with type addr = Ipaddr.t
module IO = Lwt
include Mehari.NET
with module IO := IO
and type addr = Ipaddr.t
with type addr = Ipaddr.t
Rate limiter. See Rate limit.
type middleware =
(addr Mehari.request -> Mehari.response IO.t) ->
addr Mehari.request ->
Mehari.response IO.t
Middlewares take a handler
, and run some code before or after — producing a “bigger” handler
. See Middleware.
val no_middleware : middleware
Does nothing but call its inner handler. Useful for disabling middleware conditionally during application startup:
if development then
my_middleware
else
Mehari.no_middleware
val pipeline : middleware list -> middleware
Combines a list of middlewares into one, such that these two lines are equivalent: Mehari.pipeline [ mw1 ; mw2 ] @@ handler
mw1 @@ mw2 @@ handler
.
val router : route list -> addr Mehari.request -> Mehari.response IO.t
Creates a router. If none of the routes match the Mehari.request
, the router returns Mehari.not_found
.
val route :
?rate_limit:rate_limiter ->
?mw:middleware ->
?typ:[ `Raw | `Regex ] ->
string ->
(addr Mehari.request -> Mehari.response IO.t) ->
route
route ~rate_limit ~mw ~typ path handler
forwards requests for path
to handler
. path
can be a string literal or a regex in Perl style depending of typ
. If rate limit is in effect, handler
is not executed and a respond with Mehari.status
Mehari.slow_down
is sended.
val scope :
?rate_limit:rate_limiter ->
?mw:middleware ->
string ->
route list ->
route
scope ~rate_limit ~mw prefix routes
groups routes
under the path prefix
, rate_limit
and mw
.
val no_route : route
A dummy value of type route
that is completely ignored by the router. Useful for disabling routes conditionally during application start.
val make_rate_limit :
?period:int ->
int ->
[ `Second | `Minute | `Hour | `Day ] ->
rate_limiter
make_rate_limit ~period n unit
creates a rate_limiter
which limits client to n
request per period * unit
. For example,
make_rate_limit ~period:2 5 `Hour
limits client to 5 requests every 2 hours.
val virtual_hosts :
?meth:[ `ByURL | `SNI ] ->
(string * (addr Mehari.request -> Mehari.response IO.t)) list ->
addr Mehari.request ->
Mehari.response IO.t
virtual_hosts ?meth [(domain, handler); ...]
produces a handler
which enables virtual hosting at the TLS-layer using SNI.
meth
can be used to choose which source to match the hostnames against. Defaults to `SNI
.val set_log_lvl : Logs.level -> unit
Set Mehari's logger to the given log level.
val logger :
(addr Mehari.request -> Mehari.response IO.t) ->
addr Mehari.request ->
Mehari.response IO.t
Logs and times requests. Time spent logging is included.
val debug : 'a Logs.log
val info : 'a Logs.log
val warning : 'a Logs.log
val error : 'a Logs.log
val respond : 'a Mehari.status -> 'a -> Mehari.response IO.t
Same as Mehari.response
, but the new Mehari.response
is wrapped in a promise.
val respond_body : Mehari.body -> Mehari.mime -> Mehari.response IO.t
Same as respond
but respond with given Mehari.body
and use given Mehari.mime
as mime type.
val respond_text : string -> Mehari.response IO.t
Same as respond
but respond with given text and use text/plain
as Mehari.mime
type.
val respond_gemtext :
?charset:string ->
?lang:string list ->
Mehari.Gemtext.t ->
Mehari.response IO.t
Same as respond
but respond with given Mehari.Gemtext.t
and use text/gemini
as Mehari.mime
type.
val respond_raw :
[ `Body of string | `Full of int * string * string ] ->
Mehari.response IO.t
Same as Mehari.response_raw
, but the new Mehari.response
is wrapped in a promise.
include Mehari.UNIX
with module IO := IO
and type addr := addr
and type dir_path := string
type handler = addr Mehari.request -> Mehari.response IO.t
val response_document : ?mime:Mehari.mime -> string -> Mehari.response IO.t
Same as Mehari.response
but respond with content of given filename
and use given Mehari.mime
as mime type. If filename
is not present on filesystem, responds with Mehari.not_found
. If mime
parameter is not supplied, use Mehari.no_mime
as mime type.
val static :
?handler:(string -> handler) ->
?dir_listing:
(([ `Regular_file | `Directory | `Other ] * string) list -> handler) ->
?index:string ->
?show_hidden:bool ->
string ->
handler
static dir
validates the path parameter (retrieved by calling Mehari.param req 1
) by checking that it is relative and does not contain parent directory references. If these checks fail, responds with Mehari.not_found
.
If the checks succeed, static
calls handler path request
, where path
is the path generated by the concatenation of directory that was passed to static
and path of request. handler
defaults to response_document
.
If a directory is requested, static
will look for a file named index
in that directory to return. Otherwise, a directory file listing will be generated by calling dir_listing [ filename; ... ] request
. index
is default on index.gmi
.
show_hidden
decides whether hidden files should be listed. It defaults to false
for security reasons.
val from_filename :
?lookup:[ `Ext | `Content | `Both ] ->
?charset:string ->
string ->
Mehari.mime option Lwt.t
from_filename ?lookup_into ?charset ?lang fname
tries to create a Mehari.mime
by performing a mime lookup depending of the value of lookup
:
`Ext
: guesses on the file extension of fname
;`Content
: guesses on content of fname
;`Both
: performs successivly a lookup on content and file extension.Returns Mehari.make_mime ?charset "text/gemini"
if one of the previous lookup fails.
Mehari supports CGI scripting as described in RFC 3875
The CGI script must write the gemini response to the stdout stream. Status code and meta string on the first line, and the optional response body on subsequent lines. The bytes generated by the CGI script will be forwarded verbatim to the Gemini client, without any additional modification by the server.
Some variables are empty for compatibility with other CGI script.
Let's say that the url requested is gemini://localhost/cgi/foo.cgi?input
:
AUTH_TYPE
: CERTIFICATE
if a client certificate is provided, empty otherwise.CONTENT_LENGTH
: Empty.CONTENT_TYPE
: Empty.GATEWAY_INTERFACE
: CGI/1.1
.PATH_INFO
: Example value: /cgi/foo.cgi
.PATH_TRANSLATED
: Example value: /cgi/foo.cgi
.QUERY_STRING
: Example value: input
.REMOTE_ADDR
: Example value: 127.0.0.1
.REMOTE_HOST
: Same as REMOTE_ADDR
.REMOTE_IDENT
: Empty.REMOTE_METHOD
: Empty.REMOTE_USER
: Client certificate common if it is provided, empty otherwise.SCRIPT_NAME
: Example value: /var/cgi/foo.cgi
.SERVER_NAME
: Example value: /var/cgi/foo.cgi
.SERVER_PORT
: Example value: 1965
.SERVER_PROTOCOL
: GEMINI
.SERVER_SOFTWARE
: Example value: Mehari/1.0
.val run_cgi :
?timeout:float ->
?nph:bool ->
string ->
addr Mehari.request ->
Mehari.response Lwt.t
run_cgi ?timeout ?nph script_path req
executes the given file as a CGI script and return a Mehari.response
based on bytes printed on stdout by script. Responds with Mehari.cgi_error
in case of error or timeout
exceeding.
timeout
defaults to 5.0
.nph
decides if NPH (Non-Parsed Header) is enable. Defaults to false
.val run_lwt :
?port:int ->
?timeout:float ->
?verify_url_host:bool ->
?certchains:(string * string) list ->
?v4:Ipaddr.V4.Prefix.t ->
?v6:Ipaddr.V6.Prefix.t ->
handler ->
unit Lwt.t
See Mehari_mirage.S.run
.