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:
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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; }
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user