Changeset 895
- Timestamp:
- 08/21/07 20:24:56 (1 year ago)
- Files:
-
- cherokee/trunk/ChangeLog (modified) (1 diff)
- cherokee/trunk/cherokee/connection.c (modified) (3 diffs)
- cherokee/trunk/cherokee/downloader.c (modified) (2 diffs)
- cherokee/trunk/cherokee/header.c (modified) (12 diffs)
- cherokee/trunk/cherokee/header.h (modified) (1 diff)
- cherokee/trunk/cherokee/macros.h (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
cherokee/trunk/ChangeLog
r894 r895 1 2007-08-21 A.D.F <adefacc@tin.it> 2 3 * cherokee/macros.h 4 - added LBS macro (HTTP linear blank space); 5 6 * cherokee/header.h 7 - parse_request_first_line() + parse_response_first_line() + 8 cherokee_header_parse(): 9 - added formal parameter "error_code" (HTTP error code); 10 11 * cherokee/header.c 12 - parse_request_first_line() + parse_response_first_line() + 13 cherokee_header_parse(): 14 - added formal parameter "error_code" (HTTP error code); 15 - parse_request_first_line(): 16 - added support for: 17 - HTTP 505 version not supported; 18 - HTTP 501 (method) not implemented; 19 - partially rewritten the HTTP request parser in order 20 to be more standard conformant; 21 - cherokee_header_has_header(), lowered minimum HTTP request length 22 in order to handle properly HTTP/0.9 requests too 23 (which are refused with error: HTTP 505 Version Not Implemented); 24 25 * cherokee/connection.c, 26 cherokee/downloader.c 27 - added formal parameter (HTTP) error_code. 28 1 29 2007-08-13 A.D.F <adefacc@tin.it> 2 30 cherokee/trunk/cherokee/connection.c
r893 r895 1368 1368 { 1369 1369 ret_t ret; 1370 cherokee_http_t error_code = http_bad_request; 1370 1371 char *host, *upgrade, *cnt; 1371 1372 cuint_t host_len, upgrade_len, cnt_len; … … 1373 1374 /* Header parsing 1374 1375 */ 1375 ret = cherokee_header_parse (&conn->header, &conn->incoming_header, header_type_request );1376 if ( ret < ret_ok) {1376 ret = cherokee_header_parse (&conn->header, &conn->incoming_header, header_type_request, &error_code); 1377 if (unlikely (ret < ret_ok)) 1377 1378 goto error; 1378 }1379 1379 1380 1380 /* Maybe read the POST data … … 1487 1487 1488 1488 error: 1489 conn->error_code = http_bad_request;1489 conn->error_code = error_code; 1490 1490 return ret_error; 1491 1491 } cherokee/trunk/cherokee/downloader.c
r889 r895 270 270 size_t readed = 0; 271 271 cherokee_socket_t *sock = &downloader->socket; 272 cherokee_http_t error_code = http_bad_request; 272 273 273 274 ret = cherokee_socket_bufread (sock, &downloader->reply_header, DEFAULT_RECV_SIZE, &readed); … … 303 304 */ 304 305 ret = cherokee_header_parse (downloader->header, 305 &downloader->reply_header, 306 header_type_response); 306 &downloader->reply_header, 307 header_type_response, 308 &error_code 309 ); 307 310 if (unlikely(ret != ret_ok)) return ret_error; 308 311 cherokee/trunk/cherokee/header.c
r863 r895 194 194 195 195 static ret_t 196 parse_response_first_line (cherokee_header_t *hdr, cherokee_buffer_t *buf, char **next_pos )196 parse_response_first_line (cherokee_header_t *hdr, cherokee_buffer_t *buf, char **next_pos, cherokee_http_t *error_code) 197 197 { 198 198 char *line = buf->buf; … … 200 200 char tmp[4]; 201 201 char *end; 202 203 end = strchr (line, CHR_CR); 204 if (end == NULL) { 202 size_t len; 203 204 /* NOTE: here we deal only with HTTP/1.0 or higher. 205 */ 206 len = strcspn(line, CRLF); 207 end = &line[len]; 208 209 /* Some security checks 210 */ 211 if (len < 14 || buf->len < 14) { 205 212 return ret_error; 206 213 } 207 214 208 /* Some security checks209 */210 if (buf->len < 14) {211 return ret_error;212 }213 214 215 /* Return next line 215 216 */ 216 *next_pos = end + 2; 217 switch (*end) { 218 case CHR_CR: 219 if (end[1] != CHR_LF) 220 return ret_error; 221 *next_pos = end + 2; 222 break; 223 case CHR_LF: 224 *next_pos = end + 1; 225 break; 226 default: 227 return ret_error; 228 } 217 229 218 230 /* Example: 219 231 * HTTP/1.0 403 Forbidden 220 232 */ 221 if (unlikely(! cmp_str(begin, "HTTP/"))) { 233 if (unlikely(! cmp_str(begin, "HTTP/1."))) { 234 /* TODO: improve parser 235 * (if ! "HTTP/" then leave default http_bad_request). 236 */ 237 *error_code = http_version_not_supported; 222 238 return ret_error; 223 239 } 224 240 241 if (unlikely(! isdigit(begin[7]))) { 242 return ret_error; 243 } 244 225 245 /* Get the HTTP version 226 246 */ 227 247 switch (begin[7]) { 228 case '1':229 hdr->version = http_version_11;230 break;231 248 case '0': 232 249 hdr->version = http_version_10; 233 250 break; 234 case '9': 235 hdr->version = http_version_09; 236 break; 251 case '1': 237 252 default: 238 return ret_error; 253 hdr->version = http_version_11; 254 break; 239 255 } 240 256 241 257 /* Read the response code 258 * TODO: skip spaces properly (usually there is only one blank). 242 259 */ 243 260 memcpy (tmp, begin+9, 3); … … 324 341 325 342 static ret_t 326 parse_request_first_line (cherokee_header_t *hdr, cherokee_buffer_t *buf, char **next_pos )343 parse_request_first_line (cherokee_header_t *hdr, cherokee_buffer_t *buf, char **next_pos, cherokee_http_t *error_code) 327 344 { 328 345 ret_t ret; 329 346 char *line = buf->buf; 330 347 char *begin = buf->buf; 348 char *begin_ver = buf->buf; 331 349 char *end; 332 350 char *ptr; 333 351 char *restore; 334 352 char chr_end; 353 size_t len = 0; 354 size_t len_ver = 0; 335 355 336 356 /* Basic security check. The shortest possible request 337 * "GET / HTTP/1.0" is 14 characters long.. 338 */ 339 if (unlikely(buf->len < 14)) { 357 * "GET / HTTP/1.0" is 14 characters long but we want 358 * to reply to HTTP/0.9 requests too which don't have 359 * HTTP version. 360 */ 361 if (unlikely(buf->len < 6)) { 340 362 return ret_error; 341 363 } … … 352 374 /* Return begin of next line 353 375 */ 376 len = (size_t) (end - line); 354 377 *next_pos = end + 1; 355 378 } else { 356 379 /* Return begin of next line 357 380 */ 381 len = (size_t) (end - line); 358 382 *next_pos = end + 2; 359 383 } … … 362 386 restore = end; 363 387 388 /* Check shortest string length "GET /" 389 */ 390 if (len < 5) 391 goto error; 392 364 393 /* Get the method 365 394 */ 366 395 ret = parse_method (hdr, line, &begin); 367 if (unlikely (ret != ret_ok)) 396 if (unlikely (ret != ret_ok)) { 397 *error_code = http_not_implemented; 368 398 goto error; 369 370 /* Get the protocol version 371 */ 372 switch (end[-1]) { 373 case '1': 374 if (unlikely (! cmp_str (end-8, "HTTP/1.1"))) 375 goto error; 376 hdr->version = http_version_11; 377 break; 378 case '0': 379 if (unlikely (! cmp_str (end-8, "HTTP/1.0"))) 380 goto error; 381 hdr->version = http_version_10; 382 break; 383 case '9': 384 if (unlikely (! cmp_str (end-8, "HTTP/0.9"))) 385 goto error; 386 hdr->version = http_version_09; 387 break; 388 default: 399 } 400 401 /* Skip other blank spaces between method and URI. 402 */ 403 begin += strspn (begin, LBS); 404 405 /* Length of URI. 406 */ 407 len = strcspn (begin, LBS); 408 if (len == 0) 389 409 goto error; 390 } 410 411 if (begin[len] == '\0') { 412 /* HTTP/0.9 has no HTTP version string and 413 * it is not supported by this server. 414 */ 415 *error_code = http_version_not_supported; 416 goto error; 417 } 418 419 begin_ver = &begin[len]; 420 begin_ver += strspn (begin_ver, LBS); 421 len_ver = (size_t) (end - begin_ver); 422 423 /* Verify "HTTP/x.x" pattern. 424 */ 425 if (len_ver != 8 || 426 !isdigit(begin_ver[5]) || 427 begin_ver[6] != '.' || 428 !isdigit(begin_ver[7]) || 429 !cmp_str (begin_ver, "HTTP/")) { 430 goto error; 431 } 432 433 /* Get the protocol version. 434 */ 435 if (begin_ver[5] != '1' || begin_ver[7] > '1') { 436 *error_code = http_version_not_supported; 437 goto error; 438 } 439 440 hdr->version = (begin_ver[7] == '1' ? http_version_11 : http_version_10); 391 441 392 442 /* Skip the HTTP version string: " HTTP/x.y" 393 443 */ 394 end -= 9;444 end = &begin[len]; 395 445 396 446 /* Look for the QueryString 397 447 */ 398 hdr->request_args_len = end - begin;448 hdr->request_args_len = len; 399 449 ptr = strchr (begin, '?'); 400 450 401 451 if (ptr) { 402 452 end = ptr; 403 hdr->query_string_off = ++ptr - buf->buf;404 hdr->query_string_len = ( unsigned long) strchr(ptr, ' ') - (unsigned long) ptr;453 hdr->query_string_off = (off_t) (++ptr - buf->buf); 454 hdr->query_string_len = (cint_t) (&begin[len] - ptr); 405 455 } else { 406 456 hdr->query_string_len = 0; … … 409 459 /* Get the request 410 460 */ 411 hdr->request_off = begin - buf->buf;412 hdr->request_len = end - begin;461 hdr->request_off = (off_t) (begin - buf->buf); 462 hdr->request_len = (cint_t) (end - begin); 413 463 414 464 /* Check if the request is a full URL … … 418 468 char *dir; 419 469 char *host = begin + 7; 420 470 char end_chr = *end; 471 472 if (host[0] == '/' || host[0] == '.') 473 goto error; 474 475 *end = '\0'; 421 476 dir = strchr (host, '/'); 477 *end = end_chr; 422 478 if (dir == NULL) 423 479 goto error; … … 474 530 475 531 ret_t 476 cherokee_header_parse (cherokee_header_t *hdr, cherokee_buffer_t *buffer, cherokee_type_header_t type )532 cherokee_header_parse (cherokee_header_t *hdr, cherokee_buffer_t *buffer, cherokee_type_header_t type, cherokee_http_t *error_code) 477 533 { 478 534 ret_t ret; … … 483 539 char *header_end; 484 540 char chr_header_end; 541 542 /* Set default error code. 543 */ 544 *error_code = http_bad_request; 485 545 486 546 /* Check the buffer content … … 529 589 * GET /icons/compressed.png HTTP/1.1CRLF 530 590 */ 531 ret = parse_request_first_line (hdr, buffer, &begin );591 ret = parse_request_first_line (hdr, buffer, &begin, error_code); 532 592 if (unlikely(ret < ret_ok)) { 533 593 PRINT_DEBUG ("ERROR: Failed to parse header_type_request:\n===\n%s===\n", buffer->buf); … … 538 598 539 599 case header_type_response: 540 ret = parse_response_first_line (hdr, buffer, &begin );600 ret = parse_response_first_line (hdr, buffer, &begin, error_code); 541 601 if (unlikely(ret < ret_ok)) { 542 602 PRINT_DEBUG ("ERROR: Failed to parse header_type_response:\n===\n%s===\n", buffer->buf); … … 923 983 924 984 /* Do we have enough information ? 985 * len("GET /" LF_LF) = 7 (HTTP/0.9) 925 986 * len("GET /" CRLF_CRLF) = 9 (HTTP/0.9) 926 987 * len("GET / HTTP/1.0" CRLF_CRLF) = 18 (HTTP/1.x) 927 988 */ 928 if (unlikely (buffer->len < 18)) {989 if (unlikely (buffer->len < 7)) { 929 990 return ret_not_found; 930 991 } cherokee/trunk/cherokee/header.h
r841 r895 82 82 83 83 ret_t cherokee_header_clean (cherokee_header_t *hdr); 84 ret_t cherokee_header_parse (cherokee_header_t *hdr, cherokee_buffer_t *buffer, cherokee_type_header_t type );84 ret_t cherokee_header_parse (cherokee_header_t *hdr, cherokee_buffer_t *buffer, cherokee_type_header_t type, cherokee_http_t *error_code); 85 85 ret_t cherokee_header_has_header (cherokee_header_t *hdr, cherokee_buffer_t *buffer, int tail_len); 86 86 cherokee/trunk/cherokee/macros.h
r883 r895 140 140 #define CRLF "\r\n" /* EOH (End Of Header Line) */ 141 141 #define LWS " \t\r\n" /* HTTP linear white space */ 142 #define LBS " \t" /* HTTP linear blank space */ 142 143 #define CHR_CR '\r' /* Carriage return */ 143 144 #define CHR_LF '\n' /* Line feed (new line) */