↑ 1 #include <string.h>
↑ 2 #include <stdio.h>
↑ 3 #include <errno.h>
↑ 4 #include "rh_string.h"
↑ 5 #include "rhttpd.h"
↑ 6 #include "http.h"
↑ 7 #include "http_header.h"
↑ 8 #include "http_host.h"
↑ 9 #include "rh_chunk.h"
↑ 10 #include "http_range.h"
↑ 11 #include "log.h"
↑ 12
↑ 13 #define MAP_WANT_HTTP_HOST MAP_HTTP_HOST
↑ 14 #define MAP_WANT_HTTP_KEY MAP_HTTP_KEY
↑ 15 #define MAP_WANT_HTTP_VAL MAP_HTTP_VAL
↑ 16 #include "rh_charmap.h"
↑ 17
↑ 18 #define DECLARE_PROTO(_call,_name) \
↑ 19 static http_status_t http_header_ ## _call ## _ ## _name \
↑ 20 (http_header_entry_t *entry)
↑ 21
↑ 22 DECLARE_PROTO(parse, host);
↑ 23 DECLARE_PROTO(destroy, host);
↑ 24 DECLARE_PROTO(parse, validate);
↑ 25 DECLARE_PROTO(parse, connection);
↑ 26
↑ 27 #undef DECLARE_PROTO
↑ 28
↑ 29
↑ 30 #define http_header_parse_NULL NULL
↑ 31 #define http_header_destroy_NULL NULL
↑ 32
↑ 33 #define DECLARE_KEY(_key, _merge_ch, _type,_first,_full,_destroy) \
↑ 34 { CONST_STR_LEN(_key), \
↑ 35 _merge_ch, \
↑ 36 HTTP_HEADER_KEY_ ## _type, \
↑ 37 http_header_parse_ ## _first, \
↑ 38 http_header_parse_ ## _full, \
↑ 39 http_header_destroy_ ## _destroy \
↑ 40 }
↑ 41
↑ 42 static const struct http_header_key
↑ 43 http_header_keys[HTTP_HEADER_KEY_MAX] =
↑ 44 {
↑ 45 DECLARE_KEY("", ' ', RESPONSE, NULL, NULL, NULL),
↑ 46
↑ 47 DECLARE_KEY("Host", ' ', HOST, host, NULL, host),
↑ 48 DECLARE_KEY("ETag", ' ', ETAG, validate, NULL, NULL),
↑ 49 DECLARE_KEY("Date", ' ', DATE, validate, NULL, NULL),
↑ 50 DECLARE_KEY("From", ' ', FROM, validate, NULL, NULL),
↑ 51 DECLARE_KEY("Vary", ' ', VARY, validate, NULL, NULL),
↑ 52
↑ 53 DECLARE_KEY("TE", ' ', TE, validate, NULL, NULL),
↑ 54
↑ 55 DECLARE_KEY("Via", ' ', VIA, validate, NULL, NULL),
↑ 56 DECLARE_KEY("Age", ' ', AGE, validate, NULL, NULL),
↑ 57
↑ 58 DECLARE_KEY("Title", ' ', TITLE, validate, NULL, NULL),
↑ 59 DECLARE_KEY("Range", ' ', RANGE, range, NULL, range),
↑ 60 DECLARE_KEY("X-Pad", ' ', X_PAD, validate, NULL, NULL),
↑ 61 DECLARE_KEY("Allow", ' ', ALLOW, validate, NULL, NULL),
↑ 62 DECLARE_KEY("UA-OS", ' ', UA_OS, validate, NULL, NULL),
↑ 63
↑ 64 DECLARE_KEY("Set-Cookie", ' ', SET_COOKIE, validate, NULL, NULL),
↑ 65 DECLARE_KEY("Connection", ' ', CONNECTION, connection, NULL, NULL),
↑ 66 DECLARE_KEY("User-Agent", ' ', USER_AGENT, validate, NULL, NULL),
↑ 67 DECLARE_KEY("Keep-Alive", ' ', KEEP_ALIVE, validate, NULL, NULL),
↑ 68
↑ 69 DECLARE_KEY("Accept", ' ', ACCEPT, validate, NULL, NULL),
↑ 70 DECLARE_KEY("Cookie", ' ', COOKIE, validate, NULL, NULL),
↑ 71 DECLARE_KEY("UA-CPU", ' ', UA_CPU, validate, NULL, NULL),
↑ 72 DECLARE_KEY("Expect", ' ', EXPECT, validate, NULL, NULL),
↑ 73 DECLARE_KEY("Pragma", ' ', PRAGMA, validate, NULL, NULL),
↑ 74 DECLARE_KEY("Public", ' ', PUBLIC, validate, NULL, NULL),
↑ 75 DECLARE_KEY("Server", ' ', SERVER, validate, NULL, NULL),
↑ 76
↑ 77 DECLARE_KEY("UA-Disp", ' ', UA_DISP, validate, NULL, NULL),
↑ 78 DECLARE_KEY("X-Cache", ' ', X_CACHE, validate, NULL, NULL),
↑ 79 DECLARE_KEY("Trailer", ' ', TRAILER, validate, NULL, NULL),
↑ 80 DECLARE_KEY("Upgrade", ' ', UPGRADE, validate, NULL, NULL),
↑ 81 DECLARE_KEY("Cookie2", ' ', COOKIE2, validate, NULL, NULL),
↑ 82 DECLARE_KEY("Expires", ' ', EXPIRES, validate, NULL, NULL),
↑ 83 DECLARE_KEY("Referer", ' ', REFERER, validate, NULL, NULL),
↑ 84 DECLARE_KEY("Warning", ' ', WARNING, validate, NULL, NULL),
↑ 85
↑ 86 DECLARE_KEY("X-Forwarded-For", ' ', X_FORWARDED_FOR,validate,NULL,NULL),
↑ 87 DECLARE_KEY("X-Serial-Number", ' ', X_SERIAL_NUMBER,validate,NULL,NULL),
↑ 88 DECLARE_KEY("Accept-Encoding", ' ', ACCEPT_ENCODING,validate,NULL,NULL),
↑ 89 DECLARE_KEY("Accept-Language", ' ', ACCEPT_LANGUAGE,validate,NULL,NULL),
↑ 90
↑ 91 DECLARE_KEY("UA-Color", ' ', UA_COLOR, validate, NULL, NULL),
↑ 92 DECLARE_KEY("If-Match", ' ', IF_MATCH, validate, NULL, NULL),
↑ 93 DECLARE_KEY("If-Range", ' ', IF_RANGE, validate, NULL, NULL),
↑ 94 DECLARE_KEY("Location", ' ', LOCATION, validate, NULL, NULL),
↑ 95
↑ 96 DECLARE_KEY("UA-Pixels", ' ', UA_PIXELS, validate, NULL, NULL),
↑ 97 DECLARE_KEY("Client-ip", ' ', CLIENT_IP, validate, NULL, NULL),
↑ 98
↑ 99 DECLARE_KEY("Content-Type", ',', CONTENT_TYPE, validate, NULL, NULL),
↑ 100 DECLARE_KEY("Content-Base", ' ', CONTENT_BASE, validate, NULL, NULL),
↑ 101 DECLARE_KEY("Max-Forwards", ' ', MAX_FORWARDS, validate, NULL, NULL),
↑ 102 DECLARE_KEY("MIME-Version", ' ', MIME_VERSION, validate, NULL, NULL),
↑ 103
↑ 104 DECLARE_KEY("Content-Length", ' ', CONTENT_LENGTH, validate, NULL,NULL),
↑ 105 DECLARE_KEY("Accept-Charset", ' ', ACCEPT_CHARSET, validate, NULL,NULL),
↑ 106
↑ 107 DECLARE_KEY("Last-Modified", ' ', LAST_MODIFIED, validate, NULL, NULL),
↑ 108 DECLARE_KEY("Content-Range", ' ', CONTENT_RANGE, validate, NULL, NULL),
↑ 109 DECLARE_KEY("Authorization", ' ', AUTHORIZATION, validate, NULL, NULL),
↑ 110 DECLARE_KEY("Accept-Ranges", ' ', ACCEPT_RANGES, validate, NULL, NULL),
↑ 111 DECLARE_KEY("Cache-Control", ' ', CACHE_CONTROL, validate, NULL, NULL),
↑ 112 DECLARE_KEY("If-None-Match", ' ', IF_NONE_MATCH, validate, NULL, NULL),
↑ 113
↑ 114 DECLARE_KEY("Transfer-Encoding", ' ', TRANSFER_ENCODING,
↑ 115 validate, NULL, NULL),
↑ 116
↑ 117 DECLARE_KEY("If-Modified-Since", ' ', IF_MODIFIED_SINCE,
↑ 118 validate, NULL, NULL),
↑ 119
↑ 120 DECLARE_KEY("Retry-After", ' ', RETRY_AFTER, validate, NULL, NULL),
↑ 121 DECLARE_KEY("Set-Cookie2", ' ', SET_COOKIE2, validate, NULL, NULL),
↑ 122 DECLARE_KEY("Content-MD5", ' ', CONTENT_MD5, validate, NULL, NULL),
↑ 123
↑ 124
↑ 125 DECLARE_KEY("WWW-Authenticate", ' ', WWW_AUTHENTICATE,
↑ 126 validate, NULL, NULL),
↑ 127 DECLARE_KEY("Proxy-Connection", ' ', PROXY_CONNECTION,
↑ 128 validate, NULL, NULL),
↑ 129 DECLARE_KEY("Content-Encoding", ' ', CONTENT_ENCODING,
↑ 130 validate, NULL, NULL),
↑ 131 DECLARE_KEY("Content-Language", ' ', CONTENT_LANGUAGE,
↑ 132 validate, NULL, NULL),
↑ 133 DECLARE_KEY("Content-Location", ' ', CONTENT_LOCATION,
↑ 134 validate, NULL, NULL),
↑ 135
↑ 136 DECLARE_KEY("Proxy-Authenticate", ' ', PROXY_AUTHENTICATE,
↑ 137 validate, NULL, NULL),
↑ 138
↑ 139 DECLARE_KEY("If-Unmodified-Since", ' ', IF_UNMODIFIED_SINCE,
↑ 140 validate, NULL, NULL),
↑ 141 DECLARE_KEY("Proxy-Authorization", ' ', PROXY_AUTHORIZATION,
↑ 142 validate, NULL, NULL),
↑ 143
↑ 144 DECLARE_KEY("Status", ' ', STATUS, validate, NULL, NULL),
↑ 145
↑ 146 };
↑ 147 #undef DECLARE_KEY
↑ 148 #undef http_header_parse_NULL
↑ 149
↑ 150 #define DECLARE_RESPONSE_INTERNAL(_code, _msg) \
↑ 151 { (_msg), CONST_LEN(_msg), CONST_LEN(_msg), RH_BUFFER_CONST }
↑ 152
↑ 153 #define DECLARE_RESPONSE(_code, _msg) \
↑ 154 DECLARE_RESPONSE_INTERNAL(_code, "HTTP/1.1 " _msg)
↑ 155
↑ 156 /* idea of this response vector and its access method is based on apache */
↑ 157 static const rh_buffer_t http_response[] = {
↑ 158
↑ 159 #define HTTP_RESPONSE_100 0
↑ 160
↑ 161 DECLARE_RESPONSE(100, "100 Continue"),
↑ 162 DECLARE_RESPONSE(101, "101 Switching Protocols"),
↑ 163
↑ 164 #define HTTP_RESPONSE_200 (HTTP_RESPONSE_100 + 2)
↑ 165
↑ 166 DECLARE_RESPONSE(200, "200 OK"),
↑ 167 DECLARE_RESPONSE(201, "201 Created"),
↑ 168 DECLARE_RESPONSE(202, "202 Accepted"),
↑ 169 DECLARE_RESPONSE(203, "203 Non-Authoritative Information"),
↑ 170 DECLARE_RESPONSE(204, "204 No Content"),
↑ 171 DECLARE_RESPONSE(205, "205 Reset Content"),
↑ 172 DECLARE_RESPONSE(206, "206 Partial Content"),
↑ 173
↑ 174 #define HTTP_RESPONSE_300 (HTTP_RESPONSE_200 + 7)
↑ 175
↑ 176 DECLARE_RESPONSE(300, "300 Multiple Choices"),
↑ 177 DECLARE_RESPONSE(301, "301 Moved Permanently"),
↑ 178 DECLARE_RESPONSE(302, "302 Found"),
↑ 179 DECLARE_RESPONSE(303, "303 See Other"),
↑ 180 DECLARE_RESPONSE(304, "304 Not Modified"),
↑ 181 DECLARE_RESPONSE(305, "305 Use Proxy"),
↑ 182 DECLARE_RESPONSE(306, "306 (Unused)"),
↑ 183 DECLARE_RESPONSE(307, "307 Temporary Redirect"),
↑ 184
↑ 185 #define HTTP_RESPONSE_400 (HTTP_RESPONSE_300 + 8)
↑ 186
↑ 187 DECLARE_RESPONSE(400, "400 Bad Request"),
↑ 188 DECLARE_RESPONSE(401, "401 Unauthorized"),
↑ 189 DECLARE_RESPONSE(402, "402 Payment Required"),
↑ 190 DECLARE_RESPONSE(403, "403 Forbidden"),
↑ 191 DECLARE_RESPONSE(404, "404 Not Found"),
↑ 192 DECLARE_RESPONSE(405, "405 Method Not Allowed"),
↑ 193 DECLARE_RESPONSE(406, "406 Not Acceptable"),
↑ 194 DECLARE_RESPONSE(407, "407 Proxy Authentication Required"),
↑ 195 DECLARE_RESPONSE(408, "408 Request Timeout"),
↑ 196 DECLARE_RESPONSE(419, "419 Conflict"),
↑ 197 DECLARE_RESPONSE(410, "410 Gone"),
↑ 198 DECLARE_RESPONSE(411, "411 Length Required"),
↑ 199 DECLARE_RESPONSE(412, "412 Precondition Failed"),
↑ 200 DECLARE_RESPONSE(413, "413 Request Entity Too Large"),
↑ 201 DECLARE_RESPONSE(414, "414 Request URI Too Long"),
↑ 202 DECLARE_RESPONSE(415, "415 Unsupported Media Type"),
↑ 203 DECLARE_RESPONSE(416, "416 Requested Range Not Satisfiable"),
↑ 204 DECLARE_RESPONSE(417, "417 Expectation Failed"),
↑ 205
↑ 206 #define HTTP_RESPONSE_500 (HTTP_RESPONSE_400 + 18)
↑ 207
↑ 208 DECLARE_RESPONSE(500, "500 Internal Server Error"),
↑ 209 DECLARE_RESPONSE(501, "501 Not Implemented"),
↑ 210 DECLARE_RESPONSE(502, "502 Bad Gateway"),
↑ 211 DECLARE_RESPONSE(503, "503 Service Unavailable"),
↑ 212 DECLARE_RESPONSE(504, "504 Gateway Timeout"),
↑ 213 DECLARE_RESPONSE(505, "505 HTTP Version Not Supported"),
↑ 214 };
↑ 215
↑ 216 #undef DECLARE_RESPONSE
↑ 217 #undef DECLARE_RESPONSE_INTERNAL
↑ 218
↑ 219
↑ 220 static http_status_t http_header_parse_entries (http_header_t *header);
↑ 221 static http_status_t http_header_merge (http_header_t *header);
↑ 222
↑ 223 static http_status_t http_header_parse_request (http_header_t *header);
↑ 224 static const struct http_header_key * http_header_get_key (const char *key, size_t nkey);
↑ 225
↑ 226 void http_header_init (http_header_t *header, int fullclear)
↑ 227 {
↑ 228 if (fullclear)
↑ 229 rh_bzero (header, sizeof(*header));
↑ 230
↑ 231 TAILQ_INIT(&header->entries_raw);
↑ 232 TAILQ_INIT(&header->entries_parsed);
↑ 233 TAILQ_INIT(&header->entries_unknown);
↑ 234 }
↑ 235
↑ 236 static void http_header_destroy_entries (http_header_t *header,
↑ 237 struct http_header_entry_list *list)
↑ 238 {
↑ 239 for (;;) {
↑ 240 struct http_header_entry *entry;
↑ 241
↑ 242 entry = TAILQ_FIRST(list);
↑ 243 if (NULL == entry)
↑ 244 break;
↑ 245
↑ 246 TAILQ_REMOVE(list, entry, entries);
↑ 247
↑ 248 if (entry->data && entry->key->destroy) {
↑ 249 entry->key->destroy (entry);
↑ 250 entry->data = NULL;
↑ 251 }
↑ 252
↑ 253 if (entry->flags & HTTP_HEADER_KEY_FLAG_UNKNOWN) {
↑ 254
↑ 255 }
↑ 256 #if 0
↑ 257 printf ("%s() [%.*s] = [%.*s]\n", __FUNCTION__,
↑ 258 entry->key->nkey, entry->key->key,
↑ 259 entry->value.used, entry->value.data );
↑ 260 #endif
↑ 261
↑ 262 rh_buffer_destroy(&entry->value);
↑ 263 }
↑ 264 }
↑ 265
↑ 266 void http_header_destroy (http_header_t *header)
↑ 267 {
↑ 268 uri_destroy (&header->uri);
↑ 269
↑ 270 http_header_destroy_entries (header, &header->entries_raw);
↑ 271 http_header_destroy_entries (header, &header->entries_parsed);
↑ 272 http_header_destroy_entries (header, &header->entries_unknown);
↑ 273
↑ 274 http_header_clear (header);
↑ 275 }
↑ 276
↑ 277 void http_header_dump (http_header_t *header)
↑ 278 {
↑ 279 struct http_header_entry *entry;
↑ 280
↑ 281 TAILQ_FOREACH(entry, &header->entries_parsed, entries) {
↑ 282 DEBUGLOG("[%.*s]: [%.*s]",
↑ 283 entry->key->nkey,
↑ 284 entry->key->key,
↑ 285 entry->value.used,
↑ 286 entry->value.data);
↑ 287 }
↑ 288 }
↑ 289
↑ 290 void http_header_reset (http_header_t *header)
↑ 291 {
↑ 292 http_header_destroy (header);
↑ 293 http_header_init (header, 1);
↑ 294 }
↑ 295
↑ 296 http_status_t http_header_set_errno_status (http_header_t *header, int error)
↑ 297 {
↑ 298 switch (error) {
↑ 299 case ENOENT:
↑ 300 return (header->status = HTTP_STATUS_404_NOT_FOUND);
↑ 301 case EACCES:
↑ 302 case ELOOP:
↑ 303 case EROFS:
↑ 304 return (header->status = HTTP_STATUS_403_FORBIDDEN);
↑ 305 case ENAMETOOLONG:
↑ 306 return (header->status = HTTP_STATUS_414_REQUEST_URI_TOO_LONG);
↑ 307 case EMFILE:
↑ 308 case ENOMEM:
↑ 309 case ENOSPC:
↑ 310 case EOVERFLOW:
↑ 311 return (header->status = HTTP_STATUS_503_SERVICE_UNAVAILABLE);
↑ 312 default:
↑ 313 return (header->status = HTTP_STATUS_500_INTERNAL_SERVER_ERROR);
↑ 314 }
↑ 315 }
↑ 316
↑ 317 int http_header_parse (http_header_t *header, int type,
↑ 318 const char *buffer, size_t nbuffer)
↑ 319 {
↑ 320 http_status_t status;
↑ 321
↑ 322
↑ 323
↑ 324 header->type = type;
↑ 325 header->buffer = buffer;
↑ 326 header->nbuffer = nbuffer;
↑ 327
↑ 328 switch (type) {
↑ 329 case HTTP_HEADER_SERVER:
↑ 330 status = http_header_parse_request (header);
↑ 331 if (status)
↑ 332 goto error_out;
↑ 333 break;
↑ 334 default:
↑ 335 status = 500;
↑ 336 goto error_out;
↑ 337 }
↑ 338
↑ 339 /* merge lines */
↑ 340 status = http_header_merge (header);
↑ 341 if (status)
↑ 342 goto error_out;
↑ 343
↑ 344 /* first (fast) parser */
↑ 345 header->keepalive = -1;
↑ 346
↑ 347 status = http_header_parse_entries (header);
↑ 348 if (status) {
↑ 349 header->keepalive = 0;
↑ 350 goto error_out;
↑ 351 }
↑ 352
↑ 353 /* keepalive header was not send.
↑ 354 * set to true if >= http/1.1 otherwise off */
↑ 355 if (-1 == header->keepalive) {
↑ 356 if (header->version > HTTP_VERSION_10) {
↑ 357 header->keepalive = 1;
↑ 358 } else {
↑ 359 header->keepalive = 0;
↑ 360 }
↑ 361 }
↑ 362
↑ 363 return 0;
↑ 364
↑ 365 error_out:
↑ 366 header->status = status;
↑ 367 return -1;
↑ 368 }
↑ 369
↑ 370 static http_status_t http_header_parse_entries (http_header_t *header)
↑ 371 {
↑ 372 for (;;) {
↑ 373 http_header_entry_t *entry;
↑ 374 http_status_t status;
↑ 375
↑ 376 entry = TAILQ_FIRST(&header->entries_raw);
↑ 377 if (NULL == entry)
↑ 378 break;
↑ 379
↑ 380 entry->header = header;
↑ 381
↑ 382 status = entry->key->parse_first (entry);
↑ 383 if (status)
↑ 384 return status;
↑ 385
↑ 386 TAILQ_REMOVE(&header->entries_raw, entry, entries);
↑ 387 TAILQ_INSERT_TAIL(&header->entries_parsed, entry, entries);
↑ 388 }
↑ 389
↑ 390 return 0;
↑ 391 }
↑ 392
↑ 393 /*
↑ 394 *
↑ 395 * http header keys must be merged because:
↑ 396 *
↑ 397 * - there maybe more then one time the same key, eg:
↑ 398 *
↑ 399 * Connection: what=ever
↑ 400 * Host: something
↑ 401 * Connection: close
↑ 402 *
↑ 403 * But this includes a problem:
↑ 404 *
↑ 405 * Cookie: First-Cookie
↑ 406 * Some-Other: Header
↑ 407 * Cookie: Second-Cookie and DIFFERENT cookie
↑ 408 *
↑ 409 * This means, sometimes headers should not merged,
↑ 410 * they should stored in a list.
↑ 411 *
↑ 412 *
↑ 413 * - http/1.1 allows multiple lines, eg:
↑ 414 *
↑ 415 * Connection: what
↑ 416 * ever
↑ 417 * something more
↑ 418 * Host: localhorst
↑ 419 * Connection: close
↑ 420 *
↑ 421 * Note: Apache did not remove the whitespace (expect the first?).
↑ 422 *
↑ 423 * Therefore the real parser can only called if ALL lines are merged.
↑ 424 *
↑ 425 */
↑ 426 static http_status_t http_header_merge (http_header_t *header)
↑ 427 {
↑ 428 const struct http_header_key *key_def = NULL;
↑ 429
↑ 430 /*
↑ 431 *
↑ 432 * merge line by line
↑ 433 *
↑ 434 */
↑ 435 for (;;) {
↑ 436 struct http_header_entry *entry;
↑ 437 const char *line, *line_end;
↑ 438 size_t nline;
↑ 439 const char *key, *value;
↑ 440 size_t nkey, nvalue;
↑ 441
↑ 442 line_end = memchr (header->buffer, '\n', header->nbuffer);
↑ 443 if (NULL == line_end)
↑ 444 return HTTP_STATUS_400_BAD_REQUEST;
↑ 445
↑ 446 line = header->buffer;
↑ 447 nline = line_end + 1 - line;
↑ 448
↑ 449 #if 0
↑ 450 printf ("raw-line: [%.*s]\n", nline, line);
↑ 451 #endif
↑ 452
↑ 453 header->buffer += nline;
↑ 454 header->nbuffer -= nline;
↑ 455
↑ 456 if (nline < CONST_LEN(NL) || '\r' != line[nline-2])
↑ 457 return HTTP_STATUS_400_BAD_REQUEST;
↑ 458
↑ 459 nline -= CONST_LEN(NL);
↑ 460
↑ 461 if (0 == nline) {
↑ 462 if (header->nbuffer)
↑ 463 return HTTP_STATUS_400_BAD_REQUEST;
↑ 464
↑ 465 break;
↑ 466 }
↑ 467
↑ 468
↑ 469 /*
↑ 470 *
↑ 471 * split "key: value"
↑ 472 *
↑ 473 *
↑ 474 */
↑ 475
↑ 476 if (HTTP_ISSPACE(*line)) {
↑ 477 if (NULL == key_def)
↑ 478 return HTTP_STATUS_400_BAD_REQUEST;
↑ 479
↑ 480 key = key_def->key;
↑ 481 nkey = key_def->nkey;
↑ 482
↑ 483 value = line + 1; /* without first space */
↑ 484 nvalue = nline - 1;
↑ 485 } else {
↑ 486 key = line;
↑ 487
↑ 488 value = memchr (line, ':', nline);
↑ 489 if (NULL == value)
↑ 490 return HTTP_STATUS_400_BAD_REQUEST;
↑ 491
↑ 492 nkey = value - key;
↑ 493 CONST_RTRIM(key, nkey, HTTP_ISSPACE);
↑ 494
↑ 495 value += CONST_LEN(":");
↑ 496 nvalue = nline - (value - line);
↑ 497
↑ 498 key_def = http_header_get_key(key, nkey);
↑ 499 }
↑ 500
↑ 501 CONST_LTRIM(value, nvalue, HTTP_ISSPACE);
↑ 502 CONST_RTRIM(value, nvalue, HTTP_ISSPACE);
↑ 503
↑ 504 if (NULL == key_def) {
↑ 505 /* ignorie: later -> append hashed */
↑ 506 printf ("skip header: [%.*s]\n", nline, line);
↑ 507 continue;
↑ 508 }
↑ 509
↑ 510 entry = &header->entries[key_def->type];
↑ 511 entry->key = key_def;
↑ 512
↑ 513 if (1 == ++entry->found) {
↑ 514 TAILQ_INSERT_TAIL(&header->entries_raw, entry, entries);
↑ 515 }
↑ 516
↑ 517 if (entry->value.used) {
↑ 518 /* key is mergeable? */
↑ 519 /* XXX: remember the multiple "Cookie" Problem */
↑ 520 if (0 == key_def->merge_char)
↑ 521 return HTTP_STATUS_400_BAD_REQUEST;
↑ 522
↑ 523 /* append merge char if neccesary */
↑ 524 if ( key_def->merge_char != rh_buffer_ch_last(
↑ 525 &entry->value) &&
↑ 526 key_def->merge_char != value[0])
↑ 527 {
↑ 528 if (rh_buffer_append_ch (&entry->value,
↑ 529 key_def->merge_char,
↑ 530 1) )
↑ 531 {
↑ 532 return 500;
↑ 533 }
↑ 534 }
↑ 535 }
↑ 536
↑ 537 if (rh_buffer_append (&entry->value, value, nvalue))
↑ 538 return HTTP_STATUS_500_INTERNAL_SERVER_ERROR;
↑ 539 }
↑ 540
↑ 541 header->buffer = NULL;
↑ 542 header->nbuffer = 0;
↑ 543
↑ 544 return 0;
↑ 545 }
↑ 546
↑ 547 /*
↑ 548 * parse client request line: "GET / HTTP/1.1"
↑ 549 *
↑ 550 */
↑ 551 static http_status_t http_header_parse_request (http_header_t *header)
↑ 552 {
↑ 553 const char *uri;
↑ 554 size_t nuri;
↑ 555 const char *version;
↑ 556
↑ 557 if (header->nbuffer < CONST_LEN ("GET / HTTP/1.0\r\n"))
↑ 558 return HTTP_STATUS_400_BAD_REQUEST;
↑ 559
↑ 560 if (' ' == header->buffer[3]) {
↑ 561 if (RH_EQUAL4 ("GET ", header->buffer)) {
↑ 562 header->method = HTTP_METHOD_GET;
↑ 563 } else {
↑ 564 return HTTP_STATUS_501_NOT_IMPLEMENTED;
↑ 565 }
↑ 566 header->buffer += 4;
↑ 567 header->nbuffer -= 4;
↑ 568 } else
↑ 569 if (' ' == header->buffer[4]) {
↑ 570 if (RH_EQUAL4 ("HEAD", header->buffer)) {
↑ 571 header->method = HTTP_METHOD_HEAD;
↑ 572 } else
↑ 573 if (RH_EQUAL4 ("POST", header->buffer)) {
↑ 574 header->method = HTTP_METHOD_POST;
↑ 575 } else {
↑ 576 return HTTP_STATUS_501_NOT_IMPLEMENTED;
↑ 577 }
↑ 578 header->buffer += 5;
↑ 579 header->nbuffer -= 5;
↑ 580 } else
↑ 581 if (' ' == header->buffer[5]) {
↑ 582 if ( RH_EQUAL4 ("TRAC", header->buffer) &&
↑ 583 header->buffer[5] == 'E')
↑ 584 {
↑ 585 header->method = HTTP_METHOD_TRACE;
↑ 586 } else {
↑ 587 return HTTP_STATUS_501_NOT_IMPLEMENTED;
↑ 588 }
↑ 589
↑ 590 header->buffer += 6;
↑ 591 header->nbuffer -= 6;
↑ 592 } else {
↑ 593 return HTTP_STATUS_501_NOT_IMPLEMENTED;
↑ 594 }
↑ 595
↑ 596
↑ 597 /*
↑ 598 *
↑ 599 * raw uri / version
↑ 600 *
↑ 601 *
↑ 602 */
↑ 603
↑ 604 uri = header->buffer;
↑ 605
↑ 606 version = memchr (header->buffer, ' ', header->nbuffer);
↑ 607
↑ 608 if (NULL == version)
↑ 609 return HTTP_STATUS_400_BAD_REQUEST;
↑ 610
↑ 611 nuri = version - uri;
↑ 612
↑ 613 /*
↑ 614 *
↑ 615 * version
↑ 616 *
↑ 617 */
↑ 618
↑ 619 version += CONST_LEN(" ");
↑ 620
↑ 621 if (!RH_EQUAL4("HTTP", version))
↑ 622 return HTTP_STATUS_400_BAD_REQUEST;
↑ 623
↑ 624 version += CONST_LEN("HTTP");
↑ 625
↑ 626 if (RH_EQUAL4("/1.1", version))
↑ 627 header->version = HTTP_VERSION_11;
↑ 628 else
↑ 629 if (RH_EQUAL4("/1.0", version))
↑ 630 header->version = HTTP_VERSION_10;
↑ 631 else
↑ 632 /* hmmhm, maybe a real check for wrong data?:
↑ 633 * eg: "shit" maybe given */
↑ 634 return HTTP_STATUS_505_HTTP_VERSION_NOT_SUPPORTED;
↑ 635
↑ 636 version += CONST_LEN("/1.1");
↑ 637
↑ 638 if (!RH_EQUAL2(NL, version))
↑ 639 return HTTP_STATUS_400_BAD_REQUEST;
↑ 640
↑ 641 version += CONST_LEN(NL);
↑ 642
↑ 643 header->nbuffer -= version - header->buffer;
↑ 644 header->buffer = version;
↑ 645
↑ 646 if (0 != uri_parse (&header->uri, uri, nuri)) {
↑ 647 return HTTP_STATUS_400_BAD_REQUEST;
↑ 648 }
↑ 649
↑ 650 return 0;
↑ 651 }
↑ 652
↑ 653 /*
↑ 654 *
↑ 655 *
↑ 656 *
↑ 657 * p a r s e r
↑ 658 *
↑ 659 *
↑ 660 *
↑ 661 */
↑ 662
↑ 663 static http_status_t http_header_parse_validate (http_header_entry_t *entry)
↑ 664 {
↑ 665 size_t i;
↑ 666
↑ 667 for (i=0; i<entry->value.used; ++i) {
↑ 668 if (0 == MAP_HTTP_VAL[(unsigned char)(entry->value.data[i])]) {
↑ 669 printf ("%s [%.*s]\n", __FUNCTION__,
↑ 670 entry->value.used,
↑ 671 entry->value.data );
↑ 672 return HTTP_STATUS_400_BAD_REQUEST;
↑ 673 }
↑ 674 }
↑ 675 return 0;
↑ 676 }
↑ 677
↑ 678 static http_status_t http_header_parse_host (http_header_entry_t *entry)
↑ 679 {
↑ 680 http_host_t *host;
↑ 681
↑ 682 host = malloc(sizeof(*host));
↑ 683 if (NULL == host)
↑ 684 return -1;
↑ 685
↑ 686 if (0 != http_host_parse (host, entry->value.data, entry->value.used)) {
↑ 687 http_host_free (host);
↑ 688 return 400;
↑ 689 }
↑ 690
↑ 691 entry->data = host;
↑ 692
↑ 693 return 0;
↑ 694 }
↑ 695
↑ 696 static http_status_t http_header_destroy_host (http_header_entry_t *entry)
↑ 697 {
↑ 698 http_host_free(entry->data);
↑ 699 return 0;
↑ 700 }
↑ 701
↑ 702 static http_status_t http_header_parse_connection (http_header_entry_t *entry)
↑ 703 {
↑ 704 switch (entry->value.used) {
↑ 705 case CONST_LEN("close"):
↑ 706 if (0 == rh_memcasecmp(entry->value.data,
↑ 707 CONST_STR_LEN("close") ) )
↑ 708 {
↑ 709 entry->header->keepalive = 0;
↑ 710 goto done;
↑ 711 }
↑ 712 break;
↑ 713
↑ 714 case CONST_LEN("Keep-Alive"):
↑ 715 if (0 == rh_memcasecmp(entry->value.data,
↑ 716 CONST_STR_LEN("Keep-Alive") ) )
↑ 717 {
↑ 718 entry->header->keepalive = 1;
↑ 719 entry->header->keepalive_header = 1;
↑ 720 goto done;
↑ 721 }
↑ 722 break;
↑ 723 }
↑ 724
↑ 725 /* value,value,value, ... */
↑ 726
↑ 727
↑ 728 done:
↑ 729 entry->flags |= HTTP_HEADER_KEY_FLAG_PARSED;
↑ 730
↑ 731 return 0;
↑ 732 }
↑ 733
↑ 734
↑ 735
↑ 736
↑ 737 /*
↑ 738 *
↑ 739 *
↑ 740 *
↑ 741 * i n t e r f a c e
↑ 742 *
↑ 743 *
↑ 744 *
↑ 745 *
↑ 746 */
↑ 747
↑ 748 /* returns true if a if-match: header matches
↑ 749 *
↑ 750 * if-match: * | etag
↑ 751 *
↑ 752 * * = always true
↑ 753 * etag = compare
↑ 754 *
↑ 755 */
↑ 756 int http_header_if_match (http_header_t *header_in, http_header_t *header_out)
↑ 757 {
↑ 758 struct http_header_entry *entry;
↑ 759
↑ 760 entry = &header_in->entries[HTTP_HEADER_KEY_IF_MATCH];
↑ 761 if (0 == entry->found || 0 == entry->value.used)
↑ 762 return 0;
↑ 763
↑ 764 if (1 == entry->value.used && '*' == entry->value.data[0])
↑ 765 return 1;
↑ 766
↑ 767 if ( header_out->etag.used == entry->value.used &&
↑ 768 0 == rh_memcmp (header_out->etag.data, entry->value.data,
↑ 769 entry->value.used) )
↑ 770 {
↑ 771 return 1;
↑ 772 }
↑ 773
↑ 774 return 0;
↑ 775 }
↑ 776
↑ 777 /* return true if etag matches */
↑ 778 int http_header_if_none_match ( http_header_t *header_in,
↑ 779 http_header_t *header_out)
↑ 780 {
↑ 781 struct http_header_entry *etag;
↑ 782
↑ 783 etag = &header_in->entries[HTTP_HEADER_KEY_IF_NONE_MATCH];
↑ 784 if (0 == etag->found || 0 == etag->value.used)
↑ 785 return 0;
↑ 786
↑ 787 if (etag->value.used == header_out->etag.used &&
↑ 788 0 == rh_memcmp(header_out->etag.data,
↑ 789 etag->value.data, etag->value.used) )
↑ 790 {
↑ 791 return 1;
↑ 792 }
↑ 793
↑ 794 return 0;
↑ 795 }
↑ 796
↑ 797 /* returns true if the header as a range request */
↑ 798 int http_header_have_range (http_header_t *header)
↑ 799 {
↑ 800 struct http_header_entry *entry;
↑ 801
↑ 802 entry = &header->entries[HTTP_HEADER_KEY_RANGE];
↑ 803
↑ 804 if (0 == entry->found || NULL == entry->data)
↑ 805 return 0;
↑ 806
↑ 807 if (0 == ((struct http_range *)entry->data)->queue_count)
↑ 808 return 0;
↑ 809
↑ 810 return 1;
↑ 811 }
↑ 812
↑ 813 /*
↑ 814 *
↑ 815 * returns true if a (maybe) given if-modified-since header
↑ 816 * is equal or in future then the gmtime type
↑ 817 *
↑ 818 */
↑ 819
↑ 820 int http_header_is_modified (http_header_t *header, rh_gmtime_t *gmtime)
↑ 821 {
↑ 822 struct http_header_entry *entry;
↑ 823 rh_gmtime_t gmtime_cmp;
↑ 824
↑ 825 entry = HTTP_HEADER_KEY_GET(header, IF_MODIFIED_SINCE);
↑ 826 if (NULL == entry)
↑ 827 return 1;
↑ 828
↑ 829 if (gmtime->used != entry->value.used || ! gmtime->used)
↑ 830 return 1;
↑ 831
↑ 832 /* this compare matches if the client sends the header this
↑ 833 * server has send some time ago. */
↑ 834 if (0 == rh_memcmp (gmtime->data, entry->value.data, gmtime->used))
↑ 835 return 0;
↑ 836
↑ 837 if (0 != rh_gmtime_reverse ( entry->value.data,
↑ 838 entry->value.used,
↑ 839 &gmtime_cmp))
↑ 840 {
↑ 841 return 1;
↑ 842 }
↑ 843 #if 0
↑ 844 DEBUGLOG ("header_in: [%.*s]",
↑ 845 entry->value.used,
↑ 846 entry->value.data );
↑ 847
↑ 848 DEBUGLOG ("gmtime_rev:[%.*s]",
↑ 849 gmtime_cmp.used,
↑ 850 gmtime_cmp.data );
↑ 851
↑ 852 DEBUGLOG ("gmtime_cur:[%.*s]",
↑ 853 gmtime->used,
↑ 854 gmtime->data );
↑ 855 #endif
↑ 856 if (gmtime->t > gmtime_cmp.t)
↑ 857 return 1;
↑ 858
↑ 859 /* time was equal or in future */
↑ 860 return 0;
↑ 861 }
↑ 862
↑ 863
↑ 864 int http_header_clear (http_header_t *header)
↑ 865 {
↑ 866 for (;;) {
↑ 867 struct http_header_entry *entry;
↑ 868
↑ 869 entry = TAILQ_FIRST(&header->entries_parsed);
↑ 870 if (NULL == entry)
↑ 871 break;
↑ 872
↑ 873 /* should not happen, but if -> endless loop */
↑ 874 if (0 == entry->found) {
↑ 875 TAILQ_REMOVE(&header->entries_parsed, entry, entries);
↑ 876 continue;
↑ 877 }
↑ 878
↑ 879 http_header_key_clear (header, entry->key->type);
↑ 880 }
↑ 881
↑ 882 return 0;
↑ 883 }
↑ 884
↑ 885
↑ 886 int http_header_key_default (http_header_t *header,
↑ 887 enum http_header_key_type key)
↑ 888 {
↑ 889 const rh_buffer_t *response;
↑ 890
↑ 891 switch (key) {
↑ 892
↑ 893 #ifdef RHTTPD_SERVERNAME
↑ 894 case HTTP_HEADER_KEY_SERVER:
↑ 895 return HTTP_HEADER_KEY_SET_CONST_STR (
↑ 896 header,
↑ 897 SERVER,
↑ 898 RHTTPD_SERVERNAME);
↑ 899 #endif
↑ 900
↑ 901 case HTTP_HEADER_KEY_RESPONSE:
↑ 902 response = http_header_get_response (header);
↑ 903
↑ 904 return http_header_key_set_const (header,
↑ 905 HTTP_HEADER_KEY_RESPONSE,
↑ 906 response->data, response->used);
↑ 907
↑ 908 case HTTP_HEADER_KEY_CONTENT_TYPE:
↑ 909 return HTTP_HEADER_KEY_SET_CONST_STR (
↑ 910 header,
↑ 911 CONTENT_TYPE,
↑ 912 "text/plain");
↑ 913
↑ 914 case HTTP_HEADER_KEY_ACCEPT_RANGES:
↑ 915 return HTTP_HEADER_KEY_SET_CONST_STR (
↑ 916 header,
↑ 917 ACCEPT_RANGES,
↑ 918 "bytes" );
↑ 919
↑ 920 default:
↑ 921 return 0;
↑ 922 }
↑ 923
↑ 924 }
↑ 925
↑ 926 int http_header_key_clear (http_header_t *header, enum http_header_key_type key)
↑ 927 {
↑ 928 http_header_entry_t *entry;
↑ 929
↑ 930 entry = &header->entries[key];
↑ 931
↑ 932 if (0 == entry->found || NULL == entry->key)
↑ 933 return 0;
↑ 934
↑ 935 if (HTTP_HEADER_KEY_RESPONSE != key) {
↑ 936 TAILQ_REMOVE(&header->entries_parsed, entry, entries);
↑ 937 }
↑ 938
↑ 939 if (entry->data && entry->key->destroy) {
↑ 940 entry->key->destroy (entry);
↑ 941 entry->data = NULL;
↑ 942 }
↑ 943
↑ 944 rh_buffer_destroy(&entry->value);
↑ 945
↑ 946 entry->found = 0;
↑ 947
↑ 948 return 0;
↑ 949 }
↑ 950
↑ 951 int http_header_key_append (http_header_t *header,
↑ 952 enum http_header_key_type key,
↑ 953 const char *src, size_t nsrc)
↑ 954 {
↑ 955 http_header_entry_t *entry;
↑ 956
↑ 957 entry = &header->entries[key];
↑ 958
↑ 959 if (0 == entry->found) {
↑ 960 if (HTTP_HEADER_KEY_RESPONSE != key) {
↑ 961 TAILQ_INSERT_TAIL(&header->entries_parsed,
↑ 962 entry, entries);
↑ 963 }
↑ 964 entry->key = &http_header_keys[key];
↑ 965 entry->found = 1;
↑ 966 }
↑ 967
↑ 968 return rh_buffer_append(&entry->value, src, nsrc);
↑ 969 }
↑ 970
↑ 971
↑ 972 int http_header_key_set_keepalive (http_header_t *header, int keepalive)
↑ 973 {
↑ 974 char num[32];
↑ 975 int nnum;
↑ 976
↑ 977 /* Keep-Alive: timeout=15, max=17 */
↑ 978 if (!keepalive) {
↑ 979 return http_header_key_set_const (header,
↑ 980 HTTP_HEADER_KEY_CONNECTION,
↑ 981 CONST_STR_LEN("close") );
↑ 982 }
↑ 983
↑ 984 if (!header->keepalive_header)
↑ 985 return 0;
↑ 986
↑ 987 http_header_key_set_const (header,
↑ 988 HTTP_HEADER_KEY_CONNECTION,
↑ 989 CONST_STR_LEN("Keep-Alive") );
↑ 990
↑ 991 HTTP_HEADER_KEY_CLEAR (header, KEEP_ALIVE);
↑ 992
↑ 993 HTTP_HEADER_KEY_APPEND_CONST (header, KEEP_ALIVE, "timeout=15, max=");
↑ 994
↑ 995 nnum = snprintf (num, sizeof(num)-1, "%d", header->keepalive+1);
↑ 996
↑ 997 HTTP_HEADER_KEY_APPEND (header, KEEP_ALIVE, num, nnum);
↑ 998
↑ 999 return 0;
↑1000 }
↑1001
↑1002 int http_header_key_set_content_length (http_header_t *header, size_t length)
↑1003 {
↑1004 char *len;
↑1005 size_t nlen;
↑1006
↑1007 http_header_key_clear (header, HTTP_HEADER_KEY_CONTENT_LENGTH);
↑1008
↑1009 len = rh_uint2str (
↑1010 header->content_length.data,
↑1011 sizeof(header->content_length.data),
↑1012 length,
↑1013 &nlen);
↑1014
↑1015 return http_header_key_set_const (
↑1016 header,
↑1017 HTTP_HEADER_KEY_CONTENT_LENGTH,
↑1018 len,
↑1019 nlen);
↑1020 }
↑1021
↑1022 int http_header_key_set_const (http_header_t *header,
↑1023 enum http_header_key_type key,
↑1024 const char *src, size_t nsrc)
↑1025 {
↑1026 http_header_entry_t *entry;
↑1027
↑1028 http_header_key_clear (header, key);
↑1029
↑1030 entry = &header->entries[key];
↑1031
↑1032 if (0 == entry->found) {
↑1033 entry->found = 1;
↑1034 entry->key = &http_header_keys[key];
↑1035
↑1036 if (HTTP_HEADER_KEY_RESPONSE != key) {
↑1037 TAILQ_INSERT_TAIL(&header->entries_parsed,
↑1038 entry, entries);
↑1039 }
↑1040 }
↑1041
↑1042 rh_buffer_destroy(&entry->value);
↑1043 rh_buffer_set_const(&entry->value, src, nsrc);
↑1044
↑1045 return 0;
↑1046 }
↑1047
↑1048 http_header_entry_t * http_header_key_use (http_header_t *header,
↑1049 enum http_header_key_type key )
↑1050 {
↑1051
↑1052 http_header_entry_t *entry;
↑1053
↑1054 entry = &header->entries[key];
↑1055
↑1056 if (0 == entry->found) {
↑1057 entry->found = 1;
↑1058 entry->key = &http_header_keys[key];
↑1059
↑1060 if (HTTP_HEADER_KEY_RESPONSE != key) {
↑1061 TAILQ_INSERT_TAIL(&header->entries_parsed,
↑1062 entry, entries);
↑1063 }
↑1064 }
↑1065
↑1066 return entry;
↑1067 }
↑1068
↑1069 http_header_entry_t * http_header_key_get (http_header_t *header,
↑1070 enum http_header_key_type key )
↑1071 {
↑1072 return &header->entries[key];
↑1073 }
↑1074
↑1075 int http_header_into_chunk (http_header_t *header, rh_chunk_t *chunk, int term)
↑1076 {
↑1077 int success;
↑1078 http_header_entry_t *entry;
↑1079
↑1080 entry = &header->entries[HTTP_HEADER_KEY_RESPONSE];
↑1081
↑1082 if (NULL != entry && entry->found) {
↑1083 success = rh_chunk_append_buffer (
↑1084 chunk,
↑1085 entry->value.data, entry->value.used,
↑1086 NULL, NULL);
↑1087
↑1088 if (0 != success)
↑1089 return -1;
↑1090
↑1091 success = rh_chunk_append_buffer (
↑1092 chunk,
↑1093 CONST_STR_LEN(NL),
↑1094 NULL, NULL);
↑1095
↑1096 if (0 != success)
↑1097 return -1;
↑1098 }
↑1099
↑1100
↑1101 TAILQ_FOREACH(entry, &header->entries_parsed, entries) {
↑1102
↑1103 success = rh_chunk_append_buffer (
↑1104 chunk,
↑1105 entry->key->key, entry->key->nkey,
↑1106 NULL, NULL);
↑1107
↑1108 if (0 != success)
↑1109 return -1;
↑1110
↑1111 success = rh_chunk_append_buffer (
↑1112 chunk,
↑1113 CONST_STR_LEN(": "),
↑1114 NULL, NULL);
↑1115
↑1116 if (0 != success)
↑1117 return -1;
↑1118
↑1119 success = rh_chunk_append_buffer (
↑1120 chunk,
↑1121 entry->value.data, entry->value.used,
↑1122 NULL, NULL);
↑1123
↑1124 if (0 != success)
↑1125 return -1;
↑1126
↑1127 success = rh_chunk_append_buffer (
↑1128 chunk,
↑1129 CONST_STR_LEN(NL),
↑1130 NULL, NULL);
↑1131
↑1132 if (0 != success)
↑1133 return -1;
↑1134
↑1135 }
↑1136
↑1137 if (term)
↑1138 return rh_chunk_append_buffer (chunk, CONST_STR_LEN(NL),
↑1139 NULL, NULL);
↑1140 return 0;
↑1141 }
↑1142
↑1143
↑1144
↑1145
↑1146
↑1147 /*
↑1148 *
↑1149 *
↑1150 * s t a t i c c o d e
↑1151 *
↑1152 *
↑1153 *
↑1154 */
↑1155
↑1156 /* based on the idea of apache */
↑1157 const rh_buffer_t * http_header_get_response (http_header_t *header)
↑1158 {
↑1159 if (0 == header->status)
↑1160 header->status = HTTP_STATUS_400_BAD_REQUEST;
↑1161
↑1162 switch (header->status / 100) {
↑1163 case 1: return &http_response [HTTP_RESPONSE_100 + header->status-100];
↑1164 case 2: return &http_response [HTTP_RESPONSE_200 + header->status-200];
↑1165 case 3: return &http_response [HTTP_RESPONSE_300 + header->status-300];
↑1166 case 4: return &http_response [HTTP_RESPONSE_400 + header->status-400];
↑1167 case 5: return &http_response [HTTP_RESPONSE_500 + header->status-500];
↑1168 }
↑1169 return &http_response [HTTP_RESPONSE_500];
↑1170 }
↑1171
↑1172 static const struct http_header_key * http_header_get_key (const char *key,
↑1173 size_t nkey)
↑1174 {
↑1175 #define KEYCMP(_str,_key) \
↑1176 if (0 == rh_memcasecmp(key,CONST_STR_LEN(_str))) \
↑1177 return &http_header_keys[HTTP_HEADER_KEY_ ## _key]; \
↑1178 break
↑1179
↑1180 #define CASE_UC(_upper) case (_upper): case ((_upper) | 0x20)
↑1181 #define CASE_LC(_lower) case (_lower): case ((_lower) & ~0x20)
↑1182
↑1183 switch (nkey) {
↑1184 case CONST_LEN("TE"):
↑1185 KEYCMP("TE", TE);
↑1186 return NULL;
↑1187
↑1188 case CONST_LEN("Via"):
↑1189 switch ((unsigned char)key[0]) {
↑1190 CASE_UC('V'): KEYCMP("Via", VIA);
↑1191 CASE_UC('A'): KEYCMP("Age", AGE);
↑1192 }
↑1193 return NULL;
↑1194
↑1195 case CONST_LEN("Host"):
↑1196 switch ((unsigned char)key[0]) {
↑1197 CASE_UC('H'): KEYCMP("Host", HOST);
↑1198 CASE_UC('V'): KEYCMP("Vary", VARY);
↑1199 CASE_UC('E'): KEYCMP("ETag", ETAG);
↑1200 CASE_UC('D'): KEYCMP("Date", DATE);
↑1201 CASE_UC('F'): KEYCMP("From", FROM);
↑1202 }
↑1203 return NULL;
↑1204
↑1205 case CONST_LEN("Title"):
↑1206 switch ((unsigned char)key[0]) {
↑1207 CASE_UC('R'): KEYCMP("Range", RANGE);
↑1208 CASE_UC('A'): KEYCMP("Allow", ALLOW);
↑1209 CASE_UC('X'): KEYCMP("X-Pad", X_PAD);
↑1210 CASE_UC('T'): KEYCMP("Title", TITLE);
↑1211 CASE_UC('U'): KEYCMP("UA-OS", UA_OS);
↑1212 }
↑1213 return NULL;
↑1214
↑1215 case CONST_LEN("Connection"):
↑1216 switch ((unsigned char)key[0]) {
↑1217 CASE_UC('C'): KEYCMP("Connection", CONNECTION);
↑1218 CASE_UC('U'): KEYCMP("User-Agent", USER_AGENT);
↑1219 CASE_UC('K'): KEYCMP("Keep-Alive", USER_AGENT);
↑1220 CASE_UC('S'): KEYCMP("Set-Cookie", SET_COOKIE);
↑1221 }
↑1222 return NULL;
↑1223
↑1224 case CONST_LEN("Accept"):
↑1225 switch ((unsigned char)key[1]) {
↑1226 CASE_LC('c'): KEYCMP("Accept", ACCEPT);
↑1227 CASE_LC('o'): KEYCMP("Cookie", COOKIE);
↑1228 CASE_LC('r'): KEYCMP("Pragma", PRAGMA);
↑1229 CASE_LC('x'): KEYCMP("Expect", EXPECT);
↑1230 CASE_LC('e'): KEYCMP("Server", SERVER);
↑1231 CASE_LC('t'): KEYCMP("Status", STATUS);
↑1232 CASE_LC('u'): KEYCMP("Public", PUBLIC);
↑1233 CASE_UC('A'): KEYCMP("UA-CPU", UA_CPU);
↑1234 }
↑1235 return NULL;
↑1236
↑1237 case CONST_LEN("UA-Disp"):
↑1238 switch ((unsigned char)key[2]) {
↑1239 case '-' : KEYCMP("UA-Disp", UA_DISP);
↑1240 CASE_UC('C'): KEYCMP("X-Cache", X_CACHE);
↑1241 CASE_LC('a'): KEYCMP("Trailer", TRAILER);
↑1242 CASE_LC('g'): KEYCMP("Upgrade", UPGRADE);
↑1243 CASE_LC('o'): KEYCMP("Cookie2", COOKIE2);
↑1244 CASE_LC('p'): KEYCMP("Expires", EXPIRES);
↑1245 CASE_LC('f'): KEYCMP("Referer", REFERER);
↑1246 CASE_LC('r'): KEYCMP("Warning", WARNING);
↑1247 }
↑1248 return NULL;
↑1249
↑1250 case CONST_LEN("Accept-Encoding"):
↑1251 switch ((unsigned char)key[CONST_LEN("Accept-E")]) {
↑1252 CASE_LC('n'): KEYCMP("Accept-Encoding", ACCEPT_ENCODING);
↑1253 CASE_LC('a'): KEYCMP("Accept-Language", ACCEPT_LANGUAGE);
↑1254 CASE_LC('d'): KEYCMP("X-Forwarded-For", X_FORWARDED_FOR);
↑1255 case '-' : KEYCMP("X-Serial-Number", X_SERIAL_NUMBER);
↑1256 }
↑1257 return NULL;
↑1258
↑1259 case CONST_LEN("Location"):
↑1260 switch ((unsigned char)key[CONST_LEN("Loc")]) {
↑1261 CASE_LC('a'): KEYCMP("Location", LOCATION);
↑1262 CASE_UC('M'): KEYCMP("If-Match", IF_MATCH);
↑1263 CASE_UC('R'): KEYCMP("If-Range", IF_RANGE);
↑1264 CASE_UC('C'): KEYCMP("UA-Color", UA_COLOR);
↑1265 }
↑1266
↑1267 case CONST_LEN("UA-Pixels"):
↑1268 switch ((unsigned char)key[0]) {
↑1269 CASE_UC('U'): KEYCMP("UA-Pixels", UA_PIXELS);
↑1270 CASE_UC('C'): KEYCMP("Client-ip", CLIENT_IP);
↑1271 }
↑1272 return NULL;
↑1273
↑1274 case CONST_LEN("Content-Type"):
↑1275 switch ((unsigned char)key[CONST_LEN("Content-")]) {
↑1276 CASE_UC('T'): KEYCMP("Content-Type", CONTENT_TYPE);
↑1277 CASE_UC('B'): KEYCMP("Content-Base", CONTENT_BASE);
↑1278 CASE_LC('a'): KEYCMP("Max-Forwards", MAX_FORWARDS);
↑1279 CASE_LC('s'): KEYCMP("MIME-Version", MIME_VERSION);
↑1280 }
↑1281 return NULL;
↑1282
↑1283 case CONST_LEN("Content-Length"):
↑1284 switch ((unsigned char)key[0]) {
↑1285 CASE_UC('C'): KEYCMP("Content-Length", CONTENT_LENGTH);
↑1286 CASE_UC('A'): KEYCMP("Accept-Charset", ACCEPT_CHARSET);
↑1287 }
↑1288 return NULL;
↑1289
↑1290 case CONST_LEN("Last-Modified"):
↑1291 switch ((unsigned char)key[CONST_LEN("Last-M")]) {
↑1292 CASE_LC('o'): KEYCMP("Last-Modified", LAST_MODIFIED);
↑1293 CASE_LC('t'): KEYCMP("Content-Range", CONTENT_RANGE);
↑1294 CASE_LC('i'): KEYCMP("Authorization", AUTHORIZATION);
↑1295 case '-' : KEYCMP("Accept-Ranges", ACCEPT_RANGES);
↑1296 CASE_UC('C'): KEYCMP("Cache-Control", CACHE_CONTROL);
↑1297 CASE_LC('e'): KEYCMP("If-None-Match", IF_NONE_MATCH);
↑1298 }
↑1299 return NULL;
↑1300
↑1301 case CONST_LEN("Transfer-Encoding"):
↑1302 switch ((unsigned char)key[0]) {
↑1303 CASE_UC('I'): KEYCMP("If-Modified-Since", IF_MODIFIED_SINCE);
↑1304 CASE_UC('T'): KEYCMP("Transfer-Encoding", TRANSFER_ENCODING);
↑1305 }
↑1306 return NULL;
↑1307
↑1308 case CONST_LEN("Retry-After"):
↑1309 switch ((unsigned char)key[0]) {
↑1310 CASE_UC('R'): KEYCMP("Retry-After", RETRY_AFTER);
↑1311 CASE_UC('S'): KEYCMP("Set-Cookie2", SET_COOKIE2);
↑1312 CASE_UC('C'): KEYCMP("Content-MD5", CONTENT_MD5);
↑1313 }
↑1314 return NULL;
↑1315
↑1316 case CONST_LEN("WWW-Authenticate"):
↑1317 switch ((unsigned char)key[CONST_LEN("WWW-Authent")]) {
↑1318 CASE_LC('i'): KEYCMP("WWW-Authenticate", WWW_AUTHENTICATE);
↑1319 CASE_LC('c'): KEYCMP("Proxy-Connection", PROXY_CONNECTION);
↑1320 CASE_LC('o'): KEYCMP("Content-Encoding", CONTENT_ENCODING);
↑1321 CASE_LC('g'): KEYCMP("Content_Language", CONTENT_LANGUAGE);
↑1322 CASE_LC('a'): KEYCMP("Content_Location", CONTENT_LOCATION);
↑1323 }
↑1324 return NULL;
↑1325
↑1326 case CONST_LEN("Proxy_Authenticate"):
↑1327 switch ((unsigned char)key[0]) {
↑1328 CASE_UC('P'): KEYCMP("Proxy_Authenticate", PROXY_AUTHENTICATE);
↑1329 }
↑1330 return NULL;
↑1331
↑1332 case CONST_LEN("If-Unmodified-Since"):
↑1333 switch ((unsigned char)key[0]) {
↑1334 CASE_UC('I'): KEYCMP("If-Unmodified-Since",IF_UNMODIFIED_SINCE);
↑1335 CASE_UC('P'): KEYCMP("Proxy-Authorization",PROXY_AUTHORIZATION);
↑1336 }
↑1337 return NULL;
↑1338 }
↑1339
↑1340 #undef CASE_UC
↑1341 #undef CASE_LC
↑1342 #undef KEYCMP
↑1343
↑1344 return NULL;
↑1345 }
syntax highlighted by Code2HTML, v. 0.9.1