hrev45264 adds 6 changesets to branch 'master' old head: dcaec19c9a11eec63fd86420326935c5097e48e9 new head: 64a1f5a020afbbb203b72bfb07e1b08d38431bfe overview: http://cgit.haiku-os.org/haiku/log/?qt=range&q=64a1f5a+%5Edcaec19 ---------------------------------------------------------------------------- 2e7b5f9: NetworkCookieJar: don't leak a new cookie if it has expired 05f42aa: NetworkCookie: set the default path according to RFC 6265 2db5d2b: NetworkCookie: remove unused cookie attributes and add HttpOnly 33462ef: NetworkCookie: bring SetCookie parsing in line with RFC 6265 c8bc218: NetworkCookie: fix domain/path matching, and validity checks 64a1f5a: NetworkCookieJar: various small fixes and updated tests [ Hamish Morrison <hamishm53@xxxxxxxxx> ] ---------------------------------------------------------------------------- 5 files changed, 617 insertions(+), 658 deletions(-) headers/os/net/NetworkCookie.h | 93 ++- headers/os/net/NetworkCookieJar.h | 27 +- src/kits/network/libnetapi/NetworkCookie.cpp | 711 +++++++++----------- src/kits/network/libnetapi/NetworkCookieJar.cpp | 317 ++++----- src/tests/kits/net/cookie/cookie_test.cpp | 127 ++-- ############################################################################ Commit: 2e7b5f9e185297670adc17f3aada0a4af6a48838 URL: http://cgit.haiku-os.org/haiku/commit/?id=2e7b5f9 Author: Hamish Morrison <hamishm53@xxxxxxxxx> Date: Sat Jan 26 19:23:34 2013 UTC NetworkCookieJar: don't leak a new cookie if it has expired ---------------------------------------------------------------------------- diff --git a/src/kits/network/libnetapi/NetworkCookieJar.cpp b/src/kits/network/libnetapi/NetworkCookieJar.cpp index eef91d1..5b8a945 100644 --- a/src/kits/network/libnetapi/NetworkCookieJar.cpp +++ b/src/kits/network/libnetapi/NetworkCookieJar.cpp @@ -20,14 +20,14 @@ const char* kArchivedCookieMessageName = "be:cookie"; BNetworkCookieJar::BNetworkCookieJar() - : + : fCookieHashMap(new PrivateHashMap) { } BNetworkCookieJar::BNetworkCookieJar(const BNetworkCookieJar&) - : + : BArchivable(), fCookieHashMap(new PrivateHashMap) { @@ -36,7 +36,7 @@ BNetworkCookieJar::BNetworkCookieJar(const BNetworkCookieJar&) BNetworkCookieJar::BNetworkCookieJar(const BNetworkCookieList& otherList) - : + : fCookieHashMap(new PrivateHashMap) { AddCookies(otherList); @@ -44,18 +44,18 @@ BNetworkCookieJar::BNetworkCookieJar(const BNetworkCookieList& otherList) BNetworkCookieJar::BNetworkCookieJar(BMessage* archive) - : + : fCookieHashMap(new PrivateHashMap) { BMessage extractedCookie; - + for (int32 i = 0; archive->FindMessage(kArchivedCookieMessageName, i, &extractedCookie) == B_OK; i++) { - BNetworkCookie* heapCookie + BNetworkCookie* heapCookie = new(std::nothrow) BNetworkCookie(&extractedCookie); - + if (heapCookie == NULL || !AddCookie(heapCookie)) break; } @@ -65,7 +65,7 @@ BNetworkCookieJar::BNetworkCookieJar(BMessage* archive) BNetworkCookieJar::~BNetworkCookieJar() { BNetworkCookie* cookiePtr; - + for (Iterator it(GetIterator()); (cookiePtr = it.Next()); ) delete it.Remove(); } @@ -78,12 +78,12 @@ bool BNetworkCookieJar::AddCookie(const BNetworkCookie& cookie) { BNetworkCookie* heapCookie = new(std::nothrow) BNetworkCookie(cookie); - + if (!AddCookie(heapCookie)) { delete heapCookie; return false; } - + return true; } @@ -91,29 +91,27 @@ BNetworkCookieJar::AddCookie(const BNetworkCookie& cookie) bool BNetworkCookieJar::AddCookie(BNetworkCookie* cookie) { - if (cookie != NULL) { - HashString key(cookie->Domain()); - - if (!fCookieHashMap->fHashMap.ContainsKey(key)) - fCookieHashMap->fHashMap.Put(key, new BList); - - BNetworkCookieList* list = fCookieHashMap->fHashMap.Get(key); - - for (int32 i = 0; i < list->CountItems(); i++) { - BNetworkCookie* c - = reinterpret_cast<BNetworkCookie*>(list->ItemAt(i)); - - if (c->Name() == cookie->Name()) { - list->RemoveItem(i); - break; - } + if (cookie == NULL || cookie->ShouldDeleteNow()) + return false; + + HashString key(cookie->Domain()); + + if (!fCookieHashMap->fHashMap.ContainsKey(key)) + fCookieHashMap->fHashMap.Put(key, new BList); + + BNetworkCookieList* list = fCookieHashMap->fHashMap.Get(key); + + for (int32 i = 0; i < list->CountItems(); i++) { + BNetworkCookie* c + = reinterpret_cast<BNetworkCookie*>(list->ItemAt(i)); + + if (c->Name() == cookie->Name()) { + list->RemoveItem(i); + break; } - - // Discard the cookie if it's to be deleted - if (!cookie->ShouldDeleteNow()) - list->AddItem(cookie); } - + + list->AddItem(cookie); return true; } @@ -122,15 +120,15 @@ bool BNetworkCookieJar::AddCookies(const BNetworkCookieList& cookies) { for (int32 i = 0; i < cookies.CountItems(); i++) { - BNetworkCookie* cookiePtr + BNetworkCookie* cookiePtr = reinterpret_cast<BNetworkCookie*>(cookies.ItemAt(i)); - + // Using AddCookie by reference in order to avoid multiple // cookie jar share the same cookie pointers if (!AddCookie(*cookiePtr)) return false; } - + return true; } @@ -143,8 +141,8 @@ BNetworkCookieJar::DeleteOutdatedCookies() { int32 deleteCount = 0; BNetworkCookie* cookiePtr; - - for (Iterator it(GetIterator()); (cookiePtr = it.Next()); ) { + + for (Iterator it = GetIterator(); (cookiePtr = it.Next()) != NULL;) { if (cookiePtr->ShouldDeleteNow()) { delete it.Remove(); deleteCount++; @@ -160,8 +158,8 @@ BNetworkCookieJar::PurgeForExit() { int32 deleteCount = 0; BNetworkCookie* cookiePtr; - - for (Iterator it(GetIterator()); (cookiePtr = it.Next()); ) { + + for (Iterator it = GetIterator(); (cookiePtr = it.Next()) != NULL;) { if (cookiePtr->ShouldDeleteAtExit()) { delete it.Remove(); deleteCount++; @@ -182,10 +180,10 @@ BNetworkCookieJar::Archive(BMessage* into, bool deep) const if (error == B_OK) { BNetworkCookie* cookiePtr; - - for (Iterator it(GetIterator()); (cookiePtr = it.Next()); ) { + + for (Iterator it = GetIterator(); (cookiePtr = it.Next()) != NULL;) { BMessage subArchive; - + error = cookiePtr->Archive(&subArchive, deep); if (error != B_OK) return error; @@ -205,7 +203,7 @@ BNetworkCookieJar::Instantiate(BMessage* archive) { if (archive->HasMessage(kArchivedCookieMessageName)) return new(std::nothrow) BNetworkCookieJar(archive); - + return NULL; } @@ -242,11 +240,11 @@ BNetworkCookieJar::Flatten(void* buffer, ssize_t size) const { if (FlattenedSize() > size) return B_ERROR; - - fFlattened.CopyInto(reinterpret_cast<char*>(buffer), 0, + + fFlattened.CopyInto(reinterpret_cast<char*>(buffer), 0, fFlattened.Length()); reinterpret_cast<char*>(buffer)[fFlattened.Length()] = 0; - + return B_OK; } @@ -262,13 +260,13 @@ BNetworkCookieJar::AllowsTypeCode(type_code) const status_t BNetworkCookieJar::Unflatten(type_code, const void* buffer, ssize_t size) { - BString flattenedCookies; + BString flattenedCookies; flattenedCookies.SetTo(reinterpret_cast<const char*>(buffer), size); - - while (flattenedCookies.Length() > 0) { + + while (flattenedCookies.Length() > 0) { BNetworkCookie tempCookie; BString tempCookieLine; - + int32 endOfLine = flattenedCookies.FindFirst('\n', 0); if (endOfLine == -1) tempCookieLine = flattenedCookies; @@ -276,11 +274,11 @@ BNetworkCookieJar::Unflatten(type_code, const void* buffer, ssize_t size) flattenedCookies.MoveInto(tempCookieLine, 0, endOfLine); flattenedCookies.Remove(0, 1); } - + if (tempCookieLine.Length() != 0 && tempCookieLine[0] != '#') { for (int32 field = 0; field < 7; field++) { BString tempString; - + int32 endOfField = tempCookieLine.FindFirst('\t', 0); if (endOfField == -1) tempString = tempCookieLine; @@ -288,42 +286,42 @@ BNetworkCookieJar::Unflatten(type_code, const void* buffer, ssize_t size) tempCookieLine.MoveInto(tempString, 0, endOfField); tempCookieLine.Remove(0, 1); } - + switch (field) { case 0: tempCookie.SetDomain(tempString); break; - + case 1: // TODO: Useless field ATM break; - + case 2: tempCookie.SetPath(tempString); break; - + case 3: tempCookie.SetSecure(tempString == "TRUE"); break; - + case 4: tempCookie.SetExpirationDate(atoi(tempString)); break; - + case 5: tempCookie.SetName(tempString); break; - + case 6: tempCookie.SetValue(tempString); break; } // switch } // for loop - + AddCookie(tempCookie); } - } - + } + return B_OK; } @@ -346,7 +344,7 @@ BNetworkCookieJar::GetUrlIterator(const BUrl& url) const copy.SetPath("/"); return BNetworkCookieJar::UrlIterator(this, copy); } - + return BNetworkCookieJar::UrlIterator(this, url); } @@ -357,10 +355,10 @@ BNetworkCookieJar::_DoFlatten() const fFlattened.Truncate(0); BNetworkCookie* cookiePtr; - for (Iterator it(GetIterator()); (cookiePtr = it.Next()); ) { - fFlattened << cookiePtr->Domain() << '\t' << "TRUE" << '\t' - << cookiePtr->Path() << '\t' - << (cookiePtr->Secure()?"TRUE":"FALSE") << '\t' + for (Iterator it = GetIterator(); (cookiePtr = it.Next()) != NULL;) { + fFlattened << cookiePtr->Domain() << '\t' << "TRUE" << '\t' + << cookiePtr->Path() << '\t' + << (cookiePtr->Secure()?"TRUE":"FALSE") << '\t' << (int32)cookiePtr->ExpirationDate() << '\t' << cookiePtr->Name() << '\t' << cookiePtr->Value() << '\n'; } @@ -395,7 +393,7 @@ BNetworkCookieJar::Iterator::Iterator(const BNetworkCookieJar* cookieJar) { fIterator = new(std::nothrow) PrivateIterator( fCookieJar->fCookieHashMap->fHashMap.GetIterator()); - + // Locate first cookie _FindNext(); } @@ -419,7 +417,7 @@ BNetworkCookieJar::Iterator::Next() { if (!fElement) return NULL; - + BNetworkCookie* result = fElement; _FindNext(); return result; @@ -431,18 +429,18 @@ BNetworkCookieJar::Iterator::NextDomain() { if (!fElement) return NULL; - + BNetworkCookie* result = fElement; - + if (!fIterator->fCookieMapIterator.HasNext()) { fElement = NULL; return NULL; } - + fList = *(fIterator->fCookieMapIterator.NextValue()); fIndex = 0; fElement = reinterpret_cast<BNetworkCookie*>(fList->ItemAt(fIndex)); - + return result; } @@ -452,7 +450,7 @@ BNetworkCookieJar::Iterator::Remove() { if (!fLastElement) return NULL; - + BNetworkCookie* result = fLastElement; if (fIndex == 0) { @@ -466,7 +464,7 @@ BNetworkCookieJar::Iterator::Remove() fList->RemoveItem(fIndex-1); fIndex--; } - + fLastElement = NULL; return result; } @@ -490,18 +488,18 @@ void BNetworkCookieJar::Iterator::_FindNext() { fLastElement = fElement; - + fIndex++; if (fList && fIndex < fList->CountItems()) { fElement = reinterpret_cast<BNetworkCookie*>(fList->ItemAt(fIndex)); return; } - + if (!fIterator->fCookieMapIterator.HasNext()) { fElement = NULL; return; } - + fLastList = fList; fList = *(fIterator->fCookieMapIterator.NextValue()); fIndex = 0; @@ -538,11 +536,11 @@ BNetworkCookieJar::UrlIterator::UrlIterator(const BNetworkCookieJar* cookieJar, if (domain[0] != '.') domain.Prepend("."); - + // Prepending another dot since _FindNext is going to // call _SupDomain() domain.Prepend("."); - + fIterator = new(std::nothrow) PrivateIterator( fCookieJar->fCookieHashMap->fHashMap.GetIterator()); fIterator->fKey.SetTo(domain, domain.Length()); @@ -569,7 +567,7 @@ BNetworkCookieJar::UrlIterator::Next() { if (!fElement) return NULL; - + BNetworkCookie* result = fElement; _FindNext(); return result; @@ -581,15 +579,15 @@ BNetworkCookieJar::UrlIterator::Remove() { if (!fLastElement) return NULL; - + BNetworkCookie* result = fLastElement; fLastList->RemoveItem(fLastIndex); if (fLastList->CountItems() == 0) { - HashString lastKey(fLastElement->Domain(), + HashString lastKey(fLastElement->Domain(), fLastElement->Domain().Length()); - + delete fCookieJar->fCookieHashMap->fHashMap.Remove(lastKey); } @@ -620,10 +618,10 @@ BNetworkCookieJar::UrlIterator::_SupDomain() { BString domain(fIterator->fKey.GetString()); int32 nextDot = domain.FindFirst('.', 1); - + if (nextDot == -1) return false; - + domain.Remove(0, nextDot); fIterator->fKey.SetTo(domain.String(), domain.Length()); return true; @@ -635,17 +633,17 @@ BNetworkCookieJar::UrlIterator::_FindNext() { fLastIndex = fIndex; fLastElement = fElement; - + if (_FindPath()) return; - + fLastList = fList; do { if (!_SupDomain()) { fElement = NULL; return; } - + _FindDomain(); } while (!_FindPath()); } @@ -655,10 +653,10 @@ void BNetworkCookieJar::UrlIterator::_FindDomain() { fList = fCookieJar->fCookieHashMap->fHashMap.Get(fIterator->fKey); - + if (fList == NULL) fElement = NULL; - + fIndex = -1; } @@ -669,15 +667,15 @@ BNetworkCookieJar::UrlIterator::_FindPath() fIndex++; if (fList && fIndex < fList->CountItems()) { do { - fElement + fElement = reinterpret_cast<BNetworkCookie*>(fList->ItemAt(fIndex)); - - if (fElement->IsValidForPath(fUrl.Path())) + + if (fElement->IsValidForPath(fUrl.Path())) return true; - + fIndex++; } while (fList && fIndex < fList->CountItems()); } - + return false; } ############################################################################ Commit: 05f42aaba4c6b4ad6e023e029e1e2b3c55ec4d25 URL: http://cgit.haiku-os.org/haiku/commit/?id=05f42aa Author: Hamish Morrison <hamishm53@xxxxxxxxx> Date: Wed Jan 30 14:35:11 2013 UTC NetworkCookie: set the default path according to RFC 6265 ---------------------------------------------------------------------------- diff --git a/headers/os/net/NetworkCookie.h b/headers/os/net/NetworkCookie.h index 168c9b1..9ba5bc3 100644 --- a/headers/os/net/NetworkCookie.h +++ b/headers/os/net/NetworkCookie.h @@ -24,13 +24,13 @@ public: BNetworkCookie(BMessage* archive); BNetworkCookie(); virtual ~BNetworkCookie(); - + // Parse a "SetCookie" string, or "name=value" - - BNetworkCookie& ParseCookieStringFromUrl(const BString& string, + + BNetworkCookie& ParseCookieStringFromUrl(const BString& string, const BUrl& url); BNetworkCookie& ParseCookieString(const BString& cookieString); - + // Modify the cookie fields BNetworkCookie& SetComment(const BString& comment); BNetworkCookie& SetCommentUrl(const BString& commentUrl); @@ -44,7 +44,7 @@ public: BNetworkCookie& SetVersion(int8 version); BNetworkCookie& SetName(const BString& name); BNetworkCookie& SetValue(const BString& value); - + // Access the cookie fields const BString& CommentUrl() const; const BString& Comment() const; @@ -64,7 +64,7 @@ public: bool IsValidForUrl(const BUrl& url) const; bool IsValidForDomain(const BString& domain) const; bool IsValidForPath(const BString& path) const; - + // Test if cookie fields are defined bool HasCommentUrl() const; bool HasComment() const; @@ -76,16 +76,16 @@ public: bool HasVersion() const; bool HasName() const; bool HasValue() const; - + // Test if cookie could be deleted bool ShouldDeleteAtExit() const; bool ShouldDeleteNow() const; - + // BArchivable members virtual status_t Archive(BMessage* into, bool deep = true) const; static BArchivable* Instantiate(BMessage* archive); - + // Overloaded operators BNetworkCookie& operator=(const BNetworkCookie& other); BNetworkCookie& operator=(const char* string); @@ -94,15 +94,16 @@ public: private: void _Reset(); void _ExtractNameValuePair( - const BString& cookieString, int16* index, + const BString& cookieString, int16* index, bool parseField = false); - + void _SetDefaultPathForUrl(const BUrl& url); + private: mutable BString fRawCookie; mutable bool fRawCookieValid; mutable BString fRawFullCookie; mutable bool fRawFullCookieValid; - + BString fComment; BString fCommentUrl; bool fDiscard; @@ -115,7 +116,7 @@ private: int8 fVersion; BString fName; BString fValue; - + bool fHasDiscard; bool fHasExpirationDate; bool fSessionCookie; diff --git a/src/kits/network/libnetapi/NetworkCookie.cpp b/src/kits/network/libnetapi/NetworkCookie.cpp index 16fad67..475a21a 100644 --- a/src/kits/network/libnetapi/NetworkCookie.cpp +++ b/src/kits/network/libnetapi/NetworkCookie.cpp @@ -32,7 +32,7 @@ static const char* kArchivedCookieValue = "be:cookie.value"; BNetworkCookie::BNetworkCookie(const char* name, const char* value) - : + : fDiscard(false), fExpiration(BDateTime::CurrentDateTime(B_GMT_TIME)), fVersion(0), @@ -45,7 +45,7 @@ BNetworkCookie::BNetworkCookie(const char* name, const char* value) BNetworkCookie::BNetworkCookie(const BNetworkCookie& other) - : + : BArchivable(), fDiscard(false), fExpiration(BDateTime::CurrentDateTime(B_GMT_TIME)), @@ -58,7 +58,7 @@ BNetworkCookie::BNetworkCookie(const BNetworkCookie& other) BNetworkCookie::BNetworkCookie(const BString& cookieString) - : + : fDiscard(false), fExpiration(BDateTime::CurrentDateTime(B_GMT_TIME)), fVersion(0), @@ -71,7 +71,7 @@ BNetworkCookie::BNetworkCookie(const BString& cookieString) BNetworkCookie::BNetworkCookie(const BString& cookieString, const BUrl& url) - : + : fDiscard(false), fExpiration(BDateTime::CurrentDateTime(B_GMT_TIME)), fVersion(0), @@ -83,29 +83,29 @@ BNetworkCookie::BNetworkCookie(const BString& cookieString, BNetworkCookie::BNetworkCookie(BMessage* archive) - : + : fDiscard(false), fExpiration(BDateTime::CurrentDateTime(B_GMT_TIME)), fVersion(0), fSessionCookie(true) { _Reset(); - + archive->FindString(kArchivedCookieName, &fName); archive->FindString(kArchivedCookieValue, &fValue); - + archive->FindString(kArchivedCookieComment, &fComment); archive->FindString(kArchivedCookieCommentUrl, &fCommentUrl); archive->FindString(kArchivedCookieDomain, &fDomain); archive->FindString(kArchivedCookiePath, &fPath); archive->FindBool(kArchivedCookieSecure, &fSecure); - + if (archive->FindBool(kArchivedCookieDiscard, &fDiscard) == B_OK) fHasDiscard = true; - + if (archive->FindInt8(kArchivedCookieVersion, &fVersion) == B_OK) fHasVersion = true; - + int32 expiration; if (archive->FindInt32(kArchivedCookieExpirationDate, &expiration) == B_OK) { @@ -115,7 +115,7 @@ BNetworkCookie::BNetworkCookie(BMessage* archive) BNetworkCookie::BNetworkCookie() - : + : fDiscard(false), fExpiration(BDateTime::CurrentDateTime(B_GMT_TIME)), fPath("/"), @@ -140,19 +140,19 @@ BNetworkCookie::ParseCookieStringFromUrl(const BString& string, { BString cookieString(string); int16 index = 0; - + _Reset(); - + // Default values from url SetDomain(url.Host()); - SetPath(url.Path()); - + _SetDefaultPathForUrl(url); + _ExtractNameValuePair(cookieString, &index); while (index < cookieString.Length()) _ExtractNameValuePair(cookieString, &index, true); - - return *this; + + return *this; } @@ -200,11 +200,11 @@ BNetworkCookie& BNetworkCookie::SetDomain(const BString& domain) { fDomain = domain; - + // We always use pre-dotted domains for tail matching if (fDomain.ByteAt(0) != '.') fDomain.Prepend("."); - + fRawFullCookieValid = false; return *this; } @@ -244,7 +244,7 @@ BNetworkCookie::SetExpirationDate(BDateTime& expireDate) fRawFullCookieValid = false; fHasExpirationDate = true; } - + return *this; } @@ -346,12 +346,12 @@ const BString& BNetworkCookie::ExpirationString() const { BHttpTime date(ExpirationDate()); - + if (!fExpirationStringValid) { fExpirationString = date.ToString(BPrivate::B_HTTP_TIME_FORMAT_COOKIE); fExpirationStringValid = true; } - + return fExpirationString; } @@ -397,9 +397,9 @@ BNetworkCookie::RawCookie(bool full) const if (full && !fRawFullCookieValid) { fRawFullCookie.Truncate(0); fRawFullCookieValid = true; - + fRawFullCookie << fName << "=" << fValue; - + if (HasCommentUrl()) fRawFullCookie << "; Comment-Url=" << fCommentUrl; if (HasComment()) @@ -417,11 +417,11 @@ BNetworkCookie::RawCookie(bool full) const fRawFullCookie << "; Secure=" << (fSecure?"true":"false"); if (HasVersion()) fRawFullCookie << ", Version=" << fVersion; - + } else if (!full && !fRawCookieValid) { fRawCookie.Truncate(0); fRawCookieValid = true; - + fRawCookie << fName << "=" << fValue; } @@ -451,7 +451,7 @@ BNetworkCookie::IsValidForUrl(const BUrl& url) const { BString urlHost = url.Host(); BString urlPath = url.Path(); - + return IsValidForDomain(urlHost) && IsValidForPath(urlPath); } @@ -461,7 +461,7 @@ BNetworkCookie::IsValidForDomain(const BString& domain) const { if (fDomain.Length() > domain.Length()) return false; - + return domain.FindLast(fDomain) == (domain.Length() - fDomain.Length()); } @@ -471,7 +471,7 @@ BNetworkCookie::IsValidForPath(const BString& path) const { if (fPath.Length() > path.Length()) return false; - + return path.FindFirst(fPath) == 0; } @@ -559,7 +559,7 @@ BNetworkCookie::ShouldDeleteNow() const { if (!IsSessionCookie() && HasExpirationDate()) return (BDateTime::CurrentDateTime(B_GMT_TIME) > fExpiration); - + return false; } @@ -574,60 +574,60 @@ BNetworkCookie::Archive(BMessage* into, bool deep) const if (error != B_OK) return error; - + error = into->AddString(kArchivedCookieName, fName); if (error != B_OK) return error; - + error = into->AddString(kArchivedCookieValue, fValue); if (error != B_OK) return error; - - + + // We add optional fields only if they're defined if (HasComment()) { error = into->AddString(kArchivedCookieComment, fComment); if (error != B_OK) return error; - } - + } + if (HasCommentUrl()) { error = into->AddString(kArchivedCookieCommentUrl, fCommentUrl); if (error != B_OK) return error; } - + if (HasDiscard()) { error = into->AddBool(kArchivedCookieDiscard, fDiscard); if (error != B_OK) return error; } - + if (HasDomain()) { error = into->AddString(kArchivedCookieDomain, fDomain); if (error != B_OK) return error; } - + if (fHasExpirationDate) { - error = into->AddInt32(kArchivedCookieExpirationDate, + error = into->AddInt32(kArchivedCookieExpirationDate, fExpiration.Time_t()); if (error != B_OK) return error; } - + if (HasPath()) { error = into->AddString(kArchivedCookiePath, fPath); if (error != B_OK) return error; } - + if (Secure()) { error = into->AddBool(kArchivedCookieSecure, fSecure); if (error != B_OK) return error; } - + if (HasVersion()) { error = into->AddInt8(kArchivedCookieVersion, fVersion); if (error != B_OK) @@ -652,7 +652,7 @@ BNetworkCookie::Instantiate(BMessage* archive) // #pragma mark Overloaded operators -BNetworkCookie& +BNetworkCookie& BNetworkCookie::operator=(const BNetworkCookie& other) { // Should we prefer to discard the cache ? @@ -662,7 +662,7 @@ BNetworkCookie::operator=(const BNetworkCookie& other) fRawFullCookieValid = other.fRawFullCookieValid; fExpirationString = other.fExpirationString; fExpirationStringValid = other.fExpirationStringValid; - + fComment = other.fComment; fCommentUrl = other.fCommentUrl; fDiscard = other.fDiscard; @@ -673,12 +673,12 @@ BNetworkCookie::operator=(const BNetworkCookie& other) fVersion = other.fVersion; fName = other.fName; fValue = other.fValue; - + fHasDiscard = other.fHasDiscard; fHasExpirationDate = other.fHasExpirationDate; fSessionCookie = other.fSessionCookie; fHasVersion = other.fHasVersion; - + return *this; } @@ -723,7 +723,7 @@ BNetworkCookie::_Reset() fHasExpirationDate = false; fSessionCookie = true; fHasVersion = false; - + fRawCookieValid = false; fRawFullCookieValid = false; fExpirationStringValid = false; @@ -731,32 +731,32 @@ BNetworkCookie::_Reset() void -BNetworkCookie::_ExtractNameValuePair(const BString& cookieString, +BNetworkCookie::_ExtractNameValuePair(const BString& cookieString, int16* index, bool parseField) { // Skip whitespaces while (cookieString.ByteAt(*index) == ' ' && *index < cookieString.Length()) (*index)++; - + if (*index >= cookieString.Length()) return; - + // Look for a name=value pair int16 firstSemiColon = cookieString.FindFirst(";", *index); int16 firstEqual = cookieString.FindFirst("=", *index); - + BString name; BString value; - + if (firstSemiColon == -1) { if (firstEqual != -1) { cookieString.CopyInto(name, *index, firstEqual - *index); cookieString.CopyInto(value, firstEqual + 1, cookieString.Length() - firstEqual - 1); } else - cookieString.CopyInto(value, *index, + cookieString.CopyInto(value, *index, cookieString.Length() - *index); *index = cookieString.Length() + 1; @@ -799,7 +799,7 @@ BNetworkCookie::_ExtractNameValuePair(const BString& cookieString, BHttpTime date(value); SetExpirationDate(date.Parse()); // Cookie valid domain - } else if (name == "domain") + } else if (name == "domain") SetDomain(value); // Cookie valid path else if (name == "path") @@ -811,3 +811,23 @@ BNetworkCookie::_ExtractNameValuePair(const BString& cookieString, else if (name == "version") SetVersion(atoi(value.String())); } + + +void +BNetworkCookie::_SetDefaultPathForUrl(const BUrl& url) +{ + const BString& path = url.Path(); + if (path.IsEmpty() || path.ByteAt(0) != '/') { + SetPath("/"); + return; + } + + int32 index = path.FindLast('/'); + if (index == 0) { + SetPath("/"); + return; + } + + BString newPath = path; + SetPath(newPath.Truncate(index)); +} ############################################################################ Commit: 2db5d2bc95b8b37ce6f2cd0547cd5e6336992388 URL: http://cgit.haiku-os.org/haiku/commit/?id=2db5d2b Author: Hamish Morrison <hamishm53@xxxxxxxxx> Date: Wed Jan 30 16:49:37 2013 UTC NetworkCookie: remove unused cookie attributes and add HttpOnly ---------------------------------------------------------------------------- diff --git a/headers/os/net/NetworkCookie.h b/headers/os/net/NetworkCookie.h index 9ba5bc3..5a6fd01 100644 --- a/headers/os/net/NetworkCookie.h +++ b/headers/os/net/NetworkCookie.h @@ -32,33 +32,27 @@ public: BNetworkCookie& ParseCookieString(const BString& cookieString); // Modify the cookie fields - BNetworkCookie& SetComment(const BString& comment); - BNetworkCookie& SetCommentUrl(const BString& commentUrl); - BNetworkCookie& SetDiscard(bool discard); + BNetworkCookie& SetName(const BString& name); + BNetworkCookie& SetValue(const BString& value); BNetworkCookie& SetDomain(const BString& domain); + BNetworkCookie& SetPath(const BString& path); BNetworkCookie& SetMaxAge(int32 maxAge); BNetworkCookie& SetExpirationDate(time_t expireDate); BNetworkCookie& SetExpirationDate(BDateTime& expireDate); - BNetworkCookie& SetPath(const BString& path); BNetworkCookie& SetSecure(bool secure); - BNetworkCookie& SetVersion(int8 version); - BNetworkCookie& SetName(const BString& name); - BNetworkCookie& SetValue(const BString& value); + BNetworkCookie& SetHttpOnly(bool httpOnly); // Access the cookie fields - const BString& CommentUrl() const; - const BString& Comment() const; - bool Discard() const; + const BString& Name() const; + const BString& Value() const; const BString& Domain() const; - int32 MaxAge() const; + const BString& Path() const; time_t ExpirationDate() const; const BString& ExpirationString() const; - const BString& Path() const; bool Secure() const; - int8 Version() const; - const BString& Name() const; - const BString& Value() const; + bool HttpOnly() const; const BString& RawCookie(bool full) const; + bool IsSessionCookie() const; bool IsValid(bool strict = false) const; bool IsValidForUrl(const BUrl& url) const; @@ -66,16 +60,11 @@ public: bool IsValidForPath(const BString& path) const; // Test if cookie fields are defined - bool HasCommentUrl() const; - bool HasComment() const; - bool HasDiscard() const; - bool HasDomain() const; - bool HasMaxAge() const; - bool HasExpirationDate() const; - bool HasPath() const; - bool HasVersion() const; bool HasName() const; bool HasValue() const; + bool HasDomain() const; + bool HasPath() const; + bool HasExpirationDate() const; // Test if cookie could be deleted bool ShouldDeleteAtExit() const; @@ -104,23 +93,18 @@ private: mutable BString fRawFullCookie; mutable bool fRawFullCookieValid; - BString fComment; - BString fCommentUrl; - bool fDiscard; BString fDomain; BDateTime fExpiration; mutable BString fExpirationString; mutable bool fExpirationStringValid; BString fPath; bool fSecure; - int8 fVersion; + bool fHttpOnly; BString fName; BString fValue; - bool fHasDiscard; bool fHasExpirationDate; bool fSessionCookie; - bool fHasVersion; }; #endif // _B_NETWORK_COOKIE_H_ diff --git a/src/kits/network/libnetapi/NetworkCookie.cpp b/src/kits/network/libnetapi/NetworkCookie.cpp index 475a21a..ca86851 100644 --- a/src/kits/network/libnetapi/NetworkCookie.cpp +++ b/src/kits/network/libnetapi/NetworkCookie.cpp @@ -7,35 +7,30 @@ */ -#include <cstdlib> -#include <ctime> #include <new> +#include <stdio.h> +#include <stdlib.h> +#include <time.h> + #include <HttpTime.h> #include <NetworkCookie.h> -#include <cstdio> #define PRINT(x) printf x; using BPrivate::BHttpTime; -static const char* kArchivedCookieComment = "be:cookie.comment"; -static const char* kArchivedCookieCommentUrl = "be:cookie.commenturl"; -static const char* kArchivedCookieDiscard = "be:cookie.discard"; -static const char* kArchivedCookieDomain = "be:cookie.domain"; -static const char* kArchivedCookieExpirationDate = "be:cookie.expiredate"; -static const char* kArchivedCookiePath = "be:cookie.path"; -static const char* kArchivedCookieSecure = "be:cookie.secure"; -static const char* kArchivedCookieVersion = "be:cookie.version"; -static const char* kArchivedCookieName = "be:cookie.name"; -static const char* kArchivedCookieValue = "be:cookie.value"; +static const char* kArchivedCookieName = "be:cookie.name"; +static const char* kArchivedCookieValue = "be:cookie.value"; +static const char* kArchivedCookieDomain = "be:cookie.domain"; +static const char* kArchivedCookiePath = "be:cookie.path"; +static const char* kArchivedCookieExpirationDate = "be:cookie.expirationdate"; +static const char* kArchivedCookieSecure = "be:cookie.secure"; +static const char* kArchivedCookieHttpOnly = "be:cookie.httponly"; BNetworkCookie::BNetworkCookie(const char* name, const char* value) : - fDiscard(false), - fExpiration(BDateTime::CurrentDateTime(B_GMT_TIME)), - fVersion(0), fName(name), fValue(value), fSessionCookie(true) @@ -45,12 +40,6 @@ BNetworkCookie::BNetworkCookie(const char* name, const char* value) BNetworkCookie::BNetworkCookie(const BNetworkCookie& other) - : - BArchivable(), - fDiscard(false), - fExpiration(BDateTime::CurrentDateTime(B_GMT_TIME)), - fVersion(0), - fSessionCookie(true) { _Reset(); *this = other; @@ -58,11 +47,6 @@ BNetworkCookie::BNetworkCookie(const BNetworkCookie& other) BNetworkCookie::BNetworkCookie(const BString& cookieString) - : - fDiscard(false), - fExpiration(BDateTime::CurrentDateTime(B_GMT_TIME)), - fVersion(0), - fSessionCookie(true) { _Reset(); ParseCookieString(cookieString); @@ -71,11 +55,6 @@ BNetworkCookie::BNetworkCookie(const BString& cookieString) BNetworkCookie::BNetworkCookie(const BString& cookieString, const BUrl& url) - : - fDiscard(false), - fExpiration(BDateTime::CurrentDateTime(B_GMT_TIME)), - fVersion(0), - fSessionCookie(true) { _Reset(); ParseCookieStringFromUrl(cookieString, url); @@ -84,9 +63,6 @@ BNetworkCookie::BNetworkCookie(const BString& cookieString, BNetworkCookie::BNetworkCookie(BMessage* archive) : - fDiscard(false), - fExpiration(BDateTime::CurrentDateTime(B_GMT_TIME)), - fVersion(0), fSessionCookie(true) { _Reset(); @@ -94,17 +70,10 @@ BNetworkCookie::BNetworkCookie(BMessage* archive) archive->FindString(kArchivedCookieName, &fName); archive->FindString(kArchivedCookieValue, &fValue); - archive->FindString(kArchivedCookieComment, &fComment); - archive->FindString(kArchivedCookieCommentUrl, &fCommentUrl); archive->FindString(kArchivedCookieDomain, &fDomain); archive->FindString(kArchivedCookiePath, &fPath); archive->FindBool(kArchivedCookieSecure, &fSecure); - - if (archive->FindBool(kArchivedCookieDiscard, &fDiscard) == B_OK) - fHasDiscard = true; - - if (archive->FindInt8(kArchivedCookieVersion, &fVersion) == B_OK) - fHasVersion = true; + archive->FindBool(kArchivedCookieHttpOnly, &fHttpOnly); int32 expiration; if (archive->FindInt32(kArchivedCookieExpirationDate, &expiration) @@ -115,12 +84,6 @@ BNetworkCookie::BNetworkCookie(BMessage* archive) BNetworkCookie::BNetworkCookie() - : - fDiscard(false), - fExpiration(BDateTime::CurrentDateTime(B_GMT_TIME)), - fPath("/"), - fVersion(0), - fSessionCookie(true) { _Reset(); } @@ -169,28 +132,29 @@ BNetworkCookie::ParseCookieString(const BString& string) BNetworkCookie& -BNetworkCookie::SetComment(const BString& comment) +BNetworkCookie::SetName(const BString& name) { - fComment = comment; + fName = name; fRawFullCookieValid = false; + fRawCookieValid = false; return *this; } BNetworkCookie& -BNetworkCookie::SetCommentUrl(const BString& commentUrl) +BNetworkCookie::SetValue(const BString& value) { - fCommentUrl = commentUrl; + fValue = value; fRawFullCookieValid = false; + fRawCookieValid = false; return *this; } BNetworkCookie& -BNetworkCookie::SetDiscard(bool discard) +BNetworkCookie::SetPath(const BString& path) { - fDiscard = discard; - fHasDiscard = true; + fPath = path; fRawFullCookieValid = false; return *this; } @@ -250,15 +214,6 @@ BNetworkCookie::SetExpirationDate(BDateTime& expireDate) BNetworkCookie& -BNetworkCookie::SetPath(const BString& path) -{ - fPath = path; - fRawFullCookieValid = false; - return *this; -} - - -BNetworkCookie& BNetworkCookie::SetSecure(bool secure) { fSecure = secure; @@ -268,31 +223,10 @@ BNetworkCookie::SetSecure(bool secure) BNetworkCookie& -BNetworkCookie::SetVersion(int8 version) -{ - fVersion = version; - fHasVersion = true; - fRawCookieValid = false; - return *this; -} - - -BNetworkCookie& -BNetworkCookie::SetName(const BString& name) -{ - fName = name; - fRawFullCookieValid = false; - fRawCookieValid = false; - return *this; -} - - -BNetworkCookie& -BNetworkCookie::SetValue(const BString& value) +BNetworkCookie::SetHttpOnly(bool httpOnly) { - fValue = value; + fHttpOnly = httpOnly; fRawFullCookieValid = false; - fRawCookieValid = false; return *this; } @@ -301,23 +235,16 @@ BNetworkCookie::SetValue(const BString& value) const BString& -BNetworkCookie::Comment() const +BNetworkCookie::Name() const { - return fComment; + return fName; } const BString& -BNetworkCookie::CommentUrl() const -{ - return fCommentUrl; -} - - -bool -BNetworkCookie::Discard() const +BNetworkCookie::Value() const { - return fDiscard; + return fValue; } @@ -328,10 +255,10 @@ BNetworkCookie::Domain() const } -int32 -BNetworkCookie::MaxAge() const +const BString& +BNetworkCookie::Path() const { - return fExpiration.Time_t() - BDateTime::CurrentDateTime(B_GMT_TIME).Time_t(); + return fPath; } @@ -356,13 +283,6 @@ BNetworkCookie::ExpirationString() const } -const BString& -BNetworkCookie::Path() const -{ - return fPath; -} - - bool BNetworkCookie::Secure() const { @@ -370,24 +290,10 @@ BNetworkCookie::Secure() const } -int8 -BNetworkCookie::Version() const -{ - return fVersion; -} - - -const BString& -BNetworkCookie::Name() const -{ - return fName; -} - - -const BString& -BNetworkCookie::Value() const +bool +BNetworkCookie::HttpOnly() const { - return fValue; + return fHttpOnly; } @@ -400,23 +306,16 @@ BNetworkCookie::RawCookie(bool full) const fRawFullCookie << fName << "=" << fValue; - if (HasCommentUrl()) - fRawFullCookie << "; Comment-Url=" << fCommentUrl; - if (HasComment()) - fRawFullCookie << "; Comment=" << fComment; - if (HasDiscard()) - fRawFullCookie << "; Discard=" << (fDiscard?"true":"false"); if (HasDomain()) fRawFullCookie << "; Domain=" << fDomain; if (HasExpirationDate()) - fRawFullCookie << "; Max-Age=" << MaxAge(); -// fRawFullCookie << "; Expires=" << ExpirationString(); + fRawFullCookie << "; Expires=" << ExpirationString(); if (HasPath()) fRawFullCookie << "; Path=" << fPath; - if (Secure() && fSecure) - fRawFullCookie << "; Secure=" << (fSecure?"true":"false"); - if (HasVersion()) - fRawFullCookie << ", Version=" << fVersion; + if (Secure()) + fRawFullCookie << "; Secure"; + if (HttpOnly()) + fRawFullCookie << "; HttpOnly"; } else if (!full && !fRawCookieValid) { fRawCookie.Truncate(0); @@ -425,7 +324,7 @@ BNetworkCookie::RawCookie(bool full) const fRawCookie << fName << "=" << fValue; } - return full?fRawFullCookie:fRawCookie; + return full ? fRawFullCookie : fRawCookie; } @@ -442,13 +341,14 @@ BNetworkCookie::IsSessionCookie() const bool BNetworkCookie::IsValid(bool strict) const { - return HasName() && HasValue() && (!strict || HasVersion()); + return HasName() && HasValue(); } bool BNetworkCookie::IsValidForUrl(const BUrl& url) const { + // TODO: Take secure attribute into account BString urlHost = url.Host(); BString urlPath = url.Path(); @@ -480,23 +380,16 @@ BNetworkCookie::IsValidForPath(const BString& path) const bool -BNetworkCookie::HasCommentUrl() const -{ - return fCommentUrl.Length() > 0; -} - - -bool -BNetworkCookie::HasComment() const +BNetworkCookie::HasName() const { - return fComment.Length() > 0; + return fName.Length() > 0; } bool -BNetworkCookie::HasDiscard() const +BNetworkCookie::HasValue() const { - return fHasDiscard; + return fValue.Length() > 0; } @@ -515,27 +408,6 @@ BNetworkCookie::HasPath() const bool -BNetworkCookie::HasVersion() const -{ - return fHasVersion; -} - - -bool -BNetworkCookie::HasName() const -{ - return fName.Length() > 0; -} - - -bool -BNetworkCookie::HasValue() const -{ - return fValue.Length() > 0; -} - - -bool BNetworkCookie::HasExpirationDate() const { return fHasExpirationDate; @@ -548,16 +420,14 @@ BNetworkCookie::HasExpirationDate() const bool BNetworkCookie::ShouldDeleteAtExit() const { - return (HasDiscard() && Discard()) - || (!IsSessionCookie() && ShouldDeleteNow()) - || IsSessionCookie(); + return IsSessionCookie() || ShouldDeleteNow(); } bool BNetworkCookie::ShouldDeleteNow() const { - if (!IsSessionCookie() && HasExpirationDate()) + if (HasExpirationDate()) return (BDateTime::CurrentDateTime(B_GMT_TIME) > fExpiration); return false; @@ -585,24 +455,6 @@ BNetworkCookie::Archive(BMessage* into, bool deep) const // We add optional fields only if they're defined - if (HasComment()) { - error = into->AddString(kArchivedCookieComment, fComment); - if (error != B_OK) - return error; - } - - if (HasCommentUrl()) { - error = into->AddString(kArchivedCookieCommentUrl, fCommentUrl); - if (error != B_OK) - return error; - } - - if (HasDiscard()) { - error = into->AddBool(kArchivedCookieDiscard, fDiscard); - if (error != B_OK) - return error; - } - if (HasDomain()) { error = into->AddString(kArchivedCookieDomain, fDomain); if (error != B_OK) @@ -628,8 +480,8 @@ BNetworkCookie::Archive(BMessage* into, bool deep) const return error; } - if (HasVersion()) { - error = into->AddInt8(kArchivedCookieVersion, fVersion); + if (HttpOnly()) { + error = into->AddBool(kArchivedCookieHttpOnly, fHttpOnly); if (error != B_OK) return error; } @@ -663,21 +515,16 @@ BNetworkCookie::operator=(const BNetworkCookie& other) fExpirationString = other.fExpirationString; fExpirationStringValid = other.fExpirationStringValid; - fComment = other.fComment; - fCommentUrl = other.fCommentUrl; - fDiscard = other.fDiscard; + fName = other.fName; + fValue = other.fValue; fDomain = other.fDomain; - fExpiration = other.fExpiration; fPath = other.fPath; + fExpiration = other.fExpiration; fSecure = other.fSecure; - fVersion = other.fVersion; - fName = other.fName; - fValue = other.fValue; + fHttpOnly = other.fHttpOnly; - fHasDiscard = other.fHasDiscard; fHasExpirationDate = other.fHasExpirationDate; fSessionCookie = other.fSessionCookie; - fHasVersion = other.fHasVersion; return *this; } @@ -708,21 +555,16 @@ BNetworkCookie::operator!=(const BNetworkCookie& other) void BNetworkCookie::_Reset() { - fComment.Truncate(0); - fCommentUrl.Truncate(0); fDomain.Truncate(0); fPath.Truncate(0); fName.Truncate(0); fValue.Truncate(0); - fDiscard = false; fSecure = false; - fVersion = 0; - fExpiration = 0; + fHttpOnly = false; + fExpiration = BDateTime(); - fHasDiscard = false; fHasExpirationDate = false; fSessionCookie = true; - fHasVersion = false; fRawCookieValid = false; fRawFullCookieValid = false; @@ -782,17 +624,8 @@ BNetworkCookie::_ExtractNameValuePair(const BString& cookieString, name.Trim(); value.Trim(); - // Cookie comment - if (name == "comment") - SetComment(value); - // Cookie comment URL - else if (name == "comment-url") - SetCommentUrl(value); - // Cookie discard flag - else if (name == "discard") - SetDiscard(value.Length() == 0 || value.ToLower() == "true"); // Cookie max-age - else if (name == "maxage") + if (name == "maxage") SetMaxAge(atoi(value.String())); // Cookie expiration date else if (name == "expires") { @@ -807,9 +640,6 @@ BNetworkCookie::_ExtractNameValuePair(const BString& cookieString, // Cookie secure flag else if (name == "secure") SetSecure(value.Length() == 0 || value.ToLower() == "true"); - // Cookie version - else if (name == "version") - SetVersion(atoi(value.String())); } ############################################################################ Commit: 33462ef54a6c481491c9716726619b5bb25c0dcf URL: http://cgit.haiku-os.org/haiku/commit/?id=33462ef Author: Hamish Morrison <hamishm53@xxxxxxxxx> Date: Thu Jan 31 18:53:25 2013 UTC NetworkCookie: bring SetCookie parsing in line with RFC 6265 ---------------------------------------------------------------------------- diff --git a/headers/os/net/NetworkCookie.h b/headers/os/net/NetworkCookie.h index 5a6fd01..7db429f 100644 --- a/headers/os/net/NetworkCookie.h +++ b/headers/os/net/NetworkCookie.h @@ -17,7 +17,6 @@ class BNetworkCookie : public BArchivable { public: BNetworkCookie(const char* name, const char* value); - BNetworkCookie(const BNetworkCookie& other); BNetworkCookie(const BString& cookieString); BNetworkCookie(const BString& cookieString, const BUrl& url); @@ -25,7 +24,7 @@ public: BNetworkCookie(); virtual ~BNetworkCookie(); - // Parse a "SetCookie" string, or "name=value" + // Parse a "SetCookie" string BNetworkCookie& ParseCookieStringFromUrl(const BString& string, const BUrl& url); @@ -53,6 +52,7 @@ public: bool HttpOnly() const; const BString& RawCookie(bool full) const; + bool IsHostOnly() const; bool IsSessionCookie() const; bool IsValid(bool strict = false) const; bool IsValidForUrl(const BUrl& url) const; @@ -76,34 +76,36 @@ public: static BArchivable* Instantiate(BMessage* archive); // Overloaded operators - BNetworkCookie& operator=(const BNetworkCookie& other); BNetworkCookie& operator=(const char* string); bool operator==(const BNetworkCookie& other); bool operator!=(const BNetworkCookie& other); private: void _Reset(); - void _ExtractNameValuePair( - const BString& cookieString, int16* index, - bool parseField = false); - void _SetDefaultPathForUrl(const BUrl& url); + int32 _ExtractNameValuePair(const BString& string, + BString& name, BString& value, + int32 index); + int32 _ExtractAttributeValuePair( + const BString& string, BString& name, + BString& value, int32 index); + BString _DefaultPathForUrl(const BUrl& url); private: mutable BString fRawCookie; mutable bool fRawCookieValid; mutable BString fRawFullCookie; mutable bool fRawFullCookieValid; - - BString fDomain; - BDateTime fExpiration; mutable BString fExpirationString; mutable bool fExpirationStringValid; + + BString fName; + BString fValue; + BString fDomain; BString fPath; + BDateTime fExpiration; bool fSecure; bool fHttpOnly; - BString fName; - BString fValue; - bool fHasExpirationDate; + bool fHostOnly; bool fSessionCookie; }; diff --git a/src/kits/network/libnetapi/NetworkCookie.cpp b/src/kits/network/libnetapi/NetworkCookie.cpp index ca86851..a06335a 100644 --- a/src/kits/network/libnetapi/NetworkCookie.cpp +++ b/src/kits/network/libnetapi/NetworkCookie.cpp @@ -1,9 +1,10 @@ /* - * Copyright 2010 Haiku Inc. All rights reserved. + * Copyright 2010-2013 Haiku Inc. All rights reserved. * Distributed under the terms of the MIT License. * * Authors: * Christophe Huriaux, c.huriaux@xxxxxxxxx + * Hamish Morrison, hamishm53@xxxxxxxxx */ @@ -13,11 +14,10 @@ #include <stdlib.h> #include <time.h> +#include <Debug.h> #include <HttpTime.h> #include <NetworkCookie.h> -#define PRINT(x) printf x; - using BPrivate::BHttpTime; static const char* kArchivedCookieName = "be:cookie.name"; @@ -27,22 +27,14 @@ static const char* kArchivedCookiePath = "be:cookie.path"; static const char* kArchivedCookieExpirationDate = "be:cookie.expirationdate"; static const char* kArchivedCookieSecure = "be:cookie.secure"; static const char* kArchivedCookieHttpOnly = "be:cookie.httponly"; +static const char* kArchivedCookieHostOnly = "be:cookie.hostonly"; BNetworkCookie::BNetworkCookie(const char* name, const char* value) - : - fName(name), - fValue(value), - fSessionCookie(true) -{ - _Reset(); -} - - -BNetworkCookie::BNetworkCookie(const BNetworkCookie& other) { _Reset(); - *this = other; + fName = name; + fValue = value; } @@ -62,8 +54,6 @@ BNetworkCookie::BNetworkCookie(const BString& cookieString, BNetworkCookie::BNetworkCookie(BMessage* archive) - : - fSessionCookie(true) { _Reset(); @@ -74,6 +64,7 @@ BNetworkCookie::BNetworkCookie(BMessage* archive) archive->FindString(kArchivedCookiePath, &fPath); archive->FindBool(kArchivedCookieSecure, &fSecure); archive->FindBool(kArchivedCookieHttpOnly, &fHttpOnly); + archive->FindBool(kArchivedCookieHostOnly, &fHostOnly); int32 expiration; if (archive->FindInt32(kArchivedCookieExpirationDate, &expiration) @@ -101,19 +92,61 @@ BNetworkCookie& BNetworkCookie::ParseCookieStringFromUrl(const BString& string, const BUrl& url) { - BString cookieString(string); - int16 index = 0; - _Reset(); - // Default values from url - SetDomain(url.Host()); - _SetDefaultPathForUrl(url); + BString name; + BString value; + int32 index = 0; + + // Parse the name and value of the cookie + index = _ExtractNameValuePair(string, name, value, index); + // The set-cookie-string is not valid + if (index == -1) + return *this; + + SetName(name); + SetValue(value); + + // Parse the remaining cookie attributes + while (index < string.Length()) { + ASSERT(string[index] == ';'); + index++; + + index = _ExtractAttributeValuePair(string, name, value, index); + + if (name.ICompare("secure") == 0) + SetSecure(true); + else if (name.ICompare("httponly") == 0) + SetHttpOnly(true); + + // The following attributes require a value + if (value.IsEmpty()) + continue; + + if (name.ICompare("max-age") == 0) { + // Validate the max-age value + char* end = NULL; + long maxAge = strtol(value.String(), &end, 10); + if (*end == '\0') + SetMaxAge((int)maxAge); + } else if (name.ICompare("expires") == 0) { + BHttpTime date(value); + SetExpirationDate(date.Parse()); + } else if (name.ICompare("domain") == 0) + SetDomain(value); + else if (name.ICompare("path") == 0) + SetPath(value); + } - _ExtractNameValuePair(cookieString, &index); + // If no domain was specified, we set a host-only domain from the URL + if (!HasDomain()) { + SetDomain(url.Host()); + fHostOnly = true; + } - while (index < cookieString.Length()) - _ExtractNameValuePair(cookieString, &index, true); + // If no path was specified we compute the default path from the URL + if (!HasPath()) + SetPath(_DefaultPathForUrl(url)); return *this; } @@ -164,6 +197,7 @@ BNetworkCookie& BNetworkCookie::SetDomain(const BString& domain) { fDomain = domain; + fHostOnly = false; // We always use pre-dotted domains for tail matching if (fDomain.ByteAt(0) != '.') @@ -200,13 +234,11 @@ BNetworkCookie::SetExpirationDate(BDateTime& expireDate) fSessionCookie = true; fExpirationStringValid = false; fRawFullCookieValid = false; - fHasExpirationDate = false; } else { fExpiration = expireDate; fSessionCookie = false; fExpirationStringValid = false; fRawFullCookieValid = false; - fHasExpirationDate = true; } return *this; @@ -332,6 +364,13 @@ BNetworkCookie::RawCookie(bool full) const bool +BNetworkCookie::IsHostOnly() const +{ + return fHostOnly; +} + + +bool BNetworkCookie::IsSessionCookie() const { return fSessionCookie; @@ -410,7 +449,7 @@ BNetworkCookie::HasPath() const bool BNetworkCookie::HasExpirationDate() const { - return fHasExpirationDate; + return !IsSessionCookie(); } @@ -461,7 +500,7 @@ BNetworkCookie::Archive(BMessage* into, bool deep) const return error; } - if (fHasExpirationDate) { + if (HasExpirationDate()) { error = into->AddInt32(kArchivedCookieExpirationDate, fExpiration.Time_t()); if (error != B_OK) @@ -486,6 +525,12 @@ BNetworkCookie::Archive(BMessage* into, bool deep) const return error; } + if (IsHostOnly()) { + error = into->AddBool(kArchivedCookieHostOnly, true); + if (error != B_OK) + return error; + } + return B_OK; } @@ -505,32 +550,6 @@ BNetworkCookie::Instantiate(BMessage* archive) BNetworkCookie& -BNetworkCookie::operator=(const BNetworkCookie& other) -{ - // Should we prefer to discard the cache ? - fRawCookie = other.fRawCookie; - fRawCookieValid = other.fRawCookieValid; - fRawFullCookie = other.fRawFullCookie; - fRawFullCookieValid = other.fRawFullCookieValid; - fExpirationString = other.fExpirationString; - fExpirationStringValid = other.fExpirationStringValid; - - fName = other.fName; - fValue = other.fValue; - fDomain = other.fDomain; - fPath = other.fPath; - fExpiration = other.fExpiration; - fSecure = other.fSecure; - fHttpOnly = other.fHttpOnly; - - fHasExpirationDate = other.fHasExpirationDate; - fSessionCookie = other.fSessionCookie; - - return *this; -} - - -BNetworkCookie& BNetworkCookie::operator=(const char* string) { return ParseCookieString(string); @@ -555,109 +574,133 @@ BNetworkCookie::operator!=(const BNetworkCookie& other) void BNetworkCookie::_Reset() { - fDomain.Truncate(0); - fPath.Truncate(0); fName.Truncate(0); fValue.Truncate(0); - fSecure = false; - fHttpOnly = false; - fExpiration = BDateTime(); + fDomain.Truncate(0); + fPath.Truncate(0); + fExpiration = BDateTime(); + fSecure = false; + fHttpOnly = false; - fHasExpirationDate = false; - fSessionCookie = true; + fSessionCookie = true; + fHostOnly = true; - fRawCookieValid = false; - fRawFullCookieValid = false; - fExpirationStringValid = false; + fRawCookieValid = false; + fRawFullCookieValid = false; + fExpirationStringValid = false; } -void +int32 +skip_whitespace_forward(const BString& string, int32 index) +{ + while (index < string.Length() && (string[index] == ' ' + || string[index] == '\t')) + index++; + return index; +} + + +int32 +skip_whitespace_backward(const BString& string, int32 index) +{ + while (index >= 0 && (string[index] == ' ' || string[index] == '\t')) + index--; + return index; +} + + +int32 BNetworkCookie::_ExtractNameValuePair(const BString& cookieString, - int16* index, bool parseField) + BString& name, BString& value, int32 index) { - // Skip whitespaces - while (cookieString.ByteAt(*index) == ' ' - && *index < cookieString.Length()) - (*index)++; + // Find our name-value-pair and the delimiter. + int32 firstEquals = cookieString.FindFirst('=', index); + int32 nameValueEnd = cookieString.FindFirst(';', index); - if (*index >= cookieString.Length()) - return; + // If the set-cookie-string lacks a semicolon, the name-value-pair + // is the whole string. + if (nameValueEnd == -1) + nameValueEnd = cookieString.Length(); + // If the name-value-pair lacks an equals, the parse should fail. + if (firstEquals == -1 || firstEquals > nameValueEnd) + return -1; - // Look for a name=value pair - int16 firstSemiColon = cookieString.FindFirst(";", *index); - int16 firstEqual = cookieString.FindFirst("=", *index); + int32 first = skip_whitespace_forward(cookieString, index); + int32 last = skip_whitespace_backward(cookieString, firstEquals - 1); - BString name; - BString value; + // If we lack a name, fail to parse. + if (first > last) + return -1; - if (firstSemiColon == -1) { - if (firstEqual != -1) { - cookieString.CopyInto(name, *index, firstEqual - *index); - cookieString.CopyInto(value, firstEqual + 1, - cookieString.Length() - firstEqual - 1); - } else - cookieString.CopyInto(value, *index, - cookieString.Length() - *index); + cookieString.CopyInto(name, first, last - first + 1); - *index = cookieString.Length() + 1; - } else { - if (firstEqual != -1 && firstEqual < firstSemiColon) { - cookieString.CopyInto(name, *index, firstEqual - *index); - cookieString.CopyInto(value, firstEqual + 1, - firstSemiColon - firstEqual - 1); - } else - cookieString.CopyInto(value, *index, firstSemiColon - *index); - - *index = firstSemiColon + 1; - } + first = skip_whitespace_forward(cookieString, firstEquals + 1); + last = skip_whitespace_backward(cookieString, nameValueEnd - 1); + if (first <= last) + cookieString.CopyInto(value, first, last - first + 1); + else + value.SetTo(""); + + return nameValueEnd; +} + + +int32 +BNetworkCookie::_ExtractAttributeValuePair(const BString& cookieString, + BString& attribute, BString& value, int32 index) +{ + // Find the end of our cookie-av. + int32 cookieAVEnd = cookieString.FindFirst(';', index); + + // If the unparsed-attributes lacks a semicolon, then the cookie-av is the + // whole string. + if (cookieAVEnd == -1) + cookieAVEnd = cookieString.Length(); - // Cookie name/value pair - if (!parseField) { - SetName(name); - SetValue(value); - return; + int32 attributeNameEnd = cookieString.FindFirst('=', index); + // If the cookie-av has no equals, the attribute-name is the entire + // cookie-av and the attribute-value is empty. + if (attributeNameEnd == -1 || attributeNameEnd > cookieAVEnd) + attributeNameEnd = cookieAVEnd; + + int32 first = skip_whitespace_forward(cookieString, index); + int32 last = skip_whitespace_backward(cookieString, attributeNameEnd - 1); + + if (first <= last) + cookieString.CopyInto(attribute, first, last - first + 1); + else + attribute.SetTo(""); + + if (attributeNameEnd == cookieAVEnd) { + value.SetTo(""); + return cookieAVEnd; } - name.ToLower(); - name.Trim(); - value.Trim(); - - // Cookie max-age - if (name == "maxage") - SetMaxAge(atoi(value.String())); - // Cookie expiration date - else if (name == "expires") { - BHttpTime date(value); - SetExpirationDate(date.Parse()); - // Cookie valid domain - } else if (name == "domain") - SetDomain(value); - // Cookie valid path - else if (name == "path") - SetPath(value); - // Cookie secure flag - else if (name == "secure") - SetSecure(value.Length() == 0 || value.ToLower() == "true"); + first = skip_whitespace_forward(cookieString, attributeNameEnd + 1); + last = skip_whitespace_backward(cookieString, cookieAVEnd - 1); + if (first <= last) + cookieString.CopyInto(value, first, last - first + 1); + else + value.SetTo(""); + + return cookieAVEnd; } -void -BNetworkCookie::_SetDefaultPathForUrl(const BUrl& url) +BString +BNetworkCookie::_DefaultPathForUrl(const BUrl& url) { const BString& path = url.Path(); - if (path.IsEmpty() || path.ByteAt(0) != '/') { - SetPath("/"); - return; - } + if (path.IsEmpty() || path.ByteAt(0) != '/') + return ""; int32 index = path.FindLast('/'); - if (index == 0) { - SetPath("/"); - return; - } + if (index == 0) + return ""; BString newPath = path; - SetPath(newPath.Truncate(index)); + newPath.Truncate(index); + return newPath; } ############################################################################ Commit: c8bc218363618030e5db44eb268a1da456596a9f URL: http://cgit.haiku-os.org/haiku/commit/?id=c8bc218 Author: Hamish Morrison <hamishm53@xxxxxxxxx> Date: Mon Feb 4 00:06:42 2013 UTC NetworkCookie: fix domain/path matching, and validity checks ---------------------------------------------------------------------------- diff --git a/headers/os/net/NetworkCookie.h b/headers/os/net/NetworkCookie.h index 7db429f..dc9b78d 100644 --- a/headers/os/net/NetworkCookie.h +++ b/headers/os/net/NetworkCookie.h @@ -54,7 +54,7 @@ public: bool IsHostOnly() const; bool IsSessionCookie() const; - bool IsValid(bool strict = false) const; + bool IsValid() const; bool IsValidForUrl(const BUrl& url) const; bool IsValidForDomain(const BString& domain) const; bool IsValidForPath(const BString& path) const; diff --git a/src/kits/network/libnetapi/NetworkCookie.cpp b/src/kits/network/libnetapi/NetworkCookie.cpp index a06335a..e4a5311 100644 --- a/src/kits/network/libnetapi/NetworkCookie.cpp +++ b/src/kits/network/libnetapi/NetworkCookie.cpp @@ -378,16 +378,18 @@ BNetworkCookie::IsSessionCookie() const bool -BNetworkCookie::IsValid(bool strict) const +BNetworkCookie::IsValid() const { - return HasName() && HasValue(); + return HasName() && HasDomain() && HasPath(); } bool BNetworkCookie::IsValidForUrl(const BUrl& url) const { - // TODO: Take secure attribute into account + if (IsSecure() && url.Protocol() != "https") + return false; + BString urlHost = url.Host(); BString urlPath = url.Path(); @@ -398,20 +400,53 @@ BNetworkCookie::IsValidForUrl(const BUrl& url) const bool BNetworkCookie::IsValidForDomain(const BString& domain) const { - if (fDomain.Length() > domain.Length()) + // TODO: canonicalize both domains + const BString& cookieDomain = Domain(); + + int32 difference = domain.Length() - cookieDomain.Length(); + // If the cookie domain is longer than the domain string it cannot + // be valid. + if (difference < 0) return false; - return domain.FindLast(fDomain) == (domain.Length() - fDomain.Length()); + // If the cookie is host-only the domains must match exactly. + if (IsHostOnly()) + return domain == cookieDomain; + + // Otherwise, the domains must match exactly, or the cookie domain + // must be a suffix with the preceeding character being a dot. + const char* suffix = domain.String() + difference; + if (strcmp(suffix, cookieDomain.String()) == 0) { + if (difference == 0) + return true; + else if (domain[difference - 1] == '.') + return true; + } + + return false; } bool BNetworkCookie::IsValidForPath(const BString& path) const { - if (fPath.Length() > path.Length()) + const BString& cookiePath = Path(); + if (path.Length() < cookiePath.Length()) + return false; + + // The cookie path must be a prefix of the path string + if (path.Compare(cookiePath, cookiePath.Length()) != 0) return false; - return path.FindFirst(fPath) == 0; + // The paths match if they are identical, or if the last + // character of the prefix is a slash, or if the character + // after the prefix is a slash. + if (path.Length() == cookiePath.Length() + || cookiePath[cookiePath.Length() - 1] == '/' + || path[cookiePath.Length()] == '/') + return true; + + return false; } ############################################################################ Revision: hrev45264 Commit: 64a1f5a020afbbb203b72bfb07e1b08d38431bfe URL: http://cgit.haiku-os.org/haiku/commit/?id=64a1f5a Author: Hamish Morrison <hamishm53@xxxxxxxxx> Date: Thu Feb 7 17:59:43 2013 UTC NetworkCookieJar: various small fixes and updated tests ---------------------------------------------------------------------------- diff --git a/headers/os/net/NetworkCookieJar.h b/headers/os/net/NetworkCookieJar.h index 31cd196..9c3e775 100644 --- a/headers/os/net/NetworkCookieJar.h +++ b/headers/os/net/NetworkCookieJar.h @@ -1,5 +1,5 @@ /* - * Copyright 2010 Haiku Inc. All rights reserved. + * Copyright 2010-2013 Haiku Inc. All rights reserved. * Distributed under the terms of the MIT License. */ #ifndef _B_NETWORK_COOKIE_JAR_H_ @@ -24,7 +24,7 @@ public: class UrlIterator; struct PrivateIterator; struct PrivateHashMap; - + public: BNetworkCookieJar(); BNetworkCookieJar( @@ -34,16 +34,15 @@ public: BNetworkCookieJar(BMessage* archive); virtual ~BNetworkCookieJar(); - bool AddCookie(const BNetworkCookie& cookie); - bool AddCookie(BNetworkCookie* cookie); - bool AddCookies( - const BNetworkCookieList& cookies); + status_t AddCookie(const BNetworkCookie& cookie); + status_t AddCookie(BNetworkCookie* cookie); + status_t AddCookies(const BNetworkCookieList& cookies); uint32 DeleteOutdatedCookies(); uint32 PurgeForExit(); // BArchivable members - virtual status_t Archive(BMessage* into, + virtual status_t Archive(BMessage* into, bool deep = true) const; static BArchivable* Instantiate(BMessage* archive); @@ -54,20 +53,20 @@ public: virtual status_t Flatten(void* buffer, ssize_t size) const; virtual bool AllowsTypeCode(type_code code) const; - virtual status_t Unflatten(type_code code, + virtual status_t Unflatten(type_code code, const void* buffer, ssize_t size); // Iterators Iterator GetIterator() const; UrlIterator GetUrlIterator(const BUrl& url) const; - + private: void _DoFlatten() const; - + private: friend class Iterator; friend class UrlIterator; - + PrivateHashMap* fCookieHashMap; mutable BString fFlattened; }; @@ -117,7 +116,7 @@ private: UrlIterator(const BNetworkCookieJar* map, const BUrl& url); - bool _SupDomain(); + bool _SuperDomain(); void _FindNext(); void _FindDomain(); bool _FindPath(); @@ -131,10 +130,10 @@ private: BNetworkCookieList* fLastList; BNetworkCookie* fElement; BNetworkCookie* fLastElement; - + int32 fIndex; int32 fLastIndex; - + BUrl fUrl; }; diff --git a/src/kits/network/libnetapi/NetworkCookie.cpp b/src/kits/network/libnetapi/NetworkCookie.cpp index e4a5311..25b5e5c 100644 --- a/src/kits/network/libnetapi/NetworkCookie.cpp +++ b/src/kits/network/libnetapi/NetworkCookie.cpp @@ -100,14 +100,15 @@ BNetworkCookie::ParseCookieStringFromUrl(const BString& string, // Parse the name and value of the cookie index = _ExtractNameValuePair(string, name, value, index); - // The set-cookie-string is not valid - if (index == -1) + if (index == -1) { + // The set-cookie-string is not valid return *this; + } SetName(name); SetValue(value); - // Parse the remaining cookie attributes + // Parse the remaining cookie attributes. while (index < string.Length()) { ASSERT(string[index] == ';'); index++; @@ -119,12 +120,12 @@ BNetworkCookie::ParseCookieStringFromUrl(const BString& string, else if (name.ICompare("httponly") == 0) SetHttpOnly(true); - // The following attributes require a value + // The following attributes require a value. if (value.IsEmpty()) continue; if (name.ICompare("max-age") == 0) { - // Validate the max-age value + // Validate the max-age value. char* end = NULL; long maxAge = strtol(value.String(), &end, 10); if (*end == '\0') @@ -132,20 +133,31 @@ BNetworkCookie::ParseCookieStringFromUrl(const BString& string, } else if (name.ICompare("expires") == 0) { BHttpTime date(value); SetExpirationDate(date.Parse()); - } else if (name.ICompare("domain") == 0) + } else if (name.ICompare("domain") == 0) { SetDomain(value); - else if (name.ICompare("path") == 0) + } else if (name.ICompare("path") == 0) { SetPath(value); + } } - // If no domain was specified, we set a host-only domain from the URL + // If no domain was specified, we set a host-only domain from the URL. if (!HasDomain()) { SetDomain(url.Host()); fHostOnly = true; + } else { + // Otherwise the setting URL must domain-match the domain it set. + if (!IsValidForDomain(url.Host())) { + // Invalidate the cookie. + _Reset(); + return *this; + } + // We should also reject cookies with domains that match public + // suffixes. } - // If no path was specified we compute the default path from the URL - if (!HasPath()) + // If no path was specified or the path is invalid, we compute the default + // path from the URL. + if (!HasPath() || Path()[0] != '/') SetPath(_DefaultPathForUrl(url)); return *this; @@ -187,6 +199,7 @@ BNetworkCookie::SetValue(const BString& value) BNetworkCookie& BNetworkCookie::SetPath(const BString& path) { + // TODO: canonicalize the path fPath = path; fRawFullCookieValid = false; return *this; @@ -196,13 +209,10 @@ BNetworkCookie::SetPath(const BString& path) BNetworkCookie& BNetworkCookie::SetDomain(const BString& domain) { + // TODO: canonicalize the domain fDomain = domain; fHostOnly = false; - // We always use pre-dotted domains for tail matching - if (fDomain.ByteAt(0) != '.') - fDomain.Prepend("."); - fRawFullCookieValid = false; return *this; } @@ -387,13 +397,10 @@ BNetworkCookie::IsValid() const bool BNetworkCookie::IsValidForUrl(const BUrl& url) const { - if (IsSecure() && url.Protocol() != "https") + if (Secure() && url.Protocol() != "https") return false; - BString urlHost = url.Host(); - BString urlPath = url.Path(); - - return IsValidForDomain(urlHost) && IsValidForPath(urlPath); + return IsValidForDomain(url.Host()) && IsValidForPath(url.Path()); } diff --git a/src/kits/network/libnetapi/NetworkCookieJar.cpp b/src/kits/network/libnetapi/NetworkCookieJar.cpp index 5b8a945..cfe3efd 100644 --- a/src/kits/network/libnetapi/NetworkCookieJar.cpp +++ b/src/kits/network/libnetapi/NetworkCookieJar.cpp @@ -1,35 +1,37 @@ /* - * Copyright 2010 Haiku Inc. All rights reserved. + * Copyright 2010-2013 Haiku Inc. All rights reserved. * Distributed under the terms of the MIT License. * * Authors: * Christophe Huriaux, c.huriaux@xxxxxxxxx + * Hamish Morrison, hamishm53@xxxxxxxxx */ -#include <new> - #include <Debug.h> #include <HashMap.h> #include <HashString.h> #include <Message.h> #include <NetworkCookieJar.h> + +#include <new> + #include "NetworkCookieJarPrivate.h" -const char* kArchivedCookieMessageName = "be:cookie"; + +const char* kArchivedCookieMessageName = "be:cookie"; BNetworkCookieJar::BNetworkCookieJar() : - fCookieHashMap(new PrivateHashMap) + fCookieHashMap(new PrivateHashMap()) { } [ *** diff truncated: 531 lines dropped *** ]