3 OCaml HTTP - do it yourself (fully OCaml) HTTP daemon
5 Copyright (C) <2002> 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 General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
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 (** informational HTTP status, see RFC2616 *)
64 type informational_substatus =
66 | `Switching_protocols
69 (** success HTTP status, see RFC2616 *)
70 type success_substatus =
74 | `Non_authoritative_information
80 (** redirection HTTP status, see RFC2616 *)
81 type redirection_substatus =
91 (** client error HTTP status, see RFC2616 *)
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 (** server error HTTP status, see RFC2616 *)
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
145 | FileSrc of string (** filename *)
146 | InChanSrc of in_channel (** input channel *)
148 (** {2 Exceptions} *)
150 (** invalid header encountered *)
151 exception Invalid_header of string
153 (** invalid header name encountered *)
154 exception Invalid_header_name of string
156 (** invalid header value encountered *)
157 exception Invalid_header_value of string
159 (** unsupported or invalid HTTP version encountered *)
160 exception Invalid_HTTP_version of string
162 (** unsupported or invalid HTTP method encountered *)
163 exception Invalid_HTTP_method of string
165 (** invalid HTTP status code integer representation encountered *)
166 exception Invalid_code of int
168 (** invalid URL encountered *)
169 exception Malformed_URL of string
171 (** invalid query string encountered *)
172 exception Malformed_query of string
174 (** invalid query string part encountered, arguments are parameter name and
176 exception Malformed_query_part of string * string
178 (** invalid request URI encountered *)
179 exception Malformed_request_URI of string
181 (** malformed request received *)
182 exception Malformed_request of string
184 (** malformed response received, argument is response's first line *)
185 exception Malformed_response of string
187 (** a parameter you were looking for was not found *)
188 exception Param_not_found of string
190 (** invalid HTTP status line encountered *)
191 exception Invalid_status_line of string
193 (** an header you were looking for was not found *)
194 exception Header_not_found of string
196 (** raisable by callbacks to make main daemon quit, this is the only
197 'clean' way to make start functions return *)
200 (** raisable by callbacks to force a 401 (unauthorized) HTTP answer.
201 * This exception should be raised _before_ sending any data over given out
203 * @param realm authentication realm (usually needed to prompt user) *)
204 exception Unauthorized of string
206 (** {2 OO representation of HTTP messages} *)
208 (** HTTP generic messages. See {! Http_message.message} *)
209 class type message = object
211 method version: version option
212 method setVersion: version -> unit
215 method setBody: string -> unit
216 method bodyBuf: Buffer.t
217 method setBodyBuf: Buffer.t -> unit
218 method addBody: string -> unit
219 method addBodyBuf: Buffer.t -> unit
221 method addHeader: name:string -> value:string -> unit
222 method addHeaders: (string * string) list -> unit
223 method replaceHeader: name:string -> value:string -> unit
224 method replaceHeaders: (string * string) list -> unit
225 method removeHeader: name:string -> unit
226 method hasHeader: name:string -> bool
227 method header: name:string -> string
228 method headers: (string * string) list
230 method clientSockaddr: Unix.sockaddr
231 method clientAddr: string
232 method clientPort: int
234 method serverSockaddr: Unix.sockaddr
235 method serverAddr: string
236 method serverPort: int
238 method toString: string
239 method serialize: out_channel -> unit
244 class type request = object
246 (** an HTTP request is a flavour of HTTP message *)
249 (** @return request method *)
252 (** @return requested URI (including query string, fragment, ...) *)
255 (** @return requested path *)
258 (** lookup a given parameter
259 @param meth if given restrict the lookup area (e.g. if meth = POST than
260 only parameters received via POST are searched), if not given both GET and
261 POST parameter are searched in an unspecified order (actually the
262 implementation prefers POST parameters but this is not granted, you've
264 @param name name of the parameter to lookup
265 @return value associated to parameter name
266 @raise Param_not_found if parameter name was not found *)
267 method param: ?meth:meth -> string -> string
269 (** like param above but return a list of values associated to given
270 parameter (a parameter could be defined indeed more than once: passed more
271 than once in a query string or passed both insider the url (the GET way)
272 and inside message body (the POST way)) *)
273 method paramAll: ?meth:meth -> string -> string list
275 (** @return the list of all received parameters *)
276 method params: (string * string) list
278 (** @return the list of all parameters received via GET *)
279 method params_GET: (string * string) list
281 (** @return the list of all parameter received via POST *)
282 method params_POST: (string * string) list
284 (** @return authorization information, if given by the client *)
285 method authorization: auth_info option
289 (** HTTP responses *)
290 class type response = object
294 (** @return response code *)
297 (** set response code *)
298 method setCode: int -> unit
300 (** @return response status, see {! Http_types.status} *)
301 method status: status
303 (** set response status *)
304 method setStatus: status -> unit
306 (** @return reason string *)
307 method reason: string
309 (** set reason string *)
310 method setReason: string -> unit
312 (** @return status line *)
313 method statusLine: string
316 @raise Invalid_status_line if an invalid HTTP status line was passed *)
317 method setStatusLine: string -> unit
319 (** response is an informational one *)
320 method isInformational: bool
322 (** response is a success one *)
323 method isSuccess: bool
325 (** response is a redirection one *)
326 method isRedirection: bool
328 (** response is a client error one *)
329 method isClientError: bool
331 (** response is a server error one *)
332 method isServerError: bool
334 (** response is either a client error or a server error response *)
337 (** add basic headers to response, see {! Http_daemon.send_basic_headers}
339 method addBasicHeaders: unit
341 (** facilities to access some frequently used headers *)
343 (** @return Content-Type header value *)
344 method contentType: string
346 (** set Content-Type header value *)
347 method setContentType: string -> unit
349 (** @return Content-Encoding header value *)
350 method contentEncoding: string
352 (** set Content-Encoding header value *)
353 method setContentEncoding: string -> unit
355 (** @return Date header value *)
358 (** set Date header value *)
359 method setDate: string -> unit
361 (** @return Expires header value *)
362 method expires: string
364 (** set Expires header value *)
365 method setExpires: string -> unit
367 (** @return Server header value *)
368 method server: string
370 (** set Server header value *)
371 method setServer: string -> unit
375 (** {2 OO representation of other HTTP "entities"} *)
377 (** an HTTP connection from a client to a server *)
378 class type connection =
380 (** @return next request object, may block if client hasn't submitted any
381 request yet, may be None if client request was ill-formed *)
382 method getRequest: request option
384 (** respond to client sending it a response *)
385 method respond_with: response -> unit
387 (** close connection to client. Warning: this object can't be used any
388 longer after this method has been called *)
392 (** an HTTP daemon *)
395 (** @return a connection to a client, may block if no client has connected
397 method accept: connection
399 (** shortcut method, blocks until a client has submit a request and
400 return a pair request * connection *)
401 method getRequest: request * connection