1 /* 2 * Copyright 2010-2014 Haiku Inc. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Christophe Huriaux, c.huriaux@gmail.com 7 * Hamish Morrison, hamishm53@gmail.com 8 */ 9 10 11 #include <new> 12 #include <stdio.h> 13 14 #include <HashMap.h> 15 #include <HashString.h> 16 #include <Message.h> 17 #include <NetworkCookieJar.h> 18 19 #include "NetworkCookieJarPrivate.h" 20 21 using namespace BPrivate::Network; 22 23 24 // #define TRACE_COOKIE 25 #ifdef TRACE_COOKIE 26 # define TRACE(x...) printf(x) 27 #else 28 # define TRACE(x...) ; 29 #endif 30 31 32 const char* kArchivedCookieMessageName = "be:cookie"; 33 34 35 BNetworkCookieJar::BNetworkCookieJar() 36 : 37 fCookieHashMap(new(std::nothrow) PrivateHashMap()) 38 { 39 } 40 41 42 BNetworkCookieJar::BNetworkCookieJar(const BNetworkCookieJar& other) 43 : 44 fCookieHashMap(new(std::nothrow) PrivateHashMap()) 45 { 46 *this = other; 47 } 48 49 50 BNetworkCookieJar::BNetworkCookieJar(const BNetworkCookieList& otherList) 51 : 52 fCookieHashMap(new(std::nothrow) PrivateHashMap()) 53 { 54 AddCookies(otherList); 55 } 56 57 58 BNetworkCookieJar::BNetworkCookieJar(BMessage* archive) 59 : 60 fCookieHashMap(new(std::nothrow) PrivateHashMap()) 61 { 62 BMessage extractedCookie; 63 64 for (int32 i = 0; archive->FindMessage(kArchivedCookieMessageName, i, 65 &extractedCookie) == B_OK; i++) { 66 BNetworkCookie* heapCookie 67 = new(std::nothrow) BNetworkCookie(&extractedCookie); 68 69 if (heapCookie == NULL) 70 break; 71 72 if (AddCookie(heapCookie) != B_OK) { 73 delete heapCookie; 74 continue; 75 } 76 } 77 } 78 79 80 BNetworkCookieJar::~BNetworkCookieJar() 81 { 82 for (Iterator it = GetIterator(); it.Next() != NULL;) 83 delete it.Remove(); 84 85 fCookieHashMap->Lock(); 86 87 PrivateHashMap::Iterator it = fCookieHashMap->GetIterator(); 88 while (it.HasNext()) { 89 BNetworkCookieList* list = it.Next().value; 90 list->LockForWriting(); 91 delete list; 92 } 93 94 delete fCookieHashMap; 95 } 96 97 98 // #pragma mark Add cookie to cookie jar 99 100 101 status_t 102 BNetworkCookieJar::AddCookie(const BNetworkCookie& cookie) 103 { 104 BNetworkCookie* heapCookie = new(std::nothrow) BNetworkCookie(cookie); 105 if (heapCookie == NULL) 106 return B_NO_MEMORY; 107 108 status_t result = AddCookie(heapCookie); 109 if (result != B_OK) 110 delete heapCookie; 111 112 return result; 113 } 114 115 116 status_t 117 BNetworkCookieJar::AddCookie(const BString& cookie, const BUrl& referrer) 118 { 119 BNetworkCookie* heapCookie = new(std::nothrow) BNetworkCookie(cookie, 120 referrer); 121 122 if (heapCookie == NULL) 123 return B_NO_MEMORY; 124 125 status_t result = AddCookie(heapCookie); 126 127 if (result != B_OK) 128 delete heapCookie; 129 130 return result; 131 } 132 133 134 status_t 135 BNetworkCookieJar::AddCookie(BNetworkCookie* cookie) 136 { 137 if (fCookieHashMap == NULL) 138 return B_NO_MEMORY; 139 140 if (cookie == NULL || !cookie->IsValid()) 141 return B_BAD_VALUE; 142 143 HashString key(cookie->Domain()); 144 145 if (!fCookieHashMap->Lock()) 146 return B_ERROR; 147 148 // Get the cookies for the requested domain, or create a new list if there 149 // isn't one yet. 150 BNetworkCookieList* list = fCookieHashMap->Get(key); 151 if (list == NULL) { 152 list = new(std::nothrow) BNetworkCookieList(); 153 154 if (list == NULL) { 155 fCookieHashMap->Unlock(); 156 return B_NO_MEMORY; 157 } 158 159 if (fCookieHashMap->Put(key, list) != B_OK) { 160 fCookieHashMap->Unlock(); 161 delete list; 162 return B_NO_MEMORY; 163 } 164 } 165 166 if (list->LockForWriting() != B_OK) { 167 fCookieHashMap->Unlock(); 168 return B_ERROR; 169 } 170 171 fCookieHashMap->Unlock(); 172 173 // Remove any cookie with the same key as the one we're trying to add (it 174 // replaces/updates them) 175 for (int32 i = 0; i < list->CountItems(); i++) { 176 const BNetworkCookie* c = list->ItemAt(i); 177 178 if (c->Name() == cookie->Name() && c->Path() == cookie->Path()) { 179 list->RemoveItemAt(i); 180 break; 181 } 182 } 183 184 // If the cookie has an expiration date in the past, stop here: we 185 // effectively deleted a cookie. 186 if (cookie->ShouldDeleteNow()) { 187 TRACE("Remove cookie: %s\n", cookie->RawCookie(true).String()); 188 delete cookie; 189 } else { 190 // Make sure the cookie has cached the raw string and expiration date 191 // string, so it is now actually immutable. This way we can safely 192 // read the cookie data from multiple threads without any locking. 193 const BString& raw = cookie->RawCookie(true); 194 (void)raw; 195 196 TRACE("Add cookie: %s\n", raw.String()); 197 198 // Keep the list sorted by path length (longest first). This makes sure 199 // that cookies for most specific paths are returned first when 200 // iterating the cookie jar. 201 int32 i; 202 for (i = 0; i < list->CountItems(); i++) { 203 const BNetworkCookie* current = list->ItemAt(i); 204 if (current->Path().Length() < cookie->Path().Length()) 205 break; 206 } 207 list->AddItem(cookie, i); 208 } 209 210 list->Unlock(); 211 212 return B_OK; 213 } 214 215 216 status_t 217 BNetworkCookieJar::AddCookies(const BNetworkCookieList& cookies) 218 { 219 for (int32 i = 0; i < cookies.CountItems(); i++) { 220 const BNetworkCookie* cookiePtr = cookies.ItemAt(i); 221 222 // Using AddCookie by reference in order to avoid multiple 223 // cookie jar share the same cookie pointers 224 status_t result = AddCookie(*cookiePtr); 225 if (result != B_OK) 226 return result; 227 } 228 229 return B_OK; 230 } 231 232 233 // #pragma mark Purge useless cookies 234 235 236 uint32 237 BNetworkCookieJar::DeleteOutdatedCookies() 238 { 239 int32 deleteCount = 0; 240 const BNetworkCookie* cookiePtr; 241 242 for (Iterator it = GetIterator(); (cookiePtr = it.Next()) != NULL;) { 243 if (cookiePtr->ShouldDeleteNow()) { 244 delete it.Remove(); 245 deleteCount++; 246 } 247 } 248 249 return deleteCount; 250 } 251 252 253 uint32 254 BNetworkCookieJar::PurgeForExit() 255 { 256 int32 deleteCount = 0; 257 const BNetworkCookie* cookiePtr; 258 259 for (Iterator it = GetIterator(); (cookiePtr = it.Next()) != NULL;) { 260 if (cookiePtr->ShouldDeleteAtExit()) { 261 delete it.Remove(); 262 deleteCount++; 263 } 264 } 265 266 return deleteCount; 267 } 268 269 270 // #pragma mark BArchivable interface 271 272 273 status_t 274 BNetworkCookieJar::Archive(BMessage* into, bool deep) const 275 { 276 status_t error = BArchivable::Archive(into, deep); 277 278 if (error == B_OK) { 279 const BNetworkCookie* cookiePtr; 280 281 for (Iterator it = GetIterator(); (cookiePtr = it.Next()) != NULL;) { 282 BMessage subArchive; 283 284 error = cookiePtr->Archive(&subArchive, deep); 285 if (error != B_OK) 286 return error; 287 288 error = into->AddMessage(kArchivedCookieMessageName, &subArchive); 289 if (error != B_OK) 290 return error; 291 } 292 } 293 294 return error; 295 } 296 297 298 BArchivable* 299 BNetworkCookieJar::Instantiate(BMessage* archive) 300 { 301 if (archive->HasMessage(kArchivedCookieMessageName)) 302 return new(std::nothrow) BNetworkCookieJar(archive); 303 304 return NULL; 305 } 306 307 308 // #pragma mark BFlattenable interface 309 310 311 bool 312 BNetworkCookieJar::IsFixedSize() const 313 { 314 // Flattened size vary 315 return false; 316 } 317 318 319 type_code 320 BNetworkCookieJar::TypeCode() const 321 { 322 // TODO: Add a B_COOKIEJAR_TYPE 323 return B_ANY_TYPE; 324 } 325 326 327 ssize_t 328 BNetworkCookieJar::FlattenedSize() const 329 { 330 _DoFlatten(); 331 return fFlattened.Length() + 1; 332 } 333 334 335 status_t 336 BNetworkCookieJar::Flatten(void* buffer, ssize_t size) const 337 { 338 if (FlattenedSize() > size) 339 return B_ERROR; 340 341 fFlattened.CopyInto(reinterpret_cast<char*>(buffer), 0, 342 fFlattened.Length()); 343 reinterpret_cast<char*>(buffer)[fFlattened.Length()] = 0; 344 345 return B_OK; 346 } 347 348 349 bool 350 BNetworkCookieJar::AllowsTypeCode(type_code) const 351 { 352 // TODO 353 return false; 354 } 355 356 357 status_t 358 BNetworkCookieJar::Unflatten(type_code, const void* buffer, ssize_t size) 359 { 360 BString flattenedCookies; 361 flattenedCookies.SetTo(reinterpret_cast<const char*>(buffer), size); 362 363 while (flattenedCookies.Length() > 0) { 364 BNetworkCookie tempCookie; 365 BString tempCookieLine; 366 367 int32 endOfLine = flattenedCookies.FindFirst('\n', 0); 368 if (endOfLine == -1) 369 tempCookieLine = flattenedCookies; 370 else { 371 flattenedCookies.MoveInto(tempCookieLine, 0, endOfLine); 372 flattenedCookies.Remove(0, 1); 373 } 374 375 if (tempCookieLine.Length() != 0 && tempCookieLine[0] != '#') { 376 for (int32 field = 0; field < 7; field++) { 377 BString tempString; 378 379 int32 endOfField = tempCookieLine.FindFirst('\t', 0); 380 if (endOfField == -1) 381 tempString = tempCookieLine; 382 else { 383 tempCookieLine.MoveInto(tempString, 0, endOfField); 384 tempCookieLine.Remove(0, 1); 385 } 386 387 switch (field) { 388 case 0: 389 tempCookie.SetDomain(tempString); 390 break; 391 392 case 1: 393 // TODO: Useless field ATM 394 break; 395 396 case 2: 397 tempCookie.SetPath(tempString); 398 break; 399 400 case 3: 401 tempCookie.SetSecure(tempString == "TRUE"); 402 break; 403 404 case 4: 405 tempCookie.SetExpirationDate(atoi(tempString)); 406 break; 407 408 case 5: 409 tempCookie.SetName(tempString); 410 break; 411 412 case 6: 413 tempCookie.SetValue(tempString); 414 break; 415 } // switch 416 } // for loop 417 418 AddCookie(tempCookie); 419 } 420 } 421 422 return B_OK; 423 } 424 425 426 BNetworkCookieJar& 427 BNetworkCookieJar::operator=(const BNetworkCookieJar& other) 428 { 429 if (&other == this) 430 return *this; 431 432 for (Iterator it = GetIterator(); it.Next() != NULL;) 433 delete it.Remove(); 434 435 BArchivable::operator=(other); 436 BFlattenable::operator=(other); 437 438 fFlattened = other.fFlattened; 439 440 delete fCookieHashMap; 441 fCookieHashMap = new(std::nothrow) PrivateHashMap(); 442 443 for (Iterator it = other.GetIterator(); it.HasNext();) { 444 const BNetworkCookie* cookie = it.Next(); 445 AddCookie(*cookie); // Pass by reference so the cookie is copied. 446 } 447 448 return *this; 449 } 450 451 452 // #pragma mark Iterators 453 454 455 BNetworkCookieJar::Iterator 456 BNetworkCookieJar::GetIterator() const 457 { 458 return BNetworkCookieJar::Iterator(this); 459 } 460 461 462 BNetworkCookieJar::UrlIterator 463 BNetworkCookieJar::GetUrlIterator(const BUrl& url) const 464 { 465 if (!url.HasPath()) { 466 BUrl copy(url); 467 copy.SetPath("/"); 468 return BNetworkCookieJar::UrlIterator(this, copy); 469 } 470 471 return BNetworkCookieJar::UrlIterator(this, url); 472 } 473 474 475 void 476 BNetworkCookieJar::_DoFlatten() const 477 { 478 fFlattened.Truncate(0); 479 480 const BNetworkCookie* cookiePtr; 481 for (Iterator it = GetIterator(); (cookiePtr = it.Next()) != NULL;) { 482 fFlattened << cookiePtr->Domain() << '\t' << "TRUE" << '\t' 483 << cookiePtr->Path() << '\t' 484 << (cookiePtr->Secure()?"TRUE":"FALSE") << '\t' 485 << (int32)cookiePtr->ExpirationDate() << '\t' 486 << cookiePtr->Name() << '\t' << cookiePtr->Value() << '\n'; 487 } 488 } 489 490 491 // #pragma mark Iterator 492 493 494 BNetworkCookieJar::Iterator::Iterator(const Iterator& other) 495 : 496 fCookieJar(other.fCookieJar), 497 fIterator(NULL), 498 fLastList(NULL), 499 fList(NULL), 500 fElement(NULL), 501 fLastElement(NULL), 502 fIndex(0) 503 { 504 fIterator = new(std::nothrow) PrivateIterator( 505 fCookieJar->fCookieHashMap->GetIterator()); 506 507 _FindNext(); 508 } 509 510 511 BNetworkCookieJar::Iterator::Iterator(const BNetworkCookieJar* cookieJar) 512 : 513 fCookieJar(const_cast<BNetworkCookieJar*>(cookieJar)), 514 fIterator(NULL), 515 fLastList(NULL), 516 fList(NULL), 517 fElement(NULL), 518 fLastElement(NULL), 519 fIndex(0) 520 { 521 fIterator = new(std::nothrow) PrivateIterator( 522 fCookieJar->fCookieHashMap->GetIterator()); 523 524 // Locate first cookie 525 _FindNext(); 526 } 527 528 529 BNetworkCookieJar::Iterator::~Iterator() 530 { 531 if (fList != NULL) 532 fList->Unlock(); 533 if (fLastList != NULL) 534 fLastList->Unlock(); 535 536 delete fIterator; 537 } 538 539 540 BNetworkCookieJar::Iterator& 541 BNetworkCookieJar::Iterator::operator=(const Iterator& other) 542 { 543 if (this == &other) 544 return *this; 545 546 delete fIterator; 547 if (fList != NULL) 548 fList->Unlock(); 549 550 fCookieJar = other.fCookieJar; 551 fIterator = NULL; 552 fLastList = NULL; 553 fList = NULL; 554 fElement = NULL; 555 fLastElement = NULL; 556 fIndex = 0; 557 558 fIterator = new(std::nothrow) PrivateIterator( 559 fCookieJar->fCookieHashMap->GetIterator()); 560 561 _FindNext(); 562 563 return *this; 564 } 565 566 567 bool 568 BNetworkCookieJar::Iterator::HasNext() const 569 { 570 return fElement; 571 } 572 573 574 const BNetworkCookie* 575 BNetworkCookieJar::Iterator::Next() 576 { 577 if (!fElement) 578 return NULL; 579 580 const BNetworkCookie* result = fElement; 581 _FindNext(); 582 return result; 583 } 584 585 586 const BNetworkCookie* 587 BNetworkCookieJar::Iterator::NextDomain() 588 { 589 if (!fElement) 590 return NULL; 591 592 const BNetworkCookie* result = fElement; 593 594 if (!fIterator->fCookieMapIterator.HasNext()) { 595 fElement = NULL; 596 return result; 597 } 598 599 if (fList != NULL) 600 fList->Unlock(); 601 602 if (fCookieJar->fCookieHashMap->Lock()) { 603 fList = fIterator->fCookieMapIterator.Next().value; 604 fList->LockForReading(); 605 606 while (fList->CountItems() == 0 607 && fIterator->fCookieMapIterator.HasNext()) { 608 // Empty list. Skip it 609 fList->Unlock(); 610 fList = fIterator->fCookieMapIterator.Next().value; 611 fList->LockForReading(); 612 } 613 614 fCookieJar->fCookieHashMap->Unlock(); 615 } 616 617 fIndex = 0; 618 fElement = fList->ItemAt(fIndex); 619 return result; 620 } 621 622 623 const BNetworkCookie* 624 BNetworkCookieJar::Iterator::Remove() 625 { 626 if (!fLastElement) 627 return NULL; 628 629 const BNetworkCookie* result = fLastElement; 630 631 if (fIndex == 0) { 632 if (fLastList && fCookieJar->fCookieHashMap->Lock()) { 633 // We are on the first item of fList, so we need to remove the 634 // last of fLastList 635 fLastList->Unlock(); 636 if (fLastList->LockForWriting() == B_OK) { 637 fLastList->RemoveItemAt(fLastList->CountItems() - 1); 638 // TODO if the list became empty, we could remove it from the 639 // map, but this can be a problem if other iterators are still 640 // referencing it. Is there a safe place and locking pattern 641 // where we can do that? 642 fLastList->Unlock(); 643 fLastList->LockForReading(); 644 } 645 fCookieJar->fCookieHashMap->Unlock(); 646 } 647 } else { 648 fIndex--; 649 650 if (fCookieJar->fCookieHashMap->Lock()) { 651 // Switch to a write lock 652 fList->Unlock(); 653 if (fList->LockForWriting() == B_OK) { 654 fList->RemoveItemAt(fIndex); 655 fList->Unlock(); 656 } 657 fList->LockForReading(); 658 fCookieJar->fCookieHashMap->Unlock(); 659 } 660 } 661 662 fLastElement = NULL; 663 return result; 664 } 665 666 667 void 668 BNetworkCookieJar::Iterator::_FindNext() 669 { 670 fLastElement = fElement; 671 672 fIndex++; 673 if (fList && fIndex < fList->CountItems()) { 674 // Get an element from the current list 675 fElement = fList->ItemAt(fIndex); 676 return; 677 } 678 679 if (fIterator == NULL || !fIterator->fCookieMapIterator.HasNext()) { 680 // We are done iterating 681 fElement = NULL; 682 return; 683 } 684 685 // Get an element from the next list 686 if (fLastList != NULL) { 687 fLastList->Unlock(); 688 } 689 fLastList = fList; 690 691 if (fCookieJar->fCookieHashMap->Lock()) { 692 fList = (fIterator->fCookieMapIterator.Next().value); 693 fList->LockForReading(); 694 695 while (fList->CountItems() == 0 696 && fIterator->fCookieMapIterator.HasNext()) { 697 // Empty list. Skip it 698 fList->Unlock(); 699 fList = fIterator->fCookieMapIterator.Next().value; 700 fList->LockForReading(); 701 } 702 703 fCookieJar->fCookieHashMap->Unlock(); 704 } 705 706 fIndex = 0; 707 fElement = fList->ItemAt(fIndex); 708 } 709 710 711 // #pragma mark URL Iterator 712 713 714 BNetworkCookieJar::UrlIterator::UrlIterator(const UrlIterator& other) 715 : 716 fCookieJar(other.fCookieJar), 717 fIterator(NULL), 718 fList(NULL), 719 fLastList(NULL), 720 fElement(NULL), 721 fLastElement(NULL), 722 fIndex(0), 723 fLastIndex(0), 724 fUrl(other.fUrl) 725 { 726 _Initialize(); 727 } 728 729 730 BNetworkCookieJar::UrlIterator::UrlIterator(const BNetworkCookieJar* cookieJar, 731 const BUrl& url) 732 : 733 fCookieJar(const_cast<BNetworkCookieJar*>(cookieJar)), 734 fIterator(NULL), 735 fList(NULL), 736 fLastList(NULL), 737 fElement(NULL), 738 fLastElement(NULL), 739 fIndex(0), 740 fLastIndex(0), 741 fUrl(url) 742 { 743 _Initialize(); 744 } 745 746 747 BNetworkCookieJar::UrlIterator::~UrlIterator() 748 { 749 if (fList != NULL) 750 fList->Unlock(); 751 if (fLastList != NULL) 752 fLastList->Unlock(); 753 754 delete fIterator; 755 } 756 757 758 bool 759 BNetworkCookieJar::UrlIterator::HasNext() const 760 { 761 return fElement; 762 } 763 764 765 const BNetworkCookie* 766 BNetworkCookieJar::UrlIterator::Next() 767 { 768 if (!fElement) 769 return NULL; 770 771 const BNetworkCookie* result = fElement; 772 _FindNext(); 773 return result; 774 } 775 776 777 const BNetworkCookie* 778 BNetworkCookieJar::UrlIterator::Remove() 779 { 780 if (!fLastElement) 781 return NULL; 782 783 const BNetworkCookie* result = fLastElement; 784 785 if (fCookieJar->fCookieHashMap->Lock()) { 786 fLastList->Unlock(); 787 if (fLastList->LockForWriting() == B_OK) { 788 fLastList->RemoveItemAt(fLastIndex); 789 790 if (fLastList->CountItems() == 0) { 791 fCookieJar->fCookieHashMap->Remove(fIterator->fCookieMapIterator); 792 delete fLastList; 793 fLastList = NULL; 794 } else { 795 fLastList->Unlock(); 796 fLastList->LockForReading(); 797 } 798 } 799 fCookieJar->fCookieHashMap->Unlock(); 800 } 801 802 fLastElement = NULL; 803 return result; 804 } 805 806 807 BNetworkCookieJar::UrlIterator& 808 BNetworkCookieJar::UrlIterator::operator=( 809 const BNetworkCookieJar::UrlIterator& other) 810 { 811 if (this == &other) 812 return *this; 813 814 // Teardown 815 if (fList) 816 fList->Unlock(); 817 818 delete fIterator; 819 820 // Init 821 fCookieJar = other.fCookieJar; 822 fIterator = NULL; 823 fList = NULL; 824 fLastList = NULL; 825 fElement = NULL; 826 fLastElement = NULL; 827 fIndex = 0; 828 fLastIndex = 0; 829 fUrl = other.fUrl; 830 831 _Initialize(); 832 833 return *this; 834 } 835 836 837 void 838 BNetworkCookieJar::UrlIterator::_Initialize() 839 { 840 BString domain = fUrl.Host(); 841 842 if (!domain.Length()) { 843 if (fUrl.Protocol() == "file") 844 domain = "localhost"; 845 else 846 return; 847 } 848 849 fIterator = new(std::nothrow) PrivateIterator( 850 fCookieJar->fCookieHashMap->GetIterator()); 851 852 if (fIterator != NULL) { 853 // Prepending a dot since _FindNext is going to call _SupDomain() 854 domain.Prepend("."); 855 fIterator->fKey.SetTo(domain, domain.Length()); 856 _FindNext(); 857 } 858 } 859 860 861 bool 862 BNetworkCookieJar::UrlIterator::_SuperDomain() 863 { 864 BString domain(fIterator->fKey.GetString()); 865 // Makes a copy of the characters from the key. This is important, 866 // because HashString doesn't like SetTo to be called with a substring 867 // of its original string (use-after-free + memcpy overwrite). 868 int32 firstDot = domain.FindFirst('.'); 869 if (firstDot < 0) 870 return false; 871 872 const char* nextDot = domain.String() + firstDot; 873 874 fIterator->fKey.SetTo(nextDot + 1); 875 return true; 876 } 877 878 879 void 880 BNetworkCookieJar::UrlIterator::_FindNext() 881 { 882 fLastIndex = fIndex; 883 fLastElement = fElement; 884 if (fLastList != NULL) 885 fLastList->Unlock(); 886 887 fLastList = fList; 888 if (fCookieJar->fCookieHashMap->Lock()) { 889 if (fLastList) 890 fLastList->LockForReading(); 891 892 while (!_FindPath()) { 893 if (!_SuperDomain()) { 894 fElement = NULL; 895 fCookieJar->fCookieHashMap->Unlock(); 896 return; 897 } 898 899 _FindDomain(); 900 } 901 fCookieJar->fCookieHashMap->Unlock(); 902 } 903 } 904 905 906 void 907 BNetworkCookieJar::UrlIterator::_FindDomain() 908 { 909 if (fList != NULL) 910 fList->Unlock(); 911 912 if (fCookieJar->fCookieHashMap->Lock()) { 913 fList = fCookieJar->fCookieHashMap->Get(fIterator->fKey); 914 915 if (fList == NULL) 916 fElement = NULL; 917 else { 918 fList->LockForReading(); 919 } 920 fCookieJar->fCookieHashMap->Unlock(); 921 } 922 923 fIndex = -1; 924 } 925 926 927 bool 928 BNetworkCookieJar::UrlIterator::_FindPath() 929 { 930 fIndex++; 931 while (fList && fIndex < fList->CountItems()) { 932 fElement = fList->ItemAt(fIndex); 933 934 if (fElement->IsValidForPath(fUrl.Path())) 935 return true; 936 937 fIndex++; 938 } 939 940 return false; 941 } 942 943 944 // #pragma mark - BNetworkCookieList 945 946 947 BNetworkCookieList::BNetworkCookieList() 948 { 949 pthread_rwlock_init(&fLock, NULL); 950 } 951 952 953 BNetworkCookieList::~BNetworkCookieList() 954 { 955 // Note: this is expected to be called with the write lock held. 956 pthread_rwlock_destroy(&fLock); 957 } 958 959 960 status_t 961 BNetworkCookieList::LockForReading() 962 { 963 return pthread_rwlock_rdlock(&fLock); 964 } 965 966 967 status_t 968 BNetworkCookieList::LockForWriting() 969 { 970 return pthread_rwlock_wrlock(&fLock); 971 } 972 973 974 status_t 975 BNetworkCookieList::Unlock() 976 { 977 return pthread_rwlock_unlock(&fLock); 978 } 979 980