Fixed web browser thanks to ArminW/Imprudence
This commit is contained in:
671
indra/llplugin/llplugincookiestore.cpp
Normal file
671
indra/llplugin/llplugincookiestore.cpp
Normal file
@@ -0,0 +1,671 @@
|
||||
/**
|
||||
* @file llplugincookiestore.cpp
|
||||
* @brief LLPluginCookieStore provides central storage for http cookies used by plugins
|
||||
*
|
||||
* @cond
|
||||
* $LicenseInfo:firstyear=2010&license=viewergpl$
|
||||
*
|
||||
* Copyright (c) 2010, Linden Research, Inc.
|
||||
*
|
||||
* Second Life Viewer Source Code
|
||||
* The source code in this file ("Source Code") is provided by Linden Lab
|
||||
* to you under the terms of the GNU General Public License, version 2.0
|
||||
* ("GPL"), unless you have obtained a separate licensing agreement
|
||||
* ("Other License"), formally executed by you and Linden Lab. Terms of
|
||||
* the GPL can be found in doc/GPL-license.txt in this distribution, or
|
||||
* online at http://secondlife.com/developers/opensource/gplv2
|
||||
*
|
||||
* There are special exceptions to the terms and conditions of the GPL as
|
||||
* it is applied to this Source Code. View the full text of the exception
|
||||
* in the file doc/FLOSS-exception.txt in this software distribution, or
|
||||
* online at
|
||||
* http://secondlife.com/developers/opensource/flossexception
|
||||
*
|
||||
* By copying, modifying or distributing this software, you acknowledge
|
||||
* that you have read and understood your obligations described above,
|
||||
* and agree to abide by those obligations.
|
||||
*
|
||||
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
|
||||
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
|
||||
* COMPLETENESS OR PERFORMANCE.
|
||||
* $/LicenseInfo$
|
||||
*
|
||||
* @endcond
|
||||
*/
|
||||
|
||||
#include "linden_common.h"
|
||||
#include "indra_constants.h"
|
||||
|
||||
#include "llplugincookiestore.h"
|
||||
#include <iostream>
|
||||
|
||||
// for curl_getdate() (apparently parsing RFC 1123 dates is hard)
|
||||
#include <curl/curl.h>
|
||||
|
||||
LLPluginCookieStore::LLPluginCookieStore():
|
||||
mHasChangedCookies(false)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
LLPluginCookieStore::~LLPluginCookieStore()
|
||||
{
|
||||
clearCookies();
|
||||
}
|
||||
|
||||
|
||||
LLPluginCookieStore::Cookie::Cookie(const std::string &s, std::string::size_type cookie_start, std::string::size_type cookie_end):
|
||||
mCookie(s, cookie_start, cookie_end - cookie_start),
|
||||
mNameStart(0), mNameEnd(0),
|
||||
mValueStart(0), mValueEnd(0),
|
||||
mDomainStart(0), mDomainEnd(0),
|
||||
mPathStart(0), mPathEnd(0),
|
||||
mDead(false), mChanged(true)
|
||||
{
|
||||
}
|
||||
|
||||
LLPluginCookieStore::Cookie *LLPluginCookieStore::Cookie::createFromString(const std::string &s, std::string::size_type cookie_start, std::string::size_type cookie_end, const std::string &host)
|
||||
{
|
||||
Cookie *result = new Cookie(s, cookie_start, cookie_end);
|
||||
|
||||
if(!result->parse(host))
|
||||
{
|
||||
delete result;
|
||||
result = NULL;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string LLPluginCookieStore::Cookie::getKey() const
|
||||
{
|
||||
std::string result;
|
||||
if(mDomainEnd > mDomainStart)
|
||||
{
|
||||
result += mCookie.substr(mDomainStart, mDomainEnd - mDomainStart);
|
||||
}
|
||||
result += ';';
|
||||
if(mPathEnd > mPathStart)
|
||||
{
|
||||
result += mCookie.substr(mPathStart, mPathEnd - mPathStart);
|
||||
}
|
||||
result += ';';
|
||||
result += mCookie.substr(mNameStart, mNameEnd - mNameStart);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool LLPluginCookieStore::Cookie::parse(const std::string &host)
|
||||
{
|
||||
bool first_field = true;
|
||||
|
||||
std::string::size_type cookie_end = mCookie.size();
|
||||
std::string::size_type field_start = 0;
|
||||
|
||||
LL_DEBUGS("CookieStoreParse") << "parsing cookie: " << mCookie << LL_ENDL;
|
||||
while(field_start < cookie_end)
|
||||
{
|
||||
// Finding the start of the next field requires honoring special quoting rules
|
||||
// see the definition of 'quoted-string' in rfc2616 for details
|
||||
std::string::size_type next_field_start = findFieldEnd(field_start);
|
||||
|
||||
// The end of this field should not include the terminating ';' or any trailing whitespace
|
||||
std::string::size_type field_end = mCookie.find_last_not_of("; ", next_field_start);
|
||||
if(field_end == std::string::npos || field_end < field_start)
|
||||
{
|
||||
// This field was empty or all whitespace. Set end = start so it shows as empty.
|
||||
field_end = field_start;
|
||||
}
|
||||
else if (field_end < next_field_start)
|
||||
{
|
||||
// we actually want the index of the char _after_ what 'last not of' found
|
||||
++field_end;
|
||||
}
|
||||
|
||||
// find the start of the actual name (skip separator and possible whitespace)
|
||||
std::string::size_type name_start = mCookie.find_first_not_of("; ", field_start);
|
||||
if(name_start == std::string::npos || name_start > next_field_start)
|
||||
{
|
||||
// Again, nothing but whitespace.
|
||||
name_start = field_start;
|
||||
}
|
||||
|
||||
// the name and value are separated by the first equals sign
|
||||
std::string::size_type name_value_sep = mCookie.find_first_of("=", name_start);
|
||||
if(name_value_sep == std::string::npos || name_value_sep > field_end)
|
||||
{
|
||||
// No separator found, so this is a field without an =
|
||||
name_value_sep = field_end;
|
||||
}
|
||||
|
||||
// the name end is before the name-value separator
|
||||
std::string::size_type name_end = mCookie.find_last_not_of("= ", name_value_sep);
|
||||
if(name_end == std::string::npos || name_end < name_start)
|
||||
{
|
||||
// I'm not sure how we'd hit this case... it seems like it would have to be an empty name.
|
||||
name_end = name_start;
|
||||
}
|
||||
else if (name_end < name_value_sep)
|
||||
{
|
||||
// we actually want the index of the char _after_ what 'last not of' found
|
||||
++name_end;
|
||||
}
|
||||
|
||||
// Value is between the name-value sep and the end of the field.
|
||||
std::string::size_type value_start = mCookie.find_first_not_of("= ", name_value_sep);
|
||||
if(value_start == std::string::npos || value_start > field_end)
|
||||
{
|
||||
// All whitespace or empty value
|
||||
value_start = field_end;
|
||||
}
|
||||
std::string::size_type value_end = mCookie.find_last_not_of("; ", field_end);
|
||||
if(value_end == std::string::npos || value_end < value_start)
|
||||
{
|
||||
// All whitespace or empty value
|
||||
value_end = value_start;
|
||||
}
|
||||
else if (value_end < field_end)
|
||||
{
|
||||
// we actually want the index of the char _after_ what 'last not of' found
|
||||
++value_end;
|
||||
}
|
||||
|
||||
LL_DEBUGS("CookieStoreParse")
|
||||
<< " field name: \"" << mCookie.substr(name_start, name_end - name_start)
|
||||
<< "\", value: \"" << mCookie.substr(value_start, value_end - value_start) << "\""
|
||||
<< LL_ENDL;
|
||||
|
||||
// See whether this field is one we know
|
||||
if(first_field)
|
||||
{
|
||||
// The first field is the name=value pair
|
||||
mNameStart = name_start;
|
||||
mNameEnd = name_end;
|
||||
mValueStart = value_start;
|
||||
mValueEnd = value_end;
|
||||
first_field = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Subsequent fields must come from the set in rfc2109
|
||||
if(matchName(name_start, name_end, "expires"))
|
||||
{
|
||||
std::string date_string(mCookie, value_start, value_end - value_start);
|
||||
// If the cookie contains an "expires" field, it MUST contain a parsable date.
|
||||
|
||||
// HACK: LLDate apparently can't PARSE an rfc1123-format date, even though it can GENERATE one.
|
||||
// The curl function curl_getdate can do this, but I'm hesitant to unilaterally introduce a curl dependency in LLDate.
|
||||
#if 1
|
||||
time_t date = curl_getdate(date_string.c_str(), NULL );
|
||||
mDate.secondsSinceEpoch((F64)date);
|
||||
LL_DEBUGS("CookieStoreParse") << " expire date parsed to: " << mDate.asRFC1123() << LL_ENDL;
|
||||
#else
|
||||
// This doesn't work (rfc1123-format dates cause it to fail)
|
||||
if(!mDate.fromString(date_string))
|
||||
{
|
||||
// Date failed to parse.
|
||||
LL_WARNS("CookieStoreParse") << "failed to parse cookie's expire date: " << date << LL_ENDL;
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else if(matchName(name_start, name_end, "domain"))
|
||||
{
|
||||
mDomainStart = value_start;
|
||||
mDomainEnd = value_end;
|
||||
}
|
||||
else if(matchName(name_start, name_end, "path"))
|
||||
{
|
||||
mPathStart = value_start;
|
||||
mPathEnd = value_end;
|
||||
}
|
||||
else if(matchName(name_start, name_end, "max-age"))
|
||||
{
|
||||
// TODO: how should we handle this?
|
||||
}
|
||||
else if(matchName(name_start, name_end, "secure"))
|
||||
{
|
||||
// We don't care about the value of this field (yet)
|
||||
}
|
||||
else if(matchName(name_start, name_end, "version"))
|
||||
{
|
||||
// We don't care about the value of this field (yet)
|
||||
}
|
||||
else if(matchName(name_start, name_end, "comment"))
|
||||
{
|
||||
// We don't care about the value of this field (yet)
|
||||
}
|
||||
else if(matchName(name_start, name_end, "httponly"))
|
||||
{
|
||||
// We don't care about the value of this field (yet)
|
||||
}
|
||||
else
|
||||
{
|
||||
// An unknown field is a parse failure
|
||||
LL_WARNS("CookieStoreParse") << "unexpected field name: " << mCookie.substr(name_start, name_end - name_start) << LL_ENDL;
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// move on to the next field, skipping this field's separator and any leading whitespace
|
||||
field_start = mCookie.find_first_not_of("; ", next_field_start);
|
||||
}
|
||||
|
||||
// The cookie MUST have a name
|
||||
if(mNameEnd <= mNameStart)
|
||||
return false;
|
||||
|
||||
// If the cookie doesn't have a domain, add the current host as the domain.
|
||||
if(mDomainEnd <= mDomainStart)
|
||||
{
|
||||
if(host.empty())
|
||||
{
|
||||
// no domain and no current host -- this is a parse failure.
|
||||
return false;
|
||||
}
|
||||
|
||||
// Figure out whether this cookie ended with a ";" or not...
|
||||
std::string::size_type last_char = mCookie.find_last_not_of(" ");
|
||||
if((last_char != std::string::npos) && (mCookie[last_char] != ';'))
|
||||
{
|
||||
mCookie += ";";
|
||||
}
|
||||
|
||||
mCookie += " domain=";
|
||||
mDomainStart = mCookie.size();
|
||||
mCookie += host;
|
||||
mDomainEnd = mCookie.size();
|
||||
|
||||
LL_DEBUGS("CookieStoreParse") << "added domain (" << mDomainStart << " to " << mDomainEnd << "), new cookie is: " << mCookie << LL_ENDL;
|
||||
}
|
||||
|
||||
// If the cookie doesn't have a path, add "/".
|
||||
if(mPathEnd <= mPathStart)
|
||||
{
|
||||
// Figure out whether this cookie ended with a ";" or not...
|
||||
std::string::size_type last_char = mCookie.find_last_not_of(" ");
|
||||
if((last_char != std::string::npos) && (mCookie[last_char] != ';'))
|
||||
{
|
||||
mCookie += ";";
|
||||
}
|
||||
|
||||
mCookie += " path=";
|
||||
mPathStart = mCookie.size();
|
||||
mCookie += "/";
|
||||
mPathEnd = mCookie.size();
|
||||
|
||||
LL_DEBUGS("CookieStoreParse") << "added path (" << mPathStart << " to " << mPathEnd << "), new cookie is: " << mCookie << LL_ENDL;
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string::size_type LLPluginCookieStore::Cookie::findFieldEnd(std::string::size_type start, std::string::size_type end)
|
||||
{
|
||||
std::string::size_type result = start;
|
||||
|
||||
if(end == std::string::npos)
|
||||
end = mCookie.size();
|
||||
|
||||
bool in_quotes = false;
|
||||
for(; (result < end); result++)
|
||||
{
|
||||
switch(mCookie[result])
|
||||
{
|
||||
case '\\':
|
||||
if(in_quotes)
|
||||
result++; // The next character is backslash-quoted. Skip over it.
|
||||
break;
|
||||
case '"':
|
||||
in_quotes = !in_quotes;
|
||||
break;
|
||||
case ';':
|
||||
if(!in_quotes)
|
||||
return result;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If we got here, no ';' was found.
|
||||
return end;
|
||||
}
|
||||
|
||||
bool LLPluginCookieStore::Cookie::matchName(std::string::size_type start, std::string::size_type end, const char *name)
|
||||
{
|
||||
// NOTE: this assumes 'name' is already in lowercase. The code which uses it should be able to arrange this...
|
||||
|
||||
while((start < end) && (*name != '\0'))
|
||||
{
|
||||
if(tolower(mCookie[start]) != *name)
|
||||
return false;
|
||||
|
||||
start++;
|
||||
name++;
|
||||
}
|
||||
|
||||
// iff both strings hit the end at the same time, they're equal.
|
||||
return ((start == end) && (*name == '\0'));
|
||||
}
|
||||
|
||||
std::string LLPluginCookieStore::getAllCookies()
|
||||
{
|
||||
std::stringstream result;
|
||||
writeAllCookies(result);
|
||||
return result.str();
|
||||
}
|
||||
|
||||
void LLPluginCookieStore::writeAllCookies(std::ostream& s)
|
||||
{
|
||||
cookie_map_t::iterator iter;
|
||||
for(iter = mCookies.begin(); iter != mCookies.end(); iter++)
|
||||
{
|
||||
// Don't return expired cookies
|
||||
if(!iter->second->isDead())
|
||||
{
|
||||
s << (iter->second->getCookie()) << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
std::string LLPluginCookieStore::getPersistentCookies()
|
||||
{
|
||||
std::stringstream result;
|
||||
writePersistentCookies(result);
|
||||
return result.str();
|
||||
}
|
||||
|
||||
void LLPluginCookieStore::writePersistentCookies(std::ostream& s)
|
||||
{
|
||||
cookie_map_t::iterator iter;
|
||||
for(iter = mCookies.begin(); iter != mCookies.end(); iter++)
|
||||
{
|
||||
// Don't return expired cookies or session cookies
|
||||
if(!iter->second->isDead() && !iter->second->isSessionCookie())
|
||||
{
|
||||
s << iter->second->getCookie() << "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string LLPluginCookieStore::getChangedCookies(bool clear_changed)
|
||||
{
|
||||
std::stringstream result;
|
||||
writeChangedCookies(result, clear_changed);
|
||||
|
||||
return result.str();
|
||||
}
|
||||
|
||||
void LLPluginCookieStore::writeChangedCookies(std::ostream& s, bool clear_changed)
|
||||
{
|
||||
if(mHasChangedCookies)
|
||||
{
|
||||
lldebugs << "returning changed cookies: " << llendl;
|
||||
cookie_map_t::iterator iter;
|
||||
for(iter = mCookies.begin(); iter != mCookies.end(); )
|
||||
{
|
||||
cookie_map_t::iterator next = iter;
|
||||
next++;
|
||||
|
||||
// Only return cookies marked as "changed"
|
||||
if(iter->second->isChanged())
|
||||
{
|
||||
s << iter->second->getCookie() << "\n";
|
||||
|
||||
lldebugs << " " << iter->second->getCookie() << llendl;
|
||||
|
||||
// If requested, clear the changed mark
|
||||
if(clear_changed)
|
||||
{
|
||||
if(iter->second->isDead())
|
||||
{
|
||||
// If this cookie was previously marked dead, it needs to be removed entirely.
|
||||
delete iter->second;
|
||||
mCookies.erase(iter);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Not dead, just mark as not changed.
|
||||
iter->second->setChanged(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
iter = next;
|
||||
}
|
||||
}
|
||||
|
||||
if(clear_changed)
|
||||
mHasChangedCookies = false;
|
||||
}
|
||||
|
||||
void LLPluginCookieStore::setAllCookies(const std::string &cookies, bool mark_changed)
|
||||
{
|
||||
clearCookies();
|
||||
setCookies(cookies, mark_changed);
|
||||
}
|
||||
|
||||
void LLPluginCookieStore::readAllCookies(std::istream& s, bool mark_changed)
|
||||
{
|
||||
clearCookies();
|
||||
readCookies(s, mark_changed);
|
||||
}
|
||||
|
||||
void LLPluginCookieStore::setCookies(const std::string &cookies, bool mark_changed)
|
||||
{
|
||||
std::string::size_type start = 0;
|
||||
|
||||
while(start != std::string::npos)
|
||||
{
|
||||
std::string::size_type end = cookies.find_first_of("\r\n", start);
|
||||
if(end > start)
|
||||
{
|
||||
// The line is non-empty. Try to create a cookie from it.
|
||||
setOneCookie(cookies, start, end, mark_changed);
|
||||
}
|
||||
start = cookies.find_first_not_of("\r\n ", end);
|
||||
}
|
||||
}
|
||||
|
||||
void LLPluginCookieStore::setCookiesFromHost(const std::string &cookies, const std::string &host, bool mark_changed)
|
||||
{
|
||||
std::string::size_type start = 0;
|
||||
|
||||
while(start != std::string::npos)
|
||||
{
|
||||
std::string::size_type end = cookies.find_first_of("\r\n", start);
|
||||
if(end > start)
|
||||
{
|
||||
// The line is non-empty. Try to create a cookie from it.
|
||||
setOneCookie(cookies, start, end, mark_changed, host);
|
||||
}
|
||||
start = cookies.find_first_not_of("\r\n ", end);
|
||||
}
|
||||
}
|
||||
|
||||
void LLPluginCookieStore::readCookies(std::istream& s, bool mark_changed)
|
||||
{
|
||||
std::string line;
|
||||
while(s.good() && !s.eof())
|
||||
{
|
||||
std::getline(s, line);
|
||||
if(!line.empty())
|
||||
{
|
||||
// Try to create a cookie from this line.
|
||||
setOneCookie(line, 0, std::string::npos, mark_changed);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string LLPluginCookieStore::quoteString(const std::string &s)
|
||||
{
|
||||
std::stringstream result;
|
||||
|
||||
result << '"';
|
||||
|
||||
for(std::string::size_type i = 0; i < s.size(); ++i)
|
||||
{
|
||||
char c = s[i];
|
||||
switch(c)
|
||||
{
|
||||
// All these separators need to be quoted in HTTP headers, according to section 2.2 of rfc 2616:
|
||||
case '(': case ')': case '<': case '>': case '@':
|
||||
case ',': case ';': case ':': case '\\': case '"':
|
||||
case '/': case '[': case ']': case '?': case '=':
|
||||
case '{': case '}': case ' ': case '\t':
|
||||
result << '\\';
|
||||
break;
|
||||
}
|
||||
|
||||
result << c;
|
||||
}
|
||||
|
||||
result << '"';
|
||||
|
||||
return result.str();
|
||||
}
|
||||
|
||||
std::string LLPluginCookieStore::unquoteString(const std::string &s)
|
||||
{
|
||||
std::stringstream result;
|
||||
|
||||
bool in_quotes = false;
|
||||
|
||||
for(std::string::size_type i = 0; i < s.size(); ++i)
|
||||
{
|
||||
char c = s[i];
|
||||
switch(c)
|
||||
{
|
||||
case '\\':
|
||||
if(in_quotes)
|
||||
{
|
||||
// The next character is backslash-quoted. Pass it through untouched.
|
||||
++i;
|
||||
if(i < s.size())
|
||||
{
|
||||
result << s[i];
|
||||
}
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
case '"':
|
||||
in_quotes = !in_quotes;
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
|
||||
result << c;
|
||||
}
|
||||
|
||||
return result.str();
|
||||
}
|
||||
|
||||
// The flow for deleting a cookie is non-obvious enough that I should call it out here...
|
||||
// Deleting a cookie is done by setting a cookie with the same name, path, and domain, but with an expire timestamp in the past.
|
||||
// (This is exactly how a web server tells a browser to delete a cookie.)
|
||||
// When deleting with mark_changed set to true, this replaces the existing cookie in the list with an entry that's marked both dead and changed.
|
||||
// Some time later when writeChangedCookies() is called with clear_changed set to true, the dead cookie is deleted from the list after being returned, so that the
|
||||
// delete operation (in the form of the expired cookie) is passed along.
|
||||
void LLPluginCookieStore::setOneCookie(const std::string &s, std::string::size_type cookie_start, std::string::size_type cookie_end, bool mark_changed, const std::string &host)
|
||||
{
|
||||
Cookie *cookie = Cookie::createFromString(s, cookie_start, cookie_end, host);
|
||||
if(cookie)
|
||||
{
|
||||
LL_DEBUGS("CookieStoreUpdate") << "setting cookie: " << cookie->getCookie() << LL_ENDL;
|
||||
|
||||
// Create a key for this cookie
|
||||
std::string key = cookie->getKey();
|
||||
|
||||
// Check to see whether this cookie should have expired
|
||||
if(!cookie->isSessionCookie() && (cookie->getDate() < LLDate::now()))
|
||||
{
|
||||
// This cookie has expired.
|
||||
if(mark_changed)
|
||||
{
|
||||
// If we're marking cookies as changed, we should keep it anyway since we'll need to send it out with deltas.
|
||||
cookie->setDead(true);
|
||||
LL_DEBUGS("CookieStoreUpdate") << " marking dead" << LL_ENDL;
|
||||
}
|
||||
else
|
||||
{
|
||||
// If we're not marking cookies as changed, we don't need to keep this cookie at all.
|
||||
// If the cookie was already in the list, delete it.
|
||||
removeCookie(key);
|
||||
|
||||
delete cookie;
|
||||
cookie = NULL;
|
||||
|
||||
LL_DEBUGS("CookieStoreUpdate") << " removing" << LL_ENDL;
|
||||
}
|
||||
}
|
||||
|
||||
if(cookie)
|
||||
{
|
||||
// If it already exists in the map, replace it.
|
||||
cookie_map_t::iterator iter = mCookies.find(key);
|
||||
if(iter != mCookies.end())
|
||||
{
|
||||
if(iter->second->getCookie() == cookie->getCookie())
|
||||
{
|
||||
// The new cookie is identical to the old -- don't mark as changed.
|
||||
// Just leave the old one in the map.
|
||||
delete cookie;
|
||||
cookie = NULL;
|
||||
|
||||
LL_DEBUGS("CookieStoreUpdate") << " unchanged" << LL_ENDL;
|
||||
}
|
||||
else
|
||||
{
|
||||
// A matching cookie was already in the map. Replace it.
|
||||
delete iter->second;
|
||||
iter->second = cookie;
|
||||
|
||||
cookie->setChanged(mark_changed);
|
||||
if(mark_changed)
|
||||
mHasChangedCookies = true;
|
||||
|
||||
LL_DEBUGS("CookieStoreUpdate") << " replacing" << LL_ENDL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// The cookie wasn't in the map. Insert it.
|
||||
mCookies.insert(std::make_pair(key, cookie));
|
||||
|
||||
cookie->setChanged(mark_changed);
|
||||
if(mark_changed)
|
||||
mHasChangedCookies = true;
|
||||
|
||||
LL_DEBUGS("CookieStoreUpdate") << " adding" << LL_ENDL;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_WARNS("CookieStoreUpdate") << "failed to parse cookie: " << s.substr(cookie_start, cookie_end - cookie_start) << LL_ENDL;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void LLPluginCookieStore::clearCookies()
|
||||
{
|
||||
while(!mCookies.empty())
|
||||
{
|
||||
cookie_map_t::iterator iter = mCookies.begin();
|
||||
delete iter->second;
|
||||
mCookies.erase(iter);
|
||||
}
|
||||
}
|
||||
|
||||
void LLPluginCookieStore::removeCookie(const std::string &key)
|
||||
{
|
||||
cookie_map_t::iterator iter = mCookies.find(key);
|
||||
if(iter != mCookies.end())
|
||||
{
|
||||
delete iter->second;
|
||||
mCookies.erase(iter);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user