+ocaml-http (0.0.8) unstable; urgency=low
+
+ * Added support for "ancient" HTTP requests which specify no HTTP
+ version
+ - 'version' method on message now has type 'version option'
+
+ -- Stefano Zacchiroli <zack@debian.org> Fri, 10 Jan 2003 10:36:53 +0100
+
ocaml-http (0.0.7) unstable; urgency=low
* Added support for POST requests
val _contentsBuf = Buffer.create 1024
val _headers = Hashtbl.create 11
- val mutable _version: version = version
+ val mutable _version: version option = version
initializer
self#setBody body;
self#addHeaders headers
method version = _version
- method setVersion v = _version <- v
+ method setVersion v = _version <- Some v
method body = Buffer.contents _contentsBuf
method setBody c =
@param entity body included in the message
@param headers message headers shipped with the message *)
class virtual message:
- body: string -> headers: (string * string) list -> version: version ->
+ body: string -> headers: (string * string) list -> version: version option ->
clisockaddr: Unix.sockaddr -> srvsockaddr: Unix.sockaddr ->
object
- method version: version
+ method version: version option
method setVersion: version -> unit
method body: string
let parse_request_fst_line ic =
let request_line = generic_input_line ~sep:crlf ~ic in
debug_print (sprintf "HTTP request line (not yet parsed): %s" request_line);
- match Pcre.split ~rex:pieces_sep request_line with
- | [ meth_raw; uri_raw; http_version_raw ] ->
- (try
+ try
+ (match Pcre.split ~rex:pieces_sep request_line with
+ | [ meth_raw; uri_raw ] -> (* ancient HTTP request line *)
(method_of_string meth_raw, (* method *)
Http_parser_sanity.url_of_string uri_raw, (* uri *)
- version_of_string http_version_raw) (* version *)
- with Neturl.Malformed_URL -> raise (Malformed_request_URI uri_raw))
- | _ -> raise (Malformed_request request_line)
+ None) (* no version given *)
+ | [ meth_raw; uri_raw; http_version_raw ] -> (* HTTP 1.{0,1} *)
+ (method_of_string meth_raw, (* method *)
+ Http_parser_sanity.url_of_string uri_raw, (* uri *)
+ Some (version_of_string http_version_raw)) (* version *)
+ | _ -> raise (Malformed_request request_line))
+ with Malformed_URL url -> raise (Malformed_request_URI url)
let parse_path uri = patch_empty_path (String.concat "/" (Neturl.url_path uri))
let parse_query_get_params uri =
val split_query_params: string -> (string * string) list
-val parse_request_fst_line: in_channel -> meth * Neturl.url * version
+val parse_request_fst_line: in_channel -> meth * Neturl.url * version option
val parse_query_get_params: Neturl.url -> (string * string) list
val parse_path: Neturl.url -> string
val parse_headers: in_channel -> (string * string) list
heal_header_name name;
heal_header_value name
-let url_of_string = url_of_string request_uri_syntax
+let url_of_string s =
+ try
+ url_of_string request_uri_syntax s
+ with Neturl.Malformed_URL -> raise (Malformed_URL s)
let string_of_url = Neturl.string_of_url
(** remove heading and/or trailing LWS sequences as per RFC2616 *)
val normalize_header_value: string -> string
+ (** parse an URL from a string.
+ @raise Malformed_URL if an invalid URL is encountered *)
val url_of_string: string -> Neturl.url
val string_of_url: Neturl.url -> string
let uri_str = Neturl.string_of_url uri in
let path = Http_parser.parse_path uri in
let query_get_params = Http_parser.parse_query_get_params uri in
- let headers =
- List.map (* lowercase header names to ease lookups before having a request
- object *)
- (fun (h,v) -> (String.lowercase h, v))
- (Http_parser.parse_headers ic) (* trailing \r\n consumed! *)
- in
- let body =
- (* TODO fallback on Transfer-Encoding if Content-Length isn't defined *)
- if meth = `POST then
- Buffer.contents
- (try (* read only Content-Length bytes *)
- let limit_raw =
- (try
- List.assoc "content-length" headers
- with Not_found -> raise Fallback)
- in
- let limit =
- (try (* TODO supports only a maximum content-length of 1Gb *)
- int_of_string limit_raw
- with Failure "int_of_string" ->
- raise (Invalid_header ("content-length: " ^ limit_raw)))
- in
- Http_misc.buf_of_inchan ~limit ic
- with Fallback -> Http_misc.buf_of_inchan ic) (* read until EOF *)
- else "" (* TODO empty body for methods other than POST, is what we want? *)
+ let (headers, body) =
+ (match version with
+ | None -> [], "" (* No version given, use request's 1st line only *)
+ | Some version -> (* Version specified, parse also headers and body *)
+ let headers =
+ List.map (* lowercase header names to ease lookups before having a
+ request object *)
+ (fun (h,v) -> (String.lowercase h, v))
+ (Http_parser.parse_headers ic) (* trailing \r\n consumed! *)
+ in
+ let body =
+ (* TODO fallback on size defined in Transfer-Encoding if
+ Content-Length isn't defined *)
+ if meth = `POST then
+ Buffer.contents
+ (try (* read only Content-Length bytes *)
+ let limit_raw =
+ (try
+ List.assoc "content-length" headers
+ with Not_found -> raise Fallback)
+ in
+ let limit =
+ (try (* TODO supports only a maximum content-length of 1Gb *)
+ int_of_string limit_raw
+ with Failure "int_of_string" ->
+ raise (Invalid_header ("content-length: " ^ limit_raw)))
+ in
+ Http_misc.buf_of_inchan ~limit ic
+ with Fallback -> Http_misc.buf_of_inchan ic) (* read until EOF *)
+ else (* TODO empty body for methods other than POST, is ok? *)
+ ""
+ in
+ (headers, body))
in
let query_post_params =
match meth with
method params_POST = query_post_params
method private fstLineToString =
- sprintf "%s %s %s"
- (string_of_method self#meth) self#uri (string_of_version self#version)
-
- end
-
-(* (* OLD IMPLEMENTATION *)
-class request
- ~body ~headers ~version ~meth ~uri
- ~clisockaddr ~srvsockaddr
- ~path ~params
- ()
- =
- object (self)
-
- inherit
- Http_message.message ~body ~headers ~version ~clisockaddr ~srvsockaddr
-
- val params_tbl =
- let tbl = Hashtbl.create (List.length params) in
- List.iter (fun (n,v) -> Hashtbl.add tbl n v) params;
- tbl
-
- method meth = meth
- method uri = uri
- method path = path
- method param name =
- try
- Hashtbl.find params_tbl name
- with Not_found ->
- raise (Param_not_found name)
- method paramAll name = List.rev (Hashtbl.find_all params_tbl name)
- method params = params
-
- method private fstLineToString =
- sprintf
- "%s %s %s"
- (string_of_method self#meth)
- self#uri
- (string_of_version self#version)
+ let method_string = string_of_method self#meth in
+ match self#version with
+ | Some version ->
+ sprintf "%s %s %s" method_string self#uri (string_of_version version)
+ | None -> sprintf "%s %s" method_string self#uri
end
-*)
(* "version code reason_phrase" *)
object (self)
+ (* note that response objects can't be created with a None version *)
inherit
- Http_message.message ~body ~headers ~version ~clisockaddr ~srvsockaddr
+ Http_message.message
+ ~body ~headers ~version:(Some version) ~clisockaddr ~srvsockaddr
val mutable _code =
match status with
| Some (s: Http_types.status) -> code_of_status s
val mutable _reason: string option = None
+ method private getRealVersion =
+ match self#version with
+ | None ->
+ failwith ("Http_response.fstLineToString: " ^
+ "can't serialize an HTTP response with no HTTP version defined")
+ | Some v -> string_of_version v
+
method code = _code
method setCode c =
ignore (status_of_code c); (* sanity check on c *)
| 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]
+ String.concat " "
+ [self#getRealVersion; string_of_int self#code; self#reason]
method setStatusLine s =
try
let subs = Pcre.extract ~rex:status_line_RE s in
method setServer s = self#replaceHeader "Server" s
method private fstLineToString =
- sprintf
- "%s %d %s"
- (string_of_version self#version)
- self#code
- self#reason
+ sprintf "%s %d %s" self#getRealVersion self#code self#reason
end
exception Invalid_code of int
exception Invalid_status of status
+exception Malformed_URL of string
exception Malformed_query of string
exception Malformed_query_part of string * string
exception Unsupported_method of string
class type message = object
- method version: version
+ method version: version option
method setVersion: version -> unit
method body: string