summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjcampan@chromium.org <jcampan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2008-09-24 17:42:42 +0000
committerjcampan@chromium.org <jcampan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2008-09-24 17:42:42 +0000
commit8a3422c9488ce79e305973d29a01811762e35465 (patch)
tree7fc94cb7aa013f7bb2afaf4100b1a8f45208cc00
parent5eb64653873981c7dbf693a9aba7c7da011b14a3 (diff)
downloadchromium_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
-rw-r--r--base/observer_list.h8
-rw-r--r--chrome/browser/automation/automation_provider.cc113
-rw-r--r--chrome/browser/automation/automation_provider.h28
-rw-r--r--chrome/browser/automation/automation_tab_tracker.h47
-rw-r--r--chrome/browser/navigation_controller.cc1
-rw-r--r--chrome/browser/navigation_controller.h4
-rw-r--r--chrome/browser/provisional_load_details.cc6
-rw-r--r--chrome/browser/provisional_load_details.h6
-rw-r--r--chrome/browser/ssl_manager.cc68
-rw-r--r--chrome/browser/ssl_manager.h32
-rw-r--r--chrome/browser/ssl_policy.cc35
-rw-r--r--chrome/browser/ssl_uitest.cc439
-rw-r--r--chrome/browser/web_contents.cc4
-rw-r--r--chrome/common/render_messages.h4
-rw-r--r--chrome/common/resource_dispatcher.cc2
-rw-r--r--chrome/common/resource_dispatcher_unittest.cc3
-rw-r--r--chrome/common/security_filter_peer.cc15
-rw-r--r--chrome/common/security_filter_peer.h9
-rw-r--r--chrome/plugin/chrome_plugin_host.cc3
-rw-r--r--chrome/renderer/chrome_plugin_host.cc3
-rw-r--r--chrome/renderer/render_view.cc1
-rw-r--r--chrome/test/automation/automation_messages_internal.h45
-rw-r--r--chrome/test/automation/browser_proxy.cc20
-rw-r--r--chrome/test/automation/browser_proxy.h3
-rw-r--r--chrome/test/automation/tab_proxy.cc76
-rw-r--r--chrome/test/automation/tab_proxy.h29
-rw-r--r--chrome/test/data/ssl/bad_iframe.html9
-rw-r--r--chrome/test/data/ssl/frame_left.html7
-rw-r--r--chrome/test/data/ssl/frame_right.html3
-rw-r--r--chrome/test/data/ssl/page_with_mixed_contents.html10
-rw-r--r--chrome/test/data/ssl/top_frame.html25
-rw-r--r--webkit/glue/resource_handle_win.cc9
-rw-r--r--webkit/glue/resource_loader_bridge.h7
-rw-r--r--webkit/glue/webresponse.h4
-rw-r--r--webkit/glue/webresponse_impl.h4
-rw-r--r--webkit/port/platform/network/ResourceResponse.h14
-rw-r--r--webkit/tools/test_shell/simple_resource_loader_bridge.cc15
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;
}