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