diff --git a/indra/llmessage/aihttpheaders.cpp b/indra/llmessage/aihttpheaders.cpp index 0c6009cad..f019e05ac 100644 --- a/indra/llmessage/aihttpheaders.cpp +++ b/indra/llmessage/aihttpheaders.cpp @@ -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; +} + diff --git a/indra/llmessage/aihttpheaders.h b/indra/llmessage/aihttpheaders.h index da40ed7f9..637390660 100644 --- a/indra/llmessage/aihttpheaders.h +++ b/indra/llmessage/aihttpheaders.h @@ -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::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; diff --git a/indra/llmessage/llhttpclient.cpp b/indra/llmessage/llhttpclient.cpp index 50c6a17e5..4021850a5 100644 --- a/indra/llmessage/llhttpclient.cpp +++ b/indra/llmessage/llhttpclient.cpp @@ -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) diff --git a/indra/llmessage/llhttpclient.h b/indra/llmessage/llhttpclient.h index 70614cc84..e3819cce8 100644 --- a/indra/llmessage/llhttpclient.h +++ b/indra/llmessage/llhttpclient.h @@ -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; } diff --git a/indra/newview/llmarketplacefunctions.cpp b/indra/newview/llmarketplacefunctions.cpp index df2bf5322..c77312204 100644 --- a/indra/newview/llmarketplacefunctions.cpp +++ b/indra/newview/llmarketplacefunctions.cpp @@ -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; + } } } diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index d68b64253..9599ae0cc 100644 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -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; } }