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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
|
# HTTP/1.1 requests (RFC 9112) read a packet at a time: each packet's bytes added to what the last ones left, and every
# request they complete read: its line, its fields (names lowercased), its body by Content-Length or chunked, a chunked
# one's trailers. The grammar is h11's. A stream that is no HTTP fails its event.
record Field {
name: bytes
value: bytes
}
record Request {
method: bytes
target: bytes
minor = 1 # HTTP/1.minor
fields: list of Field
body: bytes
trailers: list of Field
}
state requests: list of Request
state pending: bytes # the bytes no request has completed
input packet = message { data: bytes }
fn letter(b) = b >= 0x61 && b <= 0x7a || b >= 0x41 && b <= 0x5a
fn digit(b) = b >= 0x30 && b <= 0x39
fn mark(b) = b == 0x21 || b >= 0x23 && b <= 0x27 || b == 0x2a || b == 0x2b || b == 0x2d || b == 0x2e # ! # $ % & ' * + - .
fn token(b) = letter(b) || digit(b) || mark(b) || b >= 0x5e && b <= 0x60 || b == 0x7c || b == 0x7e # and ^ _ ` | ~
fn hex(b) = digit(b) || b >= 0x61 && b <= 0x66 || b >= 0x41 && b <= 0x46
fn space(b) = b == 0 || b >= 9 && b <= 13 || b == 0x20 # never in a field value's words
fn blank(b) = b == 0x20 || b == 9
# Where the CRLF at or after i is, or -1 if it has not come yet.
fn crlf(d, i) {
let j = i
while j + 1 < d.bytes {
if d[j] == 13 && d[j + 1] == 10 { return j }
j = j + 1
}
return -1
}
fn lower(s) {
let out = s[0 .. 0]
for k in 0 .. s.bytes { out = out + byte(if s[k] >= 0x41 && s[k] <= 0x5a { s[k] + 32 } else { s[k] }) }
return out
}
# The field line d[i .. e]: its name lowercased, its value without the spaces around it.
fn field(d, i, e) -> Field {
let c = i
while c < e && d[c] != 0x3a { c = c + 1 }
require c > i && c < e
for k in i .. c { require token(d[k]) }
let a = c + 1
let b = e
while a < b && blank(d[a]) { a = a + 1 }
while b > a && blank(d[b - 1]) { b = b - 1 }
for k in a .. b { require !space(d[k]) || blank(d[k]) }
return Field { name: lower(d[i .. c]), value: d[a .. b] }
}
# The field lines from i to an empty line, and where it ends; -1 if they have not all come.
fn fields(d, i) {
let out: list of Field
let j = i
let e = crlf(d, j)
while e > j {
out.append(field(d, j, e))
j = e + 2
e = crlf(d, j)
}
return out, if e < 0 { -1 } else { e + 2 }
}
# The request at the start of d, and its length; -1 if d holds only part of one.
fn request(d) -> Request, number {
let e = crlf(d, 0)
if e < 0 { return Request {}, -1 }
let s1 = 0
while s1 < e && d[s1] != 0x20 { s1 = s1 + 1 }
let s2 = s1 + 1
while s2 < e && d[s2] != 0x20 { s2 = s2 + 1 }
require s1 > 0 && s2 > s1 + 1 && s2 + 9 == e
for k in 0 .. s1 { require token(d[k]) }
for k in s1 + 1 .. s2 { require d[k] >= 0x21 && d[k] <= 0x7e }
require d[s2 + 1 .. e - 1] == "HTTP/1." && (d[e - 1] == 0x30 || d[e - 1] == 0x31)
let found, i = fields(d, e + 2)
if i < 0 { return Request {}, -1 }
let hosts, coded, lengths, length = 0, 0, 0, 0
let chunked = false
for f in found {
if f.name == "host" { hosts = hosts + 1 }
if f.name == "transfer-encoding" {
coded = coded + 1
chunked = lower(f.value) == "chunked"
}
if f.name == "content-length" {
lengths = lengths + 1
require f.value.bytes > 0
for k in 0 .. f.value.bytes {
require digit(f.value[k])
length = length * 10 + number(f.value[k] - 0x30)
}
}
}
require hosts <= 1 && (hosts == 1 || d[e - 1] == 0x30) # HTTP/1.1 names its host
let body = d[0 .. 0]
let trailers: list of Field
let j = i
if coded > 0 {
require lengths == 0 && coded == 1 && chunked
let more = true
while more {
let c = crlf(d, j)
if c < 0 { return Request {}, -1 }
let semi = j
while semi < c && d[semi] != 0x3b { semi = semi + 1 }
let z = semi
if semi == c {
while z > j && blank(d[z - 1]) { z = z - 1 }
}
require z > j && z - j <= 20
let n = 0
for k in j .. z {
require hex(d[k])
n = n * 16 + number(if d[k] <= 0x39 { d[k] - 0x30 } else if d[k] >= 0x61 { d[k] - 0x57 } else { d[k] - 0x37 })
}
for k in semi .. c { require d[k] != 10 }
require n <= 2147483648 # 2^31 at most: ours, not h11's
if n == 0 {
let t, after = fields(d, c + 2)
if after < 0 { return Request {}, -1 }
for f in t { trailers.append(f) }
j = after
more = false
} else {
if d.bytes < c + 4 + n { return Request {}, -1 }
require d[c + 2 + n] == 13 && d[c + 3 + n] == 10
body = body + d[c + 2 .. c + 2 + n]
j = c + 4 + n
}
}
} else if lengths > 0 {
require lengths == 1 && length <= 2147483648
if d.bytes < i + length { return Request {}, -1 }
body = d[i .. i + length]
j = i + length
}
return Request { method: d[0 .. s1], target: d[s1 + 1 .. s2], minor: number(d[e - 1] - 0x30), fields: found, body: body,
trailers: trailers }, j
}
on packet {
let d = pending + packet.data
let going = true
while going && d.bytes > 0 {
let r, n = request(d)
if n < 0 {
going = false
} else {
requests.append(r)
d = d[n .. d.bytes]
}
}
pending = d
}
|