3 OCaml HTTP - do it yourself (fully OCaml) HTTP daemon
5 Copyright (C) <2002-2005> Stefano Zacchiroli <zack@cs.unibo.it>
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU Library General Public License as
9 published by the Free Software Foundation, version 2.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU Library General Public License for more details.
16 You should have received a copy of the GNU Library General Public
17 License along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
22 (** Type definitions *)
24 (** HTTP version, actually only 1.0 and 1.1 are supported. Note that
25 'supported' here means only 'accepted inside a HTTP request line', no
26 different behaviours are actually implemented depending on HTTP version *)
32 (** HTTP method, actually only GET and POST methods are supported *)
38 (** Daemon behaviour wrt request handling. `Single mode use a single process
39 to handle all requests, no request is served until a previous one has been
40 fully served. `Fork mode fork a new process for each request, the new process
41 will execute the callback function and then exit. `Thread mode create a new
42 thread for each request, the new thread will execute the callback function and
43 then exit, threads can communicate using standard OCaml Thread library. *)
44 type daemon_mode = [ `Single | `Fork | `Thread ]
46 (** A TCP server is a function taking an address on which bind and listen for
47 connections, an optional timeout after which abort client connections and a
48 callback function which in turn takes an input and an output channel as
49 arguments. After receiving this argument a TCP server sits and waits for
50 connection, on each connection it apply the callback function to channels
51 connected to client. *)
53 sockaddr:Unix.sockaddr -> timeout:int option ->
54 (in_channel -> out_channel -> unit) ->
57 (** authentication information *)
59 [ `Basic of string * string (* username, password *)
60 (* | `Digest of ... (* TODO digest authentication *) *)
63 (** @see "RFC2616" informational HTTP status *)
64 type informational_substatus =
66 | `Switching_protocols
69 (** @see "RFC2616" success HTTP status *)
70 type success_substatus =
74 | `Non_authoritative_information
80 (** @see "RFC2616" redirection HTTP status *)
81 type redirection_substatus =
91 (** @see "RFC2616" client error HTTP status *)
92 type client_error_substatus =
100 | `Proxy_authentication_required
105 | `Precondition_failed
106 | `Request_entity_too_large
107 | `Request_URI_too_large
108 | `Unsupported_media_type
109 | `Requested_range_not_satisfiable
110 | `Expectation_failed
113 (** @see "RFC2616" server error HTTP status *)
114 type server_error_substatus =
115 [ `Internal_server_error
118 | `Service_unavailable
120 | `HTTP_version_not_supported
123 type informational_status = [ `Informational of informational_substatus ]
124 type success_status = [ `Success of success_substatus ]
125 type redirection_status = [ `Redirection of redirection_substatus ]
126 type client_error_status = [ `Client_error of client_error_substatus ]
127 type server_error_status = [ `Server_error of server_error_substatus ]
130 [ client_error_status
131 | server_error_status
136 [ informational_status
139 | client_error_status
140 | server_error_status
143 type status_code = [ `Code of int | `Status of status ]
147 | FileSrc of string (** filename *)
148 | InChanSrc of in_channel (** input channel *)
150 (** {2 Exceptions} *)
152 (** invalid header encountered *)
153 exception Invalid_header of string
155 (** invalid header name encountered *)
156 exception Invalid_header_name of string
158 (** invalid header value encountered *)
159 exception Invalid_header_value of string
161 (** unsupported or invalid HTTP version encountered *)
162 exception Invalid_HTTP_version of string
164 (** unsupported or invalid HTTP method encountered *)
165 exception Invalid_HTTP_method of string
167 (** invalid HTTP status code integer representation encountered *)
168 exception Invalid_code of int
170 (** invalid URL encountered *)
171 exception Malformed_URL of string
173 (** invalid query string encountered *)
174 exception Malformed_query of string
176 (** invalid query string part encountered, arguments are parameter name and
178 exception Malformed_query_part of string * string
180 (** invalid request URI encountered *)
181 exception Malformed_request_URI of string
183 (** malformed request received *)
184 exception Malformed_request of string
186 (** malformed response received, argument is response's first line *)
187 exception Malformed_response of string
189 (** a parameter you were looking for was not found *)
190 exception Param_not_found of string
192 (** invalid HTTP status line encountered *)
193 exception Invalid_status_line of string
195 (** an header you were looking for was not found *)
196 exception Header_not_found of string
198 (** raisable by callbacks to make main daemon quit, this is the only
199 * 'clean' way to make start functions return *)
202 (** raisable by callbacks to force a 401 (unauthorized) HTTP answer.
203 * This exception should be raised _before_ sending any data over given out
205 * @param realm authentication realm (usually needed to prompt user) *)
206 exception Unauthorized of string
208 (** {2 OO representation of HTTP messages} *)
210 (** HTTP generic messages. See {! Http_message.message} *)
211 class type message = object
213 method version: version option
214 method setVersion: version -> unit
217 method setBody: string -> unit
218 method bodyBuf: Buffer.t
219 method setBodyBuf: Buffer.t -> unit
220 method addBody: string -> unit
221 method addBodyBuf: Buffer.t -> unit
223 method addHeader: name:string -> value:string -> unit
224 method addHeaders: (string * string) list -> unit
225 method replaceHeader: name:string -> value:string -> unit
226 method replaceHeaders: (string * string) list -> unit
227 method removeHeader: name:string -> unit
228 method hasHeader: name:string -> bool
229 method header: name:string -> string
230 method headers: (string * string) list
232 method clientSockaddr: Unix.sockaddr
233 method clientAddr: string
234 method clientPort: int
236 method serverSockaddr: Unix.sockaddr
237 method serverAddr: string
238 method serverPort: int
240 method toString: string
241 method serialize: out_channel -> unit
246 class type request = object
248 (** an HTTP request is a flavour of HTTP message *)
251 (** @return request method *)
254 (** @return requested URI (including query string, fragment, ...) *)
257 (** @return requested path *)
260 (** lookup a given parameter
261 @param meth if given restrict the lookup area (e.g. if meth = POST than
262 only parameters received via POST are searched), if not given both GET
263 and POST parameter are searched in an unspecified order (actually the
264 implementation prefers POST parameters but this is not granted, you've
266 @param default if provided, this value will be returned in case no
267 parameter of that name is available instead of raising Param_not_found
268 @param name name of the parameter to lookup
269 @return value associated to parameter name
270 @raise Param_not_found if parameter name was not found *)
271 method param: ?meth:meth -> ?default:string -> string -> string
273 (** like param above but return a list of values associated to given
274 parameter (a parameter could be defined indeed more than once: passed more
275 than once in a query string or passed both insider the url (the GET way)
276 and inside message body (the POST way)) *)
277 method paramAll: ?meth:meth -> string -> string list
279 (** @return the list of all received parameters *)
280 method params: (string * string) list
282 (** @return the list of all parameters received via GET *)
283 method params_GET: (string * string) list
285 (** @return the list of all parameter received via POST *)
286 method params_POST: (string * string) list
288 (** @return authorization information, if given by the client *)
289 method authorization: auth_info option
293 (** HTTP responses *)
294 class type response = object
298 (** @return response code *)
301 (** set response code *)
302 method setCode: int -> unit
304 (** @return response status *)
305 method status: status
307 (** set response status *)
308 method setStatus: status -> unit
310 (** @return reason string *)
311 method reason: string
313 (** set reason string *)
314 method setReason: string -> unit
316 (** @return status line *)
317 method statusLine: string
320 @raise Invalid_status_line if an invalid HTTP status line was passed *)
321 method setStatusLine: string -> unit
323 (** response is an informational one *)
324 method isInformational: bool
326 (** response is a success one *)
327 method isSuccess: bool
329 (** response is a redirection one *)
330 method isRedirection: bool
332 (** response is a client error one *)
333 method isClientError: bool
335 (** response is a server error one *)
336 method isServerError: bool
338 (** response is either a client error or a server error response *)
341 (** add basic headers to response, see {!Http_daemon.send_basic_headers}
343 method addBasicHeaders: unit
345 (** facilities to access some frequently used headers *)
347 (** @return Content-Type header value *)
348 method contentType: string
350 (** set Content-Type header value *)
351 method setContentType: string -> unit
353 (** @return Content-Encoding header value *)
354 method contentEncoding: string
356 (** set Content-Encoding header value *)
357 method setContentEncoding: string -> unit
359 (** @return Date header value *)
362 (** set Date header value *)
363 method setDate: string -> unit
365 (** @return Expires header value *)
366 method expires: string
368 (** set Expires header value *)
369 method setExpires: string -> unit
371 (** @return Server header value *)
372 method server: string
374 (** set Server header value *)
375 method setServer: string -> unit
379 (** {2 Daemon specification} *)
381 (** daemon specification, describe the behaviour of an HTTP daemon.
383 * The default daemon specification is {!Http_daemon.default_spec}
387 (** @param address adress on which daemon will be listening, can be both a
388 * numeric address (e.g. "127.0.0.1") and an hostname (e.g. "localhost") *)
389 auth: (string * auth_info) option;
390 (** authentication requirements (currently only basic authentication is
391 * supported). If set to None no authentication is required. If set to Some
392 * ("realm", `Basic ("foo", "bar")), only clients authenticated with baisc
393 * authentication, for realm "realm", providing username "foo" and password
394 * "bar" are accepted; others are rejected with a 401 response code *)
395 callback: request -> out_channel -> unit;
396 (** function which will be called each time a correct HTTP request will be
397 * received. 1st callback argument is an Http_types.request object
398 * corresponding to the request received; 2nd argument is an output channel
399 * corresponding to the socket connected to the client *)
401 (** requests handling mode, it can have three different values:
402 * - `Single -> all requests will be handled by the same process,
403 * - `Fork -> each request will be handled by a child process,
404 * - `Thread -> each request will be handled by a (new) thread *)
405 port: int; (** TCP port on which the daemon will be listening *)
406 root_dir: string option;
407 (** directory to which ocaml http will chdir before starting handling
408 * requests; if None, no chdir will be performed (i.e. stay in the current
409 * working directory) *)
410 exn_handler: (exn -> out_channel -> unit) option;
411 (** what to do when executing callback raises an exception. If None, the
412 * exception will be re-raised: in `Fork/`Thread mode the current
413 * process/thread will be terminated. in `Single mode the exception is
414 * ignored and the client socket closed. If Some callback, the callback will
415 * be executed before acting as per None; the callback is meant to perform
416 * some clean up actions, like releasing global mutexes in `Thread mode *)
418 (** timeout in seconds after which an incoming HTTP request will be
419 * terminated closing the corresponding TCP connection; None disable the
422 (** whether ocaml-http will automatically close the connection with the
423 * client after callback has completed its execution. If set to true, close
424 * will be attempted no matter if the callback raises an exception or not *)
427 (** {2 OO representation of other HTTP entities} *)
429 (** an HTTP connection from a client to a server *)
430 class type connection =
432 (** @return next request object, may block if client hasn't submitted any
433 request yet, may be None if client request was ill-formed *)
434 method getRequest: request option
436 (** respond to client sending it a response *)
437 method respond_with: response -> unit
439 (** close connection to client. Warning: this object can't be used any
440 longer after this method has been called *)
444 (** an HTTP daemon *)
447 (** @return a connection to a client, may block if no client has connected
449 method accept: connection
451 (** shortcut method, blocks until a client has submit a request and
452 return a pair request * connection *)
453 method getRequest: request * connection