line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
#include |
2
|
|
|
|
|
|
|
#include |
3
|
|
|
|
|
|
|
#include |
4
|
|
|
|
|
|
|
#include |
5
|
|
|
|
|
|
|
#include "glog.h" |
6
|
|
|
|
|
|
|
#include "gmem.h" |
7
|
|
|
|
|
|
|
#include "header.h" |
8
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
#define HEADER_IS_CLASS(h, v) (h->order >= v && h->order < (v+100)) |
10
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
#define HEADER_IS_GENERAL(h) HEADER_IS_CLASS(h, HEADER_TYPE_GENERAL) |
12
|
|
|
|
|
|
|
#define HEADER_IS_REQUEST(h) HEADER_IS_CLASS(h, HEADER_TYPE_REQUEST) |
13
|
|
|
|
|
|
|
#define HEADER_IS_RESPONSE(h) HEADER_IS_CLASS(h, HEADER_TYPE_RESPONSE) |
14
|
|
|
|
|
|
|
#define HEADER_IS_ENTITY(h) HEADER_IS_CLASS(h, HEADER_TYPE_ENTITY) |
15
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
/* |
17
|
|
|
|
|
|
|
* List of all standard headers, with the correct ordering for them. |
18
|
|
|
|
|
|
|
*/ |
19
|
|
|
|
|
|
|
static Header standard_headers[] = { |
20
|
|
|
|
|
|
|
/* general headers */ |
21
|
|
|
|
|
|
|
{ 100, "Cache-Control" }, |
22
|
|
|
|
|
|
|
{ 101, "Connection" }, |
23
|
|
|
|
|
|
|
{ 102, "Date" }, |
24
|
|
|
|
|
|
|
{ 103, "Pragma" }, |
25
|
|
|
|
|
|
|
{ 104, "Trailer" }, |
26
|
|
|
|
|
|
|
{ 105, "Transfer-Encoding" }, |
27
|
|
|
|
|
|
|
{ 106, "Upgrade" }, |
28
|
|
|
|
|
|
|
{ 107, "Via" }, |
29
|
|
|
|
|
|
|
{ 108, "Warning" }, |
30
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
/* request headers */ |
32
|
|
|
|
|
|
|
{ 200, "Accept" }, |
33
|
|
|
|
|
|
|
{ 201, "Accept-Charset" }, |
34
|
|
|
|
|
|
|
{ 202, "Accept-Encoding" }, |
35
|
|
|
|
|
|
|
{ 203, "Accept-Language" }, |
36
|
|
|
|
|
|
|
{ 204, "Authorization" }, |
37
|
|
|
|
|
|
|
{ 205, "Expect" }, |
38
|
|
|
|
|
|
|
{ 206, "From" }, |
39
|
|
|
|
|
|
|
{ 207, "Host" }, |
40
|
|
|
|
|
|
|
{ 208, "If-Match" }, |
41
|
|
|
|
|
|
|
{ 209, "If-Modified-Since" }, |
42
|
|
|
|
|
|
|
{ 210, "If-None-Match" }, |
43
|
|
|
|
|
|
|
{ 211, "If-Range" }, |
44
|
|
|
|
|
|
|
{ 212, "If-Unmodified-Since" }, |
45
|
|
|
|
|
|
|
{ 213, "Max-Forwards" }, |
46
|
|
|
|
|
|
|
{ 214, "Proxy-Authorization" }, |
47
|
|
|
|
|
|
|
{ 215, "Range" }, |
48
|
|
|
|
|
|
|
{ 216, "Referer" }, |
49
|
|
|
|
|
|
|
{ 217, "TE" }, |
50
|
|
|
|
|
|
|
{ 218, "User-Agent" }, |
51
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
/* response headers */ |
53
|
|
|
|
|
|
|
{ 300, "Accept-Ranges" }, |
54
|
|
|
|
|
|
|
{ 301, "Age" }, |
55
|
|
|
|
|
|
|
{ 302, "ETag" }, |
56
|
|
|
|
|
|
|
{ 303, "Location" }, |
57
|
|
|
|
|
|
|
{ 304, "Proxy-Authenticate" }, |
58
|
|
|
|
|
|
|
{ 305, "Retry-After" }, |
59
|
|
|
|
|
|
|
{ 306, "Server" }, |
60
|
|
|
|
|
|
|
{ 307, "Vary" }, |
61
|
|
|
|
|
|
|
{ 308, "WWW-Authenticate" }, |
62
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
/* entity headers */ |
64
|
|
|
|
|
|
|
{ 400, "Allow" }, |
65
|
|
|
|
|
|
|
{ 401, "Content-Encoding" }, |
66
|
|
|
|
|
|
|
{ 402, "Content-Language" }, |
67
|
|
|
|
|
|
|
{ 403, "Content-Length" }, |
68
|
|
|
|
|
|
|
{ 404, "Content-Location" }, |
69
|
|
|
|
|
|
|
{ 405, "Content-MD5" }, |
70
|
|
|
|
|
|
|
{ 406, "Content-Range" }, |
71
|
|
|
|
|
|
|
{ 407, "Content-Type" }, |
72
|
|
|
|
|
|
|
{ 408, "Expires" }, |
73
|
|
|
|
|
|
|
{ 409, "Last-Modified" }, |
74
|
|
|
|
|
|
|
}; |
75
|
|
|
|
|
|
|
static int standard_headers_size = sizeof(standard_headers) / sizeof(standard_headers[0]); |
76
|
|
|
|
|
|
|
|
77
|
|
|
|
|
|
|
static int normalise(char* buf, const char* str); |
78
|
|
|
|
|
|
|
|
79
|
|
|
|
|
|
|
|
80
|
96
|
|
|
|
|
|
Header* header_create(const char* name) { |
81
|
|
|
|
|
|
|
int l; |
82
|
96
|
|
|
|
|
|
Header* h = 0; |
83
|
96
|
|
|
|
|
|
GMEM_NEW(h, Header*, sizeof(Header)); |
84
|
96
|
|
|
|
|
|
h->order = HEADER_TYPE_NONE; |
85
|
96
|
|
|
|
|
|
l = strlen(name) + 1; |
86
|
96
|
|
|
|
|
|
GMEM_NEW(h->name, char*, l); |
87
|
96
|
|
|
|
|
|
normalise(h->name, name); |
88
|
|
|
|
|
|
|
GLOG(("=C= Created header [%s] => [%s]", name, h->name)); |
89
|
96
|
|
|
|
|
|
return h; |
90
|
|
|
|
|
|
|
} |
91
|
|
|
|
|
|
|
|
92
|
46
|
|
|
|
|
|
Header* header_clone(Header* header) { |
93
|
|
|
|
|
|
|
Header *h; |
94
|
46
|
100
|
|
|
|
|
if (header->order != HEADER_TYPE_NONE) { |
95
|
11
|
|
|
|
|
|
return header; |
96
|
|
|
|
|
|
|
} |
97
|
|
|
|
|
|
|
|
98
|
35
|
|
|
|
|
|
h = header_create(header->name); |
99
|
35
|
|
|
|
|
|
return h; |
100
|
|
|
|
|
|
|
} |
101
|
|
|
|
|
|
|
|
102
|
181
|
|
|
|
|
|
void header_destroy(Header* header) { |
103
|
181
|
100
|
|
|
|
|
if (header->order != HEADER_TYPE_NONE) { |
104
|
85
|
|
|
|
|
|
return; |
105
|
|
|
|
|
|
|
} |
106
|
96
|
|
|
|
|
|
GMEM_DELSTR(header->name, -1); |
107
|
96
|
|
|
|
|
|
GMEM_DEL(header, Header*, sizeof(Header)); |
108
|
|
|
|
|
|
|
} |
109
|
|
|
|
|
|
|
|
110
|
|
|
|
|
|
|
#define CONVERT(c) c == '_' ? '-' : isupper(c) ? tolower(c) : c |
111
|
|
|
|
|
|
|
|
112
|
|
|
|
|
|
|
/* TODO: this could probably made faster if we precomputed the CONVERTed */ |
113
|
|
|
|
|
|
|
/* values instead of doing it over and over again... */ |
114
|
5914
|
|
|
|
|
|
int header_compare(const char* n1, const char* n2) { |
115
|
5914
|
|
|
|
|
|
int p = 0; |
116
|
|
|
|
|
|
|
char c1; |
117
|
|
|
|
|
|
|
char c2; |
118
|
|
|
|
|
|
|
while (1) { |
119
|
9627
|
100
|
|
|
|
|
if (n1[p] == '\0' || n2[p] == '\0') { |
|
|
100
|
|
|
|
|
|
120
|
|
|
|
|
|
|
break; |
121
|
|
|
|
|
|
|
} |
122
|
9340
|
100
|
|
|
|
|
c1 = CONVERT(n1[p]); |
|
|
100
|
|
|
|
|
|
123
|
9340
|
50
|
|
|
|
|
c2 = CONVERT(n2[p]); |
|
|
100
|
|
|
|
|
|
124
|
9340
|
100
|
|
|
|
|
if (c1 < c2) { |
125
|
2868
|
|
|
|
|
|
return -1; |
126
|
|
|
|
|
|
|
} |
127
|
6472
|
100
|
|
|
|
|
if (c1 > c2) { |
128
|
2759
|
|
|
|
|
|
return +1; |
129
|
|
|
|
|
|
|
} |
130
|
3713
|
|
|
|
|
|
++p; |
131
|
3713
|
|
|
|
|
|
} |
132
|
287
|
100
|
|
|
|
|
if (n1[p] == '\0' && n2[p] != '\0') { |
|
|
100
|
|
|
|
|
|
133
|
48
|
|
|
|
|
|
return -1; |
134
|
|
|
|
|
|
|
} |
135
|
239
|
100
|
|
|
|
|
if (n1[p] != '\0' && n2[p] == '\0') { |
|
|
50
|
|
|
|
|
|
136
|
7
|
|
|
|
|
|
return +1; |
137
|
|
|
|
|
|
|
} |
138
|
232
|
|
|
|
|
|
return 0; |
139
|
|
|
|
|
|
|
} |
140
|
|
|
|
|
|
|
|
141
|
5890
|
|
|
|
|
|
int header_matches_type_or_name(const Header* h, int type, const char* name) { |
142
|
|
|
|
|
|
|
int cmp; |
143
|
5890
|
50
|
|
|
|
|
if (type != HEADER_TYPE_NONE && !HEADER_IS_CLASS(h, type)) { |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
144
|
0
|
|
|
|
|
|
return 0; |
145
|
|
|
|
|
|
|
} |
146
|
5890
|
|
|
|
|
|
cmp = header_compare(name, h->name); |
147
|
|
|
|
|
|
|
/* GLOG(("=C= compare [%s] & [%s] => %d", name, h->name, cmp)); */ |
148
|
5890
|
|
|
|
|
|
return cmp == 0; |
149
|
|
|
|
|
|
|
} |
150
|
|
|
|
|
|
|
|
151
|
135
|
|
|
|
|
|
Header* header_lookup_standard(int type, const char* name) { |
152
|
|
|
|
|
|
|
int j; |
153
|
5224
|
100
|
|
|
|
|
for (j = 0; j < standard_headers_size; ++j) { |
154
|
5163
|
|
|
|
|
|
Header* h = &standard_headers[j]; |
155
|
5163
|
100
|
|
|
|
|
if (header_matches_type_or_name(h, type, name)) { |
156
|
74
|
|
|
|
|
|
return h; |
157
|
|
|
|
|
|
|
} |
158
|
|
|
|
|
|
|
} |
159
|
|
|
|
|
|
|
|
160
|
61
|
|
|
|
|
|
return 0; |
161
|
|
|
|
|
|
|
} |
162
|
|
|
|
|
|
|
|
163
|
0
|
|
|
|
|
|
void header_dump(const Header* h, FILE* fp) { |
164
|
0
|
|
|
|
|
|
fprintf(fp, "[%p", h); |
165
|
0
|
0
|
|
|
|
|
if (h) { |
166
|
0
|
|
|
|
|
|
fprintf(fp, "|%3d|%s", h->order, h->name); |
167
|
|
|
|
|
|
|
} |
168
|
0
|
|
|
|
|
|
fprintf(fp, "]\n"); |
169
|
0
|
|
|
|
|
|
fflush(fp); |
170
|
0
|
|
|
|
|
|
} |
171
|
|
|
|
|
|
|
|
172
|
34
|
|
|
|
|
|
int header_is_entity(const Header* h) { |
173
|
34
|
|
|
|
|
|
const char* start = "content-"; |
174
|
|
|
|
|
|
|
int j; |
175
|
|
|
|
|
|
|
|
176
|
34
|
100
|
|
|
|
|
if (HEADER_IS_ENTITY(h)) { |
|
|
100
|
|
|
|
|
|
177
|
|
|
|
|
|
|
GLOG(("=C= header [%s] is entity (QUICK)", h->name)); |
178
|
16
|
|
|
|
|
|
return 1; |
179
|
|
|
|
|
|
|
} |
180
|
|
|
|
|
|
|
|
181
|
18
|
50
|
|
|
|
|
if (HEADER_IS_GENERAL(h) || |
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
182
|
16
|
100
|
|
|
|
|
HEADER_IS_REQUEST(h) || |
|
|
50
|
|
|
|
|
|
183
|
14
|
100
|
|
|
|
|
HEADER_IS_RESPONSE(h)) { |
184
|
|
|
|
|
|
|
GLOG(("=C= header [%s] is not entity (QUICK)", h->name)); |
185
|
7
|
|
|
|
|
|
return 0; |
186
|
|
|
|
|
|
|
} |
187
|
|
|
|
|
|
|
|
188
|
57
|
100
|
|
|
|
|
for (j = 0; start[j] != 0; ++j) { |
189
|
53
|
100
|
|
|
|
|
if (h->name[j] == '\0') { |
190
|
|
|
|
|
|
|
GLOG(("=C= header [%s] is not entity (EOS)", h->name)); |
191
|
2
|
|
|
|
|
|
return 0; |
192
|
|
|
|
|
|
|
} |
193
|
51
|
100
|
|
|
|
|
if (tolower(h->name[j]) != start[j]) { |
194
|
|
|
|
|
|
|
GLOG(("=C= header [%s] is not entity (DIFF)", h->name)); |
195
|
5
|
|
|
|
|
|
return 0; |
196
|
|
|
|
|
|
|
} |
197
|
|
|
|
|
|
|
} |
198
|
|
|
|
|
|
|
|
199
|
|
|
|
|
|
|
GLOG(("=C= header [%s] is entity (CMP)", h->name)); |
200
|
4
|
|
|
|
|
|
return 1; |
201
|
|
|
|
|
|
|
} |
202
|
|
|
|
|
|
|
|
203
|
96
|
|
|
|
|
|
static int normalise(char* buf, const char* str) { |
204
|
96
|
|
|
|
|
|
int word = 0; |
205
|
96
|
|
|
|
|
|
int j = 0; |
206
|
492
|
100
|
|
|
|
|
for (j = 0; str[j] != '\0'; ++j) { |
207
|
396
|
100
|
|
|
|
|
if (isalpha(str[j])) { |
208
|
376
|
100
|
|
|
|
|
if (word) { |
209
|
266
|
|
|
|
|
|
buf[j] = tolower(str[j]); |
210
|
|
|
|
|
|
|
} else { |
211
|
110
|
|
|
|
|
|
buf[j] = toupper(str[j]); |
212
|
376
|
|
|
|
|
|
word = 1; |
213
|
|
|
|
|
|
|
} |
214
|
|
|
|
|
|
|
} else { |
215
|
20
|
100
|
|
|
|
|
buf[j] = str[j] == '_' ? '-' : str[j]; |
216
|
20
|
|
|
|
|
|
word = 0; |
217
|
|
|
|
|
|
|
} |
218
|
|
|
|
|
|
|
} |
219
|
96
|
|
|
|
|
|
buf[j] = '\0'; |
220
|
96
|
|
|
|
|
|
return j; |
221
|
|
|
|
|
|
|
} |