↑ 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 <