Home | History | Annotate | Download | only in src
      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