merge changes for 5.1.3-release
commit
2c536cd91d
1
.hgtags
1
.hgtags
|
|
@ -534,3 +534,4 @@ abcab37e1b29414ab8c03af9ca2ab489d809788a 5.0.7-release
|
|||
ad0e15543836d64d6399d28b32852510435e344a 5.1.0-release
|
||||
26d9e9bb166a9a417f35b1863223a597af8185fd 5.1.1-release
|
||||
2eb917875efdfe920680b9049302d0f03721245d 5.1.2-release
|
||||
7c00e5b6cb3d95712e9d8e29277c805bca2bda90 5.1.3-release
|
||||
|
|
|
|||
|
|
@ -556,9 +556,9 @@
|
|||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>bbdea742f2a89bcd6360e61e01d6be93</string>
|
||||
<string>118987b1a5b56214cfdbd0c763e180da</string>
|
||||
<key>url</key>
|
||||
<string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/8207/32592/dullahan-1.1.820_3.3071.1637.gcb6cf75-darwin64-508196.tar.bz2</string>
|
||||
<string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/15127/97748/dullahan-1.1.1080_3.3325.1750.gaabe4c4-darwin64-513449.tar.bz2</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>darwin64</string>
|
||||
|
|
@ -568,9 +568,9 @@
|
|||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>31e11a74e0d3f1e5e4036cb5fea8d944</string>
|
||||
<string>2ecc71350b30a1057091b9cd7af18b1c</string>
|
||||
<key>url</key>
|
||||
<string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/8209/32599/dullahan-1.1.820_3.3071.1634.g9cc59c8-windows-508196.tar.bz2</string>
|
||||
<string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/15128/97755/dullahan-1.1.1080_3.3325.1750.gaabe4c4-windows-513449.tar.bz2</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>windows</string>
|
||||
|
|
@ -580,16 +580,16 @@
|
|||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>f965d244e7921c06ee79b68a4abcea3b</string>
|
||||
<string>2ed3e49388514dafb907c59a209d580e</string>
|
||||
<key>url</key>
|
||||
<string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/8208/32602/dullahan-1.1.820_3.3071.1634.g9cc59c8-windows64-508196.tar.bz2</string>
|
||||
<string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/15129/97760/dullahan-1.1.1080_3.3325.1750.gaabe4c4-windows64-513449.tar.bz2</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>windows64</string>
|
||||
</map>
|
||||
</map>
|
||||
<key>version</key>
|
||||
<string>1.1.820_3.3071.1634.g9cc59c8</string>
|
||||
<string>1.1.1080_3.3325.1750.gaabe4c4</string>
|
||||
</map>
|
||||
<key>elfio</key>
|
||||
<map>
|
||||
|
|
@ -3260,9 +3260,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
|
|||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>f1248b6692dcbb1a42db87ca8d9fed93</string>
|
||||
<string>4aefe12a3825d1b4b8370986d84792a2</string>
|
||||
<key>url</key>
|
||||
<string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/13982/87166/viewer_manager-1.0.512801-darwin64-512801.tar.bz2</string>
|
||||
<string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/15295/98583/viewer_manager-1.0.513540-darwin64-513540.tar.bz2</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>darwin64</string>
|
||||
|
|
@ -3284,9 +3284,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
|
|||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>c174ecc0893f8c193571b1dc80b823ad</string>
|
||||
<string>db96bc8a83e6577d31657586100bfc35</string>
|
||||
<key>url</key>
|
||||
<string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/13983/87172/viewer_manager-1.0.512801-windows-512801.tar.bz2</string>
|
||||
<string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/15298/98589/viewer_manager-1.0.513540-windows-513540.tar.bz2</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>windows</string>
|
||||
|
|
@ -3297,7 +3297,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
|
|||
<key>source_type</key>
|
||||
<string>hg</string>
|
||||
<key>version</key>
|
||||
<string>1.0.512801</string>
|
||||
<string>1.0.513540</string>
|
||||
</map>
|
||||
<key>vlc-bin</key>
|
||||
<map>
|
||||
|
|
@ -3316,9 +3316,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
|
|||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>c5e6d9440e3a4a12102dd2bbb703963e</string>
|
||||
<string>e5635e173c75dc0675b48ab5f5e4868b</string>
|
||||
<key>url</key>
|
||||
<string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/2225/4736/vlc_bin-2.2.4.502214-darwin64-502214.tar.bz2</string>
|
||||
<string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/12143/71451/vlc_bin-2.2.8.511703-darwin64-511703.tar.bz2</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>darwin64</string>
|
||||
|
|
@ -3340,9 +3340,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
|
|||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>dc37f7cc77a62891bb9ae46c9e19f95e</string>
|
||||
<string>add560654a53cb1c554044a4fac3c718</string>
|
||||
<key>url</key>
|
||||
<string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/1219/2834/vlc_bin-2.2.4.501207-windows-501207.tar.bz2</string>
|
||||
<string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/12144/71458/vlc_bin-2.2.8.511703-windows-511703.tar.bz2</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>windows</string>
|
||||
|
|
@ -3352,16 +3352,16 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
|
|||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>148ee599afeba9794de14ca433389504</string>
|
||||
<string>94bf04b49acc1e1bf2c06e2232f8a083</string>
|
||||
<key>url</key>
|
||||
<string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/1218/2829/vlc_bin-2.2.4.501207-windows64-501207.tar.bz2</string>
|
||||
<string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/12145/71463/vlc_bin-2.2.8.511703-windows64-511703.tar.bz2</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>windows64</string>
|
||||
</map>
|
||||
</map>
|
||||
<key>version</key>
|
||||
<string>2.2.4.502214</string>
|
||||
<string>2.2.8.511703</string>
|
||||
</map>
|
||||
<key>xmlrpc-epi</key>
|
||||
<map>
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
void LLPluginClassMedia::cookies_enabled(bool enable)
|
||||
{
|
||||
LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "set_cookies");
|
||||
message.setValue("cookies", cookies);
|
||||
sendMessage(message);
|
||||
}
|
||||
|
||||
void LLPluginClassMedia::enable_cookies(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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -703,7 +703,7 @@ namespace LLNotificationComparators
|
|||
{
|
||||
struct orderByUUID
|
||||
{
|
||||
bool operator()(LLNotificationPtr lhs, LLNotificationPtr rhs)
|
||||
bool operator()(LLNotificationPtr lhs, LLNotificationPtr rhs) const
|
||||
{
|
||||
return lhs->id() < rhs->id();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@
|
|||
#include "media_plugin_base.h"
|
||||
|
||||
#include <functional>
|
||||
#include <chrono>
|
||||
|
||||
#include "dullahan.h"
|
||||
|
||||
|
|
@ -64,12 +65,12 @@ private:
|
|||
void onLoadStartCallback();
|
||||
void onRequestExitCallback();
|
||||
void onLoadEndCallback(int httpStatusCode);
|
||||
void onLoadError(int status, const std::string error_text);
|
||||
void onAddressChangeCallback(std::string url);
|
||||
void onNavigateURLCallback(std::string url, std::string target);
|
||||
void onOpenPopupCallback(std::string url, std::string target);
|
||||
bool onHTTPAuthCallback(const std::string host, const std::string realm, std::string& username, std::string& password);
|
||||
void onCursorChangedCallback(dullahan::ECursorType type);
|
||||
void onFileDownloadCallback(std::string filename);
|
||||
const std::string onFileDialogCallback();
|
||||
const std::vector<std::string> onFileDialog(dullahan::EFileDialogType dialog_type, const std::string dialog_title, const std::string default_file, const std::string dialog_accept_filter, bool& use_default);
|
||||
|
||||
void postDebugMessage(const std::string& msg);
|
||||
void authResponse(LLPluginMessage &message);
|
||||
|
|
@ -95,7 +96,9 @@ private:
|
|||
bool mCanPaste;
|
||||
std::string mCachePath;
|
||||
std::string mCookiePath;
|
||||
std::string mPickedFile;
|
||||
std::string mCefLogFile;
|
||||
bool mCefLogVerbose;
|
||||
std::vector<std::string> mPickedFiles;
|
||||
VolumeCatcher mVolumeCatcher;
|
||||
F32 mCurVolume;
|
||||
dullahan* mCEFLib;
|
||||
|
|
@ -115,7 +118,7 @@ MediaPluginBase(host_send_func, host_user_data)
|
|||
mCookiesEnabled = true;
|
||||
mPluginsEnabled = false;
|
||||
mJavascriptEnabled = true;
|
||||
mDisableGPU = true;
|
||||
mDisableGPU = false;
|
||||
mUserAgentSubtring = "";
|
||||
mAuthUsername = "";
|
||||
mAuthPassword = "";
|
||||
|
|
@ -125,7 +128,9 @@ MediaPluginBase(host_send_func, host_user_data)
|
|||
mCanPaste = false;
|
||||
mCachePath = "";
|
||||
mCookiePath = "";
|
||||
mPickedFile = "";
|
||||
mCefLogFile = "";
|
||||
mCefLogVerbose = false;
|
||||
mPickedFiles.clear();
|
||||
mCurVolume = 0.0;
|
||||
|
||||
mCEFLib = new dullahan();
|
||||
|
|
@ -166,6 +171,10 @@ void MediaPluginCEF::onPageChangedCallback(const unsigned char* pixels, int x, i
|
|||
{
|
||||
memcpy(mPixels, pixels, mWidth * mHeight * mDepth);
|
||||
}
|
||||
else
|
||||
{
|
||||
mCEFLib->setSize(mWidth, mHeight);
|
||||
}
|
||||
setDirty(0, 0, mWidth, mHeight);
|
||||
}
|
||||
}
|
||||
|
|
@ -208,6 +217,21 @@ void MediaPluginCEF::onLoadStartCallback()
|
|||
sendMessage(message);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
void MediaPluginCEF::onLoadError(int status, const std::string error_text)
|
||||
{
|
||||
std::stringstream msg;
|
||||
|
||||
msg << "<b>Loading error!</b>";
|
||||
msg << "<p>";
|
||||
msg << "Message: " << error_text;
|
||||
msg << "<br>";
|
||||
msg << "Code: " << status;
|
||||
|
||||
mCEFLib->showBrowserMessage(msg.str());
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
void MediaPluginCEF::onRequestExitCallback()
|
||||
|
|
@ -241,12 +265,11 @@ void MediaPluginCEF::onAddressChangeCallback(std::string url)
|
|||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
void MediaPluginCEF::onNavigateURLCallback(std::string url, std::string target)
|
||||
void MediaPluginCEF::onOpenPopupCallback(std::string url, std::string target)
|
||||
{
|
||||
LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "click_href");
|
||||
message.setValue("uri", url);
|
||||
message.setValue("target", target);
|
||||
message.setValue("uuid", ""); // not used right now
|
||||
sendMessage(message);
|
||||
}
|
||||
|
||||
|
|
@ -285,30 +308,52 @@ bool MediaPluginCEF::onHTTPAuthCallback(const std::string host, const std::strin
|
|||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
void MediaPluginCEF::onFileDownloadCallback(const std::string filename)
|
||||
const std::vector<std::string> MediaPluginCEF::onFileDialog(dullahan::EFileDialogType dialog_type, const std::string dialog_title, const std::string default_file, std::string dialog_accept_filter, bool& use_default)
|
||||
{
|
||||
mAuthOK = false;
|
||||
// do not use the default CEF file picker
|
||||
use_default = false;
|
||||
|
||||
LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "file_download");
|
||||
message.setValue("filename", filename);
|
||||
if (dialog_type == dullahan::FD_OPEN_FILE)
|
||||
{
|
||||
mPickedFiles.clear();
|
||||
|
||||
sendMessage(message);
|
||||
LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "pick_file");
|
||||
message.setValueBoolean("blocking_request", true);
|
||||
message.setValueBoolean("multiple_files", false);
|
||||
|
||||
sendMessage(message);
|
||||
|
||||
return mPickedFiles;
|
||||
}
|
||||
else if (dialog_type == dullahan::FD_OPEN_MULTIPLE_FILES)
|
||||
{
|
||||
mPickedFiles.clear();
|
||||
|
||||
LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "pick_file");
|
||||
message.setValueBoolean("blocking_request", true);
|
||||
message.setValueBoolean("multiple_files", true);
|
||||
|
||||
sendMessage(message);
|
||||
|
||||
return mPickedFiles;
|
||||
}
|
||||
else if (dialog_type == dullahan::FD_SAVE_FILE)
|
||||
{
|
||||
mAuthOK = false;
|
||||
|
||||
LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "file_download");
|
||||
message.setValue("filename", default_file);
|
||||
|
||||
sendMessage(message);
|
||||
|
||||
return std::vector<std::string>();
|
||||
}
|
||||
|
||||
return std::vector<std::string>();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
const std::string MediaPluginCEF::onFileDialogCallback()
|
||||
{
|
||||
mPickedFile.clear();
|
||||
|
||||
LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "pick_file");
|
||||
message.setValueBoolean("blocking_request", true);
|
||||
|
||||
sendMessage(message);
|
||||
|
||||
return mPickedFile;
|
||||
}
|
||||
|
||||
void MediaPluginCEF::onCursorChangedCallback(dullahan::ECursorType type)
|
||||
{
|
||||
std::string name = "";
|
||||
|
|
@ -341,6 +386,8 @@ void MediaPluginCEF::onCursorChangedCallback(dullahan::ECursorType type)
|
|||
sendMessage(message);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
void MediaPluginCEF::authResponse(LLPluginMessage &message)
|
||||
{
|
||||
mAuthOK = message.getValueBoolean("ok");
|
||||
|
|
@ -373,7 +420,7 @@ void MediaPluginCEF::receiveMessage(const char* message_string)
|
|||
versions[LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER] = LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER_VERSION;
|
||||
message.setValueLLSD("versions", versions);
|
||||
|
||||
std::string plugin_version = "CEF plugin 1.1.3";
|
||||
std::string plugin_version = "CEF plugin 1.1.412";
|
||||
message.setValue("plugin_version", plugin_version);
|
||||
sendMessage(message);
|
||||
}
|
||||
|
|
@ -439,17 +486,17 @@ void MediaPluginCEF::receiveMessage(const char* message_string)
|
|||
mCEFLib->setOnTitleChangeCallback(std::bind(&MediaPluginCEF::onTitleChangeCallback, this, std::placeholders::_1));
|
||||
mCEFLib->setOnLoadStartCallback(std::bind(&MediaPluginCEF::onLoadStartCallback, this));
|
||||
mCEFLib->setOnLoadEndCallback(std::bind(&MediaPluginCEF::onLoadEndCallback, this, std::placeholders::_1));
|
||||
mCEFLib->setOnLoadErrorCallback(std::bind(&MediaPluginCEF::onLoadError, this, std::placeholders::_1, std::placeholders::_2));
|
||||
mCEFLib->setOnAddressChangeCallback(std::bind(&MediaPluginCEF::onAddressChangeCallback, this, std::placeholders::_1));
|
||||
mCEFLib->setOnNavigateURLCallback(std::bind(&MediaPluginCEF::onNavigateURLCallback, this, std::placeholders::_1, std::placeholders::_2));
|
||||
mCEFLib->setOnOpenPopupCallback(std::bind(&MediaPluginCEF::onOpenPopupCallback, this, std::placeholders::_1, std::placeholders::_2));
|
||||
mCEFLib->setOnHTTPAuthCallback(std::bind(&MediaPluginCEF::onHTTPAuthCallback, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4));
|
||||
mCEFLib->setOnFileDownloadCallback(std::bind(&MediaPluginCEF::onFileDownloadCallback, this, std::placeholders::_1));
|
||||
mCEFLib->setOnFileDialogCallback(std::bind(&MediaPluginCEF::onFileDialogCallback, this));
|
||||
mCEFLib->setOnFileDialogCallback(std::bind(&MediaPluginCEF::onFileDialog, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5));
|
||||
mCEFLib->setOnCursorChangedCallback(std::bind(&MediaPluginCEF::onCursorChangedCallback, this, std::placeholders::_1));
|
||||
mCEFLib->setOnRequestExitCallback(std::bind(&MediaPluginCEF::onRequestExitCallback, this));
|
||||
|
||||
dullahan::dullahan_settings settings;
|
||||
settings.accept_language_list = mHostLanguage;
|
||||
settings.background_color = 0xffffffff;
|
||||
settings.background_color = 0xff282828;
|
||||
settings.cache_enabled = true;
|
||||
settings.cache_path = mCachePath;
|
||||
settings.cookie_store_path = mCookiePath;
|
||||
|
|
@ -468,6 +515,8 @@ void MediaPluginCEF::receiveMessage(const char* message_string)
|
|||
settings.plugins_enabled = mPluginsEnabled;
|
||||
settings.user_agent_substring = mCEFLib->makeCompatibleUserAgentString(mUserAgentSubtring);
|
||||
settings.webgl_enabled = true;
|
||||
settings.log_file = mCefLogFile;
|
||||
settings.log_verbose = mCefLogVerbose;
|
||||
|
||||
std::vector<std::string> custom_schemes(1, "secondlife");
|
||||
mCEFLib->setCustomSchemes(custom_schemes);
|
||||
|
|
@ -497,8 +546,11 @@ void MediaPluginCEF::receiveMessage(const char* message_string)
|
|||
{
|
||||
std::string user_data_path_cache = message_in.getValue("cache_path");
|
||||
std::string user_data_path_cookies = message_in.getValue("cookies_path");
|
||||
|
||||
mCachePath = user_data_path_cache + "cef_cache";
|
||||
mCookiePath = user_data_path_cookies + "cef_cookies";
|
||||
mCefLogFile = message_in.getValue("cef_log_file");
|
||||
mCefLogVerbose = message_in.getValueBoolean("cef_verbose_log");
|
||||
}
|
||||
else if (message_name == "size_change")
|
||||
{
|
||||
|
|
@ -520,11 +572,11 @@ void MediaPluginCEF::receiveMessage(const char* message_string)
|
|||
|
||||
mTextureWidth = texture_width;
|
||||
mTextureHeight = texture_height;
|
||||
|
||||
mCEFLib->setSize(mWidth, mHeight);
|
||||
};
|
||||
};
|
||||
|
||||
mCEFLib->setSize(mWidth, mHeight);
|
||||
|
||||
LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "size_change_response");
|
||||
message.setValue("name", name);
|
||||
message.setValueS32("width", width);
|
||||
|
|
@ -650,7 +702,14 @@ void MediaPluginCEF::receiveMessage(const char* message_string)
|
|||
}
|
||||
if (message_name == "pick_file_response")
|
||||
{
|
||||
mPickedFile = message_in.getValue("file");
|
||||
LLSD file_list_llsd = message_in.getValueLLSD("file_list");
|
||||
|
||||
LLSD::array_const_iterator iter = file_list_llsd.beginArray();
|
||||
LLSD::array_const_iterator end = file_list_llsd.endArray();
|
||||
for (; iter != end; ++iter)
|
||||
{
|
||||
mPickedFiles.push_back(((*iter).asString()));
|
||||
}
|
||||
}
|
||||
if (message_name == "auth_response")
|
||||
{
|
||||
|
|
@ -697,6 +756,10 @@ void MediaPluginCEF::receiveMessage(const char* message_string)
|
|||
{
|
||||
mCookiesEnabled = message_in.getValueBoolean("enable");
|
||||
}
|
||||
else if (message_name == "clear_cookies")
|
||||
{
|
||||
mCEFLib->deleteAllCookies();
|
||||
}
|
||||
else if (message_name == "set_user_agent")
|
||||
{
|
||||
mUserAgentSubtring = message_in.getValue("user_agent");
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
5.1.3
|
||||
5.1.4
|
||||
|
|
|
|||
|
|
@ -16155,6 +16155,17 @@
|
|||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
<key>CefVerboseLog</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Enable/disable CEF verbose loggingk</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
</map>
|
||||
</llsd>
|
||||
|
||||
|
|
|
|||
|
|
@ -1940,8 +1940,6 @@ bool LLAppViewer::cleanup()
|
|||
|
||||
LLAvatarIconIDCache::getInstance()->save();
|
||||
|
||||
LLViewerMedia::saveCookieFile();
|
||||
|
||||
// Stop the plugin read thread if it's running.
|
||||
LLPluginProcessParent::setUseReadThread(false);
|
||||
|
||||
|
|
@ -3179,8 +3177,14 @@ LLSD LLAppViewer::getViewerInfo() const
|
|||
cef_ver_codec << " / CEF: ";
|
||||
cef_ver_codec << CEF_VERSION;
|
||||
|
||||
cef_ver_codec << " / Chrome: ";
|
||||
cef_ver_codec << " / Chromium: ";
|
||||
cef_ver_codec << CHROME_VERSION_MAJOR;
|
||||
cef_ver_codec << ".";
|
||||
cef_ver_codec << CHROME_VERSION_MINOR;
|
||||
cef_ver_codec << ".";
|
||||
cef_ver_codec << CHROME_VERSION_BUILD;
|
||||
cef_ver_codec << ".";
|
||||
cef_ver_codec << CHROME_VERSION_PATCH;
|
||||
|
||||
info["LIBCEF_VERSION"] = cef_ver_codec.str();
|
||||
#else
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/**
|
||||
/**
|
||||
* @file llfloaterfacebook.cpp
|
||||
* @brief Implementation of llfloaterfacebook
|
||||
* @author Gilbert@lindenlab.com
|
||||
|
|
@ -41,7 +41,6 @@
|
|||
#include "llresmgr.h" // LLLocale
|
||||
#include "llsdserialize.h"
|
||||
#include "llloadingindicator.h"
|
||||
#include "llplugincookiestore.h"
|
||||
#include "llslurl.h"
|
||||
#include "lltrans.h"
|
||||
#include "llsnapshotlivepreview.h"
|
||||
|
|
@ -296,16 +295,11 @@ void LLFacebookStatusPanel::showConnectedLayout()
|
|||
void LLFacebookStatusPanel::onConnect()
|
||||
{
|
||||
LLFacebookConnect::instance().checkConnectionToFacebook(true);
|
||||
|
||||
//Clear only the facebook browser cookies so that the facebook login screen appears
|
||||
LLViewerMedia::getCookieStore()->removeCookiesByDomain(".facebook.com");
|
||||
}
|
||||
|
||||
void LLFacebookStatusPanel::onDisconnect()
|
||||
{
|
||||
LLFacebookConnect::instance().disconnectFromFacebook();
|
||||
|
||||
LLViewerMedia::getCookieStore()->removeCookiesByDomain(".facebook.com");
|
||||
}
|
||||
|
||||
void LLFacebookStatusPanel::clearAndClose()
|
||||
|
|
@ -810,7 +804,7 @@ void LLFacebookCheckinPanel::sendCheckin()
|
|||
LLAgentUI::buildSLURL(slurl);
|
||||
std::string slurl_string = slurl.getSLURLString();
|
||||
|
||||
// Use a valid http:// URL if the scheme is secondlife://
|
||||
// Use a valid http:// URL if the scheme is secondlife://
|
||||
LLURI slurl_uri(slurl_string);
|
||||
if (slurl_uri.scheme() == LLSLURL::SLURL_SECONDLIFE_SCHEME)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -40,7 +40,6 @@
|
|||
#include "llresmgr.h" // LLLocale
|
||||
#include "llsdserialize.h"
|
||||
#include "llloadingindicator.h"
|
||||
#include "llplugincookiestore.h"
|
||||
#include "llslurl.h"
|
||||
#include "lltrans.h"
|
||||
#include "llsnapshotlivepreview.h"
|
||||
|
|
@ -660,16 +659,11 @@ void LLFlickrAccountPanel::showConnectedLayout()
|
|||
void LLFlickrAccountPanel::onConnect()
|
||||
{
|
||||
LLFlickrConnect::instance().checkConnectionToFlickr(true);
|
||||
|
||||
//Clear only the flickr browser cookies so that the flickr login screen appears
|
||||
LLViewerMedia::getCookieStore()->removeCookiesByDomain(".flickr.com");
|
||||
}
|
||||
|
||||
void LLFlickrAccountPanel::onDisconnect()
|
||||
{
|
||||
LLFlickrConnect::instance().disconnectFromFlickr();
|
||||
|
||||
LLViewerMedia::getCookieStore()->removeCookiesByDomain(".flickr.com");
|
||||
}
|
||||
|
||||
////////////////////////
|
||||
|
|
|
|||
|
|
@ -41,7 +41,6 @@
|
|||
#include "llresmgr.h" // LLLocale
|
||||
#include "llsdserialize.h"
|
||||
#include "llloadingindicator.h"
|
||||
#include "llplugincookiestore.h"
|
||||
#include "llslurl.h"
|
||||
#include "lltrans.h"
|
||||
#include "llsnapshotlivepreview.h"
|
||||
|
|
@ -683,16 +682,11 @@ void LLTwitterAccountPanel::showConnectedLayout()
|
|||
void LLTwitterAccountPanel::onConnect()
|
||||
{
|
||||
LLTwitterConnect::instance().checkConnectionToTwitter(true);
|
||||
|
||||
//Clear only the twitter browser cookies so that the twitter login screen appears
|
||||
LLViewerMedia::getCookieStore()->removeCookiesByDomain(".twitter.com");
|
||||
}
|
||||
|
||||
void LLTwitterAccountPanel::onDisconnect()
|
||||
{
|
||||
LLTwitterConnect::instance().disconnectFromTwitter();
|
||||
|
||||
LLViewerMedia::getCookieStore()->removeCookiesByDomain(".twitter.com");
|
||||
}
|
||||
|
||||
////////////////////////
|
||||
|
|
|
|||
|
|
@ -1022,7 +1022,7 @@ void LLMediaCtrl::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event)
|
|||
// try as slurl first
|
||||
if (!LLURLDispatcher::dispatch(url, "clicked", NULL, mTrusted))
|
||||
{
|
||||
LLWeb::loadURL(url, target, std::string());
|
||||
LLWeb::loadURL(url, target, uuid);
|
||||
}
|
||||
|
||||
// CP: removing this code because we no longer support popups so this breaks the flow.
|
||||
|
|
|
|||
|
|
@ -965,9 +965,6 @@ bool idle_startup()
|
|||
// Load Avatars icons cache
|
||||
LLAvatarIconIDCache::getInstance()->load();
|
||||
|
||||
// Load media plugin cookies
|
||||
LLViewerMedia::loadCookieFile();
|
||||
|
||||
LLRenderMuteList::getInstance()->loadFromFile();
|
||||
|
||||
//-------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -736,7 +736,7 @@ LLTextureView::~LLTextureView()
|
|||
typedef std::pair<F32,LLViewerFetchedTexture*> decode_pair_t;
|
||||
struct compare_decode_pair
|
||||
{
|
||||
bool operator()(const decode_pair_t& a, const decode_pair_t& b)
|
||||
bool operator()(const decode_pair_t& a, const decode_pair_t& b) const
|
||||
{
|
||||
return a.first > b.first;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -50,7 +50,6 @@
|
|||
#include "llpanelprofile.h"
|
||||
#include "llparcel.h"
|
||||
#include "llpluginclassmedia.h"
|
||||
#include "llplugincookiestore.h"
|
||||
#include "llurldispatcher.h"
|
||||
#include "lluuid.h"
|
||||
#include "llversioninfo.h"
|
||||
|
|
@ -154,7 +153,6 @@ LLViewerMediaObserver::~LLViewerMediaObserver()
|
|||
}
|
||||
|
||||
|
||||
LLPluginCookieStore *LLViewerMedia::sCookieStore = NULL;
|
||||
LLURL LLViewerMedia::sOpenIDURL;
|
||||
std::string LLViewerMedia::sOpenIDCookie;
|
||||
LLPluginClassMedia* LLViewerMedia::sSpareBrowserMediaSource = NULL;
|
||||
|
|
@ -169,8 +167,6 @@ static F64 sLowestLoadableImplInterest = 0.0f;
|
|||
static bool sAnyMediaShowing = false;
|
||||
static bool sAnyMediaPlaying = false;
|
||||
static boost::signals2::connection sTeleportFinishConnection;
|
||||
static std::string sUpdatedCookies;
|
||||
static const char *PLUGIN_COOKIE_FILE_NAME = "plugin_cookies.txt";
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
static void add_media_impl(LLViewerMediaImpl* media)
|
||||
|
|
@ -610,12 +606,6 @@ void LLViewerMedia::updateMedia(void *dummy_arg)
|
|||
|
||||
sAnyMediaShowing = false;
|
||||
sAnyMediaPlaying = false;
|
||||
sUpdatedCookies = getCookieStore()->getChangedCookies();
|
||||
if(!sUpdatedCookies.empty())
|
||||
{
|
||||
LL_DEBUGS() << "updated cookies will be sent to all loaded plugins: " << LL_ENDL;
|
||||
LL_DEBUGS() << sUpdatedCookies << LL_ENDL;
|
||||
}
|
||||
|
||||
impl_list::iterator iter = sViewerMediaImplList.begin();
|
||||
impl_list::iterator end = sViewerMediaImplList.end();
|
||||
|
|
@ -1059,64 +1049,6 @@ void LLViewerMedia::clearAllCookies()
|
|||
pimpl->mMediaSource->clear_cookies();
|
||||
}
|
||||
}
|
||||
|
||||
// Clear all cookies from the cookie store
|
||||
getCookieStore()->setAllCookies("");
|
||||
|
||||
// FIXME: this may not be sufficient, since the on-disk cookie file won't get written until some browser instance exits cleanly.
|
||||
// It also won't clear cookies for other accounts, or for any account if we're not logged in, and won't do anything at all if there are no webkit plugins loaded.
|
||||
// Until such time as we can centralize cookie storage, the following hack should cover these cases:
|
||||
|
||||
// HACK: Look for cookie files in all possible places and delete them.
|
||||
// NOTE: this assumes knowledge of what happens inside the webkit plugin (it's what adds 'browser_profile' to the path and names the cookie file)
|
||||
|
||||
// Places that cookie files can be:
|
||||
// <getOSUserAppDir>/browser_profile/cookies
|
||||
// <getOSUserAppDir>/first_last/browser_profile/cookies (note that there may be any number of these!)
|
||||
// <getOSUserAppDir>/first_last/plugin_cookies.txt (note that there may be any number of these!)
|
||||
|
||||
std::string base_dir = gDirUtilp->getOSUserAppDir() + gDirUtilp->getDirDelimiter();
|
||||
std::string target;
|
||||
std::string filename;
|
||||
|
||||
LL_DEBUGS() << "base dir = " << base_dir << LL_ENDL;
|
||||
|
||||
// The non-logged-in version is easy
|
||||
target = base_dir;
|
||||
target += "browser_profile";
|
||||
target += gDirUtilp->getDirDelimiter();
|
||||
target += "cookies";
|
||||
LL_DEBUGS() << "target = " << target << LL_ENDL;
|
||||
if(LLFile::isfile(target))
|
||||
{
|
||||
LLFile::remove(target);
|
||||
}
|
||||
|
||||
// the hard part: iterate over all user directories and delete the cookie file from each one
|
||||
LLDirIterator dir_iter(base_dir, "*_*");
|
||||
while (dir_iter.next(filename))
|
||||
{
|
||||
target = gDirUtilp->add(base_dir, filename);
|
||||
gDirUtilp->append(target, "browser_profile");
|
||||
gDirUtilp->append(target, "cookies");
|
||||
LL_DEBUGS() << "target = " << target << LL_ENDL;
|
||||
if(LLFile::isfile(target))
|
||||
{
|
||||
LLFile::remove(target);
|
||||
}
|
||||
|
||||
// Other accounts may have new-style cookie files too -- delete them as well
|
||||
target = gDirUtilp->add(base_dir, filename);
|
||||
gDirUtilp->append(target, PLUGIN_COOKIE_FILE_NAME);
|
||||
LL_DEBUGS() << "target = " << target << LL_ENDL;
|
||||
if(LLFile::isfile(target))
|
||||
{
|
||||
LLFile::remove(target);
|
||||
}
|
||||
}
|
||||
|
||||
// If we have an OpenID cookie, re-add it to the cookie store.
|
||||
setOpenIDCookie(std::string());
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -1145,7 +1077,7 @@ void LLViewerMedia::setCookiesEnabled(bool enabled)
|
|||
LLViewerMediaImpl* pimpl = *iter;
|
||||
if(pimpl->mMediaSource)
|
||||
{
|
||||
pimpl->mMediaSource->enable_cookies(enabled);
|
||||
pimpl->mMediaSource->cookies_enabled(enabled);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1170,127 +1102,7 @@ void LLViewerMedia::setProxyConfig(bool enable, const std::string &host, int por
|
|||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
// static
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
// static
|
||||
LLPluginCookieStore *LLViewerMedia::getCookieStore()
|
||||
{
|
||||
if(sCookieStore == NULL)
|
||||
{
|
||||
sCookieStore = new LLPluginCookieStore;
|
||||
}
|
||||
|
||||
return sCookieStore;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
// static
|
||||
void LLViewerMedia::loadCookieFile()
|
||||
{
|
||||
// build filename for each user
|
||||
std::string resolved_filename = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, PLUGIN_COOKIE_FILE_NAME);
|
||||
|
||||
if (resolved_filename.empty())
|
||||
{
|
||||
LL_INFOS() << "can't get path to plugin cookie file - probably not logged in yet." << LL_ENDL;
|
||||
return;
|
||||
}
|
||||
|
||||
// open the file for reading
|
||||
llifstream file(resolved_filename.c_str());
|
||||
if (!file.is_open())
|
||||
{
|
||||
LL_WARNS() << "can't load plugin cookies from file \"" << PLUGIN_COOKIE_FILE_NAME << "\"" << LL_ENDL;
|
||||
return;
|
||||
}
|
||||
|
||||
getCookieStore()->readAllCookies(file, true);
|
||||
|
||||
file.close();
|
||||
|
||||
// send the clear_cookies message to all loaded plugins
|
||||
impl_list::iterator iter = sViewerMediaImplList.begin();
|
||||
impl_list::iterator end = sViewerMediaImplList.end();
|
||||
for (; iter != end; iter++)
|
||||
{
|
||||
LLViewerMediaImpl* pimpl = *iter;
|
||||
if(pimpl->mMediaSource)
|
||||
{
|
||||
pimpl->mMediaSource->clear_cookies();
|
||||
}
|
||||
}
|
||||
|
||||
// If we have an OpenID cookie, re-add it to the cookie store.
|
||||
setOpenIDCookie(std::string());
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
// static
|
||||
void LLViewerMedia::saveCookieFile()
|
||||
{
|
||||
// build filename for each user
|
||||
std::string resolved_filename = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, PLUGIN_COOKIE_FILE_NAME);
|
||||
|
||||
if (resolved_filename.empty())
|
||||
{
|
||||
LL_INFOS() << "can't get path to plugin cookie file - probably not logged in yet." << LL_ENDL;
|
||||
return;
|
||||
}
|
||||
|
||||
// open a file for writing
|
||||
llofstream file(resolved_filename.c_str());
|
||||
if (!file.is_open())
|
||||
{
|
||||
LL_WARNS() << "can't open plugin cookie file \"" << PLUGIN_COOKIE_FILE_NAME << "\" for writing" << LL_ENDL;
|
||||
return;
|
||||
}
|
||||
|
||||
getCookieStore()->writePersistentCookies(file);
|
||||
|
||||
file.close();
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
// static
|
||||
void LLViewerMedia::addCookie(const std::string &name, const std::string &value, const std::string &domain, const LLDate &expires, const std::string &path, bool secure)
|
||||
{
|
||||
std::stringstream cookie;
|
||||
|
||||
cookie << name << "=" << LLPluginCookieStore::quoteString(value);
|
||||
|
||||
if(expires.notNull())
|
||||
{
|
||||
cookie << "; expires=" << expires.asRFC1123();
|
||||
}
|
||||
|
||||
cookie << "; domain=" << domain;
|
||||
|
||||
cookie << "; path=" << path;
|
||||
|
||||
if(secure)
|
||||
{
|
||||
cookie << "; secure";
|
||||
}
|
||||
|
||||
getCookieStore()->setCookies(cookie.str());
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
// static
|
||||
void LLViewerMedia::addSessionCookie(const std::string &name, const std::string &value, const std::string &domain, const std::string &path, bool secure)
|
||||
{
|
||||
// A session cookie just has a NULL date.
|
||||
addCookie(name, value, domain, LLDate(), path, secure);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
// static
|
||||
void LLViewerMedia::removeCookie(const std::string &name, const std::string &domain, const std::string &path )
|
||||
{
|
||||
// To remove a cookie, add one with the same name, domain, and path that expires in the past.
|
||||
|
||||
addCookie(name, "", domain, LLDate(LLDate::now().secondsSinceEpoch() - 1.0), path);
|
||||
}
|
||||
|
||||
//// static
|
||||
|
||||
LLSD LLViewerMedia::getHeaders()
|
||||
{
|
||||
|
|
@ -1395,8 +1207,6 @@ void LLViewerMedia::getOpenIDCookieCoro(std::string url)
|
|||
hostEnd = authority.size();
|
||||
}
|
||||
|
||||
getCookieStore()->setCookiesFromHost(sOpenIDCookie, authority.substr(hostStart, hostEnd - hostStart));
|
||||
|
||||
if (url.length())
|
||||
{
|
||||
LLMediaCtrl* media_instance = LLFloaterReg::getInstance("destinations")->getChild<LLMediaCtrl>("destination_guide_contents");
|
||||
|
|
@ -1434,7 +1244,6 @@ void LLViewerMedia::getOpenIDCookieCoro(std::string url)
|
|||
httpHeaders->append(HTTP_OUT_HEADER_COOKIE, sOpenIDCookie);
|
||||
httpHeaders->append(HTTP_OUT_HEADER_USER_AGENT, getCurrentUserAgent());
|
||||
|
||||
|
||||
LL_DEBUGS("MediaAuth") << "Requesting " << url << LL_ENDL;
|
||||
LL_DEBUGS("MediaAuth") << "sOpenIDCookie = [" << sOpenIDCookie << "]" << LL_ENDL;
|
||||
|
||||
|
|
@ -1459,13 +1268,9 @@ void LLViewerMedia::getOpenIDCookieCoro(std::string url)
|
|||
const std::string& cookie = resultHeaders[HTTP_IN_HEADER_SET_COOKIE].asStringRef();
|
||||
LL_DEBUGS("MediaAuth") << "cookie = " << cookie << LL_ENDL;
|
||||
|
||||
// *TODO: What about bad status codes? Does this destroy previous cookies?
|
||||
LLViewerMedia::getCookieStore()->setCookiesFromHost(cookie, hostAuth);
|
||||
|
||||
// Set cookie for snapshot publishing.
|
||||
std::string authCookie = cookie.substr(0, cookie.find(";")); // strip path
|
||||
LLWebProfile::setAuthCookie(authCookie);
|
||||
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -1660,12 +1465,6 @@ void LLViewerMedia::cleanupClass()
|
|||
delete sSpareBrowserMediaSource;
|
||||
sSpareBrowserMediaSource = NULL;
|
||||
}
|
||||
|
||||
if (sCookieStore != NULL)
|
||||
{
|
||||
delete sCookieStore;
|
||||
sCookieStore = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -1898,6 +1697,8 @@ LLPluginClassMedia* LLViewerMediaImpl::newSourceFromMediaType(std::string media_
|
|||
std::string user_data_path_cookies = gDirUtilp->getOSUserAppDir();
|
||||
user_data_path_cookies += gDirUtilp->getDirDelimiter();
|
||||
|
||||
std::string user_data_path_cef_log = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "cef_log.txt");
|
||||
|
||||
// Fix for EXT-5960 - make browser profile specific to user (cache, cookies etc.)
|
||||
// If the linden username returned is blank, that can only mean we are
|
||||
// at the login page displaying login Web page or Web browser test via Develop menu.
|
||||
|
|
@ -1906,7 +1707,6 @@ LLPluginClassMedia* LLViewerMediaImpl::newSourceFromMediaType(std::string media_
|
|||
std::string linden_user_dir = gDirUtilp->getLindenUserDir();
|
||||
if ( ! linden_user_dir.empty() )
|
||||
{
|
||||
// gDirUtilp->getLindenUserDir() is whole path, not just Linden name
|
||||
user_data_path_cookies = linden_user_dir;
|
||||
user_data_path_cookies += gDirUtilp->getDirDelimiter();
|
||||
};
|
||||
|
|
@ -1927,13 +1727,13 @@ LLPluginClassMedia* LLViewerMediaImpl::newSourceFromMediaType(std::string media_
|
|||
{
|
||||
media_source = new LLPluginClassMedia(owner);
|
||||
media_source->setSize(default_width, default_height);
|
||||
media_source->setUserDataPath(user_data_path_cache, user_data_path_cookies);
|
||||
media_source->setUserDataPath(user_data_path_cache, user_data_path_cookies, user_data_path_cef_log);
|
||||
media_source->setLanguageCode(LLUI::getLanguage());
|
||||
media_source->setZoomFactor(zoom_factor);
|
||||
|
||||
// collect 'cookies enabled' setting from prefs and send to embedded browser
|
||||
bool cookies_enabled = gSavedSettings.getBOOL( "CookiesEnabled" );
|
||||
media_source->enable_cookies( cookies_enabled || clean_browser);
|
||||
media_source->cookies_enabled( cookies_enabled || clean_browser);
|
||||
|
||||
// collect 'plugins enabled' setting from prefs and send to embedded browser
|
||||
bool plugins_enabled = gSavedSettings.getBOOL( "BrowserPluginsEnabled" );
|
||||
|
|
@ -2040,17 +1840,6 @@ bool LLViewerMediaImpl::initializePlugin(const std::string& media_type)
|
|||
media_source->clear_cache();
|
||||
}
|
||||
|
||||
// TODO: Only send cookies to plugins that need them
|
||||
// Ideally, the plugin should tell us whether it handles cookies or not -- either via the init response or through a separate message.
|
||||
// Due to the ordering of messages, it's possible we wouldn't get that information back in time to send cookies before sending a navigate message,
|
||||
// which could cause odd race conditions.
|
||||
std::string all_cookies = LLViewerMedia::getCookieStore()->getAllCookies();
|
||||
LL_DEBUGS() << "setting cookies: " << all_cookies << LL_ENDL;
|
||||
if(!all_cookies.empty())
|
||||
{
|
||||
media_source->set_cookies(all_cookies);
|
||||
}
|
||||
|
||||
mMediaSource = media_source;
|
||||
mMediaSource->setDeleteOK(false) ;
|
||||
updateVolume();
|
||||
|
|
@ -2992,14 +2781,10 @@ void LLViewerMediaImpl::update()
|
|||
updateVolume();
|
||||
|
||||
// TODO: this is updated every frame - is this bad?
|
||||
updateJavascriptObject();
|
||||
|
||||
// If we didn't just create the impl, it may need to get cookie updates.
|
||||
if(!sUpdatedCookies.empty())
|
||||
{
|
||||
// TODO: Only send cookies to plugins that need them
|
||||
mMediaSource->set_cookies(sUpdatedCookies);
|
||||
}
|
||||
// Removing this as part of the post viewer64 media update
|
||||
// Removed as not implemented in CEF embedded browser
|
||||
// See MAINT-8194 for a more fuller description
|
||||
// updateJavascriptObject();
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -3489,22 +3274,40 @@ void LLViewerMediaImpl::handleMediaEvent(LLPluginClassMedia* plugin, LLPluginCla
|
|||
|
||||
case LLViewerMediaObserver::MEDIA_EVENT_PICK_FILE_REQUEST:
|
||||
{
|
||||
// Display a file picker
|
||||
std::string response;
|
||||
|
||||
LLFilePicker& picker = LLFilePicker::instance();
|
||||
if (!picker.getOpenFile(LLFilePicker::FFLOAD_ALL))
|
||||
std::vector<std::string> responses;
|
||||
|
||||
bool pick_multiple_files = plugin->getIsMultipleFilePick();
|
||||
if (pick_multiple_files == false)
|
||||
{
|
||||
// The user didn't pick a file -- the empty response string will indicate this.
|
||||
picker.getOpenFile(LLFilePicker::FFLOAD_ALL);
|
||||
|
||||
std::string filename = picker.getFirstFile();
|
||||
responses.push_back(filename);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (picker.getMultipleOpenFiles())
|
||||
{
|
||||
std::string filename = picker.getFirstFile();
|
||||
|
||||
response = picker.getFirstFile();
|
||||
responses.push_back(filename);
|
||||
|
||||
plugin->sendPickFileResponse(response);
|
||||
while (!filename.empty())
|
||||
{
|
||||
filename = picker.getNextFile();
|
||||
|
||||
if (!filename.empty())
|
||||
{
|
||||
responses.push_back(filename);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
plugin->sendPickFileResponse(responses);
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case LLViewerMediaObserver::MEDIA_EVENT_AUTH_REQUEST:
|
||||
{
|
||||
LLNotification::Params auth_request_params;
|
||||
|
|
@ -3572,13 +3375,6 @@ void LLViewerMediaImpl::handleMediaEvent(LLPluginClassMedia* plugin, LLPluginCla
|
|||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// virtual
|
||||
void LLViewerMediaImpl::handleCookieSet(LLPluginClassMedia* self, const std::string &cookie)
|
||||
{
|
||||
LLViewerMedia::getCookieStore()->setCookies(cookie);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// virtual
|
||||
void
|
||||
|
|
|
|||
|
|
@ -50,7 +50,6 @@ class LLViewerMediaTexture;
|
|||
class LLMediaEntry;
|
||||
class LLVOVolume;
|
||||
class LLMimeDiscoveryResponder;
|
||||
class LLPluginCookieStore;
|
||||
|
||||
typedef LLPointer<LLViewerMediaImpl> viewer_media_t;
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -149,13 +148,6 @@ public:
|
|||
// Set the proxy config for all loaded plugins
|
||||
static void setProxyConfig(bool enable, const std::string &host, int port);
|
||||
|
||||
static LLPluginCookieStore *getCookieStore();
|
||||
static void loadCookieFile();
|
||||
static void saveCookieFile();
|
||||
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& url, const std::string &cookie);
|
||||
|
||||
|
|
@ -178,7 +170,6 @@ private:
|
|||
static void openIDSetupCoro(std::string openidUrl, std::string openidToken);
|
||||
static void getOpenIDCookieCoro(std::string url);
|
||||
|
||||
static LLPluginCookieStore *sCookieStore;
|
||||
static LLURL sOpenIDURL;
|
||||
static std::string sOpenIDCookie;
|
||||
static LLPluginClassMedia* sSpareBrowserMediaSource;
|
||||
|
|
@ -337,7 +328,6 @@ public:
|
|||
|
||||
// Inherited from LLPluginClassMediaOwner
|
||||
/*virtual*/ void handleMediaEvent(LLPluginClassMedia* plugin, LLPluginClassMediaOwner::EMediaEvent);
|
||||
/*virtual*/ void handleCookieSet(LLPluginClassMedia* self, const std::string &cookie);
|
||||
|
||||
// LLEditMenuHandler overrides
|
||||
/*virtual*/ void cut();
|
||||
|
|
|
|||
|
|
@ -440,7 +440,7 @@ public:
|
|||
|
||||
struct CompareRegionByLastUpdate
|
||||
{
|
||||
bool operator()(const LLViewerRegion* const& lhs, const LLViewerRegion* const& rhs)
|
||||
bool operator()(const LLViewerRegion* const& lhs, const LLViewerRegion* const& rhs) const
|
||||
{
|
||||
S32 lpa = lhs->getLastUpdate();
|
||||
S32 rpa = rhs->getLastUpdate();
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ public:
|
|||
|
||||
struct CompareVOCacheEntry
|
||||
{
|
||||
bool operator()(const LLVOCacheEntry* const& lhs, const LLVOCacheEntry* const& rhs)
|
||||
bool operator()(const LLVOCacheEntry* const& lhs, const LLVOCacheEntry* const& rhs) const
|
||||
{
|
||||
F32 lpa = lhs->getSceneContribution();
|
||||
F32 rpa = rhs->getSceneContribution();
|
||||
|
|
|
|||
|
|
@ -31,7 +31,6 @@
|
|||
// libs
|
||||
#include "llbufferstream.h"
|
||||
#include "llimagepng.h"
|
||||
#include "llplugincookiestore.h"
|
||||
|
||||
#include "llsdserialize.h"
|
||||
|
||||
|
|
|
|||
|
|
@ -8,14 +8,14 @@
|
|||
help_topic="floater_about"
|
||||
save_rect="true"
|
||||
title="ABOUT [CAPITALIZED_APP_NAME]"
|
||||
width="470">
|
||||
width="500">
|
||||
|
||||
<tab_container
|
||||
follows="all"
|
||||
top="25"
|
||||
left="10"
|
||||
height="405"
|
||||
width="450"
|
||||
width="480"
|
||||
name="about_tab"
|
||||
tab_position="top">
|
||||
<panel
|
||||
|
|
@ -33,7 +33,7 @@
|
|||
max_length="65536"
|
||||
name="support_editor"
|
||||
top="5"
|
||||
width="435"
|
||||
width="465"
|
||||
word_wrap="true" />
|
||||
<button
|
||||
follows="left|top"
|
||||
|
|
@ -56,7 +56,7 @@
|
|||
left="5"
|
||||
name="linden_intro"
|
||||
top="10"
|
||||
width="435"
|
||||
width="465"
|
||||
wrap="true">
|
||||
Second Life is brought to you by the Lindens,
|
||||
with open source contributions from:
|
||||
|
|
@ -71,7 +71,7 @@ with open source contributions from:
|
|||
max_length="65536"
|
||||
name="contrib_names"
|
||||
top_pad="10"
|
||||
width="435"
|
||||
width="465"
|
||||
word_wrap="true">
|
||||
Dummy Name replaced at run time
|
||||
</text_editor>
|
||||
|
|
@ -91,7 +91,7 @@ Dummy Name replaced at run time
|
|||
max_length="65536"
|
||||
name="licenses_editor"
|
||||
top="5"
|
||||
width="435"
|
||||
width="465"
|
||||
word_wrap="true">
|
||||
3Dconnexion SDK Copyright (C) 1992-2009 3Dconnexion
|
||||
APR Copyright (C) 2011 The Apache Software Foundation
|
||||
|
|
|
|||
|
|
@ -178,108 +178,7 @@
|
|||
width="22">
|
||||
<button.commit_callback
|
||||
function="WebContent.TestURL"
|
||||
parameter="https://callum-linden.s3.amazonaws.com/ceftests.html"/>
|
||||
</button>
|
||||
|
||||
<button
|
||||
image_overlay="Video_URL_Off"
|
||||
image_disabled="PushButton_Disabled"
|
||||
image_disabled_selected="PushButton_Disabled"
|
||||
image_selected="PushButton_Selected"
|
||||
image_unselected="PushButton_Off"
|
||||
chrome="true"
|
||||
tool_tip="MPEG4 Video Test"
|
||||
enabled="true"
|
||||
follows="left|top"
|
||||
height="22"
|
||||
layout="topleft"
|
||||
left="27"
|
||||
name="VLC Plugin Test"
|
||||
top="0"
|
||||
width="22">
|
||||
<button.commit_callback
|
||||
function="WebContent.TestURL"
|
||||
parameter="https://callum-linden.s3.amazonaws.com/sample_media/ss.mp4"/>
|
||||
</button>
|
||||
<button
|
||||
image_overlay="Video_URL_Off"
|
||||
image_disabled="PushButton_Disabled"
|
||||
image_disabled_selected="PushButton_Disabled"
|
||||
image_selected="PushButton_Selected"
|
||||
image_unselected="PushButton_Off"
|
||||
chrome="true"
|
||||
tool_tip="MKV Video Test"
|
||||
enabled="true"
|
||||
follows="left|top"
|
||||
height="22"
|
||||
layout="topleft"
|
||||
left="51"
|
||||
name="VLC Plugin Test"
|
||||
top="0"
|
||||
width="22">
|
||||
<button.commit_callback
|
||||
function="WebContent.TestURL"
|
||||
parameter="https://callum-linden.s3.amazonaws.com/sample_media/jellyfish.mkv"/>
|
||||
</button>
|
||||
<button
|
||||
image_overlay="Video_URL_Off"
|
||||
image_disabled="PushButton_Disabled"
|
||||
image_disabled_selected="PushButton_Disabled"
|
||||
image_selected="PushButton_Selected"
|
||||
image_unselected="PushButton_Off"
|
||||
chrome="true"
|
||||
tool_tip="WebM Video Test"
|
||||
enabled="true"
|
||||
follows="left|top"
|
||||
height="22"
|
||||
layout="topleft"
|
||||
left="75"
|
||||
name="VLC Plugin Test"
|
||||
top="0"
|
||||
width="22">
|
||||
<button.commit_callback
|
||||
function="WebContent.TestURL"
|
||||
parameter="https://callum-linden.s3.amazonaws.com/sample_media/jumprope.webm"/>
|
||||
</button>
|
||||
<button
|
||||
image_overlay="Video_URL_Off"
|
||||
image_disabled="PushButton_Disabled"
|
||||
image_disabled_selected="PushButton_Disabled"
|
||||
image_selected="PushButton_Selected"
|
||||
image_unselected="PushButton_Off"
|
||||
chrome="true"
|
||||
tool_tip="MP3 audio Test"
|
||||
enabled="true"
|
||||
follows="left|top"
|
||||
height="22"
|
||||
layout="topleft"
|
||||
left="99"
|
||||
name="VLC Plugin Test"
|
||||
top="0"
|
||||
width="22">
|
||||
<button.commit_callback
|
||||
function="WebContent.TestURL"
|
||||
parameter="https://callum-linden.s3.amazonaws.com/alegria.mp3"/>
|
||||
</button>
|
||||
<button
|
||||
image_overlay="Video_URL_Off"
|
||||
image_disabled="PushButton_Disabled"
|
||||
image_disabled_selected="PushButton_Disabled"
|
||||
image_selected="PushButton_Selected"
|
||||
image_unselected="PushButton_Off"
|
||||
chrome="true"
|
||||
tool_tip="FLV Test"
|
||||
enabled="true"
|
||||
follows="left|top"
|
||||
height="22"
|
||||
layout="topleft"
|
||||
left="123"
|
||||
name="VLC Plugin Test"
|
||||
top="0"
|
||||
width="22">
|
||||
<button.commit_callback
|
||||
function="WebContent.TestURL"
|
||||
parameter="https://callum-linden.s3.amazonaws.com/sample_media/vandal.flv"/>
|
||||
parameter="https://sl-viewer-media-system.s3.amazonaws.com/index.html"/>
|
||||
</button>
|
||||
</layout_panel>
|
||||
<layout_panel
|
||||
|
|
|
|||
|
|
@ -245,7 +245,7 @@
|
|||
name="Media Browser">
|
||||
<menu_item_call.on_click
|
||||
function="Advanced.WebContentTest"
|
||||
parameter="http://google.com"/>
|
||||
parameter="http://duckduckgo.com"/>
|
||||
</menu_item_call>
|
||||
<menu
|
||||
create_jump_keys="true"
|
||||
|
|
|
|||
|
|
@ -3173,7 +3173,7 @@
|
|||
shortcut="control|alt|shift|Z">
|
||||
<menu_item_call.on_click
|
||||
function="Advanced.WebContentTest"
|
||||
parameter="http://google.com"/>
|
||||
parameter="http://duckduckgo.com"/>
|
||||
</menu_item_call>
|
||||
<menu_item_call
|
||||
label="FB Connect Test"
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@
|
|||
follows="left|top"
|
||||
height="23"
|
||||
label="Clear History"
|
||||
tool_tip="Clear login image, last location, teleport history, web, and texture cache"
|
||||
tool_tip="Clear login image, last location, teleport history, web and texture cache"
|
||||
layout="topleft"
|
||||
left="30"
|
||||
name="clear_cache"
|
||||
|
|
|
|||
|
|
@ -106,38 +106,6 @@
|
|||
width="300">
|
||||
Web:
|
||||
</text>
|
||||
<!-- <radio_group
|
||||
control_name="UseExternalBrowser"
|
||||
draw_border="false"
|
||||
follows="top|left"
|
||||
height="40"
|
||||
layout="topleft"
|
||||
left_delta="50"
|
||||
name="use_external_browser"
|
||||
top_pad="-2"
|
||||
width="480">
|
||||
<radio_item
|
||||
height="20"
|
||||
label="Use my browser (IE, Firefox, Safari)"
|
||||
layout="topleft"
|
||||
left_delta="0"
|
||||
name="external"
|
||||
value="true"
|
||||
top="0"
|
||||
tool_tip="Use the default system web browser for help, web links, etc. Not recommended if running full screen."
|
||||
width="480" />
|
||||
<radio_item
|
||||
height="20"
|
||||
label="Use built-in browser"
|
||||
layout="topleft"
|
||||
left="0"
|
||||
name="internal"
|
||||
value=""
|
||||
tool_tip="Use the built-in web browser for help, web links, etc. This browser opens as a new window inside [APP_NAME]."
|
||||
top_delta="20"
|
||||
width="480" />
|
||||
</radio_group> -->
|
||||
|
||||
<radio_group
|
||||
control_name="PreferredBrowserBehavior"
|
||||
follows="left|top"
|
||||
|
|
@ -149,7 +117,7 @@
|
|||
width="480">
|
||||
<radio_item
|
||||
height="20"
|
||||
label="Use my browser (Chrome, Firefox, IE) for all links"
|
||||
label="Use the default system browser for all links"
|
||||
layout="topleft"
|
||||
left="0"
|
||||
name="internal"
|
||||
|
|
@ -159,17 +127,17 @@
|
|||
width="480" />
|
||||
<radio_item
|
||||
height="20"
|
||||
label="Use built-in browser for Second Life links only"
|
||||
label="Use the built-in browser for Second Life links only"
|
||||
layout="topleft"
|
||||
left_delta="0"
|
||||
name="external"
|
||||
value="1"
|
||||
tool_tip="Use the default system web browser for help, web links, etc. Builtin browser will be used only for LindenLab/SecondLife links."
|
||||
tool_tip="Use the default system web browser for help, web links, etc. The built-in browser will be used only for LindenLab/Second Life links."
|
||||
top_delta="20"
|
||||
width="480" />
|
||||
<radio_item
|
||||
height="20"
|
||||
label="Use built-in browser for all links"
|
||||
label="Use the built-in browser for all links"
|
||||
layout="topleft"
|
||||
left="0"
|
||||
name="external_all"
|
||||
|
|
@ -193,22 +161,6 @@
|
|||
radio_style="false"
|
||||
width="400"
|
||||
top_pad="5"/>
|
||||
|
||||
<check_box
|
||||
top_delta="4"
|
||||
enabled="true"
|
||||
follows="left|top"
|
||||
height="14"
|
||||
initial_value="true"
|
||||
control_name="CookiesEnabled"
|
||||
label="Accept cookies"
|
||||
left_delta="0"
|
||||
mouse_opaque="true"
|
||||
name="cookies_enabled"
|
||||
radio_style="false"
|
||||
width="400"
|
||||
top_pad="5"/>
|
||||
|
||||
<check_box
|
||||
top_delta="4"
|
||||
enabled="true"
|
||||
|
|
|
|||
Loading…
Reference in New Issue