• 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_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 ////////////////////////////////////////////////////////////////////////////////////
getValidMediaData(INPUT_DATA_QUEUE & aDataInQueue,PVMFSharedMediaDataPtr & aMediaData,bool & isEOS)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 
isValidInput()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 ////////////////////////////////////////////////////////////////////////////////////
setURI(OSCL_wString & aUri,const bool aRedirectURI)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 
getHostAndPort(OSCL_String & aSerAdd,int32 & aSerPort)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 
parseURL(OSCL_String & aUrl8,OSCL_String & aSerAdd,int32 & aSerPort)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 ////////////////////////////////////////////////////////////////////////////////////
parseResponse(INPUT_DATA_QUEUE & aDataQueue)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 
getNextMediaData(INPUT_DATA_QUEUE & aDataInQueue,PVMFSharedMediaDataPtr & aMediaData)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 
validateEOSInput(int32 parsingStatus)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 
extractServerVersionNum()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 
saveOutputData(RefCountHTTPEntityUnit & entityUnit,OUTPUT_DATA_QUEUE & aOutputData,uint32 & aTotalEntityDataSize)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 
checkParsingDone(const int32 parsingStatus)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 
isRedirectResponse()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
create()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 
construct()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 
setDownloadSize(const uint32 aInitialSize)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 
getRedirectURI(OSCL_String & aRedirectUri)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 
getContentType(OSCL_String & aContentType)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 
isServerSupportBasicAuthentication()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 
getAuthenInfo(OSCL_String & aRealm)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 
getRealmPtr(const char * & ptrRealm,uint32 & len,uint32 & length)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 
getBasicPtr(const StrPtrLen aAuthenValue,uint32 & length)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 
isServerSendAuthenticationHeader()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 
isNewContentRangeInfoMatchingCurrentOne(const uint32 aPrevContentLength)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 ////////////////////////////////////////////////////////////////////////////////////
processMicroState(INPUT_DATA_QUEUE & aDataQueue)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 
doProcessMicroStateSendRequestPreCheck()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 
doProcessMicroStateSendRequest()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 
doProcessMicroStateGetResponsePreCheck()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 
doProcessMicroStateGetResponse(INPUT_DATA_QUEUE & aDataQueue)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 
processMicroStateSendRequestPreCheck()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 
processMicroStateSendRequest()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 
composeRequest(OsclMemoryFragment & aFrag)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 
doCompose(OsclMemoryFragment & aFrag)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 
processMicroStateGetResponsePreCheck()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 
processMicroStateGetResponse(INPUT_DATA_QUEUE & aDataQueue)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
checkParsingStatus(int32 parsingStatus)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 
handleParsingSyntaxError()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 
getDownloadRate()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 
getDownloadTimeForEstimation()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 
setExtensionFields(Oscl_Vector<OSCL_HeapString<OsclMemAllocator>,OsclMemAllocator> & aExtensionHeaderKeys,Oscl_Vector<OSCL_HeapString<OsclMemAllocator>,OsclMemAllocator> & aExtensionHeaderValues,Oscl_Vector<uint32,OsclMemAllocator> & aMaskBitForHTTPMethod,Oscl_Vector<bool,OsclMemAllocator> & aExtensionHeadersPurgeOnRedirect,const HTTPMethod aMethod)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 
getBitMaskForHttpMethod(Oscl_Vector<uint32,OsclMemAllocator> & aMaskBitForHTTPMethod,const HTTPMethod aMethod)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 
constructAuthenHeader(OSCL_String & aUserID,OSCL_String & aPasswd)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+/=";
base64enc(char * data,char * out)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