File Coverage

header.c
Criterion Covered Total %
statement 71 79 89.8
branch 58 70 82.8
condition n/a
subroutine n/a
pod n/a
total 129 149 86.5


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             }