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