Fix cookie handling.

Cookies are now collected during redirects, one the last cookie
of a given name is kept. Cookies are then set by looking for
the right cookie name (instead of what viewer 3 does: just
use the last cookie that was set).

This fixes the merchant outbox.
This commit is contained in:
Aleric Inglewood
2012-12-24 19:58:36 +01:00
parent fac3fc67b6
commit b22832ba54
6 changed files with 85 additions and 26 deletions

View File

@@ -107,6 +107,20 @@ void AIHTTPReceivedHeaders::addHeader(std::string const& key, std::string const&
{
mContainer = new Container;
}
else if (equal(key, "set-cookie"))
{
// If a cookie with this name already exists, replace it.
std::string const name = value.substr(0, value.find('='));
container_t::iterator const end = mContainer->mKeyValuePairs.end();
for (container_t::iterator header = mContainer->mKeyValuePairs.begin(); header != end; ++header)
{
if (equal(header->first, "set-cookie") && header->second.substr(0, header->second.find('=')) == name)
{
header->second = value;
return;
}
}
}
mContainer->mKeyValuePairs.insert(container_t::value_type(key, value));
}
@@ -151,3 +165,20 @@ std::ostream& operator<<(std::ostream& os, AIHTTPReceivedHeaders const& headers)
return os;
}
//static
bool AIHTTPReceivedHeaders::equal(std::string const& key1, std::string const& key2)
{
if (key1.length() != key2.length())
{
return false;
}
for (std::string::const_iterator i1 = key1.begin(), i2 = key2.begin(); i1 != key1.end(); ++i1, ++i2)
{
if ((*i1 ^ *i2) & 0xdf != 0)
{
return false;
}
}
return true;
}

View File

@@ -132,6 +132,9 @@ class AIHTTPReceivedHeaders {
// Add a header.
void addHeader(std::string const& key, std::string const& value);
// Swap headers with another container.
void swap(AIHTTPReceivedHeaders& headers) { LLPointer<Container>::swap(mContainer, headers.mContainer); }
// Return true if there are no headers associated with this object.
bool empty(void) const { return !mContainer || mContainer->mKeyValuePairs.empty(); }
@@ -147,6 +150,9 @@ class AIHTTPReceivedHeaders {
// For debug purposes.
friend std::ostream& operator<<(std::ostream& os, AIHTTPReceivedHeaders const& headers);
// Returns true if the two keys compare equal (ie, "Set-Cookie" == "set-cookie").
static bool equal(std::string const& key1, std::string const& key2);
private:
struct Container : public LLThreadSafeRefCount {
container_t mKeyValuePairs;

View File

@@ -367,6 +367,22 @@ void LLHTTPClient::ResponderBase::decode_raw_body(U32 status, std::string const&
}
}
std::string const& LLHTTPClient::ResponderBase::get_cookie(std::string const& key)
{
AIHTTPReceivedHeaders::range_type cookies;
mReceivedHeaders.getValues("set-cookie", cookies);
for (AIHTTPReceivedHeaders::iterator_type cookie = cookies.first; cookie != cookies.second; ++cookie)
{
if (key == cookie->second.substr(0, cookie->second.find('=')))
{
return cookie->second;
}
}
// Not found.
static std::string empty_dummy;
return empty_dummy;
}
// Called with HTML body.
// virtual
void LLHTTPClient::ResponderWithCompleted::completedRaw(U32 status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer)

View File

@@ -155,7 +155,16 @@ public:
{
// It's possible that this page was moved (302), so we already saw headers
// from the 302 page and are starting over on the new page now.
mReceivedHeaders.clear();
// Erase all headers EXCEPT the cookies.
AIHTTPReceivedHeaders set_cookie_headers;
AIHTTPReceivedHeaders::range_type cookies;
mReceivedHeaders.getValues("set-cookie", cookies);
for (AIHTTPReceivedHeaders::iterator_type cookie = cookies.first; cookie != cookies.second; ++cookie)
{
set_cookie_headers.addHeader(cookie->first, cookie->second);
}
// Replace headers with just the cookie headers.
mReceivedHeaders.swap(set_cookie_headers);
}
// Called for all remaining headers.
@@ -170,6 +179,9 @@ public:
completedHeaders(status, reason, mReceivedHeaders);
}
// Extract cookie 'key' from mReceivedHeaders and return the string 'key=value', or an empty string if key does not exists.
std::string const& get_cookie(std::string const& key);
public:
// Derived classes that implement completed_headers()/completedHeaders() should return true here.
virtual bool needsHeaders(void) const { return false; }

View File

@@ -200,12 +200,19 @@ namespace LLMarketplaceImport
/*virtual*/ bool followRedir(void) const { return true; }
/*virtual*/ bool needsHeaders(void) const { return true; }
void completedHeaders(U32 status, std::string const& reason, AIHTTPReceivedHeaders const& headers)
/*virtual*/ void completedHeaders(U32 status, std::string const& reason, AIHTTPReceivedHeaders const& headers)
{
std::string set_cookie_string;
if (headers.getFirstValue("set-cookie", set_cookie_string) && !set_cookie_string.empty())
if (status == HTTP_OK)
{
sMarketplaceCookie = set_cookie_string;
std::string value = get_cookie("_slm_session");
if (!value.empty())
{
sMarketplaceCookie = value;
}
else if (sMarketplaceCookie.empty())
{
llwarns << "No such cookie \"_slm_session\" received!" << llendl;
}
}
}

View File

@@ -141,12 +141,7 @@ public:
{
LL_DEBUGS("MediaAuth") << "status = " << status << ", reason = " << reason << LL_ENDL;
LL_DEBUGS("MediaAuth") << headers << LL_ENDL;
AIHTTPReceivedHeaders::range_type cookies;
if (headers.getValues("set-cookie", cookies))
{
for (AIHTTPReceivedHeaders::iterator_type cookie = cookies.first; cookie != cookies.second; ++cookie)
LLViewerMedia::openIDCookieResponse(cookie->second);
}
LLViewerMedia::openIDCookieResponse(get_cookie("agni_sl_session_id"));
}
/* virtual */ void completedRaw(
@@ -190,30 +185,22 @@ public:
for (AIHTTPReceivedHeaders::iterator_type cookie = cookies.first; cookie != cookies.second; ++cookie)
{
LLViewerMedia::getCookieStore()->setCookiesFromHost(cookie->second, mHost);
// The should be only one set-cookie header, and the key should be '_my_secondlife_session'.
// However, lets be a little more flexible. We look for the first header with a key that
// contains the string 'session'.
std::string key = cookie->second.substr(0, cookie->second.find('='));
if (key.find("session") != std::string::npos)
if (key == "_my_secondlife_session")
{
// Set cookie for snapshot publishing.
std::string auth_cookie = cookie->second.substr(0, cookie->second.find(";")); // strip path
if (found)
{
llwarns << "LLViewerMediaWebProfileResponder received more than one *session* cookie!?!" << llendl;
}
else
{
LL_INFOS("MediaAuth") << "Setting openID auth cookie \"" << auth_cookie << "\"." << LL_ENDL;
LLWebProfile::setAuthCookie(auth_cookie);
found = true;
}
LL_INFOS("MediaAuth") << "Setting openID auth cookie \"" << auth_cookie << "\"." << LL_ENDL;
LLWebProfile::setAuthCookie(auth_cookie);
found = true;
break;
}
}
}
if (!found)
{
llwarns << "LLViewerMediaWebProfileResponder did not receive a session ID cookie! OpenID authentications will fail!" << llendl;
llwarns << "LLViewerMediaWebProfileResponder did not receive a session ID cookie \"_my_secondlife_session\"! OpenID authentications will fail!" << llendl;
}
}