summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--indra/llcommon/llassettype.cpp74
-rw-r--r--indra/llcommon/llassettype.h8
-rw-r--r--indra/llcommon/llversionserver.h2
-rw-r--r--indra/llcommon/llversionviewer.h2
-rw-r--r--indra/llmessage/llassetstorage.cpp6
-rw-r--r--indra/llplugin/CMakeLists.txt17
-rw-r--r--indra/llplugin/llplugincookiestore.cpp75
-rw-r--r--indra/llplugin/llplugincookiestore.h9
-rw-r--r--indra/llplugin/tests/llplugincookiestore_test.cpp211
-rw-r--r--indra/newview/English.lproj/InfoPlist.strings4
-rw-r--r--indra/newview/Info-SecondLife.plist2
-rw-r--r--indra/newview/llstartup.cpp7
-rw-r--r--indra/newview/llviewermedia.cpp99
-rw-r--r--indra/newview/llviewermedia.h8
-rw-r--r--indra/newview/res/viewerRes.rc8
15 files changed, 469 insertions, 63 deletions
diff --git a/indra/llcommon/llassettype.cpp b/indra/llcommon/llassettype.cpp
index e5068f1bc5..1c664e093b 100644
--- a/indra/llcommon/llassettype.cpp
+++ b/indra/llcommon/llassettype.cpp
@@ -45,9 +45,9 @@ struct AssetEntry : public LLDictionaryEntry
AssetEntry(const char *desc_name,
const char *type_name, // 8 character limit!
const char *human_name, // for decoding to human readable form; put any and as many printable characters you want in each one
- BOOL can_link, // can you create a link to this type?
- BOOL can_fetch, // can you fetch this asset by ID?
- BOOL can_know) // can you see this asset's ID?
+ bool can_link, // can you create a link to this type?
+ bool can_fetch, // can you fetch this asset by ID?
+ bool can_know) // can you see this asset's ID?
:
LLDictionaryEntry(desc_name),
mTypeName(type_name),
@@ -61,9 +61,9 @@ struct AssetEntry : public LLDictionaryEntry
const char *mTypeName;
const char *mHumanName;
- BOOL mCanLink;
- BOOL mCanFetch;
- BOOL mCanKnow;
+ bool mCanLink;
+ bool mCanFetch;
+ bool mCanKnow;
};
class LLAssetDictionary : public LLSingleton<LLAssetDictionary>,
@@ -77,30 +77,30 @@ LLAssetDictionary::LLAssetDictionary()
{
// DESCRIPTION TYPE NAME HUMAN NAME CAN LINK? CAN FETCH? CAN KNOW?
// |--------------------|-----------|-------------------|-----------|-----------|---------|
- addEntry(LLAssetType::AT_TEXTURE, new AssetEntry("TEXTURE", "texture", "texture", FALSE, FALSE, TRUE));
- addEntry(LLAssetType::AT_SOUND, new AssetEntry("SOUND", "sound", "sound", FALSE, TRUE, TRUE));
- addEntry(LLAssetType::AT_CALLINGCARD, new AssetEntry("CALLINGCARD", "callcard", "calling card", FALSE, FALSE, FALSE));
- addEntry(LLAssetType::AT_LANDMARK, new AssetEntry("LANDMARK", "landmark", "landmark", FALSE, TRUE, TRUE));
- addEntry(LLAssetType::AT_SCRIPT, new AssetEntry("SCRIPT", "script", "legacy script", FALSE, FALSE, FALSE));
- addEntry(LLAssetType::AT_CLOTHING, new AssetEntry("CLOTHING", "clothing", "clothing", TRUE, TRUE, TRUE));
- addEntry(LLAssetType::AT_OBJECT, new AssetEntry("OBJECT", "object", "object", TRUE, FALSE, FALSE));
- addEntry(LLAssetType::AT_NOTECARD, new AssetEntry("NOTECARD", "notecard", "note card", FALSE, FALSE, TRUE));
- addEntry(LLAssetType::AT_CATEGORY, new AssetEntry("CATEGORY", "category", "folder", TRUE, FALSE, FALSE));
- addEntry(LLAssetType::AT_LSL_TEXT, new AssetEntry("LSL_TEXT", "lsltext", "lsl2 script", FALSE, FALSE, FALSE));
- addEntry(LLAssetType::AT_LSL_BYTECODE, new AssetEntry("LSL_BYTECODE", "lslbyte", "lsl bytecode", FALSE, FALSE, FALSE));
- addEntry(LLAssetType::AT_TEXTURE_TGA, new AssetEntry("TEXTURE_TGA", "txtr_tga", "tga texture", FALSE, FALSE, FALSE));
- addEntry(LLAssetType::AT_BODYPART, new AssetEntry("BODYPART", "bodypart", "body part", TRUE, TRUE, TRUE));
- addEntry(LLAssetType::AT_SOUND_WAV, new AssetEntry("SOUND_WAV", "snd_wav", "sound", FALSE, FALSE, FALSE));
- addEntry(LLAssetType::AT_IMAGE_TGA, new AssetEntry("IMAGE_TGA", "img_tga", "targa image", FALSE, FALSE, FALSE));
- addEntry(LLAssetType::AT_IMAGE_JPEG, new AssetEntry("IMAGE_JPEG", "jpeg", "jpeg image", FALSE, FALSE, FALSE));
- addEntry(LLAssetType::AT_ANIMATION, new AssetEntry("ANIMATION", "animatn", "animation", FALSE, TRUE, TRUE));
- addEntry(LLAssetType::AT_GESTURE, new AssetEntry("GESTURE", "gesture", "gesture", TRUE, TRUE, TRUE));
- addEntry(LLAssetType::AT_SIMSTATE, new AssetEntry("SIMSTATE", "simstate", "simstate", FALSE, FALSE, FALSE));
+ addEntry(LLAssetType::AT_TEXTURE, new AssetEntry("TEXTURE", "texture", "texture", false, false, true));
+ addEntry(LLAssetType::AT_SOUND, new AssetEntry("SOUND", "sound", "sound", false, true, true));
+ addEntry(LLAssetType::AT_CALLINGCARD, new AssetEntry("CALLINGCARD", "callcard", "calling card", false, false, false));
+ addEntry(LLAssetType::AT_LANDMARK, new AssetEntry("LANDMARK", "landmark", "landmark", false, true, true));
+ addEntry(LLAssetType::AT_SCRIPT, new AssetEntry("SCRIPT", "script", "legacy script", false, false, false));
+ addEntry(LLAssetType::AT_CLOTHING, new AssetEntry("CLOTHING", "clothing", "clothing", true, true, true));
+ addEntry(LLAssetType::AT_OBJECT, new AssetEntry("OBJECT", "object", "object", true, false, false));
+ addEntry(LLAssetType::AT_NOTECARD, new AssetEntry("NOTECARD", "notecard", "note card", false, false, true));
+ addEntry(LLAssetType::AT_CATEGORY, new AssetEntry("CATEGORY", "category", "folder", true, false, false));
+ addEntry(LLAssetType::AT_LSL_TEXT, new AssetEntry("LSL_TEXT", "lsltext", "lsl2 script", false, false, false));
+ addEntry(LLAssetType::AT_LSL_BYTECODE, new AssetEntry("LSL_BYTECODE", "lslbyte", "lsl bytecode", false, false, false));
+ addEntry(LLAssetType::AT_TEXTURE_TGA, new AssetEntry("TEXTURE_TGA", "txtr_tga", "tga texture", false, false, false));
+ addEntry(LLAssetType::AT_BODYPART, new AssetEntry("BODYPART", "bodypart", "body part", true, true, true));
+ addEntry(LLAssetType::AT_SOUND_WAV, new AssetEntry("SOUND_WAV", "snd_wav", "sound", false, false, false));
+ addEntry(LLAssetType::AT_IMAGE_TGA, new AssetEntry("IMAGE_TGA", "img_tga", "targa image", false, false, false));
+ addEntry(LLAssetType::AT_IMAGE_JPEG, new AssetEntry("IMAGE_JPEG", "jpeg", "jpeg image", false, false, false));
+ addEntry(LLAssetType::AT_ANIMATION, new AssetEntry("ANIMATION", "animatn", "animation", false, true, true));
+ addEntry(LLAssetType::AT_GESTURE, new AssetEntry("GESTURE", "gesture", "gesture", true, true, true));
+ addEntry(LLAssetType::AT_SIMSTATE, new AssetEntry("SIMSTATE", "simstate", "simstate", false, false, false));
- addEntry(LLAssetType::AT_LINK, new AssetEntry("LINK", "link", "sym link", FALSE, FALSE, TRUE));
- addEntry(LLAssetType::AT_LINK_FOLDER, new AssetEntry("FOLDER_LINK", "link_f", "sym folder link", FALSE, FALSE, TRUE));
+ addEntry(LLAssetType::AT_LINK, new AssetEntry("LINK", "link", "sym link", false, false, true));
+ addEntry(LLAssetType::AT_LINK_FOLDER, new AssetEntry("FOLDER_LINK", "link_f", "sym folder link", false, false, true));
- addEntry(LLAssetType::AT_NONE, new AssetEntry("NONE", "-1", NULL, FALSE, FALSE, FALSE));
+ addEntry(LLAssetType::AT_NONE, new AssetEntry("NONE", "-1", NULL, false, false, false));
};
// static
@@ -202,7 +202,7 @@ LLAssetType::EType LLAssetType::lookupHumanReadable(const std::string& readable_
}
// static
-BOOL LLAssetType::lookupCanLink(EType asset_type)
+bool LLAssetType::lookupCanLink(EType asset_type)
{
const LLAssetDictionary *dict = LLAssetDictionary::getInstance();
const AssetEntry *entry = dict->lookup(asset_type);
@@ -210,18 +210,18 @@ BOOL LLAssetType::lookupCanLink(EType asset_type)
{
return entry->mCanLink;
}
- return FALSE;
+ return false;
}
// static
// Not adding this to dictionary since we probably will only have these two types
-BOOL LLAssetType::lookupIsLinkType(EType asset_type)
+bool LLAssetType::lookupIsLinkType(EType asset_type)
{
if (asset_type == AT_LINK || asset_type == AT_LINK_FOLDER)
{
- return TRUE;
+ return true;
}
- return FALSE;
+ return false;
}
// static
@@ -233,7 +233,7 @@ const std::string &LLAssetType::badLookup()
}
// static
-BOOL LLAssetType::lookupIsAssetFetchByIDAllowed(EType asset_type)
+bool LLAssetType::lookupIsAssetFetchByIDAllowed(EType asset_type)
{
const LLAssetDictionary *dict = LLAssetDictionary::getInstance();
const AssetEntry *entry = dict->lookup(asset_type);
@@ -241,11 +241,11 @@ BOOL LLAssetType::lookupIsAssetFetchByIDAllowed(EType asset_type)
{
return entry->mCanFetch;
}
- return FALSE;
+ return false;
}
// static
-BOOL LLAssetType::lookupIsAssetIDKnowable(EType asset_type)
+bool LLAssetType::lookupIsAssetIDKnowable(EType asset_type)
{
const LLAssetDictionary *dict = LLAssetDictionary::getInstance();
const AssetEntry *entry = dict->lookup(asset_type);
@@ -253,5 +253,5 @@ BOOL LLAssetType::lookupIsAssetIDKnowable(EType asset_type)
{
return entry->mCanKnow;
}
- return FALSE;
+ return false;
}
diff --git a/indra/llcommon/llassettype.h b/indra/llcommon/llassettype.h
index 4440e1bac3..2c2dc27aaa 100644
--- a/indra/llcommon/llassettype.h
+++ b/indra/llcommon/llassettype.h
@@ -143,11 +143,11 @@ public:
static EType getType(const std::string& desc_name);
static const std::string& getDesc(EType asset_type);
- static BOOL lookupCanLink(EType asset_type);
- static BOOL lookupIsLinkType(EType asset_type);
+ static bool lookupCanLink(EType asset_type);
+ static bool lookupIsLinkType(EType asset_type);
- static BOOL lookupIsAssetFetchByIDAllowed(EType asset_type); // the asset allows direct download
- static BOOL lookupIsAssetIDKnowable(EType asset_type); // asset data can be known by the viewer
+ static bool lookupIsAssetFetchByIDAllowed(EType asset_type); // the asset allows direct download
+ static bool lookupIsAssetIDKnowable(EType asset_type); // asset data can be known by the viewer
static const std::string& badLookup(); // error string when a lookup fails
diff --git a/indra/llcommon/llversionserver.h b/indra/llcommon/llversionserver.h
index 0f1e59a18c..e3663544db 100644
--- a/indra/llcommon/llversionserver.h
+++ b/indra/llcommon/llversionserver.h
@@ -36,7 +36,7 @@
const S32 LL_VERSION_MAJOR = 1;
const S32 LL_VERSION_MINOR = 31;
const S32 LL_VERSION_PATCH = 0;
-const S32 LL_VERSION_BUILD = 200030;
+const S32 LL_VERSION_BUILD = 203110;
const char * const LL_CHANNEL = "Second Life Server";
diff --git a/indra/llcommon/llversionviewer.h b/indra/llcommon/llversionviewer.h
index 540aea4252..3ab4257fab 100644
--- a/indra/llcommon/llversionviewer.h
+++ b/indra/llcommon/llversionviewer.h
@@ -36,7 +36,7 @@
const S32 LL_VERSION_MAJOR = 2;
const S32 LL_VERSION_MINOR = 0;
const S32 LL_VERSION_PATCH = 0;
-const S32 LL_VERSION_BUILD = 200030;
+const S32 LL_VERSION_BUILD = 203110;
const char * const LL_CHANNEL = "Second Life Developer";
diff --git a/indra/llmessage/llassetstorage.cpp b/indra/llmessage/llassetstorage.cpp
index 0ab1081200..02523467e8 100644
--- a/indra/llmessage/llassetstorage.cpp
+++ b/indra/llmessage/llassetstorage.cpp
@@ -408,6 +408,8 @@ void LLAssetStorage::getAssetData(const LLUUID uuid, LLAssetType::EType type, vo
{
lldebugs << "LLAssetStorage::getAssetData() - " << uuid << "," << LLAssetType::lookup(type) << llendl;
+ llinfos << "ASSET_TRACE requesting " << uuid << " type " << LLAssetType::lookup(type) << llendl;
+
if (mShutDown)
{
return; // don't get the asset or do any callbacks, we are shutting down
@@ -471,6 +473,8 @@ void LLAssetStorage::getAssetData(const LLUUID uuid, LLAssetType::EType type, vo
// we've already got the file
// theoretically, partial files w/o a pending request shouldn't happen
// unless there's a weird error
+ llinfos << "ASSET_TRACE asset " << uuid << " found in VFS" << llendl;
+
if (callback)
{
callback(mVFS, uuid, type, user_data, LL_ERR_NOERR, LL_EXSTAT_VFS_CACHED);
@@ -528,6 +532,8 @@ void LLAssetStorage::downloadCompleteCallback(
LLAssetType::EType file_type,
void* user_data, LLExtStat ext_status)
{
+ llinfos << "ASSET_TRACE asset " << file_id << " downloadCompleteCallback" << llendl;
+
lldebugs << "LLAssetStorage::downloadCompleteCallback() for " << file_id
<< "," << LLAssetType::lookup(file_type) << llendl;
LLAssetRequest* req = (LLAssetRequest*)user_data;
diff --git a/indra/llplugin/CMakeLists.txt b/indra/llplugin/CMakeLists.txt
index def9fcbeae..441becbae0 100644
--- a/indra/llplugin/CMakeLists.txt
+++ b/indra/llplugin/CMakeLists.txt
@@ -3,6 +3,7 @@
project(llplugin)
include(00-Common)
+include(CURL)
include(LLCommon)
include(LLImage)
include(LLMath)
@@ -55,3 +56,19 @@ list(APPEND llplugin_SOURCE_FILES ${llplugin_HEADER_FILES})
add_library (llplugin ${llplugin_SOURCE_FILES})
add_subdirectory(slplugin)
+
+# Add tests
+include(LLAddBuildTest)
+# UNIT TESTS
+SET(llplugin_TEST_SOURCE_FILES
+ llplugincookiestore.cpp
+ )
+
+# llplugincookiestore has a dependency on curl, so we need to link the curl library into the test.
+set_source_files_properties(
+ llplugincookiestore.cpp
+ PROPERTIES
+ LL_TEST_ADDITIONAL_LIBRARIES "${CURL_LIBRARIES}"
+ )
+
+LL_ADD_PROJECT_UNIT_TESTS(llplugin "${llplugin_TEST_SOURCE_FILES}")
diff --git a/indra/llplugin/llplugincookiestore.cpp b/indra/llplugin/llplugincookiestore.cpp
index 1964b8d789..85b1e70d78 100644
--- a/indra/llplugin/llplugincookiestore.cpp
+++ b/indra/llplugin/llplugincookiestore.cpp
@@ -53,7 +53,7 @@ LLPluginCookieStore::~LLPluginCookieStore()
LLPluginCookieStore::Cookie::Cookie(const std::string &s, std::string::size_type cookie_start, std::string::size_type cookie_end):
- mCookie(s, cookie_start, cookie_end),
+ mCookie(s, cookie_start, cookie_end - cookie_start),
mNameStart(0), mNameEnd(0),
mValueStart(0), mValueEnd(0),
mDomainStart(0), mDomainEnd(0),
@@ -62,11 +62,11 @@ LLPluginCookieStore::Cookie::Cookie(const std::string &s, std::string::size_type
{
}
-LLPluginCookieStore::Cookie *LLPluginCookieStore::Cookie::createFromString(const std::string &s, std::string::size_type cookie_start, std::string::size_type cookie_end)
+LLPluginCookieStore::Cookie *LLPluginCookieStore::Cookie::createFromString(const std::string &s, std::string::size_type cookie_start, std::string::size_type cookie_end, const std::string &host)
{
Cookie *result = new Cookie(s, cookie_start, cookie_end);
- if(!result->parse())
+ if(!result->parse(host))
{
delete result;
result = NULL;
@@ -92,7 +92,7 @@ std::string LLPluginCookieStore::Cookie::getKey() const
return result;
}
-bool LLPluginCookieStore::Cookie::parse()
+bool LLPluginCookieStore::Cookie::parse(const std::string &host)
{
bool first_field = true;
@@ -248,7 +248,50 @@ bool LLPluginCookieStore::Cookie::parse()
// The cookie MUST have a name
if(mNameEnd <= mNameStart)
return false;
+
+ // If the cookie doesn't have a domain, add the current host as the domain.
+ if(mDomainEnd <= mDomainStart)
+ {
+ if(host.empty())
+ {
+ // no domain and no current host -- this is a parse failure.
+ return false;
+ }
+
+ // Figure out whether this cookie ended with a ";" or not...
+ std::string::size_type last_char = mCookie.find_last_not_of(" ");
+ if((last_char != std::string::npos) && (mCookie[last_char] != ';'))
+ {
+ mCookie += ";";
+ }
+
+ mCookie += " domain=";
+ mDomainStart = mCookie.size();
+ mCookie += host;
+ mDomainEnd = mCookie.size();
+
+ lldebugs << "added domain (" << mDomainStart << " to " << mDomainEnd << "), new cookie is: " << mCookie << llendl;
+ }
+
+ // If the cookie doesn't have a path, add "/".
+ if(mPathEnd <= mPathStart)
+ {
+ // Figure out whether this cookie ended with a ";" or not...
+ std::string::size_type last_char = mCookie.find_last_not_of(" ");
+ if((last_char != std::string::npos) && (mCookie[last_char] != ';'))
+ {
+ mCookie += ";";
+ }
+
+ mCookie += " path=";
+ mPathStart = mCookie.size();
+ mCookie += "/";
+ mPathEnd = mCookie.size();
+ lldebugs << "added path (" << mPathStart << " to " << mPathEnd << "), new cookie is: " << mCookie << llendl;
+ }
+
+
return true;
}
@@ -409,13 +452,29 @@ void LLPluginCookieStore::setCookies(const std::string &cookies, bool mark_chang
while(start != std::string::npos)
{
- std::string::size_type end = cookies.find('\n', start);
+ std::string::size_type end = cookies.find_first_of("\r\n", start);
if(end > start)
{
// The line is non-empty. Try to create a cookie from it.
setOneCookie(cookies, start, end, mark_changed);
}
- start = cookies.find_first_not_of("\n ", end);
+ start = cookies.find_first_not_of("\r\n ", end);
+ }
+}
+
+void LLPluginCookieStore::setCookiesFromHost(const std::string &cookies, const std::string &host, bool mark_changed)
+{
+ std::string::size_type start = 0;
+
+ while(start != std::string::npos)
+ {
+ std::string::size_type end = cookies.find_first_of("\r\n", start);
+ if(end > start)
+ {
+ // The line is non-empty. Try to create a cookie from it.
+ setOneCookie(cookies, start, end, mark_changed, host);
+ }
+ start = cookies.find_first_not_of("\r\n ", end);
}
}
@@ -502,9 +561,9 @@ std::string LLPluginCookieStore::unquoteString(const std::string &s)
// When deleting with mark_changed set to true, this replaces the existing cookie in the list with an entry that's marked both dead and changed.
// Some time later when writeChangedCookies() is called with clear_changed set to true, the dead cookie is deleted from the list after being returned, so that the
// delete operation (in the form of the expired cookie) is passed along.
-void LLPluginCookieStore::setOneCookie(const std::string &s, std::string::size_type cookie_start, std::string::size_type cookie_end, bool mark_changed)
+void LLPluginCookieStore::setOneCookie(const std::string &s, std::string::size_type cookie_start, std::string::size_type cookie_end, bool mark_changed, const std::string &host)
{
- Cookie *cookie = Cookie::createFromString(s, cookie_start, cookie_end);
+ Cookie *cookie = Cookie::createFromString(s, cookie_start, cookie_end, host);
if(cookie)
{
lldebugs << "setting cookie: " << cookie->getCookie() << llendl;
diff --git a/indra/llplugin/llplugincookiestore.h b/indra/llplugin/llplugincookiestore.h
index 5250f008b6..a93f0c14f0 100644
--- a/indra/llplugin/llplugincookiestore.h
+++ b/indra/llplugin/llplugincookiestore.h
@@ -66,18 +66,21 @@ public:
void setCookies(const std::string &cookies, bool mark_changed = true);
void readCookies(std::istream& s, bool mark_changed = true);
+ // sets one or more cookies (without reinitializing anything), supplying a hostname the cookies came from -- use when setting a cookie manually
+ void setCookiesFromHost(const std::string &cookies, const std::string &host, bool mark_changed = true);
+
// quote or unquote a string as per the definition of 'quoted-string' in rfc2616
static std::string quoteString(const std::string &s);
static std::string unquoteString(const std::string &s);
private:
- void setOneCookie(const std::string &s, std::string::size_type cookie_start, std::string::size_type cookie_end, bool mark_changed);
+ void setOneCookie(const std::string &s, std::string::size_type cookie_start, std::string::size_type cookie_end, bool mark_changed, const std::string &host = LLStringUtil::null);
class Cookie
{
public:
- static Cookie *createFromString(const std::string &s, std::string::size_type cookie_start = 0, std::string::size_type cookie_end = std::string::npos);
+ static Cookie *createFromString(const std::string &s, std::string::size_type cookie_start = 0, std::string::size_type cookie_end = std::string::npos, const std::string &host = LLStringUtil::null);
// Construct a string from the cookie that uniquely represents it, to be used as a key in a std::map.
std::string getKey() const;
@@ -95,7 +98,7 @@ private:
private:
Cookie(const std::string &s, std::string::size_type cookie_start = 0, std::string::size_type cookie_end = std::string::npos);
- bool parse();
+ bool parse(const std::string &host);
std::string::size_type findFieldEnd(std::string::size_type start = 0, std::string::size_type end = std::string::npos);
bool matchName(std::string::size_type start, std::string::size_type end, const char *name);
diff --git a/indra/llplugin/tests/llplugincookiestore_test.cpp b/indra/llplugin/tests/llplugincookiestore_test.cpp
new file mode 100644
index 0000000000..020d9c1977
--- /dev/null
+++ b/indra/llplugin/tests/llplugincookiestore_test.cpp
@@ -0,0 +1,211 @@
+/**
+ * @file llplugincookiestore_test.cpp
+ * @brief Unit tests for LLPluginCookieStore.
+ *
+ * @cond
+ * $LicenseInfo:firstyear=2010&license=viewergpl$
+ *
+ * Copyright (c) 2010, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlife.com/developers/opensource/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at http://secondlife.com/developers/opensource/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ * @endcond
+ */
+
+#include "linden_common.h"
+#include "../test/lltut.h"
+
+#include "../llplugincookiestore.h"
+
+
+namespace tut
+{
+ // Main Setup
+ struct LLPluginCookieStoreFixture
+ {
+ LLPluginCookieStoreFixture()
+ {
+ // We need dates definitively in the past and the future to properly test cookie expiration.
+ LLDate now = LLDate::now();
+ LLDate past(now.secondsSinceEpoch() - (60.0 * 60.0 * 24.0)); // 1 day in the past
+ LLDate future(now.secondsSinceEpoch() + (60.0 * 60.0 * 24.0)); // 1 day in the future
+
+ mPastString = past.asRFC1123();
+ mFutureString = future.asRFC1123();
+ }
+
+ std::string mPastString;
+ std::string mFutureString;
+ LLPluginCookieStore mCookieStore;
+
+ // List of cookies used for validation
+ std::list<std::string> mCookies;
+
+ // This sets up mCookies from a string returned by one of the functions in LLPluginCookieStore
+ void setCookies(const std::string &cookies)
+ {
+ mCookies.clear();
+ std::string::size_type start = 0;
+
+ while(start != std::string::npos)
+ {
+ std::string::size_type end = cookies.find_first_of("\r\n", start);
+ if(end > start)
+ {
+ std::string line(cookies, start, end - start);
+ if(line.find_first_not_of("\r\n\t ") != std::string::npos)
+ {
+ // The line has some non-whitespace characters. Save it to the list.
+ mCookies.push_back(std::string(cookies, start, end - start));
+ }
+ }
+ start = cookies.find_first_not_of("\r\n ", end);
+ }
+ }
+
+ // This ensures that a cookie matching the one passed is in the list.
+ void ensureCookie(const std::string &cookie)
+ {
+ std::list<std::string>::iterator iter;
+ for(iter = mCookies.begin(); iter != mCookies.end(); iter++)
+ {
+ if(*iter == cookie)
+ {
+ // Found the cookie
+ // TODO: this should do a smarter equality comparison on the two cookies, instead of just a string compare.
+ return;
+ }
+ }
+
+ // Didn't find this cookie
+ std::string message = "cookie not found: ";
+ message += cookie;
+ ensure(message, false);
+ }
+
+ // This ensures that the number of cookies in the list matches what's expected.
+ void ensureSize(const std::string &message, size_t size)
+ {
+ if(mCookies.size() != size)
+ {
+ std::stringstream full_message;
+
+ full_message << message << " (expected " << size << ", actual " << mCookies.size() << ")";
+ ensure(full_message.str(), false);
+ }
+ }
+ };
+
+ typedef test_group<LLPluginCookieStoreFixture> factory;
+ typedef factory::object object;
+ factory tf("LLPluginCookieStore test");
+
+ // Tests
+ template<> template<>
+ void object::test<1>()
+ {
+ // Test 1: cookie uniqueness and update lists.
+ // Valid, distinct cookies:
+
+ std::string cookie01 = "cookieA=value; domain=example.com; path=/";
+ std::string cookie02 = "cookieB=value; domain=example.com; path=/"; // different name
+ std::string cookie03 = "cookieA=value; domain=foo.example.com; path=/"; // different domain
+ std::string cookie04 = "cookieA=value; domain=example.com; path=/bar/"; // different path
+ std::string cookie05 = "cookieC; domain=example.com; path=/"; // empty value
+ std::string cookie06 = "cookieD=value; domain=example.com; path=/; expires="; // different name, persistent cookie
+ cookie06 += mFutureString;
+
+ mCookieStore.setCookies(cookie01);
+ mCookieStore.setCookies(cookie02);
+ mCookieStore.setCookies(cookie03);
+ mCookieStore.setCookies(cookie04);
+ mCookieStore.setCookies(cookie05);
+ mCookieStore.setCookies(cookie06);
+
+ // Invalid cookies (these will get parse errors and not be added to the store)
+
+ std::string badcookie01 = "cookieD=value; domain=example.com; path=/; foo=bar"; // invalid field name
+ std::string badcookie02 = "cookieE=value; path=/"; // no domain
+
+ mCookieStore.setCookies(badcookie01);
+ mCookieStore.setCookies(badcookie02);
+
+ // All cookies added so far should have been marked as "changed"
+ setCookies(mCookieStore.getChangedCookies());
+ ensureSize("count of changed cookies", 6);
+ ensureCookie(cookie01);
+ ensureCookie(cookie02);
+ ensureCookie(cookie03);
+ ensureCookie(cookie04);
+ ensureCookie(cookie05);
+ ensureCookie(cookie06);
+
+ // Save off the current state of the cookie store (we'll restore it later)
+ std::string savedCookies = mCookieStore.getAllCookies();
+
+ // Test replacing cookies
+ std::string cookie01a = "cookieA=newvalue; domain=example.com; path=/"; // updated value
+ std::string cookie02a = "cookieB=newvalue; domain=example.com; path=/; expires="; // remove cookie (by setting an expire date in the past)
+ cookie02a += mPastString;
+
+ mCookieStore.setCookies(cookie01a);
+ mCookieStore.setCookies(cookie02a);
+
+ // test for getting changed cookies
+ setCookies(mCookieStore.getChangedCookies());
+ ensureSize("count of updated cookies", 2);
+ ensureCookie(cookie01a);
+ ensureCookie(cookie02a);
+
+ // and for the state of the store after getting changed cookies
+ setCookies(mCookieStore.getAllCookies());
+ ensureSize("count of valid cookies", 5);
+ ensureCookie(cookie01a);
+ ensureCookie(cookie03);
+ ensureCookie(cookie04);
+ ensureCookie(cookie05);
+ ensureCookie(cookie06);
+
+ // Check that only the persistent cookie is returned here
+ setCookies(mCookieStore.getPersistentCookies());
+ ensureSize("count of persistent cookies", 1);
+ ensureCookie(cookie06);
+
+ // Restore the cookie store to a previous state and verify
+ mCookieStore.setAllCookies(savedCookies);
+
+ // Since setAllCookies defaults to not marking cookies as changed, this list should be empty.
+ setCookies(mCookieStore.getChangedCookies());
+ ensureSize("count of changed cookies after restore", 0);
+
+ // Verify that the restore worked as it should have.
+ setCookies(mCookieStore.getAllCookies());
+ ensureSize("count of restored cookies", 6);
+ ensureCookie(cookie01);
+ ensureCookie(cookie02);
+ ensureCookie(cookie03);
+ ensureCookie(cookie04);
+ ensureCookie(cookie05);
+ ensureCookie(cookie06);
+ }
+
+}
diff --git a/indra/newview/English.lproj/InfoPlist.strings b/indra/newview/English.lproj/InfoPlist.strings
index 879408d6e4..02c3dfc6e0 100644
--- a/indra/newview/English.lproj/InfoPlist.strings
+++ b/indra/newview/English.lproj/InfoPlist.strings
@@ -2,6 +2,6 @@
CFBundleName = "Second Life";
-CFBundleShortVersionString = "Second Life version 2.0.0.200030";
-CFBundleGetInfoString = "Second Life version 2.0.0.200030, Copyright 2004-2009 Linden Research, Inc.";
+CFBundleShortVersionString = "Second Life version 2.0.0.203110";
+CFBundleGetInfoString = "Second Life version 2.0.0.203110, Copyright 2004-2009 Linden Research, Inc.";
diff --git a/indra/newview/Info-SecondLife.plist b/indra/newview/Info-SecondLife.plist
index 38ebb22b84..4cb01a0f33 100644
--- a/indra/newview/Info-SecondLife.plist
+++ b/indra/newview/Info-SecondLife.plist
@@ -32,7 +32,7 @@
</dict>
</array>
<key>CFBundleVersion</key>
- <string>2.0.0.200030</string>
+ <string>2.0.0.203110</string>
<key>CSResourcesFileMapped</key>
<true/>
</dict>
diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp
index 1a1dffe85c..b5a73a3143 100644
--- a/indra/newview/llstartup.cpp
+++ b/indra/newview/llstartup.cpp
@@ -3087,6 +3087,13 @@ bool process_login_success_response()
}
}
+ // Start the process of fetching the OpenID session cookie for this user login
+ std::string openid_url = response["openid_url"];
+ if(!openid_url.empty())
+ {
+ std::string openid_token = response["openid_token"];
+ LLViewerMedia::openIDSetup(openid_url, openid_token);
+ }
bool success = false;
// JC: gesture loading done below, when we have an asset system
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;
diff --git a/indra/newview/llviewermedia.h b/indra/newview/llviewermedia.h
index 10dacf9532..e829d7a5b4 100644
--- a/indra/newview/llviewermedia.h
+++ b/indra/newview/llviewermedia.h
@@ -44,6 +44,8 @@
#include "llpluginclassmedia.h"
#include "v4color.h"
+#include "llurl.h"
+
class LLViewerMediaImpl;
class LLUUID;
class LLViewerMediaTexture;
@@ -152,11 +154,17 @@ public:
static void addCookie(const std::string &name, const std::string &value, const std::string &domain, const LLDate &expires, const std::string &path = std::string("/"), bool secure = false );
static void addSessionCookie(const std::string &name, const std::string &value, const std::string &domain, const std::string &path = std::string("/"), bool secure = false );
static void removeCookie(const std::string &name, const std::string &domain, const std::string &path = std::string("/") );
+
+ static void openIDSetup(const std::string &openid_url, const std::string &openid_token);
+ static void openIDCookieResponse(const std::string &cookie);
private:
+ static void setOpenIDCookie();
static void onTeleportFinished();
static LLPluginCookieStore *sCookieStore;
+ static LLURL sOpenIDURL;
+ static std::string sOpenIDCookie;
};
// Implementation functions not exported into header file
diff --git a/indra/newview/res/viewerRes.rc b/indra/newview/res/viewerRes.rc
index 7a965cf57e..ecdcacec46 100644
--- a/indra/newview/res/viewerRes.rc
+++ b/indra/newview/res/viewerRes.rc
@@ -129,8 +129,8 @@ TOOLBUY CURSOR "toolbuy.cur"
//
VS_VERSION_INFO VERSIONINFO
- FILEVERSION 2,0,0,3422
- PRODUCTVERSION 2,0,0,3422
+ FILEVERSION 2,0,0,203110
+ PRODUCTVERSION 2,0,0,203110
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@@ -147,12 +147,12 @@ BEGIN
BEGIN
VALUE "CompanyName", "Linden Lab"
VALUE "FileDescription", "Second Life"
- VALUE "FileVersion", "2.0.0.200030"
+ VALUE "FileVersion", "2.0.0.203110"
VALUE "InternalName", "Second Life"
VALUE "LegalCopyright", "Copyright © 2001-2008, Linden Research, Inc."
VALUE "OriginalFilename", "SecondLife.exe"
VALUE "ProductName", "Second Life"
- VALUE "ProductVersion", "2.0.0.200030"
+ VALUE "ProductVersion", "2.0.0.203110"
END
END
BLOCK "VarFileInfo"