summaryrefslogtreecommitdiff
path: root/indra/llplugin
diff options
context:
space:
mode:
authorRider Linden <rider@lindenlab.com>2018-04-13 14:50:07 -0700
committerRider Linden <rider@lindenlab.com>2018-04-13 14:50:07 -0700
commit033b6269593deb370378663354ee2a78eba54387 (patch)
tree200c8575c45a2384a8fa2803cd9a724c85057eae /indra/llplugin
parent7b56db31f91545102744885b4f70c93278e837bd (diff)
parent41f4e854732a7c75a813b2e99285cc41bde13e5e (diff)
Merge
Diffstat (limited to 'indra/llplugin')
-rw-r--r--indra/llplugin/CMakeLists.txt19
-rw-r--r--indra/llplugin/llpluginclassmedia.cpp48
-rw-r--r--indra/llplugin/llpluginclassmedia.h10
-rw-r--r--indra/llplugin/llpluginclassmediaowner.h28
-rw-r--r--indra/llplugin/llplugincookiestore.cpp689
-rw-r--r--indra/llplugin/llplugincookiestore.h123
-rw-r--r--indra/llplugin/tests/llplugincookiestore_test.cpp207
7 files changed, 48 insertions, 1076 deletions
diff --git a/indra/llplugin/CMakeLists.txt b/indra/llplugin/CMakeLists.txt
index 129efeb529..5cc129a267 100644
--- a/indra/llplugin/CMakeLists.txt
+++ b/indra/llplugin/CMakeLists.txt
@@ -29,7 +29,6 @@ include_directories(SYSTEM
set(llplugin_SOURCE_FILES
llpluginclassmedia.cpp
- llplugincookiestore.cpp
llplugininstance.cpp
llpluginmessage.cpp
llpluginmessagepipe.cpp
@@ -43,7 +42,6 @@ set(llplugin_HEADER_FILES
llpluginclassmedia.h
llpluginclassmediaowner.h
- llplugincookiestore.h
llplugininstance.h
llpluginmessage.h
llpluginmessageclasses.h
@@ -70,20 +68,3 @@ add_library (llplugin ${llplugin_SOURCE_FILES})
add_subdirectory(slplugin)
-# Add tests
-if (LL_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};${NGHTTP2_LIBRARIES}"
- )
-
- LL_ADD_PROJECT_UNIT_TESTS(llplugin "${llplugin_TEST_SOURCE_FILES}")
-endif (LL_TESTS)
diff --git a/indra/llplugin/llpluginclassmedia.cpp b/indra/llplugin/llpluginclassmedia.cpp
index 680017204c..78eb6e75bb 100644
--- a/indra/llplugin/llpluginclassmedia.cpp
+++ b/indra/llplugin/llpluginclassmedia.cpp
@@ -31,6 +31,9 @@
#include "llpluginclassmedia.h"
#include "llpluginmessageclasses.h"
+#include "llcontrol.h"
+
+extern LLControlGroup gSavedSettings;
static int LOW_PRIORITY_TEXTURE_SIZE_DEFAULT = 256;
@@ -792,15 +795,22 @@ F64 LLPluginClassMedia::getCPUUsage()
return result;
}
-void LLPluginClassMedia::sendPickFileResponse(const std::string &file)
+void LLPluginClassMedia::sendPickFileResponse(const std::vector<std::string> files)
{
LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "pick_file_response");
- message.setValue("file", file);
if(mPlugin && mPlugin->isBlocked())
{
// If the plugin sent a blocking pick-file request, the response should unblock it.
message.setValueBoolean("blocking_response", true);
}
+
+ LLSD file_list = LLSD::emptyArray();
+ for (std::vector<std::string>::const_iterator in_iter = files.begin(); in_iter != files.end(); ++in_iter)
+ {
+ file_list.append(LLSD::String(*in_iter));
+ }
+ message.setValueLLSD("file_list", file_list);
+
sendMessage(message);
}
@@ -836,11 +846,17 @@ void LLPluginClassMedia::paste()
sendMessage(message);
}
-void LLPluginClassMedia::setUserDataPath(const std::string &user_data_path_cache, const std::string &user_data_path_cookies)
+void LLPluginClassMedia::setUserDataPath(const std::string &user_data_path_cache,
+ const std::string &user_data_path_cookies,
+ const std::string &user_data_path_cef_log)
{
LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "set_user_data_path");
message.setValue("cache_path", user_data_path_cache);
message.setValue("cookies_path", user_data_path_cookies);
+ message.setValue("cef_log_file", user_data_path_cef_log);
+
+ bool cef_verbose_log = gSavedSettings.getBOOL("CefVerboseLog");
+ message.setValueBoolean("cef_verbose_log", cef_verbose_log);
sendMessage(message);
}
@@ -1090,6 +1106,7 @@ void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message)
}
else if(message_name == "pick_file")
{
+ mIsMultipleFilePick = message.getValueBoolean("multiple_files");
mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_PICK_FILE_REQUEST);
}
else if(message_name == "auth_request")
@@ -1151,7 +1168,12 @@ void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message)
{
mClickURL = message.getValue("uri");
mClickTarget = message.getValue("target");
- mClickUUID = message.getValue("uuid");
+
+ // need a link to have a UUID that identifies it to a system further
+ // upstream - plugin could make it but we have access to LLUUID here
+ // so why don't we use it
+ mClickUUID = LLUUID::generateNewID().asString();
+
mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_CLICK_LINK_HREF);
}
else if(message_name == "click_nofollow")
@@ -1166,13 +1188,6 @@ void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message)
mStatusCode = message.getValueS32("status_code");
mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_NAVIGATE_ERROR_PAGE);
}
- else if(message_name == "cookie_set")
- {
- if(mOwner)
- {
- mOwner->handleCookieSet(this, message.getValue("cookie"));
- }
- }
else if(message_name == "close_request")
{
mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_CLOSE_REQUEST);
@@ -1287,16 +1302,9 @@ void LLPluginClassMedia::clear_cookies()
sendMessage(message);
}
-void LLPluginClassMedia::set_cookies(const std::string &cookies)
-{
- LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "set_cookies");
- message.setValue("cookies", cookies);
- sendMessage(message);
-}
-
-void LLPluginClassMedia::enable_cookies(bool enable)
+void LLPluginClassMedia::cookies_enabled(bool enable)
{
- LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "enable_cookies");
+ LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "cookies_enabled");
message.setValueBoolean("enable", enable);
sendMessage(message);
}
diff --git a/indra/llplugin/llpluginclassmedia.h b/indra/llplugin/llpluginclassmedia.h
index 3b0739d044..3b3075c6bd 100644
--- a/indra/llplugin/llpluginclassmedia.h
+++ b/indra/llplugin/llpluginclassmedia.h
@@ -176,7 +176,7 @@ public:
F64 getCPUUsage();
- void sendPickFileResponse(const std::string &file);
+ void sendPickFileResponse(const std::vector<std::string> files);
void sendAuthResponse(bool ok, const std::string &username, const std::string &password);
@@ -195,7 +195,7 @@ public:
bool canPaste() const { return mCanPaste; };
// These can be called before init(), and they will be queued and sent before the media init message.
- void setUserDataPath(const std::string &user_data_path_cache, const std::string &user_data_path_cookies);
+ void setUserDataPath(const std::string &user_data_path_cache, const std::string &user_data_path_cookies, const std::string &user_data_path_cef_log);
void setLanguageCode(const std::string &language_code);
void setPluginsEnabled(const bool enabled);
void setJavascriptEnabled(const bool enabled);
@@ -210,7 +210,7 @@ public:
void clear_cache();
void clear_cookies();
void set_cookies(const std::string &cookies);
- void enable_cookies(bool enable);
+ void cookies_enabled(bool enable);
void proxy_setup(bool enable, const std::string &host = LLStringUtil::null, int port = 0);
void browse_stop();
void browse_reload(bool ignore_cache = false);
@@ -277,6 +277,9 @@ public:
std::string getAuthURL() const { return mAuthURL; };
std::string getAuthRealm() const { return mAuthRealm; };
+ // These are valid during MEDIA_EVENT_PICK_FILE_REQUEST
+ bool getIsMultipleFilePick() const { return mIsMultipleFilePick; }
+
// These are valid during MEDIA_EVENT_LINK_HOVERED
std::string getHoverText() const { return mHoverText; };
std::string getHoverLink() const { return mHoverLink; };
@@ -435,6 +438,7 @@ protected:
std::string mHoverText;
std::string mHoverLink;
std::string mFileDownloadFilename;
+ bool mIsMultipleFilePick;
/////////////////////////////////////////
// media_time class
diff --git a/indra/llplugin/llpluginclassmediaowner.h b/indra/llplugin/llpluginclassmediaowner.h
index 391c23d883..89f55eaf71 100644
--- a/indra/llplugin/llpluginclassmediaowner.h
+++ b/indra/llplugin/llpluginclassmediaowner.h
@@ -1,4 +1,4 @@
-/**
+/**
* @file llpluginclassmediaowner.h
* @brief LLPluginClassMedia handles interaction with a plugin which knows about the "media" message class.
*
@@ -6,21 +6,21 @@
* $LicenseInfo:firstyear=2008&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
- *
+ *
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
- *
+ *
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
- *
+ *
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
+ *
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
* @endcond
@@ -34,18 +34,17 @@
#include <queue>
class LLPluginClassMedia;
-class LLPluginCookieStore;
class LLPluginClassMediaOwner
{
public:
typedef enum
{
- MEDIA_EVENT_CONTENT_UPDATED, // contents/dirty rect have updated
+ MEDIA_EVENT_CONTENT_UPDATED, // contents/dirty rect have updated
MEDIA_EVENT_TIME_DURATION_UPDATED, // current time and/or duration have updated
MEDIA_EVENT_SIZE_CHANGED, // media size has changed
MEDIA_EVENT_CURSOR_CHANGED, // plugin has requested a cursor change
-
+
MEDIA_EVENT_NAVIGATE_BEGIN, // browser has begun navigation
MEDIA_EVENT_NAVIGATE_COMPLETE, // browser has finished navigation
MEDIA_EVENT_PROGRESS_UPDATED, // browser has updated loading progress
@@ -58,8 +57,8 @@ public:
MEDIA_EVENT_CLOSE_REQUEST, // The plugin requested its window be closed (currently hooked up to javascript window.close in webkit)
MEDIA_EVENT_PICK_FILE_REQUEST, // The plugin wants the user to pick a file
MEDIA_EVENT_GEOMETRY_CHANGE, // The plugin requested its window geometry be changed (per the javascript window interface)
-
- MEDIA_EVENT_PLUGIN_FAILED_LAUNCH, // The plugin failed to launch
+
+ MEDIA_EVENT_PLUGIN_FAILED_LAUNCH, // The plugin failed to launch
MEDIA_EVENT_PLUGIN_FAILED, // The plugin died unexpectedly
MEDIA_EVENT_AUTH_REQUEST, // The plugin wants to display an auth dialog
@@ -69,9 +68,9 @@ public:
MEDIA_EVENT_DEBUG_MESSAGE, // plugin sending back debug information for host to process
MEDIA_EVENT_LINK_HOVERED // Got a "link hovered" event from the plugin
-
+
} EMediaEvent;
-
+
typedef enum
{
MEDIA_NONE, // Uninitialized -- no useful state
@@ -81,12 +80,11 @@ public:
MEDIA_PLAYING, // playing (only for time-based media)
MEDIA_PAUSED, // paused (only for time-based media)
MEDIA_DONE // finished playing (only for time-based media)
-
+
} EMediaStatus;
-
+
virtual ~LLPluginClassMediaOwner() {};
virtual void handleMediaEvent(LLPluginClassMedia* /*self*/, EMediaEvent /*event*/) {};
- virtual void handleCookieSet(LLPluginClassMedia* /*self*/, const std::string &/*cookie*/) {};
};
#endif // LL_LLPLUGINCLASSMEDIAOWNER_H
diff --git a/indra/llplugin/llplugincookiestore.cpp b/indra/llplugin/llplugincookiestore.cpp
deleted file mode 100644
index a5d717389d..0000000000
--- a/indra/llplugin/llplugincookiestore.cpp
+++ /dev/null
@@ -1,689 +0,0 @@
-/**
- * @file llplugincookiestore.cpp
- * @brief LLPluginCookieStore provides central storage for http cookies used by plugins
- *
- * @cond
- * $LicenseInfo:firstyear=2010&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- * @endcond
- */
-
-#include "linden_common.h"
-#include "llstl.h"
-#include "indra_constants.h"
-
-#include "llplugincookiestore.h"
-#include <iostream>
-
-// for curl_getdate() (apparently parsing RFC 1123 dates is hard)
-#include <curl/curl.h>
-
-LLPluginCookieStore::LLPluginCookieStore():
- mHasChangedCookies(false)
-{
-}
-
-
-LLPluginCookieStore::~LLPluginCookieStore()
-{
- clearCookies();
-}
-
-
-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 - cookie_start),
- mNameStart(0), mNameEnd(0),
- mValueStart(0), mValueEnd(0),
- mDomainStart(0), mDomainEnd(0),
- mPathStart(0), mPathEnd(0),
- mDead(false), mChanged(true)
-{
-}
-
-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(host))
- {
- delete result;
- result = NULL;
- }
-
- return result;
-}
-
-std::string LLPluginCookieStore::Cookie::getKey() const
-{
- std::string result;
- if(mDomainEnd > mDomainStart)
- {
- result += mCookie.substr(mDomainStart, mDomainEnd - mDomainStart);
- }
- result += ';';
- if(mPathEnd > mPathStart)
- {
- result += mCookie.substr(mPathStart, mPathEnd - mPathStart);
- }
- result += ';';
- result += mCookie.substr(mNameStart, mNameEnd - mNameStart);
- return result;
-}
-
-std::string LLPluginCookieStore::Cookie::getDomain() const
-{
- std::string result;
- if(mDomainEnd > mDomainStart)
- {
- result += mCookie.substr(mDomainStart, mDomainEnd - mDomainStart);
- }
- return result;
-}
-
-bool LLPluginCookieStore::Cookie::parse(const std::string &host)
-{
- bool first_field = true;
-
- std::string::size_type cookie_end = mCookie.size();
- std::string::size_type field_start = 0;
-
- LL_DEBUGS("CookieStoreParse") << "parsing cookie: " << mCookie << LL_ENDL;
- while(field_start < cookie_end)
- {
- // Finding the start of the next field requires honoring special quoting rules
- // see the definition of 'quoted-string' in rfc2616 for details
- std::string::size_type next_field_start = findFieldEnd(field_start);
-
- // The end of this field should not include the terminating ';' or any trailing whitespace
- std::string::size_type field_end = mCookie.find_last_not_of("; ", next_field_start);
- if(field_end == std::string::npos || field_end < field_start)
- {
- // This field was empty or all whitespace. Set end = start so it shows as empty.
- field_end = field_start;
- }
- else if (field_end < next_field_start)
- {
- // we actually want the index of the char _after_ what 'last not of' found
- ++field_end;
- }
-
- // find the start of the actual name (skip separator and possible whitespace)
- std::string::size_type name_start = mCookie.find_first_not_of("; ", field_start);
- if(name_start == std::string::npos || name_start > next_field_start)
- {
- // Again, nothing but whitespace.
- name_start = field_start;
- }
-
- // the name and value are separated by the first equals sign
- std::string::size_type name_value_sep = mCookie.find_first_of("=", name_start);
- if(name_value_sep == std::string::npos || name_value_sep > field_end)
- {
- // No separator found, so this is a field without an =
- name_value_sep = field_end;
- }
-
- // the name end is before the name-value separator
- std::string::size_type name_end = mCookie.find_last_not_of("= ", name_value_sep);
- if(name_end == std::string::npos || name_end < name_start)
- {
- // I'm not sure how we'd hit this case... it seems like it would have to be an empty name.
- name_end = name_start;
- }
- else if (name_end < name_value_sep)
- {
- // we actually want the index of the char _after_ what 'last not of' found
- ++name_end;
- }
-
- // Value is between the name-value sep and the end of the field.
- std::string::size_type value_start = mCookie.find_first_not_of("= ", name_value_sep);
- if(value_start == std::string::npos || value_start > field_end)
- {
- // All whitespace or empty value
- value_start = field_end;
- }
- std::string::size_type value_end = mCookie.find_last_not_of("; ", field_end);
- if(value_end == std::string::npos || value_end < value_start)
- {
- // All whitespace or empty value
- value_end = value_start;
- }
- else if (value_end < field_end)
- {
- // we actually want the index of the char _after_ what 'last not of' found
- ++value_end;
- }
-
- LL_DEBUGS("CookieStoreParse")
- << " field name: \"" << mCookie.substr(name_start, name_end - name_start)
- << "\", value: \"" << mCookie.substr(value_start, value_end - value_start) << "\""
- << LL_ENDL;
-
- // See whether this field is one we know
- if(first_field)
- {
- // The first field is the name=value pair
- mNameStart = name_start;
- mNameEnd = name_end;
- mValueStart = value_start;
- mValueEnd = value_end;
- first_field = false;
- }
- else
- {
- // Subsequent fields must come from the set in rfc2109
- if(matchName(name_start, name_end, "expires"))
- {
- std::string date_string(mCookie, value_start, value_end - value_start);
- // If the cookie contains an "expires" field, it MUST contain a parsable date.
-
- // HACK: LLDate apparently can't PARSE an rfc1123-format date, even though it can GENERATE one.
- // The curl function curl_getdate can do this, but I'm hesitant to unilaterally introduce a curl dependency in LLDate.
-#if 1
- time_t date = curl_getdate(date_string.c_str(), NULL );
- mDate.secondsSinceEpoch((F64)date);
- LL_DEBUGS("CookieStoreParse") << " expire date parsed to: " << mDate.asRFC1123() << LL_ENDL;
-#else
- // This doesn't work (rfc1123-format dates cause it to fail)
- if(!mDate.fromString(date_string))
- {
- // Date failed to parse.
- LL_WARNS("CookieStoreParse") << "failed to parse cookie's expire date: " << date << LL_ENDL;
- return false;
- }
-#endif
- }
- else if(matchName(name_start, name_end, "domain"))
- {
- mDomainStart = value_start;
- mDomainEnd = value_end;
- }
- else if(matchName(name_start, name_end, "path"))
- {
- mPathStart = value_start;
- mPathEnd = value_end;
- }
- else if(matchName(name_start, name_end, "max-age"))
- {
- // TODO: how should we handle this?
- }
- else if(matchName(name_start, name_end, "secure"))
- {
- // We don't care about the value of this field (yet)
- }
- else if(matchName(name_start, name_end, "version"))
- {
- // We don't care about the value of this field (yet)
- }
- else if(matchName(name_start, name_end, "comment"))
- {
- // We don't care about the value of this field (yet)
- }
- else if(matchName(name_start, name_end, "httponly"))
- {
- // We don't care about the value of this field (yet)
- }
- else
- {
- // An unknown field is a parse failure
- LL_WARNS("CookieStoreParse") << "unexpected field name: " << mCookie.substr(name_start, name_end - name_start) << LL_ENDL;
- return false;
- }
-
- }
-
-
- // move on to the next field, skipping this field's separator and any leading whitespace
- field_start = mCookie.find_first_not_of("; ", next_field_start);
- }
-
- // 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();
-
- LL_DEBUGS("CookieStoreParse") << "added domain (" << mDomainStart << " to " << mDomainEnd << "), new cookie is: " << mCookie << LL_ENDL;
- }
-
- // 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();
-
- LL_DEBUGS("CookieStoreParse") << "added path (" << mPathStart << " to " << mPathEnd << "), new cookie is: " << mCookie << LL_ENDL;
- }
-
-
- return true;
-}
-
-std::string::size_type LLPluginCookieStore::Cookie::findFieldEnd(std::string::size_type start, std::string::size_type end)
-{
- std::string::size_type result = start;
-
- if(end == std::string::npos)
- end = mCookie.size();
-
- bool in_quotes = false;
- for(; (result < end); result++)
- {
- switch(mCookie[result])
- {
- case '\\':
- if(in_quotes)
- result++; // The next character is backslash-quoted. Skip over it.
- break;
- case '"':
- in_quotes = !in_quotes;
- break;
- case ';':
- if(!in_quotes)
- return result;
- break;
- }
- }
-
- // If we got here, no ';' was found.
- return end;
-}
-
-bool LLPluginCookieStore::Cookie::matchName(std::string::size_type start, std::string::size_type end, const char *name)
-{
- // NOTE: this assumes 'name' is already in lowercase. The code which uses it should be able to arrange this...
-
- while((start < end) && (*name != '\0'))
- {
- if(tolower(mCookie[start]) != *name)
- return false;
-
- start++;
- name++;
- }
-
- // iff both strings hit the end at the same time, they're equal.
- return ((start == end) && (*name == '\0'));
-}
-
-std::string LLPluginCookieStore::getAllCookies()
-{
- std::stringstream result;
- writeAllCookies(result);
- return result.str();
-}
-
-void LLPluginCookieStore::writeAllCookies(std::ostream& s)
-{
- cookie_map_t::iterator iter;
- for(iter = mCookies.begin(); iter != mCookies.end(); iter++)
- {
- // Don't return expired cookies
- if(!iter->second->isDead())
- {
- s << (iter->second->getCookie()) << "\n";
- }
- }
-
-}
-
-std::string LLPluginCookieStore::getPersistentCookies()
-{
- std::stringstream result;
- writePersistentCookies(result);
- return result.str();
-}
-
-void LLPluginCookieStore::writePersistentCookies(std::ostream& s)
-{
- cookie_map_t::iterator iter;
- for(iter = mCookies.begin(); iter != mCookies.end(); iter++)
- {
- // Don't return expired cookies or session cookies
- if(!iter->second->isDead() && !iter->second->isSessionCookie())
- {
- s << iter->second->getCookie() << "\n";
- }
- }
-}
-
-std::string LLPluginCookieStore::getChangedCookies(bool clear_changed)
-{
- std::stringstream result;
- writeChangedCookies(result, clear_changed);
-
- return result.str();
-}
-
-void LLPluginCookieStore::writeChangedCookies(std::ostream& s, bool clear_changed)
-{
- if(mHasChangedCookies)
- {
- LL_DEBUGS() << "returning changed cookies: " << LL_ENDL;
- cookie_map_t::iterator iter;
- for(iter = mCookies.begin(); iter != mCookies.end(); )
- {
- cookie_map_t::iterator next = iter;
- next++;
-
- // Only return cookies marked as "changed"
- if(iter->second->isChanged())
- {
- s << iter->second->getCookie() << "\n";
-
- LL_DEBUGS() << " " << iter->second->getCookie() << LL_ENDL;
-
- // If requested, clear the changed mark
- if(clear_changed)
- {
- if(iter->second->isDead())
- {
- // If this cookie was previously marked dead, it needs to be removed entirely.
- delete iter->second;
- mCookies.erase(iter);
- }
- else
- {
- // Not dead, just mark as not changed.
- iter->second->setChanged(false);
- }
- }
- }
-
- iter = next;
- }
- }
-
- if(clear_changed)
- mHasChangedCookies = false;
-}
-
-void LLPluginCookieStore::setAllCookies(const std::string &cookies, bool mark_changed)
-{
- clearCookies();
- setCookies(cookies, mark_changed);
-}
-
-void LLPluginCookieStore::readAllCookies(std::istream& s, bool mark_changed)
-{
- clearCookies();
- readCookies(s, mark_changed);
-}
-
-void LLPluginCookieStore::setCookies(const std::string &cookies, 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);
- }
- 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);
- }
-}
-
-void LLPluginCookieStore::readCookies(std::istream& s, bool mark_changed)
-{
- std::string line;
- while(s.good() && !s.eof())
- {
- std::getline(s, line);
- if(!line.empty())
- {
- // Try to create a cookie from this line.
- setOneCookie(line, 0, std::string::npos, mark_changed);
- }
- }
-}
-
-std::string LLPluginCookieStore::quoteString(const std::string &s)
-{
- std::stringstream result;
-
- result << '"';
-
- for(std::string::size_type i = 0; i < s.size(); ++i)
- {
- char c = s[i];
- switch(c)
- {
- // All these separators need to be quoted in HTTP headers, according to section 2.2 of rfc 2616:
- case '(': case ')': case '<': case '>': case '@':
- case ',': case ';': case ':': case '\\': case '"':
- case '/': case '[': case ']': case '?': case '=':
- case '{': case '}': case ' ': case '\t':
- result << '\\';
- break;
- }
-
- result << c;
- }
-
- result << '"';
-
- return result.str();
-}
-
-std::string LLPluginCookieStore::unquoteString(const std::string &s)
-{
- std::stringstream result;
-
- bool in_quotes = false;
-
- for(std::string::size_type i = 0; i < s.size(); ++i)
- {
- char c = s[i];
- switch(c)
- {
- case '\\':
- if(in_quotes)
- {
- // The next character is backslash-quoted. Pass it through untouched.
- ++i;
- if(i < s.size())
- {
- result << s[i];
- }
- continue;
- }
- break;
- case '"':
- in_quotes = !in_quotes;
- continue;
- break;
- }
-
- result << c;
- }
-
- return result.str();
-}
-
-// The flow for deleting a cookie is non-obvious enough that I should call it out here...
-// Deleting a cookie is done by setting a cookie with the same name, path, and domain, but with an expire timestamp in the past.
-// (This is exactly how a web server tells a browser to delete a cookie.)
-// 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, const std::string &host)
-{
- Cookie *cookie = Cookie::createFromString(s, cookie_start, cookie_end, host);
- if(cookie)
- {
- LL_DEBUGS("CookieStoreUpdate") << "setting cookie: " << cookie->getCookie() << LL_ENDL;
-
- // Create a key for this cookie
- std::string key = cookie->getKey();
-
- // Check to see whether this cookie should have expired
- if(!cookie->isSessionCookie() && (cookie->getDate() < LLDate::now()))
- {
- // This cookie has expired.
- if(mark_changed)
- {
- // If we're marking cookies as changed, we should keep it anyway since we'll need to send it out with deltas.
- cookie->setDead(true);
- LL_DEBUGS("CookieStoreUpdate") << " marking dead" << LL_ENDL;
- }
- else
- {
- // If we're not marking cookies as changed, we don't need to keep this cookie at all.
- // If the cookie was already in the list, delete it.
- removeCookie(key);
-
- delete cookie;
- cookie = NULL;
-
- LL_DEBUGS("CookieStoreUpdate") << " removing" << LL_ENDL;
- }
- }
-
- if(cookie)
- {
- // If it already exists in the map, replace it.
- cookie_map_t::iterator iter = mCookies.find(key);
- if(iter != mCookies.end())
- {
- if(iter->second->getCookie() == cookie->getCookie())
- {
- // The new cookie is identical to the old -- don't mark as changed.
- // Just leave the old one in the map.
- delete cookie;
- cookie = NULL;
-
- LL_DEBUGS("CookieStoreUpdate") << " unchanged" << LL_ENDL;
- }
- else
- {
- // A matching cookie was already in the map. Replace it.
- delete iter->second;
- iter->second = cookie;
-
- cookie->setChanged(mark_changed);
- if(mark_changed)
- mHasChangedCookies = true;
-
- LL_DEBUGS("CookieStoreUpdate") << " replacing" << LL_ENDL;
- }
- }
- else
- {
- // The cookie wasn't in the map. Insert it.
- mCookies.insert(std::make_pair(key, cookie));
-
- cookie->setChanged(mark_changed);
- if(mark_changed)
- mHasChangedCookies = true;
-
- LL_DEBUGS("CookieStoreUpdate") << " adding" << LL_ENDL;
- }
- }
- }
- else
- {
- LL_WARNS("CookieStoreUpdate") << "failed to parse cookie: " << s.substr(cookie_start, cookie_end - cookie_start) << LL_ENDL;
- }
-
-}
-
-void LLPluginCookieStore::clearCookies()
-{
- std::for_each(mCookies.begin(), mCookies.end(), DeletePairedPointer());
- mCookies.clear();
-}
-
-void LLPluginCookieStore::removeCookie(const std::string &key)
-{
- cookie_map_t::iterator iter = mCookies.find(key);
- if(iter != mCookies.end())
- {
- delete iter->second;
- mCookies.erase(iter);
- }
-}
-
-void LLPluginCookieStore::removeCookiesByDomain(const std::string &domain)
-{
- cookie_map_t::iterator iter = mCookies.begin();
- while(iter != mCookies.end())
- {
- if(iter->second->getDomain() == domain)
- {
- cookie_map_t::iterator doErase = iter;
- iter++;
- delete doErase->second;
- mCookies.erase(doErase);
- }
- else
- {
- iter++;
- }
- }
-}
diff --git a/indra/llplugin/llplugincookiestore.h b/indra/llplugin/llplugincookiestore.h
deleted file mode 100644
index a2fdeab647..0000000000
--- a/indra/llplugin/llplugincookiestore.h
+++ /dev/null
@@ -1,123 +0,0 @@
-/**
- * @file llplugincookiestore.h
- * @brief LLPluginCookieStore provides central storage for http cookies used by plugins
- *
- * @cond
- * $LicenseInfo:firstyear=2010&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- * @endcond
- */
-
-#ifndef LL_LLPLUGINCOOKIESTORE_H
-#define LL_LLPLUGINCOOKIESTORE_H
-
-#include "lldate.h"
-#include <map>
-#include <string>
-#include <iostream>
-
-class LLPluginCookieStore
-{
- LOG_CLASS(LLPluginCookieStore);
-public:
- LLPluginCookieStore();
- ~LLPluginCookieStore();
-
- // gets all cookies currently in storage -- use when initializing a plugin
- std::string getAllCookies();
- void writeAllCookies(std::ostream& s);
-
- // gets only persistent cookies (i.e. not session cookies) -- use when writing cookies to a file
- std::string getPersistentCookies();
- void writePersistentCookies(std::ostream& s);
-
- // gets cookies which are marked as "changed" -- use when sending periodic updates to plugins
- std::string getChangedCookies(bool clear_changed = true);
- void writeChangedCookies(std::ostream& s, bool clear_changed = true);
-
- // (re)initializes internal data structures and bulk-sets cookies -- use when reading cookies from a file
- void setAllCookies(const std::string &cookies, bool mark_changed = false);
- void readAllCookies(std::istream& s, bool mark_changed = false);
-
- // sets one or more cookies (without reinitializing anything) -- use when receiving cookies from a plugin
- 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);
-
- void removeCookiesByDomain(const std::string &domain);
-
-private:
-
- 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, 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;
- std::string getDomain() const;
-
- const std::string &getCookie() const { return mCookie; };
- bool isSessionCookie() const { return mDate.isNull(); };
-
- bool isDead() const { return mDead; };
- void setDead(bool dead) { mDead = dead; };
-
- bool isChanged() const { return mChanged; };
- void setChanged(bool changed) { mChanged = changed; };
-
- const LLDate &getDate() const { return mDate; };
-
- private:
- Cookie(const std::string &s, std::string::size_type cookie_start = 0, std::string::size_type cookie_end = std::string::npos);
- 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);
-
- std::string mCookie; // The full cookie, in RFC 2109 string format
- LLDate mDate; // The expiration date of the cookie. For session cookies, this will be a null date (mDate.isNull() is true).
- // Start/end indices of various parts of the cookie string. Stored as indices into the string to save space and time.
- std::string::size_type mNameStart, mNameEnd;
- std::string::size_type mValueStart, mValueEnd;
- std::string::size_type mDomainStart, mDomainEnd;
- std::string::size_type mPathStart, mPathEnd;
- bool mDead;
- bool mChanged;
- };
-
- typedef std::map<std::string, Cookie*> cookie_map_t;
-
- cookie_map_t mCookies;
- bool mHasChangedCookies;
-
- void clearCookies();
- void removeCookie(const std::string &key);
-};
-
-#endif // LL_LLPLUGINCOOKIESTORE_H
diff --git a/indra/llplugin/tests/llplugincookiestore_test.cpp b/indra/llplugin/tests/llplugincookiestore_test.cpp
deleted file mode 100644
index c2cb236cba..0000000000
--- a/indra/llplugin/tests/llplugincookiestore_test.cpp
+++ /dev/null
@@ -1,207 +0,0 @@
-/**
- * @file llplugincookiestore_test.cpp
- * @brief Unit tests for LLPluginCookieStore.
- *
- * @cond
- * $LicenseInfo:firstyear=2010&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- * @endcond
- */
-
-#include "linden_common.h"
-#include <list>
-#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");
-
- // 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=/; Max-Age=10; Secure; Version=1; Comment=foo!; HTTPOnly"; // cookie with every supported field, in different cases.
- 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);
- }
-
-}