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_progressive_download.h"
     19 
     20 //////  ProgressiveDownloadState_HEAD implementation ////////////////////////////
     21 OSCL_EXPORT_REF void ProgressiveDownloadState_HEAD::setRequestBasics()
     22 {
     23     iComposer->setMethod(HTTP_METHOD_HEAD);
     24     //iComposer->setVersion(HTTP_V1_1);
     25     iComposer->setVersion((HTTPVersion)iCfgFile->getHttpVersion());
     26     StrPtrLen uri((iURI.getURI()).get_cstr(), (iURI.getURI()).get_size());
     27     iComposer->setURI(uri);
     28 }
     29 
     30 OSCL_EXPORT_REF bool ProgressiveDownloadState_HEAD::setHeaderFields()
     31 {
     32     if (!DownloadState::setHeaderFields()) return false;
     33     if (!ProtocolState::constructAuthenHeader(iCfgFile->GetUserId(), iCfgFile->GetUserAuth())) return false;
     34 
     35     return setExtensionFields(iCfgFile->getExtensionHeaderKeys(),
     36                               iCfgFile->getExtensionHeaderValues(),
     37                               iCfgFile->getHTTPMethodMasksForExtensionHeader(),
     38                               iCfgFile->getExtensionHeadersPurgeOnRedirect(),
     39                               HTTP_METHOD_HEAD);
     40 }
     41 
     42 OSCL_EXPORT_REF int32 ProgressiveDownloadState_HEAD::checkParsingStatus(int32 parsingStatus)
     43 {
     44     if (parsingStatus == HttpParsingBasicObject::PARSE_SUCCESS_END_OF_INPUT && iParser->isHttpHeaderParsed())
     45         return PROCESS_SUCCESS_END_OF_MESSAGE;
     46 
     47     return ProtocolState::checkParsingStatus(parsingStatus);
     48 }
     49 
     50 OSCL_EXPORT_REF int32 ProgressiveDownloadState_HEAD::OutputDataAvailable(OUTPUT_DATA_QUEUE *aOutputQueue, const bool isHttpHeader)
     51 {
     52     if (isHttpHeader)
     53     {
     54         iDataSideInfo.set(ProtocolEngineOutputDataType_HttpHeader);
     55         iObserver->OutputDataAvailable(*aOutputQueue, iDataSideInfo);
     56     }
     57     return HttpParsingBasicObject::PARSE_SUCCESS;
     58 }
     59 
     60 //////  ProgressiveDownloadState_GET implementation ////////////////////////////
     61 OSCL_EXPORT_REF int32 ProgressiveDownloadState_GET::processMicroStateGetResponsePreCheck()
     62 {
     63     int32 status = DownloadState::processMicroStateGetResponsePreCheck();
     64     if (status != PROCESS_SUCCESS) return status;
     65 
     66     // set the existing download size if this is resume download
     67     iParser->setDownloadSize(iCfgFile->GetCurrentFileSize());
     68 
     69     return PROCESS_SUCCESS;
     70 }
     71 
     72 OSCL_EXPORT_REF bool ProgressiveDownloadState_GET::setHeaderFields()
     73 {
     74     // check range header
     75     if (!setRangeHeaderFields()) return false;
     76 
     77     // set authentication header and common headers
     78     if (!ProtocolState::constructAuthenHeader(iCfgFile->GetUserId(), iCfgFile->GetUserAuth())) return false;
     79     if (!DownloadState::setHeaderFields()) return false;
     80 
     81     // change "Connection" field
     82     StrCSumPtrLen connectionKey = "Connection";
     83     char *nullPtr = NULL; // remove "Connection" field
     84     if (!iComposer->setField(connectionKey, nullPtr)) return false;
     85     // reset "Connection: Close"
     86     StrPtrLen  connectionValue = "Close";
     87     if (!iComposer->setField(connectionKey, &connectionValue)) return false;
     88 
     89 
     90     return setExtensionFields(iCfgFile->getExtensionHeaderKeys(),
     91                               iCfgFile->getExtensionHeaderValues(),
     92                               iCfgFile->getHTTPMethodMasksForExtensionHeader(),
     93                               iCfgFile->getExtensionHeadersPurgeOnRedirect());
     94 }
     95 
     96 OSCL_EXPORT_REF bool ProgressiveDownloadState_GET::setRangeHeaderFields()
     97 {
     98     if (iRangeHeaderSupported)
     99     {
    100         // only send Range header for previous non-zero bytes position.
    101         // Some server may not like this, Range: bytes=0-
    102         if (iCfgFile->GetCurrentFileSize() > 0 && iCfgFile->GetOverallFileSize() > 0)
    103         {
    104             StrCSumPtrLen rangeKey = "Range";
    105             char buffer[64];
    106             oscl_snprintf(buffer, 64, "bytes=%d-%d", iCfgFile->GetCurrentFileSize(), iCfgFile->GetOverallFileSize());
    107             LOGINFODATAPATH((0, "ProgressiveDownloadState_GET::setHeaderFields(), Range: bytes=%d-", iCfgFile->GetCurrentFileSize()));
    108             if (!iComposer->setField(rangeKey, buffer)) return false;
    109         }
    110     }
    111     return true;
    112 }
    113 
    114 OSCL_EXPORT_REF int32 ProgressiveDownloadState_GET::updateDownloadStatistics()
    115 {
    116     int32 status = DownloadState::updateDownloadStatistics();
    117     if (status == PROCESS_SUCCESS_END_OF_MESSAGE_TRUNCATED)
    118     {
    119         iSendEndOfMessageTruncate = true;
    120     }
    121     return status;
    122 }
    123 
    124 
    125 OSCL_EXPORT_REF int32 ProgressiveDownloadState_GET::checkParsingStatus(int32 parsingStatus)
    126 {
    127     // EOS means connection is down, and can be treated as download complete
    128     if (parsingStatus == HttpParsingBasicObject::PARSE_EOS_INPUT_DATA)
    129     {
    130         if (iParser->getDownloadSize() > 0 && iParser->isDownloadReallyHappen())
    131         {
    132             iCfgFile->SetCurrentFileSize(iParser->getDownloadSize());
    133             if (iParser->getContentLength() == 0) iCfgFile->SetOverallFileSize(iParser->getDownloadSize());
    134             LOGINFODATAPATH((0, "ProgressiveDownloadState_GET::checkParsingStatus(), GOT EOS and COMPLETE DOWNLOAD, downloadSize=%d, contentLength=%d, isDownloadHappen=%d",
    135                              iParser->getDownloadSize(), iParser->getContentLength(), (int32)iParser->isDownloadReallyHappen()));
    136             return PROCESS_SUCCESS_END_OF_MESSAGE_BY_SERVER_DISCONNECT;
    137         }
    138     }
    139 
    140     // download complete with truncation
    141     if (iSendEndOfMessageTruncate)
    142     {
    143         iSendEndOfMessageTruncate = false;
    144         return PROCESS_SUCCESS_END_OF_MESSAGE_TRUNCATED;
    145     }
    146 
    147     return DownloadState::checkParsingStatus(parsingStatus);
    148 }
    149 
    150 
    151 // From HttpParsingBasicObjectObserver
    152 OSCL_EXPORT_REF int32 ProgressiveDownloadState_GET::OutputDataAvailable(OUTPUT_DATA_QUEUE *aOutputQueue, const bool isHttpHeader)
    153 {
    154     if (isHttpHeader)
    155     {
    156         int32 status = checkContentInfoMatchingForResumeDownload();
    157         if (status != HttpParsingBasicObject::PARSE_SUCCESS) return status;
    158 
    159         iDataSideInfo.set(ProtocolEngineOutputDataType_HttpHeader);
    160         iObserver->OutputDataAvailable(*aOutputQueue, iDataSideInfo);
    161     }
    162     else    // output data to data stream object
    163     {
    164         if (iParser->getDownloadSize() > iCfgFile->GetCurrentFileSize())
    165         {
    166             updateOutputDataQueue(aOutputQueue); // aOutputQueue could have the partial valid data for resume download and trucated content case
    167             iDataSideInfo.set(ProtocolEngineOutputDataType_NormalData);
    168             iObserver->OutputDataAvailable(*aOutputQueue, iDataSideInfo);
    169             return updateDownloadStatistics(); // could return PROCESS_SUCCESS_END_OF_MESSAGE_TRUNCATED
    170         }
    171     }
    172     return HttpParsingBasicObject::PARSE_SUCCESS;
    173 }
    174 
    175 OSCL_EXPORT_REF int32 ProgressiveDownloadState_GET::checkContentInfoMatchingForResumeDownload()
    176 {
    177     if (iCfgFile->IsNewSession()) return HttpParsingBasicObject::PARSE_SUCCESS;
    178     uint32 prevOverallFileSize = iCfgFile->GetOverallFileSize();
    179     if (iCfgFile->GetOverallFileSize() == iCfgFile->GetMaxAllowedFileSize() && !iCfgFile->HasContentLength())
    180     {
    181         prevOverallFileSize = 0; // no content-length for the previous download
    182     }
    183     int32 status = iParser->isNewContentRangeInfoMatchingCurrentOne(prevOverallFileSize);
    184     // Get internal download size synced up with new content-range info
    185     iParser->setDownloadSize();
    186     return status;
    187 }
    188 
    189 OSCL_EXPORT_REF void ProgressiveDownloadState_GET::updateOutputDataQueue(OUTPUT_DATA_QUEUE *aOutputQueue)
    190 {
    191     // get start fragment especially for resume download case
    192     bool aUseAllNewDownloadData;
    193     uint32 aStartFragNo = 0, aStartFragOffset = 0;
    194     getStartFragmentInNewDownloadData(*aOutputQueue, aUseAllNewDownloadData, aStartFragNo, aStartFragOffset);
    195     if (aUseAllNewDownloadData) return;
    196 
    197     LOGINFODATAPATH((0, "ProgressiveDownloadState_GET::updateOutputDataQueue()->getStartFragmentInNewDownloadData() : aOutputQueue->size=%d, aStartFragNo=%d, aStartFragOffset=%d",
    198                      aOutputQueue->size(), aStartFragNo, aStartFragOffset));
    199 
    200     LOGINFODATAPATH((0, "ProgressiveDownloadState_GET::updateOutputDataQueue()->getStartFragmentInNewDownloadData() : downloadSize=%d, currFileSize=%d",
    201                      iParser->getDownloadSize(), iCfgFile->GetCurrentFileSize()));
    202 
    203     // process start fragment
    204     if (!(aStartFragNo == 0 && aStartFragOffset == 0))   // exist offset
    205     {
    206         OsclMemoryFragment memFrag;
    207         uint8 *startPtr = (uint8*)((*aOutputQueue)[aStartFragNo].getMemFragPtr()) + aStartFragOffset;
    208         memFrag.ptr = (OsclAny*)startPtr;
    209         memFrag.len = (*aOutputQueue)[aStartFragNo].getMemFragSize() - aStartFragOffset;
    210         OsclRefCounter *refcnt = (*aOutputQueue)[aStartFragNo].getRefCounter();
    211         OsclRefCounterMemFrag refCountMemFrag = OsclRefCounterMemFrag(memFrag, refcnt, memFrag.len);
    212         refcnt->addRef(); // manually add reference counter since there will be vector push_back happens.
    213 
    214         for (uint32 i = 0; i <= aStartFragNo; i++)
    215         {
    216             aOutputQueue->erase(aOutputQueue->begin());
    217         }
    218         if (memFrag.len > 0) aOutputQueue->push_front(refCountMemFrag);
    219 
    220         LOGINFODATAPATH((0, "ProgressiveDownloadState_GET::updateOutputDataQueue() after processing start fragment: aOutputQueue->size=%d", aOutputQueue->size()));
    221     }
    222 
    223     // get end fragment especially for truncated content case
    224     uint32 aEndFragNo = 0, aEndFragValidLen = 0;
    225     getEndFragmentInNewDownloadData(*aOutputQueue, aEndFragNo, aEndFragValidLen);
    226 
    227     LOGINFODATAPATH((0, "ProgressiveDownloadState_GET::updateOutputDataQueue()->getEndFragmentInNewDownloadData() : aOutputQueue->size=%d, aEndFragNo=%d, aEndFragValidLen=%d",
    228                      aOutputQueue->size(), aEndFragNo, aEndFragValidLen));
    229 
    230     LOGINFODATAPATH((0, "ProgressiveDownloadState_GET::updateOutputDataQueue()->getStartFragmentInNewDownloadData() : downloadSize=%d, overallFileSize=%d",
    231                      iParser->getDownloadSize(), iCfgFile->GetOverallFileSize()));
    232 
    233     // process end fragment
    234     if (!(aEndFragNo == aOutputQueue->size() - 1 &&
    235             aEndFragValidLen == (*aOutputQueue)[aEndFragNo].getMemFragSize()))
    236     {
    237         OsclMemoryFragment memFrag;
    238         memFrag.ptr = (*aOutputQueue)[aEndFragNo].getMemFragPtr();
    239         memFrag.len = aEndFragValidLen;
    240         OsclRefCounter *refcnt = (*aOutputQueue)[aEndFragNo].getRefCounter();
    241         OsclRefCounterMemFrag refCountMemFrag = OsclRefCounterMemFrag(memFrag, refcnt, memFrag.len);
    242         refcnt->addRef(); // manually add reference counter since there will be vector push_back happens.
    243 
    244         for (int32 j = (int32)aOutputQueue->size() - 1; j >= (int32)aEndFragNo; j--)
    245         {
    246             aOutputQueue->erase(&(aOutputQueue->back()));
    247         }
    248 
    249         aOutputQueue->push_back(refCountMemFrag);
    250 
    251         LOGINFODATAPATH((0, "ProgressiveDownloadState_GET::updateOutputDataQueue() after processing end fragment: aOutputQueue->size=%d", aOutputQueue->size()));
    252     }
    253 }
    254 
    255 OSCL_EXPORT_REF void ProgressiveDownloadState_GET::getStartFragmentInNewDownloadData(OUTPUT_DATA_QUEUE &aOutputQueue,
    256         bool &aUseAllNewDownloadData,
    257         uint32 &aStartFragNo,
    258         uint32 &aStartFragOffset)
    259 {
    260     aUseAllNewDownloadData = false;
    261     aStartFragNo = aStartFragOffset = 0;
    262 
    263     uint32 validSize = iParser->getDownloadSize() - iCfgFile->GetCurrentFileSize();
    264 
    265     uint32 totalSize = 0, prevTotalSize = 0;
    266     for (uint32 i = 0; i < aOutputQueue.size(); i++)
    267     {
    268         prevTotalSize = totalSize;
    269         totalSize += aOutputQueue[i].getMemFragSize();
    270         if (prevTotalSize <= validSize && validSize < totalSize)
    271         {
    272             if (validSize < totalSize && i < aOutputQueue.size() - 1)
    273             {
    274                 aStartFragNo = i;
    275                 aStartFragOffset = validSize - prevTotalSize;
    276                 return;
    277             }
    278         }
    279     }
    280 
    281     aUseAllNewDownloadData = (validSize == totalSize) &
    282                              (iParser->getDownloadSize() <= iCfgFile->GetOverallFileSize());
    283 }
    284 
    285 OSCL_EXPORT_REF void ProgressiveDownloadState_GET::getEndFragmentInNewDownloadData(OUTPUT_DATA_QUEUE &aOutputQueue,
    286         uint32 &aEndFragNo,
    287         uint32 &aEndFragValidLen)
    288 {
    289     aEndFragNo = aOutputQueue.size() - 1;
    290     aEndFragValidLen = aOutputQueue[aEndFragNo].getMemFragSize();
    291 
    292     if (iParser->getDownloadSize() > iCfgFile->GetOverallFileSize())
    293     {
    294         uint32 extraSize = iParser->getDownloadSize() - iCfgFile->GetOverallFileSize();
    295         uint32 reduceSize = 0, prevReduceSize = 0;
    296         for (int32 i = aOutputQueue.size() - 1; i >= 0; i--)
    297         {
    298             prevReduceSize = reduceSize;
    299             reduceSize += aOutputQueue[i].getMemFragSize();
    300             if (prevReduceSize <= extraSize && extraSize < reduceSize)
    301             {
    302                 aEndFragNo = i;
    303                 aEndFragValidLen = reduceSize - extraSize;
    304                 return;
    305             }
    306         }
    307     }
    308 }
    309 
    310 ////////////////////////////////////////////////////////////////////////////////////
    311 //////  ProgressiveStreamingState implementation
    312 ////////////////////////////////////////////////////////////////////////////////////
    313 
    314 OSCL_EXPORT_REF int32 ProgressiveStreamingState_GET::checkParsingStatus(int32 parsingStatus)
    315 {
    316     // download complete with truncation
    317     if (iSendEndOfMessageTruncate)
    318     {
    319         iSendEndOfMessageTruncate = false;
    320         return PROCESS_SUCCESS_END_OF_MESSAGE_TRUNCATED;
    321     }
    322 
    323     return DownloadState::checkParsingStatus(parsingStatus);
    324 }
    325 
    326