status_t BNetworkCookieJar::AddCookie(BNetworkCookie* cookie) { if (cookie == NULL) return B_BAD_VALUE; HashString key(cookie->Domain()); BNetworkCookieList* list = fCookieHashMap->fHashMap.Get(key); if (list == NULL) { list = new(std::nothrow) BNetworkCookieList(); if (list == NULL || fCookieHashMap->fHashMap.Put(key, list) != B_OK) return B_NO_MEMORY; } for (int32 i = 0; i < list->CountItems(); i++) { BNetworkCookie* c = reinterpret_cast<BNetworkCookie*>(list->ItemAt(i)); if (c->Name() == cookie->Name() && c->Path() == cookie->Path()) { list->RemoveItem(i); break; } } if (cookie->ShouldDeleteNow()) delete cookie; else list->AddItem(cookie); return B_OK; }
status_t BNetworkCookieJar::AddCookies(const BNetworkCookieList& cookies) { for (int32 i = 0; i < cookies.CountItems(); i++) { const BNetworkCookie* cookiePtr = cookies.ItemAt(i); // Using AddCookie by reference in order to avoid multiple // cookie jar share the same cookie pointers status_t result = AddCookie(*cookiePtr); if (result != B_OK) return result; } return B_OK; }
BNetworkCookieJar::~BNetworkCookieJar() { for (Iterator it = GetIterator(); it.Next() != NULL;) { delete it.Remove(); } fCookieHashMap->Lock(); PrivateHashMap::Iterator it = fCookieHashMap->GetIterator(); while(it.HasNext()) { BNetworkCookieList* list = *it.NextValue(); it.Remove(); list->LockForWriting(); delete list; } delete fCookieHashMap; }
status_t BNetworkCookieJar::AddCookie(BNetworkCookie* cookie) { if (fCookieHashMap == NULL) return B_NO_MEMORY; if (cookie == NULL || !cookie->IsValid()) return B_BAD_VALUE; HashString key(cookie->Domain()); if (!fCookieHashMap->Lock()) return B_ERROR; // Get the cookies for the requested domain, or create a new list if there // isn't one yet. BNetworkCookieList* list = fCookieHashMap->Get(key); if (list == NULL) { list = new(std::nothrow) BNetworkCookieList(); if (list == NULL) { fCookieHashMap->Unlock(); return B_NO_MEMORY; } if (fCookieHashMap->Put(key, list) != B_OK) { fCookieHashMap->Unlock(); delete list; return B_NO_MEMORY; } } if (list->LockForWriting() != B_OK) { fCookieHashMap->Unlock(); return B_ERROR; } fCookieHashMap->Unlock(); // Remove any cookie with the same key as the one we're trying to add (it // replaces/updates them) for (int32 i = 0; i < list->CountItems(); i++) { const BNetworkCookie* c = list->ItemAt(i); if (c->Name() == cookie->Name() && c->Path() == cookie->Path()) { list->RemoveItemAt(i); break; } } // If the cookie has an expiration date in the past, stop here: we // effectively deleted a cookie. if (cookie->ShouldDeleteNow()) { TRACE("Remove cookie: %s\n", cookie->RawCookie(true).String()); delete cookie; } else { // Make sure the cookie has cached the raw string and expiration date // string, so it is now actually immutable. This way we can safely // read the cookie data from multiple threads without any locking. const BString& raw = cookie->RawCookie(true); (void)raw; TRACE("Add cookie: %s\n", raw.String()); // Keep the list sorted by path length (longest first). This makes sure // that cookies for most specific paths are returned first when // iterating the cookie jar. int32 i; for (i = 0; i < list->CountItems(); i++) { const BNetworkCookie* current = list->ItemAt(i); if (current->Path().Length() < cookie->Path().Length()) break; } list->AddItem(cookie, i); } list->Unlock(); return B_OK; }