blob: 31e1c7428a093ce19ff2590bf72cfe2472fb63b5 (
plain)
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
|
#include "internal.h"
//
// content length functions
//
static const fhp_cl_parser_t FHP_DEFAULT_CL_PARSER = {
.state = FHP_CL_STATE_INIT,
.val = 0,
.err = FHP_OK,
};
fhp_err_t
fhp_cl_parser_init(fhp_cl_parser_t * const p) {
// init parser
*p = FHP_DEFAULT_CL_PARSER;
// return succes
return FHP_OK;
}
static fhp_err_t
fhp_cl_parser_push_byte(
fhp_cl_parser_t * const p,
uint8_t byte
) {
retry:
switch (p->state) {
case FHP_CL_STATE_INIT:
switch (byte) {
CASE_OWS_CHARS
// ignore
break;
CASE_DIGIT_CHARS
// set state
p->state = FHP_CL_STATE_DATA;
goto retry;
break;
default:
// invalid character before content-length
return FHP_ERR_INVALID_CHAR_BEFORE_CL;
}
break;
case FHP_CL_STATE_DATA:
switch (byte) {
CASE_OWS_CHARS
// set state
p->state = FHP_CL_STATE_TRAILING_SPACES;
goto retry;
break;
CASE_DIGIT_CHARS
{
// cache old value
uint64_t old_val = p->val;
// update value
p->val = p->val * 10 + (byte - '0');
// check for overflow
if (p->val < old_val)
return FHP_ERR_CL_OVERFLOW;
}
break;
default:
// invalid character in content-length
return FHP_ERR_INVALID_CHAR_IN_CL;
}
break;
case FHP_CL_STATE_TRAILING_SPACES:
switch (byte) {
CASE_OWS_CHARS
// ignore trailing spaces
break;
default:
// invalid character after content-length
return FHP_ERR_INVALID_CHAR_AFTER_CL;
}
break;
case FHP_CL_STATE_ERROR:
// return last error
return p->err;
break;
case FHP_CL_STATE_DONE:
// shouldn't be reached
return FHP_ERR_CL_PARSER_DONE;
break;
default:
// never reached
return FHP_ERR_BAD_CL_STATE;
}
// return succes
return FHP_OK;
}
fhp_err_t
fhp_cl_parser_push(
fhp_cl_parser_t *p,
uint8_t * const buf,
size_t len
) {
for (size_t i = 0; i < len; i++) {
// push byte
fhp_err_t err = fhp_cl_parser_push_byte(p, buf[i]);
// check error
if (err != FHP_OK) {
// cache error
p->err = err;
// set state
p->state = FHP_CL_STATE_ERROR;
// return error
return err;
}
}
// return succes
return FHP_OK;
}
fhp_err_t
fhp_cl_parser_done(
fhp_cl_parser_t * const p,
uint64_t * const ret_val
) {
// check for error
if (p->err != FHP_OK)
return p->err;
// set state
p->state = FHP_CL_STATE_DONE;
// save number of tes
if (ret_val)
*ret_val = p->val;
// return success
return FHP_OK;
}
|