summaryrefslogtreecommitdiff
path: root/indra/newview/llviewermedia.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/newview/llviewermedia.cpp')
-rw-r--r--indra/newview/llviewermedia.cpp454
1 files changed, 440 insertions, 14 deletions
diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp
index 86336e353c..170eb7ae86 100644
--- a/indra/newview/llviewermedia.cpp
+++ b/indra/newview/llviewermedia.cpp
@@ -45,11 +45,13 @@
#include "llviewertexturelist.h"
#include "llvovolume.h"
#include "llpluginclassmedia.h"
+#include "llplugincookiestore.h"
#include "llviewerwindow.h"
#include "llfocusmgr.h"
#include "llcallbacklist.h"
#include "llparcel.h"
#include "llaudioengine.h" // for gAudiop
+#include "llurldispatcher.h"
#include "llvoavatar.h"
#include "llvoavatarself.h"
#include "llviewerregion.h"
@@ -255,6 +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;
@@ -263,6 +302,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)
@@ -398,7 +439,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;
@@ -697,12 +737,19 @@ 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();
- for(; iter != end; iter++)
+ for(; iter != end;)
{
- LLViewerMediaImpl* pimpl = *iter;
+ LLViewerMediaImpl* pimpl = *iter++;
pimpl->update();
pimpl->calculateInterest();
}
@@ -851,7 +898,7 @@ void LLViewerMedia::updateMedia(void *dummy_arg)
}
}
// update the audio stream here as well
- if(!inworld_media_enabled || !inworld_audio_enabled)
+ if( !inworld_audio_enabled)
{
if(LLViewerMedia::isParcelAudioPlaying() && gAudiop && LLViewerMedia::hasParcelAudio())
{
@@ -981,6 +1028,314 @@ bool LLViewerMedia::isParcelAudioPlaying()
return (LLViewerMedia::hasParcelAudio() && gAudiop && LLAudioEngine::AUDIO_PLAYING == gAudiop->isInternetStreamPlaying());
}
+/////////////////////////////////////////////////////////////////////////////////////////
+// static
+void LLViewerMedia::clearAllCookies()
+{
+ // Clear all cookies for all 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();
+ }
+ }
+
+ // 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:
+
+ // HACK: Look for cookie files in all possible places and delete them.
+ // NOTE: this assumes knowledge of what happens inside the webkit plugin (it's what adds 'browser_profile' to the path and names the cookie file)
+
+ // Places that cookie files can be:
+ // <getOSUserAppDir>/browser_profile/cookies
+ // <getOSUserAppDir>/first_last/browser_profile/cookies (note that there may be any number of these!)
+ // <getOSUserAppDir>/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;
+ std::string filename;
+
+ lldebugs << "base dir = " << base_dir << llendl;
+
+ // The non-logged-in version is easy
+ target = base_dir;
+ target += "browser_profile";
+ target += gDirUtilp->getDirDelimiter();
+ target += "cookies";
+ lldebugs << "target = " << target << llendl;
+ if(LLFile::isfile(target))
+ {
+ LLFile::remove(target);
+ }
+
+ // the hard part: iterate over all user directories and delete the cookie file from each one
+ while(gDirUtilp->getNextFileInDir(base_dir, "*_*", filename, false))
+ {
+ target = base_dir;
+ target += filename;
+ target += gDirUtilp->getDirDelimiter();
+ target += "browser_profile";
+ target += gDirUtilp->getDirDelimiter();
+ target += "cookies";
+ lldebugs << "target = " << target << llendl;
+ if(LLFile::isfile(target))
+ {
+ LLFile::remove(target);
+ }
+
+ // Other accounts may have new-style cookie files too -- delete them as well
+ target = base_dir;
+ target += filename;
+ target += gDirUtilp->getDirDelimiter();
+ target += PLUGIN_COOKIE_FILE_NAME;
+ lldebugs << "target = " << target << llendl;
+ if(LLFile::isfile(target))
+ {
+ LLFile::remove(target);
+ }
+ }
+
+ // If we have an OpenID cookie, re-add it to the cookie store.
+ setOpenIDCookie();
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// static
+void LLViewerMedia::clearAllCaches()
+{
+ // Clear all plugins' caches
+ impl_list::iterator iter = sViewerMediaImplList.begin();
+ impl_list::iterator end = sViewerMediaImplList.end();
+ for (; iter != end; iter++)
+ {
+ LLViewerMediaImpl* pimpl = *iter;
+ pimpl->clearCache();
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// static
+void LLViewerMedia::setCookiesEnabled(bool enabled)
+{
+ // Set the "cookies enabled" flag for 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->enable_cookies(enabled);
+ }
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// static
+void LLViewerMedia::setProxyConfig(bool enable, const std::string &host, int port)
+{
+ // Set the proxy config for 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->proxy_setup(enable, host, port);
+ }
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// 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();
+
+ // 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();
+ }
+ }
+
+ // If we have an OpenID cookie, re-add it to the cookie store.
+ setOpenIDCookie();
+}
+
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// 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);
+}
+
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// 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;
@@ -1090,7 +1445,8 @@ LLViewerMediaImpl::LLViewerMediaImpl( const LLUUID& texture_id,
mBackgroundColor(LLColor4::white),
mNavigateSuspended(false),
mNavigateSuspendedDeferred(false),
- mIsUpdated(false)
+ mIsUpdated(false),
+ mTrustedBrowser(false)
{
// Set up the mute list observer if it hasn't been set up already.
@@ -1117,11 +1473,6 @@ LLViewerMediaImpl::LLViewerMediaImpl( const LLUUID& texture_id,
//////////////////////////////////////////////////////////////////////////////////////////
LLViewerMediaImpl::~LLViewerMediaImpl()
{
- if( gEditMenuHandler == this )
- {
- gEditMenuHandler = NULL;
- }
-
destroyMediaSource();
LLViewerMediaTexture::removeMediaImplFromTexture(mTextureId) ;
@@ -1181,7 +1532,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;
+ }
}
}
@@ -1229,6 +1583,19 @@ LLPluginClassMedia* LLViewerMediaImpl::newSourceFromMediaType(std::string media_
std::string user_data_path = gDirUtilp->getOSUserAppDir();
user_data_path += gDirUtilp->getDirDelimiter();
+ // Fix for EXT-5960 - make browser profile specific to user (cache, cookies etc.)
+ // If the linden username returned is blank, that can only mean we are
+ // at the login page displaying login Web page or Web browser test via Develop menu.
+ // In this case we just use whatever gDirUtilp->getOSUserAppDir() gives us (this
+ // is what we always used before this change)
+ std::string linden_user_dir = gDirUtilp->getLindenUserDir();
+ if ( ! linden_user_dir.empty() )
+ {
+ // gDirUtilp->getLindenUserDir() is whole path, not just Linden name
+ user_data_path = linden_user_dir;
+ user_data_path += gDirUtilp->getDirDelimiter();
+ };
+
// See if the plugin executable exists
llstat s;
if(LLFile::stat(launcher_name, &s))
@@ -1243,7 +1610,22 @@ LLPluginClassMedia* LLViewerMediaImpl::newSourceFromMediaType(std::string media_
{
LLPluginClassMedia* media_source = new LLPluginClassMedia(owner);
media_source->setSize(default_width, default_height);
- if (media_source->init(launcher_name, plugin_name, gSavedSettings.getBOOL("PluginAttachDebuggerToPlugins"), user_data_path))
+ media_source->setUserDataPath(user_data_path);
+ media_source->setLanguageCode(LLUI::getLanguage());
+
+ // collect 'cookies enabled' setting from prefs and send to embedded browser
+ bool cookies_enabled = gSavedSettings.getBOOL( "CookiesEnabled" );
+ media_source->enable_cookies( cookies_enabled );
+
+ // collect 'plugins enabled' setting from prefs and send to embedded browser
+ bool plugins_enabled = gSavedSettings.getBOOL( "BrowserPluginsEnabled" );
+ media_source->setPluginsEnabled( plugins_enabled );
+
+ // collect 'javascript enabled' setting from prefs and send to embedded browser
+ bool javascript_enabled = gSavedSettings.getBOOL( "BrowserJavascriptEnabled" );
+ media_source->setJavascriptEnabled( javascript_enabled );
+
+ if (media_source->init(launcher_name, plugin_name, gSavedSettings.getBOOL("PluginAttachDebuggerToPlugins")))
{
return media_source;
}
@@ -1304,12 +1686,25 @@ bool LLViewerMediaImpl::initializePlugin(const std::string& media_type)
media_source->focus(mHasFocus);
media_source->setBackgroundColor(mBackgroundColor);
+ media_source->proxy_setup(gSavedSettings.getBOOL("BrowserProxyEnabled"), gSavedSettings.getString("BrowserProxyAddress"), gSavedSettings.getS32("BrowserProxyPort"));
+
if(mClearCache)
{
mClearCache = false;
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();
@@ -2007,6 +2402,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)
{
@@ -2340,6 +2745,14 @@ void LLViewerMediaImpl::handleMediaEvent(LLPluginClassMedia* plugin, LLPluginCla
{
switch(event)
{
+ case MEDIA_EVENT_CLICK_LINK_NOFOLLOW:
+ {
+ LL_DEBUGS("Media") << "MEDIA_EVENT_CLICK_LINK_NOFOLLOW, uri is: " << plugin->getClickURL() << LL_ENDL;
+ std::string url = plugin->getClickURL();
+ LLURLDispatcher::dispatch(url, NULL, mTrustedBrowser);
+
+ }
+ break;
case MEDIA_EVENT_PLUGIN_FAILED_LAUNCH:
{
// The plugin failed to load properly. Make sure the timer doesn't retry.
@@ -2461,6 +2874,13 @@ void LLViewerMediaImpl::handleMediaEvent(LLPluginClassMedia* plugin, LLPluginCla
////////////////////////////////////////////////////////////////////////////////
// virtual
+void LLViewerMediaImpl::handleCookieSet(LLPluginClassMedia* self, const std::string &cookie)
+{
+ LLViewerMedia::getCookieStore()->setCookies(cookie);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// virtual
void
LLViewerMediaImpl::cut()
{
@@ -2548,7 +2968,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.
}
@@ -2872,7 +3298,7 @@ bool LLViewerMediaImpl::isObjectAttachedToAnotherAvatar(LLVOVolume *obj)
if (NULL != object)
{
LLVOAvatar *avatar = object->asAvatar();
- if (NULL != avatar && avatar != gAgent.getAvatarObject())
+ if ((NULL != avatar) && (avatar != gAgentAvatarp))
{
result = true;
break;