| 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
|
88
|
|
|
|
|
|
Header* header_create(const char* name) { |
|
81
|
|
|
|
|
|
|
int l; |
|
82
|
88
|
|
|
|
|
|
Header* h = 0; |
|
83
|
88
|
|
|
|
|
|
GMEM_NEW(h, Header*, sizeof(Header)); |
|
84
|
88
|
|
|
|
|
|
h->order = HEADER_TYPE_NONE; |
|
85
|
88
|
|
|
|
|
|
l = strlen(name) + 1; |
|
86
|
88
|
|
|
|
|
|
GMEM_NEW(h->name, char*, l); |
|
87
|
88
|
|
|
|
|
|
normalise(h->name, name); |
|
88
|
|
|
|
|
|
|
GLOG(("=C= Created header [%s] => [%s]", name, h->name)); |
|
89
|
88
|
|
|
|
|
|
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
|
173
|
|
|
|
|
|
void header_destroy(Header* header) { |
|
103
|
173
|
100
|
|
|
|
|
if (header->order != HEADER_TYPE_NONE) { |
|
104
|
85
|
|
|
|
|
|
return; |
|
105
|
|
|
|
|
|
|
} |
|
106
|
88
|
|
|
|
|
|
GMEM_DELSTR(header->name, -1); |
|
107
|
88
|
|
|
|
|
|
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
|
5534
|
|
|
|
|
|
int header_compare(const char* n1, const char* n2) { |
|
115
|
5534
|
|
|
|
|
|
int p = 0; |
|
116
|
|
|
|
|
|
|
char c1; |
|
117
|
|
|
|
|
|
|
char c2; |
|
118
|
|
|
|
|
|
|
while (1) { |
|
119
|
9227
|
100
|
|
|
|
|
if (n1[p] == '\0' || n2[p] == '\0') { |
|
|
|
100
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
break; |
|
121
|
|
|
|
|
|
|
} |
|
122
|
8944
|
100
|
|
|
|
|
c1 = CONVERT(n1[p]); |
|
|
|
100
|
|
|
|
|
|
|
123
|
8944
|
50
|
|
|
|
|
c2 = CONVERT(n2[p]); |
|
|
|
100
|
|
|
|
|
|
|
124
|
8944
|
100
|
|
|
|
|
if (c1 < c2) { |
|
125
|
2660
|
|
|
|
|
|
return -1; |
|
126
|
|
|
|
|
|
|
} |
|
127
|
6284
|
100
|
|
|
|
|
if (c1 > c2) { |
|
128
|
2591
|
|
|
|
|
|
return +1; |
|
129
|
|
|
|
|
|
|
} |
|
130
|
3693
|
|
|
|
|
|
++p; |
|
131
|
3693
|
|
|
|
|
|
} |
|
132
|
283
|
100
|
|
|
|
|
if (n1[p] == '\0' && n2[p] != '\0') { |
|
|
|
100
|
|
|
|
|
|
|
133
|
48
|
|
|
|
|
|
return -1; |
|
134
|
|
|
|
|
|
|
} |
|
135
|
235
|
100
|
|
|
|
|
if (n1[p] != '\0' && n2[p] == '\0') { |
|
|
|
50
|
|
|
|
|
|
|
136
|
7
|
|
|
|
|
|
return +1; |
|
137
|
|
|
|
|
|
|
} |
|
138
|
228
|
|
|
|
|
|
return 0; |
|
139
|
|
|
|
|
|
|
} |
|
140
|
|
|
|
|
|
|
|
|
141
|
5510
|
|
|
|
|
|
int header_matches_type_or_name(const Header* h, int type, const char* name) { |
|
142
|
|
|
|
|
|
|
int cmp; |
|
143
|
5510
|
50
|
|
|
|
|
if (type != HEADER_TYPE_NONE && !HEADER_IS_CLASS(h, type)) { |
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
144
|
0
|
|
|
|
|
|
return 0; |
|
145
|
|
|
|
|
|
|
} |
|
146
|
5510
|
|
|
|
|
|
cmp = header_compare(name, h->name); |
|
147
|
|
|
|
|
|
|
/* GLOG(("=C= compare [%s] & [%s] => %d", name, h->name, cmp)); */ |
|
148
|
5510
|
|
|
|
|
|
return cmp == 0; |
|
149
|
|
|
|
|
|
|
} |
|
150
|
|
|
|
|
|
|
|
|
151
|
127
|
|
|
|
|
|
Header* header_lookup_standard(int type, const char* name) { |
|
152
|
|
|
|
|
|
|
int j; |
|
153
|
4840
|
100
|
|
|
|
|
for (j = 0; j < standard_headers_size; ++j) { |
|
154
|
4787
|
|
|
|
|
|
Header* h = &standard_headers[j]; |
|
155
|
4787
|
100
|
|
|
|
|
if (header_matches_type_or_name(h, type, name)) { |
|
156
|
74
|
|
|
|
|
|
return h; |
|
157
|
|
|
|
|
|
|
} |
|
158
|
|
|
|
|
|
|
} |
|
159
|
|
|
|
|
|
|
|
|
160
|
53
|
|
|
|
|
|
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
|
88
|
|
|
|
|
|
static int normalise(char* buf, const char* str) { |
|
204
|
88
|
|
|
|
|
|
int word = 0; |
|
205
|
88
|
|
|
|
|
|
int j = 0; |
|
206
|
460
|
100
|
|
|
|
|
for (j = 0; str[j] != '\0'; ++j) { |
|
207
|
372
|
100
|
|
|
|
|
if (isalpha(str[j])) { |
|
208
|
352
|
100
|
|
|
|
|
if (word) { |
|
209
|
250
|
|
|
|
|
|
buf[j] = tolower(str[j]); |
|
210
|
|
|
|
|
|
|
} else { |
|
211
|
102
|
|
|
|
|
|
buf[j] = toupper(str[j]); |
|
212
|
352
|
|
|
|
|
|
word = 1; |
|
213
|
|
|
|
|
|
|
} |
|
214
|
|
|
|
|
|
|
} else { |
|
215
|
20
|
100
|
|
|
|
|
buf[j] = str[j] == '_' ? '-' : str[j]; |
|
216
|
20
|
|
|
|
|
|
word = 0; |
|
217
|
|
|
|
|
|
|
} |
|
218
|
|
|
|
|
|
|
} |
|
219
|
88
|
|
|
|
|
|
buf[j] = '\0'; |
|
220
|
88
|
|
|
|
|
|
return j; |
|
221
|
|
|
|
|
|
|
} |