1/////////////////////////////////////////////////////////////////////////// 2// 3// Copyright (c) 2000-2003 Intel Corporation 4// All rights reserved. 5// 6// Redistribution and use in source and binary forms, with or without 7// modification, are permitted provided that the following conditions are met: 8// 9// * Redistributions of source code must retain the above copyright notice, 10// this list of conditions and the following disclaimer. 11// * Redistributions in binary form must reproduce the above copyright notice, 12// this list of conditions and the following disclaimer in the documentation 13// and/or other materials provided with the distribution. 14// * Neither name of Intel Corporation nor the names of its contributors 15// may be used to endorse or promote products derived from this software 16// without specific prior written permission. 17// 18// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR 22// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 23// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 24// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 25// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 26// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 27// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29// 30/////////////////////////////////////////////////////////////////////////// 31 32/************************************************************************ 33* Purpose: This file contains functions for scanner and parser for http 34* messages. 35************************************************************************/ 36 37#include <assert.h> 38#include <string.h> 39#include <ctype.h> 40#include <limits.h> 41#include <stdarg.h> 42#include "strintmap.h" 43#include "httpparser.h" 44#include "statcodes.h" 45#include "unixutil.h" 46 47// entity positions 48 49#define NUM_HTTP_METHODS 9 50static str_int_entry Http_Method_Table[NUM_HTTP_METHODS] = { 51 {"GET", HTTPMETHOD_GET}, 52 {"HEAD", HTTPMETHOD_HEAD}, 53 {"M-POST", HTTPMETHOD_MPOST}, 54 {"M-SEARCH", HTTPMETHOD_MSEARCH}, 55 {"NOTIFY", HTTPMETHOD_NOTIFY}, 56 {"POST", HTTPMETHOD_POST}, 57 {"SUBSCRIBE", HTTPMETHOD_SUBSCRIBE}, 58 {"UNSUBSCRIBE", HTTPMETHOD_UNSUBSCRIBE}, 59 {"POST", SOAPMETHOD_POST}, 60 61}; 62 63#define NUM_HTTP_HEADER_NAMES 33 64str_int_entry Http_Header_Names[NUM_HTTP_HEADER_NAMES] = { 65 {"ACCEPT", HDR_ACCEPT}, 66 {"ACCEPT-CHARSET", HDR_ACCEPT_CHARSET}, 67 {"ACCEPT-ENCODING", HDR_ACCEPT_ENCODING}, 68 {"ACCEPT-LANGUAGE", HDR_ACCEPT_LANGUAGE}, 69 {"ACCEPT-RANGES", HDR_ACCEPT_RANGE}, 70 {"CACHE-CONTROL", HDR_CACHE_CONTROL}, 71 {"CALLBACK", HDR_CALLBACK}, 72 {"CONTENT-ENCODING", HDR_CONTENT_ENCODING}, 73 {"CONTENT-LANGUAGE", HDR_CONTENT_LANGUAGE}, 74 {"CONTENT-LENGTH", HDR_CONTENT_LENGTH}, 75 {"CONTENT-LOCATION", HDR_CONTENT_LOCATION}, 76 {"CONTENT-RANGE", HDR_CONTENT_RANGE}, 77 {"CONTENT-TYPE", HDR_CONTENT_TYPE}, 78 {"DATE", HDR_DATE}, 79 {"EXT", HDR_EXT}, 80 {"HOST", HDR_HOST}, 81 {"IF-RANGE", HDR_IF_RANGE}, 82 {"LOCATION", HDR_LOCATION}, 83 {"MAN", HDR_MAN}, 84 {"MX", HDR_MX}, 85 {"NT", HDR_NT}, 86 {"NTS", HDR_NTS}, 87 {"RANGE", HDR_RANGE}, 88 {"SEQ", HDR_SEQ}, 89 {"SERVER", HDR_SERVER}, 90 {"SID", HDR_SID}, 91 {"SOAPACTION", HDR_SOAPACTION}, 92 {"ST", HDR_ST}, 93 {"TE", HDR_TE}, 94 {"TIMEOUT", HDR_TIMEOUT}, 95 {"TRANSFER-ENCODING", HDR_TRANSFER_ENCODING}, 96 {"USER-AGENT", HDR_USER_AGENT}, 97 {"USN", HDR_USN} 98}; 99 100/***********************************************************************/ 101 102/************* scanner **************/ 103 104/***********************************************************************/ 105 106#define TOKCHAR_CR 0xD 107#define TOKCHAR_LF 0xA 108 109/************************************************************************ 110* Function : scanner_init 111* 112* Parameters : 113* OUT scanner_t* scanner ; Scanner Object to be initialized 114* IN membuffer* bufptr ; Buffer to be copied 115* 116* Description : Intialize scanner 117* 118* Return : void ; 119* 120* Note : 121************************************************************************/ 122static XINLINE void 123scanner_init( OUT scanner_t * scanner, 124 IN membuffer * bufptr ) 125{ 126 scanner->cursor = 0; 127 scanner->msg = bufptr; 128 scanner->entire_msg_loaded = FALSE; 129} 130 131/************************************************************************ 132* Function : is_separator_char 133* 134* Parameters : 135* IN char c ; character to be tested against used separator values 136* 137* Description : Finds the separator character. 138* 139* Return : xboolean ; 140* 141* Note : 142************************************************************************/ 143static XINLINE xboolean 144is_separator_char( IN char c ) 145{ 146 return strchr( " \t()<>@,;:\\\"/[]?={}", c ) != NULL; 147} 148 149/************************************************************************ 150* Function : is_identifier_char 151* 152* Parameters : 153* IN char c ; character to be tested for separator values 154* 155* Description : Calls the function to indentify separator character 156* 157* Return : xboolean ; 158* 159* Note : 160************************************************************************/ 161static XINLINE xboolean 162is_identifier_char( IN char c ) 163{ 164 return ( c >= 32 && c <= 126 ) && !is_separator_char( c ); 165} 166 167/************************************************************************ 168* Function : is_control_char 169* 170* Parameters : 171* IN char c ; character to be tested for a control character 172* 173* Description : Determines if the passed value is a control character 174* 175* Return : xboolean ; 176* 177* Note : 178************************************************************************/ 179static XINLINE xboolean 180is_control_char( IN char c ) 181{ 182 return ( ( c >= 0 && c <= 31 ) || ( c == 127 ) ); 183} 184 185/************************************************************************ 186* Function : is_qdtext_char 187* 188* Parameters : 189* IN char cc ; character to be tested for CR/LF 190* 191* Description : Checks to see if the passed in value is CR/LF 192* 193* Return : xboolean ; 194* 195* Note : 196************************************************************************/ 197static XINLINE xboolean 198is_qdtext_char( IN char cc ) 199{ 200 unsigned char c = ( unsigned char )cc; 201 202 // we don't check for this; it's checked in get_token() 203 assert( c != '"' ); 204 205 if( ( c >= 32 && c != 127 ) || 206 ( c == TOKCHAR_CR || c == TOKCHAR_LF || c == '\t' ) 207 ) { 208 return TRUE; 209 } else { 210 return FALSE; 211 } 212} 213 214/************************************************************************ 215* Function : scanner_get_token 216* 217* Parameters : 218* INOUT scanner_t* scanner ; Scanner Object 219* OUT memptr* token ; Token 220* OUT token_type_t* tok_type ; Type of token 221* 222* Description : reads next token from the input stream 223* note: 0 and is used as a marker, and will not be valid in a quote 224* 225* Return : parse_status_t ; 226* PARSE_OK 227* PARSE_INCOMPLETE -- not enuf chars to get a token 228* PARSE_FAILURE -- bad msg format 229* 230* Note : 231************************************************************************/ 232static parse_status_t 233scanner_get_token( INOUT scanner_t * scanner, 234 OUT memptr * token_1, 235 OUT token_type_t * tok_type ) 236{ 237 char *cursor; 238 char *null_terminator; // point to null-terminator in buffer 239 char c; 240 token_type_t token_type; 241 xboolean got_end_quote; 242 243 assert( scanner ); 244 assert( token_1 ); 245 assert( tok_type ); 246 247 // point to next char in buffer 248 cursor = scanner->msg->buf + scanner->cursor; 249 null_terminator = scanner->msg->buf + scanner->msg->length; 250 251 // not enough chars in input to parse 252 if( cursor == null_terminator ) { 253 return PARSE_INCOMPLETE; 254 } 255 256 c = *cursor; 257 if( is_identifier_char( c ) ) { 258 // scan identifier 259 260 token_1->buf = cursor++; 261 token_type = TT_IDENTIFIER; 262 263 while( is_identifier_char( *cursor ) ) { 264 cursor++; 265 } 266 267 if( !scanner->entire_msg_loaded && cursor == null_terminator ) { 268 // possibly more valid chars 269 return PARSE_INCOMPLETE; 270 } 271 // calc token length 272 token_1->length = cursor - token_1->buf; 273 } else if( c == ' ' || c == '\t' ) { 274 token_1->buf = cursor++; 275 token_type = TT_WHITESPACE; 276 277 while( *cursor == ' ' || *cursor == '\t' ) { 278 cursor++; 279 } 280 281 if( !scanner->entire_msg_loaded && cursor == null_terminator ) { 282 // possibly more chars 283 return PARSE_INCOMPLETE; 284 } 285 token_1->length = cursor - token_1->buf; 286 } else if( c == TOKCHAR_CR ) { 287 // scan CRLF 288 289 token_1->buf = cursor++; 290 if( cursor == null_terminator ) { 291 // not enuf info to determine CRLF 292 return PARSE_INCOMPLETE; 293 } 294 if( *cursor != TOKCHAR_LF ) { 295 // couldn't match CRLF; match as CR 296 token_type = TT_CTRL; // ctrl char 297 token_1->length = 1; 298 } else { 299 // got CRLF 300 token_1->length = 2; 301 token_type = TT_CRLF; 302 cursor++; 303 } 304 } else if( c == TOKCHAR_LF ) // accept \n as CRLF 305 { 306 token_1->buf = cursor++; 307 token_1->length = 1; 308 token_type = TT_CRLF; 309 } else if( c == '"' ) { 310 // quoted text 311 token_1->buf = cursor++; 312 token_type = TT_QUOTEDSTRING; 313 got_end_quote = FALSE; 314 315 while( cursor < null_terminator ) { 316 c = *cursor++; 317 if( c == '"' ) { 318 got_end_quote = TRUE; 319 break; 320 } else if( c == '\\' ) { 321 if( cursor < null_terminator ) { 322 c = *cursor++; 323 //if ( !(c > 0 && c <= 127) ) 324 if( c == 0 ) { 325 return PARSE_FAILURE; 326 } 327 } 328 // else, while loop handles incomplete buf 329 } else if( is_qdtext_char( c ) ) { 330 // just accept char 331 } else { 332 // bad quoted text 333 return PARSE_FAILURE; 334 } 335 } 336 if( got_end_quote ) { 337 token_1->length = cursor - token_1->buf; 338 } else // incomplete 339 { 340 assert( cursor == null_terminator ); 341 return PARSE_INCOMPLETE; 342 } 343 } else if( is_separator_char( c ) ) { 344 // scan separator 345 346 token_1->buf = cursor++; 347 token_type = TT_SEPARATOR; 348 token_1->length = 1; 349 } else if( is_control_char( c ) ) { 350 // scan ctrl char 351 352 token_1->buf = cursor++; 353 token_type = TT_CTRL; 354 token_1->length = 1; 355 } else { 356 return PARSE_FAILURE; 357 } 358 359 scanner->cursor += token_1->length; // move to next token 360 *tok_type = token_type; 361 return PARSE_OK; 362} 363 364/************************************************************************ 365* Function : scanner_get_str 366* 367* Parameters : 368* IN scanner_t* scanner ; Scanner Object 369* 370* Description : returns ptr to next char in string 371* 372* Return : char* ; 373* 374* Note : 375************************************************************************/ 376static XINLINE char * 377scanner_get_str( IN scanner_t * scanner ) 378{ 379 return scanner->msg->buf + scanner->cursor; 380} 381 382/************************************************************************ 383* Function : scanner_pushback 384* 385* Parameters : 386* INOUT scanner_t* scanner ; Scanner Object 387* IN size_t pushback_bytes ; Bytes to be moved back 388* 389* Description : Move back by a certain number of bytes. 390* This is used to put back one or more tokens back into the input 391* 392* Return : void ; 393* 394* Note : 395************************************************************************/ 396static XINLINE void 397scanner_pushback( INOUT scanner_t * scanner, 398 IN size_t pushback_bytes ) 399{ 400 scanner->cursor -= pushback_bytes; 401} 402 403/***********************************************************************/ 404 405/************* end of scanner **************/ 406 407/***********************************************************************/ 408 409/***********************************************************************/ 410 411/************* parser **************/ 412 413/***********************************************************************/ 414 415/***********************************************************************/ 416 417/************* http_message_t **************/ 418 419/***********************************************************************/ 420 421/************************************************************************ 422* Function : httpmsg_compare 423* 424* Parameters : 425* void* param1 ; 426* void* param2 ; 427* 428* Description : Compares name id in the http headers. 429* 430* Return : int ; 431* 432* Note : 433************************************************************************/ 434static int 435httpmsg_compare( void *param1, 436 void *param2 ) 437{ 438 assert( param1 != NULL ); 439 assert( param2 != NULL ); 440 441 return ( ( http_header_t * ) param1 )->name_id == 442 ( ( http_header_t * ) param2 )->name_id; 443} 444 445/************************************************************************ 446* Function : httpheader_free 447* 448* Parameters : 449* void *msg ; 450* 451* Description : Free memory allocated for the http header 452* 453* Return : void ; 454* 455* Note : 456************************************************************************/ 457static void 458httpheader_free( void *msg ) 459{ 460 http_header_t *hdr = ( http_header_t * ) msg; 461 462 if(hdr==NULL) 463 return; 464 membuffer_destroy( &hdr->name_buf ); 465 membuffer_destroy( &hdr->value ); 466 free( hdr ); 467} 468 469/************************************************************************ 470* Function : httpmsg_init 471* 472* Parameters : 473* INOUT http_message_t* msg ; HTTP Message Object 474* 475* Description : Initialize and allocate memory for http message 476* 477* Return : void ; 478* 479* Note : 480************************************************************************/ 481void 482httpmsg_init( INOUT http_message_t * msg ) 483{ 484 msg->initialized = 1; 485 msg->entity.buf = NULL; 486 msg->entity.length = 0; 487 ListInit( &msg->headers, httpmsg_compare, httpheader_free ); 488 membuffer_init( &msg->msg ); 489 membuffer_init( &msg->status_msg ); 490} 491 492/************************************************************************ 493* Function : httpmsg_destroy 494* 495* Parameters : 496* INOUT http_message_t* msg ; HTTP Message Object 497* 498* Description : Free memory allocated for the http message 499* 500* Return : void ; 501* 502* Note : 503************************************************************************/ 504void 505httpmsg_destroy( INOUT http_message_t * msg ) 506{ 507 assert( msg != NULL ); 508 509 if( msg->initialized == 1 ) { 510 ListDestroy( &msg->headers, 1 ); 511 membuffer_destroy( &msg->msg ); 512 membuffer_destroy( &msg->status_msg ); 513 if(msg->urlbuf) 514 free( msg->urlbuf ); 515 msg->initialized = 0; 516 } 517} 518 519/************************************************************************ 520* Function : httpmsg_find_hdr_str 521* 522* Parameters : 523* IN http_message_t* msg ; HTTP Message Object 524* IN const char* header_name ; Header name to be compared with 525* 526* Description : Compares the header name with the header names stored 527* in the linked list of messages 528* 529* Return : http_header_t* - Pointer to a header on success; 530* NULL on failure 531* 532* Note : 533************************************************************************/ 534http_header_t * 535httpmsg_find_hdr_str( IN http_message_t * msg, 536 IN const char *header_name ) 537{ 538 http_header_t *header; 539 540 ListNode *node; 541 542 node = ListHead( &msg->headers ); 543 while( node != NULL ) { 544 545 header = ( http_header_t * ) node->item; 546 547 if( memptr_cmp_nocase( &header->name, header_name ) == 0 ) { 548 return header; 549 } 550 551 node = ListNext( &msg->headers, node ); 552 } 553 return NULL; 554} 555 556/************************************************************************ 557* Function : httpmsg_find_hdr 558* 559* Parameters : 560* IN http_message_t* msg ; HTTP Message Object 561* IN int header_name_id ; Header Name ID to be compared with 562* OUT memptr* value ; Buffer to get the ouput to. 563* 564* Description : Finds header from a list, with the given 'name_id'. 565* 566* Return : http_header_t* - Pointer to a header on success; * 567* NULL on failure 568* 569* Note : 570************************************************************************/ 571http_header_t * 572httpmsg_find_hdr( IN http_message_t * msg, 573 IN int header_name_id, 574 OUT memptr * value ) 575{ 576 http_header_t header; // temp header for searching 577 578 ListNode *node; 579 580 http_header_t *data; 581 582 header.name_id = header_name_id; 583 584 node = ListFind( &msg->headers, NULL, &header ); 585 586 if( node == NULL ) { 587 return NULL; 588 } 589 590 data = ( http_header_t * ) node->item; 591 592 if( value != NULL ) { 593 value->buf = data->value.buf; 594 value->length = data->value.length; 595 } 596 597 return data; 598} 599 600/***********************************************************************/ 601 602/************* http_parser_t **************/ 603 604/***********************************************************************/ 605 606/************************************************************************ 607* Function : skip_blank_lines 608* 609* Parameters : 610* INOUT scanner_t* scanner ; Scanner Object 611* 612* Description : skips blank lines at the start of a msg. 613* 614* Return : int ; 615* 616* Note : 617************************************************************************/ 618static XINLINE int 619skip_blank_lines( INOUT scanner_t * scanner ) 620{ 621 memptr token_1; 622 token_type_t tok_type; 623 parse_status_t status; 624 625 // skip ws, crlf 626 do { 627 status = scanner_get_token( scanner, &token_1, &tok_type ); 628 } while( status == PARSE_OK && 629 ( tok_type == TT_WHITESPACE || tok_type == TT_CRLF ) ); 630 631 if( status == PARSE_OK ) { 632 // pushback a non-whitespace token 633 scanner->cursor -= token_1.length; 634 //scanner_pushback( scanner, token.length ); 635 } 636 637 return status; 638} 639 640/************************************************************************ 641* Function : skip_lws 642* 643* Parameters : 644* INOUT scanner_t* scanner ; Scanner Object 645* 646* Description : skip linear whitespace. 647* 648* Return : int ; 649* PARSE_OK: (LWS)* removed from input 650* PARSE_FAILURE: bad input 651* PARSE_INCOMPLETE: incomplete input 652* 653* Note : 654************************************************************************/ 655static XINLINE int 656skip_lws( INOUT scanner_t * scanner ) 657{ 658 memptr token_1; 659 token_type_t tok_type; 660 parse_status_t status; 661 size_t save_pos; 662 xboolean matched; 663 664 do { 665 save_pos = scanner->cursor; 666 matched = FALSE; 667 668 // get CRLF or WS 669 status = scanner_get_token( scanner, &token_1, &tok_type ); 670 if( status == PARSE_OK ) { 671 if( tok_type == TT_CRLF ) { 672 // get WS 673 status = scanner_get_token( scanner, &token_1, &tok_type ); 674 } 675 676 if( status == PARSE_OK && tok_type == TT_WHITESPACE ) { 677 matched = TRUE; 678 } else { 679 // did not match LWS; pushback token(s) 680 scanner->cursor = save_pos; 681 } 682 } 683 } while( matched ); 684 685 // if entire msg is loaded, ignore an 'incomplete' warning 686 if( status == PARSE_INCOMPLETE && scanner->entire_msg_loaded ) { 687 status = PARSE_OK; 688 } 689 690 return status; 691} 692 693/************************************************************************ 694* Function : match_non_ws_string 695* 696* Parameters : 697* INOUT scanner_t* scanner ; Scanner Object 698* OUT memptr* str ; Buffer to get the scanner buffer contents. 699* 700* Description : Match a string without whitespace or CRLF (%S) 701* 702* Return : XINLINE parse_status_t ; 703* PARSE_OK 704* PARSE_NO_MATCH 705* PARSE_FAILURE 706* PARSE_INCOMPLETE 707* 708* Note : 709************************************************************************/ 710static XINLINE parse_status_t 711match_non_ws_string( INOUT scanner_t * scanner, 712 OUT memptr * str ) 713{ 714 memptr token_1; 715 token_type_t tok_type; 716 parse_status_t status; 717 xboolean done = FALSE; 718 size_t save_cursor; 719 720 save_cursor = scanner->cursor; 721 722 str->length = 0; 723 str->buf = scanner_get_str( scanner ); // point to next char in input 724 725 while( !done ) { 726 status = scanner_get_token( scanner, &token_1, &tok_type ); 727 if( status == PARSE_OK && 728 tok_type != TT_WHITESPACE && tok_type != TT_CRLF ) { 729 // append non-ws token 730 str->length += token_1.length; 731 } else { 732 done = TRUE; 733 } 734 } 735 736 if( status == PARSE_OK ) { 737 // last token was WS; push it back in 738 scanner->cursor -= token_1.length; 739 } 740 // tolerate 'incomplete' msg 741 if( status == PARSE_OK || 742 ( status == PARSE_INCOMPLETE && scanner->entire_msg_loaded ) 743 ) { 744 if( str->length == 0 ) { 745 // no strings found 746 return PARSE_NO_MATCH; 747 } else { 748 return PARSE_OK; 749 } 750 } else { 751 // error -- pushback tokens 752 scanner->cursor = save_cursor; 753 return status; 754 } 755} 756 757/************************************************************************ 758* Function : match_raw_value 759* 760* Parameters : 761* INOUT scanner_t* scanner ; Scanner Object 762* OUT memptr* raw_value ; Buffer to get the scanner buffer 763* contents 764* 765* Description : Matches a raw value in a the input; value's length 766* can be 0 or more. Whitespace after value is trimmed. On success, 767* scanner points the CRLF that ended the value 768* 769* Return : parse_status_t ; 770* PARSE_OK 771* PARSE_INCOMPLETE 772* PARSE_FAILURE 773* 774* Note : 775************************************************************************/ 776static XINLINE parse_status_t 777match_raw_value( INOUT scanner_t * scanner, 778 OUT memptr * raw_value ) 779{ 780 memptr token_1; 781 token_type_t tok_type; 782 parse_status_t status; 783 xboolean done = FALSE; 784 xboolean saw_crlf = FALSE; 785 size_t pos_at_crlf = 0; 786 size_t save_pos; 787 char c; 788 789 save_pos = scanner->cursor; 790 791 // value points to start of input 792 raw_value->buf = scanner_get_str( scanner ); 793 raw_value->length = 0; 794 795 while( !done ) { 796 status = scanner_get_token( scanner, &token_1, &tok_type ); 797 if( status == PARSE_OK ) { 798 if( !saw_crlf ) { 799 if( tok_type == TT_CRLF ) { 800 // CRLF could end value 801 saw_crlf = TRUE; 802 803 // save input position at start of CRLF 804 pos_at_crlf = scanner->cursor - token_1.length; 805 } 806 // keep appending value 807 raw_value->length += token_1.length; 808 } else // already seen CRLF 809 { 810 if( tok_type == TT_WHITESPACE ) { 811 // start again; forget CRLF 812 saw_crlf = FALSE; 813 raw_value->length += token_1.length; 814 } else { 815 // non-ws means value ended just before CRLF 816 done = TRUE; 817 818 // point to the crlf which ended the value 819 scanner->cursor = pos_at_crlf; 820 } 821 } 822 } else { 823 // some kind of error; restore scanner position 824 scanner->cursor = save_pos; 825 done = TRUE; 826 } 827 } 828 829 if( status == PARSE_OK ) { 830 // trim whitespace on right side of value 831 while( raw_value->length > 0 ) { 832 // get last char 833 c = raw_value->buf[raw_value->length - 1]; 834 835 if( c != ' ' && c != '\t' && 836 c != TOKCHAR_CR && c != TOKCHAR_LF ) { 837 // done; no more whitespace 838 break; 839 } 840 // remove whitespace 841 raw_value->length--; 842 } 843 } 844 845 return status; 846} 847 848/************************************************************************ 849* Function: match_int 850* 851* Parameters: 852* INOUT scanner_t* scanner ; Scanner Object 853* IN int base : Base of number in the string; 854* valid values: 10 or 16 855* OUT int* value ; Number stored here 856* 857* Description: Matches an unsigned integer value in the input. The 858* integer is returned in 'value'. Except for PARSE_OK result, the 859* scanner's cursor is moved back to its original position on error. 860* 861* Returns: 862* PARSE_OK 863* PARSE_NO_MATCH -- got different kind of token 864* PARSE_FAILURE -- bad input 865* PARSE_INCOMPLETE 866************************************************************************/ 867static XINLINE int 868match_int( INOUT scanner_t * scanner, 869 IN int base, 870 OUT int *value ) 871{ 872 memptr token_1; 873 token_type_t tok_type; 874 parse_status_t status; 875 int num; 876 char *end_ptr; 877 size_t save_pos; 878 879 save_pos = scanner->cursor; 880 881 status = scanner_get_token( scanner, &token_1, &tok_type ); 882 if( status == PARSE_OK ) { 883 if( tok_type == TT_IDENTIFIER ) { 884 errno = 0; 885 886 num = strtol( token_1.buf, &end_ptr, base ); 887 if( ( num < 0 ) 888 // all and only those chars in token should be used for num 889 || ( end_ptr != token_1.buf + token_1.length ) 890 || ( ( num == LONG_MIN || num == LONG_MAX ) 891 && ( errno == ERANGE ) ) 892 ) { 893 status = PARSE_NO_MATCH; 894 } 895 896 *value = num; // save result 897 } else { 898 status = PARSE_NO_MATCH; // token must be an identifier 899 } 900 } 901 902 if( status != PARSE_OK ) { 903 // restore scanner position for bad values 904 scanner->cursor = save_pos; 905 } 906 907 return status; 908} 909 910/************************************************************************ 911* Function: read_until_crlf 912* 913* Parameters: 914* INOUT scanner_t* scanner ; Scanner Object 915* OUT memptr* str ; Buffer to copy scanner buffer contents to 916* 917* Description: Reads data until end of line; the crlf at the end of 918* line is not consumed. On error, scanner is not restored. On 919* success, 'str' points to a string that runs until eol 920* 921* Returns: 922* PARSE_OK 923* PARSE_FAILURE 924* PARSE_INCOMPLETE 925************************************************************************/ 926static XINLINE int 927read_until_crlf( INOUT scanner_t * scanner, 928 OUT memptr * str ) 929{ 930 memptr token_1; 931 token_type_t tok_type; 932 parse_status_t status; 933 size_t start_pos; 934 935 start_pos = scanner->cursor; 936 str->buf = scanner_get_str( scanner ); 937 938 // read until we hit a crlf 939 do { 940 status = scanner_get_token( scanner, &token_1, &tok_type ); 941 } while( status == PARSE_OK && tok_type != TT_CRLF ); 942 943 if( status == PARSE_OK ) { 944 // pushback crlf in stream 945 scanner->cursor -= token_1.length; 946 947 // str should include all strings except crlf at the end 948 str->length = scanner->cursor - start_pos; 949 } 950 951 return status; 952} 953 954/************************************************************************ 955* Function: skip_to_end_of_header 956* 957* Parameters: 958* INOUT scanner_t* scanner ; Scanner Object 959* 960* Description: Skip to end of header 961* 962* Returns: 963* PARSE_OK 964* PARSE_FAILURE 965* PARSE_INCOMPLETE 966************************************************************************/ 967static XINLINE int 968skip_to_end_of_header( INOUT scanner_t * scanner ) 969{ 970 memptr dummy_raw_value; 971 parse_status_t status; 972 973 status = match_raw_value( scanner, &dummy_raw_value ); 974 return status; 975} 976 977/************************************************************************ 978* Function: match_char 979* 980* Parameters: 981* INOUT scanner_t* scanner ; Scanner Object 982* IN char c ; Character to be compared with 983* IN xboolean case_sensitive; Flag indicating whether comparison should 984* be case sensitive 985* 986* Description: Compares a character to the next char in the scanner; 987* on error, scanner chars are not restored 988* 989* Returns: 990* PARSE_OK 991* PARSE_NO_MATCH 992* PARSE_INCOMPLETE 993************************************************************************/ 994static XINLINE parse_status_t 995match_char( INOUT scanner_t * scanner, 996 IN char c, 997 IN xboolean case_sensitive ) 998{ 999 char scan_char; 1000 1001 if( scanner->cursor >= scanner->msg->length ) { 1002 return PARSE_INCOMPLETE; 1003 } 1004 // read next char from scanner 1005 scan_char = scanner->msg->buf[scanner->cursor++]; 1006 1007 if( case_sensitive ) { 1008 return c == scan_char ? PARSE_OK : PARSE_NO_MATCH; 1009 } else { 1010 return tolower( c ) == tolower( scan_char ) ? 1011 PARSE_OK : PARSE_NO_MATCH; 1012 } 1013} 1014 1015//////////////////////////////////////////////////////////////////////// 1016// args for ... 1017// %d, int * (31-bit positive integer) 1018// %x, int * (31-bit postive number encoded as hex) 1019// %s, memptr* (simple identifier) 1020// %q, memptr* (quoted string) 1021// %S, memptr* (non-whitespace string) 1022// %R, memptr* (raw value) 1023// %U, uri_type* (url) 1024// %L, memptr* (string until end of line) 1025// %P, int * (current index of the string being scanned) 1026// 1027// no args for 1028// ' ' LWS* 1029// \t whitespace 1030// "%%" matches '%' 1031// "% " matches ' ' 1032// %c matches CRLF 1033// %i ignore case in literal matching 1034// %n case-sensitive matching in literals 1035// %w optional whitespace; (similar to '\t', 1036// except whitespace is optional) 1037// %0 (zero) match null-terminator char '\0' 1038// (can only be used as last char in fmt) 1039// use only in matchstr(), not match() 1040// other chars match literally 1041// 1042// returns: 1043// PARSE_OK 1044// PARSE_INCOMPLETE 1045// PARSE_FAILURE -- bad input 1046// PARSE_NO_MATCH -- input does not match pattern 1047 1048/************************************************************************ 1049* Function : vfmatch 1050* 1051* Parameters : 1052* INOUT scanner_t* scanner ; Scanner Object 1053* IN const char* fmt ; Pattern Format 1054* va_list argp ; List of variable arguments 1055* 1056* Description : Extracts variable parameters depending on the passed 1057* in format parameter. Parses data also based on the passed in 1058* format parameter. 1059* 1060* Return : int ; 1061* PARSE_OK 1062* PARSE_INCOMPLETE 1063* PARSE_FAILURE - bad input 1064* PARSE_NO_MATCH - input does not match pattern 1065* 1066* Note : 1067************************************************************************/ 1068static int 1069vfmatch( INOUT scanner_t * scanner, 1070 IN const char *fmt, 1071 va_list argp ) 1072{ 1073 char c; 1074 const char *fmt_ptr = fmt; 1075 parse_status_t status; 1076 memptr *str_ptr; 1077 memptr temp_str; 1078 int *int_ptr; 1079 uri_type *uri_ptr; 1080 size_t save_pos; 1081 int stat; 1082 xboolean case_sensitive = TRUE; 1083 memptr token_1; 1084 token_type_t tok_type; 1085 int base; 1086 1087 assert( scanner != NULL ); 1088 assert( fmt != NULL ); 1089 1090 // save scanner pos; to aid error recovery 1091 save_pos = scanner->cursor; 1092 1093 status = PARSE_OK; 1094 while( ( ( c = *fmt_ptr++ ) != 0 ) && ( status == PARSE_OK ) 1095 ) { 1096 if( c == '%' ) { 1097 c = *fmt_ptr++; 1098 1099 switch ( c ) { 1100 1101 case 'R': // raw value 1102 str_ptr = va_arg( argp, memptr * ); 1103 assert( str_ptr != NULL ); 1104 status = match_raw_value( scanner, str_ptr ); 1105 break; 1106 1107 case 's': // simple identifier 1108 str_ptr = va_arg( argp, memptr * ); 1109 assert( str_ptr != NULL ); 1110 status = scanner_get_token( scanner, str_ptr, 1111 &tok_type ); 1112 if( status == PARSE_OK && tok_type != TT_IDENTIFIER ) { 1113 // not an identifier 1114 status = PARSE_NO_MATCH; 1115 } 1116 break; 1117 1118 case 'c': // crlf 1119 status = scanner_get_token( scanner, 1120 &token_1, &tok_type ); 1121 if( status == PARSE_OK && tok_type != TT_CRLF ) { 1122 // not CRLF token 1123 status = PARSE_NO_MATCH; 1124 } 1125 break; 1126 1127 case 'd': // integer 1128 case 'x': // hex number 1129 int_ptr = va_arg( argp, int * ); 1130 1131 assert( int_ptr != NULL ); 1132 base = ( c == 'd' ? 10 : 16 ); 1133 status = match_int( scanner, base, int_ptr ); 1134 break; 1135 1136 case 'S': // non-whitespace string 1137 case 'U': // uri 1138 if( c == 'S' ) { 1139 str_ptr = va_arg( argp, memptr * ); 1140 } else { 1141 str_ptr = &temp_str; 1142 } 1143 assert( str_ptr != NULL ); 1144 status = match_non_ws_string( scanner, str_ptr ); 1145 if( c == 'U' && status == PARSE_OK ) { 1146 uri_ptr = va_arg( argp, uri_type * ); 1147 assert( uri_ptr != NULL ); 1148 stat = parse_uri( str_ptr->buf, str_ptr->length, 1149 uri_ptr ); 1150 if( stat != HTTP_SUCCESS ) { 1151 status = PARSE_NO_MATCH; 1152 } 1153 } 1154 break; 1155 1156 case 'L': // string till eol 1157 str_ptr = va_arg( argp, memptr * ); 1158 assert( str_ptr != NULL ); 1159 status = read_until_crlf( scanner, str_ptr ); 1160 break; 1161 1162 case ' ': // match space 1163 case '%': // match percentage symbol 1164 status = match_char( scanner, c, case_sensitive ); 1165 break; 1166 1167 case 'n': // case-sensitive match 1168 case_sensitive = TRUE; 1169 break; 1170 1171 case 'i': // ignore case 1172 case_sensitive = FALSE; 1173 break; 1174 1175 case 'q': // quoted string 1176 str_ptr = ( memptr * ) va_arg( argp, memptr * ); 1177 status = 1178 scanner_get_token( scanner, str_ptr, &tok_type ); 1179 if( status == PARSE_OK && tok_type != TT_QUOTEDSTRING ) { 1180 status = PARSE_NO_MATCH; // not a quoted string 1181 } 1182 break; 1183 1184 case 'w': // optional whitespace 1185 status = scanner_get_token( scanner, 1186 &token_1, &tok_type ); 1187 if( status == PARSE_OK && tok_type != TT_WHITESPACE ) { 1188 // restore non-whitespace token 1189 scanner->cursor -= token_1.length; 1190 } 1191 break; 1192 1193 case 'P': // current pos of scanner 1194 int_ptr = va_arg( argp, int * ); 1195 1196 assert( int_ptr != NULL ); 1197 *int_ptr = scanner->cursor; 1198 break; 1199 1200 // valid only in matchstr() 1201 case '0': // end of msg? 1202 // check that we are 1 beyond last char 1203 if( scanner->cursor == scanner->msg->length && 1204 scanner->msg->buf[scanner->cursor] == '\0' ) { 1205 status = PARSE_OK; 1206 } else { 1207 status = PARSE_NO_MATCH; 1208 } 1209 break; 1210 1211 default: 1212 assert( 0 ); // unknown option 1213 } 1214 } else { 1215 switch ( c ) { 1216 case ' ': // LWS* 1217 status = skip_lws( scanner ); 1218 break; 1219 1220 case '\t': // Whitespace 1221 status = scanner_get_token( scanner, 1222 &token_1, &tok_type ); 1223 if( status == PARSE_OK && tok_type != TT_WHITESPACE ) { 1224 // not whitespace token 1225 status = PARSE_NO_MATCH; 1226 } 1227 break; 1228 1229 default: // match characters 1230 { 1231 status = match_char( scanner, c, case_sensitive ); 1232 } 1233 } 1234 } 1235 } 1236 1237 if( status != PARSE_OK ) { 1238 // on error, restore original scanner pos 1239 scanner->cursor = save_pos; 1240 } 1241 1242 return status; 1243} 1244 1245/************************************************************************ 1246* Function: match 1247* 1248* Parameters: 1249* INOUT scanner_t* scanner ; Scanner Object 1250* IN const char* fmt; Pattern format 1251* ... 1252* 1253* Description: matches a variable parameter list and takes necessary 1254* actions based on the data type specified. 1255* 1256* Returns: 1257* PARSE_OK 1258* PARSE_NO_MATCH 1259* PARSE_INCOMPLETE 1260************************************************************************/ 1261static int 1262match( INOUT scanner_t * scanner, 1263 IN const char *fmt, 1264 ... ) 1265{ 1266 int ret_code; 1267 va_list args; 1268 1269 va_start( args, fmt ); 1270 ret_code = vfmatch( scanner, fmt, args ); 1271 va_end( args ); 1272 1273 return ret_code; 1274} 1275 1276/************************************************************************ 1277* Function: matchstr 1278* 1279* Parameters: 1280* IN char *str ; String to be matched 1281* IN size_t slen ; Length of the string 1282* IN const char* fmt ; Pattern format 1283* ... 1284* 1285* Description: Matches a variable parameter list with a string 1286* and takes actions based on the data type specified. 1287* 1288* Returns: 1289* PARSE_OK 1290* PARSE_NO_MATCH -- failure to match pattern 'fmt' 1291* PARSE_FAILURE -- 'str' is bad input 1292************************************************************************/ 1293int 1294matchstr( IN char *str, 1295 IN size_t slen, 1296 IN const char *fmt, 1297 ... ) 1298{ 1299 int ret_code; 1300 char save_char; 1301 scanner_t scanner; 1302 membuffer buf; 1303 va_list arg_list; 1304 1305 // null terminate str 1306 save_char = str[slen]; 1307 str[slen] = '\0'; 1308 1309 membuffer_init( &buf ); 1310 1311 // under no circumstances should this buffer be modifed because its memory 1312 // might have not come from malloc() 1313 membuffer_attach( &buf, str, slen ); 1314 1315 scanner_init( &scanner, &buf ); 1316 scanner.entire_msg_loaded = TRUE; 1317 1318 va_start( arg_list, fmt ); 1319 ret_code = vfmatch( &scanner, fmt, arg_list ); 1320 va_end( arg_list ); 1321 1322 // restore str 1323 str[slen] = save_char; 1324 1325 // don't destroy buf 1326 1327 return ret_code; 1328} 1329 1330/************************************************************************ 1331* Function: parser_init 1332* 1333* Parameters: 1334* OUT http_parser_t* parser ; HTTP Parser object 1335* 1336* Description: Initializes the parser object. 1337* 1338* Returns: 1339* void 1340************************************************************************/ 1341static XINLINE void 1342parser_init( OUT http_parser_t * parser ) 1343{ 1344 memset( parser, 0, sizeof( http_parser_t ) ); 1345 1346 parser->http_error_code = HTTP_BAD_REQUEST; // err msg by default 1347 parser->ent_position = ENTREAD_DETERMINE_READ_METHOD; 1348 parser->valid_ssdp_notify_hack = FALSE; 1349 1350 httpmsg_init( &parser->msg ); 1351 scanner_init( &parser->scanner, &parser->msg.msg ); 1352} 1353 1354/************************************************************************ 1355* Function: parser_parse_requestline 1356* 1357* Parameters: 1358* INOUT http_parser_t* parser ; HTTP Parser object 1359* 1360* Description: Get HTTP Method, URL location and version information. 1361* 1362* Returns: 1363* PARSE_OK 1364* PARSE_SUCCESS 1365* PARSE_FAILURE 1366************************************************************************/ 1367static parse_status_t 1368parser_parse_requestline( INOUT http_parser_t * parser ) 1369{ 1370 parse_status_t status; 1371 http_message_t *hmsg = &parser->msg; 1372 memptr method_str; 1373 memptr version_str; 1374 int index; 1375 char save_char; 1376 int num_scanned; 1377 memptr url_str; 1378 1379 assert( parser->position == POS_REQUEST_LINE ); 1380 1381 status = skip_blank_lines( &parser->scanner ); 1382 if( status != PARSE_OK ) { 1383 return status; 1384 } 1385 //simple get http 0.9 as described in http 1.0 spec 1386 1387 status = 1388 match( &parser->scanner, "%s\t%S%w%c", &method_str, &url_str ); 1389 1390 if( status == PARSE_OK ) { 1391 1392 index = 1393 map_str_to_int( method_str.buf, method_str.length, 1394 Http_Method_Table, NUM_HTTP_METHODS, TRUE ); 1395 1396 if( index < 0 ) { 1397 // error; method not found 1398 parser->http_error_code = HTTP_NOT_IMPLEMENTED; 1399 return PARSE_FAILURE; 1400 } 1401 1402 if( Http_Method_Table[index].id != HTTPMETHOD_GET ) { 1403 parser->http_error_code = HTTP_BAD_REQUEST; 1404 return PARSE_FAILURE; 1405 } 1406 1407 hmsg->method = HTTPMETHOD_SIMPLEGET; 1408 1409 // store url 1410 hmsg->urlbuf = str_alloc( url_str.buf, url_str.length ); 1411 if( hmsg->urlbuf == NULL ) { 1412 // out of mem 1413 parser->http_error_code = HTTP_INTERNAL_SERVER_ERROR; 1414 return PARSE_FAILURE; 1415 } 1416 if( parse_uri( hmsg->urlbuf, url_str.length, &hmsg->uri ) != 1417 HTTP_SUCCESS ) { 1418 return PARSE_FAILURE; 1419 } 1420 1421 parser->position = POS_COMPLETE; // move to headers 1422 1423 return PARSE_SUCCESS; 1424 } 1425 1426 status = match( &parser->scanner, 1427 "%s\t%S\t%ihttp%w/%w%L%c", &method_str, &url_str, 1428 &version_str ); 1429 if( status != PARSE_OK ) { 1430 return status; 1431 } 1432 // store url 1433 hmsg->urlbuf = str_alloc( url_str.buf, url_str.length ); 1434 if( hmsg->urlbuf == NULL ) { 1435 // out of mem 1436 parser->http_error_code = HTTP_INTERNAL_SERVER_ERROR; 1437 return PARSE_FAILURE; 1438 } 1439 if( parse_uri( hmsg->urlbuf, url_str.length, &hmsg->uri ) != 1440 HTTP_SUCCESS ) { 1441 return PARSE_FAILURE; 1442 } 1443 // scan version 1444 save_char = version_str.buf[version_str.length]; 1445 version_str.buf[version_str.length] = '\0'; // null-terminate 1446 num_scanned = sscanf( version_str.buf, "%d . %d", 1447 &hmsg->major_version, &hmsg->minor_version ); 1448 version_str.buf[version_str.length] = save_char; // restore 1449 if( num_scanned != 2 || 1450 hmsg->major_version < 0 || hmsg->minor_version < 0 ) { 1451 // error; bad http version 1452 return PARSE_FAILURE; 1453 } 1454 1455 index = 1456 map_str_to_int( method_str.buf, method_str.length, 1457 Http_Method_Table, NUM_HTTP_METHODS, TRUE ); 1458 if( index < 0 ) { 1459 // error; method not found 1460 parser->http_error_code = HTTP_NOT_IMPLEMENTED; 1461 return PARSE_FAILURE; 1462 } 1463 1464 hmsg->method = Http_Method_Table[index].id; 1465 parser->position = POS_HEADERS; // move to headers 1466 1467 return PARSE_OK; 1468} 1469 1470/************************************************************************ 1471* Function: parser_parse_responseline 1472* 1473* Parameters: 1474* INOUT http_parser_t* parser ; HTTP Parser object 1475* 1476* Description: Get HTTP Method, URL location and version information. 1477* 1478* Returns: 1479* PARSE_OK 1480* PARSE_SUCCESS 1481* PARSE_FAILURE 1482************************************************************************/ 1483parse_status_t 1484parser_parse_responseline( INOUT http_parser_t * parser ) 1485{ 1486 parse_status_t status; 1487 http_message_t *hmsg = &parser->msg; 1488 memptr line; 1489 char save_char; 1490 int num_scanned; 1491 int i; 1492 char *p; 1493 1494 assert( parser->position == POS_RESPONSE_LINE ); 1495 1496 status = skip_blank_lines( &parser->scanner ); 1497 if( status != PARSE_OK ) { 1498 return status; 1499 } 1500 // response line 1501 //status = match( &parser->scanner, "%ihttp%w/%w%d\t.\t%d\t%d\t%L%c", 1502 // &hmsg->major_version, &hmsg->minor_version, 1503 // &hmsg->status_code, &hmsg->status_msg ); 1504 1505 status = match( &parser->scanner, "%ihttp%w/%w%L%c", &line ); 1506 if( status != PARSE_OK ) { 1507 return status; 1508 } 1509 1510 save_char = line.buf[line.length]; 1511 line.buf[line.length] = '\0'; // null-terminate 1512 1513 // scan http version and ret code 1514 num_scanned = sscanf( line.buf, "%d . %d %d", 1515 &hmsg->major_version, &hmsg->minor_version, 1516 &hmsg->status_code ); 1517 1518 line.buf[line.length] = save_char; // restore 1519 1520 if( num_scanned != 3 || 1521 hmsg->major_version < 0 || 1522 hmsg->minor_version < 0 || hmsg->status_code < 0 ) { 1523 // bad response line 1524 return PARSE_FAILURE; 1525 } 1526 // 1527 // point to status msg 1528 // 1529 1530 p = line.buf; 1531 1532 // skip 3 ints 1533 for( i = 0; i < 3; i++ ) { 1534 // go to start of num 1535 while( !isdigit( *p ) ) { 1536 p++; 1537 } 1538 1539 // skip int 1540 while( isdigit( *p ) ) { 1541 p++; 1542 } 1543 } 1544 1545 // whitespace must exist after status code 1546 if( *p != ' ' && *p != '\t' ) { 1547 return PARSE_FAILURE; 1548 } 1549 // skip whitespace 1550 while( *p == ' ' || *p == '\t' ) { 1551 p++; 1552 } 1553 1554 // now, p is at start of status msg 1555 if( membuffer_assign( &hmsg->status_msg, p, 1556 line.length - ( p - line.buf ) ) != 0 ) { 1557 // out of mem 1558 parser->http_error_code = HTTP_INTERNAL_SERVER_ERROR; 1559 return PARSE_FAILURE; 1560 } 1561 1562 parser->position = POS_HEADERS; // move to headers 1563 1564 return PARSE_OK; 1565} 1566 1567/************************************************************************ 1568* Function: parser_parse_headers 1569* 1570* Parameters: 1571* INOUT http_parser_t* parser ; HTTP Parser object 1572* 1573* Description: Get HTTP Method, URL location and version information. 1574* 1575* Returns: 1576* PARSE_OK 1577* PARSE_SUCCESS 1578* PARSE_FAILURE 1579************************************************************************/ 1580parse_status_t 1581parser_parse_headers( INOUT http_parser_t * parser ) 1582{ 1583 parse_status_t status; 1584 memptr token_1; 1585 memptr hdr_value; 1586 token_type_t tok_type; 1587 scanner_t *scanner = &parser->scanner; 1588 size_t save_pos; 1589 http_header_t *header; 1590 int header_id; 1591 int ret = 0; 1592 int index_1; 1593 http_header_t *orig_header; 1594 char save_char; 1595 int ret2; 1596 1597 assert( parser->position == POS_HEADERS || 1598 parser->ent_position == ENTREAD_CHUNKY_HEADERS ); 1599 1600 while( TRUE ) { 1601 save_pos = scanner->cursor; 1602 1603 // 1604 // check end of headers 1605 // 1606 status = scanner_get_token( scanner, &token_1, &tok_type ); 1607 if( status != PARSE_OK ) { 1608 return status; 1609 } 1610 1611 if( tok_type == TT_CRLF ) { 1612 1613 // end of headers 1614 if( ( parser->msg.is_request ) 1615 && ( parser->msg.method == HTTPMETHOD_POST ) ) { 1616 parser->position = POS_COMPLETE; //post entity parsing 1617 //is handled separately 1618 return PARSE_SUCCESS; 1619 } 1620 1621 parser->position = POS_ENTITY; // read entity next 1622 return PARSE_OK; 1623 } 1624 // 1625 // not end; read header 1626 // 1627 if( tok_type != TT_IDENTIFIER ) { 1628 return PARSE_FAILURE; // didn't see header name 1629 } 1630 1631 status = match( scanner, " : %R%c", &hdr_value ); 1632 if( status != PARSE_OK ) { 1633 // pushback tokens; useful only on INCOMPLETE error 1634 scanner->cursor = save_pos; 1635 return status; 1636 } 1637 // 1638 // add header 1639 // 1640 1641 // find header 1642 index_1 = map_str_to_int( token_1.buf, token_1.length, Http_Header_Names, 1643 NUM_HTTP_HEADER_NAMES, FALSE ); 1644 if( index_1 != -1 ) { 1645 1646 //Check if it is a soap header 1647 if( Http_Header_Names[index_1].id == HDR_SOAPACTION ) { 1648 parser->msg.method = SOAPMETHOD_POST; 1649 } 1650 1651 header_id = Http_Header_Names[index_1].id; 1652 orig_header = 1653 httpmsg_find_hdr( &parser->msg, header_id, NULL ); 1654 } else { 1655 header_id = HDR_UNKNOWN; 1656 1657 save_char = token_1.buf[token_1.length]; 1658 token_1.buf[token_1.length] = '\0'; 1659 1660 orig_header = httpmsg_find_hdr_str( &parser->msg, token_1.buf ); 1661 1662 token_1.buf[token_1.length] = save_char; // restore 1663 } 1664 1665 if( orig_header == NULL ) { 1666 // 1667 // add new header 1668 // 1669 1670 header = ( http_header_t * ) malloc( sizeof( http_header_t ) ); 1671 if( header == NULL ) { 1672 parser->http_error_code = HTTP_INTERNAL_SERVER_ERROR; 1673 return PARSE_FAILURE; 1674 } 1675 membuffer_init( &header->name_buf ); 1676 membuffer_init( &header->value ); 1677 1678 // value can be 0 length 1679 if( hdr_value.length == 0 ) { 1680 hdr_value.buf = "\0"; 1681 hdr_value.length = 1; 1682 } 1683 // save in header in buffers 1684 if( membuffer_assign 1685 ( &header->name_buf, token_1.buf, token_1.length ) != 0 1686 || membuffer_assign( &header->value, hdr_value.buf, 1687 hdr_value.length ) != 0 ) { 1688 // not enuf mem 1689 parser->http_error_code = HTTP_INTERNAL_SERVER_ERROR; 1690 return PARSE_FAILURE; 1691 } 1692 1693 header->name.buf = header->name_buf.buf; 1694 header->name.length = header->name_buf.length; 1695 header->name_id = header_id; 1696 1697 ListAddTail( &parser->msg.headers, header ); 1698 1699 //NNS: ret = dlist_append( &parser->msg.headers, header ); 1700 if( ret == UPNP_E_OUTOF_MEMORY ) { 1701 parser->http_error_code = HTTP_INTERNAL_SERVER_ERROR; 1702 return PARSE_FAILURE; 1703 } 1704 } else if( hdr_value.length > 0 ) { 1705 // 1706 // append value to existing header 1707 // 1708 1709 // append space 1710 ret = membuffer_append_str( &orig_header->value, ", " ); 1711 1712 // append continuation of header value 1713 ret2 = membuffer_append( &orig_header->value, 1714 hdr_value.buf, hdr_value.length ); 1715 1716 if( ret == UPNP_E_OUTOF_MEMORY || ret2 == UPNP_E_OUTOF_MEMORY ) { 1717 // not enuf mem 1718 parser->http_error_code = HTTP_INTERNAL_SERVER_ERROR; 1719 return PARSE_FAILURE; 1720 } 1721 } 1722 } // end while 1723 1724} 1725 1726//////////////////////////////////////////////////////////////////////// 1727#ifdef HIGHLY_UNLIKELY 1728// ************** 1729static parse_status_t 1730parser_parse_headers_old( INOUT http_parser_t * parser ) 1731{ 1732 parse_status_t status; 1733 memptr token_1; 1734 memptr hdr_value; 1735 token_type_t tok_type; 1736 scanner_t *scanner = &parser->scanner; 1737 size_t save_pos; 1738 http_header_t *header; 1739 int header_id; 1740 int ret = 0; 1741 int index_1; 1742 http_header_t *orig_header; 1743 char save_char; 1744 int ret2, 1745 ret3; 1746 1747 assert( parser->position == POS_HEADERS || 1748 parser->ent_position == ENTREAD_CHUNKY_HEADERS ); 1749 1750 while( TRUE ) { 1751 save_pos = scanner->cursor; 1752 1753 // 1754 // check end of headers 1755 // 1756 status = scanner_get_token( scanner, &token_1, &tok_type ); 1757 if( status != PARSE_OK ) { 1758 return status; 1759 } 1760 1761 if( tok_type == TT_CRLF ) { 1762 // end of headers 1763 parser->position = POS_ENTITY; // read entity next 1764 return PARSE_OK; 1765 } 1766 // 1767 // not end; read header 1768 // 1769 if( tok_type != TT_IDENTIFIER ) { 1770 return PARSE_FAILURE; // didn't see header name 1771 } 1772 1773 status = match( scanner, " : %R%c", &hdr_value ); 1774 if( status != PARSE_OK ) { 1775 // pushback tokens; useful only on INCOMPLETE error 1776 scanner->cursor = save_pos; 1777 return status; 1778 } 1779 1780 // 1781 // add header 1782 // 1783 1784 // find header 1785 index_1 = map_str_to_int( token_1.buf, token_1.length, Http_Header_Names, 1786 NUM_HTTP_HEADER_NAMES, FALSE ); 1787 if( index_1 != -1 ) { 1788 header_id = Http_Header_Names[index_1].id; 1789 1790 orig_header = 1791 httpmsg_find_hdr( &parser->msg, header_id, NULL ); 1792 } else { 1793 header_id = HDR_UNKNOWN; 1794 1795 save_char = token_1.buf[token_1.length]; 1796 token_1.buf[token_1.length] = '\0'; 1797 1798 orig_header = httpmsg_find_hdr_str( &parser->msg, token_1.buf ); 1799 1800 token_1.buf[token_1.length] = save_char; // restore 1801 } 1802 1803 if( orig_header == NULL ) { 1804 // 1805 // add new header 1806 // 1807 1808 header = ( http_header_t * ) malloc( sizeof( http_header_t ) ); 1809 if( header == NULL ) { 1810 parser->http_error_code = HTTP_INTERNAL_SERVER_ERROR; 1811 return PARSE_FAILURE; 1812 } 1813 membuffer_init( &header->multi_hdr_buf ); 1814 1815 header->name = token_1; 1816 header->value = hdr_value; 1817 header->name_id = header_id; 1818 1819 ret = dlist_append( &parser->msg.headers, header ); 1820 if( ret == UPNP_E_OUTOF_MEMORY ) { 1821 parser->http_error_code = HTTP_INTERNAL_SERVER_ERROR; 1822 return PARSE_FAILURE; 1823 } 1824 } else if( hdr_value.length > 0 ) { 1825 // 1826 // append value to existing header 1827 // 1828 1829 if( orig_header->multi_hdr_buf.buf == NULL ) { 1830 // store in buffer 1831 ret = membuffer_append( &orig_header->multi_hdr_buf, 1832 orig_header->value.buf, 1833 orig_header->value.length ); 1834 } 1835 // append space 1836 ret2 = 1837 membuffer_append( &orig_header->multi_hdr_buf, ", ", 2 ); 1838 1839 // append continuation of header value 1840 ret3 = membuffer_append( &orig_header->multi_hdr_buf, 1841 hdr_value.buf, hdr_value.length ); 1842 1843 if( ret == UPNP_E_OUTOF_MEMORY || 1844 ret2 == UPNP_E_OUTOF_MEMORY || 1845 ret3 == UPNP_E_OUTOF_MEMORY ) { 1846 // not enuf mem 1847 parser->http_error_code = HTTP_INTERNAL_SERVER_ERROR; 1848 return PARSE_FAILURE; 1849 } 1850 // header value points to allocated buf 1851 orig_header->value.buf = orig_header->multi_hdr_buf.buf; 1852 orig_header->value.length = orig_header->multi_hdr_buf.length; 1853 } 1854 } // end while 1855 1856} 1857#endif 1858// ****************************** 1859 1860/************************************************************************ 1861* Function: parser_parse_entity_using_clen 1862* 1863* Parameters: 1864* INOUT http_parser_t* parser ; HTTP Parser object 1865* 1866* Description: reads entity using content-length 1867* 1868* Returns: 1869* PARSE_INCOMPLETE 1870* PARSE_FAILURE -- entity length > content-length value 1871* PARSE_SUCCESS 1872************************************************************************/ 1873static XINLINE parse_status_t 1874parser_parse_entity_using_clen( INOUT http_parser_t * parser ) 1875{ 1876 //int entity_length; 1877 1878 assert( parser->ent_position == ENTREAD_USING_CLEN ); 1879 1880 // determine entity (i.e. body) length so far 1881 //entity_length = parser->msg.msg.length - parser->entity_start_position; 1882 parser->msg.entity.length = 1883 parser->msg.msg.length - parser->entity_start_position; 1884 1885 if( parser->msg.entity.length < parser->content_length ) { 1886 // more data to be read 1887 return PARSE_INCOMPLETE; 1888 } else { 1889 if( parser->msg.entity.length > parser->content_length ) { 1890 // silently discard extra data 1891 parser->msg.msg.buf[parser->entity_start_position + 1892 parser->content_length] = '\0'; 1893 } 1894 // save entity length 1895 parser->msg.entity.length = parser->content_length; 1896 1897 // save entity start ptr; (the very last thing to do) 1898 parser->msg.entity.buf = parser->msg.msg.buf + 1899 parser->entity_start_position; 1900 1901 // done reading entity 1902 parser->position = POS_COMPLETE; 1903 return PARSE_SUCCESS; 1904 } 1905} 1906 1907/************************************************************************ 1908* Function: parser_parse_chunky_body 1909* 1910* Parameters: 1911* INOUT http_parser_t* parser ; HTTP Parser object 1912* 1913* Description: Read data in the chunks 1914* 1915* Returns: 1916* PARSE_INCOMPLETE 1917* PARSE_FAILURE -- entity length > content-length value 1918* PARSE_SUCCESS 1919************************************************************************/ 1920static XINLINE parse_status_t 1921parser_parse_chunky_body( INOUT http_parser_t * parser ) 1922{ 1923 parse_status_t status; 1924 size_t save_pos; 1925 1926 // if 'chunk_size' of bytes have been read; read next chunk 1927 if( ( int )( parser->msg.msg.length - parser->scanner.cursor ) >= 1928 parser->chunk_size ) { 1929 // move to next chunk 1930 parser->scanner.cursor += parser->chunk_size; 1931 save_pos = parser->scanner.cursor; 1932 1933 //discard CRLF 1934 status = match( &parser->scanner, "%c" ); 1935 if( status != PARSE_OK ) { 1936 parser->scanner.cursor -= parser->chunk_size; //move back 1937 //parser->scanner.cursor = save_pos; 1938 return status; 1939 } 1940 1941 membuffer_delete( &parser->msg.msg, save_pos, 1942 ( parser->scanner.cursor - save_pos ) ); 1943 parser->scanner.cursor = save_pos; 1944 parser->msg.entity.length += parser->chunk_size; //update temp 1945 parser->ent_position = ENTREAD_USING_CHUNKED; 1946 return PARSE_CONTINUE_1; 1947 } else { 1948 return PARSE_INCOMPLETE; // need more data for chunk 1949 } 1950} 1951 1952/************************************************************************ 1953* Function: parser_parse_chunky_headers 1954* 1955* Parameters: 1956* INOUT http_parser_t* parser ; HTTP Parser object 1957* 1958* Description: Read headers at the end of the chunked entity 1959* 1960* Returns: 1961* PARSE_INCOMPLETE 1962* PARSE_FAILURE -- entity length > content-length value 1963* PARSE_SUCCESS 1964************************************************************************/ 1965static XINLINE parse_status_t 1966parser_parse_chunky_headers( INOUT http_parser_t * parser ) 1967{ 1968 parse_status_t status; 1969 size_t save_pos; 1970 1971 save_pos = parser->scanner.cursor; 1972 status = parser_parse_headers( parser ); 1973 if( status == PARSE_OK ) { 1974 // finally, done with the whole msg 1975 parser->position = POS_COMPLETE; 1976 1977 // save entity start ptr as the very last thing to do 1978 parser->msg.entity.buf = parser->msg.msg.buf + 1979 parser->entity_start_position; 1980 1981 membuffer_delete( &parser->msg.msg, save_pos, 1982 ( parser->scanner.cursor - save_pos ) ); 1983 parser->scanner.cursor = save_pos; 1984 1985 return PARSE_SUCCESS; 1986 } else { 1987 return status; 1988 } 1989} 1990 1991/************************************************************************ 1992* Function: parser_parse_chunky_entity 1993* 1994* Parameters: 1995* INOUT http_parser_t* parser - HTTP Parser Object 1996* 1997* Description: Read headers at the end of the chunked entity 1998* 1999* Returns: 2000* PARSE_INCOMPLETE 2001* PARSE_FAILURE -- entity length > content-length value 2002* PARSE_SUCCESS 2003* PARSE_CONTINUE_1 2004************************************************************************/ 2005static XINLINE parse_status_t 2006parser_parse_chunky_entity( INOUT http_parser_t * parser ) 2007{ 2008 scanner_t *scanner = &parser->scanner; 2009 parse_status_t status; 2010 size_t save_pos; 2011 memptr dummy; 2012 2013 assert( parser->ent_position == ENTREAD_USING_CHUNKED ); 2014 2015 save_pos = scanner->cursor; 2016 2017 // get size of chunk, discard extension, discard CRLF 2018 status = match( scanner, "%x%L%c", &parser->chunk_size, &dummy ); 2019 if( status != PARSE_OK ) { 2020 scanner->cursor = save_pos; 2021 DBGONLY( UpnpPrintf 2022 ( UPNP_INFO, HTTP, __FILE__, __LINE__, 2023 "CHUNK COULD NOT BE PARSED\n" ); ) 2024 return status; 2025 } 2026 // remove chunk info just matched; just retain data 2027 membuffer_delete( &parser->msg.msg, save_pos, 2028 ( scanner->cursor - save_pos ) ); 2029 scanner->cursor = save_pos; // adjust scanner too 2030 2031 if( parser->chunk_size == 0 ) { 2032 // done reading entity; determine length of entity 2033 parser->msg.entity.length = parser->scanner.cursor - 2034 parser->entity_start_position; 2035 2036 // read entity headers 2037 parser->ent_position = ENTREAD_CHUNKY_HEADERS; 2038 } else { 2039 // read chunk body 2040 parser->ent_position = ENTREAD_CHUNKY_BODY; 2041 } 2042 2043 return PARSE_CONTINUE_1; // continue to reading body 2044} 2045 2046/************************************************************************ 2047* Function: parser_parse_entity_until_close 2048* 2049* Parameters: 2050* INOUT http_parser_t* parser ; HTTP Parser object 2051* 2052* Description: Read headers at the end of the chunked entity 2053* 2054* Returns: 2055* PARSE_INCOMPLETE_ENTITY 2056************************************************************************/ 2057static XINLINE parse_status_t 2058parser_parse_entity_until_close( INOUT http_parser_t * parser ) 2059{ 2060 size_t cursor; 2061 2062 assert( parser->ent_position == ENTREAD_UNTIL_CLOSE ); 2063 2064 // eat any and all data 2065 cursor = parser->msg.msg.length; 2066 2067 // update entity length 2068 parser->msg.entity.length = cursor - parser->entity_start_position; 2069 2070 // update pointer 2071 parser->msg.entity.buf = 2072 parser->msg.msg.buf + parser->entity_start_position; 2073 2074 parser->scanner.cursor = cursor; 2075 2076 return PARSE_INCOMPLETE_ENTITY; // add anything 2077} 2078 2079/************************************************************************ 2080* Function: parser_get_entity_read_method 2081* 2082* Parameters: 2083* INOUT http_parser_t* parser ; HTTP Parser object 2084* 2085* Description: Determines method to read entity 2086* 2087* Returns: 2088* PARSE_OK 2089* PARSE_FAILURE 2090* PARSE_COMPLETE -- no more reading to do 2091************************************************************************/ 2092XINLINE parse_status_t 2093parser_get_entity_read_method( INOUT http_parser_t * parser ) 2094{ 2095 http_message_t *hmsg = &parser->msg; 2096 int response_code; 2097 memptr hdr_value; 2098 2099 assert( parser->ent_position == ENTREAD_DETERMINE_READ_METHOD ); 2100 2101 // entity points to start of msg body 2102 parser->msg.entity.buf = scanner_get_str( &parser->scanner ); 2103 parser->msg.entity.length = 0; 2104 2105 // remember start of body 2106 parser->entity_start_position = parser->scanner.cursor; 2107 2108 // std http rules for determining content length 2109 2110 // * no body for 1xx, 204, 304 and HEAD, GET, 2111 // SUBSCRIBE, UNSUBSCRIBE 2112 if( hmsg->is_request ) { 2113 switch ( hmsg->method ) { 2114 case HTTPMETHOD_HEAD: 2115 case HTTPMETHOD_GET: 2116 //case HTTPMETHOD_POST: 2117 case HTTPMETHOD_SUBSCRIBE: 2118 case HTTPMETHOD_UNSUBSCRIBE: 2119 case HTTPMETHOD_MSEARCH: 2120 // no body; mark as done 2121 parser->position = POS_COMPLETE; 2122 return PARSE_SUCCESS; 2123 break; 2124 2125 default: 2126 ; // do nothing 2127 } 2128 } else // response 2129 { 2130 response_code = hmsg->status_code; 2131 2132 if( response_code == 204 || 2133 response_code == 304 || 2134 ( response_code >= 100 && response_code <= 199 ) || 2135 hmsg->request_method == HTTPMETHOD_HEAD || 2136 hmsg->request_method == HTTPMETHOD_MSEARCH || 2137 hmsg->request_method == HTTPMETHOD_SUBSCRIBE || 2138 hmsg->request_method == HTTPMETHOD_UNSUBSCRIBE || 2139 hmsg->request_method == HTTPMETHOD_NOTIFY ) { 2140 parser->position = POS_COMPLETE; 2141 return PARSE_SUCCESS; 2142 } 2143 } 2144 2145 // * transfer-encoding -- used to indicate chunked data 2146 if( httpmsg_find_hdr( hmsg, HDR_TRANSFER_ENCODING, &hdr_value ) ) { 2147 if( raw_find_str( &hdr_value, "chunked" ) >= 0 ) { 2148 // read method to use chunked transfer encoding 2149 parser->ent_position = ENTREAD_USING_CHUNKED; 2150 DBGONLY( UpnpPrintf 2151 ( UPNP_INFO, HTTP, __FILE__, __LINE__, 2152 "Found Chunked Encoding ....\n" ); ) 2153 2154 return PARSE_CONTINUE_1; 2155 } 2156 } 2157 // * use content length 2158 if( httpmsg_find_hdr( hmsg, HDR_CONTENT_LENGTH, &hdr_value ) ) { 2159 parser->content_length = raw_to_int( &hdr_value, 10 ); 2160 if( parser->content_length < 0 ) { 2161 // bad content-length 2162 return PARSE_FAILURE; 2163 } 2164 parser->ent_position = ENTREAD_USING_CLEN; 2165 return PARSE_CONTINUE_1; 2166 } 2167 // * multi-part/byteranges not supported (yet) 2168 2169 // * read until connection is closed 2170 if( hmsg->is_request ) { 2171 // set hack flag for NOTIFY methods; if set to true this is 2172 // a valid SSDP notify msg 2173 if( hmsg->method == HTTPMETHOD_NOTIFY ) { 2174 parser->valid_ssdp_notify_hack = TRUE; 2175 } 2176 2177 parser->http_error_code = HTTP_LENGTH_REQUIRED; 2178 return PARSE_FAILURE; 2179 } 2180 2181 parser->ent_position = ENTREAD_UNTIL_CLOSE; 2182 return PARSE_CONTINUE_1; 2183} 2184 2185/************************************************************************ 2186* Function: parser_parse_entity 2187* 2188* Parameters: 2189* INOUT http_parser_t* parser ; HTTP Parser object 2190* 2191* Description: Determines method to read entity 2192* 2193* Returns: 2194* PARSE_OK 2195* PARSE_FAILURE 2196* PARSE_COMPLETE -- no more reading to do 2197************************************************************************/ 2198XINLINE parse_status_t 2199parser_parse_entity( INOUT http_parser_t * parser ) 2200{ 2201 parse_status_t status = PARSE_OK; 2202 2203 assert( parser->position == POS_ENTITY ); 2204 2205 do { 2206 switch ( parser->ent_position ) { 2207 case ENTREAD_USING_CLEN: 2208 status = parser_parse_entity_using_clen( parser ); 2209 break; 2210 2211 case ENTREAD_USING_CHUNKED: 2212 status = parser_parse_chunky_entity( parser ); 2213 break; 2214 2215 case ENTREAD_CHUNKY_BODY: 2216 status = parser_parse_chunky_body( parser ); 2217 break; 2218 2219 case ENTREAD_CHUNKY_HEADERS: 2220 status = parser_parse_chunky_headers( parser ); 2221 break; 2222 2223 case ENTREAD_UNTIL_CLOSE: 2224 status = parser_parse_entity_until_close( parser ); 2225 break; 2226 2227 case ENTREAD_DETERMINE_READ_METHOD: 2228 status = parser_get_entity_read_method( parser ); 2229 break; 2230 2231 default: 2232 assert( 0 ); 2233 } 2234 2235 } while( status == PARSE_CONTINUE_1 ); 2236 2237 return status; 2238} 2239 2240/************************************************************************ 2241* Function: parser_request_init 2242* 2243* Parameters: 2244* OUT http_parser_t* parser ; HTTP Parser object 2245* 2246* Description: Initializes parser object for a request 2247* 2248* Returns: 2249* void 2250************************************************************************/ 2251void 2252parser_request_init( OUT http_parser_t * parser ) 2253{ 2254 parser_init( parser ); 2255 parser->msg.is_request = TRUE; 2256 parser->position = POS_REQUEST_LINE; 2257} 2258 2259/************************************************************************ 2260* Function: parser_response_init 2261* 2262* Parameters: 2263* OUT http_parser_t* parser ; HTTP Parser object 2264* IN http_method_t request_method ; Request method 2265* 2266* Description: Initializes parser object for a response 2267* 2268* Returns: 2269* void 2270************************************************************************/ 2271void 2272parser_response_init( OUT http_parser_t * parser, 2273 IN http_method_t request_method ) 2274{ 2275 parser_init( parser ); 2276 parser->msg.is_request = FALSE; 2277 parser->msg.request_method = request_method; 2278 parser->position = POS_RESPONSE_LINE; 2279} 2280 2281/************************************************************************ 2282* Function: parser_parse 2283* 2284* Parameters: 2285* INOUT http_parser_t* parser ; HTTP Parser object 2286* 2287* Description: The parser function. Depending on the position of the 2288* parser object the actual parsing function is invoked 2289* 2290* Returns: 2291* void 2292************************************************************************/ 2293parse_status_t 2294parser_parse( INOUT http_parser_t * parser ) 2295{ 2296 parse_status_t status; 2297 2298 //takes an http_parser_t with memory already allocated 2299 //in the message 2300 assert( parser != NULL ); 2301 2302 do { 2303 switch ( parser->position ) { 2304 case POS_ENTITY: 2305 status = parser_parse_entity( parser ); 2306 2307 break; 2308 2309 case POS_HEADERS: 2310 status = parser_parse_headers( parser ); 2311 2312 break; 2313 2314 case POS_REQUEST_LINE: 2315 status = parser_parse_requestline( parser ); 2316 2317 break; 2318 2319 case POS_RESPONSE_LINE: 2320 status = parser_parse_responseline( parser ); 2321 2322 break; 2323 2324 default: 2325 { 2326 status = PARSE_FAILURE; 2327 assert( 0 ); 2328 } 2329 } 2330 2331 } while( status == PARSE_OK ); 2332 2333 return status; 2334 2335} 2336 2337/************************************************************************ 2338* Function: parser_append 2339* 2340* Parameters: 2341* INOUT http_parser_t* parser ; HTTP Parser Object 2342* IN const char* buf ; buffer to be appended to the parser 2343* buffer 2344* IN size_t buf_length ; Size of the buffer 2345* 2346* Description: The parser function. Depending on the position of the 2347* parser object the actual parsing function is invoked 2348* 2349* Returns: 2350* void 2351************************************************************************/ 2352parse_status_t 2353parser_append( INOUT http_parser_t * parser, 2354 IN const char *buf, 2355 IN size_t buf_length ) 2356{ 2357 int ret_code; 2358 2359 assert( parser != NULL ); 2360 assert( buf != NULL ); 2361 2362 // append data to buffer 2363 ret_code = membuffer_append( &parser->msg.msg, buf, buf_length ); 2364 if( ret_code != 0 ) { 2365 // set failure status 2366 parser->http_error_code = HTTP_INTERNAL_SERVER_ERROR; 2367 return PARSE_FAILURE; 2368 } 2369 2370 return parser_parse( parser ); 2371} 2372 2373/************************************************************************ 2374********** end of parser *********** 2375************************************************************************/ 2376 2377/************************************************************************ 2378* Function: raw_to_int 2379* 2380* Parameters: 2381* IN memptr* raw_value ; Buffer to be converted 2382* IN int base ; Base to use for conversion 2383* 2384* Description: Converts raw character data to long-integer value 2385* 2386* Returns: 2387* int 2388************************************************************************/ 2389int 2390raw_to_int( IN memptr * raw_value, 2391 IN int base ) 2392{ 2393 int num; 2394 char *end_ptr; 2395 2396 if( raw_value->length == 0 ) { 2397 return -1; 2398 } 2399 2400 errno = 0; 2401 num = strtol( raw_value->buf, &end_ptr, base ); 2402 if( ( num < 0 ) 2403 // all and only those chars in token should be used for num 2404 || ( end_ptr != raw_value->buf + raw_value->length ) 2405 || ( ( num == LONG_MIN || num == LONG_MAX ) 2406 && ( errno == ERANGE ) ) 2407 ) { 2408 return -1; 2409 } 2410 return num; 2411 2412} 2413 2414/************************************************************************ 2415* Function: raw_find_str 2416* 2417* Parameters: 2418* IN memptr* raw_value ; Buffer containg the string 2419* IN const char* str ; Substring to be found 2420* 2421* Description: Find a substring from raw character string buffer 2422* 2423* Returns: 2424* int - index at which the substring is found. 2425************************************************************************/ 2426int 2427raw_find_str( IN memptr * raw_value, 2428 IN const char *str ) 2429{ 2430 char c; 2431 char *ptr; 2432 2433 c = raw_value->buf[raw_value->length]; // save 2434 raw_value->buf[raw_value->length] = 0; // null-terminate 2435 2436 ptr = strstr( raw_value->buf, str ); 2437 2438 raw_value->buf[raw_value->length] = c; // restore 2439 2440 if( ptr == 0 ) { 2441 return -1; 2442 } 2443 2444 return ptr - raw_value->buf; // return index 2445} 2446 2447/************************************************************************ 2448* Function: method_to_str 2449* 2450* Parameters: 2451* IN http_method_t method ; HTTP method 2452* 2453* Description: A wrapper function that maps a method id to a method 2454* nameConverts a http_method id stored in the HTTP Method 2455* 2456* Returns: 2457* const char* ptr - Ptr to the HTTP Method * 2458************************************************************************/ 2459const char * 2460method_to_str( IN http_method_t method ) 2461{ 2462 int index; 2463 2464 index = map_int_to_str( method, Http_Method_Table, NUM_HTTP_METHODS ); 2465 2466 assert( index != -1 ); 2467 2468 return index == -1 ? NULL : Http_Method_Table[index].name; 2469} 2470 2471/************************************************************************ 2472* Function: print_http_headers 2473* 2474* Parameters: 2475* http_message_t* hmsg ; HTTP Message object 2476* 2477* Description: 2478* 2479* Returns: 2480* void 2481************************************************************************/ 2482void 2483print_http_headers( http_message_t * hmsg ) 2484{ 2485 2486 ListNode *node; 2487 2488 //NNS: dlist_node *node; 2489 http_header_t *header; 2490 2491 // print start line 2492 if( hmsg->is_request ) { 2493 //printf( "method = %d, version = %d.%d, url = %.*s\n", 2494 // hmsg->method, hmsg->major_version, hmsg->minor_version, 2495 // hmsg->uri.pathquery.size, hmsg->uri.pathquery.buff); 2496 } else { 2497 // printf( "resp status = %d, version = %d.%d, status msg = %.*s\n", 2498 // hmsg->status_code, hmsg->major_version, hmsg->minor_version, 2499 // (int)hmsg->status_msg.length, hmsg->status_msg.buf); 2500 } 2501 2502 // print headers 2503 2504 node = ListHead( &hmsg->headers ); 2505 //NNS: node = dlist_first_node( &hmsg->headers ); 2506 while( node != NULL ) { 2507 2508 header = ( http_header_t * ) node->item; 2509 //NNS: header = (http_header_t *)node->data; 2510 //printf( "hdr name: %.*s, value: %.*s\n", 2511 // (int)header->name.length, header->name.buf, 2512 // (int)header->value.length, header->value.buf ); 2513 2514 node = ListNext( &hmsg->headers, node ); 2515 2516 //NNS: node = dlist_next( &hmsg->headers, node ); 2517 } 2518} 2519