+class request ic =
+ let (meth, uri, version) = Http_parser.parse_request_fst_line ic in
+ 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? *)
+ in
+ let query_post_params =
+ match meth with
+ | `POST ->
+ let ct = try List.assoc "content-type" headers with Not_found -> "" in
+ if ct = "application/x-www-form-urlencoded" then
+ Http_parser.split_query_params body
+ else []
+ | _ -> []
+ in
+ let params = query_post_params @ query_get_params in (* prefers POST params *)
+ let _ = debug_dump_request path params in
+ let (clisockaddr, srvsockaddr) =
+ (Http_misc.peername_of_in_channel ic, Http_misc.sockname_of_in_channel ic)
+ in