• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 ////////////////////////////
setRequestBasics()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 
setHeaderFields()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 
checkParsingStatus(int32 parsingStatus)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 
OutputDataAvailable(OUTPUT_DATA_QUEUE * aOutputQueue,const bool isHttpHeader)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 ////////////////////////////
processMicroStateGetResponsePreCheck()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 
setHeaderFields()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 
setRangeHeaderFields()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 
updateDownloadStatistics()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 
checkParsingStatus(int32 parsingStatus)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
OutputDataAvailable(OUTPUT_DATA_QUEUE * aOutputQueue,const bool isHttpHeader)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 
checkContentInfoMatchingForResumeDownload()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 
updateOutputDataQueue(OUTPUT_DATA_QUEUE * aOutputQueue)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 
getStartFragmentInNewDownloadData(OUTPUT_DATA_QUEUE & aOutputQueue,bool & aUseAllNewDownloadData,uint32 & aStartFragNo,uint32 & aStartFragOffset)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 
getEndFragmentInNewDownloadData(OUTPUT_DATA_QUEUE & aOutputQueue,uint32 & aEndFragNo,uint32 & aEndFragValidLen)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 
checkParsingStatus(int32 parsingStatus)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