diff options
author | jcampan@chromium.org <jcampan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-09-24 17:42:42 +0000 |
---|---|---|
committer | jcampan@chromium.org <jcampan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-09-24 17:42:42 +0000 |
commit | 8a3422c9488ce79e305973d29a01811762e35465 (patch) | |
tree | 7fc94cb7aa013f7bb2afaf4100b1a8f45208cc00 | |
parent | 5eb64653873981c7dbf693a9aba7c7da011b14a3 (diff) | |
download | chromium_src-8a3422c9488ce79e305973d29a01811762e35465.zip chromium_src-8a3422c9488ce79e305973d29a01811762e35465.tar.gz chromium_src-8a3422c9488ce79e305973d29a01811762e35465.tar.bz2 |
This CL adds new UI tests for the SSL UI.
Some more info:
SSL UI Tests:
Added new tests for redirects and frames.
Also improved the mixed-content test to exercise the "block mixed-contents" preference and the show info-bar.
Automation:
For the new UI tests, added methods to tab_proxy and browser_proxy. The ones of most interest are GetLastNavigatinTime and WaitForNavigation that ensures we wait for a navigation to occur or have occured when taking actions that asynchronously trigger navigations.
Resource loading:
Added a flag to the response we get when loading a resource that indicates whether that resource was filtered (blocked or altered) by the security peer. We use this flag to notify back the browser when we report a load has been committed.
This is so the SSL manager knows a frame has been filtered (in which case we have no cert info but should not consider that as unsafe).
BUG=2004
Review URL: http://codereview.chromium.org/3165
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@2553 0039d316-1c4b-4281-b951-d872f2087c98
37 files changed, 988 insertions, 123 deletions
diff --git a/base/observer_list.h b/base/observer_list.h index d34e838..52571df 100644 --- a/base/observer_list.h +++ b/base/observer_list.h @@ -86,6 +86,14 @@ class ObserverList { } } + size_t size() const { + return observers_.size(); + } + + ObserverType* GetElementAt(int index) const { + return observers_[index]; + } + // An iterator class that can be used to access the list of observers. See // also the FOREACH_OBSERVER macro defined below. class Iterator { diff --git a/chrome/browser/automation/automation_provider.cc b/chrome/browser/automation/automation_provider.cc index 4c1ed49..8c2da33 100644 --- a/chrome/browser/automation/automation_provider.cc +++ b/chrome/browser/automation/automation_provider.cc @@ -21,11 +21,13 @@ #include "chrome/browser/navigation_entry.h" #include "chrome/browser/printing/print_job.h" #include "chrome/browser/render_view_host.h" +#include "chrome/browser/ssl_manager.h" #include "chrome/browser/ssl_blocking_page.h" #include "chrome/browser/web_contents.h" #include "chrome/browser/views/bookmark_bar_view.h" #include "chrome/browser/views/location_bar_view.h" #include "chrome/common/chrome_paths.h" +#include "chrome/common/pref_service.h" #include "chrome/test/automation/automation_messages.h" #include "net/base/cookie_monster.h" #include "net/url_request/url_request_filter.h" @@ -182,7 +184,6 @@ class NavigationControllerRestoredObserver : public NotificationObserver { DISALLOW_COPY_AND_ASSIGN(NavigationControllerRestoredObserver); }; - class NavigationNotificationObserver : public NotificationObserver { public: NavigationNotificationObserver(NavigationController* controller, @@ -195,6 +196,8 @@ class NavigationNotificationObserver : public NotificationObserver { controller_(controller), navigation_started_(false) { NotificationService* service = NotificationService::current(); + service->AddObserver(this, NOTIFY_NAV_ENTRY_COMMITTED, + Source<NavigationController>(controller_)); service->AddObserver(this, NOTIFY_LOAD_START, Source<NavigationController>(controller_)); service->AddObserver(this, NOTIFY_LOAD_STOP, @@ -222,6 +225,8 @@ class NavigationNotificationObserver : public NotificationObserver { void Unregister() { NotificationService* service = NotificationService::current(); + service->RemoveObserver(this, NOTIFY_NAV_ENTRY_COMMITTED, + Source<NavigationController>(controller_)); service->RemoveObserver(this, NOTIFY_LOAD_START, Source<NavigationController>(controller_)); service->RemoveObserver(this, NOTIFY_LOAD_STOP, @@ -235,7 +240,14 @@ class NavigationNotificationObserver : public NotificationObserver { virtual void Observe(NotificationType type, const NotificationSource& source, const NotificationDetails& details) { - if (type == NOTIFY_LOAD_START) { + // We listen for 2 events to determine when the navigation started because: + // - when this is used by the WaitForNavigation method, we might be invoked + // afer the load has started (but not after the entry was committed, as + // WaitForNavigation compares times of the last navigation). + // - when this is used with a page requiring authentication, we will not get + // a NOTIFY_NAV_ENTRY_COMMITTED until after we authenticate, so we need the + // NOTIFY_LOAD_START. + if (type == NOTIFY_NAV_ENTRY_COMMITTED || type == NOTIFY_LOAD_START) { navigation_started_ = true; } else if (type == NOTIFY_LOAD_STOP) { if (navigation_started_) { @@ -758,6 +770,16 @@ void AutomationProvider::OnMessageReceived(const IPC::Message& message) { HandleFindWindowLocationRequest) IPC_MESSAGE_HANDLER(AutomationMsg_BookmarkBarVisibilityRequest, GetBookmarkBarVisitility) + IPC_MESSAGE_HANDLER(AutomationMsg_GetSSLInfoBarCountRequest, + GetSSLInfoBarCount) + IPC_MESSAGE_HANDLER(AutomationMsg_ClickSSLInfoBarLinkRequest, + ClickSSLInfoBarLink) + IPC_MESSAGE_HANDLER(AutomationMsg_GetLastNavigationTimeRequest, + GetLastNavigationTime) + IPC_MESSAGE_HANDLER(AutomationMsg_WaitForNavigationRequest, + WaitForNavigation) + IPC_MESSAGE_HANDLER(AutomationMsg_SetIntPreferenceRequest, + SetIntPreference) IPC_END_MESSAGE_MAP() } @@ -2294,3 +2316,90 @@ void TestingAutomationProvider::Observe(NotificationType type, void TestingAutomationProvider::OnRemoveProvider() { AutomationProviderList::GetInstance()->RemoveProvider(this); } + +void AutomationProvider::GetSSLInfoBarCount(const IPC::Message& message, + int handle) { + int count = -1; // -1 means error. + if (tab_tracker_->ContainsHandle(handle)) { + NavigationController* nav_controller = tab_tracker_->GetResource(handle); + if (nav_controller) { + count = static_cast<int>(nav_controller->ssl_manager()-> + visible_info_bars_.size()); + } + } + Send(new AutomationMsg_GetSSLInfoBarCountResponse(message.routing_id(), + count)); +} + +void AutomationProvider::ClickSSLInfoBarLink(const IPC::Message& message, + int handle, + int info_bar_index, + bool wait_for_navigation) { + bool success = false; + if (tab_tracker_->ContainsHandle(handle)) { + NavigationController* nav_controller = tab_tracker_->GetResource(handle); + if (nav_controller) { + int count = static_cast<int>(nav_controller->ssl_manager()-> + visible_info_bars_.size()); + if (info_bar_index >= 0 && info_bar_index < count) { + if (wait_for_navigation) { + AddNavigationStatusListener(nav_controller, + new AutomationMsg_ClickSSLInfoBarLinkResponse( + message.routing_id(), true), + new AutomationMsg_ClickSSLInfoBarLinkResponse( + message.routing_id(), true)); + } + SSLManager::SSLInfoBar* info_bar = + nav_controller->ssl_manager()->visible_info_bars_. + GetElementAt(info_bar_index); + info_bar->LinkActivated(NULL, 0); // Parameters are not used. + success = true; + } + } + } + if (!wait_for_navigation || !success) + Send(new AutomationMsg_ClickSSLInfoBarLinkResponse(message.routing_id(), + success)); +} + +void AutomationProvider::GetLastNavigationTime(const IPC::Message& message, + int handle) { + Time time = tab_tracker_->GetLastNavigationTime(handle); + Send(new AutomationMsg_GetLastNavigationTimeResponse(message.routing_id(), + time.ToInternalValue())); +} + +void AutomationProvider::WaitForNavigation(const IPC::Message& message, + int handle, + int64 last_navigation_time) { + NavigationController* controller = NULL; + if (tab_tracker_->ContainsHandle(handle)) + controller = tab_tracker_->GetResource(handle); + + Time time = tab_tracker_->GetLastNavigationTime(handle); + if (time.ToInternalValue() > last_navigation_time || !controller) { + Send(new AutomationMsg_WaitForNavigationResponse(message.routing_id(), + controller != NULL)); + return; + } + + AddNavigationStatusListener(controller, + new AutomationMsg_WaitForNavigationResponse(message.routing_id(), + true), + new AutomationMsg_WaitForNavigationResponse(message.routing_id(), + true)); +} + +void AutomationProvider::SetIntPreference(const IPC::Message& message, + int handle, + std::wstring name, + int value) { + bool success = false; + if (browser_tracker_->ContainsHandle(handle)) { + Browser* browser = browser_tracker_->GetResource(handle); + browser->profile()->GetPrefs()->SetInteger(name.c_str(), value); + success = true; + } + Send(new AutomationMsg_SetIntPreferenceResponse(message.routing_id(), + success)); +} diff --git a/chrome/browser/automation/automation_provider.h b/chrome/browser/automation/automation_provider.h index 674565c..d67615f 100644 --- a/chrome/browser/automation/automation_provider.h +++ b/chrome/browser/automation/automation_provider.h @@ -294,7 +294,7 @@ class AutomationProvider : public base::RefCounted<AutomationProvider>, // Retrieves if a query to an autocomplete provider is in progress. void AutocompleteEditIsQueryInProgress(const IPC::Message& message, - int autocomplete_edit_handle); + int autocomplete_edit_handle); // Retrieves the individual autocomplete matches displayed by the popup. void AutocompleteEditGetMatches(const IPC::Message& message, @@ -304,6 +304,32 @@ class AutomationProvider : public base::RefCounted<AutomationProvider>, void OnMessageFromExternalHost(int handle, const std::string& target, const std::string& message); + // Retrieves the number of SSL related info-bars currently showing in |count|. + void GetSSLInfoBarCount(const IPC::Message& message, int handle); + + // Causes a click on the link of the info-bar at |info_bar_index|. If + // |wait_for_navigation| is true, it sends the reply after a navigation has + // occurred. + void ClickSSLInfoBarLink(const IPC::Message& message, + int handle, + int info_bar_index, + bool wait_for_navigation); + + // Retrieves the last time a navigation occurred for the tab. + void GetLastNavigationTime(const IPC::Message& message, int handle); + + // Waits for a new navigation in the tab if none has happened since + // |last_navigation_time|. + void WaitForNavigation(const IPC::Message& message, + int handle, + int64 last_navigation_time); + + // Sets the int value for preference with name |name|. + void SetIntPreference(const IPC::Message& message, + int handle, + std::wstring name, + int value); + // Convert a tab handle into a WebContents. If |tab| is non-NULL a pointer // to the tab is also returned. Returns NULL in case of failure or if the tab // is not of the WebContents type. diff --git a/chrome/browser/automation/automation_tab_tracker.h b/chrome/browser/automation/automation_tab_tracker.h index 5cda520..bb9ac24 100644 --- a/chrome/browser/automation/automation_tab_tracker.h +++ b/chrome/browser/automation/automation_tab_tracker.h @@ -28,6 +28,11 @@ public: NotificationService::current()->AddObserver( this, NOTIFY_EXTERNAL_TAB_CLOSED, Source<NavigationController>(resource)); + // We also want to know about navigations so we can keep track of the last + // navigation time. + NotificationService::current()->AddObserver( + this, NOTIFY_NAV_ENTRY_COMMITTED, + Source<NavigationController>(resource)); } virtual void RemoveObserver(NavigationController* resource) { @@ -36,7 +41,49 @@ public: NotificationService::current()->RemoveObserver( this, NOTIFY_EXTERNAL_TAB_CLOSED, Source<NavigationController>(resource)); + NotificationService::current()->RemoveObserver( + this, NOTIFY_NAV_ENTRY_COMMITTED, + Source<NavigationController>(resource)); + } + + virtual void Observe(NotificationType type, + const NotificationSource& source, + const NotificationDetails& details) { + switch (type) { + case NOTIFY_NAV_ENTRY_COMMITTED: + last_navigation_times_[Source<NavigationController>(source).ptr()] = + Time::Now(); + return; + case NOTIFY_EXTERNAL_TAB_CLOSED: + case NOTIFY_TAB_CLOSING: + std::map<NavigationController*, Time>::iterator iter = + last_navigation_times_.find( + Source<NavigationController>(source).ptr()); + if (iter != last_navigation_times_.end()) + last_navigation_times_.erase(iter); + break; + } + AutomationResourceTracker::Observe(type, source, details); + } + + Time GetLastNavigationTime(int handle) { + if (ContainsHandle(handle)) { + NavigationController* controller = GetResource(handle); + if (controller) { + std::map<NavigationController*, Time>::const_iterator iter = + last_navigation_times_.find(controller); + if (iter != last_navigation_times_.end()) + return iter->second; + } + } + return Time(); } + + private: + // Last time a navigation occurred. + std::map<NavigationController*, Time> last_navigation_times_; + + DISALLOW_COPY_AND_ASSIGN(AutomationTabTracker); }; #endif // CHROME_BROWSER_AUTOMATION_AUTOMATION_TAB_TRACKER_H__ diff --git a/chrome/browser/navigation_controller.cc b/chrome/browser/navigation_controller.cc index ae5a9b8..91c1fb4 100644 --- a/chrome/browser/navigation_controller.cc +++ b/chrome/browser/navigation_controller.cc @@ -561,6 +561,7 @@ bool NavigationController::RendererDidNavigate( details->is_main_frame = PageTransition::IsMainFrame(params.transition); details->is_interstitial = is_interstitial; details->serialized_security_info = params.security_info; + details->is_content_filtered = params.is_content_filtered; NotifyNavigationEntryCommitted(details); // It is now a safe time to schedule collection for any tab contents of a diff --git a/chrome/browser/navigation_controller.h b/chrome/browser/navigation_controller.h index 0e1b5919..7d99876 100644 --- a/chrome/browser/navigation_controller.h +++ b/chrome/browser/navigation_controller.h @@ -79,6 +79,10 @@ class NavigationController { // won't care about interstitial loads. bool is_interstitial; + // Whether the content of this frame has been altered/blocked because it was + // unsafe. + bool is_content_filtered; + // When the committed load is a web page from the renderer, this string // specifies the security state if the page is secure. // See ViewHostMsg_FrameNavigate_Params.security_info, where it comes from. diff --git a/chrome/browser/provisional_load_details.cc b/chrome/browser/provisional_load_details.cc index 274ecf8..f7a9f89 100644 --- a/chrome/browser/provisional_load_details.cc +++ b/chrome/browser/provisional_load_details.cc @@ -11,12 +11,14 @@ ProvisionalLoadDetails::ProvisionalLoadDetails(bool is_main_frame, bool is_interstitial_page, bool is_in_page_navigation, const GURL& url, - const std::string& security_info) + const std::string& security_info, + bool is_content_filtered) : is_main_frame_(is_main_frame), is_interstitial_page_(is_interstitial_page), is_in_page_navigation_(is_in_page_navigation), url_(url), - error_code_(net::OK) { + error_code_(net::OK), + is_content_filtered_(is_content_filtered) { SSLManager::DeserializeSecurityInfo(security_info, &ssl_cert_id_, &ssl_cert_status_, diff --git a/chrome/browser/provisional_load_details.h b/chrome/browser/provisional_load_details.h index 2c342c1..9f63acb 100644 --- a/chrome/browser/provisional_load_details.h +++ b/chrome/browser/provisional_load_details.h @@ -23,7 +23,8 @@ class ProvisionalLoadDetails { bool interstitial_page, bool in_page_navigation, const GURL& url, - const std::string& security_info); + const std::string& security_info, + bool is_filtered); virtual ~ProvisionalLoadDetails() { } void set_error_code(int error_code) { error_code_ = error_code; }; @@ -43,6 +44,8 @@ class ProvisionalLoadDetails { int ssl_security_bits() const { return ssl_security_bits_; } + bool is_content_filtered() const { return is_content_filtered_; } + private: int error_code_; GURL url_; @@ -52,6 +55,7 @@ class ProvisionalLoadDetails { int ssl_cert_id_; int ssl_cert_status_; int ssl_security_bits_; + bool is_content_filtered_; DISALLOW_EVIL_CONSTRUCTORS(ProvisionalLoadDetails); }; diff --git a/chrome/browser/ssl_manager.cc b/chrome/browser/ssl_manager.cc index 0d03c3e..94bc42e 100644 --- a/chrome/browser/ssl_manager.cc +++ b/chrome/browser/ssl_manager.cc @@ -35,40 +35,10 @@ #include "webkit/glue/resource_type.h" #include "generated_resources.h" -//////////////////////////////////////////////////////////////////////////////// -// SSLInfoBar -// -// An info bar with a message and an optional link that runs a task when -// clicked. - -class SSLInfoBar : public InfoBarItemView, - public ChromeViews::LinkController { - public: - SSLInfoBar::SSLInfoBar(SSLManager* manager, - const std::wstring& message, - const std::wstring& link_text, - Task* task); - - virtual SSLInfoBar::~SSLInfoBar(); - - const std::wstring GetMessageText() const; - - // ChromeViews::LinkController method. - virtual void LinkActivated(ChromeViews::Link* source, int event_flags); - - private: - ChromeViews::Label* label_; - ChromeViews::Link* link_; - SSLManager* manager_; - scoped_ptr<Task> task_; - - DISALLOW_COPY_AND_ASSIGN(SSLInfoBar); -}; - -SSLInfoBar::SSLInfoBar(SSLManager* manager, - const std::wstring& message, - const std::wstring& link_text, - Task* task) +SSLManager::SSLInfoBar::SSLInfoBar(SSLManager* manager, + const std::wstring& message, + const std::wstring& link_text, + Task* task) : label_(NULL), link_(NULL), manager_(manager), @@ -94,19 +64,20 @@ SSLInfoBar::SSLInfoBar(SSLManager* manager, DCHECK(manager); } -SSLInfoBar::~SSLInfoBar() { +SSLManager::SSLInfoBar::~SSLInfoBar() { // Notify our manager that we no longer exist. manager_->OnInfoBarClose(this); } -const std::wstring SSLInfoBar::GetMessageText() const { +const std::wstring SSLManager::SSLInfoBar::GetMessageText() const { if (!label_) return std::wstring(); return label_->GetText(); } -void SSLInfoBar::LinkActivated(ChromeViews::Link* source, int event_flags) { +void SSLManager::SSLInfoBar::LinkActivated(ChromeViews::Link* source, + int event_flags) { if (task_.get()) { task_->Run(); task_.reset(); // Ensures we won't run the task again. @@ -643,10 +614,27 @@ void SSLManager::DidCommitProvisionalLoad( // An HTTPS response may not have a certificate for some reason. When that // happens, use the unauthenticated (HTTP) rather than the authentication // broken security style so that we can detect this error condition. - if (net::IsCertStatusError(ssl_cert_status)) + if (net::IsCertStatusError(ssl_cert_status)) { changed |= SetMaxSecurityStyle(SECURITY_STYLE_AUTHENTICATION_BROKEN); - else if (details->entry->url().SchemeIsSecure() && !ssl_cert_id) - changed |= SetMaxSecurityStyle(SECURITY_STYLE_UNAUTHENTICATED); + if (!details->is_main_frame && + !details->entry->ssl().has_unsafe_content()) { + details->entry->ssl().set_has_unsafe_content(); + changed = true; + } + } else if (details->entry->url().SchemeIsSecure() && !ssl_cert_id) { + if (details->is_main_frame) { + changed |= SetMaxSecurityStyle(SECURITY_STYLE_UNAUTHENTICATED); + } else { + // If the frame has been blocked we keep our security style as + // authenticated in that case as nothing insecure is actually showing or + // loaded. + if (!details->is_content_filtered && + !details->entry->ssl().has_mixed_content()) { + details->entry->ssl().set_has_mixed_content(); + changed = true; + } + } + } if (changed) { // Only send the notification when something actually changed. diff --git a/chrome/browser/ssl_manager.h b/chrome/browser/ssl_manager.h index f0409b7..a5f466f 100644 --- a/chrome/browser/ssl_manager.h +++ b/chrome/browser/ssl_manager.h @@ -18,6 +18,7 @@ #include "chrome/common/notification_registrar.h" #include "chrome/common/notification_service.h" #include "chrome/common/render_messages.h" +#include "chrome/views/link.h" #include "googleurl/src/gurl.h" #include "net/base/net_errors.h" #include "net/base/ssl_info.h" @@ -25,6 +26,7 @@ #include "webkit/glue/console_message_level.h" #include "webkit/glue/resource_type.h" +class AutomationProvider; class InfoBarItemView; class NavigationEntry; class LoadFromMemoryCacheDetails; @@ -34,7 +36,6 @@ class PrefService; class ResourceRedirectDetails; class ResourceRequestDetails; class SSLErrorInfo; -class SSLInfoBar; class TabContents; class Task; class URLRequest; @@ -261,6 +262,32 @@ class SSLManager : public NotificationObserver { virtual SecurityStyle GetDefaultStyle(const GURL& url) = 0; }; + // An info bar with a message and an optional link that runs a task when + // clicked. + class SSLInfoBar : public InfoBarItemView, + public ChromeViews::LinkController { + public: + SSLInfoBar(SSLManager* manager, + const std::wstring& message, + const std::wstring& link_text, + Task* task); + + virtual ~SSLInfoBar(); + + const std::wstring GetMessageText() const; + + // ChromeViews::LinkController method. + virtual void LinkActivated(ChromeViews::Link* source, int event_flags); + + private: + ChromeViews::Label* label_; + ChromeViews::Link* link_; + SSLManager* manager_; + scoped_ptr<Task> task_; + + DISALLOW_COPY_AND_ASSIGN(SSLInfoBar); + }; + static void RegisterUserPrefs(PrefService* prefs); // Construct an SSLManager for the specified tab. @@ -400,6 +427,9 @@ class SSLManager : public NotificationObserver { std::wstring* ca_name); private: + // The AutomationProvider needs to access the InfoBars. + friend class AutomationProvider; + // SSLMessageInfo contains the information necessary for displaying a message // in an info-bar. struct SSLMessageInfo { diff --git a/chrome/browser/ssl_policy.cc b/chrome/browser/ssl_policy.cc index d75b895..a93b31d 100644 --- a/chrome/browser/ssl_policy.cc +++ b/chrome/browser/ssl_policy.cc @@ -318,7 +318,21 @@ class DefaultPolicy : public SSLPolicy { mixed_content_handler->StartRequest(filter_policy); NavigationEntry* entry = navigation_controller->GetActiveEntry(); - entry->ssl().set_has_mixed_content(); + // Even though we are loading the mixed-content resource, it will not be + // included in the page when we set the policy to FILTER_ALL or + // FILTER_ALL_EXCEPT_IMAGES (only images and they are stamped with warning + // icons), so we don't set the mixed-content mode in these cases. + if (filter_policy == FilterPolicy::DONT_FILTER) + entry->ssl().set_has_mixed_content(); + + // Print a message indicating the mixed-contents resource in the console. + const std::wstring& msg = l10n_util::GetStringF( + IDS_MIXED_CONTENT_LOG_MESSAGE, + UTF8ToWide(entry->url().spec()), + UTF8ToWide(mixed_content_handler->request_url().spec())); + mixed_content_handler->manager()-> + AddMessageToConsole(msg, MESSAGE_LEVEL_WARNING); + NotificationService::current()->Notify( NOTIFY_SSL_STATE_CHANGED, Source<NavigationController>(navigation_controller), @@ -414,25 +428,6 @@ void SSLPolicy::OnRequestStarted(SSLManager* manager, const GURL& url, } } - // Note that when navigating to an inner-frame, we get this notification - // before the new navigation entry is created. For now we just copy the - // mixed/unsafe content state from the old entry to the new one. It is OK - // to set the state on the wrong entry, as if we navigate back to it, its - // state will be reset. - - // Now check for mixed content. - if (entry->url().SchemeIsSecure() && !url.SchemeIsSecure()) { - if (!ssl.has_mixed_content()) { - changed = true; - ssl.set_has_mixed_content(); - } - const std::wstring& msg = l10n_util::GetStringF( - IDS_MIXED_CONTENT_LOG_MESSAGE, - UTF8ToWide(entry->url().spec()), - UTF8ToWide(url.spec())); - manager->AddMessageToConsole(msg, MESSAGE_LEVEL_WARNING); - } - if (changed) { // Only send the notification when something actually changed. NotificationService::current()->Notify( diff --git a/chrome/browser/ssl_uitest.cc b/chrome/browser/ssl_uitest.cc index f2bcdef..4446a02 100644 --- a/chrome/browser/ssl_uitest.cc +++ b/chrome/browser/ssl_uitest.cc @@ -7,6 +7,7 @@ #include <string> +#include "chrome/common/pref_names.h" #include "chrome/test/automation/browser_proxy.h" #include "chrome/test/automation/tab_proxy.h" #include "chrome/test/ui/ui_test.h" @@ -206,6 +207,8 @@ TEST_F(SSLUITest, TestMixedContents) { kDocRoot, GetOKCertPath()); TestServer http_server(kDocRoot); + // Load a page with mixed-content, the default behavior is to show the mixed + // content. scoped_ptr<TabProxy> tab(GetActiveTabProxy()); NavigateTab(tab.get(), https_server.TestServerPageW(L"files/ssl/page_with_mixed_contents.html")); @@ -222,10 +225,54 @@ TEST_F(SSLUITest, TestMixedContents) { EXPECT_EQ(0, cert_status & net::CERT_STATUS_ALL_ERRORS); // No errors expected. EXPECT_EQ(NavigationEntry::SSLStatus::MIXED_CONTENT, mixed_content_state); -} + // Now select the block mixed-content pref and reload the page. + scoped_ptr<BrowserProxy> browser_proxy(automation()->GetBrowserWindow(0)); + EXPECT_TRUE(browser_proxy.get()); + EXPECT_TRUE(browser_proxy->SetIntPreference(prefs::kMixedContentFiltering, + FilterPolicy::FILTER_ALL)); + EXPECT_TRUE(tab->Reload()); + + // The image should be filtered. + int img_width; + EXPECT_TRUE(tab->ExecuteAndExtractInt(L"", + L"javascript:void(window.domAutomationController)" + L".send(ImageWidth());", + &img_width)); + // In order to check that the image was not loaded, we check its width. + // The actual image (Google logo) is 114 pixels wide, we assume the broken + // image is less than 100. + EXPECT_GT(100, img_width); + + // The state should be OK since we are not showing the resource. + EXPECT_TRUE(tab->GetSecurityState(&security_style, &cert_status, + &mixed_content_state)); + EXPECT_EQ(SECURITY_STYLE_AUTHENTICATED, security_style); + EXPECT_EQ(0, cert_status & net::CERT_STATUS_ALL_ERRORS); + EXPECT_EQ(NavigationEntry::SSLStatus::NORMAL_CONTENT, mixed_content_state); + + // There should be one info-bar to show the mixed-content. + int info_bar_count = 0; + EXPECT_TRUE(tab->GetSSLInfoBarCount(&info_bar_count)); + EXPECT_EQ(1, info_bar_count); + + // Activate the link on the info-bar to show the mixed-content. + EXPECT_TRUE(tab->ClickSSLInfoBarLink(0, true)); -/* TODO(jcampan) bug 2004: fix this test. + // The image should show now. + EXPECT_TRUE(tab->ExecuteAndExtractInt(L"", + L"javascript:void(window.domAutomationController)" + L".send(ImageWidth());", + &img_width)); + EXPECT_LT(100, img_width); + + // And our status should be mixed-content. + EXPECT_TRUE(tab->GetSecurityState(&security_style, &cert_status, + &mixed_content_state)); + EXPECT_EQ(SECURITY_STYLE_AUTHENTICATED, security_style); + EXPECT_EQ(0, cert_status & net::CERT_STATUS_ALL_ERRORS); + EXPECT_EQ(NavigationEntry::SSLStatus::MIXED_CONTENT, mixed_content_state); +} // Visits a page with unsafe content and make sure that: // - frames content is replaced with warning @@ -248,10 +295,10 @@ TEST_F(SSLUITest, TestUnsafeContents) { int cert_status; int mixed_content_state; // When the bad content is filtered, the state is expected to be - // unauthenticated. + // authenticated. EXPECT_TRUE(tab->GetSecurityState(&security_style, &cert_status, &mixed_content_state)); - EXPECT_EQ(SECURITY_STYLE_UNAUTHENTICATED, security_style); + EXPECT_EQ(SECURITY_STYLE_AUTHENTICATED, security_style); EXPECT_EQ(0, cert_status & net::CERT_STATUS_ALL_ERRORS); // No errors expected. EXPECT_EQ(NavigationEntry::SSLStatus::NORMAL_CONTENT, mixed_content_state); @@ -271,7 +318,7 @@ TEST_F(SSLUITest, TestUnsafeContents) { L".send(ImageWidth());", &img_width)); // In order to check that the image was not loaded, we check its width. - // The actual image (Google logo is 114 pixels wide), we assume the broken + // The actual image (Google logo) is 114 pixels wide, we assume the broken // image is less than 100. EXPECT_GT(100, img_width); @@ -282,7 +329,6 @@ TEST_F(SSLUITest, TestUnsafeContents) { &js_result)); EXPECT_FALSE(js_result); } -*/ // Visits a page with mixed content loaded by JS (after the initial page load). TEST_F(SSLUITest, TestMixedContentsLoadedFromJS) { @@ -502,32 +548,395 @@ TEST_F(SSLUITest, DISABLED_TestCloseTabWithUnsafePopup) { tab->Close(); } -// TODO (jcampan): more tests to do below. - // Visit a page over bad https that is a redirect to a page with good https. +TEST_F(SSLUITest, TestRedirectBadToGoodHTTPS) { + HTTPSTestServer good_https_server(kHostName, kOKHTTPSPort, + kDocRoot, GetOKCertPath()); + HTTPSTestServer bad_https_server(kHostName, kBadHTTPSPort, + kDocRoot, GetExpiredCertPath()); + + scoped_ptr<TabProxy> tab(GetActiveTabProxy()); + GURL url1 = bad_https_server.TestServerPageW(L"server-redirect?"); + GURL url2 = good_https_server.TestServerPageW(L"files/ssl/google.html"); + NavigateTab(tab.get(), GURL(url1.spec() + url2.spec())); + + NavigationEntry::PageType page_type; + EXPECT_TRUE(tab->GetPageType(&page_type)); + EXPECT_EQ(page_type, NavigationEntry::INTERSTITIAL_PAGE); + + SecurityStyle security_style; + int cert_status; + int mixed_content_state; + EXPECT_TRUE(tab->GetSecurityState(&security_style, &cert_status, + &mixed_content_state)); + EXPECT_EQ(SECURITY_STYLE_AUTHENTICATION_BROKEN, security_style); + EXPECT_EQ(net::CERT_STATUS_DATE_INVALID, cert_status); + EXPECT_EQ(NavigationEntry::SSLStatus::NORMAL_CONTENT, mixed_content_state); + + EXPECT_TRUE(tab->TakeActionOnSSLBlockingPage(true)); + // We have been redirected to the good page. + EXPECT_TRUE(tab->GetSecurityState(&security_style, &cert_status, + &mixed_content_state)); + EXPECT_EQ(SECURITY_STYLE_AUTHENTICATED, security_style); + EXPECT_EQ(0, + cert_status & net::CERT_STATUS_ALL_ERRORS); // No errors expected. + EXPECT_EQ(NavigationEntry::SSLStatus::NORMAL_CONTENT, mixed_content_state); +} // Visit a page over good https that is a redirect to a page with bad https. +TEST_F(SSLUITest, TestRedirectGoodToBadHTTPS) { + HTTPSTestServer good_https_server(kHostName, kOKHTTPSPort, + kDocRoot, GetOKCertPath()); + HTTPSTestServer bad_https_server(kHostName, kBadHTTPSPort, + kDocRoot, GetExpiredCertPath()); + + scoped_ptr<TabProxy> tab(GetActiveTabProxy()); + GURL url1 = good_https_server.TestServerPageW(L"server-redirect?"); + GURL url2 = bad_https_server.TestServerPageW(L"files/ssl/google.html"); + NavigateTab(tab.get(), GURL(url1.spec() + url2.spec())); + + NavigationEntry::PageType page_type; + EXPECT_TRUE(tab->GetPageType(&page_type)); + EXPECT_EQ(page_type, NavigationEntry::INTERSTITIAL_PAGE); + + EXPECT_TRUE(tab->TakeActionOnSSLBlockingPage(true)); + + SecurityStyle security_style; + int cert_status; + int mixed_content_state; + EXPECT_TRUE(tab->GetSecurityState(&security_style, &cert_status, + &mixed_content_state)); + EXPECT_EQ(SECURITY_STYLE_AUTHENTICATION_BROKEN, security_style); + EXPECT_EQ(net::CERT_STATUS_DATE_INVALID, + cert_status & net::CERT_STATUS_ALL_ERRORS); + EXPECT_EQ(NavigationEntry::SSLStatus::NORMAL_CONTENT, mixed_content_state); +} // Visit a page over http that is a redirect to a page with https (good and // bad). +TEST_F(SSLUITest, TestRedirectHTTPToHTTPS) { + TestServer http_server(kDocRoot); + HTTPSTestServer good_https_server(kHostName, kOKHTTPSPort, + kDocRoot, GetOKCertPath()); + HTTPSTestServer bad_https_server(kHostName, kBadHTTPSPort, + kDocRoot, GetExpiredCertPath()); -// Visit a page over https that is a redirect to a page with http. + // HTTP redirects to good HTTPS. + scoped_ptr<TabProxy> tab(GetActiveTabProxy()); + GURL http_url = http_server.TestServerPageW(L"server-redirect?"); + GURL good_https_url = + good_https_server.TestServerPageW(L"files/ssl/google.html"); + NavigateTab(tab.get(), GURL(http_url.spec() + good_https_url.spec())); -// Visit a page over https that contains a frame with a redirect. + SecurityStyle security_style; + int cert_status; + int mixed_content_state; + EXPECT_TRUE(tab->GetSecurityState(&security_style, &cert_status, + &mixed_content_state)); + EXPECT_EQ(SECURITY_STYLE_AUTHENTICATED, security_style); + EXPECT_EQ(0, cert_status & net::CERT_STATUS_ALL_ERRORS); + EXPECT_EQ(NavigationEntry::SSLStatus::NORMAL_CONTENT, mixed_content_state); + + // HTTP redirects to bad HTTPS. + GURL bad_https_url = + bad_https_server.TestServerPageW(L"files/ssl/google.html"); + NavigateTab(tab.get(), GURL(http_url.spec() + bad_https_url.spec())); + + NavigationEntry::PageType page_type; + EXPECT_TRUE(tab->GetPageType(&page_type)); + EXPECT_EQ(page_type, NavigationEntry::INTERSTITIAL_PAGE); + + // Continue on the interstitial. + EXPECT_TRUE(tab->TakeActionOnSSLBlockingPage(true)); + + EXPECT_TRUE(tab->GetSecurityState(&security_style, &cert_status, + &mixed_content_state)); + EXPECT_EQ(SECURITY_STYLE_AUTHENTICATION_BROKEN, security_style); + EXPECT_EQ(net::CERT_STATUS_DATE_INVALID, + cert_status & net::CERT_STATUS_ALL_ERRORS); + EXPECT_EQ(NavigationEntry::SSLStatus::NORMAL_CONTENT, mixed_content_state); +} + +// Visit a page over https that is a redirect to a page with http (to make sure +// we don't keep the secure state). +TEST_F(SSLUITest, TestRedirectHTTPSToHTTP) { + TestServer http_server(kDocRoot); + HTTPSTestServer https_server(kHostName, kOKHTTPSPort, + kDocRoot, GetOKCertPath()); + + scoped_ptr<TabProxy> tab(GetActiveTabProxy()); + GURL https_url = https_server.TestServerPageW(L"server-redirect?"); + GURL http_url = http_server.TestServerPageW(L"files/ssl/google.html"); + NavigateTab(tab.get(), GURL(https_url.spec() + http_url.spec())); + + SecurityStyle security_style; + int cert_status; + int mixed_content_state; + EXPECT_TRUE(tab->GetSecurityState(&security_style, &cert_status, + &mixed_content_state)); + EXPECT_EQ(SECURITY_STYLE_UNAUTHENTICATED, security_style); + EXPECT_EQ(0, cert_status & net::CERT_STATUS_ALL_ERRORS); + EXPECT_EQ(NavigationEntry::SSLStatus::NORMAL_CONTENT, mixed_content_state); +} // Visits a page to which we could not connect (bad port) over http and https +// and make sure the security style is correct. +TEST_F(SSLUITest, TestConnectToBadPort) { + scoped_ptr<TabProxy> tab(GetActiveTabProxy()); -// XMLHttpRequest mixed in synchronous mode. + GURL http_url("http://localhost:17"); + NavigateTab(tab.get(), http_url); -// XMLHttpRequest mixed in asynchronous mode. + SecurityStyle security_style; + int cert_status; + int mixed_content_state; + EXPECT_TRUE(tab->GetSecurityState(&security_style, &cert_status, + &mixed_content_state)); + EXPECT_EQ(SECURITY_STYLE_UNAUTHENTICATED, security_style); + EXPECT_EQ(0, cert_status & net::CERT_STATUS_ALL_ERRORS); + EXPECT_EQ(NavigationEntry::SSLStatus::NORMAL_CONTENT, mixed_content_state); -// XMLHttpRequest over bad ssl in synchronous mode. + // Same thing over HTTPS. + GURL https_url("https://localhost:17"); + NavigateTab(tab.get(), https_url); -// XMLHttpRequest over OK ssl in synchronous mode. + EXPECT_TRUE(tab->GetSecurityState(&security_style, &cert_status, + &mixed_content_state)); + EXPECT_EQ(SECURITY_STYLE_UNAUTHENTICATED, security_style); + EXPECT_EQ(0, cert_status & net::CERT_STATUS_ALL_ERRORS); + EXPECT_EQ(NavigationEntry::SSLStatus::NORMAL_CONTENT, mixed_content_state); +} // // Frame navigation // -// Navigate to broken frame and back. +// From a good HTTPS top frame: +// - navigate to an OK HTTPS frame +// - navigate to a bad HTTPS (expect unsafe content and filtered frame), then +// back +// - navigate to HTTP (expect mixed content), then back +TEST_F(SSLUITest, TestGoodFrameNavigation) { + TestServer http_server(kDocRoot); + HTTPSTestServer good_https_server(kHostName, kOKHTTPSPort, + kDocRoot, GetOKCertPath()); + HTTPSTestServer bad_https_server(kHostName, kBadHTTPSPort, + kDocRoot, GetExpiredCertPath()); + + scoped_ptr<TabProxy> tab(GetActiveTabProxy()); + NavigateTab(tab.get(), + good_https_server.TestServerPageW(L"files/ssl/top_frame.html")); + + SecurityStyle security_style; + int cert_status; + int mixed_content_state; + EXPECT_TRUE(tab->GetSecurityState(&security_style, &cert_status, + &mixed_content_state)); + EXPECT_EQ(SECURITY_STYLE_AUTHENTICATED, security_style); + EXPECT_EQ(0, cert_status & net::CERT_STATUS_ALL_ERRORS); + EXPECT_EQ(NavigationEntry::SSLStatus::NORMAL_CONTENT, mixed_content_state); + + bool success = false; + // Now navigate inside the frame. + int64 last_nav_time = 0; + EXPECT_TRUE(tab->GetLastNavigationTime(&last_nav_time)); + EXPECT_TRUE(tab->ExecuteAndExtractBool(L"", + L"javascript:void(window.domAutomationController)" + L".send(clickLink('goodHTTPSLink'));", + &success)); + EXPECT_TRUE(success); + EXPECT_TRUE(tab->WaitForNavigation(last_nav_time)); + + // We should still be fine. + EXPECT_TRUE(tab->GetSecurityState(&security_style, &cert_status, + &mixed_content_state)); + EXPECT_EQ(SECURITY_STYLE_AUTHENTICATED, security_style); + EXPECT_EQ(0, cert_status & net::CERT_STATUS_ALL_ERRORS); + EXPECT_EQ(NavigationEntry::SSLStatus::NORMAL_CONTENT, mixed_content_state); + + // Now let's hit a bad page. + EXPECT_TRUE(tab->GetLastNavigationTime(&last_nav_time)); + EXPECT_TRUE(tab->ExecuteAndExtractBool(L"", + L"javascript:void(window.domAutomationController)" + L".send(clickLink('badHTTPSLink'));", + &success)); + EXPECT_TRUE(success); + EXPECT_TRUE(tab->WaitForNavigation(last_nav_time)); + + // The security style should still be secure. + EXPECT_TRUE(tab->GetSecurityState(&security_style, &cert_status, + &mixed_content_state)); + EXPECT_EQ(SECURITY_STYLE_AUTHENTICATED, security_style); + EXPECT_EQ(0, cert_status & net::CERT_STATUS_ALL_ERRORS); + EXPECT_EQ(NavigationEntry::SSLStatus::NORMAL_CONTENT, mixed_content_state); + + // And the frame should be blocked. + bool is_content_evil = true; + std::wstring content_frame_xpath(L"html/frameset/frame[2]"); + std::wstring is_frame_evil_js( + L"javascript:void(window.domAutomationController)" + L".send(document.getElementById('evilDiv') != null);"); + EXPECT_TRUE(tab->ExecuteAndExtractBool(content_frame_xpath, + is_frame_evil_js, + &is_content_evil)); + EXPECT_FALSE(is_content_evil); + + // Now go back, our state should return to OK. + EXPECT_TRUE(tab->GoBack()); + EXPECT_TRUE(tab->GetSecurityState(&security_style, &cert_status, + &mixed_content_state)); + EXPECT_EQ(SECURITY_STYLE_AUTHENTICATED, security_style); + EXPECT_EQ(0, cert_status & net::CERT_STATUS_ALL_ERRORS); + EXPECT_EQ(NavigationEntry::SSLStatus::NORMAL_CONTENT, mixed_content_state); + + // Navigate to a page served over HTTP. + EXPECT_TRUE(tab->GetLastNavigationTime(&last_nav_time)); + EXPECT_TRUE(tab->ExecuteAndExtractBool(L"", + L"javascript:void(window.domAutomationController)" + L".send(clickLink('HTTPLink'));", + &success)); + EXPECT_TRUE(success); + EXPECT_TRUE(tab->WaitForNavigation(last_nav_time)); + + // Our state should be mixed-content. + // Status should be "contains bad contents". + EXPECT_TRUE(tab->GetSecurityState(&security_style, &cert_status, + &mixed_content_state)); + EXPECT_EQ(SECURITY_STYLE_AUTHENTICATED, security_style); + EXPECT_EQ(0, cert_status & net::CERT_STATUS_ALL_ERRORS); + EXPECT_EQ(NavigationEntry::SSLStatus::MIXED_CONTENT, mixed_content_state); + + // Go back, our state should be back to OK. + EXPECT_TRUE(tab->GoBack()); + EXPECT_TRUE(tab->GetSecurityState(&security_style, &cert_status, + &mixed_content_state)); + EXPECT_EQ(SECURITY_STYLE_AUTHENTICATED, security_style); + EXPECT_EQ(0, cert_status & net::CERT_STATUS_ALL_ERRORS); + EXPECT_EQ(NavigationEntry::SSLStatus::NORMAL_CONTENT, mixed_content_state); +} + +// From a bad HTTPS top frame: +// - navigate to an OK HTTPS frame (expected to be still authentication broken). +TEST_F(SSLUITest, TestBadFrameNavigation) { + HTTPSTestServer good_https_server(kHostName, kOKHTTPSPort, + kDocRoot, GetOKCertPath()); + HTTPSTestServer bad_https_server(kHostName, kBadHTTPSPort, + kDocRoot, GetExpiredCertPath()); + + scoped_ptr<TabProxy> tab(GetActiveTabProxy()); + NavigateTab(tab.get(), + bad_https_server.TestServerPageW(L"files/ssl/top_frame.html")); + + SecurityStyle security_style; + int cert_status; + int mixed_content_state; + EXPECT_TRUE(tab->GetSecurityState(&security_style, &cert_status, + &mixed_content_state)); + EXPECT_EQ(SECURITY_STYLE_AUTHENTICATION_BROKEN, security_style); + EXPECT_EQ(net::CERT_STATUS_DATE_INVALID, + cert_status & net::CERT_STATUS_ALL_ERRORS); + EXPECT_EQ(NavigationEntry::SSLStatus::NORMAL_CONTENT, mixed_content_state); + + // Continue on the interstitial. + EXPECT_TRUE(tab->TakeActionOnSSLBlockingPage(true)); + + // Navigate to a good frame. + bool success = false; + int64 last_nav_time = 0; + EXPECT_TRUE(tab->GetLastNavigationTime(&last_nav_time)); + EXPECT_TRUE(tab->ExecuteAndExtractBool(L"", + L"javascript:void(window.domAutomationController)" + L".send(clickLink('goodHTTPSLink'));", + &success)); + EXPECT_TRUE(success); + EXPECT_TRUE(tab->WaitForNavigation(last_nav_time)); + + // We should still be authentication broken. + EXPECT_TRUE(tab->GetSecurityState(&security_style, &cert_status, + &mixed_content_state)); + EXPECT_EQ(SECURITY_STYLE_AUTHENTICATION_BROKEN, security_style); + EXPECT_EQ(net::CERT_STATUS_DATE_INVALID, + cert_status & net::CERT_STATUS_ALL_ERRORS); + EXPECT_EQ(NavigationEntry::SSLStatus::NORMAL_CONTENT, mixed_content_state); +} + +// From an HTTP top frame, navigate to good and bad HTTPS (security state should +// stay unauthenticated). +TEST_F(SSLUITest, TestUnauthenticatedFrameNavigation) { + TestServer http_server(kDocRoot); + HTTPSTestServer good_https_server(kHostName, kOKHTTPSPort, + kDocRoot, GetOKCertPath()); + HTTPSTestServer bad_https_server(kHostName, kBadHTTPSPort, + kDocRoot, GetExpiredCertPath()); + + scoped_ptr<TabProxy> tab(GetActiveTabProxy()); + NavigateTab(tab.get(), + http_server.TestServerPageW(L"files/ssl/top_frame.html")); + + SecurityStyle security_style; + int cert_status; + int mixed_content_state; + EXPECT_TRUE(tab->GetSecurityState(&security_style, &cert_status, + &mixed_content_state)); + EXPECT_EQ(SECURITY_STYLE_UNAUTHENTICATED, security_style); + EXPECT_EQ(0, cert_status & net::CERT_STATUS_ALL_ERRORS); + EXPECT_EQ(NavigationEntry::SSLStatus::NORMAL_CONTENT, mixed_content_state); + + // Now navigate inside the frame to a secure HTTPS frame. + bool success = false; + int64 last_nav_time = 0; + EXPECT_TRUE(tab->GetLastNavigationTime(&last_nav_time)); + EXPECT_TRUE(tab->ExecuteAndExtractBool(L"", + L"javascript:void(window.domAutomationController)" + L".send(clickLink('goodHTTPSLink'));", + &success)); + EXPECT_TRUE(success); + EXPECT_TRUE(tab->WaitForNavigation(last_nav_time)); + + // We should still be unauthenticated. + EXPECT_TRUE(tab->GetSecurityState(&security_style, &cert_status, + &mixed_content_state)); + EXPECT_EQ(SECURITY_STYLE_UNAUTHENTICATED, security_style); + EXPECT_EQ(0, cert_status & net::CERT_STATUS_ALL_ERRORS); + EXPECT_EQ(NavigationEntry::SSLStatus::NORMAL_CONTENT, mixed_content_state); + + // Now navigate to a bad HTTPS frame. + EXPECT_TRUE(tab->GetLastNavigationTime(&last_nav_time)); + EXPECT_TRUE(tab->ExecuteAndExtractBool(L"", + L"javascript:void(window.domAutomationController)" + L".send(clickLink('badHTTPSLink'));", + &success)); + EXPECT_TRUE(success); + EXPECT_TRUE(tab->WaitForNavigation(last_nav_time)); + + // State should not have changed. + EXPECT_TRUE(tab->GetSecurityState(&security_style, &cert_status, + &mixed_content_state)); + EXPECT_EQ(SECURITY_STYLE_UNAUTHENTICATED, security_style); + EXPECT_EQ(0, cert_status & net::CERT_STATUS_ALL_ERRORS); + EXPECT_EQ(NavigationEntry::SSLStatus::NORMAL_CONTENT, mixed_content_state); + + // And the frame should have been blocked (see bug #2316). + bool is_content_evil = true; + std::wstring content_frame_xpath(L"html/frameset/frame[2]"); + std::wstring is_frame_evil_js( + L"javascript:void(window.domAutomationController)" + L".send(document.getElementById('evilDiv') != null);"); + EXPECT_TRUE(tab->ExecuteAndExtractBool(content_frame_xpath, + is_frame_evil_js, + &is_content_evil)); + EXPECT_FALSE(is_content_evil); +} + + +// TODO (jcampan): more tests to do below. +// Visit a page over https that contains a frame with a redirect. + +// XMLHttpRequest mixed in synchronous mode. + +// XMLHttpRequest mixed in asynchronous mode. + +// XMLHttpRequest over bad ssl in synchronous mode. + +// XMLHttpRequest over OK ssl in synchronous mode. diff --git a/chrome/browser/web_contents.cc b/chrome/browser/web_contents.cc index 3ac7298..b00d63f 100644 --- a/chrome/browser/web_contents.cc +++ b/chrome/browser/web_contents.cc @@ -1604,7 +1604,7 @@ void WebContents::DidStartProvisionalLoadForFrame( is_main_frame, render_manager_.IsRenderViewInterstitial(render_view_host), controller()->IsURLInPageNavigation(url), - url, std::string()); + url, std::string(), false); NotificationService::current()-> Notify(NOTIFY_FRAME_PROVISIONAL_LOAD_START, Source<NavigationController>(controller()), @@ -1671,7 +1671,7 @@ void WebContents::DidFailProvisionalLoadWithError( is_main_frame, render_manager_.IsRenderViewInterstitial(render_view_host), controller()->IsURLInPageNavigation(url), - url, std::string()); + url, std::string(), false); details.set_error_code(error_code); render_manager_.set_showing_repost_interstitial(showing_repost_interstitial); diff --git a/chrome/common/render_messages.h b/chrome/common/render_messages.h index f1c9bcda..7deb5dc 100644 --- a/chrome/common/render_messages.h +++ b/chrome/common/render_messages.h @@ -101,6 +101,10 @@ struct ViewHostMsg_FrameNavigate_Params { // True if this was a post request. bool is_post; + + // Whether the content of the frame was replaced with some alternate content + // (this can happen if the resource was insecure). + bool is_content_filtered; }; // Parameters structure for ViewHostMsg_ContextMenu, which has too many data diff --git a/chrome/common/resource_dispatcher.cc b/chrome/common/resource_dispatcher.cc index 669ce7e..e3099af 100644 --- a/chrome/common/resource_dispatcher.cc +++ b/chrome/common/resource_dispatcher.cc @@ -337,7 +337,7 @@ void ResourceDispatcher::OnReceivedResponse( } RESOURCE_LOG("Dispatching response for " << peer->GetURLForDebugging()); - peer->OnReceivedResponse(response_head); + peer->OnReceivedResponse(response_head, false); } void ResourceDispatcher::OnReceivedData(int request_id, diff --git a/chrome/common/resource_dispatcher_unittest.cc b/chrome/common/resource_dispatcher_unittest.cc index 1297ff0..a75e556 100644 --- a/chrome/common/resource_dispatcher_unittest.cc +++ b/chrome/common/resource_dispatcher_unittest.cc @@ -33,7 +33,8 @@ class TestRequestCallback : public ResourceLoaderBridge::Peer { } virtual void OnReceivedResponse( - const ResourceLoaderBridge::ResponseInfo& info) { + const ResourceLoaderBridge::ResponseInfo& info, + bool content_filtered) { } virtual void OnReceivedData(const char* data, int len) { diff --git a/chrome/common/security_filter_peer.cc b/chrome/common/security_filter_peer.cc index 50f1877..58db3ee 100644 --- a/chrome/common/security_filter_peer.cc +++ b/chrome/common/security_filter_peer.cc @@ -104,7 +104,8 @@ void SecurityFilterPeer::OnReceivedRedirect(const GURL& new_url) { } void SecurityFilterPeer::OnReceivedResponse( - const webkit_glue::ResourceLoaderBridge::ResponseInfo& info) { + const webkit_glue::ResourceLoaderBridge::ResponseInfo& info, + bool content_filtered) { NOTREACHED(); } @@ -164,7 +165,8 @@ BufferedPeer::~BufferedPeer() { } void BufferedPeer::OnReceivedResponse( - const webkit_glue::ResourceLoaderBridge::ResponseInfo& info) { + const webkit_glue::ResourceLoaderBridge::ResponseInfo& info, + bool response_filtered) { ProcessResponseInfo(info, &response_info_, mime_type_); } @@ -179,13 +181,13 @@ void BufferedPeer::OnCompletedRequest(const URLRequestStatus& status) { // Give sub-classes a chance at altering the data. if (status.status() != URLRequestStatus::SUCCESS || !DataReady()) { // Pretend we failed to load the resource. - original_peer_->OnReceivedResponse(response_info_); + original_peer_->OnReceivedResponse(response_info_, true); URLRequestStatus status(URLRequestStatus::CANCELED, 0); original_peer_->OnCompletedRequest(status); return; } - original_peer_->OnReceivedResponse(response_info_); + original_peer_->OnReceivedResponse(response_info_, true); if (!data_.empty()) original_peer_->OnReceivedData(data_.data(), static_cast<int>(data_.size())); @@ -209,7 +211,8 @@ ReplaceContentPeer::~ReplaceContentPeer() { } void ReplaceContentPeer::OnReceivedResponse( - const webkit_glue::ResourceLoaderBridge::ResponseInfo& info) { + const webkit_glue::ResourceLoaderBridge::ResponseInfo& info, + bool content_filtered) { // Ignore this, we'll serve some alternate content in OnCompletedRequest. } @@ -221,7 +224,7 @@ void ReplaceContentPeer::OnCompletedRequest(const URLRequestStatus& status) { webkit_glue::ResourceLoaderBridge::ResponseInfo info; ProcessResponseInfo(info, &info, mime_type_); info.content_length = static_cast<int>(data_.size()); - original_peer_->OnReceivedResponse(info); + original_peer_->OnReceivedResponse(info, true); if (!data_.empty()) original_peer_->OnReceivedData(data_.data(), static_cast<int>(data_.size())); diff --git a/chrome/common/security_filter_peer.h b/chrome/common/security_filter_peer.h index 0363f35..616680d 100644 --- a/chrome/common/security_filter_peer.h +++ b/chrome/common/security_filter_peer.h @@ -40,7 +40,8 @@ class SecurityFilterPeer : public webkit_glue::ResourceLoaderBridge::Peer { // ResourceLoaderBridge::Peer methods. virtual void OnReceivedRedirect(const GURL& new_url); virtual void OnReceivedResponse( - const webkit_glue::ResourceLoaderBridge::ResponseInfo& info); + const webkit_glue::ResourceLoaderBridge::ResponseInfo& info, + bool content_filtered); virtual void OnReceivedData(const char* data, int len); virtual void OnCompletedRequest(const URLRequestStatus& status); virtual std::string GetURLForDebugging(); @@ -67,7 +68,8 @@ class BufferedPeer : public SecurityFilterPeer { // ResourceLoaderBridge::Peer Implementation. virtual void OnReceivedResponse( - const webkit_glue::ResourceLoaderBridge::ResponseInfo& info); + const webkit_glue::ResourceLoaderBridge::ResponseInfo& info, + bool content_filtered); virtual void OnReceivedData(const char* data, int len); virtual void OnCompletedRequest(const URLRequestStatus& status); @@ -104,7 +106,8 @@ class ReplaceContentPeer : public SecurityFilterPeer { // ResourceLoaderBridge::Peer Implementation. virtual void OnReceivedResponse( - const webkit_glue::ResourceLoaderBridge::ResponseInfo& info); + const webkit_glue::ResourceLoaderBridge::ResponseInfo& info, + bool content_filtered); void OnReceivedData(const char* data, int len); void OnCompletedRequest(const URLRequestStatus& status); private: diff --git a/chrome/plugin/chrome_plugin_host.cc b/chrome/plugin/chrome_plugin_host.cc index bcc397a..9512c43 100644 --- a/chrome/plugin/chrome_plugin_host.cc +++ b/chrome/plugin/chrome_plugin_host.cc @@ -61,7 +61,8 @@ class PluginRequestHandlerProxy } virtual void OnReceivedResponse( - const ResourceLoaderBridge::ResponseInfo& info) { + const ResourceLoaderBridge::ResponseInfo& info, + bool content_filtered) { response_headers_ = info.headers; plugin_->functions().response_funcs->start_completed( cprequest_.get(), CPERR_SUCCESS); diff --git a/chrome/renderer/chrome_plugin_host.cc b/chrome/renderer/chrome_plugin_host.cc index 9de6669..5caa99c 100644 --- a/chrome/renderer/chrome_plugin_host.cc +++ b/chrome/renderer/chrome_plugin_host.cc @@ -64,7 +64,8 @@ class PluginRequestHandlerProxy } virtual void OnReceivedResponse( - const ResourceLoaderBridge::ResponseInfo& info) { + const ResourceLoaderBridge::ResponseInfo& info, + bool content_filtered) { response_headers_ = info.headers; plugin_->functions().response_funcs->start_completed( cprequest_.get(), CPERR_SUCCESS); diff --git a/chrome/renderer/render_view.cc b/chrome/renderer/render_view.cc index 032584b..f9d6b33 100644 --- a/chrome/renderer/render_view.cc +++ b/chrome/renderer/render_view.cc @@ -940,6 +940,7 @@ void RenderView::UpdateURL(WebFrame* frame) { ViewHostMsg_FrameNavigate_Params params; params.is_post = false; params.page_id = page_id_; + params.is_content_filtered = response.IsContentFiltered(); if (!request.GetSecurityInfo().empty()) { // SSL state specified in the request takes precedence over the one in the // response. diff --git a/chrome/test/automation/automation_messages_internal.h b/chrome/test/automation/automation_messages_internal.h index aed439e..e6cf72a 100644 --- a/chrome/test/automation/automation_messages_internal.h +++ b/chrome/test/automation/automation_messages_internal.h @@ -27,8 +27,8 @@ // The IPC message IDs are part of an enum and hence the value // assumed to be constant across the builds may change. // The messages AutomationMsg_WindowHWND* in particular should not change -// since the PageCyclerReferenceTest depend on the correctness of the -// the message IDs across the builds. +// since the PageCyclerReferenceTest depends on the correctness of the +// message IDs across the builds. // By using a start value of 0 for automation messages, we keep backward // compatability with old builds. @@ -760,5 +760,46 @@ IPC_BEGIN_MESSAGES(Automation, 0) IPC_MESSAGE_ROUTED2(AutomationMsg_BookmarkBarVisibilityResponse, bool, /* is_visible */ bool /* still_animating */) + + // This message requests the number of SSL related info bars opened. It + // returns -1 if an error occurred. + IPC_MESSAGE_ROUTED1(AutomationMsg_GetSSLInfoBarCountRequest, + int /* tab_handle */) + IPC_MESSAGE_ROUTED1(AutomationMsg_GetSSLInfoBarCountResponse, + int /* info bar count */) + + // This message triggers the action associated with the link in the info-bar + // at the specified index. If |wait for navigation| is true, it won't return + // until a navigation has occurred. + IPC_MESSAGE_ROUTED3(AutomationMsg_ClickSSLInfoBarLinkRequest, + int /* tab_handle */, + int /* info bar index */, + bool /* wait for navigation */) + IPC_MESSAGE_ROUTED1(AutomationMsg_ClickSSLInfoBarLinkResponse, + bool /* success flag */) + + // This message retrieves the last time a navigation occurred in the specified + // tab. The value is intended to be used with WaitForNavigation. + IPC_MESSAGE_ROUTED1(AutomationMsg_GetLastNavigationTimeRequest, + int /* tab_handle */) + IPC_MESSAGE_ROUTED1(AutomationMsg_GetLastNavigationTimeResponse, + int64 /* last navigation time */) + + // This messages is used to block until a new navigation occurs (if there is + // none more recent then the time specified). + IPC_MESSAGE_ROUTED2(AutomationMsg_WaitForNavigationRequest, + int /* tab_handle */, + int64 /* last navigation time */) + IPC_MESSAGE_ROUTED1(AutomationMsg_WaitForNavigationResponse, + bool /* success */) + + // This messages sets an int-value preference. + IPC_MESSAGE_ROUTED3(AutomationMsg_SetIntPreferenceRequest, + int /* browser handle */, + std::wstring /* pref name */, + int /* value */) + IPC_MESSAGE_ROUTED1(AutomationMsg_SetIntPreferenceResponse, + bool /* success */) + IPC_END_MESSAGES(Automation) diff --git a/chrome/test/automation/browser_proxy.cc b/chrome/test/automation/browser_proxy.cc index 425c6b5..8a30c31 100644 --- a/chrome/test/automation/browser_proxy.cc +++ b/chrome/test/automation/browser_proxy.cc @@ -372,3 +372,23 @@ bool BrowserProxy::GetBookmarkBarVisibility(bool* is_visible, delete response; return true; } + +bool BrowserProxy::SetIntPreference(const std::wstring& name, int value) { + if (!is_valid()) + return false; + + IPC::Message* response = NULL; + bool success = sender_->SendAndWaitForResponse( + new AutomationMsg_SetIntPreferenceRequest(0, handle_, name , value), + &response, AutomationMsg_SetIntPreferenceResponse::ID); + + scoped_ptr<IPC::Message> response_deleter(response); // Delete on return. + if (!success) + return false; + + if (AutomationMsg_SetIntPreferenceResponse::Read(response, &success)) + return success; + + // We failed to deserialize the returned value. + return false; +}
\ No newline at end of file diff --git a/chrome/test/automation/browser_proxy.h b/chrome/test/automation/browser_proxy.h index 133a93d2..b2c92ca 100644 --- a/chrome/test/automation/browser_proxy.h +++ b/chrome/test/automation/browser_proxy.h @@ -143,6 +143,9 @@ class BrowserProxy : public AutomationResourceProxy { // it into position. Returns false on failure. bool GetBookmarkBarVisibility(bool* is_visible, bool* is_animating); + // Sets the int value of the specified preference. + bool SetIntPreference(const std::wstring& name, int value); + private: DISALLOW_COPY_AND_ASSIGN(BrowserProxy); }; diff --git a/chrome/test/automation/tab_proxy.cc b/chrome/test/automation/tab_proxy.cc index f284b26..7668c19 100644 --- a/chrome/test/automation/tab_proxy.cc +++ b/chrome/test/automation/tab_proxy.cc @@ -966,3 +966,79 @@ void TabProxy::HandleMessageFromExternalHost(AutomationHandle handle, DCHECK(succeeded); } +bool TabProxy::GetSSLInfoBarCount(int* count) { + if (!is_valid()) + return false; + + IPC::Message* response = NULL; + bool success = sender_->SendAndWaitForResponse( + new AutomationMsg_GetSSLInfoBarCountRequest(0, handle_), + &response, + AutomationMsg_GetSSLInfoBarCountResponse::ID); + scoped_ptr<IPC::Message> auto_deleter(response); + if (!success) + return false; + + void* iter = NULL; + response->ReadInt(&iter, count); + return true; +} + +bool TabProxy::ClickSSLInfoBarLink(int info_bar_index, + bool wait_for_navigation) { + if (!is_valid()) + return false; + + IPC::Message* response = NULL; + bool success = sender_->SendAndWaitForResponse( + new AutomationMsg_ClickSSLInfoBarLinkRequest(0, handle_, + info_bar_index, + wait_for_navigation), + &response, + AutomationMsg_ClickSSLInfoBarLinkResponse::ID); + scoped_ptr<IPC::Message> auto_deleter(response); + if (!success) + return false; + + void* iter = NULL; + response->ReadBool(&iter, &success); + return success; +} + +bool TabProxy::GetLastNavigationTime(int64* last_navigation_time) { + if (!is_valid()) + return false; + + IPC::Message* response = NULL; + bool success = sender_->SendAndWaitForResponse( + new AutomationMsg_GetLastNavigationTimeRequest(0, handle_), + &response, + AutomationMsg_GetLastNavigationTimeResponse::ID); + scoped_ptr<IPC::Message> auto_deleter(response); + if (!success) + return false; + + void* iter = NULL; + response->ReadInt64(&iter, last_navigation_time); + return true; +} + +bool TabProxy::WaitForNavigation(int64 last_navigation_time) { + if (!is_valid()) + return false; + + IPC::Message* response = NULL; + bool success = sender_->SendAndWaitForResponse( + new AutomationMsg_WaitForNavigationRequest(0, + handle_, + last_navigation_time), + &response, + AutomationMsg_WaitForNavigationResponse::ID); + scoped_ptr<IPC::Message> auto_deleter(response); + if (!success) + return false; + + void* iter = NULL; + response->ReadBool(&iter, &success); + return success; +}
\ No newline at end of file diff --git a/chrome/test/automation/tab_proxy.h b/chrome/test/automation/tab_proxy.h index 220d096..a13e6a5 100644 --- a/chrome/test/automation/tab_proxy.h +++ b/chrome/test/automation/tab_proxy.h @@ -44,10 +44,9 @@ class TabProxy : public AutomationResourceProxy { // failure. ConstrainedWindowProxy* GetConstrainedWindow(int window_index) const; - // Execute a javascript in a frame's context whose xpath - // is provided as the first parameter and extract - // the values from the resulting json string. - // Example: + // Executes a javascript in a frame's context whose xpath is provided as the + // first parameter and extract the values from the resulting json string. + // Examples: // jscript = "window.domAutomationController.send('string');" // will result in value = "string" // jscript = "window.domAutomationController.send(24);" @@ -254,6 +253,28 @@ class TabProxy : public AutomationResourceProxy { const std::string& target, const std::string& message); + // Retrieves the number of SSL related info-bars currently showing in |count|. + bool GetSSLInfoBarCount(int* count); + + // Causes a click on the link of the info-bar at |info_bar_index|. If + // |wait_for_navigation| is true, this call does not return until a navigation + // has occured. + bool ClickSSLInfoBarLink(int info_bar_index, bool wait_for_navigation); + + // Retrieves the time at which the last navigation occured. This is intended + // to be used with WaitForNavigation (see below). + bool GetLastNavigationTime(int64* last_navigation_time); + + // Waits for a new navigation if none as occurred since |last_navigation_time| + // The purpose of this function is for operations that causes asynchronous + // navigation to happen. + // It is supposed to be used as follow: + // int64 last_nav_time; + // tab_proxy->GetLastNavigationTime(&last_nav_time); + // tab_proxy->SomeOperationThatTriggersAnAsynchronousNavigation(); + // tab_proxy->WaitForNavigation(last_nav_time); + bool WaitForNavigation(int64 last_navigation_time); + private: DISALLOW_COPY_AND_ASSIGN(TabProxy); }; diff --git a/chrome/test/data/ssl/bad_iframe.html b/chrome/test/data/ssl/bad_iframe.html index 53eff7e..b20481c 100644 --- a/chrome/test/data/ssl/bad_iframe.html +++ b/chrome/test/data/ssl/bad_iframe.html @@ -1,10 +1,9 @@ <html> -<script> - window.open('google.html', name, - "status = 1, height = 300, width = 300, resizable = 0" ); -</script> - +<body> <H1>Evil IFrame</H1> +<div id="evilDiv"> This frame is loaded over insecure HTTPS. +</div> +</body> </html> diff --git a/chrome/test/data/ssl/frame_left.html b/chrome/test/data/ssl/frame_left.html new file mode 100644 index 0000000..128d69e --- /dev/null +++ b/chrome/test/data/ssl/frame_left.html @@ -0,0 +1,7 @@ +<html> +<body> +<a id="goodHTTPSLink" href="https://127.0.0.1:9443/files/ssl/google.html" TARGET="contentFrame">Good HTTPS page</a><br> +<a id="badHTTPSLink" href="https://127.0.0.1:9666/files/ssl/bad_iframe.html" TARGET="contentFrame">Bad HTTPS page</a><br> +<a id="HTTPLink" href="http://127.0.0.1:1337/files/ssl/google.html" TARGET="contentFrame">HTTP page</a><br> +</body> +</html> diff --git a/chrome/test/data/ssl/frame_right.html b/chrome/test/data/ssl/frame_right.html new file mode 100644 index 0000000..d49d61d9 --- /dev/null +++ b/chrome/test/data/ssl/frame_right.html @@ -0,0 +1,3 @@ +<html> +This is the content frame. +</html> diff --git a/chrome/test/data/ssl/page_with_mixed_contents.html b/chrome/test/data/ssl/page_with_mixed_contents.html index 2bf9bb24..b19730a 100644 --- a/chrome/test/data/ssl/page_with_mixed_contents.html +++ b/chrome/test/data/ssl/page_with_mixed_contents.html @@ -1,9 +1,15 @@ <html> -<head><title>Page with mixed contents</title></head> +<head><title>Page with mixed contents</title> +<script> + function ImageWidth() { + return document.getElementById("bad_image").width; + } +</script> +</head> <body> This page contains an image which is served over an http connection, causing mixed contents (when this page is loaded over https).<br> -<img src="http://localhost:1337/files/ssl/google_files/logo.gif"/> +<img id="bad_image" src="http://localhost:1337/files/ssl/google_files/logo.gif"/> </body> </html> diff --git a/chrome/test/data/ssl/top_frame.html b/chrome/test/data/ssl/top_frame.html new file mode 100644 index 0000000..ac5c144 --- /dev/null +++ b/chrome/test/data/ssl/top_frame.html @@ -0,0 +1,25 @@ +<html> + <head><title>This is a test page with frames</title> + <script> + function simulateClick(target) { + var evt = document.createEvent("MouseEvents"); + evt.initMouseEvent("click", true, true, window, + 0, 0, 0, 0, 0, false, false, + false, false, 0, null); + + return target.dispatchEvent(evt); + } + + function clickLink(linkID) { + target = frames['navFrame'].document.getElementById(linkID); + if (target == null) + alert("clickLink failed for id=" + linkID); + return simulateClick(target); + } + </script> + </head> + <frameset cols="25%,75%"> + <frame src="frame_left.html" name="navFrame"> + <frame src="frame_right.html" name="contentFrame"> + </frameset> +</html> diff --git a/webkit/glue/resource_handle_win.cc b/webkit/glue/resource_handle_win.cc index 09a22c2..da485c1 100644 --- a/webkit/glue/resource_handle_win.cc +++ b/webkit/glue/resource_handle_win.cc @@ -200,7 +200,8 @@ class ResourceHandleInternal : public ResourceLoaderBridge::Peer { // ResourceLoaderBridge::Peer implementation virtual void OnReceivedRedirect(const GURL& new_url); virtual void OnReceivedResponse( - const ResourceLoaderBridge::ResponseInfo& info); + const ResourceLoaderBridge::ResponseInfo& info, + bool content_filtered); virtual void OnReceivedData(const char* data, int len); virtual void OnCompletedRequest(const URLRequestStatus& status); virtual std::string GetURLForDebugging(); @@ -268,7 +269,7 @@ void ResourceHandleInternal::HandleDataUrl() { if (GetInfoFromDataUrl(webkit_glue::KURLToGURL(request_.url()), &info, &data, &status)) { - OnReceivedResponse(info); + OnReceivedResponse(info, false); if (data.size()) OnReceivedData(data.c_str(), data.size()); @@ -502,11 +503,13 @@ void ResourceHandleInternal::OnReceivedRedirect(const GURL& new_url) { } void ResourceHandleInternal::OnReceivedResponse( - const ResourceLoaderBridge::ResponseInfo& info) { + const ResourceLoaderBridge::ResponseInfo& info, + bool content_filtered) { DCHECK(pending_); // TODO(darin): need a way to properly initialize a ResourceResponse ResourceResponse response = MakeResourceResponse(request_.url(), info); + response.setIsContentFiltered(content_filtered); expected_content_length_ = response.expectedContentLength(); diff --git a/webkit/glue/resource_loader_bridge.h b/webkit/glue/resource_loader_bridge.h index 835a9e7..15414ae 100644 --- a/webkit/glue/resource_loader_bridge.h +++ b/webkit/glue/resource_loader_bridge.h @@ -79,8 +79,11 @@ class ResourceLoaderBridge { virtual void OnReceivedRedirect(const GURL& new_url) = 0; // Called when response headers are available (after all redirects have - // been followed). - virtual void OnReceivedResponse(const ResponseInfo& info) = 0; + // been followed). |content_filtered| is set to true if the contents is + // altered or replaced (usually for security reasons when the resource is + // deemed unsafe). + virtual void OnReceivedResponse(const ResponseInfo& info, + bool content_filtered) = 0; // Called when a chunk of response data is available. This method may // be called multiple times or not at all if an error occurs. diff --git a/webkit/glue/webresponse.h b/webkit/glue/webresponse.h index 9e98586..7259057 100644 --- a/webkit/glue/webresponse.h +++ b/webkit/glue/webresponse.h @@ -22,6 +22,10 @@ class WebResponse { // used. virtual std::string GetSecurityInfo() const = 0; + // Returns whether the content of this resource was filtered (usually for + // security reasons). + virtual bool IsContentFiltered() const = 0; + WebResponse() { } virtual ~WebResponse() { } diff --git a/webkit/glue/webresponse_impl.h b/webkit/glue/webresponse_impl.h index 83260e3..504094b 100644 --- a/webkit/glue/webresponse_impl.h +++ b/webkit/glue/webresponse_impl.h @@ -38,6 +38,10 @@ class WebResponseImpl : public WebResponse { response_ = response; } + virtual bool IsContentFiltered() const { + return response_.isContentFiltered(); + } + private: WebCore::ResourceResponse response_; diff --git a/webkit/port/platform/network/ResourceResponse.h b/webkit/port/platform/network/ResourceResponse.h index 801f244..cf498bd 100644 --- a/webkit/port/platform/network/ResourceResponse.h +++ b/webkit/port/platform/network/ResourceResponse.h @@ -37,14 +37,16 @@ namespace WebCore { class ResourceResponse : public ResourceResponseBase { public: ResourceResponse() - : ResourceResponseBase() + : ResourceResponseBase(), + m_isContentFiltered(false) { // TODO(ericroman): move this into ResourceResponseBase m_lastModifiedDate = 0; } ResourceResponse(const KURL& url, const String& mimeType, long long expectedLength, const String& textEncodingName, const String& filename) - : ResourceResponseBase(url, mimeType, expectedLength, textEncodingName, filename) + : ResourceResponseBase(url, mimeType, expectedLength, textEncodingName, filename), + m_isContentFiltered(false) { // TODO(ericroman): move this into ResourceResponseBase m_lastModifiedDate = 0; @@ -55,6 +57,11 @@ public: m_securityInfo = securityInfo; } + bool isContentFiltered() const { return m_isContentFiltered; } + void setIsContentFiltered(bool isContentFiltered) { + m_isContentFiltered = isContentFiltered; + } + private: friend class ResourceResponseBase; @@ -68,6 +75,9 @@ private: notImplemented(); } + // Whether the contents for this response has been altered/blocked (usually + // for security reasons. + bool m_isContentFiltered; }; } // namespace WebCore diff --git a/webkit/tools/test_shell/simple_resource_loader_bridge.cc b/webkit/tools/test_shell/simple_resource_loader_bridge.cc index 336e42a..ce7157b 100644 --- a/webkit/tools/test_shell/simple_resource_loader_bridge.cc +++ b/webkit/tools/test_shell/simple_resource_loader_bridge.cc @@ -143,9 +143,10 @@ class RequestProxy : public URLRequest::Delegate, peer_->OnReceivedRedirect(new_url); } - void NotifyReceivedResponse(const ResourceLoaderBridge::ResponseInfo& info) { + void NotifyReceivedResponse(const ResourceLoaderBridge::ResponseInfo& info, + bool content_filtered) { if (peer_) - peer_->OnReceivedResponse(info); + peer_->OnReceivedResponse(info, content_filtered); } void NotifyReceivedData(int bytes_read) { @@ -231,9 +232,10 @@ class RequestProxy : public URLRequest::Delegate, } virtual void OnReceivedResponse( - const ResourceLoaderBridge::ResponseInfo& info) { + const ResourceLoaderBridge::ResponseInfo& info, + bool content_filtered) { owner_loop_->PostTask(FROM_HERE, NewRunnableMethod( - this, &RequestProxy::NotifyReceivedResponse, info)); + this, &RequestProxy::NotifyReceivedResponse, info, content_filtered)); } virtual void OnReceivedData(int bytes_read) { @@ -263,7 +265,7 @@ class RequestProxy : public URLRequest::Delegate, info.headers = request->response_headers(); request->GetMimeType(&info.mime_type); request->GetCharset(&info.charset); - OnReceivedResponse(info); + OnReceivedResponse(info, false); AsyncReadData(); // start reading } else { Done(); @@ -324,7 +326,8 @@ class SyncRequestProxy : public RequestProxy { } virtual void OnReceivedResponse( - const ResourceLoaderBridge::ResponseInfo& info) { + const ResourceLoaderBridge::ResponseInfo& info, + bool content_filtered) { *static_cast<ResourceLoaderBridge::ResponseInfo*>(result_) = info; } |