]> matita.cs.unibo.it Git - helm.git/blobdiff - helm/DEVEL/ocaml-http/http_response.ml
no longer use -pack and Http.*, now interface is the usual Http_*
[helm.git] / helm / DEVEL / ocaml-http / http_response.ml
diff --git a/helm/DEVEL/ocaml-http/http_response.ml b/helm/DEVEL/ocaml-http/http_response.ml
new file mode 100644 (file)
index 0000000..b71d887
--- /dev/null
@@ -0,0 +1,137 @@
+
+(*
+  OCaml HTTP - do it yourself (fully OCaml) HTTP daemon
+
+  Copyright (C) <2002> Stefano Zacchiroli <zack@cs.unibo.it>
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*)
+
+open Http_common;;
+open Http_daemon;;
+
+exception Invalid_status_line of string
+exception Header_not_found of string
+
+  (* TODO sanity checks on set* methods' arguments (e.g. dates 822 compliant,
+  code values < 600, ...) *)
+class response =
+  let default_code = 200 in
+    (* remove all bindings of 'name' from hashtbl 'tbl' *)
+  let rec hashtbl_remove_all tbl name =
+    if not (Hashtbl.mem tbl name) then
+      raise (Header_not_found name);
+    Hashtbl.remove tbl name;
+    if Hashtbl.mem tbl name then hashtbl_remove_all tbl name
+  in
+    (* "version code reason_phrase" *)
+  let status_line_re = Pcre.regexp "^(HTTP/\d\.\d) (\d{3}) (.*)$" in
+  object (self)
+    val mutable version = Http_common.http_version
+    val mutable code = default_code val mutable reason: string option = None
+    val contentsBuf = Buffer.create 1024
+    val headers = Hashtbl.create 11
+
+    method version = version
+    method setVersion v = version <- v
+
+    method code = code
+    method setCode c = code <- c
+    method status = status_of_code code
+    method setStatus (s: Http_types.status) = code <- code_of_status s
+    method reason =
+      match reason with
+      | None -> reason_phrase_of_code code
+      | Some r -> r
+    method setReason r = reason <- Some r
+    method statusLine =
+      String.concat
+        " "
+        [string_of_version self#version; string_of_int self#code; self#reason]
+    method setStatusLine s =
+      try
+        let subs = Pcre.extract ~rex:status_line_re s in
+        self#setVersion (Http_common.version_of_string subs.(1));
+        self#setCode (int_of_string subs.(2));
+        self#setReason subs.(3)
+      with Not_found ->
+        raise (Invalid_status_line s)
+
+    method isInformational = is_informational code
+    method isSuccess = is_success code
+    method isRedirection = is_redirection code
+    method isClientError = is_client_error code
+    method isServerError = is_server_error code
+    method isError = is_error code
+
+    method contents = Buffer.contents contentsBuf
+    method setContents c =
+      Buffer.clear contentsBuf;
+      Buffer.add_string contentsBuf c
+    method contentsBuf = contentsBuf
+    method setContentsBuf b =
+      Buffer.clear contentsBuf;
+      Buffer.add_buffer contentsBuf b
+    method addContents s = Buffer.add_string contentsBuf s
+    method addContentsBuf b = Buffer.add_buffer contentsBuf b
+
+      (** adds an header named 'name' with value 'value', if an header with the
+      same name exists, the new value is considered an addition to the header as
+      specified in RFC 2616, thus getting value for this header will return a
+      comma separated list of values provided via 'addHeader' *)
+    method addHeader ~name ~value = Hashtbl.add headers name value
+      (** set the value of header 'name' to 'value', removing all previous
+      values if any *)
+    method replaceHeader ~name ~value = Hashtbl.replace headers name value
+      (** remove the header named 'name', please note that this remove all
+      values provided for this header *)
+    method removeHeader ~name = hashtbl_remove_all headers name
+    method hasHeader ~name = Hashtbl.mem headers name
+      (** @return value of header 'name', if multiple values were provided for
+      header 'name', the return value will be a comma separated list of
+      provided values as stated in RFC 2616 *)
+    method header ~name =
+      if not (self#hasHeader name) then
+        raise (Header_not_found name);
+      String.concat ", " (List.rev (Hashtbl.find_all headers name))
+      (** @return all headers as a list of pairs <name, value> *)
+    method headers =
+      List.rev
+        (Hashtbl.fold
+          (fun name _ headers -> (name, self#header ~name)::headers)
+          headers
+          [])
+
+    method contentType = self#header "Content-Type"
+    method setContentType t = self#replaceHeader "Content-Type" t
+    method contentEncoding = self#header "Content-Encoding"
+    method setContentEncoding e = self#replaceHeader "Content-Encoding" e
+    method date = self#header "Date"
+    method setDate d = self#replaceHeader "Date" d
+    method expires = self#header "Expires"
+    method setExpires t = self#replaceHeader "Expires" t
+    method server = self#header "Server"
+    method setServer s = self#replaceHeader "Server" s
+
+    method serialize outchan =
+      output_string outchan self#statusLine;
+      send_CRLF outchan;
+      send_headers self#headers outchan;
+      send_CRLF outchan;
+      Buffer.output_buffer outchan contentsBuf;
+      flush outchan
+
+  end
+