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