mutable s_uri: string option;
mutable s_version: version option;
mutable s_headers: header_fields;
+ mutable num_bytes_parsed: int
}
type error =
s_uri = None;
s_version = Some HTTP09;
s_headers = [];
+ num_bytes_parsed = 0
}
let is_done s = s.cursor = Done
+ let num_bytes_parsed state =
+ if state.cursor = Start then 0 else state.num_bytes_parsed
(* From http://tools.ietf.org/html/rfc1945#section-4:
Simple-Request = "GET" SP Request-URI CRLF ; HTTP/0.9
let i = ref 0 in
while get_parse_result state = None && !i < len do
parse_char state str.[!i];
- incr i
+ incr i;
+ state.num_bytes_parsed <- state.num_bytes_parsed + 1
done;
match get_parse_result state with
| Some v -> Result (v, (String.sub str !i (len - !i)))
mutable s_status_code: int option;
mutable s_reason_phrase: string option;
mutable s_headers: header_fields;
+ mutable num_bytes_parsed: int
}
type error =
s_status_code = None;
s_reason_phrase = None;
s_headers = [];
+ num_bytes_parsed = 0
}
let is_done s = s.cursor = Done
+ let num_bytes_parsed state =
+ if state.cursor = Start then 0 else state.num_bytes_parsed
(* From http://tools.ietf.org/html/rfc1945#section-4:
Simple-Response = [ Entity-Body ] ; HTTP/0.9
let i = ref 0 in
while get_parse_result state = None && !i < len do
parse_char state str.[!i];
- incr i
+ incr i;
+ state.num_bytes_parsed <- state.num_bytes_parsed + 1
done;
match get_parse_result state with
| Some v -> Result (v, (String.sub str !i (len - !i)))
mutable remaining_length: int64;
max_payload_length: int64;
mutable body: Buffer.t;
- mutable headers: header_fields
+ mutable headers: header_fields;
+ mutable num_bytes_parsed: int64
}
let is_done s = s.cursor = Done
+ let num_bytes_parsed state = state.num_bytes_parsed
+
type error =
| Parse_error of cursor * char
remaining_length = -1L;
max_payload_length = max_payload_length;
body = Buffer.create 512;
- headers = []
+ headers = [];
+ num_bytes_parsed = 0L
}
let default_max_payload_length = Int64.of_int (10*1024*1024)
let content_length = get_content_length version hdrs in
let multipart_body = content_type_is_multipart_byteranges hdrs in
let default = init_default_state max_payload_length in
+
match version, meth, content_length, chunked, multipart_body with
| HTTP09, _, _, _, _
- | _, Request_header.Connect, _, _, _ (* The caller really needs to handle this specially. *)
- | _, _, `HTTP09, _, _
- | _, _, `Some 0L, _, _ -> No_payload
- | _, _, `Some l, _, _ -> Payload { default with
- content_length = Length l;
- remaining_length = l
- }
- | _, _, `Error, _, _ -> Error "Invalid Content-Length"
- | _, _, _, true, _ -> Payload { default with
- cursor = Start_chunk_length;
- content_length = Chunked
- }
- | _, _, _, _, true -> Error "multipart/byteranges is currently unsupported"
+ | _, Request_header.Connect, _, _, _ -> No_payload
+
+ (* We need to check Transfer-Encoding before Content-Length.
+ http://tools.ietf.org/html/rfc2616#section-4.4, Item 3.
+ *)
+ | _, _, _, true, false -> Payload { default with
+ cursor = Start_chunk_length;
+ content_length = Chunked
+ }
+ | _, _, `HTTP09, _, false
+ | HTTP11, _, `None, _, false -> No_payload
+ | _, _, `Some 0L, _, false -> No_payload
+ | _, _, `Some l, _, false -> Payload { default with
+ content_length = Length l;
+ remaining_length = l
+ }
+ | _, _, `Error, _, false -> Error "Invalid Content-Length"
+ | _, _, _, _, true -> Error "multipart/byteranges is unsupported"
(* Default to assuming that the payload is terminated by a Connection:close. *)
- | _ -> Payload default
+ | _ -> Payload default
let init_from_response ?(max_payload_length=default_max_payload_length) resp =
let version = resp.Response_header.version in
let content_length = get_content_length version hdrs in
let multipart_body = content_type_is_multipart_byteranges hdrs in
let default = init_default_state max_payload_length in
+
match status_code, content_length, chunked, multipart_body with
| sc, _, _, _
(* http://tools.ietf.org/html/rfc2616#section-4.4, Item 1. *)
when sc/100 = 1 || sc = 204 || sc = 304 -> No_payload
+ (* We need to check Transfer-Encoding before Content-Length.
+ http://tools.ietf.org/html/rfc2616#section-4.4, Item 3.
+ *)
+ | _, _, true, _ -> Payload { default with
+ cursor = Start_chunk_length;
+ content_length = Chunked
+ }
+
| _, `HTTP09, _, _ -> Payload default (* Connection: close *)
| _, `Some 0L, _, _ -> No_payload
| _, `Some l, _, _ -> Payload { default with
}
| _, `Error, _, _ -> Error "Invalid Content-Length"
- | _, _, true, _ -> Payload { default with
- cursor = Start_chunk_length;
- content_length = Chunked
- }
-
| _, _, _, true -> Error "multipart/byteranges is currently unsupported"
(* Default to assuming that the payload is terminated by a Connection:close. *)
| _ -> Payload default
let parse_char s c =
- Printf.printf "parsing %C in state %s...\n" c (string_of_cursor s.cursor);
+ dbg "parsing %C in state %s...\n" c (string_of_cursor s.cursor);
let raise_bad_char () = raise_error (Parse_error (s.cursor, c)) in
match s.cursor with
| In_body ->
let i = ref 0 in
while get_parse_result state = None && !i < len do
parse_char state str.[!i];
- incr i
+ incr i;
+ state.num_bytes_parsed <- Int64.succ state.num_bytes_parsed
done;
match get_parse_result state with
| Some v -> Result (v, (String.sub str !i (len - !i)))