From 4e7838fb004f67c51d1b9991ba6782be7036bd7e Mon Sep 17 00:00:00 2001 From: Monroe Linden Date: Fri, 26 Mar 2010 15:39:21 -0700 Subject: Implemented central storage mechanism for media plugin cookies. Added LLPluginCookieStore, which manages the central list of cookies. New Mac and Windows versions of llqtwebkit, built from the tip of the cookie-api branch on http://bitbucket.org/lindenlab/llqtwebkit/ (currently revision f35a5eab8c2f). Added "set_cookies" and "cookie_set" messages to the media_browser message class in the plugin API, and made the webkit plugin use them appropriately. Added methods to LLViewerMedia to read/write the cookie file and add/remove individual cookies. Added hooks to read/write the cookie file (plugin_cookies.txt) in the same places as the location history (idle_startup() in llstartup.cpp and LLAppViewer::cleanup(), respectively). Reviewed by Richard at http://codereview.lindenlab.com/1006003 --- indra/newview/llviewermedia.cpp | 150 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 149 insertions(+), 1 deletion(-) (limited to 'indra/newview/llviewermedia.cpp') diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index 2fcd3f1114..8863bf187d 100644 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -45,6 +45,7 @@ #include "llviewertexturelist.h" #include "llvovolume.h" #include "llpluginclassmedia.h" +#include "llplugincookiestore.h" #include "llviewerwindow.h" #include "llfocusmgr.h" #include "llcallbacklist.h" @@ -256,6 +257,7 @@ public: LLViewerMediaImpl *mMediaImpl; bool mInitialized; }; +LLPluginCookieStore *LLViewerMedia::sCookieStore = NULL; static LLViewerMedia::impl_list sViewerMediaImplList; static LLViewerMedia::impl_id_map sViewerMediaTextureIDMap; static LLTimer sMediaCreateTimer; @@ -264,6 +266,8 @@ static F32 sGlobalVolume = 1.0f; static F64 sLowestLoadableImplInterest = 0.0f; static bool sAnyMediaShowing = false; static boost::signals2::connection sTeleportFinishConnection; +static std::string sUpdatedCookies; +static const char *PLUGIN_COOKIE_FILE_NAME = "plugin_cookies.txt"; ////////////////////////////////////////////////////////////////////////////////////////// static void add_media_impl(LLViewerMediaImpl* media) @@ -399,7 +403,6 @@ viewer_media_t LLViewerMedia::updateMediaImpl(LLMediaEntry* media_entry, const s media_impl->setHomeURL(media_entry->getHomeURL()); media_impl->mMediaAutoPlay = media_entry->getAutoPlay(); media_impl->mMediaEntryURL = media_entry->getCurrentURL(); - if(media_impl->isAutoPlayable()) { needs_navigate = true; @@ -698,6 +701,13 @@ static bool proximity_comparitor(const LLViewerMediaImpl* i1, const LLViewerMedi void LLViewerMedia::updateMedia(void *dummy_arg) { sAnyMediaShowing = false; + sUpdatedCookies = getCookieStore()->getChangedCookies(); + if(!sUpdatedCookies.empty()) + { + lldebugs << "updated cookies will be sent to all loaded plugins: " << llendl; + lldebugs << sUpdatedCookies << llendl; + } + impl_list::iterator iter = sViewerMediaImplList.begin(); impl_list::iterator end = sViewerMediaImplList.end(); @@ -1095,6 +1105,116 @@ void LLViewerMedia::setProxyConfig(bool enable, const std::string &host, int por ///////////////////////////////////////////////////////////////////////////////////////// // static +///////////////////////////////////////////////////////////////////////////////////////// +// static +LLPluginCookieStore *LLViewerMedia::getCookieStore() +{ + if(sCookieStore == NULL) + { + sCookieStore = new LLPluginCookieStore; + } + + return sCookieStore; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// static +void LLViewerMedia::loadCookieFile() +{ + // build filename for each user + std::string resolved_filename = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, PLUGIN_COOKIE_FILE_NAME); + + if (resolved_filename.empty()) + { + llinfos << "can't get path to plugin cookie file - probably not logged in yet." << llendl; + return; + } + + // open the file for reading + llifstream file(resolved_filename); + if (!file.is_open()) + { + llwarns << "can't load plugin cookies from file \"" << PLUGIN_COOKIE_FILE_NAME << "\"" << llendl; + return; + } + + getCookieStore()->readAllCookies(file, true); + + file.close(); + + // TODO: send the clear_cookies message to all loaded plugins +} + + +///////////////////////////////////////////////////////////////////////////////////////// +// static +void LLViewerMedia::saveCookieFile() +{ + // build filename for each user + std::string resolved_filename = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, PLUGIN_COOKIE_FILE_NAME); + + if (resolved_filename.empty()) + { + llinfos << "can't get path to plugin cookie file - probably not logged in yet." << llendl; + return; + } + + // open a file for writing + llofstream file (resolved_filename); + if (!file.is_open()) + { + llwarns << "can't open plugin cookie file \"" << PLUGIN_COOKIE_FILE_NAME << "\" for writing" << llendl; + return; + } + + getCookieStore()->writePersistentCookies(file); + + file.close(); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// static +void LLViewerMedia::addCookie(const std::string &name, const std::string &value, const std::string &domain, const LLDate &expires, const std::string &path, bool secure) +{ + std::stringstream cookie; + + cookie << name << "=" << LLPluginCookieStore::quoteString(value); + + if(expires.notNull()) + { + cookie << "; expires=" << expires.asRFC1123(); + } + + cookie << "; domain=" << domain; + + cookie << "; path=" << path; + + if(secure) + { + cookie << "; secure"; + } + + getCookieStore()->setCookies(cookie.str()); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// static +void LLViewerMedia::addSessionCookie(const std::string &name, const std::string &value, const std::string &domain, const std::string &path, bool secure) +{ + // A session cookie just has a NULL date. + addCookie(name, value, domain, LLDate(), path, secure); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// static +void LLViewerMedia::removeCookie(const std::string &name, const std::string &domain, const std::string &path ) +{ + // To remove a cookie, add one with the same name, domain, and path that expires in the past. + + addCookie(name, "", domain, LLDate(LLDate::now().secondsSinceEpoch() - 1.0), path); +} + + bool LLViewerMedia::hasInWorldMedia() { if (sInWorldMediaDisabled) return false; @@ -1455,6 +1575,17 @@ bool LLViewerMediaImpl::initializePlugin(const std::string& media_type) media_source->clear_cache(); } + // TODO: Only send cookies to plugins that need them + // Ideally, the plugin should tell us whether it handles cookies or not -- either via the init response or through a separate message. + // Due to the ordering of messages, it's possible we wouldn't get that information back in time to send cookies before sending a navigate message, + // which could cause odd race conditions. + std::string all_cookies = LLViewerMedia::getCookieStore()->getAllCookies(); + lldebugs << "setting cookies: " << all_cookies << llendl; + if(!all_cookies.empty()) + { + media_source->set_cookies(all_cookies); + } + mMediaSource = media_source; updateVolume(); @@ -2152,6 +2283,16 @@ void LLViewerMediaImpl::update() } } } + else + { + // If we didn't just create the impl, it may need to get cookie updates. + if(!sUpdatedCookies.empty()) + { + // TODO: Only send cookies to plugins that need them + mMediaSource->set_cookies(sUpdatedCookies); + } + } + if(mMediaSource == NULL) { @@ -2612,6 +2753,13 @@ void LLViewerMediaImpl::handleMediaEvent(LLPluginClassMedia* plugin, LLPluginCla emitEvent(plugin, event); } +//////////////////////////////////////////////////////////////////////////////// +// virtual +void LLViewerMediaImpl::handleCookieSet(LLPluginClassMedia* self, const std::string &cookie) +{ + LLViewerMedia::getCookieStore()->setCookies(cookie); +} + //////////////////////////////////////////////////////////////////////////////// // virtual void -- cgit v1.2.3 From 28e3190296f7d6791e6fd0297f9fcab10239648f Mon Sep 17 00:00:00 2001 From: Monroe Linden Date: Fri, 26 Mar 2010 16:19:34 -0700 Subject: Fix a couple of minor issues with the central cookie storage code. Made LLViewerMedia::clearAllCookies() delete the new per-user cookie file (userdir/plugin_cookies.txt) as well as the old one. Made LLViewerMedia::loadCookieFile() send the clear_cookies message to all loaded plugins. --- indra/newview/llviewermedia.cpp | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) (limited to 'indra/newview/llviewermedia.cpp') diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index 8863bf187d..ab55fcff6e 100644 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -1018,6 +1018,7 @@ void LLViewerMedia::clearAllCookies() // Places that cookie files can be: // /browser_profile/cookies // /first_last/browser_profile/cookies (note that there may be any number of these!) + // /first_last/plugin_cookies.txt (note that there may be any number of these!) std::string base_dir = gDirUtilp->getOSUserAppDir() + gDirUtilp->getDirDelimiter(); std::string target; @@ -1050,6 +1051,16 @@ void LLViewerMedia::clearAllCookies() { LLFile::remove(target); } + + target = base_dir; + target += filename; + target += gDirUtilp->getDirDelimiter(); + target += PLUGIN_COOKIE_FILE_NAME; + lldebugs << "target = " << target << llendl; + if(LLFile::isfile(target)) + { + LLFile::remove(target); + } } @@ -1142,7 +1153,18 @@ void LLViewerMedia::loadCookieFile() file.close(); - // TODO: send the clear_cookies message to all loaded plugins + // send the clear_cookies message to all loaded plugins + impl_list::iterator iter = sViewerMediaImplList.begin(); + impl_list::iterator end = sViewerMediaImplList.end(); + for (; iter != end; iter++) + { + LLViewerMediaImpl* pimpl = *iter; + if(pimpl->mMediaSource) + { + pimpl->mMediaSource->clear_cookies(); + } + } + } -- cgit v1.2.3 From cb7ea3f354f8305471e40090fff96e868517b60e Mon Sep 17 00:00:00 2001 From: Monroe Linden Date: Fri, 26 Mar 2010 18:21:10 -0700 Subject: Fix "clear cookies" not clearing cookies in some cases LLViewerMedia::clearAllCookies was sending "clear cookies" messages to all plugins and deleting cookie files, but it wasn't clearing the cookies in the central store. It now does all of the above. --- indra/newview/llviewermedia.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'indra/newview/llviewermedia.cpp') diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index ab55fcff6e..61a75f7227 100644 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -1008,6 +1008,9 @@ void LLViewerMedia::clearAllCookies() } } + // Clear all cookies from the cookie store + getCookieStore()->setAllCookies(""); + // FIXME: this may not be sufficient, since the on-disk cookie file won't get written until some browser instance exits cleanly. // It also won't clear cookies for other accounts, or for any account if we're not logged in, and won't do anything at all if there are no webkit plugins loaded. // Until such time as we can centralize cookie storage, the following hack should cover these cases: @@ -1051,7 +1054,8 @@ void LLViewerMedia::clearAllCookies() { LLFile::remove(target); } - + + // Other accounts may have new-style cookie files too -- delete them as well target = base_dir; target += filename; target += gDirUtilp->getDirDelimiter(); -- cgit v1.2.3 From 94e6e10739c8321b6fb651a109901380ef92975a Mon Sep 17 00:00:00 2001 From: Loren Shih Date: Mon, 29 Mar 2010 12:00:26 -0400 Subject: EXT-6536 : Make LLVOAvatarSelf a singleton Superficial cleanup to replace all instances of "LLVOAvatarSelf *avatarp = gAgent.getAvatarObject" with "gAgentAvatar". --- indra/newview/llviewermedia.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra/newview/llviewermedia.cpp') diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index 2fcd3f1114..49a3ed14dc 100644 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -3025,7 +3025,7 @@ bool LLViewerMediaImpl::isObjectAttachedToAnotherAvatar(LLVOVolume *obj) if (NULL != object) { LLVOAvatar *avatar = object->asAvatar(); - if (NULL != avatar && avatar != gAgent.getAvatarObject()) + if ((NULL != avatar) && (avatar != gAgentAvatar)) { result = true; break; -- cgit v1.2.3 From 58d76a9ecf83b49e42fabfada27ca20814f93cf3 Mon Sep 17 00:00:00 2001 From: Loren Shih Date: Mon, 29 Mar 2010 12:11:51 -0400 Subject: EXT-6536 : Make LLVOAvatarSelf a singleton Superficial cleanup to replace all instances of "gAgentAvatar" with "gAgentAvatarp". --- indra/newview/llviewermedia.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra/newview/llviewermedia.cpp') diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index 49a3ed14dc..9bf2a5fad2 100644 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -3025,7 +3025,7 @@ bool LLViewerMediaImpl::isObjectAttachedToAnotherAvatar(LLVOVolume *obj) if (NULL != object) { LLVOAvatar *avatar = object->asAvatar(); - if ((NULL != avatar) && (avatar != gAgentAvatar)) + if ((NULL != avatar) && (avatar != gAgentAvatarp)) { result = true; break; -- cgit v1.2.3 From 5c190996222ce2cf14997e16e16beb110173c0a2 Mon Sep 17 00:00:00 2001 From: Monroe Linden Date: Wed, 31 Mar 2010 13:53:40 -0700 Subject: Enable OpenID auth in the embedded webkit browser. Extract openid_url and openid_token tokens from the login response in process_login_success_response() and send them to LLViewerMedia if they're present. Added LLViewerMedia::openIDSetup() to receive openid_url and openid_token, and added code to LLViewerMedia to do a POST with LLHTTPClient, retrieve the resulting cookie, and push it into the central cookie store. Also made sure the OpenID cookie gets re-added when the cookie store is cleared. Added LLPluginCookieStore::setCookiesFromHost() to properly add a cookie that may not have a domain set. Made LLPluginCookieStore::Cookie::parse() add missing domain and path fields to cookies as necessary. Fixed an issue where carriage returns in the string passed to LLPluginCookieStore::setCookies() or LLPluginCookieStore::setCookiesFromHost() would cause a parse failure. Reviewed by gino and callum at http://codereview.lindenlab.com/1254001 --- indra/newview/llviewermedia.cpp | 99 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 97 insertions(+), 2 deletions(-) (limited to 'indra/newview/llviewermedia.cpp') diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index 6f0d9cdd95..d9fabc7d64 100644 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -257,7 +257,43 @@ public: LLViewerMediaImpl *mMediaImpl; bool mInitialized; }; + +class LLViewerMediaOpenIDResponder : public LLHTTPClient::Responder +{ +LOG_CLASS(LLViewerMediaOpenIDResponder); +public: + LLViewerMediaOpenIDResponder( ) + { + } + + ~LLViewerMediaOpenIDResponder() + { + } + + /* virtual */ void completedHeader(U32 status, const std::string& reason, const LLSD& content) + { + LL_DEBUGS("MediaAuth") << "status = " << status << ", reason = " << reason << LL_ENDL; + LL_DEBUGS("MediaAuth") << content << LL_ENDL; + std::string cookie = content["set-cookie"].asString(); + + LLViewerMedia::openIDCookieResponse(cookie); + } + + /* virtual */ void completedRaw( + U32 status, + const std::string& reason, + const LLChannelDescriptors& channels, + const LLIOPipe::buffer_ptr_t& buffer) + { + // This is just here to disable the default behavior (attempting to parse the response as llsd). + // We don't care about the content of the response, only the set-cookie header. + } + +}; + LLPluginCookieStore *LLViewerMedia::sCookieStore = NULL; +LLURL LLViewerMedia::sOpenIDURL; +std::string LLViewerMedia::sOpenIDCookie; static LLViewerMedia::impl_list sViewerMediaImplList; static LLViewerMedia::impl_id_map sViewerMediaTextureIDMap; static LLTimer sMediaCreateTimer; @@ -1067,7 +1103,8 @@ void LLViewerMedia::clearAllCookies() } } - + // If we have an OpenID cookie, re-add it to the cookie store. + setOpenIDCookie(); } ///////////////////////////////////////////////////////////////////////////////////////// @@ -1168,7 +1205,9 @@ void LLViewerMedia::loadCookieFile() pimpl->mMediaSource->clear_cookies(); } } - + + // If we have an OpenID cookie, re-add it to the cookie store. + setOpenIDCookie(); } @@ -1241,6 +1280,62 @@ void LLViewerMedia::removeCookie(const std::string &name, const std::string &dom } +///////////////////////////////////////////////////////////////////////////////////////// +// static +void LLViewerMedia::setOpenIDCookie() +{ + if(!sOpenIDCookie.empty()) + { + getCookieStore()->setCookiesFromHost(sOpenIDCookie, sOpenIDURL.mAuthority); + } +} + +///////////////////////////////////////////////////////////////////////////////////////// +// static +void LLViewerMedia::openIDSetup(const std::string &openid_url, const std::string &openid_token) +{ + LL_DEBUGS("MediaAuth") << "url = \"" << openid_url << "\", token = \"" << openid_token << "\"" << LL_ENDL; + + // post the token to the url + // the responder will need to extract the cookie(s). + + // Save the OpenID URL for later -- we may need the host when adding the cookie. + sOpenIDURL.init(openid_url.c_str()); + + // We shouldn't ever do this twice, but just in case this code gets repurposed later, clear existing cookies. + sOpenIDCookie.clear(); + + LLSD headers = LLSD::emptyMap(); + // Keep LLHTTPClient from adding an "Accept: application/llsd+xml" header + headers["Accept"] = "*/*"; + // and use the expected content-type for a post, instead of the LLHTTPClient::postRaw() default of "application/octet-stream" + headers["Content-Type"] = "application/x-www-form-urlencoded"; + + // postRaw() takes ownership of the buffer and releases it later, so we need to allocate a new buffer here. + size_t size = openid_token.size(); + U8 *data = new U8[size]; + memcpy(data, openid_token.data(), size); + + LLHTTPClient::postRaw( + openid_url, + data, + size, + new LLViewerMediaOpenIDResponder(), + headers); + +} + +///////////////////////////////////////////////////////////////////////////////////////// +// static +void LLViewerMedia::openIDCookieResponse(const std::string &cookie) +{ + LL_DEBUGS("MediaAuth") << "Cookie received: \"" << cookie << "\"" << LL_ENDL; + + sOpenIDCookie += cookie; + + setOpenIDCookie(); +} + bool LLViewerMedia::hasInWorldMedia() { if (sInWorldMediaDisabled) return false; -- cgit v1.2.3 From ab79bf7aaeaa0cbd7b2571601971cce97f9b4acd Mon Sep 17 00:00:00 2001 From: Tofu Linden Date: Thu, 1 Apr 2010 17:34:26 +0100 Subject: Checker: CHECKED_RETURN Function: LLViewerMediaImpl::createMediaSource() File: /indra/newview/llviewermedia.cpp --- indra/newview/llviewermedia.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'indra/newview/llviewermedia.cpp') diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index d9fabc7d64..d3eed40f25 100644 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -1537,7 +1537,10 @@ void LLViewerMediaImpl::createMediaSource() } else if(! mMimeType.empty()) { - initializeMedia(mMimeType); + if (!initializeMedia(mMimeType)) + { + LL_WARNS("Media") << "Failed to initialize media for mime type " << mMimeType << LL_ENDL; + } } } -- cgit v1.2.3 From dcc5e0a4faaf7d877a736ade4a334d1936e71bef Mon Sep 17 00:00:00 2001 From: Richard Linden Date: Thu, 1 Apr 2010 15:48:56 -0700 Subject: EXT-3531 - Ctrl-p doesn't work reliably on login moved gEditMenuHandler handling to LLEditMenuHandler destructor --- indra/newview/llviewermedia.cpp | 5 ----- 1 file changed, 5 deletions(-) (limited to 'indra/newview/llviewermedia.cpp') diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index d3eed40f25..e0cbddafae 100644 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -1473,11 +1473,6 @@ LLViewerMediaImpl::LLViewerMediaImpl( const LLUUID& texture_id, ////////////////////////////////////////////////////////////////////////////////////////// LLViewerMediaImpl::~LLViewerMediaImpl() { - if( gEditMenuHandler == this ) - { - gEditMenuHandler = NULL; - } - destroyMediaSource(); LLViewerMediaTexture::removeMediaImplFromTexture(mTextureId) ; -- cgit v1.2.3 From 8cd95bd12a238c99052cff9195b39467d22e1275 Mon Sep 17 00:00:00 2001 From: Xiaohong Bao Date: Fri, 2 Apr 2010 10:33:20 -0600 Subject: add some debug code for EXT-5394: Crash in LLViewerMediaImpl::calculateInterest() --- indra/newview/llviewermedia.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'indra/newview/llviewermedia.cpp') diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index 6f0d9cdd95..5474eeb486 100644 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -2875,7 +2875,13 @@ void LLViewerMediaImpl::calculateInterest() if(!mObjectList.empty()) { // Just use the first object in the list. We could go through the list and find the closest object, but this should work well enough. - LLVector3d global_delta = gAgent.getPositionGlobal() - (*mObjectList.begin())->getPositionGlobal(); + std::list< LLVOVolume* >::iterator iter = mObjectList.begin() ; + LLVOVolume* objp = *iter ; + llassert_always(objp != NULL) ; + + LLVector3d obj_global = objp->getPositionGlobal() ; + LLVector3d agent_global = gAgent.getPositionGlobal() ; + LLVector3d global_delta = agent_global - obj_global ; mProximityDistance = global_delta.magVecSquared(); // use distance-squared because it's cheaper and sorts the same. } -- cgit v1.2.3