package tiny_httpd

  1. Overview
  2. Docs
Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source

Source file util.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
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
let percent_encode ?(skip = fun _ -> false) s =
  let buf = Buffer.create (String.length s) in
  String.iter
    (function
      | c when skip c -> Buffer.add_char buf c
      | ( ' ' | '!' | '"' | '#' | '$' | '%' | '&' | '\'' | '(' | ')' | '*' | '+'
        | ',' | '/' | ':' | ';' | '=' | '?' | '@' | '[' | ']' | '~' ) as c ->
        Printf.bprintf buf "%%%02X" (Char.code c)
      | c when Char.code c < 32 || Char.code c > 127 ->
        Printf.bprintf buf "%%%02X" (Char.code c)
      | c -> Buffer.add_char buf c)
    s;
  Buffer.contents buf

let int_of_hex_nibble = function
  | '0' .. '9' as c -> Char.code c - Char.code '0'
  | 'a' .. 'f' as c -> 10 + Char.code c - Char.code 'a'
  | 'A' .. 'F' as c -> 10 + Char.code c - Char.code 'A'
  | _ -> invalid_arg "string: invalid hex"

let percent_decode (s : string) : _ option =
  let buf = Buffer.create (String.length s) in
  let i = ref 0 in
  try
    while !i < String.length s do
      match String.get s !i with
      | '%' ->
        if !i + 2 < String.length s then (
          (match
             (int_of_hex_nibble (String.get s (!i + 1)) lsl 4)
             + int_of_hex_nibble (String.get s (!i + 2))
           with
          | n -> Buffer.add_char buf (Char.chr n)
          | exception _ -> raise Exit);
          i := !i + 3
        ) else
          raise Exit (* truncated *)
      | '+' ->
        Buffer.add_char buf ' ';
        incr i (* for query strings *)
      | c ->
        Buffer.add_char buf c;
        incr i
    done;
    Some (Buffer.contents buf)
  with Exit -> None

exception Invalid_query

let find_q_index_ s = String.index s '?'

let get_non_query_path s =
  match find_q_index_ s with
  | i -> String.sub s 0 i
  | exception Not_found -> s

let get_query s : string =
  match find_q_index_ s with
  | i -> String.sub s (i + 1) (String.length s - i - 1)
  | exception Not_found -> ""

let split_query s = get_non_query_path s, get_query s

let split_on_slash s : _ list =
  let l = ref [] in
  let i = ref 0 in
  let n = String.length s in
  while !i < n do
    match String.index_from s !i '/' with
    | exception Not_found ->
      if !i < n then (* last component *) l := String.sub s !i (n - !i) :: !l;
      i := n (* done *)
    | j ->
      if j > !i then l := String.sub s !i (j - !i) :: !l;
      i := j + 1
  done;
  List.rev !l

let parse_query s : (_ list, string) result =
  let s =
    (* skip hash if present *)
    match String.index_opt s '#' with
    | Some i -> String.sub s (i + 1) (String.length s - i - 1)
    | None -> s
  in
  let pairs = ref [] in
  let is_sep_ = function
    | '&' | ';' -> true
    | _ -> false
  in
  let i = ref 0 in
  let j = ref 0 in
  try
    let percent_decode s =
      match percent_decode s with
      | Some x -> x
      | None -> raise Invalid_query
    in
    let parse_pair () =
      let eq = String.index_from s !i '=' in
      let k = percent_decode @@ String.sub s !i (eq - !i) in
      let v = percent_decode @@ String.sub s (eq + 1) (!j - eq - 1) in
      pairs := (k, v) :: !pairs
    in
    while !i < String.length s do
      while !j < String.length s && not (is_sep_ (String.get s !j)) do
        incr j
      done;
      if !j < String.length s then (
        assert (is_sep_ (String.get s !j));
        parse_pair ();
        i := !j + 1;
        j := !i
      ) else (
        parse_pair ();
        i := String.length s (* done *)
      )
    done;
    Ok !pairs
  with
  | Invalid_argument _ | Not_found | Failure _ ->
    Error (Printf.sprintf "error in parse_query for %S: i=%d,j=%d" s !i !j)
  | Invalid_query -> Error ("invalid query string: " ^ s)

let show_sockaddr = function
  | Unix.ADDR_UNIX f -> f
  | Unix.ADDR_INET (inet, port) ->
    Printf.sprintf "%s:%d" (Unix.string_of_inet_addr inet) port

let is_ipv6_str addr : bool = String.contains addr ':'
OCaml

Innovation. Community. Security.