-
Notifications
You must be signed in to change notification settings - Fork 2
/
httpRequest.ml
75 lines (67 loc) · 2 KB
/
httpRequest.ml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
(*
httpRequest.ml
Copyright (c) 2012- Masaki WATANABE
license: see LICENSE
*)
open Utils
open ExtString
open Lwt
type http_request = {
path_args : string list;
get_args : (string * string) list;
input_header_fields : (string * string) list;
}
type t = http_request
let string_until c stream =
Lwt_stream.get_while (fun c1 -> c <> c1) stream >>= fun chars ->
Lwt_stream.next stream >>= fun _ ->
return (String.implode chars)
;;
let parse_header stream =
string_until ' ' stream >>= fun method_str ->
string_until ' ' stream >>= fun query_string ->
string_until '\r' stream >>= fun version ->
Lwt_stream.next stream >>= function
| '\n' ->
return (method_str, query_string, version)
| _ -> failwith "invalid header"
;;
let parse_field stream =
Lwt_stream.npeek 2 stream >>= function
| ['\r'; '\n'] ->
Lwt_stream.nget 2 stream >>= fun _ -> return None
| _ ->
string_until ':' stream >>= fun key ->
string_until '\r' stream >>= fun value ->
Lwt_stream.next stream >>= function
| '\n' ->
return @@ Some (String.strip key, String.strip value)
| _ ->
return None
;;
let parse_many parse_fn stream =
let rec iter ret =
parse_fn stream >>= function
| Some value -> iter (value :: ret)
| None -> return ret in
iter []
;;
let parse_query_args query_string =
let parse_path_args str =
String.nsplit str "/" in
let parse_nv str =
match String.nsplit "=" str with
| [name; value] -> (name, value)
| _ -> (str, "") in
let parse_get_args str =
String.nsplit "&" str +> List.map parse_nv in
match String.nsplit query_string "?" with
| before :: after :: _ -> (parse_path_args before, parse_get_args after)
| _ -> (parse_path_args query_string, [])
;;
let parse stream =
parse_header stream >>= fun (method_str, query_string, version) ->
parse_many parse_field stream >>= fun input_header_fields ->
let (path_args, get_args) = parse_query_args query_string in
return {path_args; get_args; input_header_fields}
;;