summaryrefslogtreecommitdiffstats
path: root/chrome_frame
diff options
context:
space:
mode:
Diffstat (limited to 'chrome_frame')
-rw-r--r--chrome_frame/bho.cc2
-rw-r--r--chrome_frame/chrome_active_document.cc42
-rw-r--r--chrome_frame/chrome_active_document.h1
-rw-r--r--chrome_frame/chrome_frame_activex_base.h3
-rw-r--r--chrome_frame/chrome_frame_automation.cc25
-rw-r--r--chrome_frame/chrome_frame_automation.h41
-rw-r--r--chrome_frame/chrome_frame_npapi.cc16
-rw-r--r--chrome_frame/protocol_sink_wrap.cc3
-rw-r--r--chrome_frame/test/reliability/page_load_test.cc4
-rw-r--r--chrome_frame/test/test_with_web_server.cc6
-rw-r--r--chrome_frame/test/util_unittests.cc173
-rw-r--r--chrome_frame/utils.cc142
-rw-r--r--chrome_frame/utils.h19
13 files changed, 251 insertions, 226 deletions
diff --git a/chrome_frame/bho.cc b/chrome_frame/bho.cc
index 62ffa8e..f8d44e6 100644
--- a/chrome_frame/bho.cc
+++ b/chrome_frame/bho.cc
@@ -300,7 +300,7 @@ void Bho::ProcessOptInUrls(IWebBrowser2* browser, BSTR url) {
#endif
std::wstring current_url(url, SysStringLen(url));
- if (IsValidUrlScheme(current_url, false)) {
+ if (IsValidUrlScheme(GURL(current_url), false)) {
bool cf_protocol = StartsWith(current_url, kChromeProtocolPrefix, false);
if (!cf_protocol && IsOptInUrl(current_url.c_str())) {
DLOG(INFO) << "Opt-in URL. Switching to cf.";
diff --git a/chrome_frame/chrome_active_document.cc b/chrome_frame/chrome_active_document.cc
index 1c03c94..0890c99 100644
--- a/chrome_frame/chrome_active_document.cc
+++ b/chrome_frame/chrome_active_document.cc
@@ -42,8 +42,6 @@
#include "chrome_frame/crash_reporting/crash_metrics.h"
#include "chrome_frame/utils.h"
-const wchar_t kChromeAttachExternalTabPrefix[] = L"attach_external_tab";
-
static const wchar_t kUseChromeNetworking[] = L"UseChromeNetworking";
static const wchar_t kHandleTopLevelRequests[] = L"HandleTopLevelRequests";
@@ -124,14 +122,6 @@ HRESULT ChromeActiveDocument::FinalConstruct() {
LoadAccelerators(this_module,
MAKEINTRESOURCE(IDR_CHROME_FRAME_IE_FULL_TAB));
DCHECK(accelerator_table_ != NULL);
-
- HRESULT hr = security_manager_.CreateInstance(CLSID_InternetSecurityManager);
- if (FAILED(hr)) {
- NOTREACHED() << __FUNCTION__
- << " Failed to create InternetSecurityManager. Error: 0x%x"
- << hr;
- }
-
return S_OK;
}
@@ -273,10 +263,6 @@ STDMETHODIMP ChromeActiveDocument::Load(BOOL fully_avalable,
return E_INVALIDARG;
}
- if (!CanNavigateInFullTabMode(cf_url, security_manager_)) {
- return E_INVALIDARG;
- }
-
std::string referrer(mgr ? mgr->referrer() : EmptyString());
// With CTransaction patch we have more robust way to grab the referrer for
@@ -289,12 +275,12 @@ STDMETHODIMP ChromeActiveDocument::Load(BOOL fully_avalable,
}
if (!LaunchUrl(cf_url, referrer)) {
- NOTREACHED() << __FUNCTION__ << " Failed to launch url:" << url;
+ DLOG(ERROR) << __FUNCTION__ << " Failed to launch url:" << url;
return E_INVALIDARG;
}
if (!cf_url.is_chrome_protocol() && !cf_url.attach_to_external_tab())
- url_fetcher_->SetInfoForUrl(cf_url.url(), moniker_name, bind_context);
+ url_fetcher_->SetInfoForUrl(url.c_str(), moniker_name, bind_context);
THREAD_SAFE_UMA_HISTOGRAM_CUSTOM_COUNTS("ChromeFrame.FullTabLaunchType",
cf_url.is_chrome_protocol(),
@@ -405,10 +391,6 @@ STDMETHODIMP ChromeActiveDocument::LoadHistory(IStream* stream,
return E_INVALIDARG;
}
- if (!CanNavigateInFullTabMode(cf_url, security_manager_)) {
- return E_INVALIDARG;
- }
-
const std::string& referrer = EmptyString();
if (!LaunchUrl(cf_url, referrer)) {
NOTREACHED() << __FUNCTION__ << " Failed to launch url:" << url;
@@ -735,10 +717,12 @@ void ChromeActiveDocument::UpdateNavigationState(
// an external tab container within chrome and then connecting to it from IE.
// We still want to update the address bar/history, etc, to ensure that
// the special URL used by Chrome to indicate this is updated correctly.
+ ChromeFrameUrl cf_url;
+ bool is_attach_external_tab_url = cf_url.Parse(std::wstring(url_)) &&
+ cf_url.attach_to_external_tab();
bool is_internal_navigation = ((new_navigation_info.navigation_index > 0) &&
(new_navigation_info.navigation_index !=
- navigation_info_.navigation_index)) ||
- MatchPatternWide(static_cast<BSTR>(url_), kChromeFrameAttachTabPattern);
+ navigation_info_.navigation_index)) || is_attach_external_tab_url;
if (new_navigation_info.url.is_valid())
url_.Allocate(UTF8ToWide(new_navigation_info.url.spec()).c_str());
@@ -991,18 +975,14 @@ HRESULT ChromeActiveDocument::IEExec(const GUID* cmd_group_guid,
bool ChromeActiveDocument::LaunchUrl(const ChromeFrameUrl& cf_url,
const std::string& referrer) {
DCHECK(automation_client_.get() != NULL);
- DCHECK(!cf_url.url().empty());
-
- url_.Allocate(cf_url.url().c_str());
-
- std::string utf8_url(WideToUTF8(cf_url.url()));
- DLOG(INFO) << "this:" << this << " url is:" << utf8_url;
+ DCHECK(!cf_url.gurl().is_empty());
+ url_.Allocate(UTF8ToWide(cf_url.gurl().spec()).c_str());
if (cf_url.attach_to_external_tab()) {
dimensions_ = cf_url.dimensions();
automation_client_->AttachExternalTab(cf_url.cookie());
SetWindowDimensions();
- } else if (!automation_client_->InitiateNavigation(utf8_url,
+ } else if (!automation_client_->InitiateNavigation(cf_url.gurl().spec(),
referrer,
is_privileged_)) {
DLOG(ERROR) << "Invalid URL: " << url_;
@@ -1015,10 +995,8 @@ bool ChromeActiveDocument::LaunchUrl(const ChromeFrameUrl& cf_url,
return true;
automation_client_->SetUrlFetcher(url_fetcher_.get());
-
- GURL url(utf8_url);
return InitializeAutomation(GetHostProcessName(false), L"", IsIEInPrivate(),
- false, url, GURL(referrer));
+ false, cf_url.gurl(), GURL(referrer));
}
diff --git a/chrome_frame/chrome_active_document.h b/chrome_frame/chrome_active_document.h
index 7f9fd9d..146f091 100644
--- a/chrome_frame/chrome_active_document.h
+++ b/chrome_frame/chrome_active_document.h
@@ -458,7 +458,6 @@ END_EXEC_COMMAND_MAP()
// a new ChromeActiveDocument instance is taking its place.
bool is_automation_client_reused_;
- ScopedComPtr<IInternetSecurityManager> security_manager_;
ScopedComPtr<INewWindowManager> popup_manager_;
bool popup_allowed_;
HACCEL accelerator_table_;
diff --git a/chrome_frame/chrome_frame_activex_base.h b/chrome_frame/chrome_frame_activex_base.h
index a2774e3..9e6734b 100644
--- a/chrome_frame/chrome_frame_activex_base.h
+++ b/chrome_frame/chrome_frame_activex_base.h
@@ -606,9 +606,6 @@ END_MSG_MAP()
std::string src_utf8;
WideToUTF8(src, SysStringLen(src), &src_utf8);
std::string full_url = ResolveURL(GetDocumentUrl(), src_utf8);
- if (full_url.empty()) {
- return E_INVALIDARG;
- }
// We can initiate navigation here even if ready_state is not complete.
// We do not have to set proxy, and AutomationClient will take care
diff --git a/chrome_frame/chrome_frame_automation.cc b/chrome_frame/chrome_frame_automation.cc
index 216b7a9..05109c5 100644
--- a/chrome_frame/chrome_frame_automation.cc
+++ b/chrome_frame/chrome_frame_automation.cc
@@ -609,6 +609,13 @@ bool ChromeFrameAutomationClient::Initialize(
// InitializeComplete is called successfully.
init_state_ = INITIALIZING;
+ HRESULT hr = security_manager_.CreateInstance(CLSID_InternetSecurityManager);
+ if (FAILED(hr)) {
+ NOTREACHED() << __FUNCTION__
+ << " Failed to create InternetSecurityManager. Error: 0x%x"
+ << hr;
+ }
+
if (chrome_launch_params_->url().is_valid())
navigate_after_initialization_ = false;
@@ -657,7 +664,7 @@ void ChromeFrameAutomationClient::Uninitialize() {
if (::IsWindow(m_hWnd))
DestroyWindow();
- DCHECK(navigate_after_initialization_ == false);
+ // DCHECK(navigate_after_initialization_ == false);
handle_top_level_requests_ = false;
ui_thread_id_ = 0;
chrome_frame_delegate_ = NULL;
@@ -670,11 +677,11 @@ bool ChromeFrameAutomationClient::InitiateNavigation(const std::string& url,
return false;
GURL parsed_url(url);
+
// Catch invalid URLs early.
- if (!parsed_url.is_valid() ||
- !IsValidUrlScheme(UTF8ToWide(url), is_privileged)) {
- DLOG(ERROR) << "Invalid URL passed to InitiateNavigation: " << url
- << " is_privileged=" << is_privileged;
+ // Can we allow this navigation to happen?
+ if (!CanNavigate(parsed_url, security_manager_, is_privileged)) {
+ DLOG(ERROR) << __FUNCTION__ << " Not allowing navigation to: " << url;
return false;
}
@@ -1357,6 +1364,14 @@ void ChromeFrameAutomationClient::RunUnloadHandlers(HWND notification_window,
}
}
+void ChromeFrameAutomationClient::SetUrlFetcher(
+ PluginUrlRequestManager* url_fetcher) {
+ DCHECK(url_fetcher != NULL);
+ url_fetcher_ = url_fetcher;
+ url_fetcher_flags_ = url_fetcher->GetThreadSafeFlags();
+ url_fetcher_->set_delegate(this);
+}
+
void ChromeFrameAutomationClient::SetZoomLevel(PageZoom::Function zoom_level) {
if (automation_server_) {
automation_server_->Send(new AutomationMsg_SetZoomLevel(0, tab_handle_,
diff --git a/chrome_frame/chrome_frame_automation.h b/chrome_frame/chrome_frame_automation.h
index 4a3fcc5..e2bdfa0 100644
--- a/chrome_frame/chrome_frame_automation.h
+++ b/chrome_frame/chrome_frame_automation.h
@@ -397,6 +397,9 @@ class ChromeFrameAutomationClient
handle_top_level_requests_ = handle_top_level_requests;
}
+ // Url request manager set up.
+ void SetUrlFetcher(PluginUrlRequestManager* url_fetcher);
+
// Called if the same instance of the ChromeFrameAutomationClient object
// is reused.
bool Reinitialize(ChromeFrameDelegate* chrome_frame_delegate,
@@ -455,6 +458,20 @@ class ChromeFrameAutomationClient
// Helpers
void ReportNavigationError(AutomationMsg_NavigationResponseValues error_code,
const std::string& url);
+
+ bool ProcessUrlRequestMessage(TabProxy* tab, const IPC::Message& msg,
+ bool ui_thread);
+
+ // PluginUrlRequestDelegate implementation. Simply adds tab's handle
+ // as parameter and forwards to Chrome via IPC.
+ virtual void OnResponseStarted(int request_id, const char* mime_type,
+ const char* headers, int size, base::Time last_modified,
+ const std::string& redirect_url, int redirect_status);
+ virtual void OnReadComplete(int request_id, const std::string& data);
+ virtual void OnResponseEnd(int request_id, const URLRequestStatus& status);
+ virtual void OnCookiesRetrieved(bool success, const GURL& url,
+ const std::string& cookie_string, int cookie_id);
+
bool is_initialized() const {
return init_state_ == INITIALIZED;
}
@@ -497,34 +514,16 @@ class ChromeFrameAutomationClient
scoped_refptr<ChromeFrameLaunchParams> chrome_launch_params_;
+ // Cache security manager for URL zone checking
+ ScopedComPtr<IInternetSecurityManager> security_manager_;
+
// When host network stack is used, this object is in charge of
// handling network requests.
PluginUrlRequestManager* url_fetcher_;
PluginUrlRequestManager::ThreadSafeFlags url_fetcher_flags_;
- bool ProcessUrlRequestMessage(TabProxy* tab, const IPC::Message& msg,
- bool ui_thread);
-
- // PluginUrlRequestDelegate implementation. Simply adds tab's handle
- // as parameter and forwards to Chrome via IPC.
- virtual void OnResponseStarted(int request_id, const char* mime_type,
- const char* headers, int size, base::Time last_modified,
- const std::string& redirect_url, int redirect_status);
- virtual void OnReadComplete(int request_id, const std::string& data);
- virtual void OnResponseEnd(int request_id, const URLRequestStatus& status);
- virtual void OnCookiesRetrieved(bool success, const GURL& url,
- const std::string& cookie_string, int cookie_id);
-
friend class BeginNavigateContext;
friend class CreateExternalTabContext;
-
- public:
- void SetUrlFetcher(PluginUrlRequestManager* url_fetcher) {
- DCHECK(url_fetcher != NULL);
- url_fetcher_ = url_fetcher;
- url_fetcher_flags_ = url_fetcher->GetThreadSafeFlags();
- url_fetcher_->set_delegate(this);
- }
};
#endif // CHROME_FRAME_CHROME_FRAME_AUTOMATION_H_
diff --git a/chrome_frame/chrome_frame_npapi.cc b/chrome_frame/chrome_frame_npapi.cc
index 52151a7..e9ee6e9 100644
--- a/chrome_frame/chrome_frame_npapi.cc
+++ b/chrome_frame/chrome_frame_npapi.cc
@@ -1093,17 +1093,25 @@ bool ChromeFrameNPAPI::NavigateToURL(const NPVariant* args, uint32_t arg_count,
}
std::string url("about:blank");
-
if (!NPVARIANT_IS_NULL(args[0])) {
const NPString& str = args[0].value.stringValue;
if (str.UTF8Length) {
url.assign(std::string(str.UTF8Characters, str.UTF8Length));
}
}
- DLOG(WARNING) << __FUNCTION__ << " " << url;
+
+ GURL document_url(GetDocumentUrl());
+ if (document_url.SchemeIsSecure()) {
+ GURL source_url(url);
+ if (!source_url.SchemeIsSecure()) {
+ DLOG(WARNING) << __FUNCTION__ << " Prevnting navigation to HTTP url"
+ " since the containing document is HTTPS. URL: " << source_url <<
+ " Document URL: " << document_url;
+ return false;
+ }
+ }
+
std::string full_url = ResolveURL(GetDocumentUrl(), url);
- if (full_url.empty())
- return false;
src_ = full_url;
// Navigate only if we completed initialization i.e. proxy is set etc.
diff --git a/chrome_frame/protocol_sink_wrap.cc b/chrome_frame/protocol_sink_wrap.cc
index 3388b16..0b3e5a7 100644
--- a/chrome_frame/protocol_sink_wrap.cc
+++ b/chrome_frame/protocol_sink_wrap.cc
@@ -583,7 +583,8 @@ bool HandleAttachToExistingExternalTab(LPCWSTR url,
IInternetProtocol* protocol,
IInternetProtocolSink* prot_sink,
IBindCtx* bind_ctx) {
- if (MatchPatternWide(url, kChromeFrameAttachTabPattern)) {
+ ChromeFrameUrl cf_url;
+ if (cf_url.Parse(url) && cf_url.attach_to_external_tab()) {
scoped_refptr<ProtData> prot_data = ProtData::DataFromProtocol(protocol);
if (!prot_data) {
// Pass NULL as the read function which indicates that always return EOF
diff --git a/chrome_frame/test/reliability/page_load_test.cc b/chrome_frame/test/reliability/page_load_test.cc
index 6d701cd..ae0fd3e 100644
--- a/chrome_frame/test/reliability/page_load_test.cc
+++ b/chrome_frame/test/reliability/page_load_test.cc
@@ -384,12 +384,12 @@ class PageLoadTest : public testing::Test {
}
SetConfigBool(kChromeFrameHeadlessMode, true);
- SetConfigBool(kEnableGCFProtocol, true);
+ SetConfigBool(kAllowUnsafeURLs, true);
}
virtual void TearDown() {
DeleteConfigValue(kChromeFrameHeadlessMode);
- DeleteConfigValue(kEnableGCFProtocol);
+ DeleteConfigValue(kAllowUnsafeURLs);
}
FilePath ConstructSavedDebugLogPath(const FilePath& debug_log_path,
diff --git a/chrome_frame/test/test_with_web_server.cc b/chrome_frame/test/test_with_web_server.cc
index 2db6172..dead3d2 100644
--- a/chrome_frame/test/test_with_web_server.cc
+++ b/chrome_frame/test/test_with_web_server.cc
@@ -77,7 +77,7 @@ void ChromeFrameTestWithWebServer::SetUp() {
CloseAllBrowsers();
// Make sure that we are not accidently enabling gcf protocol.
- SetConfigBool(kEnableGCFProtocol, false);
+ SetConfigBool(kAllowUnsafeURLs, false);
PathService::Get(base::DIR_SOURCE_ROOT, &test_file_path_);
test_file_path_ = test_file_path_.Append(FILE_PATH_LITERAL("chrome_frame"))
@@ -766,9 +766,9 @@ TEST_F(ChromeFrameTestWithWebServer, FullTabModeIE_MetaTag) {
const wchar_t kCFProtocolPage[] = L"files/cf_protocol.html";
TEST_F(ChromeFrameTestWithWebServer, FullTabModeIE_CFProtocol) {
// Temporarily enable gcf: protocol for this test.
- SetConfigBool(kEnableGCFProtocol, true);
+ SetConfigBool(kAllowUnsafeURLs, true);
SimpleBrowserTest(IE, kCFProtocolPage, L"chrome_frame_protocol");
- SetConfigBool(kEnableGCFProtocol, false);
+ SetConfigBool(kAllowUnsafeURLs, false);
}
const wchar_t kPersistentCookieTest[] =
diff --git a/chrome_frame/test/util_unittests.cc b/chrome_frame/test/util_unittests.cc
index b4da4c4..95c55c7 100644
--- a/chrome_frame/test/util_unittests.cc
+++ b/chrome_frame/test/util_unittests.cc
@@ -93,7 +93,8 @@ TEST(UtilTests, IsValidUrlScheme) {
for (int i = 0; i < arraysize(test_cases); ++i) {
const Cases& test = test_cases[i];
- EXPECT_EQ(test.expected, IsValidUrlScheme(test.url, test.is_privileged));
+ EXPECT_EQ(test.expected, IsValidUrlScheme(GURL(test.url),
+ test.is_privileged));
}
}
@@ -118,27 +119,42 @@ TEST(UtilTests, GetTempInternetFiles) {
TEST(UtilTests, ParseAttachTabUrlTest) {
ChromeFrameUrl cf_url;
- EXPECT_TRUE(cf_url.Parse(L"http://f/?attach_external_tab&10&1&0&0&100&100"));
+ EXPECT_TRUE(cf_url.Parse(L"http://f/?attach_external_tab&10&1&2&3&123&321"));
EXPECT_TRUE(cf_url.attach_to_external_tab());
EXPECT_FALSE(cf_url.is_chrome_protocol());
-
EXPECT_EQ(10, cf_url.cookie());
EXPECT_EQ(1, cf_url.disposition());
- EXPECT_EQ(0, cf_url.dimensions().x());
- EXPECT_EQ(0, cf_url.dimensions().y());
- EXPECT_EQ(100, cf_url.dimensions().width());
- EXPECT_EQ(100, cf_url.dimensions().height());
+ EXPECT_EQ(gfx::Rect(2, 3, 123, 321), cf_url.dimensions());
- EXPECT_TRUE(cf_url.Parse(L"http://www.foobar.com?&10&1&0&0&100&100"));
+ EXPECT_TRUE(cf_url.Parse(L"http://www.foobar.com?&10&1&2&3&123&321"));
EXPECT_FALSE(cf_url.attach_to_external_tab());
+ EXPECT_FALSE(cf_url.is_chrome_protocol());
+ EXPECT_EQ(0, cf_url.cookie());
+ EXPECT_EQ(0, cf_url.disposition());
+ EXPECT_EQ(gfx::Rect(0, 0, 0, 0), cf_url.dimensions());
EXPECT_FALSE(cf_url.Parse(L"attach_external_tab&10&1"));
- EXPECT_TRUE(cf_url.attach_to_external_tab());
+ EXPECT_FALSE(cf_url.attach_to_external_tab());
+ EXPECT_FALSE(cf_url.is_chrome_protocol());
+ EXPECT_EQ(0, cf_url.cookie());
+ EXPECT_EQ(0, cf_url.disposition());
+ EXPECT_EQ(gfx::Rect(0, 0, 0, 0), cf_url.dimensions());
+
+ EXPECT_TRUE(cf_url.Parse(L"gcf:http://f/?attach_tab&10&1&2&3&123&321"));
+ EXPECT_FALSE(cf_url.attach_to_external_tab());
+ EXPECT_TRUE(cf_url.is_chrome_protocol());
+ EXPECT_EQ(0, cf_url.cookie());
+ EXPECT_EQ(0, cf_url.disposition());
+ EXPECT_EQ(gfx::Rect(0, 0, 0, 0), cf_url.dimensions());
- EXPECT_TRUE(cf_url.Parse(L"gcf:http://f/?attach_tab&10&1&0&0&100&100"));
+ EXPECT_TRUE(cf_url.Parse(L"gcf:http://google.com"));
EXPECT_FALSE(cf_url.attach_to_external_tab());
EXPECT_TRUE(cf_url.is_chrome_protocol());
+ EXPECT_EQ(0, cf_url.cookie());
+ EXPECT_EQ(0, cf_url.disposition());
+ EXPECT_EQ(gfx::Rect(0, 0, 0, 0), cf_url.dimensions());
+ EXPECT_EQ(cf_url.gurl(), GURL("http://google.com"));
}
// Mock for the IInternetSecurityManager interface
@@ -172,74 +188,91 @@ class MockIInternetSecurityManager : public IInternetSecurityManager {
HRESULT(DWORD zone, IEnumString** enum_string, DWORD flags));
};
-TEST(UtilTests, CanNavigateFullTabModeTest) {
- ChromeFrameUrl cf_url;
-
+TEST(UtilTests, CanNavigateTest) {
MockIInternetSecurityManager mock;
- EXPECT_CALL(mock, MapUrlToZone(testing::StartsWith(L"http://blah"),
- testing::_, testing::_))
- .WillRepeatedly(testing::DoAll(
- testing::SetArgumentPointee<1>(URLZONE_INTERNET),
- testing::Return(S_OK)));
-
- EXPECT_CALL(mock, MapUrlToZone(testing::StartsWith(L"http://untrusted"),
- testing::_, testing::_))
- .WillRepeatedly(testing::DoAll(
- testing::SetArgumentPointee<1>(URLZONE_UNTRUSTED),
- testing::Return(S_OK)));
-
- EXPECT_CALL(mock, MapUrlToZone(testing::StartsWith(L"about:"),
- testing::_, testing::_))
- .WillRepeatedly(testing::DoAll(
- testing::SetArgumentPointee<1>(URLZONE_TRUSTED),
- testing::Return(S_OK)));
-
- EXPECT_CALL(mock, MapUrlToZone(testing::StartsWith(L"view-source:"),
- testing::_, testing::_))
- .WillRepeatedly(testing::DoAll(
- testing::SetArgumentPointee<1>(URLZONE_TRUSTED),
- testing::Return(S_OK)));
-
- EXPECT_TRUE(cf_url.Parse(
- L"http://blah/?attach_external_tab&10&1&0&0&100&100"));
- EXPECT_TRUE(CanNavigateInFullTabMode(cf_url, &mock));
-
- EXPECT_TRUE(cf_url.Parse(
- L"http://untrusted/bar.html"));
- EXPECT_FALSE(CanNavigateInFullTabMode(cf_url, &mock));
-
- EXPECT_TRUE(cf_url.Parse(
- L"http://blah/?attach_external_tab&10&1&0&0&100&100"));
- EXPECT_TRUE(CanNavigateInFullTabMode(cf_url, &mock));
- EXPECT_TRUE(cf_url.Parse(L"gcf:about:blank"));
- EXPECT_TRUE(CanNavigateInFullTabMode(cf_url, &mock));
-
- EXPECT_TRUE(cf_url.Parse(L"gcf:view-source:http://www.foo.com"));
- EXPECT_TRUE(CanNavigateInFullTabMode(cf_url, &mock));
-
- EXPECT_TRUE(cf_url.Parse(L"gcf:about:version"));
- EXPECT_TRUE(CanNavigateInFullTabMode(cf_url, &mock));
-
- EXPECT_TRUE(cf_url.Parse(L"gcf:about:bar"));
- EXPECT_TRUE(CanNavigateInFullTabMode(cf_url, &mock));
-
- bool enable_gcf = GetConfigBool(false, kEnableGCFProtocol);
+ struct Zones {
+ const wchar_t* url_prefix;
+ URLZONE zone;
+ } test_zones[] = {
+ { L"http://blah", URLZONE_INTERNET },
+ { L"http://untrusted", URLZONE_UNTRUSTED },
+ { L"about:", URLZONE_TRUSTED },
+ { L"view-source:", URLZONE_TRUSTED },
+ { L"chrome-extension:", URLZONE_TRUSTED },
+ { L"ftp:", URLZONE_UNTRUSTED },
+ { L"file:", URLZONE_LOCAL_MACHINE },
+ { L"sip:", URLZONE_UNTRUSTED },
+ };
- SetConfigBool(kEnableGCFProtocol, false);
+ for (int i = 0; i < arraysize(test_zones); ++i) {
+ const Zones& zone = test_zones[i];
+ EXPECT_CALL(mock, MapUrlToZone(testing::StartsWith(zone.url_prefix),
+ testing::_, testing::_))
+ .WillRepeatedly(testing::DoAll(
+ testing::SetArgumentPointee<1>(zone.zone),
+ testing::Return(S_OK)));
+ }
- EXPECT_TRUE(cf_url.Parse(L"gcf:http://blah"));
- EXPECT_FALSE(CanNavigateInFullTabMode(cf_url, &mock));
+ struct Cases {
+ const char* url;
+ bool is_privileged;
+ bool default_expected;
+ bool unsafe_expected;
+ } test_cases[] = {
+ // Invalid URL
+ { " ", false, false, false },
+ { "foo bar", true, false, false },
+
+ //non-privileged test cases
+ { "http://blah/?attach_external_tab&10&1&0&0&100&100", false, true, true },
+ { "http://untrusted/bar.html", false, false, true },
+ { "http://blah/?attach_external_tab&10&1&0&0&100&100", false, true, true },
+ { "view-source:http://www.google.ca", false, true, true },
+ { "view-source:javascript:alert('foo');", false, false, true },
+ { "about:blank", false, true, true },
+ { "About:Version", false, true, true },
+ { "about:config", false, false, true },
+ { "chrome-extension://aaaaaaaaaaaaaaaaaaa/toolstrip.html", false, false,
+ true },
+ { "ftp://www.google.ca", false, false, true },
+ { "file://www.google.ca", false, false, true },
+ { "file://C:\boot.ini", false, false, true },
+ { "SIP:someone@10.1.2.3", false, false, true },
+
+ //privileged test cases
+ { "http://blah/?attach_external_tab&10&1&0&0&100&100", true, true, true },
+ { "http://untrusted/bar.html", true, false, true },
+ { "http://blah/?attach_external_tab&10&1&0&0&100&100", true, true, true },
+ { "view-source:http://www.google.ca", true, true, true },
+ { "view-source:javascript:alert('foo');", true, false, true },
+ { "about:blank", true, true, true },
+ { "About:Version", true, true, true },
+ { "about:config", true, false, true },
+ { "chrome-extension://aaaaaaaaaaaaaaaaaaa/toolstrip.html", true, true,
+ true },
+ { "ftp://www.google.ca", true, false, true },
+ { "file://www.google.ca", true, false, true },
+ { "file://C:\boot.ini", true, false, true },
+ { "sip:someone@10.1.2.3", false, false, true },
+ };
- SetConfigBool(kEnableGCFProtocol, true);
+ for (int i = 0; i < arraysize(test_cases); ++i) {
+ const Cases& test = test_cases[i];
+ bool actual = CanNavigate(GURL(test.url), &mock, test.is_privileged);
+ EXPECT_EQ(test.default_expected, actual) << "Failure url: " << test.url;
+ }
- EXPECT_TRUE(cf_url.Parse(L"gcf:http://blah"));
- EXPECT_TRUE(CanNavigateInFullTabMode(cf_url, &mock));
+ bool enable_gcf = GetConfigBool(false, kAllowUnsafeURLs);
+ SetConfigBool(kAllowUnsafeURLs, true);
- EXPECT_TRUE(cf_url.Parse(L"gcf:http://untrusted/bar"));
- EXPECT_FALSE(CanNavigateInFullTabMode(cf_url, &mock));
+ for (int i = 0; i < arraysize(test_cases); ++i) {
+ const Cases& test = test_cases[i];
+ bool actual = CanNavigate(GURL(test.url), &mock, test.is_privileged);
+ EXPECT_EQ(test.unsafe_expected, actual) << "Failure url: " << test.url;
+ }
- SetConfigBool(kEnableGCFProtocol, enable_gcf);
+ SetConfigBool(kAllowUnsafeURLs, enable_gcf);
}
TEST(UtilTests, ParseVersionTest) {
diff --git a/chrome_frame/utils.cc b/chrome_frame/utils.cc
index f60f6c0..c2eade6 100644
--- a/chrome_frame/utils.cc
+++ b/chrome_frame/utils.cc
@@ -41,16 +41,16 @@ const wchar_t kContentAttribName[] = L"content";
const wchar_t kXUACompatValue[] = L"x-ua-compatible";
const wchar_t kBodyTag[] = L"body";
const wchar_t kChromeContentPrefix[] = L"chrome=";
+const char kGCFProtocol[] = "gcf";
const wchar_t kChromeProtocolPrefix[] = L"gcf:";
const wchar_t kChromeMimeType[] = L"application/chromepage";
const wchar_t kPatchProtocols[] = L"PatchProtocols";
-const wchar_t kChromeFrameAttachTabPattern[] = L"*?attach_external_tab&*";
static const wchar_t kChromeFrameConfigKey[] =
L"Software\\Google\\ChromeFrame";
static const wchar_t kRenderInGCFUrlList[] = L"RenderInGcfUrls";
static const wchar_t kRenderInHostUrlList[] = L"RenderInHostUrls";
-static const wchar_t kEnableGCFProtocol[] = L"EnableGCFProtocol";
+static const wchar_t kAllowUnsafeURLs[] = L"AllowUnsafeURLs";
static const wchar_t kEnableGCFRendererByDefault[] = L"IsDefaultRenderer";
static const wchar_t kEnableBuggyBhoIntercept[] = L"EnableBuggyBhoIntercept";
@@ -62,7 +62,7 @@ static const wchar_t kChromeFramePersistNPAPIReg[] = L"PersistNPAPIReg";
const wchar_t kChromeFrameOmahaSuffix[] = L"-cf";
const wchar_t kDevChannelName[] = L"-dev";
-const wchar_t kChromeAttachExternalTabPrefix[] = L"?attach_external_tab";
+const char kAttachExternalTabPrefix[] = "attach_external_tab";
// Indicates that we are running in a test environment, where execptions, etc
// are handled by the chrome test crash server.
@@ -856,21 +856,19 @@ bool CheckForCFNavigation(IBrowserService* browser, bool clear_flag) {
return ret;
}
-bool IsValidUrlScheme(const std::wstring& url, bool is_privileged) {
- if (url.empty())
+bool IsValidUrlScheme(const GURL& url, bool is_privileged) {
+ if (url.is_empty())
return false;
- GURL crack_url(url);
-
- if (crack_url.SchemeIs(chrome::kHttpScheme) ||
- crack_url.SchemeIs(chrome::kHttpsScheme) ||
- crack_url.SchemeIs(chrome::kAboutScheme))
+ if (url.SchemeIs(chrome::kHttpScheme) ||
+ url.SchemeIs(chrome::kHttpsScheme) ||
+ url.SchemeIs(chrome::kAboutScheme))
return true;
// Additional checking for view-source. Allow only http and https
// URLs in view source.
- if (crack_url.SchemeIs(chrome::kViewSourceScheme)) {
- GURL sub_url(crack_url.path());
+ if (url.SchemeIs(chrome::kViewSourceScheme)) {
+ GURL sub_url(url.path());
if (sub_url.SchemeIs(chrome::kHttpScheme) ||
sub_url.SchemeIs(chrome::kHttpsScheme))
return true;
@@ -879,8 +877,8 @@ bool IsValidUrlScheme(const std::wstring& url, bool is_privileged) {
}
if (is_privileged &&
- (crack_url.SchemeIs(chrome::kDataScheme) ||
- crack_url.SchemeIs(chrome::kExtensionScheme)))
+ (url.SchemeIs(chrome::kDataScheme) ||
+ url.SchemeIs(chrome::kExtensionScheme)))
return true;
return false;
@@ -1270,49 +1268,34 @@ HRESULT ReadStream(IStream* stream, size_t size, std::string* data) {
return hr;
}
-ChromeFrameUrl::ChromeFrameUrl()
- : is_chrome_protocol_(false),
- attach_to_external_tab_(false),
- cookie_(0),
- disposition_(0) {
+ChromeFrameUrl::ChromeFrameUrl() {
+ Reset();
}
bool ChromeFrameUrl::Parse(const std::wstring& url) {
- bool ret = false;
- if (url.empty())
- return ret;
+ Reset();
+ parsed_url_ = GURL(url);
- url_ = url;
+ if (parsed_url_.is_empty())
+ return false;
- attach_to_external_tab_ = MatchPatternWide(url.c_str(),
- kChromeFrameAttachTabPattern);
- is_chrome_protocol_ = StartsWith(url, kChromeProtocolPrefix, false);
- DCHECK(!(attach_to_external_tab_ && is_chrome_protocol_));
+ is_chrome_protocol_ = parsed_url_.SchemeIs(kGCFProtocol);
if (is_chrome_protocol_) {
- url_.erase(0, lstrlen(kChromeProtocolPrefix));
+ parsed_url_ = GURL(url.c_str() + lstrlen(kChromeProtocolPrefix));
+ return true;
}
- if (attach_to_external_tab_) {
- ret = ParseAttachExternalTabUrl();
- } else {
- ret = true;
- }
- return ret;
+ return ParseAttachExternalTabUrl();
}
bool ChromeFrameUrl::ParseAttachExternalTabUrl() {
- size_t attach_external_tab_start_pos =
- url_.find(kChromeAttachExternalTabPrefix);
- if (attach_external_tab_start_pos == std::wstring::npos) {
- DLOG(ERROR) << "Invalid url:" << url_;
- return false;
+ std::string query = parsed_url_.query();
+ if (!StartsWithASCII(query, kAttachExternalTabPrefix, false)) {
+ return parsed_url_.is_valid();
}
- std::wstring url =
- url_.substr(attach_external_tab_start_pos,
- url_.length() - attach_external_tab_start_pos);
-
- WStringTokenizer tokenizer(url, L"&");
+ attach_to_external_tab_ = true;
+ StringTokenizer tokenizer(query, "&");
// Skip over kChromeAttachExternalTabPrefix
tokenizer.GetNext();
// Read the following items in order.
@@ -1323,79 +1306,86 @@ bool ChromeFrameUrl::ParseAttachExternalTabUrl() {
// 5. dimension.width
// 6. dimension.height.
if (tokenizer.GetNext()) {
- wchar_t* end_ptr = 0;
- cookie_ = _wcstoui64(tokenizer.token().c_str(), &end_ptr, 10);
+ char* end_ptr = 0;
+ cookie_ = _strtoui64(tokenizer.token().c_str(), &end_ptr, 10);
} else {
return false;
}
if (tokenizer.GetNext()) {
- disposition_ = _wtoi(tokenizer.token().c_str());
+ disposition_ = atoi(tokenizer.token().c_str());
} else {
return false;
}
if (tokenizer.GetNext()) {
- dimensions_.set_x(_wtoi(tokenizer.token().c_str()));
+ dimensions_.set_x(atoi(tokenizer.token().c_str()));
} else {
return false;
}
if (tokenizer.GetNext()) {
- dimensions_.set_y(_wtoi(tokenizer.token().c_str()));
+ dimensions_.set_y(atoi(tokenizer.token().c_str()));
} else {
return false;
}
if (tokenizer.GetNext()) {
- dimensions_.set_width(_wtoi(tokenizer.token().c_str()));
+ dimensions_.set_width(atoi(tokenizer.token().c_str()));
} else {
return false;
}
if (tokenizer.GetNext()) {
- dimensions_.set_height(_wtoi(tokenizer.token().c_str()));
+ dimensions_.set_height(atoi(tokenizer.token().c_str()));
} else {
return false;
}
return true;
}
-bool CanNavigateInFullTabMode(const ChromeFrameUrl& cf_url,
- IInternetSecurityManager* security_manager) {
- bool is_privileged = false;
+void ChromeFrameUrl::Reset() {
+ attach_to_external_tab_ = false;
+ is_chrome_protocol_ = false;
+ cookie_ = 0;
+ dimensions_.SetRect(0, 0, 0, 0);
+ disposition_ = 0;
+}
- if (!IsValidUrlScheme(cf_url.url(), is_privileged)) {
- DLOG(WARNING) << __FUNCTION__ << " Disallowing navigation to url: "
- << cf_url.url();
+bool CanNavigate(const GURL& url, IInternetSecurityManager* security_manager,
+ bool is_privileged) {
+ if (!url.is_valid()) {
+ DLOG(ERROR) << "Invalid URL passed to InitiateNavigation: " << url;
return false;
}
- if (security_manager) {
- DWORD zone = URLZONE_INVALID;
- security_manager->MapUrlToZone(cf_url.url().c_str(), &zone, 0);
- if (zone == URLZONE_UNTRUSTED) {
+ // No sanity checks if unsafe URLs are allowed
+ if (GetConfigBool(false, kAllowUnsafeURLs))
+ return true;
+
+ if (!IsValidUrlScheme(url, is_privileged)) {
+ DLOG(WARNING) << __FUNCTION__ << " Disallowing navigation to url: " << url;
+ return false;
+ }
+
+ // Allow only about:blank or about:version
+ if (url.SchemeIs(chrome::kAboutScheme)) {
+ if (!LowerCaseEqualsASCII(url.spec(), chrome::kAboutBlankURL) &&
+ !LowerCaseEqualsASCII(url.spec(), chrome::kAboutVersionURL)) {
DLOG(WARNING) << __FUNCTION__
- << " Disallowing navigation to restricted url: "
- << cf_url.url();
+ << " Disallowing navigation to about url: " << url;
return false;
}
}
- if (cf_url.is_chrome_protocol()) {
- // Allow chrome protocol (gcf:) if -
- // - explicitly enabled using registry
- // - for gcf:attach_external_tab
- // - for gcf:about and gcf:view-source
- GURL crack_url(cf_url.url());
- bool allow_gcf_protocol =
- GetConfigBool(false, kEnableGCFProtocol) ||
- crack_url.SchemeIs(chrome::kAboutScheme) ||
- crack_url.SchemeIs(chrome::kViewSourceScheme);
- if (!allow_gcf_protocol) {
+ // Prevent navigations to URLs in untrusted zone, even in Firefox.
+ if (security_manager) {
+ DWORD zone = URLZONE_INVALID;
+ std::wstring unicode_url = UTF8ToWide(url.spec());
+ security_manager->MapUrlToZone(unicode_url.c_str(), &zone, 0);
+ if (zone == URLZONE_UNTRUSTED) {
DLOG(WARNING) << __FUNCTION__
- << " Disallowing navigation to gcf url: "
- << cf_url.url();
+ << " Disallowing navigation to restricted url: " << url;
return false;
}
}
diff --git a/chrome_frame/utils.h b/chrome_frame/utils.h
index beb7fa1..8640f11 100644
--- a/chrome_frame/utils.h
+++ b/chrome_frame/utils.h
@@ -24,10 +24,11 @@
// utils.h : Various utility functions and classes
extern const wchar_t kChromeContentPrefix[];
+extern const char kGCFProtocol[];
extern const wchar_t kChromeProtocolPrefix[];
extern const wchar_t kChromeFrameHeadlessMode[];
extern const wchar_t kChromeFrameUnpinnedMode[];
-extern const wchar_t kEnableGCFProtocol[];
+extern const wchar_t kAllowUnsafeURLs[];
extern const wchar_t kEnableBuggyBhoIntercept[];
extern const wchar_t kChromeMimeType[];
extern const wchar_t kChromeFrameAttachTabPattern[];
@@ -276,7 +277,7 @@ bool CheckForCFNavigation(IBrowserService* browser, bool clear_flag);
// Returns true if the URL passed in is something which can be handled by
// Chrome. If this function returns false then we should fail the navigation.
// When is_privileged is true, chrome extension URLs will be considered valid.
-bool IsValidUrlScheme(const std::wstring& url, bool is_privileged);
+bool IsValidUrlScheme(const GURL& url, bool is_privileged);
// Returns the raw http headers for the current request given an
// IWinInetHttpInfo pointer.
@@ -503,8 +504,8 @@ class ChromeFrameUrl {
return dimensions_;
}
- const std::wstring& url() const {
- return url_;
+ const GURL& gurl() const {
+ return parsed_url_;
}
private:
@@ -512,19 +513,23 @@ class ChromeFrameUrl {
// suffix portion of the URL which contains the attach_external_tab prefix.
bool ParseAttachExternalTabUrl();
+ // Clear state.
+ void Reset();
+
bool attach_to_external_tab_;
bool is_chrome_protocol_;
- std::wstring url_;
uint64 cookie_;
gfx::Rect dimensions_;
int disposition_;
+
+ GURL parsed_url_;
};
// Returns true if we can navigate to this URL.
// This function checks if the url scheme is valid for navigation within
// chrome and whether it is a restricted URL as per IE settings. In either of
// these cases it returns false.
-bool CanNavigateInFullTabMode(const ChromeFrameUrl& cf_url,
- IInternetSecurityManager* security_manager);
+bool CanNavigate(const GURL& url, IInternetSecurityManager* security_manager,
+ bool is_privileged);
#endif // CHROME_FRAME_UTILS_H_