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 (** informational HTTP status, see RFC2616 *)
58 type informational_substatus =
60 | `Switching_protocols
63 (** success HTTP status, see RFC2616 *)
64 type success_substatus =
68 | `Non_authoritative_information
74 (** redirection HTTP status, see RFC2616 *)
75 type redirection_substatus =
85 (** client error HTTP status, see RFC2616 *)
86 type client_error_substatus =
94 | `Proxy_authentication_required
99 | `Precondition_failed
100 | `Request_entity_too_large
101 | `Request_URI_too_large
102 | `Unsupported_media_type
103 | `Requested_range_not_satisfiable
104 | `Expectation_failed
107 (** server error HTTP status, see RFC2616 *)
108 type server_error_substatus =
109 [ `Internal_server_error
112 | `Service_unavailable
114 | `HTTP_version_not_supported
117 type informational_status = [ `Informational of informational_substatus ]
118 type success_status = [ `Success of success_substatus ]
119 type redirection_status = [ `Redirection of redirection_substatus ]
120 type client_error_status = [ `Client_error of client_error_substatus ]
121 type server_error_status = [ `Server_error of server_error_substatus ]
124 [ client_error_status
125 | server_error_status
130 [ informational_status
133 | client_error_status
134 | server_error_status
139 | FileSrc of string (** filename *)
140 | InChanSrc of in_channel (** input channel *)
142 (** {2 Exceptions} *)
144 (** invalid header encountered *)
145 exception Invalid_header of string
147 (** invalid header name encountered *)
148 exception Invalid_header_name of string
150 (** invalid header value encountered *)
151 exception Invalid_header_value of string
153 (** unsupported or invalid HTTP version encountered *)
154 exception Invalid_HTTP_version of string
156 (** unsupported or invalid HTTP method encountered *)
157 exception Invalid_HTTP_method of string
159 (** invalid HTTP status code integer representation encountered *)
160 exception Invalid_code of int
162 (** invalid URL encountered *)
163 exception Malformed_URL of string
165 (** invalid query string encountered *)
166 exception Malformed_query of string
168 (** invalid query string part encountered, arguments are parameter name and
170 exception Malformed_query_part of string * string
172 (** invalid request URI encountered *)
173 exception Malformed_request_URI of string
175 (** malformed request received *)
176 exception Malformed_request of string
178 (** malformed response received, argument is response's first line *)
179 exception Malformed_response of string
181 (** a parameter you were looking for was not found *)
182 exception Param_not_found of string
184 (** invalid HTTP status line encountered *)
185 exception Invalid_status_line of string
187 (** an header you were looking for was not found *)
188 exception Header_not_found of string
190 (** raisable by callback functions to make main daemon quit, this is the only
191 'clean' way to make start functions return *)
194 (** {2 OO representation of HTTP messages} *)
196 (** HTTP generic messages. See {! Http_message.message} *)
197 class type message = object
199 method version: version option
200 method setVersion: version -> unit
203 method setBody: string -> unit
204 method bodyBuf: Buffer.t
205 method setBodyBuf: Buffer.t -> unit
206 method addBody: string -> unit
207 method addBodyBuf: Buffer.t -> unit
209 method addHeader: name:string -> value:string -> unit
210 method addHeaders: (string * string) list -> unit
211 method replaceHeader: name:string -> value:string -> unit
212 method replaceHeaders: (string * string) list -> unit
213 method removeHeader: name:string -> unit
214 method hasHeader: name:string -> bool
215 method header: name:string -> string
216 method headers: (string * string) list
218 method clientSockaddr: Unix.sockaddr
219 method clientAddr: string
220 method clientPort: int
222 method serverSockaddr: Unix.sockaddr
223 method serverAddr: string
224 method serverPort: int
226 method toString: string
227 method serialize: out_channel -> unit
232 class type request = object
234 (** an HTTP request is a flavour of HTTP message *)
237 (** @return request method *)
240 (** @return requested URI (including query string, fragment, ...) *)
243 (** @return requested path *)
246 (** lookup a given parameter
247 @param meth if given restrict the lookup area (e.g. if meth = POST than
248 only parameters received via POST are searched), if not given both GET and
249 POST parameter are searched in an unspecified order (actually the
250 implementation prefers POST parameters but this is not granted, you've
252 @param name name of the parameter to lookup
253 @return value associated to parameter name
254 @raise Param_not_found if parameter name was not found *)
255 method param: ?meth:meth -> string -> string
257 (** like param above but return a list of values associated to given
258 parameter (a parameter could be defined indeed more than once: passed more
259 than once in a query string or passed both insider the url (the GET way)
260 and inside message body (the POST way)) *)
261 method paramAll: ?meth:meth -> string -> string list
263 (** @return the list of all received parameters *)
264 method params: (string * string) list
266 (** @return the list of all parameters received via GET *)
267 method params_GET: (string * string) list
269 (** @return the list of all parameter received via POST *)
270 method params_POST: (string * string) list
274 (** HTTP responses *)
275 class type response = object
279 (** @return response code *)
282 (** set response code *)
283 method setCode: int -> unit
285 (** @return response status, see {! Http_types.status} *)
286 method status: status
288 (** set response status *)
289 method setStatus: status -> unit
291 (** @return reason string *)
292 method reason: string
294 (** set reason string *)
295 method setReason: string -> unit
297 (** @return status line *)
298 method statusLine: string
301 @raise Invalid_status_line if an invalid HTTP status line was passed *)
302 method setStatusLine: string -> unit
304 (** response is an informational one *)
305 method isInformational: bool
307 (** response is a success one *)
308 method isSuccess: bool
310 (** response is a redirection one *)
311 method isRedirection: bool
313 (** response is a client error one *)
314 method isClientError: bool
316 (** response is a server error one *)
317 method isServerError: bool
319 (** response is either a client error or a server error response *)
322 (** add basic headers to response, see {! Http_daemon.send_basic_headers}
324 method addBasicHeaders: unit
326 (** facilities to access some frequently used headers *)
328 (** @return Content-Type header value *)
329 method contentType: string
331 (** set Content-Type header value *)
332 method setContentType: string -> unit
334 (** @return Content-Encoding header value *)
335 method contentEncoding: string
337 (** set Content-Encoding header value *)
338 method setContentEncoding: string -> unit
340 (** @return Date header value *)
343 (** set Date header value *)
344 method setDate: string -> unit
346 (** @return Expires header value *)
347 method expires: string
349 (** set Expires header value *)
350 method setExpires: string -> unit
352 (** @return Server header value *)
353 method server: string
355 (** set Server header value *)
356 method setServer: string -> unit
360 (** {2 OO representation of other HTTP "entities"} *)
362 (** an HTTP connection from a client to a server *)
363 class type connection =
365 (** @return next request object, may block if client hasn't submitted any
366 request yet, may be None if client request was ill-formed *)
367 method getRequest: request option
369 (** respond to client sending it a response *)
370 method respond_with: response -> unit
372 (** close connection to client. Warning: this object can't be used any
373 longer after this method has been called *)
377 (** an HTTP daemon *)
380 (** @return a connection to a client, may block if no client has connected
382 method accept: connection
384 (** shortcut method, blocks until a client has submit a request and
385 return a pair request * connection *)
386 method getRequest: request * connection