diff options
Diffstat (limited to 'indra/llplugin')
| -rw-r--r-- | indra/llplugin/CMakeLists.txt | 19 | ||||
| -rw-r--r-- | indra/llplugin/llpluginclassmedia.cpp | 48 | ||||
| -rw-r--r-- | indra/llplugin/llpluginclassmedia.h | 10 | ||||
| -rw-r--r-- | indra/llplugin/llpluginclassmediaowner.h | 28 | ||||
| -rw-r--r-- | indra/llplugin/llplugincookiestore.cpp | 689 | ||||
| -rw-r--r-- | indra/llplugin/llplugincookiestore.h | 123 | ||||
| -rw-r--r-- | indra/llplugin/tests/llplugincookiestore_test.cpp | 207 | 
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 f3fd4277ce..9d447b0f37 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);  } @@ -1092,6 +1108,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") @@ -1153,7 +1170,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") @@ -1168,13 +1190,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); @@ -1289,16 +1304,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); -	} - -} | 
