NetworkCookie: bring SetCookie parsing in line with RFC 6265
This commit is contained in:
@@ -17,7 +17,6 @@ class BNetworkCookie : public BArchivable {
|
|||||||
public:
|
public:
|
||||||
BNetworkCookie(const char* name,
|
BNetworkCookie(const char* name,
|
||||||
const char* value);
|
const char* value);
|
||||||
BNetworkCookie(const BNetworkCookie& other);
|
|
||||||
BNetworkCookie(const BString& cookieString);
|
BNetworkCookie(const BString& cookieString);
|
||||||
BNetworkCookie(const BString& cookieString,
|
BNetworkCookie(const BString& cookieString,
|
||||||
const BUrl& url);
|
const BUrl& url);
|
||||||
@@ -25,7 +24,7 @@ public:
|
|||||||
BNetworkCookie();
|
BNetworkCookie();
|
||||||
virtual ~BNetworkCookie();
|
virtual ~BNetworkCookie();
|
||||||
|
|
||||||
// Parse a "SetCookie" string, or "name=value"
|
// Parse a "SetCookie" string
|
||||||
|
|
||||||
BNetworkCookie& ParseCookieStringFromUrl(const BString& string,
|
BNetworkCookie& ParseCookieStringFromUrl(const BString& string,
|
||||||
const BUrl& url);
|
const BUrl& url);
|
||||||
@@ -53,6 +52,7 @@ public:
|
|||||||
bool HttpOnly() const;
|
bool HttpOnly() const;
|
||||||
const BString& RawCookie(bool full) const;
|
const BString& RawCookie(bool full) const;
|
||||||
|
|
||||||
|
bool IsHostOnly() const;
|
||||||
bool IsSessionCookie() const;
|
bool IsSessionCookie() const;
|
||||||
bool IsValid(bool strict = false) const;
|
bool IsValid(bool strict = false) const;
|
||||||
bool IsValidForUrl(const BUrl& url) const;
|
bool IsValidForUrl(const BUrl& url) const;
|
||||||
@@ -76,34 +76,36 @@ public:
|
|||||||
static BArchivable* Instantiate(BMessage* archive);
|
static BArchivable* Instantiate(BMessage* archive);
|
||||||
|
|
||||||
// Overloaded operators
|
// Overloaded operators
|
||||||
BNetworkCookie& operator=(const BNetworkCookie& other);
|
|
||||||
BNetworkCookie& operator=(const char* string);
|
BNetworkCookie& operator=(const char* string);
|
||||||
bool operator==(const BNetworkCookie& other);
|
bool operator==(const BNetworkCookie& other);
|
||||||
bool operator!=(const BNetworkCookie& other);
|
bool operator!=(const BNetworkCookie& other);
|
||||||
private:
|
private:
|
||||||
void _Reset();
|
void _Reset();
|
||||||
void _ExtractNameValuePair(
|
int32 _ExtractNameValuePair(const BString& string,
|
||||||
const BString& cookieString, int16* index,
|
BString& name, BString& value,
|
||||||
bool parseField = false);
|
int32 index);
|
||||||
void _SetDefaultPathForUrl(const BUrl& url);
|
int32 _ExtractAttributeValuePair(
|
||||||
|
const BString& string, BString& name,
|
||||||
|
BString& value, int32 index);
|
||||||
|
BString _DefaultPathForUrl(const BUrl& url);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
mutable BString fRawCookie;
|
mutable BString fRawCookie;
|
||||||
mutable bool fRawCookieValid;
|
mutable bool fRawCookieValid;
|
||||||
mutable BString fRawFullCookie;
|
mutable BString fRawFullCookie;
|
||||||
mutable bool fRawFullCookieValid;
|
mutable bool fRawFullCookieValid;
|
||||||
|
|
||||||
BString fDomain;
|
|
||||||
BDateTime fExpiration;
|
|
||||||
mutable BString fExpirationString;
|
mutable BString fExpirationString;
|
||||||
mutable bool fExpirationStringValid;
|
mutable bool fExpirationStringValid;
|
||||||
BString fPath;
|
|
||||||
bool fSecure;
|
|
||||||
bool fHttpOnly;
|
|
||||||
BString fName;
|
BString fName;
|
||||||
BString fValue;
|
BString fValue;
|
||||||
|
BString fDomain;
|
||||||
|
BString fPath;
|
||||||
|
BDateTime fExpiration;
|
||||||
|
bool fSecure;
|
||||||
|
bool fHttpOnly;
|
||||||
|
|
||||||
bool fHasExpirationDate;
|
bool fHostOnly;
|
||||||
bool fSessionCookie;
|
bool fSessionCookie;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -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.
|
* Distributed under the terms of the MIT License.
|
||||||
*
|
*
|
||||||
* Authors:
|
* Authors:
|
||||||
* Christophe Huriaux, [email protected]
|
* Christophe Huriaux, [email protected]
|
||||||
|
* Hamish Morrison, [email protected]
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
@@ -13,11 +14,10 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
|
#include <Debug.h>
|
||||||
#include <HttpTime.h>
|
#include <HttpTime.h>
|
||||||
#include <NetworkCookie.h>
|
#include <NetworkCookie.h>
|
||||||
|
|
||||||
#define PRINT(x) printf x;
|
|
||||||
|
|
||||||
using BPrivate::BHttpTime;
|
using BPrivate::BHttpTime;
|
||||||
|
|
||||||
static const char* kArchivedCookieName = "be:cookie.name";
|
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* kArchivedCookieExpirationDate = "be:cookie.expirationdate";
|
||||||
static const char* kArchivedCookieSecure = "be:cookie.secure";
|
static const char* kArchivedCookieSecure = "be:cookie.secure";
|
||||||
static const char* kArchivedCookieHttpOnly = "be:cookie.httponly";
|
static const char* kArchivedCookieHttpOnly = "be:cookie.httponly";
|
||||||
|
static const char* kArchivedCookieHostOnly = "be:cookie.hostonly";
|
||||||
|
|
||||||
|
|
||||||
BNetworkCookie::BNetworkCookie(const char* name, const char* value)
|
BNetworkCookie::BNetworkCookie(const char* name, const char* value)
|
||||||
:
|
|
||||||
fName(name),
|
|
||||||
fValue(value),
|
|
||||||
fSessionCookie(true)
|
|
||||||
{
|
{
|
||||||
_Reset();
|
_Reset();
|
||||||
}
|
fName = name;
|
||||||
|
fValue = value;
|
||||||
|
|
||||||
BNetworkCookie::BNetworkCookie(const BNetworkCookie& other)
|
|
||||||
{
|
|
||||||
_Reset();
|
|
||||||
*this = other;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -62,8 +54,6 @@ BNetworkCookie::BNetworkCookie(const BString& cookieString,
|
|||||||
|
|
||||||
|
|
||||||
BNetworkCookie::BNetworkCookie(BMessage* archive)
|
BNetworkCookie::BNetworkCookie(BMessage* archive)
|
||||||
:
|
|
||||||
fSessionCookie(true)
|
|
||||||
{
|
{
|
||||||
_Reset();
|
_Reset();
|
||||||
|
|
||||||
@@ -74,6 +64,7 @@ BNetworkCookie::BNetworkCookie(BMessage* archive)
|
|||||||
archive->FindString(kArchivedCookiePath, &fPath);
|
archive->FindString(kArchivedCookiePath, &fPath);
|
||||||
archive->FindBool(kArchivedCookieSecure, &fSecure);
|
archive->FindBool(kArchivedCookieSecure, &fSecure);
|
||||||
archive->FindBool(kArchivedCookieHttpOnly, &fHttpOnly);
|
archive->FindBool(kArchivedCookieHttpOnly, &fHttpOnly);
|
||||||
|
archive->FindBool(kArchivedCookieHostOnly, &fHostOnly);
|
||||||
|
|
||||||
int32 expiration;
|
int32 expiration;
|
||||||
if (archive->FindInt32(kArchivedCookieExpirationDate, &expiration)
|
if (archive->FindInt32(kArchivedCookieExpirationDate, &expiration)
|
||||||
@@ -101,19 +92,61 @@ BNetworkCookie&
|
|||||||
BNetworkCookie::ParseCookieStringFromUrl(const BString& string,
|
BNetworkCookie::ParseCookieStringFromUrl(const BString& string,
|
||||||
const BUrl& url)
|
const BUrl& url)
|
||||||
{
|
{
|
||||||
BString cookieString(string);
|
|
||||||
int16 index = 0;
|
|
||||||
|
|
||||||
_Reset();
|
_Reset();
|
||||||
|
|
||||||
// Default values from 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If no domain was specified, we set a host-only domain from the URL
|
||||||
|
if (!HasDomain()) {
|
||||||
SetDomain(url.Host());
|
SetDomain(url.Host());
|
||||||
_SetDefaultPathForUrl(url);
|
fHostOnly = true;
|
||||||
|
}
|
||||||
|
|
||||||
_ExtractNameValuePair(cookieString, &index);
|
// If no path was specified we compute the default path from the URL
|
||||||
|
if (!HasPath())
|
||||||
while (index < cookieString.Length())
|
SetPath(_DefaultPathForUrl(url));
|
||||||
_ExtractNameValuePair(cookieString, &index, true);
|
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
@@ -164,6 +197,7 @@ BNetworkCookie&
|
|||||||
BNetworkCookie::SetDomain(const BString& domain)
|
BNetworkCookie::SetDomain(const BString& domain)
|
||||||
{
|
{
|
||||||
fDomain = domain;
|
fDomain = domain;
|
||||||
|
fHostOnly = false;
|
||||||
|
|
||||||
// We always use pre-dotted domains for tail matching
|
// We always use pre-dotted domains for tail matching
|
||||||
if (fDomain.ByteAt(0) != '.')
|
if (fDomain.ByteAt(0) != '.')
|
||||||
@@ -200,13 +234,11 @@ BNetworkCookie::SetExpirationDate(BDateTime& expireDate)
|
|||||||
fSessionCookie = true;
|
fSessionCookie = true;
|
||||||
fExpirationStringValid = false;
|
fExpirationStringValid = false;
|
||||||
fRawFullCookieValid = false;
|
fRawFullCookieValid = false;
|
||||||
fHasExpirationDate = false;
|
|
||||||
} else {
|
} else {
|
||||||
fExpiration = expireDate;
|
fExpiration = expireDate;
|
||||||
fSessionCookie = false;
|
fSessionCookie = false;
|
||||||
fExpirationStringValid = false;
|
fExpirationStringValid = false;
|
||||||
fRawFullCookieValid = false;
|
fRawFullCookieValid = false;
|
||||||
fHasExpirationDate = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
@@ -331,6 +363,13 @@ BNetworkCookie::RawCookie(bool full) const
|
|||||||
// #pragma mark Cookie test
|
// #pragma mark Cookie test
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
BNetworkCookie::IsHostOnly() const
|
||||||
|
{
|
||||||
|
return fHostOnly;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
BNetworkCookie::IsSessionCookie() const
|
BNetworkCookie::IsSessionCookie() const
|
||||||
{
|
{
|
||||||
@@ -410,7 +449,7 @@ BNetworkCookie::HasPath() const
|
|||||||
bool
|
bool
|
||||||
BNetworkCookie::HasExpirationDate() const
|
BNetworkCookie::HasExpirationDate() const
|
||||||
{
|
{
|
||||||
return fHasExpirationDate;
|
return !IsSessionCookie();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -461,7 +500,7 @@ BNetworkCookie::Archive(BMessage* into, bool deep) const
|
|||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fHasExpirationDate) {
|
if (HasExpirationDate()) {
|
||||||
error = into->AddInt32(kArchivedCookieExpirationDate,
|
error = into->AddInt32(kArchivedCookieExpirationDate,
|
||||||
fExpiration.Time_t());
|
fExpiration.Time_t());
|
||||||
if (error != B_OK)
|
if (error != B_OK)
|
||||||
@@ -486,6 +525,12 @@ BNetworkCookie::Archive(BMessage* into, bool deep) const
|
|||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (IsHostOnly()) {
|
||||||
|
error = into->AddBool(kArchivedCookieHostOnly, true);
|
||||||
|
if (error != B_OK)
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -504,32 +549,6 @@ BNetworkCookie::Instantiate(BMessage* archive)
|
|||||||
// #pragma mark Overloaded operators
|
// #pragma mark Overloaded operators
|
||||||
|
|
||||||
|
|
||||||
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&
|
||||||
BNetworkCookie::operator=(const char* string)
|
BNetworkCookie::operator=(const char* string)
|
||||||
{
|
{
|
||||||
@@ -555,16 +574,16 @@ BNetworkCookie::operator!=(const BNetworkCookie& other)
|
|||||||
void
|
void
|
||||||
BNetworkCookie::_Reset()
|
BNetworkCookie::_Reset()
|
||||||
{
|
{
|
||||||
fDomain.Truncate(0);
|
|
||||||
fPath.Truncate(0);
|
|
||||||
fName.Truncate(0);
|
fName.Truncate(0);
|
||||||
fValue.Truncate(0);
|
fValue.Truncate(0);
|
||||||
|
fDomain.Truncate(0);
|
||||||
|
fPath.Truncate(0);
|
||||||
|
fExpiration = BDateTime();
|
||||||
fSecure = false;
|
fSecure = false;
|
||||||
fHttpOnly = false;
|
fHttpOnly = false;
|
||||||
fExpiration = BDateTime();
|
|
||||||
|
|
||||||
fHasExpirationDate = false;
|
|
||||||
fSessionCookie = true;
|
fSessionCookie = true;
|
||||||
|
fHostOnly = true;
|
||||||
|
|
||||||
fRawCookieValid = false;
|
fRawCookieValid = false;
|
||||||
fRawFullCookieValid = false;
|
fRawFullCookieValid = false;
|
||||||
@@ -572,92 +591,116 @@ BNetworkCookie::_Reset()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
int32
|
||||||
BNetworkCookie::_ExtractNameValuePair(const BString& cookieString,
|
skip_whitespace_forward(const BString& string, int32 index)
|
||||||
int16* index, bool parseField)
|
|
||||||
{
|
{
|
||||||
// Skip whitespaces
|
while (index < string.Length() && (string[index] == ' '
|
||||||
while (cookieString.ByteAt(*index) == ' '
|
|| string[index] == '\t'))
|
||||||
&& *index < cookieString.Length())
|
index++;
|
||||||
(*index)++;
|
return 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.Length() - *index);
|
|
||||||
|
|
||||||
*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;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cookie name/value pair
|
|
||||||
if (!parseField) {
|
|
||||||
SetName(name);
|
|
||||||
SetValue(value);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
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");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
int32
|
||||||
BNetworkCookie::_SetDefaultPathForUrl(const BUrl& url)
|
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,
|
||||||
|
BString& name, BString& value, int32 index)
|
||||||
|
{
|
||||||
|
// Find our name-value-pair and the delimiter.
|
||||||
|
int32 firstEquals = cookieString.FindFirst('=', index);
|
||||||
|
int32 nameValueEnd = cookieString.FindFirst(';', index);
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
|
||||||
|
int32 first = skip_whitespace_forward(cookieString, index);
|
||||||
|
int32 last = skip_whitespace_backward(cookieString, firstEquals - 1);
|
||||||
|
|
||||||
|
// If we lack a name, fail to parse.
|
||||||
|
if (first > last)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
cookieString.CopyInto(name, first, last - first + 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();
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BString
|
||||||
|
BNetworkCookie::_DefaultPathForUrl(const BUrl& url)
|
||||||
{
|
{
|
||||||
const BString& path = url.Path();
|
const BString& path = url.Path();
|
||||||
if (path.IsEmpty() || path.ByteAt(0) != '/') {
|
if (path.IsEmpty() || path.ByteAt(0) != '/')
|
||||||
SetPath("/");
|
return "";
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int32 index = path.FindLast('/');
|
int32 index = path.FindLast('/');
|
||||||
if (index == 0) {
|
if (index == 0)
|
||||||
SetPath("/");
|
return "";
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
BString newPath = path;
|
BString newPath = path;
|
||||||
SetPath(newPath.Truncate(index));
|
newPath.Truncate(index);
|
||||||
|
return newPath;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user