1
1
type t =
2
- { headers : Bigstringaf .t
3
- ; payload : Payload .t
2
+ { payload_length : int
3
+ ; is_fin : bool
4
+ ; mask : int32 option
5
+ ; payload : Payload .t
6
+ ; opcode : Websocket.Opcode .t
4
7
}
5
8
6
- let is_fin t =
7
- let bits = Bigstringaf. unsafe_get t. headers 0 |> Char. code in
9
+ let is_fin headers =
10
+ let bits = Bigstringaf. unsafe_get headers 0 |> Char. code in
8
11
bits land (1 lsl 7 ) = 1 lsl 7
9
12
;;
10
13
11
- let rsv t =
14
+ (* let rsv t =
12
15
let bits = Bigstringaf.unsafe_get t.headers 0 |> Char.code in
13
16
(bits lsr 4) land 0b0111
14
17
;;
18
+ *)
15
19
16
- let opcode t =
17
- let bits = Bigstringaf. unsafe_get t. headers 0 |> Char. code in
20
+ let opcode headers =
21
+ let bits = Bigstringaf. unsafe_get headers 0 |> Char. code in
18
22
bits land 0b1111 |> Websocket.Opcode. unsafe_of_code
19
23
;;
20
24
21
25
let payload_length_of_headers headers =
22
26
let bits = Bigstringaf. unsafe_get headers 1 |> Char. code in
23
27
let length = bits land 0b01111111 in
24
- if length = 126 then Bigstringaf. unsafe_get_int16_be headers 2 else
25
- (* This is technically unsafe, but if somebody's asking us to read 2^63
26
- * bytes, then we're already screwed. *)
27
- if length = 127 then Bigstringaf. unsafe_get_int64_be headers 2 |> Int64. to_int else
28
- length
28
+ if length < = 125 then
29
+ (* From RFC6455§5.3:
30
+ * The length of the "Payload data", in bytes: if 0-125, that is the
31
+ * payload length. *)
32
+ length
33
+ else if length = 126 then
34
+ (* From RFC6455§5.3:
35
+ * If 126, the following 2 bytes interpreted as a 16-bit unsigned integer
36
+ * are the payload length. *)
37
+ Bigstringaf. unsafe_get_int16_be headers 2
38
+ else begin
39
+ assert (length = 127 );
40
+ (* This is technically unsafe, but if somebody's asking us to read 2^63
41
+ * bytes, then we're already screwed. *)
42
+ Bigstringaf. unsafe_get_int64_be headers 2 |> Int64. to_int
43
+ end
29
44
;;
30
45
31
- let payload_length t = payload_length_of_headers t.headers
32
-
33
- let has_mask t =
34
- let bits = Bigstringaf. unsafe_get t.headers 1 |> Char. code in
35
- bits land (1 lsl 7 ) = 1 lsl 7
36
- ;;
46
+ (* let payload_length t = payload_length_of_headers t.headers *)
37
47
38
- let mask t =
39
- if not (has_mask t)
48
+ let mask =
49
+ let has_mask headers =
50
+ let bits = Bigstringaf. unsafe_get headers 1 |> Char. code in
51
+ (bits land 0b1000_0000 ) = 0b1000_0000
52
+ in
53
+ let mask_exn headers =
54
+ let bits = Bigstringaf. unsafe_get headers 1 |> Char. code in
55
+ if bits = 254 then Bigstringaf. unsafe_get_int32_be headers 4 else
56
+ if bits = 255 then Bigstringaf. unsafe_get_int32_be headers 10 else
57
+ if bits > = 127 then Bigstringaf. unsafe_get_int32_be headers 2 else
58
+ failwith " Frame.mask_exn: no mask present"
59
+ in
60
+ fun headers ->
61
+ if not (has_mask headers)
40
62
then None
41
63
else
42
- Some (
43
- let bits = Bigstringaf. unsafe_get t.headers 1 |> Char. code in
44
- if bits = 254 then Bigstringaf. unsafe_get_int32_be t.headers 4 else
45
- if bits = 255 then Bigstringaf. unsafe_get_int32_be t.headers 10 else
46
- Bigstringaf. unsafe_get_int32_be t.headers 2 )
47
- ;;
48
-
49
- let mask_exn t =
50
- let bits = Bigstringaf. unsafe_get t.headers 1 |> Char. code in
51
- if bits = 254 then Bigstringaf. unsafe_get_int32_be t.headers 4 else
52
- if bits = 255 then Bigstringaf. unsafe_get_int32_be t.headers 10 else
53
- if bits > = 127 then Bigstringaf. unsafe_get_int32_be t.headers 2 else
54
- failwith " Frame.mask_exn: no mask present"
55
- ;;
56
-
57
- let length t =
58
- let payload_length = payload_length t in
59
- Bigstringaf. length t.headers + payload_length
64
+ Some (mask_exn headers)
60
65
;;
61
66
62
67
let payload_offset_of_bits bits =
@@ -85,25 +90,23 @@ let parse_headers =
85
90
let payload_parser t =
86
91
let open Angstrom in
87
92
let unmask t bs ~src_off =
88
- match mask t with
93
+ match t.mask with
89
94
| None -> bs
90
95
| Some mask ->
91
96
Websocket.Frame. apply_mask mask bs ~src_off ;
92
97
bs
93
98
in
94
99
let finish payload =
95
- let open Angstrom in
96
100
Payload. close payload;
97
101
commit
98
102
in
99
103
let schedule_size ~src_off payload n =
100
- let open Angstrom in
101
104
begin if Payload. is_closed payload
102
105
then advance n
103
106
else take_bigstring n >> | fun bs ->
104
107
let faraday = Payload. unsafe_faraday payload in
105
108
Faraday. schedule_bigstring faraday (unmask ~src_off t bs)
106
- end *> commit
109
+ end < * commit
107
110
in
108
111
let read_exact =
109
112
let rec read_exact src_off n =
@@ -117,24 +120,28 @@ let payload_parser t =
117
120
available >> = fun m ->
118
121
let m' = (min m n) in
119
122
let n' = n - m' in
120
- schedule_size ~src_off t.payload m' >> = fun () -> read_exact (src_off + m') n'
123
+ schedule_size ~src_off t.payload m'
124
+ >> = fun () -> read_exact (src_off + m') n'
121
125
in
122
126
fun n -> read_exact 0 n
123
127
in
124
- read_exact (payload_length t)
128
+ read_exact t.payload_length
125
129
>> = fun () -> finish t.payload
126
130
;;
127
131
128
132
let frame ~buf =
129
133
let open Angstrom in
130
134
parse_headers
131
135
>> | fun headers ->
132
- let len = payload_length_of_headers headers in
133
- let payload = match len with
136
+ let payload_length = payload_length_of_headers headers
137
+ and is_fin = is_fin headers
138
+ and opcode = opcode headers
139
+ and mask = mask headers in
140
+ let payload = match payload_length with
134
141
| 0 -> Payload. empty
135
142
| _ -> Payload. create buf
136
143
in
137
- { headers ; payload }
144
+ { is_fin; opcode; mask; payload_length ; payload }
138
145
;;
139
146
140
147
module Reader = struct
@@ -157,9 +164,7 @@ module Reader = struct
157
164
skip_many
158
165
(frame ~buf < * commit >> = fun frame ->
159
166
let payload = frame.payload in
160
- let is_fin = is_fin frame in
161
- let opcode = opcode frame in
162
- let len = payload_length frame in
167
+ let { is_fin; opcode; payload_length = len; _ } = frame in
163
168
frame_handler ~opcode ~is_fin ~len payload;
164
169
payload_parser frame)
165
170
in
0 commit comments