1 /* ------------------------------------------------------------------ 2 * Copyright (C) 1998-2009 PacketVideo 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 13 * express or implied. 14 * See the License for the specific language governing permissions 15 * and limitations under the License. 16 * ------------------------------------------------------------------- 17 */ 18 #include "http_parser.h" 19 #include "http_parser_internal.h" 20 #include "oscl_string_utils.h" 21 #include "oscl_string_containers.h" 22 23 // Use default DLL entry point for Symbian 24 #include "oscl_dll.h" 25 26 OSCL_DLL_ENTRY_POINT_DEFAULT() 27 28 29 // three inline functions for multiple class implementation 30 inline bool isLetter(const char c) 31 { 32 return ((c >= 65 && c <= 90) || (c >= 97 && c <= 122) || (c == 45)); // A-Z, or a-z or - 33 } 34 35 inline bool isDigit(const char c) 36 { 37 return (c >= 48 && c <= 57); 38 } 39 40 inline bool isHexDigit(const char c) 41 { 42 return (isDigit(c) || (c >= 65 && c <= 70) || (c >= 97 && c <= 102)); // 0-9, A-F or a-f 43 } 44 45 46 //////////////////////////////////////////////////////////////////////////////////// 47 ////// HTTPParser implementation /////////////////////////////////////////////////// 48 //////////////////////////////////////////////////////////////////////////////////// 49 50 OSCL_EXPORT_REF int32 HTTPParser::parse(const OsclRefCounterMemFrag &aInputDataStream, RefCountHTTPEntityUnit &aEntityUnit) 51 { 52 if (!iParserInput->push_back((OsclRefCounterMemFrag &)aInputDataStream)) // not a new data fragment 53 return PARSE_NEED_MORE_DATA; 54 55 if (!aEntityUnit.empty()) aEntityUnit.clear(); 56 if (!iHeader->isParsed()) return iHeader->parse(*iParserInput, aEntityUnit); 57 58 return parseEntityBody(aEntityUnit); 59 } 60 61 //////////////////////////////////////////////////////////////////////////////////// 62 OSCL_EXPORT_REF int32 HTTPParser::doSanityCheckForResponseHeader() 63 { 64 if (!iHeader->isParsed()) return PARSE_HEADER_NOT_PARSED_YET; 65 return iHeader->doSanityCheckForResponseHeader(); 66 } 67 68 69 //////////////////////////////////////////////////////////////////////////////////// 70 // assume aFieldKeyList has enough space to hold all parsed key list, if it is small, it will cause crash 71 // since we have no way to check the space 72 OSCL_EXPORT_REF uint32 HTTPParser::getFieldKeyListInHeader(StrPtrLen *&aFieldKeyList) 73 { 74 return iHeader->getKeyValuesStore()->getCurrentKeyList(aFieldKeyList); // iHeader should be created successfully in factory method 75 } 76 77 //////////////////////////////////////////////////////////////////////////////////// 78 OSCL_EXPORT_REF bool HTTPParser::getField(const StrCSumPtrLen &aNewFieldName, StrPtrLen &aNewFieldValue, uint32 index) 79 { 80 return iHeader->getField(aNewFieldName, aNewFieldValue, index); 81 } 82 83 //////////////////////////////////////////////////////////////////////////////////// 84 OSCL_EXPORT_REF uint32 HTTPParser::getNumberOfFieldsByKey(const StrCSumPtrLen &aNewFieldName) 85 { 86 return iHeader->getNumberOfFieldsByKey(aNewFieldName); 87 } 88 89 //////////////////////////////////////////////////////////////////////////////////// 90 OSCL_EXPORT_REF uint32 HTTPParser::getTotalFieldsInHeader() 91 { 92 return iHeader->getNumFields(); 93 } 94 95 //////////////////////////////////////////////////////////////////////////////////// 96 OSCL_EXPORT_REF uint32 HTTPParser::getHTTPStatusCode() 97 { 98 return iHeader->getStatusCode(); 99 } 100 101 //////////////////////////////////////////////////////////////////////////////////// 102 OSCL_EXPORT_REF void HTTPParser::getContentInfo(HTTPContentInfo &aContentInfo) 103 { 104 aContentInfo.clear(); 105 if (iContentInfo) iContentInfo->get(aContentInfo); 106 } 107 108 109 //////////////////////////////////////////////////////////////////////////////////// 110 // reset the parser to parse a new HTTP response 111 OSCL_EXPORT_REF void HTTPParser::reset() 112 { 113 if (iParserInput) iParserInput->clear(); 114 if (iContentInfo) iContentInfo->clear(); 115 if (iHeader) iHeader->reset(); 116 117 // delete iEntityBody 118 if (iEntityBody) OSCL_DELETE(iEntityBody); 119 iEntityBody = NULL; 120 } 121 122 //////////////////////////////////////////////////////////////////////////////////// 123 // factory method 124 OSCL_EXPORT_REF HTTPParser* HTTPParser::create() 125 { 126 HTTPParser *parser = OSCL_NEW(HTTPParser, ()); 127 if (!parser) return NULL; 128 if (!parser->construct()) 129 { 130 OSCL_DELETE(parser); 131 return NULL; 132 } 133 return parser; 134 } 135 136 //////////////////////////////////////////////////////////////////////////////////// 137 bool HTTPParser::construct() 138 { 139 reset(); 140 141 // create the component objects 142 if ((iContentInfo = OSCL_NEW(HTTPContentInfoInternal, ())) == NULL) return false; 143 if ((iParserInput = HTTPParserInput::create()) == NULL) return false; 144 if ((iHeader = HTTPParserHeaderObject::create(iContentInfo)) == NULL) return false; 145 return true; 146 } 147 148 //////////////////////////////////////////////////////////////////////////////////// 149 // destructor 150 OSCL_EXPORT_REF HTTPParser::~HTTPParser() 151 { 152 reset(); 153 154 // delete iParserInput 155 if (iParserInput) OSCL_DELETE(iParserInput); 156 iParserInput = NULL; 157 158 // delete iContentInfo 159 if (iContentInfo) OSCL_DELETE(iContentInfo); 160 iContentInfo = NULL; 161 162 // delete iHeader 163 if (iHeader) OSCL_DELETE(iHeader); 164 iHeader = NULL; 165 166 // delete iEntityBody 167 if (iEntityBody) OSCL_DELETE(iEntityBody); 168 iEntityBody = NULL; 169 } 170 171 //////////////////////////////////////////////////////////////////////////////////// 172 int32 HTTPParser::parseEntityBody(RefCountHTTPEntityUnit &aEntityUnit) 173 { 174 if (!iHeader || !iHeader->isParsed()) return PARSE_HEADER_NOT_PARSED_YET; 175 if (iHeader->isWholeResponseParsed()) return PARSE_SUCCESS_END_OF_MESSAGE; 176 177 if (!iEntityBody) 178 { 179 // create iEntityBody 180 // After parsing the header, we should get right content type, iContentType 181 if (iContentInfo->getContentType() == HTTP_CONTENT_NORMAL) 182 iEntityBody = OSCL_NEW(HTTPParserNormalContentObject, (iHeader->getKeyValuesStore(), iHeader->getAllocator(), iContentInfo)); 183 else if (iContentInfo->getContentType() == HTTP_CONTENT_NULTIPART) 184 iEntityBody = OSCL_NEW(HTTPParserMultipartContentObject, (iHeader->getKeyValuesStore(), iHeader->getAllocator(), iContentInfo)); 185 else if (iContentInfo->getContentType() == HTTP_CONTENT_CHUNKED_TRANSFER_ENCODING) 186 iEntityBody = OSCL_NEW(HTTPParserCTEContentObject, (iHeader->getKeyValuesStore(), iHeader->getAllocator(), iContentInfo)); 187 188 if (!iEntityBody) return PARSE_MEMORY_ALLOCATION_FAILURE; 189 } 190 191 return iEntityBody->parse(*iParserInput, aEntityUnit); 192 } 193 194 195 ///////////////////////////////////////////////////////////////////////////////////// 196 ////////// HTTPContentInfoInternal Implementation /////////////////////////////////////////// 197 ///////////////////////////////////////////////////////////////////////////////////// 198 bool HTTPContentInfoInternal::parseContentInfo(StringKeyValueStore &aKeyValueStore) 199 { 200 // Content-Length 201 StrCSumPtrLen contenLengthKey("Content-Length"); 202 StrPtrLen contentLengthValue; 203 if (aKeyValueStore.getValueByKey(contenLengthKey, contentLengthValue)) 204 { 205 // has content length 206 PV_atoi(contentLengthValue.c_str(), 'd', iContentLength); 207 } 208 209 // Content-Type 210 StrCSumPtrLen contentTypeKey("Content-Type"); 211 StrPtrLen contentTypeValue; 212 if (aKeyValueStore.getValueByKey(contentTypeKey, contentTypeValue)) 213 { 214 // has content type 215 if (!parseContentType(contentTypeValue)) return false; 216 } 217 218 // Content-Range 219 StrCSumPtrLen contentRangeKey("Content-Range"); 220 StrPtrLen contentRangeValue; 221 if (aKeyValueStore.getValueByKey(contentRangeKey, contentRangeValue)) 222 { 223 // has content type 224 parseContentRange(contentRangeValue); 225 } 226 227 // check Chunked Transfer-Encoding, "Transfer-Encoding : chunked" 228 StrCSumPtrLen transferEncodingKey("Transfer-Encoding"); 229 StrPtrLen transferEncodingValue; 230 if (aKeyValueStore.getValueByKey(transferEncodingKey, transferEncodingValue)) 231 { 232 // has content type 233 verifyTransferEncoding(transferEncodingValue); 234 } 235 return true; 236 } 237 238 ///////////////////////////////////////////////////////////////////////////////////// 239 void HTTPContentInfoInternal::parseContentRange(const StrPtrLen &aContentRange) 240 { 241 char *ptr = (char *)aContentRange.c_str(); 242 uint32 len = aContentRange.length(); 243 244 while (!isLetter(*ptr) && len > 0) 245 { 246 ptr++; 247 len--; 248 } 249 OSCL_FastString bytesString(_STRLIT_CHAR("bytes")); 250 if (len <= oscl_strlen(bytesString.get_cstr())) return; 251 252 if (((ptr[0] | OSCL_ASCII_CASE_MAGIC_BIT) == 'b') && 253 ((ptr[1] | OSCL_ASCII_CASE_MAGIC_BIT) == 'y') && 254 ((ptr[2] | OSCL_ASCII_CASE_MAGIC_BIT) == 't') && 255 ((ptr[3] | OSCL_ASCII_CASE_MAGIC_BIT) == 'e') && 256 ((ptr[4] | OSCL_ASCII_CASE_MAGIC_BIT) == 's')) 257 { 258 // find "bytes" 259 ptr += 5; 260 if ((len -= 5) <= 0) return; 261 262 // get the left side of the range 263 while (!isDigit(*ptr) && len > 0) 264 { 265 ptr++; 266 len--; 267 } 268 char *start_ptr = ptr; 269 uint32 start_len = len; 270 while (isDigit(*ptr) && len > 0) 271 { 272 ptr++; 273 len--; 274 } 275 PV_atoi(start_ptr, 'd', start_len - len, iContentRangeLeft); 276 277 // get the right side of the range 278 while (!isDigit(*ptr) && len > 0) 279 { 280 ptr++; 281 len--; 282 } 283 start_ptr = ptr; 284 start_len = len; 285 while (isDigit(*ptr) && len > 0) 286 { 287 ptr++; 288 len--; 289 } 290 PV_atoi(start_ptr, 'd', start_len - len, iContentRangeRight); 291 292 // get the content length 293 while (!isDigit(*ptr) && len > 0) 294 { 295 ptr++; 296 len--; 297 } 298 start_ptr = ptr; 299 start_len = len; 300 while (isDigit(*ptr) && len > 0) 301 { 302 ptr++; 303 len--; 304 } 305 PV_atoi(start_ptr, 'd', start_len - len, iContentLength); 306 } 307 } 308 309 ///////////////////////////////////////////////////////////////////////////////////// 310 bool HTTPContentInfoInternal::parseContentType(const StrPtrLen &aContentType) 311 { 312 // identify multipart content type and chunked transfer-encoding 313 // Content-type: multipart/byteranges; boundary=THIS_STRING_SEPARATES 314 char *ptr = (char *)aContentType.c_str(); 315 uint32 len = aContentType.length(); 316 317 // eat non-letter characters 318 while (!isLetter(*ptr) && len > 0) 319 { 320 ptr++; 321 len--; 322 } 323 OSCL_FastString typeString(_STRLIT_CHAR("multipart/byteranges")); 324 if (len <= oscl_strlen(typeString.get_cstr())) return true; 325 326 if (((ptr[0] | OSCL_ASCII_CASE_MAGIC_BIT) == 'm') && 327 ((ptr[1] | OSCL_ASCII_CASE_MAGIC_BIT) == 'u') && 328 ((ptr[2] | OSCL_ASCII_CASE_MAGIC_BIT) == 'l') && 329 ((ptr[3] | OSCL_ASCII_CASE_MAGIC_BIT) == 't') && 330 ((ptr[4] | OSCL_ASCII_CASE_MAGIC_BIT) == 'i') && 331 ((ptr[5] | OSCL_ASCII_CASE_MAGIC_BIT) == 'p') && 332 ((ptr[6] | OSCL_ASCII_CASE_MAGIC_BIT) == 'a') && 333 ((ptr[7] | OSCL_ASCII_CASE_MAGIC_BIT) == 'r') && 334 ((ptr[8] | OSCL_ASCII_CASE_MAGIC_BIT) == 't') && 335 (ptr[9] == '/') && 336 ((ptr[10] | OSCL_ASCII_CASE_MAGIC_BIT) == 'b') && 337 ((ptr[11] | OSCL_ASCII_CASE_MAGIC_BIT) == 'y') && 338 ((ptr[12] | OSCL_ASCII_CASE_MAGIC_BIT) == 't') && 339 ((ptr[13] | OSCL_ASCII_CASE_MAGIC_BIT) == 'e') && 340 ((ptr[14] | OSCL_ASCII_CASE_MAGIC_BIT) == 'r') && 341 ((ptr[15] | OSCL_ASCII_CASE_MAGIC_BIT) == 'a') && 342 ((ptr[16] | OSCL_ASCII_CASE_MAGIC_BIT) == 'n') && 343 ((ptr[17] | OSCL_ASCII_CASE_MAGIC_BIT) == 'g') && 344 ((ptr[18] | OSCL_ASCII_CASE_MAGIC_BIT) == 'e') && 345 ((ptr[19] | OSCL_ASCII_CASE_MAGIC_BIT) == 's')) 346 { 347 // find "multipart/byteranges" 348 // constinue search "boundary" 349 ptr += 20; 350 if ((len -= 20) <= 8) return false; 351 352 while (!isLetter(*ptr) && len > 0) 353 { 354 ptr++; 355 len--; 356 } 357 if (((ptr[0] | OSCL_ASCII_CASE_MAGIC_BIT) == 'b') && 358 ((ptr[1] | OSCL_ASCII_CASE_MAGIC_BIT) == 'o') && 359 ((ptr[2] | OSCL_ASCII_CASE_MAGIC_BIT) == 'u') && 360 ((ptr[3] | OSCL_ASCII_CASE_MAGIC_BIT) == 'n') && 361 ((ptr[4] | OSCL_ASCII_CASE_MAGIC_BIT) == 'd') && 362 ((ptr[5] | OSCL_ASCII_CASE_MAGIC_BIT) == 'a') && 363 ((ptr[6] | OSCL_ASCII_CASE_MAGIC_BIT) == 'r') && 364 ((ptr[7] | OSCL_ASCII_CASE_MAGIC_BIT) == 'y')) 365 { 366 // find "boundary" 367 ptr += 8; 368 if ((len -= 8) <= 0) return false; 369 370 // find "=" 371 while (*ptr != HTTP_CHAR_EQUAL && len > 0) 372 { 373 ptr++; 374 len--; 375 } 376 if (len <= 0) return false; 377 ptr++; 378 379 while ((*ptr == HTTP_CHAR_SPACE || *ptr == HTTP_CHAR_TAB) && len > 0) 380 { 381 ptr++; 382 len--; 383 } 384 char *boundaryStartPtr = ptr; 385 uint32 start_len = (uint32)len; 386 while (!(*ptr == HTTP_CHAR_NULL || *ptr == HTTP_CHAR_SPACE || *ptr == HTTP_CHAR_TAB || 387 *ptr == HTTP_CHAR_CR || *ptr == HTTP_CHAR_LF) && len > 0) 388 { 389 ptr++; 390 len--; 391 } 392 iContentType = HTTP_CONTENT_NULTIPART; 393 return copyBoundaryString(boundaryStartPtr, start_len - (uint32)len); 394 } 395 } 396 return true; 397 } 398 399 ///////////////////////////////////////////////////////////////////////////////////// 400 void HTTPContentInfoInternal::verifyTransferEncoding(const StrPtrLen &aTransferEncodingValue) 401 { 402 char *ptr = (char *)aTransferEncodingValue.c_str(); 403 uint32 len = aTransferEncodingValue.length(); 404 405 // eat non-letter characters 406 while (!isLetter(*ptr) && len > 0) 407 { 408 ptr++; 409 len--; 410 } 411 OSCL_FastString chunkedString(_STRLIT_CHAR("chunked")); 412 if (len < oscl_strlen(chunkedString.get_cstr())) return; 413 414 if (((ptr[0] | OSCL_ASCII_CASE_MAGIC_BIT) == 'c') && 415 ((ptr[1] | OSCL_ASCII_CASE_MAGIC_BIT) == 'h') && 416 ((ptr[2] | OSCL_ASCII_CASE_MAGIC_BIT) == 'u') && 417 ((ptr[3] | OSCL_ASCII_CASE_MAGIC_BIT) == 'n') && 418 ((ptr[4] | OSCL_ASCII_CASE_MAGIC_BIT) == 'k') && 419 ((ptr[5] | OSCL_ASCII_CASE_MAGIC_BIT) == 'e') && 420 ((ptr[6] | OSCL_ASCII_CASE_MAGIC_BIT) == 'd')) 421 { 422 // find "chunked" 423 iContentType = HTTP_CONTENT_CHUNKED_TRANSFER_ENCODING; 424 } 425 } 426 427 bool HTTPContentInfoInternal::copyBoundaryString(const char* aBoundaryString, const uint32 aBoundaryStringLength) 428 { 429 // allocate memory for boundary string 430 if (!iBoundaryBuffer) iBoundaryBuffer = new char[aBoundaryStringLength+1]; 431 if (!iBoundaryBuffer) return false; 432 if (!aBoundaryString) return false; 433 434 oscl_memcpy(iBoundaryBuffer, aBoundaryString, aBoundaryStringLength); 435 iBoundaryBuffer[aBoundaryStringLength] = HTTP_CHAR_NULL; 436 iBoundary.setPtrLen(iBoundaryBuffer, aBoundaryStringLength); 437 return true; 438 } 439 440 //////////////////////////////////////////////////////////////////////////////////// 441 bool HTTPContentInfoInternal::parseBoudaryLine(HTTPMemoryFragment &aInputLineData, bool &isFinalBoundary) 442 { 443 isFinalBoundary = false; 444 445 // check boundary line : --BOUNDARY STRING 446 char *ptr = (char *)aInputLineData.getPtr(); 447 int32 len = aInputLineData.getAvailableSpace(); 448 while (*ptr != HTTP_CHAR_MINUS && len > 0) 449 { 450 ptr++; 451 len--; 452 } 453 if (len <= 0) return false; // this line is not boundary line 454 if (*(++ptr) != HTTP_CHAR_MINUS) return false; // not "--" 455 ptr++; 456 len -= 2; 457 if (len < iBoundary.length()) return false; 458 char *boundaryString = (char *)iBoundary.c_str(); 459 int32 i = 0; 460 for (i = 0; i < iBoundary.length(); i++) 461 { 462 if (ptr[i] != boundaryString[i]) return false; 463 } 464 465 // check the last "--" as the flag of final boundary string 466 ptr += iBoundary.length(); 467 len -= iBoundary.length(); 468 if (len >= 2) 469 { 470 if (*ptr == HTTP_CHAR_MINUS && *(ptr + 1) == HTTP_CHAR_MINUS) 471 { 472 isFinalBoundary = true; 473 } 474 } 475 return true; 476 } 477 478 479 ///////////////////////////////////////////////////////////////////////////////////// 480 ////////// HTTPParserInput Implementation /////////////////////////////////////////// 481 ///////////////////////////////////////////////////////////////////////////////////// 482 HTTPParserInput* HTTPParserInput::create() 483 { 484 HTTPParserInput *parserInput = OSCL_NEW(HTTPParserInput, ()); 485 if (!parserInput) return NULL; 486 if (!parserInput->construct()) 487 { 488 OSCL_DELETE(parserInput); 489 return NULL; 490 } 491 return parserInput; 492 } 493 494 bool HTTPParserInput::construct() 495 { 496 // create iLineBuffer 497 OsclMemAllocator alloc; 498 iLineBuffer = (char *)alloc.allocate(iLineBufferSize); 499 if (!iLineBuffer) return false; 500 501 int32 err = 0; 502 OSCL_TRY(err, 503 iDataInQueue.reserve(DATA_QUEUE_VECTOR_RESERVE_SIZE); 504 iDataOutQueue.reserve(DATA_QUEUE_VECTOR_RESERVE_SIZE); 505 ); 506 return (err == 0); 507 508 } 509 510 HTTPParserInput::~HTTPParserInput() 511 { 512 clear(); 513 iDataInQueue.clear(); 514 iDataOutQueue.clear(); 515 if (iLineBuffer) 516 { 517 OsclMemAllocator alloc; 518 alloc.deallocate(iLineBuffer); 519 iLineBuffer = NULL; 520 } 521 } 522 523 bool HTTPParserInput::push_back(OsclRefCounterMemFrag &aFrag) 524 { 525 if (!aFrag.getMemFragPtr() || !aFrag.getRefCounter()) // empty fragment 526 { 527 return (!iDataInQueue.empty()); // true for iDataInQueue not being empty 528 } 529 530 // check if this input is same to the previous one 531 if (!iDataInQueue.empty()) 532 { 533 if ((uint8*)aFrag.getMemFragPtr() == (uint8*)iDataInQueue[iDataInQueue.size()-1].getMemFragPtr()) 534 { 535 return true; // true for iDataInQueue not being empty 536 } 537 } 538 539 // push into the data queue 540 int32 err = 0; 541 OSCL_TRY(err, iDataInQueue.push_back(aFrag);); 542 if (err) return false; 543 544 return true; 545 } 546 547 ///////////////////////////////////////////////////////////////////////////////////// 548 bool HTTPParserInput::getNextCompleteLine(HTTPMemoryFragment &aHttpFrag, bool aHeaderParsed) 549 { 550 int32 offset = isNextLineAvailable(aHeaderParsed); 551 if (offset <= 0) return false; 552 aHttpFrag.bind(iHTTPMemFrag.getPtr(), offset); 553 return true; 554 } 555 556 // aRequestDataSize==0 means no request size, the function needs to send out whatever amount of data it has, 557 // but with one input data fragment each time. 558 // return value: actual size, if aRequestDataSize > 0, actual size <= aRequestDataSize 559 // actual size = 0, => no data, -1 means error 560 int32 HTTPParserInput::getData(HTTPMemoryFragment &aHttpFrag, const uint32 aRequestDataSize) 561 { 562 if (iDataInQueue.empty()) return 0; 563 564 uint32 requestSize = (aRequestDataSize > 0 ? aRequestDataSize : 0xffffffff); 565 uint32 availableFragSize = iDataInQueue[0].getMemFragSize() - iDataInQueueMemFragOffset; 566 uint32 actualSize = OSCL_MIN(requestSize, availableFragSize); 567 568 if (actualSize > 0) 569 { 570 // create the output fragments 571 uint8* fragStartPtr = (uint8*)iDataInQueue[0].getMemFragPtr() + iDataInQueueMemFragOffset; 572 aHttpFrag.bind((void *)fragStartPtr, actualSize); 573 if (!constructOutputFragment(actualSize, (void *)fragStartPtr, (iDataInQueueMemFragOffset == 0))) return -1; 574 } 575 576 // check if iDataInQueue[0] needs to be removed and update iDataInQueueMemFragOffset 577 if (availableFragSize <= requestSize) 578 { 579 iDataInQueue.erase(iDataInQueue.begin()); 580 iDataInQueueMemFragOffset = 0; 581 } 582 else 583 { 584 // updata iDataInQueueMemFragOffset 585 iDataInQueueMemFragOffset += actualSize; 586 } 587 588 return (int32)actualSize; 589 } 590 591 // This function is for parsing multipart content, specically for the final boundary string like --boundaryString--, which could 592 // has no "\r\n", so getNextCompleteLine may not work in this case 593 // In general, if iLineBuffer has data, then send out iLineBuffer, then check if input data queue has data, if it has, then send 594 // out the first buffer. Return false for no any data (both iLineBuffer and data queue are empty) 595 // Note that this function doesn't do "get" that means changing internal pointers, instead, only does "view" 596 bool HTTPParserInput::viewAvailableInputData(HTTPMemoryFragment &aHttpFrag) 597 { 598 if (iLineBufferOccupied == 0 && iDataInQueue.empty()) return false; 599 600 if (iLineBufferOccupied) 601 { 602 aHttpFrag.bind(iLineBuffer, iLineBufferOccupied); 603 } 604 else // iDataInQueue is not empty 605 { 606 int32 availableFragSize = iDataInQueue[0].getMemFragSize() - iDataInQueueMemFragOffset; 607 if (availableFragSize == 0) return false; 608 uint8* fragStartPtr = (uint8*)iDataInQueue[0].getMemFragPtr() + iDataInQueueMemFragOffset; 609 aHttpFrag.bind(fragStartPtr, availableFragSize); 610 } 611 return true; 612 } 613 614 615 ///////////////////////////////////////////////////////////////////////////////////// 616 bool HTTPParserInput::getOutputMemFrag(OsclRefCounterMemFrag &aMemFrag) 617 { 618 if (iDataOutQueue.empty()) return false; 619 iDataOutQueue[0].getRefCountMemFrag(aMemFrag); 620 iDataOutQueue.erase(iDataOutQueue.begin()); 621 return true; 622 } 623 624 ///////////////////////////////////////////////////////////////////////////////////// 625 // pass ending CRLF 626 void HTTPParserInput::skipCRLF() 627 { 628 if (iDataInQueue.empty()) return; 629 uint8* fragStartPtr = (uint8*)iDataInQueue[0].getMemFragPtr() + iDataInQueueMemFragOffset; 630 int32 availableFragSize = iDataInQueue[0].getMemFragSize() - iDataInQueueMemFragOffset; 631 while ((*fragStartPtr == HTTP_CHAR_CR || *fragStartPtr == HTTP_CHAR_LF) && availableFragSize > 0) 632 { 633 *fragStartPtr++; 634 availableFragSize--; 635 iDataInQueueMemFragOffset++; 636 } 637 } 638 639 // return value: 0 => not available ; >0 means the offset of the next complete line from the current point 640 // -1 error 641 int32 HTTPParserInput::isNextLineAvailable(bool aHeaderParsed) 642 { 643 if (iDataInQueue.empty()) return 0; 644 645 while (iDataInQueue.size() > 0) 646 { 647 if (iDataInQueueMemFragOffset >= iDataInQueue[0].getMemFragSize()) 648 { 649 // remove iDataInQueue[0], since it is copied to iDataOutQueue 650 iDataInQueue.erase(iDataInQueue.begin()); 651 iDataInQueueMemFragOffset = 0; 652 iHTTPMemFrag.clear(); 653 return 0; 654 } 655 656 bool bNewData = (iDataInQueueMemFragOffset == 0); 657 iHTTPMemFrag.bind((void *)((uint8*)iDataInQueue[0].getMemFragPtr() + iDataInQueueMemFragOffset), 658 iDataInQueue[0].getMemFragSize() - iDataInQueueMemFragOffset); 659 660 int32 offset = checkNextLine(iHTTPMemFrag); 661 iDataInQueueMemFragOffset += offset; 662 if (offset > 0 && iLineBufferOccupied == 0) 663 { 664 // construct an output fragment 665 if (!constructOutputFragment(iDataInQueueMemFragOffset, NULL, bNewData)) return -1; 666 return offset; 667 } 668 669 // copy to iLineBuffer to concatenate the line fragments 670 uint32 remaining_bytes = (offset > 0 ? offset : iHTTPMemFrag.getAvailableSpace()); 671 HTTPMemoryFragment aFrag(iHTTPMemFrag.getPtr(), remaining_bytes); 672 if (assemblyLineFragments(aFrag)) return -1; 673 674 if (offset > 0) 675 { 676 iHTTPMemFrag.bind(iLineBuffer, iLineBufferOccupied); 677 if (!constructOutputFragment(iDataInQueueMemFragOffset, NULL, bNewData)) return -1; 678 iLineBufferOccupied = 0; 679 return iHTTPMemFrag.getCapacity(); 680 } 681 682 if (!aHeaderParsed) 683 { 684 // save iDataInQueue[0] 685 if (!bNewData && !iDataOutQueue.empty()) iDataOutQueue.erase(&iDataOutQueue.back()); 686 int32 err = 0; 687 OSCL_TRY(err, iDataOutQueue.push_back(iDataInQueue[0]);); 688 if (err) return -1; 689 } 690 // remove iDataInQueue[0] 691 iDataInQueue.erase(iDataInQueue.begin()); 692 iDataInQueueMemFragOffset = 0; 693 iHTTPMemFrag.clear(); 694 } 695 696 return 0; 697 } 698 699 int32 HTTPParserInput::assemblyLineFragments(HTTPMemoryFragment &aFrag) 700 { 701 if (aFrag.getCapacity() <= iLineBufferSize - iLineBufferOccupied) 702 { 703 oscl_memcpy(iLineBuffer + iLineBufferOccupied, (char*)aFrag.getPtr(), aFrag.getCapacity()); 704 } 705 else 706 { 707 // realloc iLineBuffer 708 // aFrag.getCapacity()+iLineBufferOccupied>iLineBufferSize 709 iLineBufferSize = (aFrag.getCapacity() + iLineBufferOccupied) << 1; 710 711 OsclMemAllocator alloc; 712 char *aNewLineBuffer = (char*)alloc.allocate(iLineBufferSize); 713 if (!aNewLineBuffer) return -1; 714 if (iLineBufferOccupied) oscl_memcpy(aNewLineBuffer, iLineBuffer, iLineBufferOccupied); 715 oscl_memcpy(aNewLineBuffer + iLineBufferOccupied, (char*)aFrag.getPtr(), aFrag.getCapacity()); 716 717 // deallocate iLineBuffer 718 alloc.deallocate(iLineBuffer); 719 iLineBuffer = aNewLineBuffer; 720 } 721 iLineBufferOccupied += aFrag.getCapacity(); 722 return 0; 723 } 724 725 ///////////////////////////////////////////////////////////////////////////////////// 726 int32 HTTPParserInput::checkNextLine(HTTPMemoryFragment &aInputDataStream) 727 { 728 char *ptr = (char *)aInputDataStream.getPtr(), *start_ptr = ptr; 729 int32 streamLength = aInputDataStream.getAvailableSpace(); 730 while (streamLength > 1 && (*ptr != HTTP_CHAR_CR && *ptr != HTTP_CHAR_LF)) 731 { 732 ptr++; 733 streamLength--; 734 } 735 736 if (*ptr == HTTP_CHAR_CR || *ptr == HTTP_CHAR_LF) 737 { 738 if (streamLength > 1 && 739 (ptr[1] == HTTP_CHAR_CR || ptr[1] == HTTP_CHAR_LF) && 740 ptr[1] != ptr[0]) ptr++; // avoid double CR or double LF, should treat it as different lines 741 // Note that double CR(CRLFCRLF) or double LF (CRLFCRLF, or LFLF) means end of HTTP header 742 return ptr - start_ptr + 1; 743 } 744 745 return 0; // no complete key-value pair available 746 } 747 748 ///////////////////////////////////////////////////////////////////////////////////// 749 // if aNewMemFragPtr=NULL, no change to memory fragment pointer, existing fragment with larger length 750 bool HTTPParserInput::constructOutputFragment(const uint32 aNewMemFragLen, const void *aNewMemFragPtr, const bool isNewFrag) 751 { 752 if (isNewFrag || iDataOutQueue.empty()) 753 { 754 RefCounterMemoryFragment refCountMemfrag(iDataInQueue[0].getMemFrag(), iDataInQueue[0].getRefCounter()); 755 int32 err = 0; 756 OSCL_TRY(err, iDataOutQueue.push_back(refCountMemfrag);); 757 if (err) return false; 758 } 759 760 // update ptr and len of the memory fragment 761 iDataOutQueue.back().update(aNewMemFragLen); 762 if (aNewMemFragPtr) iDataOutQueue.back().update((void*)aNewMemFragPtr); 763 return true; 764 } 765 766 bool HTTPParserInput::empty() 767 { 768 if (iDataInQueue.empty()) return true; 769 if (iDataInQueue.size() > 1) return false; 770 771 // iDataInQueue.size() = 1 772 if (iDataInQueueMemFragOffset == iDataInQueue[0].getMemFragSize()) return true; 773 return false; 774 } 775 776 ///////////////////////////////////////////////////////////////////////////////////// 777 ////////// HTTPParserBaseObject Implementation //////////////////////*///////////// 778 ///////////////////////////////////////////////////////////////////////////////////// 779 int32 HTTPParserBaseObject::parseHeaderFields(HTTPMemoryFragment &aInputLineData, const bool aReplaceOldValue) 780 { 781 // parse header fields 782 char *fieldKey; 783 uint32 fieldKeyLength; 784 char *fieldValue; 785 uint32 fieldValueLength = 0; 786 int32 status = getNextFieldKeyValuePair(aInputLineData, fieldKey, fieldKeyLength, fieldValue, fieldValueLength); 787 if (status == 1) return HTTPParser::PARSE_HEADER_AVAILABLE; // end of header 788 if (status < 0) 789 { 790 LOGINFO((0, "HTTPParserBaseObject::parseHeaderFields() : Syntax Error founded!!")); 791 return HTTPParser::PARSE_SYNTAX_ERROR; // no divider characters found! 792 } 793 794 // exception handling (no key or no value case) 795 if (fieldKeyLength == 0) return HTTPParser::PARSE_SUCCESS; // for no key, just ignore it 796 char spaceChar = HTTP_CHAR_SPACE; 797 if (fieldValueLength == 0) // for no value, just set '' 798 { 799 fieldValue = &spaceChar; 800 fieldValueLength = 1; 801 } 802 if (status != 0) return HTTPParser::PARSE_SUCCESS; // just ignore 803 804 // add a key-value pair(fieldKey, fieldValue) to store 805 return addKeyValuePairToStore(fieldKey, fieldKeyLength, fieldValue, fieldValueLength, aReplaceOldValue); 806 } 807 808 int32 HTTPParserBaseObject::addKeyValuePairToStore(const char *aFieldKey, const uint32 aFieldKeyLength, 809 const char *aFieldValue, const uint32 aFieldValueLength, 810 const bool aNeedReplaceOldValue) 811 { 812 if (aFieldKeyLength + aFieldValueLength < iKeyValueStore->getAvailableSize()) 813 { 814 if (iKeyValueStore->addKeyValuePair(aFieldKey, aFieldKeyLength, aFieldValue, aFieldValueLength, aNeedReplaceOldValue) != 0) 815 { 816 return HTTPParser::PARSE_GENERAL_ERROR; 817 } 818 } 819 else 820 { 821 // not enough memory 822 if (!reallocKeyValueStore(aFieldKeyLength + aFieldValueLength)) return HTTPParser::PARSE_MEMORY_ALLOCATION_FAILURE; 823 // re-add key-value pair to store 824 if (iKeyValueStore->addKeyValuePair(aFieldKey, aFieldKeyLength, aFieldValue, aFieldValueLength, aNeedReplaceOldValue) == 825 StringKeyValueStore::StringKeyValueStore_Failure) return HTTPParser::PARSE_GENERAL_ERROR; 826 } 827 return HTTPParser::PARSE_SUCCESS; 828 } 829 830 int32 HTTPParserBaseObject::addKeyValuePairToStore(const StrCSumPtrLen &aNewKey, 831 const StrPtrLen &aNewValue, 832 const bool aNeedReplaceOldValue) 833 { 834 return addKeyValuePairToStore((char*)aNewKey.c_str(), aNewKey.length(), 835 (char*)aNewValue.c_str(), aNewValue.length(), 836 aNeedReplaceOldValue); 837 } 838 839 840 bool HTTPParserBaseObject::reallocKeyValueStore(const uint32 aCurrKeyValueSize) 841 { 842 // calculate the new KeyValueStore size 843 uint32 miniSize = iKeyValueStore->getCurrentMemoryUsage() + aCurrKeyValueSize; 844 uint32 aNewStoreSize = OSCL_MAX(miniSize, iKeyValueStore->getStoreSize()) << 1; 845 846 // create a new store 847 StringKeyValueStore *aKeyValueStore = StringKeyValueStore::create(aNewStoreSize); 848 if (!aKeyValueStore) return false; 849 if (!aKeyValueStore->copy(*iKeyValueStore)) 850 { 851 OSCL_DELETE(aKeyValueStore); 852 return false; 853 } 854 OSCL_DELETE(iKeyValueStore); 855 iKeyValueStore = aKeyValueStore; 856 return true; 857 858 } 859 860 bool HTTPParserBaseObject::constructEntityUnit(HTTPParserInput &aParserInput, RefCountHTTPEntityUnit &aEntityUnit) 861 { 862 OsclRefCounterMemFrag entityUnit; 863 int32 err = 0; 864 OSCL_TRY(err, entityUnit = iEntityUnitAlloc->get();); 865 if (err) return false; 866 867 // add memory fragments into the entity unit 868 HTTPEntityUnit* entityUnitFrag = OSCL_PLACEMENT_NEW(((uint8*) entityUnit.getMemFragPtr()), HTTPEntityUnit()); 869 OsclRefCounterMemFrag memfrag; 870 while (aParserInput.getOutputMemFrag(memfrag)) 871 { 872 if (!entityUnitFrag->addMemFrag(memfrag)) 873 { 874 entityUnitFrag->~HTTPEntityUnit(); 875 return false; 876 } 877 } 878 //if(entityUnitFrag->getNumFragments() == 0) { entityUnitFrag->~HTTPEntityUnit(); return false; } // no memory fragments 879 aEntityUnit = RefCountHTTPEntityUnit(*entityUnitFrag, entityUnit.getRefCounter()); // no memory fragments is possible 880 entityUnitFrag->~HTTPEntityUnit(); // destruct entityUnitFrag 881 return true; 882 } 883 884 // return value: 0 normal, 1 end of header, 2 ignore, -1 error 885 int32 HTTPParserBaseObject::getNextFieldKeyValuePair(HTTPMemoryFragment &aInputDataStream, char *&aFieldKey, uint32 &aFieldKeyLength, 886 char *&aFieldValue, uint32 &aFieldValueLength) 887 { 888 // get key 889 int32 status = parseNextValueItem(aInputDataStream, aFieldKey, aFieldKeyLength, true); 890 if (status != 0) return status; // end of header or error 891 892 // get value 893 return parseNextValueItem(aInputDataStream, aFieldValue, aFieldValueLength, false); 894 } 895 896 // return value: 0 normal, 897 // 1 end of header, 898 // 2 ignore (for CRLF, to handle CRLF split into separate fragments) 899 // -1 error 900 int32 HTTPParserBaseObject::parseNextValueItem(HTTPMemoryFragment &aInputDataStream, char *&valueItemPtr, uint32 &valueItemLength, const bool isKeyItem) 901 { 902 char dividerChar0 = (isKeyItem ? HTTP_CHAR_COLON : HTTP_CHAR_CR); 903 char dividerChar1 = (isKeyItem ? HTTP_CHAR_COLON : HTTP_CHAR_LF); 904 905 char *ptr = (char *)aInputDataStream.getPtr(); 906 int32 len = aInputDataStream.getAvailableSpace(); 907 908 // eat all non-letter characters at the beginning 909 int32 status = getLineStartPoint(ptr, len, isKeyItem); 910 if (status == 2) return status; // ignore 911 if (status == 1) 912 { 913 aInputDataStream.update(ptr); // Final CRLF, end of HTTP header 914 return 1; 915 } 916 917 // search divider characters to identify the value item 918 valueItemPtr = ptr; 919 while (*ptr != dividerChar0 && *ptr != dividerChar1 && len > 0) 920 { 921 ptr++; // assuming there is no case like "zzz key :" 922 len--; 923 } 924 if (len <= 0) return -1; // no divider chars 925 926 char *end_ptr = ptr--; 927 while (*ptr == HTTP_CHAR_SPACE || *ptr == HTTP_CHAR_TAB) ptr--; // eat space or tab characater 928 valueItemLength = (ptr > valueItemPtr ? (ptr - valueItemPtr + 1) : 0); // ptr is the ending pointer for a value item 929 930 ptr = end_ptr; 931 if (isKeyItem) ptr++; 932 else 933 { 934 saveEndingCRLF(ptr, len, iPrevCRLF); 935 if (len > 0 && (ptr[1] == HTTP_CHAR_CR || ptr[1] == HTTP_CHAR_LF)) ptr++; // pass CRLF at each line 936 } 937 938 aInputDataStream.update(ptr); 939 return 0; 940 } 941 942 // return value: 0 normal, 1 end of header, 2 ignore 943 int32 HTTPParserBaseObject::getLineStartPoint(char *&ptr, int32 &len, const bool isKeyItem) 944 { 945 if (isKeyItem) 946 { 947 while (!isLetter(*ptr) && (*ptr != HTTP_CHAR_CR && *ptr != HTTP_CHAR_LF) && len > 0) 948 { 949 iPrevCRLF = 0; 950 ptr++; 951 len--; // eat all non-letter characters except CRLF 952 } 953 if (*ptr == HTTP_CHAR_CR || *ptr == HTTP_CHAR_LF) // key guarantees to have very first LETTER character 954 { 955 if (iPrevCRLF == 0) 956 { 957 saveEndingCRLF(ptr, len, iPrevCRLF); 958 if (len > 0 && (ptr[1] == HTTP_CHAR_CR || ptr[1] == HTTP_CHAR_LF)) ptr++; 959 return 2; // save CRLF to iPrevCRLF, and ignore 960 } 961 else // iPrevCRLF has something 962 { 963 uint8 currCRLF = 0; 964 saveEndingCRLF(ptr, len, currCRLF); 965 if (len > 0 && (ptr[1] == HTTP_CHAR_CR || ptr[1] == HTTP_CHAR_LF)) ptr++; 966 if (iPrevCRLF & currCRLF) return 1; // double CR or LF, end of HTTP header 967 iPrevCRLF = currCRLF; 968 return 2; // ignore 969 } 970 } 971 } 972 else 973 { 974 while ((*ptr == HTTP_CHAR_SPACE || *ptr == HTTP_CHAR_TAB) && len > 0) 975 { 976 ptr++; 977 len--; 978 } // eat space or tab character 979 } 980 981 return 0; 982 } 983 984 // aNeedReset=1, set aCRLF; aNeedReset=0, update aCRLF 985 void HTTPParserBaseObject::saveEndingCRLF(char *ptr, uint32 len, uint8& aCRLF, bool aNeedReset) 986 { 987 char *tmpPtr = ptr; 988 int32 tmpLen = (int32)len; 989 if (aNeedReset) aCRLF = 0; 990 991 // get to CRLF point 992 while ((*tmpPtr != HTTP_CHAR_CR && *tmpPtr != HTTP_CHAR_LF) && tmpLen > 0) 993 { 994 tmpPtr++; 995 tmpLen--; 996 } 997 998 while ((*tmpPtr == HTTP_CHAR_CR || *tmpPtr == HTTP_CHAR_LF) && tmpLen > 0) 999 { 1000 if (*tmpPtr == HTTP_CHAR_CR) aCRLF |= 0x2; // bit 1 = 1 1001 if (*tmpPtr == HTTP_CHAR_LF) aCRLF |= 0x1; // bit 0 = 1 1002 tmpPtr++; 1003 tmpLen--; 1004 } 1005 } 1006 1007 1008 ///////////////////////////////////////////////////////////////////////////////////// 1009 ////////// HTTPParserHeaderObject Implementation //////////////////////////////////// 1010 ///////////////////////////////////////////////////////////////////////////////////// 1011 int32 HTTPParserHeaderObject::parse(HTTPParserInput &aParserInput, RefCountHTTPEntityUnit &aEntityUnit) 1012 { 1013 HTTPMemoryFragment aInputLineData; 1014 1015 while (aParserInput.getNextCompleteLine(aInputLineData)) 1016 { 1017 if (!iHeaderFirstLineParsed) 1018 { 1019 // parse the first line : Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF 1020 int32 status = parseFirstLine(aInputLineData); 1021 if (status < 0) return status; // syntax error 1022 iHeaderFirstLineParsed = true; 1023 } 1024 else 1025 { 1026 int32 status = parseHeaderFields(aInputLineData); 1027 if (status == HTTPParser::PARSE_HEADER_AVAILABLE) 1028 { 1029 iHeaderParsed = true; 1030 // check content info 1031 if (!iContentInfo->parseContentInfo(*iKeyValueStore)) return HTTPParser::PARSE_MEMORY_ALLOCATION_FAILURE; 1032 // construct output entity unit 1033 if (!constructEntityUnit(aParserInput, aEntityUnit)) return HTTPParser::PARSE_MEMORY_ALLOCATION_FAILURE; 1034 if (!isGoodStatusCode()) 1035 { 1036 LOGINFO((0, "HTTPParserHeaderObject::parse() : NOT GOOD STATUS CODE")); 1037 return HTTPParser::PARSE_STATUS_LINE_SHOW_NOT_SUCCESSFUL; 1038 } 1039 if (checkResponseParsedComplete()) iResponseParsedComplete = true; 1040 return HTTPParser::PARSE_HEADER_AVAILABLE; 1041 } 1042 if (status != HTTPParser::PARSE_SUCCESS) return status; 1043 } 1044 1045 } // end of: while(iParserInput->getNextCompleteLine(aInputLineData)) 1046 1047 // check content info 1048 return HTTPParser::PARSE_NEED_MORE_DATA; 1049 } 1050 1051 // return value: 0 => ok , or HTTPParser enum codes 1052 int32 HTTPParserHeaderObject::parseFirstLine(HTTPMemoryFragment &aInputDataStream) 1053 { 1054 // Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF 1055 char *ptr = (char *)aInputDataStream.getPtr(); 1056 int32 len = (int32)aInputDataStream.getAvailableSpace(); 1057 1058 while (!isLetter(*ptr) && len > 0) 1059 { 1060 ptr++; 1061 len--; 1062 } 1063 if (len < 8) return HTTPParser::PARSE_SYNTAX_ERROR; 1064 1065 // check HTTP/1.x 1066 if (((ptr[0] | OSCL_ASCII_CASE_MAGIC_BIT) == 'h') && 1067 ((ptr[1] | OSCL_ASCII_CASE_MAGIC_BIT) == 't') && 1068 ((ptr[2] | OSCL_ASCII_CASE_MAGIC_BIT) == 't') && 1069 ((ptr[3] | OSCL_ASCII_CASE_MAGIC_BIT) == 'p') && 1070 (ptr[4] == '/')) 1071 { 1072 ptr += 5; // size of "http/" 1073 if (!checkHTTPVersion(ptr)) 1074 { 1075 return HTTPParser::PARSE_HTTP_VERSION_NOT_SUPPORTED; 1076 } 1077 1078 // ptr should be updated in checkHTTPVersion() 1079 while (!isDigit(*ptr) && len > 0) 1080 { 1081 ptr++; 1082 len--; 1083 } 1084 if (len <= 0) return 0; // no digital status code 1085 char *start_ptr = ptr; 1086 uint32 start_len = len; 1087 while (isDigit(*ptr) && len > 0) 1088 { 1089 ptr++; 1090 len--; 1091 } 1092 //if(len <= 0) return 1; // no Reason-Phrase 1093 1094 // get status code 1095 PV_atoi(start_ptr, 'd', start_len - len, iStatusCode); 1096 saveEndingCRLF(ptr, len, iPrevCRLF); 1097 return 0; 1098 } 1099 1100 // add first-line into the key-value store 1101 StrPtrLen firstLine = "Response-Line"; 1102 addKeyValuePairToStore(firstLine.c_str(), firstLine.length(), 1103 (char *)aInputDataStream.getPtr(), aInputDataStream.getAvailableSpace(), 1104 true); 1105 1106 return HTTPParser::PARSE_SYNTAX_ERROR; // looks like the status line has something we don't understand. 1107 } 1108 1109 bool HTTPParserHeaderObject::checkHTTPVersion(char* &aPtr) 1110 { 1111 if (aPtr[0] == '1' && aPtr[0] == HTTP_CHAR_SPACE) 1112 { 1113 // support HTTP/1 1114 aPtr += 2; 1115 iHttpVersionNum = 0; 1116 return true; 1117 } 1118 1119 if (aPtr[0] == '1' && 1120 aPtr[1] == '.' && 1121 (aPtr[2] == '0' || aPtr[2] == '1')) 1122 { 1123 iHttpVersionNum = (aPtr[2] == '0' ? 0 : 1); 1124 aPtr += 3; 1125 return true; 1126 } 1127 1128 return false; 1129 } 1130 1131 // This function gets complicated since a couple of new cases have been added 1132 bool HTTPParserHeaderObject::isGoodStatusCode() 1133 { 1134 if (iStatusCode < GOOD_HTTP_STATUS_CODE_START_FROM100 || 1135 iStatusCode > GOOD_HTTP_STATUS_CODE_END_AT299) return false; 1136 1137 // check 1xx code, 1xx code is only allowed in Http/1.1 1138 bool goodStatusCode = checkGood1xxCode(); 1139 if (!goodStatusCode) return false; 1140 1141 // check 2xx code, if 204 (no content) or 2xx code with content-length=0, then we need to error out 1142 goodStatusCode = checkGood2xxCode(); 1143 return goodStatusCode; 1144 } 1145 1146 // check 1xx code, 1xx code is only allowed in Http/1.1 1147 bool HTTPParserHeaderObject::checkGood1xxCode() 1148 { 1149 if (iHttpVersionNum == 0 && 1150 (GOOD_HTTP_STATUS_CODE_START_FROM100 <= iStatusCode && iStatusCode < GOOD_HTTP_STATUS_CODE_START_FROM200)) 1151 { 1152 return false; 1153 } 1154 return true; 1155 } 1156 1157 // check 2xx code, if 2xx code with content-length=0, then we need to error out 1158 bool HTTPParserHeaderObject::checkGood2xxCode() 1159 { 1160 uint32 goodStatusCodeStart = GOOD_HTTP_STATUS_CODE_START_FROM200; 1161 if (GOOD_HTTP_STATUS_CODE_START_FROM200 <= iStatusCode && iStatusCode <= GOOD_HTTP_STATUS_CODE_END_AT299) 1162 { 1163 // for Http status code 204 (no content), error our right away 1164 if (iStatusCode == HTTP_STATUS_CODE_204_NO_CONTENT) 1165 { 1166 LOGINFO((0, "HTTPParserHeaderObject::checkGood2xxCode() : iStatusCode=HTTP_STATUS_CODE_204_NO_CONTENT")); 1167 return false; 1168 } 1169 1170 // other 2xx code, check the zero or empty content-length 1171 StrCSumPtrLen contenLengthKey("Content-Length"); 1172 StrPtrLen contentLengthValue; 1173 if (iKeyValueStore->getValueByKey(contenLengthKey, contentLengthValue)) 1174 { 1175 // has Content-Length field 1176 uint32 aContentLength = 0; 1177 PV_atoi(contentLengthValue.c_str(), 'd', aContentLength); 1178 1179 // check the empty Content-Length case 1180 char *ptr = (char *)contentLengthValue.c_str(); 1181 if (aContentLength == 0 || ptr[0] == HTTP_CHAR_SPACE) 1182 { 1183 LOGINFO((0, "HTTPParserHeaderObject::checkGood2xxCode() : zero or empty content length for 2xx code")); 1184 return false; 1185 } 1186 } 1187 } 1188 return (goodStatusCodeStart <= iStatusCode && iStatusCode <= GOOD_HTTP_STATUS_CODE_END_AT299); 1189 } 1190 1191 int32 HTTPParserHeaderObject::doSanityCheckForResponseHeader() 1192 { 1193 // check Chunked Transfer Encoding supported for Http/1.1 only 1194 if (!checkChunkedTransferEncodingSupported()) return HTTPParser::PARSE_TRANSFER_ENCODING_NOT_SUPPORTED; 1195 return HTTPParser::PARSE_SUCCESS; 1196 } 1197 1198 1199 // check Chunked Transfer Encoding supported by Http/1.1 only 1200 bool HTTPParserHeaderObject::checkChunkedTransferEncodingSupported() 1201 { 1202 StrCSumPtrLen transferEncodingKey("Transfer-Encoding"); 1203 StrPtrLen transferEncodingValue; 1204 if (iKeyValueStore->getValueByKey(transferEncodingKey, transferEncodingValue)) 1205 { 1206 LOGINFO((0, "HTTPParserHeaderObject::checkChunkedTransferEncodingSupported() : has Transfer-encoding field, HttpVersionNum=%d", iHttpVersionNum)); 1207 // has Transfer-encoding field 1208 if (iHttpVersionNum == 0) return false; 1209 } 1210 return true; 1211 } 1212 1213 bool HTTPParserHeaderObject::checkResponseParsedComplete() 1214 { 1215 // check "Content-Length" 1216 StrCSumPtrLen contentLengthKey = "Content-Length"; 1217 StrPtrLen contentLengthValue; 1218 1219 if (!getField(contentLengthKey, contentLengthValue)) return false; // no "Content-Length" 1220 1221 // get "Content-Length" value 1222 uint32 contentLength = 0; 1223 PV_atoi(contentLengthValue.c_str(), 'd', contentLength); 1224 return (contentLength == 0); 1225 } 1226 1227 HTTPParserHeaderObject *HTTPParserHeaderObject::create(HTTPContentInfoInternal *aContentInfo) 1228 { 1229 HTTPParserHeaderObject *header = OSCL_NEW(HTTPParserHeaderObject, ()); 1230 if (!header) return NULL; 1231 if (!header->construct(aContentInfo)) 1232 { 1233 OSCL_DELETE(header); 1234 return NULL; 1235 } 1236 return header; 1237 } 1238 1239 bool HTTPParserHeaderObject::construct(HTTPContentInfoInternal *aContentInfo) 1240 { 1241 reset(); 1242 iContentInfo = aContentInfo; 1243 1244 if ((iKeyValueStore = StringKeyValueStore::create()) == NULL) return false; 1245 1246 iEntityUnitAlloc = OSCL_NEW(PVMFBufferPoolAllocator, ()); 1247 if (!iEntityUnitAlloc) return false; 1248 1249 int32 err = 0; 1250 OSCL_TRY(err, iEntityUnitAlloc->size(HTTP_ENTITY_UNIT_POOLNUM, sizeof(HTTPEntityUnit))); 1251 if (err) return false; 1252 1253 return true; 1254 } 1255 1256 HTTPParserHeaderObject::~HTTPParserHeaderObject() 1257 { 1258 reset(); 1259 1260 // delete iKeyValueStore 1261 if (iKeyValueStore) OSCL_DELETE(iKeyValueStore); 1262 iKeyValueStore = NULL; 1263 1264 // delete iEntityUnitAlloc 1265 if (iEntityUnitAlloc) OSCL_DELETE(iEntityUnitAlloc); 1266 iEntityUnitAlloc = NULL; 1267 } 1268 1269 1270 ///////////////////////////////////////////////////////////////////////////////////// 1271 ////////// HTTPParserEntityBodyObject Implementation //////////////////////////////// 1272 ///////////////////////////////////////////////////////////////////////////////////// 1273 int32 HTTPParserEntityBodyObject::parseEnityBodyChunkData(HTTPParserInput &aParserInput, RefCountHTTPEntityUnit &aEntityUnit) 1274 { 1275 int32 requestSize = iContentInfo->getContentRangeLength() - iCurrentChunkDataLength; 1276 HTTPMemoryFragment aFrag; 1277 int32 actualSize = 0; 1278 while (requestSize > 0) 1279 { 1280 if ((actualSize = aParserInput.getData(aFrag, requestSize)) <= 0) break; 1281 iCurrentChunkDataLength += actualSize; 1282 iNumChunks++; 1283 requestSize -= actualSize; 1284 } 1285 if (actualSize < 0) return HTTPParser::PARSE_MEMORY_ALLOCATION_FAILURE; 1286 if (actualSize == 0 && requestSize > 0) return HTTPParser::PARSE_NEED_MORE_DATA; 1287 1288 // get complete chunk, and then construct output entity unit 1289 if (!constructEntityUnit(aParserInput, aEntityUnit)) return HTTPParser::PARSE_MEMORY_ALLOCATION_FAILURE; 1290 1291 // pass ending CRLF for the chunk data for next chunk parsing 1292 aParserInput.skipCRLF(); 1293 return HTTPParser::PARSE_SUCCESS; 1294 } 1295 1296 ///////////////////////////////////////////////////////////////////////////////////// 1297 ////////// HTTPParserNormalContentObject Implementation ///////////////////////////// 1298 ///////////////////////////////////////////////////////////////////////////////////// 1299 int32 HTTPParserNormalContentObject::parse(HTTPParserInput &aParserInput, RefCountHTTPEntityUnit &aEntityUnit) 1300 { 1301 HTTPMemoryFragment aFrag; 1302 int32 actualSize = 0; 1303 if (iContentInfo->iContentLength == 0) iContentInfo->iContentLength = 0x7fffffff; // 0=>7fff ffff 1304 if (iCurrTotalLengthObtained == 0 && iContentInfo->iContentRangeLeft > 0) iCurrTotalLengthObtained = iContentInfo->iContentRangeLeft; 1305 int32 requestSize = (int32)iContentInfo->iContentLength - (int32)iCurrTotalLengthObtained; 1306 if (requestSize <= 0) 1307 { 1308 if (requestSize == 0) return HTTPParser::PARSE_SUCCESS_END_OF_MESSAGE; 1309 return HTTPParser::PARSE_SUCCESS_END_OF_MESSAGE_WITH_EXTRA_DATA; 1310 } 1311 while ((actualSize = aParserInput.getData(aFrag, requestSize)) > 0) 1312 { 1313 iCurrTotalLengthObtained += actualSize; 1314 if (requestSize > 0) 1315 { 1316 if ((requestSize -= actualSize) <= 0) break; // we don't need to process aFrag 1317 } 1318 } 1319 if (actualSize < 0) return HTTPParser::PARSE_MEMORY_ALLOCATION_FAILURE; 1320 1321 // construct output entity unit 1322 if (!constructEntityUnit(aParserInput, aEntityUnit)) return HTTPParser::PARSE_MEMORY_ALLOCATION_FAILURE; 1323 if (iCurrTotalLengthObtained >= iContentInfo->iContentLength) 1324 { 1325 if (iCurrTotalLengthObtained > iContentInfo->iContentLength || 1326 !aParserInput.empty()) return HTTPParser::PARSE_SUCCESS_END_OF_MESSAGE_WITH_EXTRA_DATA; 1327 return HTTPParser::PARSE_SUCCESS_END_OF_MESSAGE; 1328 } 1329 if (actualSize == 0 && iContentInfo->iContentLength > iCurrTotalLengthObtained) return HTTPParser::PARSE_SUCCESS_END_OF_INPUT; 1330 return HTTPParser::PARSE_SUCCESS; 1331 } 1332 1333 1334 ///////////////////////////////////////////////////////////////////////////////////// 1335 ////////// HTTPParserCTEContentObject Implementation ///////////////////////////// 1336 ///////////////////////////////////////////////////////////////////////////////////// 1337 int32 HTTPParserCTEContentObject::parse(HTTPParserInput &aParserInput, RefCountHTTPEntityUnit &aEntityUnit) 1338 { 1339 // get CTE chunk length 1340 if (iContentInfo->iContentRangeRight == 0) 1341 { 1342 HTTPMemoryFragment aInputLineData; 1343 int32 chunkLength = -1; 1344 while (aParserInput.getNextCompleteLine(aInputLineData, true)) // true means header is already parsed 1345 { 1346 if (getCTEChunkLength(aInputLineData, chunkLength)) break; 1347 } 1348 if (chunkLength == -1) return HTTPParser::PARSE_NEED_MORE_DATA; 1349 if (chunkLength == 0) 1350 { 1351 if (!aParserInput.empty()) return HTTPParser::PARSE_SUCCESS_END_OF_MESSAGE_WITH_EXTRA_DATA; 1352 return HTTPParser::PARSE_SUCCESS_END_OF_MESSAGE; 1353 } 1354 1355 iContentInfo->iContentRangeRight = chunkLength - 1; 1356 iContentInfo->iContentLength += chunkLength; 1357 aParserInput.clearOutputQueue(); 1358 } 1359 1360 // get CTE chunk data 1361 aParserInput.skipCRLF(); 1362 int32 status = parseEnityBodyChunkData(aParserInput, aEntityUnit); 1363 if (status == HTTPParser::PARSE_SUCCESS) reset(); // for next chunk parsing 1364 return status; 1365 } 1366 1367 bool HTTPParserCTEContentObject::getCTEChunkLength(HTTPMemoryFragment &aInputLineData, int32 &aChunkSize) 1368 { 1369 char *ptr = (char *)aInputLineData.getPtr(); 1370 int32 len = (int32)aInputLineData.getAvailableSpace(); 1371 while (!isHexDigit(*ptr) && len > 0) 1372 { 1373 ptr++; 1374 len--; 1375 } 1376 if (len <= 0) return false; 1377 char *start_ptr = ptr; 1378 int32 start_len = len; 1379 while (isHexDigit(*ptr) && len > 0) 1380 { 1381 ptr++; 1382 len--; 1383 } 1384 if (len <= 0) return false; 1385 uint32 chunkSize; 1386 PV_atoi(start_ptr, 'x', start_len - len, chunkSize); 1387 aChunkSize = (int32)chunkSize; 1388 return true; 1389 } 1390 1391 ///////////////////////////////////////////////////////////////////////////////////// 1392 ////////// HTTPParserMultipartContentObject Implementation ///////////////////////////// 1393 ///////////////////////////////////////////////////////////////////////////////////// 1394 int32 HTTPParserMultipartContentObject::parse(HTTPParserInput &aParserInput, RefCountHTTPEntityUnit &aEntityUnit) 1395 { 1396 // parse boundary string and chunk header 1397 int32 status = parseChunkHeader(aParserInput); 1398 if (status != HTTPParser::PARSE_SUCCESS) return status; 1399 1400 // get chunk data 1401 1402 status = parseEnityBodyChunkData(aParserInput, aEntityUnit); 1403 if (status != HTTPParser::PARSE_SUCCESS) return status; 1404 1405 reset(); // for next chunk parsing 1406 if (aParserInput.empty()) return HTTPParser::PARSE_SUCCESS_END_OF_INPUT; 1407 return HTTPParser::PARSE_SUCCESS; 1408 } 1409 1410 int32 HTTPParserMultipartContentObject::parseChunkHeader(HTTPParserInput &aParserInput) 1411 { 1412 if (iHeaderInEntityBodyParsed) return HTTPParser::PARSE_SUCCESS; 1413 1414 // parse boundary line 1415 if (!iBoudaryLineParsed) 1416 { 1417 int32 status = parseChunkBoundaryLine(aParserInput); 1418 if (status != HTTPParser::PARSE_SUCCESS) return status; 1419 if (!iBoudaryLineParsed) return HTTPParser::PARSE_NEED_MORE_DATA; // try next time 1420 } 1421 1422 // parse chunk header 1423 HTTPMemoryFragment aInputLineData; 1424 while (aParserInput.getNextCompleteLine(aInputLineData)) 1425 { 1426 if (!iBoudaryLineParsed) 1427 { 1428 return HTTPParser::PARSE_SYNTAX_ERROR; 1429 } 1430 int32 status = parseHeaderFields(aInputLineData, true); // true means replace the old field value with the new one 1431 if (status == HTTPParser::PARSE_HEADER_AVAILABLE) 1432 { 1433 iHeaderInEntityBodyParsed = true; 1434 iCounter++; 1435 // update content info 1436 if (!iContentInfo->parseContentInfo(*iKeyValueStore)) return HTTPParser::PARSE_MEMORY_ALLOCATION_FAILURE; 1437 aParserInput.clearOutputQueue(); 1438 saveEndingCRLF((char *)aInputLineData.getPtr(), (int32)aInputLineData.getAvailableSpace(), iPrevCRLF); 1439 break; 1440 } 1441 if (status != HTTPParser::PARSE_SUCCESS) return status; 1442 } 1443 if (!iHeaderInEntityBodyParsed) return HTTPParser::PARSE_NEED_MORE_DATA; 1444 1445 // check the extra CRLF 1446 if (needSkipCRLF()) aParserInput.skipCRLF(); 1447 return HTTPParser::PARSE_SUCCESS; 1448 } 1449 1450 1451 int32 HTTPParserMultipartContentObject::parseChunkBoundaryLine(HTTPParserInput &aParserInput) 1452 { 1453 HTTPMemoryFragment aInputLineData; 1454 if (aParserInput.getNextCompleteLine(aInputLineData)) 1455 { 1456 1457 // parse boundary line : --BOUNDARY STRING 1458 bool isFinalBoundary = false; 1459 if (iContentInfo->parseBoudaryLine(aInputLineData, isFinalBoundary)) iBoudaryLineParsed = true; 1460 if (isFinalBoundary) return HTTPParser::PARSE_SUCCESS_END_OF_MESSAGE; 1461 saveEndingCRLF((char *)aInputLineData.getPtr(), (int32)aInputLineData.getAvailableSpace(), iPrevCRLF); 1462 1463 if (!iBoudaryLineParsed) 1464 { 1465 if (aParserInput.getNextCompleteLine(aInputLineData)) 1466 { 1467 bool isFinalBoundary = false; 1468 if (iContentInfo->parseBoudaryLine(aInputLineData, isFinalBoundary)) iBoudaryLineParsed = true; 1469 } 1470 } 1471 } 1472 1473 if (!iBoudaryLineParsed) 1474 { 1475 // try to see whether it is final boundary line, like --boundaryString-- (no "\r\n") 1476 HTTPMemoryFragment frag; 1477 if (!aParserInput.viewAvailableInputData(frag)) return HTTPParser::PARSE_NEED_MORE_DATA; 1478 1479 bool isFinalBoundary = false; 1480 iContentInfo->parseBoudaryLine(frag, isFinalBoundary); 1481 if (isFinalBoundary) return HTTPParser::PARSE_SUCCESS_END_OF_MESSAGE; 1482 } 1483 return HTTPParser::PARSE_SUCCESS; 1484 } 1485