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 "pvmf_protocol_engine_common.h"
     19 #include "pvmf_media_msg_format_ids.h" // for PVMF_MEDIA_CMD_EOS_FORMAT_ID
     20 #include "oscl_utf8conv.h" // for oscl_UnicodeToUTF8
     21 
     22 ////////////////////////////////////////////////////////////////////////////////////
     23 //////  pvHttpDownloadInput implementation
     24 ////////////////////////////////////////////////////////////////////////////////////
     25 bool pvHttpDownloadInput::getValidMediaData(INPUT_DATA_QUEUE &aDataInQueue, PVMFSharedMediaDataPtr &aMediaData, bool &isEOS)
     26 {
     27     isEOS = false; //aMediaData.Bind(iCurrentInputMediaData);
     28 
     29     do
     30     {
     31         // There should be at least one media msg in the queue
     32         if (aDataInQueue.empty()) return false;
     33 
     34         // Check if the next incoming media msg is an EOS or not
     35         // Introducing a boolean variable aEOSMsg is for simulating connection shutdown cases
     36         bool aEOSMsg = aDataInQueue[0]->getFormatID() == PVMF_MEDIA_CMD_EOS_FORMAT_ID;
     37         if (aEOSMsg)
     38         {
     39             isEOS = true;
     40             aDataInQueue.erase(aDataInQueue.begin());
     41             return true;
     42         }
     43 
     44         convertToPVMFMediaData(iCurrentInputMediaData, aDataInQueue[0]);
     45         aDataInQueue.erase(aDataInQueue.begin());
     46     }
     47     while (isValidInput() == false);
     48 
     49     aMediaData.Bind(iCurrentInputMediaData);
     50     return true;
     51 }
     52 
     53 bool pvHttpDownloadInput::isValidInput()
     54 {
     55     if (iCurrentInputMediaData->getTimestamp() == 0xFFFFFFFF ||
     56             iCurrentInputMediaData->getFilledSize() == 0)
     57     {
     58         // Cannot use this input media data since TS is not available
     59         // Discard and return to retrieve another input media data from the queue
     60         unbind();
     61         return false;
     62         // ANOTHER OPTION TO DEFAULT THE TS TO 0 IN THIS CASE AND CONTINUE ON
     63     }
     64     return true;
     65 }
     66 
     67 //////  INetURI implementation
     68 ////////////////////////////////////////////////////////////////////////////////////
     69 OSCL_EXPORT_REF bool INetURI::setURI(OSCL_wString &aUri, const bool aRedirectURI)
     70 {
     71     if (aUri.get_size() == 0) return false;
     72 
     73     OsclMemAllocator alloc;
     74     char *buf = (char*)alloc.allocate(aUri.get_size() + 1);
     75     if (!buf) return false;
     76     uint32 size = oscl_UnicodeToUTF8(aUri.get_cstr(), aUri.get_size(), buf, aUri.get_size() + 1);
     77     if (size == 0)
     78     {
     79         alloc.deallocate(buf);
     80         return false;
     81     }
     82     iURI = OSCL_HeapString<OsclMemAllocator> (buf, size);
     83     alloc.deallocate(buf);
     84     // clear iHost
     85     iHostName.set(NULL, 0);
     86     iRedirectURI = aRedirectURI;
     87     return true;
     88 }
     89 
     90 OSCL_EXPORT_REF bool INetURI::getHostAndPort(OSCL_String &aSerAdd, int32 &aSerPort)
     91 {
     92     if (iURI.get_size() == 0) return false;
     93     if (iHostName.get_size() == 0)
     94     {
     95         if (!parseURL(iURI, iHostName, iHostPort)) return false;
     96     }
     97     aSerAdd = iHostName;
     98     aSerPort = iHostPort;
     99     return true;
    100 }
    101 
    102 bool INetURI::parseURL(OSCL_String &aUrl8, OSCL_String &aSerAdd, int32 &aSerPort)
    103 {
    104     OSCL_HeapString<OsclMemAllocator> tmpUrl8(aUrl8);
    105 
    106     typedef char mbchar;
    107     mbchar* aUrl = tmpUrl8.get_str();
    108 
    109     mbchar *server_ip_ptr = OSCL_CONST_CAST(mbchar*, oscl_strstr(((mbchar*)aUrl), "//"));
    110     if (server_ip_ptr == NULL) return false;
    111     server_ip_ptr += 2;
    112 
    113     /* Locate the IP address. */
    114     mbchar *server_port_ptr = OSCL_CONST_CAST(mbchar*, oscl_strstr(server_ip_ptr, ":"));
    115     mbchar *tmp_ptr = server_port_ptr;
    116     if (tmp_ptr == NULL) tmp_ptr = server_ip_ptr;
    117     mbchar *clip_name = OSCL_CONST_CAST(mbchar*, oscl_strstr(tmp_ptr, "/"));
    118     if (clip_name != NULL) *clip_name++ = '\0';
    119 
    120     /* Locate the port number if provided. */
    121     aSerPort = DEFAULT_HTTP_PORT_NUMBER;
    122     if ((server_port_ptr != NULL)  && (*(server_port_ptr + 1) != '/'))
    123     {
    124         *(server_port_ptr++) = '\0';
    125         uint32 atoi_tmp;
    126         if (PV_atoi(server_port_ptr, 'd', atoi_tmp)) aSerPort = atoi_tmp;
    127         else return false;
    128     }
    129 
    130     /* relocate the server IP address, either stop at ':' or '/' */
    131     mbchar *server_end_ptr = OSCL_CONST_CAST(mbchar*, oscl_strstr(server_ip_ptr, "/"));
    132     if (server_end_ptr) *server_end_ptr = '\0';
    133 
    134     OSCL_HeapString<OsclMemAllocator> tmpServerName(server_ip_ptr, oscl_strlen(server_ip_ptr));
    135     aSerAdd = tmpServerName;
    136     return true;
    137 }
    138 
    139 ////////////////////////////////////////////////////////////////////////////////////
    140 //////  HttpParsingBasicObject implementation
    141 ////////////////////////////////////////////////////////////////////////////////////
    142 OSCL_EXPORT_REF int32 HttpParsingBasicObject::parseResponse(INPUT_DATA_QUEUE &aDataQueue)
    143 {
    144     PVMFSharedMediaDataPtr mediaData;
    145     int32 status = getNextMediaData(aDataQueue, mediaData);
    146     if (status != PARSE_SUCCESS)
    147     {
    148         if (status == PARSE_EOS_INPUT_DATA)
    149         {
    150             return validateEOSInput(status);
    151         }
    152         return status; // no input data or eos
    153     }
    154 
    155     OsclRefCounterMemFrag fragIn;
    156     mediaData->getMediaFragment(0, fragIn);
    157     HttpParsingBasicObjectAutoCleanup cleanup(this);
    158 
    159     while (status == PARSE_SUCCESS)
    160     {
    161         RefCountHTTPEntityUnit entityUnit;
    162         int32 parsingStatus = iParser->parse(fragIn, entityUnit);
    163         if (parsingStatus < 0)
    164         {
    165             PVMF_PROTOCOL_ENGINE_LOGERRINFODATAPATH((0,
    166                                                     "HttpParsingBasicObject::parseResponse(), iParser->parse() retval=%d(iHttpHeaderParsed=%d)",
    167                                                     parsingStatus, (int32)iHttpHeaderParsed));
    168         }
    169         else
    170         {
    171 
    172             // save output data if there is
    173             iOutputQueue->clear();
    174             uint32 size = 0;
    175             if (!saveOutputData(entityUnit, *iOutputQueue, size))
    176             {
    177                 return PARSE_GENERAL_ERROR;
    178             }
    179 
    180             if (parsingStatus == HTTPParser::PARSE_HEADER_AVAILABLE)
    181             {
    182                 iHttpHeaderParsed = true;
    183                 iParser->getContentInfo(iContentInfo);
    184                 extractServerVersionNum();
    185 
    186                 // update BandWidthEstimationInfo
    187                 iBWEstInfo.update(mediaData, iHttpHeaderParsed);
    188 
    189                 // do sanity check for HTTP header
    190                 int32 sanityCheckStatus = iParser->doSanityCheckForResponseHeader();
    191                 if (sanityCheckStatus == HTTPParser::PARSE_TRANSFER_ENCODING_NOT_SUPPORTED)
    192                 {
    193                     parsingStatus = sanityCheckStatus;
    194                 }
    195                 else
    196                 {
    197                     // output data
    198                     status = iObserver->OutputDataAvailable(iOutputQueue, true);
    199                     if (status < 0) return status;
    200                 }
    201             }
    202             else if (iHttpHeaderParsed && size > 0)
    203             {
    204                 iTotalDLHttpBodySize += size;
    205                 if (iLatestMediaDataTimestamp < mediaData->getTimestamp()) iLatestMediaDataTimestamp = mediaData->getTimestamp();
    206 
    207                 // update BandWidthEstimationInfo
    208                 iBWEstInfo.update(mediaData, iHttpHeaderParsed);
    209                 PVMF_PROTOCOL_ENGINE_LOGERRINFODATAPATH((0, "HttpParsingBasicObject::parseResponse() file size = %d, download size = %d, curr_size = %d, new download size = %d",
    210                                                         iContentInfo.iContentLength, iTotalDLHttpBodySize, size, iBWEstInfo.iTotalSizePerRequest));
    211             }
    212         }
    213 
    214         // check the condition of whether parsing the current input is done or not
    215         // may send out callback for end of message or end of input cases
    216         if ((status = checkParsingDone(parsingStatus)) != PARSE_SUCCESS)
    217         {
    218             if (status != PROCESS_WAIT_FOR_INCOMING_DATA)
    219             {
    220                 PVMF_PROTOCOL_ENGINE_LOGERRINFODATAPATH((0, "HttpParsingBasicObject::parseResponse() status=checkParsingDone(parsingStatus)); parsingStatus = %d , status = %d",
    221                                                         parsingStatus, status));
    222             }
    223             return status;
    224         }
    225     }
    226 
    227     return PARSE_SUCCESS;
    228 }
    229 
    230 int32 HttpParsingBasicObject::getNextMediaData(INPUT_DATA_QUEUE &aDataInQueue, PVMFSharedMediaDataPtr &aMediaData)
    231 {
    232     bool isEOS = false;
    233     if (!iInput.getValidMediaData(aDataInQueue, aMediaData, isEOS)) return PARSE_NO_INPUT_DATA;
    234     if (isEOS)
    235     {
    236         if (!isRedirectResponse())
    237         {
    238             iNumEOSMessagesAfterRequest++;
    239             iTotalDLSizeForPrevEOS = iTotalDLSizeAtCurrEOS;
    240             iTotalDLSizeAtCurrEOS = iTotalDLHttpBodySize;
    241             PVMF_PROTOCOL_ENGINE_LOGERRINFODATAPATH((0, "HttpParsingBasicObject::getNextMediaData() isEOS=%d, iNumEOSMessagesAfterRequest=%d, iTotalDLHttpBodySize=%d, iTotalDLSizeAtCurrEOS=%d, iTotalDLSizeForPrevEOS=%d",
    242                                                     (uint32)isEOS, iNumEOSMessagesAfterRequest, iTotalDLHttpBodySize, iTotalDLSizeAtCurrEOS, iTotalDLSizeForPrevEOS));
    243 
    244         }
    245         iInput.unbind();
    246         return PARSE_EOS_INPUT_DATA;
    247     }
    248     //if(iTotalDLSizeAtCurrEOS!=iTotalDLHttpBodySize || !isEOS) {
    249     if (iTotalDLSizeAtCurrEOS > iTotalDLSizeForPrevEOS || iTotalDLHttpBodySize > iTotalDLSizeAtCurrEOS)
    250     {
    251         iNumEOSMessagesAfterRequest = 0;
    252         PVMF_PROTOCOL_ENGINE_LOGERRINFODATAPATH((0, "HttpParsingBasicObject::getNextMediaData(), non-EOS case iNumEOSMessagesAfterRequest is reset to 0, iTotalDLHttpBodySize=%d, iTotalDLSizeAtCurrEOS=%d, iTotalDLSizeForPrevEOS=%d",
    253                                                 iTotalDLHttpBodySize, iTotalDLSizeAtCurrEOS, iTotalDLSizeForPrevEOS));
    254     }
    255     if (iNumEOSMessagesAfterRequest != 0)
    256     {
    257         PVMF_PROTOCOL_ENGINE_LOGERRINFODATAPATH((0, "HttpParsingBasicObject::getNextMediaData(), should be non-EOS case and iNumEOSMessagesAfterRequest is NOT reset to 0! isEOS=%d, iNumEOSMessagesAfterRequest=%d, iTotalDLHttpBodySize=%d, iTotalDLSizeAtCurrEOS=%d, iTotalDLSizeForPrevEOS=%d",
    258                                                 (uint32)isEOS, iNumEOSMessagesAfterRequest, iTotalDLHttpBodySize, iTotalDLSizeAtCurrEOS, iTotalDLSizeForPrevEOS));
    259     }
    260     return PARSE_SUCCESS;
    261 }
    262 
    263 int32 HttpParsingBasicObject::validateEOSInput(int32 parsingStatus)
    264 {
    265     //if(!iHttpHeaderParsed && iNumEOSMessagesAfterRequest>=MAX_NUM_EOS_MESSAGES_FOR_SAME_REQUEST) { // MAX_NUM_EOS_MESSAGES_FOR_SAME_REQUEST=2
    266     if (iNumEOSMessagesAfterRequest >= iNumRetry)   // iNumRetry = MAX_NUM_EOS_MESSAGES_FOR_SAME_REQUEST=2
    267     {
    268         // if we recieve EOS message as the first response after sending request, and we do socket reconnect and send the request again, if we still
    269         // get EOS message, that means server always shuts down the connection for this request, and we don't want to try reconnect any more. That
    270         // indicates the url is probably bad.
    271         // In general, we treat download size unchange between two adjacent EOSs (even if there is some header parsed) as bad url. Otherwise we'll
    272         // run into infinite reconnect/disconnect loop
    273         return PARSE_BAD_URL;
    274     }
    275     return parsingStatus;
    276 }
    277 
    278 void HttpParsingBasicObject::extractServerVersionNum()
    279 {
    280     StrCSumPtrLen serverKey = "Server";
    281     StrPtrLen serverValue;
    282     if (!iParser->getField(serverKey, serverValue)) return;
    283     if (serverValue.length() == 0) return;
    284 
    285     // Has Sever header
    286     char *ptr = (char*)serverValue.c_str();
    287     for (int32 i = 0; i < serverValue.length(); i++)
    288     {
    289         if (!PE_isDigit(*ptr))
    290         {
    291             ptr++;
    292             continue;
    293         }
    294         iServerVersionNumber = *ptr++ - '0';
    295         if (PE_isDigit(*ptr) && ++i < serverValue.length())
    296         {
    297             iServerVersionNumber = iServerVersionNumber * 10 + (*ptr - '0');
    298         }
    299         break;
    300     }
    301 }
    302 
    303 bool HttpParsingBasicObject::saveOutputData(RefCountHTTPEntityUnit &entityUnit, OUTPUT_DATA_QUEUE &aOutputData, uint32 &aTotalEntityDataSize)
    304 {
    305     aTotalEntityDataSize = 0;
    306     int32 err = 0;
    307     OSCL_TRY(err,
    308              for (uint32 i = 0; i < entityUnit.getEntityUnit().getNumFragments(); i++)
    309 {
    310     OsclRefCounterMemFrag memfrag;
    311     entityUnit.getEntityUnit().getMemFrag(i, memfrag);
    312         aOutputData.push_back(memfrag);
    313         aTotalEntityDataSize += memfrag.getMemFragSize();
    314     }
    315             );
    316     return (err == 0);
    317 }
    318 
    319 int32 HttpParsingBasicObject::checkParsingDone(const int32 parsingStatus)
    320 {
    321     // check error case
    322     if (parsingStatus < 0)
    323     {
    324         if (parsingStatus == HTTPParser::PARSE_SYNTAX_ERROR) return PARSE_SYNTAX_ERROR;
    325         if (parsingStatus == HTTPParser::PARSE_HTTP_VERSION_NOT_SUPPORTED) return PARSE_HTTP_VERSION_NOT_SUPPORTED;
    326         if (parsingStatus == HTTPParser::PARSE_TRANSFER_ENCODING_NOT_SUPPORTED) return PARSE_TRANSFER_ENCODING_NOT_SUPPORTED;
    327         return PARSE_GENERAL_ERROR; // error happens;
    328     }
    329 
    330     if (parsingStatus == HTTPParser::PARSE_SUCCESS_END_OF_MESSAGE ||
    331             parsingStatus == HTTPParser::PARSE_SUCCESS_END_OF_MESSAGE_WITH_EXTRA_DATA ||
    332             parsingStatus == HTTPParser::PARSE_SUCCESS_END_OF_INPUT   ||
    333             parsingStatus == HTTPParser::PARSE_SUCCESS)
    334     {
    335         // send output data
    336         if (iHttpHeaderParsed && !iOutputQueue->empty())
    337         {
    338             //if(!iObserver->OutputDataAvailable(iOutputQueue, false)) return PARSE_GENERAL_ERROR;
    339             int32 status = iObserver->OutputDataAvailable(iOutputQueue, false);
    340             if (status < 0) return status;
    341             if (status == PROCESS_SUCCESS_END_OF_MESSAGE) return PARSE_SUCCESS_END_OF_MESSAGE;
    342             if (status == PROCESS_SUCCESS_END_OF_MESSAGE_TRUNCATED) return status;
    343         }
    344     }
    345     if (parsingStatus == HTTPParser::PARSE_STATUS_LINE_SHOW_NOT_SUCCESSFUL)       return PARSE_STATUS_LINE_SHOW_NOT_SUCCESSFUL; // status code >= 300
    346     if (parsingStatus == HTTPParser::PARSE_SUCCESS_END_OF_MESSAGE)                return PARSE_SUCCESS_END_OF_MESSAGE;
    347     if (parsingStatus == HTTPParser::PARSE_SUCCESS_END_OF_MESSAGE_WITH_EXTRA_DATA) return PARSE_SUCCESS_END_OF_MESSAGE_WITH_EXTRA_DATA;
    348     if (parsingStatus == HTTPParser::PARSE_NEED_MORE_DATA)                        return PARSE_NEED_MORE_DATA;
    349     if (parsingStatus == HTTPParser::PARSE_SUCCESS_END_OF_INPUT)                      return PARSE_SUCCESS_END_OF_INPUT;
    350 
    351     // HTTPParser::PARSE_SUCCESS or HTTPParser::PARSE_HEADER_AVAILABLE
    352     return PARSE_SUCCESS;
    353 }
    354 
    355 bool HttpParsingBasicObject::isRedirectResponse()
    356 {
    357     bool aPartOfRedirectResponse = false;
    358     uint32 httpStatusCode = getStatusCode();
    359     if (PROTOCOLENGINE_REDIRECT_STATUS_CODE_START <= httpStatusCode && httpStatusCode <= PROTOCOLENGINE_REDIRECT_STATUS_CODE_END)
    360     {
    361         aPartOfRedirectResponse = true;
    362     }
    363     return aPartOfRedirectResponse;
    364 }
    365 
    366 
    367 // factory method
    368 OSCL_EXPORT_REF HttpParsingBasicObject* HttpParsingBasicObject::create()
    369 {
    370     HttpParsingBasicObject *object = OSCL_NEW(HttpParsingBasicObject, ());
    371     if (!object) return NULL;
    372     if (!object->construct())
    373     {
    374         OSCL_DELETE(object);
    375         return NULL;
    376     }
    377     return object;
    378 }
    379 
    380 bool HttpParsingBasicObject::construct()
    381 {
    382     reset();
    383     resetForBadConnectionDetection();
    384     iServerVersionNumber = 0;
    385     if ((iParser = HTTPParser::create()) == NULL) return false;
    386     return true;
    387 }
    388 
    389 void HttpParsingBasicObject::setDownloadSize(const uint32 aInitialSize)
    390 {
    391     if (aInitialSize > 0)
    392         iTotalDLHttpBodySize = aInitialSize;
    393     else
    394     {
    395         // sync up with content-range_left
    396         iTotalDLHttpBodySize = iContentInfo.iContentRangeLeft;
    397     }
    398 
    399     PVMF_PROTOCOL_ENGINE_LOGERRINFODATAPATH((0, "HttpParsingBasicObject::setDownloadSize %d", iTotalDLHttpBodySize));
    400 
    401     iTotalDLSizeForPrevEOS = iTotalDLSizeAtCurrEOS = iTotalDLHttpBodySize;
    402 }
    403 
    404 OSCL_EXPORT_REF bool HttpParsingBasicObject::getRedirectURI(OSCL_String &aRedirectUri)
    405 {
    406     StrCSumPtrLen aLocation = "Location";
    407     StrPtrLen url;
    408     if (iParser->getField(aLocation, url))
    409     {
    410         if (url.length() > MIN_URL_LENGTH)   // MIN_URL_LENGTH = 1
    411         {
    412             // http_parcom views empty header value as ASCII space character 0x20
    413             // so remove the case of empty header
    414             aRedirectUri = OSCL_HeapString<OsclMemAllocator> (url.c_str(), url.length());
    415             return true;
    416         }
    417     }
    418     return false;
    419 }
    420 
    421 OSCL_EXPORT_REF bool HttpParsingBasicObject::getContentType(OSCL_String &aContentType)
    422 {
    423     StrCSumPtrLen aContentTypeKey = "Content-Type";
    424     StrPtrLen aContentTypeValue;
    425     if (iParser->getField(aContentTypeKey, aContentTypeValue))
    426     {
    427         if (aContentTypeValue.length() > 0)
    428         {
    429             aContentType = OSCL_HeapString<OsclMemAllocator> (aContentTypeValue.c_str(), aContentTypeValue.length());
    430             return true;
    431         }
    432     }
    433     return false;
    434 }
    435 
    436 OSCL_EXPORT_REF bool HttpParsingBasicObject::isServerSupportBasicAuthentication()
    437 {
    438     StrCSumPtrLen aAuthenKey = "WWW-Authenticate";
    439     uint32 numFieldsByKey = iParser->getNumberOfFieldsByKey(aAuthenKey);
    440     uint32 i = 0;
    441     for (i = 0; i < numFieldsByKey; i++)
    442     {
    443         StrPtrLen aAuthenValue;
    444         iParser->getField(aAuthenKey, aAuthenValue, i);
    445         const char *ptrRealm = aAuthenValue.c_str();
    446         uint32 len = aAuthenValue.length();
    447         uint32 length = 0;
    448 
    449         getRealmPtr(ptrRealm, len, length);
    450         getBasicPtr(aAuthenValue, length);
    451         if (length >= 6) return true;
    452     }
    453     return false;
    454 }
    455 
    456 OSCL_EXPORT_REF bool HttpParsingBasicObject::getAuthenInfo(OSCL_String &aRealm)
    457 {
    458     StrCSumPtrLen aAuthenKey = "WWW-Authenticate";
    459     uint32 numFieldsByKey = iParser->getNumberOfFieldsByKey(aAuthenKey);
    460     uint32 i = 0;
    461     for (i = 0; i < numFieldsByKey; i++)
    462     {
    463         StrPtrLen aAuthenValue;
    464         iParser->getField(aAuthenKey, aAuthenValue, i);
    465         const char *ptrRealm = aAuthenValue.c_str();
    466         uint32 len = aAuthenValue.length();
    467         uint32 length = 0;
    468 
    469         getRealmPtr(ptrRealm, len, length);
    470         if (len < 6) continue;
    471 
    472         getBasicPtr(aAuthenValue, length);
    473         if (length < 6) continue;
    474 
    475         ptrRealm += 6;
    476         len -= 6;
    477         aRealm = OSCL_HeapString<OsclMemAllocator> (ptrRealm, len);
    478         return true;
    479     }
    480     return false;
    481 }
    482 
    483 OSCL_EXPORT_REF void HttpParsingBasicObject::getRealmPtr(const char *&ptrRealm, uint32 &len, uint32 &length)
    484 {
    485     while (!(((ptrRealm[0]  | OSCL_ASCII_CASE_MAGIC_BIT) == 'r') &&
    486              ((ptrRealm[1]  | OSCL_ASCII_CASE_MAGIC_BIT) == 'e') &&
    487              ((ptrRealm[2]  | OSCL_ASCII_CASE_MAGIC_BIT) == 'a') &&
    488              ((ptrRealm[3]  | OSCL_ASCII_CASE_MAGIC_BIT) == 'l') &&
    489              ((ptrRealm[4]  | OSCL_ASCII_CASE_MAGIC_BIT) == 'm') &&
    490              ((ptrRealm[5]  | OSCL_ASCII_CASE_MAGIC_BIT) == '=')) &&
    491             len >= 6)
    492     {
    493         ptrRealm++;
    494         len--;
    495         length++;
    496     }
    497 }
    498 
    499 OSCL_EXPORT_REF void HttpParsingBasicObject::getBasicPtr(const StrPtrLen aAuthenValue, uint32 &length)
    500 {
    501     const char *ptrBasic = aAuthenValue.c_str();
    502     while (!(((ptrBasic[0]  | OSCL_ASCII_CASE_MAGIC_BIT) == 'b') &&
    503              ((ptrBasic[1]  | OSCL_ASCII_CASE_MAGIC_BIT) == 'a') &&
    504              ((ptrBasic[2]  | OSCL_ASCII_CASE_MAGIC_BIT) == 's') &&
    505              ((ptrBasic[3]  | OSCL_ASCII_CASE_MAGIC_BIT) == 'i') &&
    506              ((ptrBasic[4]  | OSCL_ASCII_CASE_MAGIC_BIT) == 'c') &&
    507              ((ptrBasic[5]  | OSCL_ASCII_CASE_MAGIC_BIT) == ' ')) &&
    508             length >= 6)
    509     {
    510         ptrBasic++;
    511         length--;
    512     }
    513 }
    514 
    515 OSCL_EXPORT_REF bool HttpParsingBasicObject::isServerSendAuthenticationHeader()
    516 {
    517     StrCSumPtrLen aAuthenKey = "WWW-Authenticate";
    518     StrPtrLen aAuthenValue;
    519     if (iParser->getField(aAuthenKey, aAuthenValue))
    520     {
    521         if (aAuthenValue.length() > 0)
    522         {
    523             return true;
    524         }
    525     }
    526     return false;
    527 }
    528 
    529 int32 HttpParsingBasicObject::isNewContentRangeInfoMatchingCurrentOne(const uint32 aPrevContentLength)
    530 {
    531     // First, consider content-length match
    532     if (aPrevContentLength != iContentInfo.iContentLength) return PARSE_CONTENT_LENGTH_NOT_MATCH;
    533 
    534     // if range doesn't support, return false
    535     if (iContentInfo.iContentRangeRight == 0) return PARSE_CONTENT_RANGE_INFO_NOT_MATCH;
    536 
    537     // Second, consider this case where content-range exists: compare iTotalDLHttpBodySize with content-range_left
    538     if (iTotalDLHttpBodySize > 0 && iContentInfo.iContentRangeRight > 0)
    539     {
    540         if (iTotalDLHttpBodySize != iContentInfo.iContentRangeLeft) return PARSE_CONTENT_RANGE_INFO_NOT_MATCH;
    541     }
    542 
    543     // for other cases, return true
    544     return PARSE_SUCCESS;
    545 }
    546 
    547 
    548 ////////////////////////////////////////////////////////////////////////////////////
    549 //////  ProtocolState implementation
    550 ////////////////////////////////////////////////////////////////////////////////////
    551 OSCL_EXPORT_REF int32 ProtocolState::processMicroState(INPUT_DATA_QUEUE &aDataQueue)
    552 {
    553     if (iProcessingState == EHttpProcessingMicroState_SendRequest)
    554     {
    555         int32 status = doProcessMicroStateSendRequestPreCheck();
    556         if (status != PROCESS_SUCCESS) return status;
    557         return doProcessMicroStateSendRequest();
    558     }
    559     else if (iProcessingState == EHttpProcessingMicroState_GetResponse)
    560     {
    561         int32 status = doProcessMicroStateGetResponsePreCheck();
    562         if (status != PROCESS_SUCCESS) return status;
    563         return doProcessMicroStateGetResponse(aDataQueue);
    564     }
    565     return PROCESS_SUCCESS;
    566 }
    567 
    568 int32 ProtocolState::doProcessMicroStateSendRequestPreCheck()
    569 {
    570     int32 status = processMicroStateSendRequestPreCheck();
    571     if (status < 0)
    572     {
    573         LOGINFODATAPATH((0, "ProtocolState::processMicroState() processMicroStateSendRequestPreCheck(), error status, errCode=%d", status));
    574         iObserver->ProtocolStateError(status);
    575         return status;
    576     }
    577     return PROCESS_SUCCESS;
    578 }
    579 
    580 int32 ProtocolState::doProcessMicroStateSendRequest()
    581 {
    582     int32 status = processMicroStateSendRequest();
    583     if (status >= 0)
    584     {
    585         // SendRequest -> GetResponse automatically
    586         iProcessingState = EHttpProcessingMicroState_GetResponse;
    587         // No need to set iNeedGetResponsePreCheck as true.
    588     }
    589     if (status != PROCESS_SUCCESS)
    590     {
    591         LOGINFODATAPATH((0, "ProtocolState::processMicroState() send request error, errCode=%d", status));
    592         if (status < 0) iObserver->ProtocolStateError(status);
    593     }
    594     return status;
    595 }
    596 
    597 int32 ProtocolState::doProcessMicroStateGetResponsePreCheck()
    598 {
    599     if (iNeedGetResponsePreCheck)
    600     {
    601         int32 status = processMicroStateGetResponsePreCheck();
    602         if (status != PROCESS_SUCCESS)
    603         {
    604             LOGINFODATAPATH((0, "ProtocolState::processMicroState() processMicroStateGetResponsePreCheck(), error status, errCode=%d", status));
    605             iObserver->ProtocolStateError(status);
    606             return status;
    607         }
    608         iNeedGetResponsePreCheck = false;
    609     }
    610     return PROCESS_SUCCESS;
    611 }
    612 
    613 int32 ProtocolState::doProcessMicroStateGetResponse(INPUT_DATA_QUEUE &aDataQueue)
    614 {
    615     int32 status = processMicroStateGetResponse(aDataQueue);
    616     if (status == PROCESS_SUCCESS_END_OF_MESSAGE ||
    617             status == PROCESS_SUCCESS_END_OF_MESSAGE_TRUNCATED ||
    618             status == PROCESS_SUCCESS_END_OF_MESSAGE_WITH_EXTRA_DATA ||
    619             status == PROCESS_SUCCESS_END_OF_MESSAGE_BY_SERVER_DISCONNECT ||
    620             status == PROCESS_SUCCESS_GOT_EOS)
    621     {
    622         // notify user that data processing at the current state is completely done.
    623         // user may choose to change to next protocol state
    624         if (status != PROCESS_SUCCESS_GOT_EOS)
    625         {
    626             ProtocolStateCompleteInfo aInfo(isDownloadStreamingDoneState(),
    627                                             isLastState(),
    628                                             isDownloadStreamingDoneState());
    629             iObserver->ProtocolStateComplete(aInfo);
    630         }
    631         iNeedGetResponsePreCheck = true;
    632     }
    633     else if (status == PROCESS_SERVER_RESPONSE_ERROR || status < 0)
    634     {
    635         int32 errorCode = status;
    636         if (status >= 0) errorCode = iParser->getStatusCode();
    637         LOGINFODATAPATH((0, "ProtocolState::processMicroState() error status, errCode=%d", errorCode));
    638         iObserver->ProtocolStateError(errorCode);
    639     }
    640     return status;
    641 }
    642 
    643 OSCL_EXPORT_REF int32 ProtocolState::processMicroStateSendRequestPreCheck()
    644 {
    645     if (!iComposer || !iObserver) return PROCESS_INPUT_OUTPUT_NOT_READY;
    646 
    647     // check good url in terms of parsing correctly to get server address and port
    648     if (!iURI.isGoodUri()) return PROCESS_BAD_URL;
    649 
    650     // reset composer
    651     iComposer->reset();
    652 
    653     return PROCESS_SUCCESS;
    654 }
    655 
    656 OSCL_EXPORT_REF int32 ProtocolState::processMicroStateSendRequest()
    657 {
    658     // create output media data to be sent to socket node through port
    659     PVMFSharedMediaDataPtr mediaData;
    660     if (!iObserver->GetBufferForRequest(mediaData)) return PROCESS_MEDIA_DATA_CREATE_FAILURE;
    661 
    662     // compose http request
    663     OsclRefCounterMemFrag fragOut;
    664     mediaData->getMediaFragment(0, fragOut);
    665     OsclMemoryFragment memFrag = fragOut.getMemFrag();
    666     memFrag.len = fragOut.getCapacity();
    667     int32 status = composeRequest(memFrag);
    668     if (status != PROCESS_SUCCESS) return status;
    669     mediaData->setMediaFragFilledLen(0, iComposer->getCurrentRequestLength(iURI.isUseAbsoluteURI())); // don't count NULL
    670 
    671     // send to port
    672     iObserver->ProtocolRequestAvailable(getProtocolRequestType());
    673 
    674     // set start time for download rate estimation
    675     iStartTime.set_to_current_time();
    676 
    677     // reset the band width estimation info structure
    678     // needed for repositioning in progressive streaming
    679     BandwidthEstimationInfo *pBWEstInfo = iParser->getBandwidthEstimationInfo();
    680     pBWEstInfo->clear();
    681 
    682     // move to the next state, GetResponse
    683     iProcessingState = EHttpProcessingMicroState_GetResponse;
    684     return PROCESS_SUCCESS;
    685 }
    686 
    687 int32 ProtocolState::composeRequest(OsclMemoryFragment &aFrag)
    688 {
    689     // reset composer to compose a new request
    690     iComposer->reset();
    691 
    692     // set three basic elements: method, url and http version
    693     setRequestBasics();
    694 
    695     // set fields
    696     if (!setHeaderFields()) return PROCESS_COMPOSE_HTTP_REQUEST_FAILURE;
    697 
    698     // compose
    699     return doCompose(aFrag);
    700 }
    701 
    702 OSCL_EXPORT_REF int32 ProtocolState::doCompose(OsclMemoryFragment &aFrag)
    703 {
    704     // compose
    705     uint32 requestLen = iComposer->getCurrentRequestLength(iURI.isUseAbsoluteURI());
    706     if (requestLen + 1 > aFrag.len)  return PROCESS_COMPOSE_HTTP_REQUEST_BUFFER_SIZE_NOT_MATCH_REQUEST_SIZE;
    707     if (iComposer->compose(aFrag, iURI.isUseAbsoluteURI())) return PROCESS_COMPOSE_HTTP_REQUEST_FAILURE;
    708     return PROCESS_SUCCESS;
    709 }
    710 
    711 OSCL_EXPORT_REF int32 ProtocolState::processMicroStateGetResponsePreCheck()
    712 {
    713     if (!iParser || !iObserver) return PROCESS_INPUT_OUTPUT_NOT_READY;
    714     iParser->reset();
    715     return PROCESS_SUCCESS;
    716 }
    717 
    718 OSCL_EXPORT_REF int32 ProtocolState::processMicroStateGetResponse(INPUT_DATA_QUEUE &aDataQueue)
    719 {
    720     int32 status = iParser->parseResponse(aDataQueue);
    721     return checkParsingStatus(status);
    722 }
    723 
    724 // shared routine for all the download protocols
    725 OSCL_EXPORT_REF int32 ProtocolState::checkParsingStatus(int32 parsingStatus)
    726 {
    727     // error part
    728     if (parsingStatus == HttpParsingBasicObject::PARSE_SYNTAX_ERROR) return handleParsingSyntaxError();
    729     if (parsingStatus == HttpParsingBasicObject::PARSE_GENERAL_ERROR) return PROCESS_GENERAL_ERROR;
    730     if (parsingStatus == HttpParsingBasicObject::PARSE_BAD_URL) return PROCESS_BAD_URL;
    731     if (parsingStatus == HttpParsingBasicObject::PARSE_HTTP_VERSION_NOT_SUPPORTED) return PROCESS_HTTP_VERSION_NOT_SUPPORTED;
    732     if (parsingStatus == HttpParsingBasicObject::PARSE_TRANSFER_ENCODING_NOT_SUPPORTED) return PROCESS_CHUNKED_TRANSFER_ENCODING_NOT_SUPPORT;
    733     if (parsingStatus < 0)
    734     {
    735         return PROCESS_PARSE_HTTP_RESPONSE_FAILURE;
    736     }
    737 
    738     if (parsingStatus == HttpParsingBasicObject::PARSE_NO_INPUT_DATA) return PROCESS_WAIT_FOR_INCOMING_DATA;
    739     if (parsingStatus == HttpParsingBasicObject::PARSE_STATUS_LINE_SHOW_NOT_SUCCESSFUL) return PROCESS_SERVER_RESPONSE_ERROR;
    740 
    741     if (parsingStatus == HttpParsingBasicObject::PARSE_SUCCESS ||
    742             parsingStatus == HttpParsingBasicObject::PARSE_NEED_MORE_DATA ||
    743             parsingStatus == HttpParsingBasicObject::PARSE_SUCCESS_END_OF_INPUT) return PROCESS_SUCCESS;
    744 
    745     if (parsingStatus == HttpParsingBasicObject::PARSE_SUCCESS_END_OF_MESSAGE) return PROCESS_SUCCESS_END_OF_MESSAGE;
    746     if (parsingStatus == HttpParsingBasicObject::PARSE_SUCCESS_END_OF_MESSAGE_WITH_EXTRA_DATA) return PROCESS_SUCCESS_END_OF_MESSAGE_WITH_EXTRA_DATA;
    747     if (parsingStatus == HttpParsingBasicObject::PARSE_EOS_INPUT_DATA) return PROCESS_SUCCESS_GOT_EOS;
    748 
    749     return PROCESS_SUCCESS;
    750 }
    751 
    752 int32 ProtocolState::handleParsingSyntaxError()
    753 {
    754     // If we run into syntax error -2 and the new http header is not available,
    755     // then ignore the current packet and search the new response packet with http response header
    756     if (!iParser->isHttpHeaderParsed())
    757     {
    758         LOGINFODATAPATH((0, "ProtocolState::handleParsingSyntaxError(), parsing error(-2) + no Http header parsed, IGNORE THE PACKET AND CONTINUE SEARCH!!"));
    759 
    760         // reset the parser
    761         uint32 currDownloadSize = iParser->getDownloadSize();
    762         iParser->reset();
    763         iParser->setDownloadSize(currDownloadSize);
    764         return PROCESS_SUCCESS;
    765     }
    766 
    767     return PROCESS_PARSE_HTTP_RESPONSE_FAILURE;
    768 }
    769 
    770 uint32 ProtocolState::getDownloadRate()
    771 {
    772     TimeValue currentTime;
    773     currentTime.set_to_current_time();
    774 
    775     TimeValue deltaTimeVal = currentTime - iStartTime;
    776     int32 deltaMilliSec0 = deltaTimeVal.to_msec();
    777 
    778     int32 deltaMilliSec = iParser->getLatestMediaDataTimestamp() - (uint32)iStartTime.to_msec();
    779     if (deltaMilliSec <= 0) return 0;
    780 
    781     BandwidthEstimationInfo *pBWEstInfo = iParser->getBandwidthEstimationInfo();
    782     int32 deltaMilliSec1 = pBWEstInfo->iLatestMediaDataTimestamp - pBWEstInfo->iFirstMediaDataTsPerRequest;
    783     if (deltaMilliSec1 <= 0) return 0;
    784 
    785     OsclFloat downloadRate0 = ((OsclFloat)getDownloadSize() / (OsclFloat)deltaMilliSec0) * (OsclFloat)1000.0; // try to avoid overflow problem for 32-bit interger multiplication
    786     OsclFloat downloadRate  = ((OsclFloat)getDownloadSize() / (OsclFloat)deltaMilliSec) * (OsclFloat)1000.0; // try to avoid overflow problem for 32-bit interger multiplication
    787     OsclFloat downloadRate1 = ((OsclFloat)(pBWEstInfo->iTotalSizePerRequest) /
    788                                (OsclFloat)deltaMilliSec1) * (OsclFloat)1000.0; // try to avoid overflow problem for 32-bit interger multiplication
    789 
    790     LOGINFODATAPATH((0, "ProtocolState::getDownloadRate(), deltaMilliSec0=%d, downloadSize=%d, downloadRate0=%dbps",
    791                      deltaMilliSec0, getDownloadSize(), (uint32)(downloadRate0*8)));
    792 
    793     LOGINFODATAPATH((0, "ProtocolState::getDownloadRate(), deltaMilliSec=%d, downloadSize=%d, downloadRate=%dbps, ",
    794                      deltaMilliSec, getDownloadSize(), (uint32)(downloadRate*8)));
    795 
    796     LOGINFODATAPATH((0, "ProtocolState::getDownloadRate(), deltaMilliSec1=%d, downloadSize1=%d, downloadRate1=%dbps",
    797                      deltaMilliSec1, pBWEstInfo->iTotalSizePerRequest, (uint32)(downloadRate1*8)));
    798 
    799     OSCL_UNUSED_ARG(downloadRate0);
    800     OSCL_UNUSED_ARG(downloadRate); // remove warnings for unused variable
    801     return (uint32)downloadRate1;
    802 }
    803 
    804 uint32 ProtocolState::getDownloadTimeForEstimation()
    805 {
    806     TimeValue currentTime;
    807     currentTime.set_to_current_time();
    808 
    809     TimeValue deltaTimeVal = currentTime - iStartTime;
    810     return (uint32)deltaTimeVal.to_msec();
    811 }
    812 
    813 OSCL_EXPORT_REF bool ProtocolState::setExtensionFields(Oscl_Vector<OSCL_HeapString<OsclMemAllocator>, OsclMemAllocator> &aExtensionHeaderKeys,
    814         Oscl_Vector<OSCL_HeapString<OsclMemAllocator>, OsclMemAllocator> &aExtensionHeaderValues,
    815         Oscl_Vector<uint32, OsclMemAllocator> &aMaskBitForHTTPMethod,
    816         Oscl_Vector<bool, OsclMemAllocator> &aExtensionHeadersPurgeOnRedirect,
    817         const HTTPMethod aMethod)
    818 {
    819     // no extension headers
    820     if (aExtensionHeaderKeys.empty() || aExtensionHeaderValues.empty()) return true;
    821     // number of extension field keys and values doesn't match
    822     if (aExtensionHeaderKeys.size() != aExtensionHeaderValues.size()) return false;
    823     if (aMaskBitForHTTPMethod.size() > 0 && (aMaskBitForHTTPMethod.size() != aExtensionHeaderKeys.size())) return false;
    824 
    825     // mask bits for Http method
    826     uint32 bitMask = getBitMaskForHttpMethod(aMaskBitForHTTPMethod, aMethod);
    827 
    828 
    829     for (uint32 i = 0; i < aExtensionHeaderKeys.size(); i++)
    830     {
    831         StrCSumPtrLen fieldKey(aExtensionHeaderKeys[i].get_cstr(),
    832                                aExtensionHeaderKeys[i].get_size());
    833 
    834         StrPtrLen fieldValue(aExtensionHeaderValues[i].get_cstr(),
    835                              aExtensionHeaderValues[i].get_size());
    836 
    837         bool addExtensionHeader = true;
    838         if (bitMask > 0) addExtensionHeader = ((aMaskBitForHTTPMethod[i] & bitMask) != 0);
    839         if (iURI.isRedirectURI() && aExtensionHeadersPurgeOnRedirect[i]) addExtensionHeader = false; // for purge on redirect
    840         if (addExtensionHeader && !iComposer->setField(fieldKey, &fieldValue)) return false;
    841     }
    842     return true;
    843 }
    844 
    845 uint32 ProtocolState::getBitMaskForHttpMethod(Oscl_Vector<uint32, OsclMemAllocator> &aMaskBitForHTTPMethod,
    846         const HTTPMethod aMethod)
    847 {
    848     uint32 bitMask = 0;
    849     if (!aMaskBitForHTTPMethod.empty())
    850     {
    851         if (aMethod == HTTP_METHOD_GET)  bitMask = MASK_HTTPGET_EXTENSIONHEADER;
    852         if (aMethod == HTTP_METHOD_POST) bitMask = MASK_HTTPPOST_EXTENSIONHEADER;
    853         if (aMethod == HTTP_METHOD_HEAD) bitMask = MASK_HTTPHEAD_EXTENSIONHEADER;
    854     }
    855     return bitMask;
    856 }
    857 
    858 OSCL_EXPORT_REF bool ProtocolState::constructAuthenHeader(OSCL_String &aUserID, OSCL_String &aPasswd)
    859 {
    860     if (aUserID.get_size() == 0 && aPasswd.get_size() == 0) return true; // empty user and authentication strings
    861 
    862     // set user and authentication for HTTP basic authentication
    863     const uint32 SIZE = 512;
    864     char buf[SIZE + 1];
    865     char *userID = (char*)aUserID.get_cstr();
    866     char *passwd = (char*)aPasswd.get_cstr();
    867     oscl_snprintf(buf, SIZE, "%s:%s", userID != NULL ? userID : "", passwd != NULL ? passwd : "");
    868     char base64buf[(SIZE<<1)+1], *ptr = (char*)base64buf;
    869     OSCL_FastString basicString(_STRLIT_CHAR("Basic "));
    870     oscl_memcpy(ptr, basicString.get_cstr(), basicString.get_size());
    871     ptr += basicString.get_size();
    872     base64enc(buf, ptr);
    873     StrCSumPtrLen auth = "Authorization";
    874     return iComposer->setField(auth, base64buf);
    875 }
    876 
    877 
    878 // subroutine for base64 encoding (used in HTTP Basic authentification)
    879 const char alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
    880 int32 ProtocolState::base64enc(char *data, char *out)
    881 {
    882     int32 len = oscl_strlen(data);
    883 
    884     int32 i, index;
    885     int32 val;
    886 
    887     for (i = 0, index = 0; i < len; i += 3, index += 4)
    888     {
    889         int32 quad = 0, trip = 0;
    890 
    891         val = (0xff & data[i]);
    892         val <<= 8;
    893         if ((i + 1) < len)
    894         {
    895             val |= (0xff & data[i+1]);
    896             trip = 1;
    897         }
    898         val <<= 8;
    899         if ((i + 2) < len)
    900         {
    901             val |= (0xff & data[i+2]);
    902             quad = 1;
    903         }
    904         out[index+3] = alphabet[(quad ? (val & 0x3f) : 64)];
    905         val >>= 6;
    906         out[index+2] = alphabet[(trip ? (val & 0x3f) : 64)];
    907         val >>= 6;
    908         out[index+1] = alphabet[val & 0x3f];
    909         val >>= 6;
    910         out[index+0] = alphabet[val & 0x3f];
    911     }
    912 
    913     //out[++index] = 0;
    914     out[index] = 0;
    915     return index;
    916 }
    917 
    918