summaryrefslogtreecommitdiffstats
path: root/chrome/browser/automation
diff options
context:
space:
mode:
authorinitial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98>2008-07-26 23:55:29 +0000
committerinitial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98>2008-07-26 23:55:29 +0000
commit09911bf300f1a419907a9412154760efd0b7abc3 (patch)
treef131325fb4e2ad12c6d3504ab75b16dd92facfed /chrome/browser/automation
parent586acc5fe142f498261f52c66862fa417c3d52d2 (diff)
downloadchromium_src-09911bf300f1a419907a9412154760efd0b7abc3.zip
chromium_src-09911bf300f1a419907a9412154760efd0b7abc3.tar.gz
chromium_src-09911bf300f1a419907a9412154760efd0b7abc3.tar.bz2
Add chrome to the repository.
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@15 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/automation')
-rw-r--r--chrome/browser/automation/automation_autocomplete_edit_tracker.h59
-rw-r--r--chrome/browser/automation/automation_browser_tracker.h58
-rw-r--r--chrome/browser/automation/automation_constrained_window_tracker.h59
-rw-r--r--chrome/browser/automation/automation_provider.cc2172
-rw-r--r--chrome/browser/automation/automation_provider.h379
-rw-r--r--chrome/browser/automation/automation_provider_list.cc78
-rw-r--r--chrome/browser/automation/automation_provider_list.h71
-rw-r--r--chrome/browser/automation/automation_resource_tracker.cc107
-rw-r--r--chrome/browser/automation/automation_resource_tracker.h180
-rw-r--r--chrome/browser/automation/automation_tab_tracker.h67
-rw-r--r--chrome/browser/automation/automation_window_tracker.h56
-rw-r--r--chrome/browser/automation/ui_controls.cc182
-rw-r--r--chrome/browser/automation/ui_controls.h62
-rw-r--r--chrome/browser/automation/url_request_failed_dns_job.cc61
-rw-r--r--chrome/browser/automation/url_request_failed_dns_job.h58
-rw-r--r--chrome/browser/automation/url_request_mock_http_job.cc111
-rw-r--r--chrome/browser/automation/url_request_mock_http_job.h60
-rw-r--r--chrome/browser/automation/url_request_mock_net_error_job.cc125
-rw-r--r--chrome/browser/automation/url_request_mock_net_error_job.h95
-rw-r--r--chrome/browser/automation/url_request_slow_download_job.cc186
-rw-r--r--chrome/browser/automation/url_request_slow_download_job.h82
21 files changed, 4308 insertions, 0 deletions
diff --git a/chrome/browser/automation/automation_autocomplete_edit_tracker.h b/chrome/browser/automation/automation_autocomplete_edit_tracker.h
new file mode 100644
index 0000000..24d688a
--- /dev/null
+++ b/chrome/browser/automation/automation_autocomplete_edit_tracker.h
@@ -0,0 +1,59 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef CHROME_BROWSER_AUTOMATION_AUTOMATION_AUTOCOMPLETE_EDIT_TRACKER_H__
+#define CHROME_BROWSER_AUTOMATION_AUTOMATION_AUTOCOMPLETE_EDIT_TRACKER_H__
+
+#include "chrome/browser/autocomplete/autocomplete_edit.h"
+#include "chrome/browser/automation/automation_resource_tracker.h"
+
+class AutomationAutocompleteEditTracker:
+ public AutomationResourceTracker<AutocompleteEdit*> {
+ public:
+ explicit AutomationAutocompleteEditTracker(IPC::Message::Sender* automation)
+ : AutomationResourceTracker(automation) { }
+
+ virtual ~AutomationAutocompleteEditTracker() {
+ ClearAllMappings();
+ }
+
+ virtual void AddObserver(AutocompleteEdit* resource) {
+ NotificationService::current()->AddObserver(
+ this, NOTIFY_AUTOCOMPLETE_EDIT_DESTROYED,
+ Source<AutocompleteEdit>(resource));
+ }
+
+ virtual void RemoveObserver(AutocompleteEdit* resource) {
+ NotificationService::current()->RemoveObserver(
+ this, NOTIFY_AUTOCOMPLETE_EDIT_DESTROYED,
+ Source<AutocompleteEdit>(resource));
+ }
+};
+
+#endif // CHROME_BROWSER_AUTOMATION_AUTOMATION_AUTOCOMPLETE_EDIT_TRACKER_H__
diff --git a/chrome/browser/automation/automation_browser_tracker.h b/chrome/browser/automation/automation_browser_tracker.h
new file mode 100644
index 0000000..2a4dfd9
--- /dev/null
+++ b/chrome/browser/automation/automation_browser_tracker.h
@@ -0,0 +1,58 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef CHROME_BROWSER_AUTOMATION_AUTOMATION_BROWSER_TRACKER_H__
+#define CHROME_BROWSER_AUTOMATION_AUTOMATION_BROWSER_TRACKER_H__
+
+#include "chrome/browser/automation/automation_resource_tracker.h"
+#include "chrome/browser/browser.h"
+#include "chrome/browser/browser_process.h"
+
+// Tracks Browser objects.
+class AutomationBrowserTracker : public AutomationResourceTracker<Browser*> {
+public:
+ AutomationBrowserTracker(IPC::Message::Sender* automation)
+ : AutomationResourceTracker(automation) { }
+
+ virtual ~AutomationBrowserTracker() {
+ ClearAllMappings();
+ }
+
+ virtual void AddObserver(Browser* resource) {
+ NotificationService::current()->AddObserver(
+ this, NOTIFY_BROWSER_CLOSED, Source<Browser>(resource));
+ }
+
+ virtual void RemoveObserver(Browser* resource) {
+ NotificationService::current()->RemoveObserver(
+ this, NOTIFY_BROWSER_CLOSED, Source<Browser>(resource));
+ }
+};
+
+#endif // CHROME_BROWSER_AUTOMATION_AUTOMATION_BROWSER_TRACKER_H__
diff --git a/chrome/browser/automation/automation_constrained_window_tracker.h b/chrome/browser/automation/automation_constrained_window_tracker.h
new file mode 100644
index 0000000..e6abd94
--- /dev/null
+++ b/chrome/browser/automation/automation_constrained_window_tracker.h
@@ -0,0 +1,59 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef CHROME_BROWSER_AUTOMATION_AUTOMATION_CONSTRAINED_WINDOW_TRACKER_H__
+#define CHROME_BROWSER_AUTOMATION_AUTOMATION_CONSTRAINED_WINDOW_TRACKER_H__
+
+#include "chrome/browser/automation/automation_resource_tracker.h"
+#include "chrome/browser/browser.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/constrained_window.h"
+
+class AutomationConstrainedWindowTracker
+ : public AutomationResourceTracker<ConstrainedWindow*> {
+public:
+ AutomationConstrainedWindowTracker(IPC::Message::Sender* automation)
+ : AutomationResourceTracker(automation) {}
+
+ virtual ~AutomationConstrainedWindowTracker() {
+ ClearAllMappings();
+ }
+
+ virtual void AddObserver(ConstrainedWindow* resource) {
+ NotificationService::current()->AddObserver(
+ this, NOTIFY_CWINDOW_CLOSED, Source<ConstrainedWindow>(resource));
+ }
+
+ virtual void RemoveObserver(ConstrainedWindow* resource) {
+ NotificationService::current()->RemoveObserver(
+ this, NOTIFY_CWINDOW_CLOSED, Source<ConstrainedWindow>(resource));
+ }
+};
+
+#endif // CHROME_BROWSER_AUTOMATION_AUTOMATION_CONSTRAINED_WINDOW_TRACKER_H__ \ No newline at end of file
diff --git a/chrome/browser/automation/automation_provider.cc b/chrome/browser/automation/automation_provider.cc
new file mode 100644
index 0000000..03abe8b
--- /dev/null
+++ b/chrome/browser/automation/automation_provider.cc
@@ -0,0 +1,2172 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "chrome/browser/automation/automation_provider.h"
+
+#include "base/path_service.h"
+#include "chrome/browser/automation/automation_provider_list.h"
+#include "chrome/browser/automation/ui_controls.h"
+#include "chrome/browser/automation/url_request_failed_dns_job.h"
+#include "chrome/browser/automation/url_request_mock_http_job.h"
+#include "chrome/browser/automation/url_request_slow_download_job.h"
+#include "chrome/browser/chrome_frame.h"
+#include "chrome/browser/dom_operation_notification_details.h"
+#include "chrome/browser/download_manager.h"
+#include "chrome/browser/external_tab_container.h"
+#include "chrome/browser/find_notification_details.h"
+#include "chrome/browser/login_prompt.h"
+#include "chrome/browser/navigation_entry.h"
+#include "chrome/browser/printing/print_job.h"
+#include "chrome/browser/save_package.h"
+#include "chrome/browser/ssl_blocking_page.h"
+#include "chrome/common/chrome_paths.h"
+#include "chrome/test/automation/automation_messages.h"
+#include "net/base/cookie_monster.h"
+#include "net/url_request/url_request_filter.h"
+
+class InitialLoadObserver : public NotificationObserver {
+ public:
+ InitialLoadObserver(size_t tab_count, AutomationProvider* automation)
+ : outstanding_tab_count_(tab_count),
+ automation_(automation) {
+ if (outstanding_tab_count_ > 0) {
+ NotificationService* service = NotificationService::current();
+ service->AddObserver(this, NOTIFY_LOAD_START,
+ NotificationService::AllSources());
+ service->AddObserver(this, NOTIFY_LOAD_STOP,
+ NotificationService::AllSources());
+ }
+ }
+
+ ~InitialLoadObserver() {
+ Unregister();
+ }
+
+ void ConditionMet() {
+ Unregister();
+ automation_->Send(new AutomationMsg_InitialLoadsComplete(0));
+ }
+
+ void Unregister() {
+ NotificationService* service = NotificationService::current();
+ service->RemoveObserver(this, NOTIFY_LOAD_START,
+ NotificationService::AllSources());
+ service->RemoveObserver(this, NOTIFY_LOAD_STOP,
+ NotificationService::AllSources());
+ }
+
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ if (type == NOTIFY_LOAD_START) {
+ if (outstanding_tab_count_ > loading_tabs_.size())
+ loading_tabs_.insert(source.map_key());
+ } else if (type == NOTIFY_LOAD_STOP) {
+ if (outstanding_tab_count_ > finished_tabs_.size()) {
+ if (loading_tabs_.find(source.map_key()) != loading_tabs_.end())
+ finished_tabs_.insert(source.map_key());
+ if (outstanding_tab_count_ == finished_tabs_.size())
+ ConditionMet();
+ }
+ } else {
+ NOTREACHED();
+ }
+ }
+
+ private:
+ typedef std::set<uintptr_t> TabSet;
+
+ AutomationProvider* automation_;
+ size_t outstanding_tab_count_;
+ TabSet loading_tabs_;
+ TabSet finished_tabs_;
+};
+
+// Watches for NewTabUI page loads for performance timing purposes.
+class NewTabUILoadObserver : public NotificationObserver {
+ public:
+ explicit NewTabUILoadObserver(AutomationProvider* automation)
+ : automation_(automation) {
+ NotificationService::current()->
+ AddObserver(this, NOTIFY_INITIAL_NEW_TAB_UI_LOAD,
+ NotificationService::AllSources());
+ }
+
+ ~NewTabUILoadObserver() {
+ Unregister();
+ }
+
+ void Unregister() {
+ NotificationService::current()->
+ RemoveObserver(this, NOTIFY_INITIAL_NEW_TAB_UI_LOAD,
+ NotificationService::AllSources());
+ }
+
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ if (type == NOTIFY_INITIAL_NEW_TAB_UI_LOAD) {
+ Details<int> load_time(details);
+ automation_->Send(
+ new AutomationMsg_InitialNewTabUILoadComplete(0, *load_time.ptr()));
+ } else {
+ NOTREACHED();
+ }
+ }
+
+ private:
+ AutomationProvider* automation_;
+};
+
+class NavigationControllerRestoredObserver : public NotificationObserver {
+ public:
+ NavigationControllerRestoredObserver(AutomationProvider* automation,
+ NavigationController* controller,
+ int32 routing_id)
+ : automation_(automation),
+ controller_(controller),
+ routing_id_(routing_id) {
+ if (FinishedRestoring()) {
+ registered_ = false;
+ SendDone();
+ } else {
+ registered_ = true;
+ NotificationService* service = NotificationService::current();
+ service->AddObserver(this, NOTIFY_LOAD_STOP,
+ NotificationService::AllSources());
+ }
+ }
+
+ ~NavigationControllerRestoredObserver() {
+ if (registered_)
+ Unregister();
+ }
+
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ if (FinishedRestoring()) {
+ SendDone();
+ Unregister();
+ }
+ }
+
+ private:
+ void Unregister() {
+ NotificationService* service = NotificationService::current();
+ service->RemoveObserver(this, NOTIFY_LOAD_STOP,
+ NotificationService::AllSources());
+ registered_ = false;
+ }
+
+ bool FinishedRestoring() {
+ return (!controller_->needs_reload() && !controller_->GetPendingEntry() &&
+ !controller_->active_contents()->IsLoading());
+ }
+
+ void SendDone() {
+ automation_->Send(new AutomationMsg_TabFinishedRestoring(routing_id_));
+ }
+
+ bool registered_;
+ AutomationProvider* automation_;
+ NavigationController* controller_;
+ const int routing_id_;
+
+ DISALLOW_EVIL_CONSTRUCTORS(NavigationControllerRestoredObserver);
+};
+
+
+class NavigationNotificationObserver : public NotificationObserver {
+ public:
+ NavigationNotificationObserver(NavigationController* controller,
+ AutomationProvider* automation,
+ IPC::Message* completed_response,
+ IPC::Message* auth_needed_response)
+ : automation_(automation),
+ completed_response_(completed_response),
+ auth_needed_response_(auth_needed_response),
+ controller_(controller),
+ navigation_started_(false) {
+ NotificationService* service = NotificationService::current();
+ service->AddObserver(this, NOTIFY_LOAD_START,
+ Source<NavigationController>(controller_));
+ service->AddObserver(this, NOTIFY_LOAD_STOP,
+ Source<NavigationController>(controller_));
+ service->AddObserver(this, NOTIFY_AUTH_NEEDED,
+ Source<NavigationController>(controller_));
+ service->AddObserver(this, NOTIFY_AUTH_SUPPLIED,
+ Source<NavigationController>(controller_));
+ }
+
+ ~NavigationNotificationObserver() {
+ if (completed_response_) delete completed_response_;
+ if (auth_needed_response_) delete auth_needed_response_;
+ Unregister();
+ }
+
+ void ConditionMet(IPC::Message** response) {
+ if (*response) {
+ automation_->Send(*response);
+ *response = NULL; // *response is deleted by Send.
+ }
+ automation_->RemoveNavigationStatusListener(this);
+ delete this;
+ }
+
+ void Unregister() {
+ NotificationService* service = NotificationService::current();
+ service->RemoveObserver(this, NOTIFY_LOAD_START,
+ Source<NavigationController>(controller_));
+ service->RemoveObserver(this, NOTIFY_LOAD_STOP,
+ Source<NavigationController>(controller_));
+ service->RemoveObserver(this, NOTIFY_AUTH_NEEDED,
+ Source<NavigationController>(controller_));
+ service->RemoveObserver(this, NOTIFY_AUTH_SUPPLIED,
+ Source<NavigationController>(controller_));
+ }
+
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ if (type == NOTIFY_LOAD_START) {
+ navigation_started_ = true;
+ } else if (type == NOTIFY_LOAD_STOP) {
+ if (navigation_started_) {
+ navigation_started_ = false;
+ ConditionMet(&completed_response_);
+ }
+ } else if (type == NOTIFY_AUTH_SUPPLIED) {
+ // The LoginHandler for this tab is no longer valid.
+ automation_->RemoveLoginHandler(controller_);
+
+ // Treat this as if navigation started again, since load start/stop don't
+ // occur while authentication is ongoing.
+ navigation_started_ = true;
+ } else if (type == NOTIFY_AUTH_NEEDED) {
+ if (navigation_started_) {
+ // Remember the login handler that wants authentication.
+ LoginHandler* handler =
+ Details<LoginNotificationDetails>(details)->handler();
+ automation_->AddLoginHandler(controller_, handler);
+
+ // Respond that authentication is needed.
+ navigation_started_ = false;
+ ConditionMet(&auth_needed_response_);
+ } else {
+ NOTREACHED();
+ }
+ } else {
+ NOTREACHED();
+ }
+ }
+
+ private:
+ AutomationProvider* automation_;
+ IPC::Message* completed_response_;
+ IPC::Message* auth_needed_response_;
+ NavigationController* controller_;
+ bool navigation_started_;
+};
+
+class TabStripNotificationObserver : public NotificationObserver {
+ public:
+ TabStripNotificationObserver(Browser* parent, NotificationType notification,
+ AutomationProvider* automation, int32 routing_id)
+ : automation_(automation),
+ notification_(notification),
+ parent_(parent),
+ routing_id_(routing_id) {
+ NotificationService::current()->
+ AddObserver(this, notification_, NotificationService::AllSources());
+ }
+
+ virtual ~TabStripNotificationObserver() {
+ Unregister();
+ }
+
+ void Unregister() {
+ NotificationService::current()->
+ RemoveObserver(this, notification_, NotificationService::AllSources());
+ }
+
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ if (type == notification_) {
+ ObserveTab(Source<NavigationController>(source).ptr());
+
+ // If verified, no need to observe anymore
+ automation_->RemoveTabStripObserver(this);
+ delete this;
+ } else {
+ NOTREACHED();
+ }
+ }
+
+ virtual void ObserveTab(NavigationController* controller) = 0;
+
+ protected:
+ AutomationProvider* automation_;
+ Browser* parent_;
+ NotificationType notification_;
+ int32 routing_id_;
+};
+
+class TabAppendedNotificationObserver : public TabStripNotificationObserver {
+ public:
+ TabAppendedNotificationObserver(Browser* parent,
+ AutomationProvider* automation, int32 routing_id)
+ : TabStripNotificationObserver(parent, NOTIFY_TAB_APPENDED, automation,
+ routing_id) {
+ }
+
+ virtual void ObserveTab(NavigationController* controller) {
+ int tab_index =
+ automation_->GetIndexForNavigationController(controller, parent_);
+ if (tab_index == TabStripModel::kNoTab) {
+ // This tab notification doesn't belong to the parent_
+ return;
+ }
+
+ // Give the same response even if auth is needed, since it doesn't matter.
+ automation_->AddNavigationStatusListener(controller,
+ new AutomationMsg_AppendTabResponse(routing_id_, tab_index),
+ new AutomationMsg_AppendTabResponse(routing_id_, tab_index));
+ }
+};
+
+class TabClosedNotificationObserver : public TabStripNotificationObserver {
+ public:
+ TabClosedNotificationObserver(Browser* parent,
+ AutomationProvider* automation,
+ int32 routing_id,
+ bool wait_until_closed)
+ : TabStripNotificationObserver(parent,
+ wait_until_closed ? NOTIFY_TAB_CLOSED :
+ NOTIFY_TAB_CLOSING,
+ automation,
+ routing_id) {
+ }
+
+ virtual void ObserveTab(NavigationController* controller) {
+ automation_->Send(new AutomationMsg_CloseTabResponse(routing_id_, true));
+ }
+};
+
+class BrowserClosedNotificationObserver : public NotificationObserver {
+ public:
+ BrowserClosedNotificationObserver(Browser* browser,
+ AutomationProvider* automation,
+ int32 routing_id)
+ : automation_(automation),
+ routing_id_(routing_id) {
+ NotificationService::current()->
+ AddObserver(this, NOTIFY_BROWSER_CLOSED, Source<Browser>(browser));
+ }
+
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ DCHECK(type == NOTIFY_BROWSER_CLOSED);
+ Details<bool> close_app(details);
+ automation_->Send(
+ new AutomationMsg_CloseBrowserResponse(routing_id_,
+ true,
+ *(close_app.ptr())));
+ delete this;
+ }
+
+ private:
+ AutomationProvider* automation_;
+ int32 routing_id_;
+};
+
+class FindInPageNotificationObserver : public NotificationObserver {
+ public:
+ FindInPageNotificationObserver(AutomationProvider* automation,
+ TabContents* parent_tab,
+ int32 routing_id)
+ : automation_(automation),
+ parent_tab_(parent_tab),
+ routing_id_(routing_id) {
+ NotificationService::current()->
+ AddObserver(this, NOTIFY_FIND_RESULT_AVAILABLE,
+ Source<TabContents>(parent_tab_));
+ }
+
+ ~FindInPageNotificationObserver() {
+ Unregister();
+ }
+
+ void Unregister() {
+ NotificationService::current()->
+ RemoveObserver(this, NOTIFY_FIND_RESULT_AVAILABLE,
+ Source<TabContents>(parent_tab_));
+ }
+
+ virtual void Observe(NotificationType type, const NotificationSource& source,
+ const NotificationDetails& details) {
+ if (type == NOTIFY_FIND_RESULT_AVAILABLE) {
+ Details<FindNotificationDetails> find_details(details);
+ if (find_details->request_id() == kFindInPageRequestId) {
+ if (find_details->final_update()) {
+ automation_->Send(new AutomationMsg_FindInPageResponse(routing_id_,
+ find_details->number_of_matches()));
+ } else {
+ DLOG(INFO) << "Ignoring, since we only care about the final message";
+ }
+ }
+ } else {
+ NOTREACHED();
+ }
+ }
+
+ // The Find mechanism is over asynchronous IPC, so a search is kicked off and
+ // we wait for notification to find out what the results are. As the user is
+ // typing, new search requests can be issued and the Request ID helps us make
+ // sense of whether this is the current request or an old one. The unit tests,
+ // however, which uses this constant issues only one search at a time, so we
+ // don't need a rolling id to identify each search. But, we still need to
+ // specify one, so we just use a fixed one - its value does not matter.
+ static const int kFindInPageRequestId;
+ private:
+ AutomationProvider* automation_;
+ TabContents* parent_tab_;
+ int32 routing_id_;
+};
+
+const int FindInPageNotificationObserver::kFindInPageRequestId = -1;
+
+class DomOperationNotificationObserver : public NotificationObserver {
+ public:
+ explicit DomOperationNotificationObserver(AutomationProvider* automation)
+ : automation_(automation) {
+ NotificationService::current()->
+ AddObserver(this, NOTIFY_DOM_OPERATION_RESPONSE,
+ NotificationService::AllSources());
+ }
+
+ ~DomOperationNotificationObserver() {
+ NotificationService::current()->
+ RemoveObserver(this, NOTIFY_DOM_OPERATION_RESPONSE,
+ NotificationService::AllSources());
+ }
+
+ virtual void Observe(NotificationType type, const NotificationSource& source,
+ const NotificationDetails& details) {
+ if (NOTIFY_DOM_OPERATION_RESPONSE == type) {
+ Details<DomOperationNotificationDetails> dom_op_details(details);
+ automation_->Send(new AutomationMsg_DomOperationResponse(
+ dom_op_details->automation_id(),
+ dom_op_details->json()));
+ }
+ }
+ private:
+ AutomationProvider* automation_;
+};
+
+class DomInspectorNotificationObserver : public NotificationObserver {
+ public:
+ explicit DomInspectorNotificationObserver(AutomationProvider* automation)
+ : automation_(automation) {
+ NotificationService::current()->
+ AddObserver(this, NOTIFY_DOM_INSPECT_ELEMENT_RESPONSE,
+ NotificationService::AllSources());
+ }
+
+ ~DomInspectorNotificationObserver() {
+ NotificationService::current()->
+ RemoveObserver(this, NOTIFY_DOM_INSPECT_ELEMENT_RESPONSE,
+ NotificationService::AllSources());
+ }
+
+ virtual void Observe(NotificationType type, const NotificationSource& source,
+ const NotificationDetails& details) {
+ if (NOTIFY_DOM_INSPECT_ELEMENT_RESPONSE == type) {
+ Details<int> dom_inspect_details(details);
+ automation_->ReceivedInspectElementResponse(*(dom_inspect_details.ptr()));
+ }
+ }
+
+ private:
+ AutomationProvider* automation_;
+};
+
+class DocumentPrintedNotificationObserver : public NotificationObserver {
+ public:
+ DocumentPrintedNotificationObserver(AutomationProvider* automation,
+ int32 routing_id)
+ : automation_(automation),
+ routing_id_(routing_id),
+ success_(false) {
+ NotificationService::current()->
+ AddObserver(this, NOTIFY_PRINT_JOB_EVENT,
+ NotificationService::AllSources());
+ }
+
+ ~DocumentPrintedNotificationObserver() {
+ automation_->Send(
+ new AutomationMsg_PrintNowResponse(routing_id_, success_));
+ automation_->RemoveNavigationStatusListener(this);
+ NotificationService::current()->
+ RemoveObserver(this, NOTIFY_PRINT_JOB_EVENT,
+ NotificationService::AllSources());
+ }
+
+ virtual void Observe(NotificationType type, const NotificationSource& source,
+ const NotificationDetails& details) {
+ using namespace printing;
+ DCHECK(type == NOTIFY_PRINT_JOB_EVENT);
+ switch (Details<JobEventDetails>(details)->type()) {
+ case JobEventDetails::JOB_DONE: {
+ // Succeeded.
+ success_ = true;
+ delete this;
+ break;
+ }
+ case JobEventDetails::USER_INIT_CANCELED:
+ case JobEventDetails::FAILED: {
+ // Failed.
+ delete this;
+ break;
+ }
+ case JobEventDetails::NEW_DOC:
+ case JobEventDetails::USER_INIT_DONE:
+ case JobEventDetails::DEFAULT_INIT_DONE:
+ case JobEventDetails::NEW_PAGE:
+ case JobEventDetails::PAGE_DONE:
+ case JobEventDetails::DOC_DONE:
+ case JobEventDetails::ALL_PAGES_REQUESTED: {
+ // Don't care.
+ break;
+ }
+ default: {
+ NOTREACHED();
+ break;
+ }
+ }
+ }
+
+ private:
+ scoped_refptr<AutomationProvider> automation_;
+ int32 routing_id_;
+ bool success_;
+};
+
+AutomationProvider::AutomationProvider(Profile* profile)
+ : connected_(false),
+ redirect_query_(0),
+ profile_(profile) {
+ AutomationProviderList* list =
+ g_browser_process->InitAutomationProviderList();
+ DCHECK(NULL != list);
+ list->AddProvider(this);
+ browser_tracker_.reset(new AutomationBrowserTracker(this));
+ window_tracker_.reset(new AutomationWindowTracker(this));
+ tab_tracker_.reset(new AutomationTabTracker(this));
+ autocomplete_edit_tracker_.reset(
+ new AutomationAutocompleteEditTracker(this));
+ cwindow_tracker_.reset(new AutomationConstrainedWindowTracker(this));
+ new_tab_ui_load_observer_.reset(new NewTabUILoadObserver(this));
+ dom_operation_observer_.reset(new DomOperationNotificationObserver(this));
+ dom_inspector_observer_.reset(new DomInspectorNotificationObserver(this));
+}
+
+AutomationProvider::~AutomationProvider() {
+ // TODO(vibhor) : Delete the pending observer objects.
+ AutomationProviderList* list =
+ g_browser_process->InitAutomationProviderList();
+ DCHECK(NULL != list);
+ list->RemoveProvider(this);
+}
+
+void AutomationProvider::ConnectToChannel(const std::wstring& channel_id) {
+ scoped_ptr<IPC::Channel> channel(
+ new IPC::Channel(channel_id, IPC::Channel::MODE_CLIENT, this));
+ connected_ = channel->Connect();
+ if (connected_) {
+ channel_.swap(channel);
+ channel_->Send(new AutomationMsg_Hello(0));
+ }
+}
+
+void AutomationProvider::SetExpectedTabCount(size_t expected_tabs) {
+ if (expected_tabs == 0) {
+ Send(new AutomationMsg_InitialLoadsComplete(0));
+ } else {
+ initial_load_observer_.reset(new InitialLoadObserver(expected_tabs, this));
+ }
+}
+
+NotificationObserver* AutomationProvider::AddNavigationStatusListener(
+ NavigationController* tab, IPC::Message* completed_response,
+ IPC::Message* auth_needed_response) {
+ NotificationObserver* observer =
+ new NavigationNotificationObserver(tab, this, completed_response,
+ auth_needed_response);
+ notification_observer_list_.AddObserver(observer);
+
+ return observer;
+}
+
+void AutomationProvider::RemoveNavigationStatusListener(
+ NotificationObserver* obs) {
+ notification_observer_list_.RemoveObserver(obs);
+}
+
+NotificationObserver* AutomationProvider::AddTabStripObserver(
+ Browser* parent, int32 routing_id) {
+ NotificationObserver* observer = new
+ TabAppendedNotificationObserver(parent, this, routing_id);
+ notification_observer_list_.AddObserver(observer);
+
+ return observer;
+}
+
+void AutomationProvider::RemoveTabStripObserver(NotificationObserver* obs) {
+ notification_observer_list_.RemoveObserver(obs);
+}
+
+void AutomationProvider::AddLoginHandler(NavigationController* tab,
+ LoginHandler* handler) {
+ login_handler_map_[tab] = handler;
+}
+
+void AutomationProvider::RemoveLoginHandler(NavigationController* tab) {
+ DCHECK(login_handler_map_[tab]);
+ login_handler_map_.erase(tab);
+}
+
+int AutomationProvider::GetIndexForNavigationController(
+ const NavigationController* controller, const Browser* parent) const {
+ DCHECK(parent);
+ return parent->GetIndexOfController(controller);
+}
+
+void AutomationProvider::OnMessageReceived(const IPC::Message& message) {
+ IPC_BEGIN_MESSAGE_MAP(AutomationProvider, message)
+ IPC_MESSAGE_HANDLER(AutomationMsg_CloseBrowserRequest, CloseBrowser)
+ IPC_MESSAGE_HANDLER(AutomationMsg_ActivateTabRequest, ActivateTab)
+ IPC_MESSAGE_HANDLER(AutomationMsg_ActiveTabIndexRequest, GetActiveTabIndex)
+ IPC_MESSAGE_HANDLER(AutomationMsg_AppendTabRequest, AppendTab)
+ IPC_MESSAGE_HANDLER(AutomationMsg_CloseTabRequest, CloseTab)
+ IPC_MESSAGE_HANDLER(AutomationMsg_GetCookiesRequest, GetCookies)
+ IPC_MESSAGE_HANDLER(AutomationMsg_SetCookieRequest, SetCookie)
+ IPC_MESSAGE_HANDLER(AutomationMsg_NavigateToURLRequest, NavigateToURL)
+ IPC_MESSAGE_HANDLER(AutomationMsg_NavigationAsyncRequest, NavigationAsync)
+ IPC_MESSAGE_HANDLER(AutomationMsg_GoBackRequest, GoBack)
+ IPC_MESSAGE_HANDLER(AutomationMsg_GoForwardRequest, GoForward)
+ IPC_MESSAGE_HANDLER(AutomationMsg_ReloadRequest, Reload)
+ IPC_MESSAGE_HANDLER(AutomationMsg_SetAuthRequest, SetAuth)
+ IPC_MESSAGE_HANDLER(AutomationMsg_CancelAuthRequest, CancelAuth)
+ IPC_MESSAGE_HANDLER(AutomationMsg_NeedsAuthRequest, NeedsAuth)
+ IPC_MESSAGE_HANDLER(AutomationMsg_RedirectsFromRequest, GetRedirectsFrom)
+ IPC_MESSAGE_HANDLER(AutomationMsg_BrowserWindowCountRequest,
+ GetBrowserWindowCount)
+ IPC_MESSAGE_HANDLER(AutomationMsg_BrowserWindowRequest, GetBrowserWindow)
+ IPC_MESSAGE_HANDLER(AutomationMsg_LastActiveBrowserWindowRequest,
+ GetLastActiveBrowserWindow)
+ IPC_MESSAGE_HANDLER(AutomationMsg_ActiveWindowRequest, GetActiveWindow)
+ IPC_MESSAGE_HANDLER(AutomationMsg_IsWindowActiveRequest, IsWindowActive)
+ IPC_MESSAGE_HANDLER(AutomationMsg_ActivateWindow, ActivateWindow);
+ IPC_MESSAGE_HANDLER(AutomationMsg_WindowHWNDRequest, GetWindowHWND)
+ IPC_MESSAGE_HANDLER(AutomationMsg_WindowViewBoundsRequest,
+ WindowGetViewBounds)
+ IPC_MESSAGE_HANDLER(AutomationMsg_SetWindowVisibleRequest, SetWindowVisible)
+ IPC_MESSAGE_HANDLER(AutomationMsg_WindowClickRequest, WindowSimulateClick)
+ IPC_MESSAGE_HANDLER(AutomationMsg_WindowKeyPressRequest,
+ WindowSimulateKeyPress)
+ IPC_MESSAGE_HANDLER(AutomationMsg_WindowDragRequest, WindowSimulateDrag)
+ IPC_MESSAGE_HANDLER(AutomationMsg_TabCountRequest, GetTabCount)
+ IPC_MESSAGE_HANDLER(AutomationMsg_TabRequest, GetTab)
+ IPC_MESSAGE_HANDLER(AutomationMsg_TabHWNDRequest, GetTabHWND)
+ IPC_MESSAGE_HANDLER(AutomationMsg_TabProcessIDRequest, GetTabProcessID)
+ IPC_MESSAGE_HANDLER(AutomationMsg_TabTitleRequest, GetTabTitle)
+ IPC_MESSAGE_HANDLER(AutomationMsg_TabURLRequest, GetTabURL)
+ IPC_MESSAGE_HANDLER(AutomationMsg_ShelfVisibilityRequest,
+ GetShelfVisibility)
+ IPC_MESSAGE_HANDLER(AutomationMsg_HandleUnused, HandleUnused)
+ IPC_MESSAGE_HANDLER(AutomationMsg_ApplyAcceleratorRequest, ApplyAccelerator)
+ IPC_MESSAGE_HANDLER(AutomationMsg_DomOperationRequest, ExecuteJavascript)
+ IPC_MESSAGE_HANDLER(AutomationMsg_ConstrainedWindowCountRequest,
+ GetConstrainedWindowCount)
+ IPC_MESSAGE_HANDLER(AutomationMsg_ConstrainedWindowRequest,
+ GetConstrainedWindow)
+ IPC_MESSAGE_HANDLER(AutomationMsg_ConstrainedTitleRequest,
+ GetConstrainedTitle)
+ IPC_MESSAGE_HANDLER(AutomationMsg_FindInPageRequest,
+ HandleFindInPageRequest)
+ IPC_MESSAGE_HANDLER(AutomationMsg_GetFocusedViewIDRequest, GetFocusedViewID)
+ IPC_MESSAGE_HANDLER(AutomationMsg_InspectElementRequest,
+ HandleInspectElementRequest)
+ IPC_MESSAGE_HANDLER(AutomationMsg_SetFilteredInet,
+ SetFilteredInet);
+ IPC_MESSAGE_HANDLER(AutomationMsg_DownloadDirectoryRequest,
+ GetDownloadDirectory);
+ IPC_MESSAGE_HANDLER(AutomationMsg_OpenNewBrowserWindow,
+ OpenNewBrowserWindow);
+ IPC_MESSAGE_HANDLER(AutomationMsg_WindowForBrowserRequest,
+ GetWindowForBrowser);
+ IPC_MESSAGE_HANDLER(AutomationMsg_AutocompleteEditForBrowserRequest,
+ GetAutocompleteEditForBrowser);
+ IPC_MESSAGE_HANDLER(AutomationMsg_BrowserForWindowRequest,
+ GetBrowserForWindow);
+ IPC_MESSAGE_HANDLER(AutomationMsg_CreateExternalTab, CreateExternalTab)
+ IPC_MESSAGE_HANDLER(AutomationMsg_NavigateInExternalTabRequest,
+ NavigateInExternalTab)
+ IPC_MESSAGE_HANDLER(AutomationMsg_ShowInterstitialPageRequest,
+ ShowInterstitialPage);
+ IPC_MESSAGE_HANDLER(AutomationMsg_HideInterstitialPageRequest,
+ HideInterstitialPage);
+ IPC_MESSAGE_HANDLER(AutomationMsg_SetAcceleratorsForTab,
+ SetAcceleratorsForTab)
+ IPC_MESSAGE_HANDLER(AutomationMsg_ProcessUnhandledAccelerator,
+ ProcessUnhandledAccelerator)
+ IPC_MESSAGE_HANDLER(AutomationMsg_WaitForTabToBeRestored,
+ WaitForTabToBeRestored)
+ IPC_MESSAGE_HANDLER(AutomationMsg_GetSecurityState,
+ GetSecurityState)
+ IPC_MESSAGE_HANDLER(AutomationMsg_GetPageType,
+ GetPageType)
+ IPC_MESSAGE_HANDLER(AutomationMsg_ActionOnSSLBlockingPage,
+ ActionOnSSLBlockingPage)
+ IPC_MESSAGE_HANDLER(AutomationMsg_BringBrowserToFront, BringBrowserToFront)
+ IPC_MESSAGE_HANDLER(AutomationMsg_IsPageMenuCommandEnabled,
+ IsPageMenuCommandEnabled)
+ IPC_MESSAGE_HANDLER(AutomationMsg_PrintNowRequest, PrintNow)
+ IPC_MESSAGE_HANDLER(AutomationMsg_SavePageRequest, SavePage)
+ IPC_MESSAGE_HANDLER(AutomationMsg_AutocompleteEditGetTextRequest,
+ GetAutocompleteEditText)
+ IPC_MESSAGE_HANDLER(AutomationMsg_AutocompleteEditSetTextRequest,
+ SetAutocompleteEditText)
+ IPC_MESSAGE_HANDLER(AutomationMsg_AutocompleteEditIsQueryInProgressRequest,
+ AutocompleteEditIsQueryInProgress)
+ IPC_MESSAGE_HANDLER(AutomationMsg_AutocompleteEditGetMatchesRequest,
+ AutocompleteEditGetMatches)
+ IPC_MESSAGE_HANDLER(AutomationMsg_ConstrainedWindowBoundsRequest,
+ GetConstrainedWindowBounds)
+ IPC_END_MESSAGE_MAP()
+}
+
+void AutomationProvider::ActivateTab(const IPC::Message& message,
+ int handle, int at_index) {
+ int status = -1;
+ if (browser_tracker_->ContainsHandle(handle) && at_index > -1) {
+ Browser* browser = browser_tracker_->GetResource(handle);
+ if (at_index >= 0 && at_index < browser->tab_count()) {
+ browser->SelectTabContentsAt(at_index, true);
+ status = 0;
+ }
+ }
+ Send(new AutomationMsg_ActivateTabResponse(message.routing_id(), status));
+}
+
+void AutomationProvider::AppendTab(const IPC::Message& message,
+ int handle, const GURL& url) {
+ int append_tab_response = -1; // -1 is the error code
+ NotificationObserver* observer = NULL;
+
+ if (browser_tracker_->ContainsHandle(handle)) {
+ Browser* browser = browser_tracker_->GetResource(handle);
+ observer = AddTabStripObserver(browser, message.routing_id());
+ TabContents* tab_contents =
+ browser->AddTabWithURL(url, PageTransition::TYPED, true, NULL);
+ if (tab_contents) {
+ append_tab_response =
+ GetIndexForNavigationController(tab_contents->controller(), browser);
+ }
+ }
+
+ if (append_tab_response < 0) {
+ // The append tab failed. Remove the TabStripObserver
+ if (observer) {
+ RemoveTabStripObserver(observer);
+ delete observer;
+ }
+
+ // This will be reached only if the tab could not be appended. In case of a
+ // successful tab append, a successful navigation notification triggers the
+ // send.
+ Send(new AutomationMsg_AppendTabResponse(message.routing_id(),
+ append_tab_response));
+ }
+}
+
+void AutomationProvider::NavigateToURL(const IPC::Message& message,
+ int handle, const GURL& url) {
+ int status = AUTOMATION_MSG_NAVIGATION_ERROR;
+
+ if (tab_tracker_->ContainsHandle(handle)) {
+ NavigationController* tab = tab_tracker_->GetResource(handle);
+
+ // Simulate what a user would do. Activate the tab and then navigate.
+ // We could allow navigating in a background tab in future.
+ Browser* browser = FindAndActivateTab(tab);
+
+ if (browser) {
+ AddNavigationStatusListener(tab,
+ new AutomationMsg_NavigateToURLResponse(
+ message.routing_id(), AUTOMATION_MSG_NAVIGATION_SUCCESS),
+ new AutomationMsg_NavigateToURLResponse(
+ message.routing_id(), AUTOMATION_MSG_NAVIGATION_AUTH_NEEDED));
+ // TODO(darin): avoid conversion to GURL
+ browser->OpenURL(url, CURRENT_TAB, PageTransition::TYPED);
+ return;
+ }
+ }
+ Send(new AutomationMsg_NavigateToURLResponse(
+ message.routing_id(), AUTOMATION_MSG_NAVIGATION_ERROR));
+}
+
+void AutomationProvider::NavigationAsync(const IPC::Message& message,
+ int handle, const GURL& url) {
+ bool status = false;
+
+ if (tab_tracker_->ContainsHandle(handle)) {
+ NavigationController* tab = tab_tracker_->GetResource(handle);
+
+ // Simulate what a user would do. Activate the tab and then navigate.
+ // We could allow navigating in a background tab in future.
+ Browser* browser = FindAndActivateTab(tab);
+
+ if (browser) {
+ // Don't add any listener unless a callback mechanism is desired.
+ // TODO(vibhor): Do this if such a requirement arises in future.
+ browser->OpenURL(url, CURRENT_TAB, PageTransition::TYPED);
+ status = true;
+ }
+ }
+
+ Send(new AutomationMsg_NavigationAsyncResponse(message.routing_id(), status));
+}
+
+void AutomationProvider::GoBack(const IPC::Message& message, int handle) {
+ if (tab_tracker_->ContainsHandle(handle)) {
+ NavigationController* tab = tab_tracker_->GetResource(handle);
+ Browser* browser = FindAndActivateTab(tab);
+ if (browser && browser->IsCommandEnabled(IDC_BACK)) {
+ AddNavigationStatusListener(tab,
+ new AutomationMsg_GoBackResponse(
+ message.routing_id(), AUTOMATION_MSG_NAVIGATION_SUCCESS),
+ new AutomationMsg_GoBackResponse(
+ message.routing_id(), AUTOMATION_MSG_NAVIGATION_AUTH_NEEDED));
+ browser->GoBack();
+ return;
+ }
+ }
+ Send(new AutomationMsg_GoBackResponse(message.routing_id(),
+ AUTOMATION_MSG_NAVIGATION_ERROR));
+}
+
+void AutomationProvider::GoForward(const IPC::Message& message, int handle) {
+ if (tab_tracker_->ContainsHandle(handle)) {
+ NavigationController* tab = tab_tracker_->GetResource(handle);
+ Browser* browser = FindAndActivateTab(tab);
+ if (browser && browser->IsCommandEnabled(IDC_FORWARD)) {
+ AddNavigationStatusListener(tab,
+ new AutomationMsg_GoForwardResponse(
+ message.routing_id(), AUTOMATION_MSG_NAVIGATION_SUCCESS),
+ new AutomationMsg_GoForwardResponse(
+ message.routing_id(), AUTOMATION_MSG_NAVIGATION_AUTH_NEEDED));
+ browser->GoForward();
+ return;
+ }
+ }
+ Send(new AutomationMsg_GoForwardResponse(message.routing_id(),
+ AUTOMATION_MSG_NAVIGATION_ERROR));
+}
+
+void AutomationProvider::Reload(const IPC::Message& message, int handle) {
+ if (tab_tracker_->ContainsHandle(handle)) {
+ NavigationController* tab = tab_tracker_->GetResource(handle);
+ Browser* browser = FindAndActivateTab(tab);
+ if (browser && browser->IsCommandEnabled(IDC_RELOAD)) {
+ AddNavigationStatusListener(tab,
+ new AutomationMsg_ReloadResponse(
+ message.routing_id(), AUTOMATION_MSG_NAVIGATION_SUCCESS),
+ new AutomationMsg_ReloadResponse(
+ message.routing_id(), AUTOMATION_MSG_NAVIGATION_AUTH_NEEDED));
+ browser->Reload();
+ return;
+ }
+ }
+ Send(new AutomationMsg_ReloadResponse(message.routing_id(),
+ AUTOMATION_MSG_NAVIGATION_ERROR));
+}
+
+void AutomationProvider::SetAuth(const IPC::Message& message, int tab_handle,
+ const std::wstring& username,
+ const std::wstring& password) {
+ int status = -1;
+
+ if (tab_tracker_->ContainsHandle(tab_handle)) {
+ NavigationController* tab = tab_tracker_->GetResource(tab_handle);
+ LoginHandlerMap::iterator iter = login_handler_map_.find(tab);
+
+ if (iter != login_handler_map_.end()) {
+ // If auth is needed again after this, assume login has failed. This is
+ // not strictly correct, because a navigation can require both proxy and
+ // server auth, but it should be OK for now.
+ LoginHandler* handler = iter->second;
+ AddNavigationStatusListener(tab,
+ new AutomationMsg_SetAuthResponse(message.routing_id(), 0),
+ new AutomationMsg_SetAuthResponse(message.routing_id(), -1));
+ handler->SetAuth(username, password);
+ status = 0;
+ }
+ }
+ if (status < 0) {
+ Send(new AutomationMsg_SetAuthResponse(message.routing_id(), status));
+ }
+}
+
+void AutomationProvider::CancelAuth(const IPC::Message& message,
+ int tab_handle) {
+ int status = -1;
+
+ if (tab_tracker_->ContainsHandle(tab_handle)) {
+ NavigationController* tab = tab_tracker_->GetResource(tab_handle);
+ LoginHandlerMap::iterator iter = login_handler_map_.find(tab);
+
+ if (iter != login_handler_map_.end()) {
+ // If auth is needed again after this, something is screwy.
+ LoginHandler* handler = iter->second;
+ AddNavigationStatusListener(tab,
+ new AutomationMsg_CancelAuthResponse(message.routing_id(), 0),
+ new AutomationMsg_CancelAuthResponse(message.routing_id(), -1));
+ handler->CancelAuth();
+ status = 0;
+ }
+ }
+ if (status < 0) {
+ Send(new AutomationMsg_CancelAuthResponse(message.routing_id(), status));
+ }
+}
+
+void AutomationProvider::NeedsAuth(const IPC::Message& message,
+ int tab_handle) {
+ bool needs_auth = false;
+
+ if (tab_tracker_->ContainsHandle(tab_handle)) {
+ NavigationController* tab = tab_tracker_->GetResource(tab_handle);
+ LoginHandlerMap::iterator iter = login_handler_map_.find(tab);
+
+ if (iter != login_handler_map_.end()) {
+ // The LoginHandler will be in our map IFF the tab needs auth.
+ needs_auth = true;
+ }
+ }
+
+ Send(new AutomationMsg_NeedsAuthResponse(message.routing_id(), needs_auth));
+}
+
+void AutomationProvider::GetRedirectsFrom(const IPC::Message& message,
+ int tab_handle,
+ const GURL& source_url) {
+ DCHECK(!redirect_query_) << "Can only handle one redirect query at once.";
+ if (tab_tracker_->ContainsHandle(tab_handle)) {
+ NavigationController* tab = tab_tracker_->GetResource(tab_handle);
+ HistoryService* history_service =
+ tab->profile()->GetHistoryService(Profile::EXPLICIT_ACCESS);
+
+ DCHECK(history_service) << "Tab " << tab_handle << "'s profile " <<
+ "has no history service";
+ if (history_service) {
+ // Schedule a history query for redirects. The response will be sent
+ // asynchronously from the callback the history system uses to notify us
+ // that it's done: OnRedirectQueryComplete.
+ redirect_query_routing_id_ = message.routing_id();
+ redirect_query_ = history_service->QueryRedirectsFrom(
+ source_url, &consumer_,
+ NewCallback(this, &AutomationProvider::OnRedirectQueryComplete));
+ return; // Response will be sent when query completes.
+ }
+ }
+
+ // Send failure response.
+ IPC::Message* msg = new IPC::Message(
+ message.routing_id(), AutomationMsg_RedirectsFromResponse::ID,
+ IPC::Message::PRIORITY_NORMAL);
+ msg->WriteInt(-1); // Negative string count indicates an error.
+ Send(msg);
+}
+
+void AutomationProvider::GetActiveTabIndex(const IPC::Message& message,
+ int handle) {
+ int active_tab_index = -1; // -1 is the error code
+ if (browser_tracker_->ContainsHandle(handle)) {
+ Browser* browser = browser_tracker_->GetResource(handle);
+ active_tab_index = browser->selected_index();
+ }
+ Send(new AutomationMsg_ActiveTabIndexResponse(message.routing_id(),
+ active_tab_index));
+}
+
+void AutomationProvider::GetBrowserWindowCount(const IPC::Message& message) {
+ Send(new AutomationMsg_BrowserWindowCountResponse(
+ message.routing_id(), static_cast<int>(BrowserList::size())));
+}
+
+void AutomationProvider::GetBrowserWindow(const IPC::Message& message,
+ int index) {
+ int handle = 0;
+ if (index >= 0) {
+ BrowserList::const_iterator iter = BrowserList::begin();
+
+ for (; (iter != BrowserList::end()) && (index > 0); ++iter, --index);
+ if (iter != BrowserList::end()) {
+ handle = browser_tracker_->Add(*iter);
+ }
+ }
+
+ Send(new AutomationMsg_BrowserWindowResponse(message.routing_id(), handle));
+}
+
+void AutomationProvider::GetLastActiveBrowserWindow(
+ const IPC::Message& message) {
+ int handle = 0;
+ Browser* browser = BrowserList::GetLastActive();
+ if (browser)
+ handle = browser_tracker_->Add(browser);
+ Send(new AutomationMsg_LastActiveBrowserWindowResponse(message.routing_id(),
+ handle));
+}
+
+BOOL CALLBACK EnumThreadWndProc(HWND hwnd, LPARAM l_param) {
+ if (hwnd == reinterpret_cast<HWND>(l_param)) {
+ return FALSE;
+ }
+ return TRUE;
+}
+
+void AutomationProvider::GetActiveWindow(const IPC::Message& message) {
+ HWND window = GetForegroundWindow();
+
+ // Let's make sure this window belongs to our process.
+ if (EnumThreadWindows(::GetCurrentThreadId(),
+ EnumThreadWndProc,
+ reinterpret_cast<LPARAM>(window))) {
+ // We enumerated all the windows and did not find the foreground window,
+ // it is not our window, ignore it.
+ Send(new AutomationMsg_ActiveWindowResponse(message.routing_id(), 0));
+ return;
+ }
+
+ int handle = window_tracker_->Add(window);
+ Send(new AutomationMsg_ActiveWindowResponse(message.routing_id(), handle));
+}
+
+void AutomationProvider::GetWindowHWND(const IPC::Message& message,
+ int handle) {
+ HWND win32_handle = window_tracker_->GetResource(handle);
+ Send(new AutomationMsg_WindowHWNDResponse(message.routing_id(),
+ win32_handle));
+}
+
+void AutomationProvider::WindowGetViewBounds(const IPC::Message& message,
+ int handle,
+ int view_id,
+ bool screen_coordinates) {
+ bool succeeded = false;
+ CRect bounds;
+ bounds.SetRect(0, 0, 0, 0);
+
+ void* iter = NULL;
+ if (window_tracker_->ContainsHandle(handle)) {
+ HWND hwnd = window_tracker_->GetResource(handle);
+ ChromeViews::RootView* root_view =
+ ChromeViews::HWNDViewContainer::FindRootView(hwnd);
+ if (root_view) {
+ ChromeViews::View* view = root_view->GetViewByID(view_id);
+ if (view) {
+ succeeded = true;
+ CPoint point(0, 0);
+ if (screen_coordinates)
+ ChromeViews::View::ConvertPointToScreen(view, &point);
+ else
+ ChromeViews::View::ConvertPointToView(view, root_view, &point);
+ view->GetLocalBounds(&bounds, false);
+ bounds.MoveToXY(point.x, point.y);
+ }
+ }
+ }
+
+ Send(new AutomationMsg_WindowViewBoundsResponse(
+ message.routing_id(), succeeded, gfx::Rect(bounds)));
+}
+
+// This task enqueues a mouse event on the event loop, so that the view
+// that it's being sent to can do the requisite post-processing.
+class MouseEventTask : public Task {
+ public:
+ MouseEventTask(ChromeViews::View* view,
+ ChromeViews::Event::EventType type,
+ POINT point,
+ int flags)
+ : view_(view), type_(type), point_(point), flags_(flags) {}
+ virtual ~MouseEventTask() {}
+
+ virtual void Run() {
+ ChromeViews::MouseEvent event(type_, point_.x, point_.y, flags_);
+ // We need to set the cursor position before we process the event because
+ // some code (tab dragging, for instance) queries the actual cursor location
+ // rather than the location of the mouse event. Note that the reason why
+ // the drag code moved away from using mouse event locations was because
+ // our conversion to screen location doesn't work well with multiple
+ // monitors, so this only works reliably in a single monitor setup.
+ CPoint screen_location = CPoint(point_.x, point_.y);
+ view_->ConvertPointToScreen(view_, &screen_location);
+ ::SetCursorPos(screen_location.x, screen_location.y);
+ switch (type_) {
+ case ChromeViews::Event::ET_MOUSE_PRESSED:
+ view_->OnMousePressed(event);
+ break;
+
+ case ChromeViews::Event::ET_MOUSE_DRAGGED:
+ view_->OnMouseDragged(event);
+ break;
+
+ case ChromeViews::Event::ET_MOUSE_RELEASED:
+ view_->OnMouseReleased(event, false);
+ break;
+
+ default:
+ NOTREACHED();
+ }
+ }
+
+ private:
+ ChromeViews::View* view_;
+ ChromeViews::Event::EventType type_;
+ POINT point_;
+ int flags_;
+
+ DISALLOW_EVIL_CONSTRUCTORS(MouseEventTask);
+};
+
+void AutomationProvider::ScheduleMouseEvent(ChromeViews::View* view,
+ ChromeViews::Event::EventType type,
+ POINT point,
+ int flags) {
+ MessageLoop::current()->PostTask(FROM_HERE,
+ new MouseEventTask(view, type, point, flags));
+}
+
+// This task just adds another task to the event queue. This is useful if
+// you want to ensure that any tasks added to the event queue after this one
+// have already been processed by the time |task| is run.
+class InvokeTaskLaterTask : public Task {
+ public:
+ explicit InvokeTaskLaterTask(Task* task) : task_(task) {}
+ virtual ~InvokeTaskLaterTask() {}
+
+ virtual void Run() {
+ MessageLoop::current()->PostTask(FROM_HERE, task_);
+ }
+
+ private:
+ Task* task_;
+
+ DISALLOW_EVIL_CONSTRUCTORS(InvokeTaskLaterTask);
+};
+
+// This task sends a WindowDragResponse message with the appropriate
+// routing ID to the automation proxy. This is implemented as a task so that
+// we know that the mouse events (and any tasks that they spawn on the message
+// loop) have been processed by the time this is sent.
+class WindowDragResponseTask : public Task {
+ public:
+ WindowDragResponseTask(AutomationProvider* provider, int routing_id)
+ : provider_(provider), routing_id_(routing_id) {}
+ virtual ~WindowDragResponseTask() {}
+
+ virtual void Run() {
+ provider_->Send(new AutomationMsg_WindowDragResponse(routing_id_, true));
+ }
+
+ private:
+ AutomationProvider* provider_;
+ int routing_id_;
+
+ DISALLOW_EVIL_CONSTRUCTORS(WindowDragResponseTask);
+};
+
+void AutomationProvider::WindowSimulateClick(const IPC::Message& message,
+ int handle,
+ POINT click,
+ int flags) {
+ HWND hwnd = 0;
+
+ if (window_tracker_->ContainsHandle(handle)) {
+ hwnd = window_tracker_->GetResource(handle);
+
+ BOOL r = ::ClientToScreen(hwnd, &click);
+ DCHECK(r);
+ ui_controls::SendMouseMove(click.x, click.y);
+
+ ui_controls::MouseButton button = ui_controls::LEFT;
+ if ((flags & ChromeViews::Event::EF_LEFT_BUTTON_DOWN) ==
+ ChromeViews::Event::EF_LEFT_BUTTON_DOWN) {
+ button = ui_controls::LEFT;
+ } else if ((flags & ChromeViews::Event::EF_RIGHT_BUTTON_DOWN) ==
+ ChromeViews::Event::EF_RIGHT_BUTTON_DOWN) {
+ button = ui_controls::RIGHT;
+ } else if ((flags & ChromeViews::Event::EF_MIDDLE_BUTTON_DOWN) ==
+ ChromeViews::Event::EF_MIDDLE_BUTTON_DOWN) {
+ button = ui_controls::MIDDLE;
+ } else {
+ NOTREACHED();
+ }
+ ui_controls::SendMouseClick(button);
+ }
+}
+
+void AutomationProvider::WindowSimulateDrag(const IPC::Message& message,
+ int handle,
+ std::vector<POINT> drag_path,
+ int flags) {
+ bool succeeded = false;
+ if (browser_tracker_->ContainsHandle(handle) && (drag_path.size() > 1)) {
+ succeeded = true;
+
+ Browser* browser = browser_tracker_->GetResource(handle);
+ DCHECK(browser);
+ ChromeViews::RootView* root = browser->frame()->GetRootView();
+ DCHECK(root);
+ ScheduleMouseEvent(root, ChromeViews::Event::ET_MOUSE_PRESSED,
+ drag_path[0], flags);
+ for (int i = 1; i < static_cast<int>(drag_path.size()); ++i) {
+ ScheduleMouseEvent(root, ChromeViews::Event::ET_MOUSE_DRAGGED,
+ drag_path[i], flags);
+ }
+ POINT end = drag_path[drag_path.size() - 1];
+ ScheduleMouseEvent(root, ChromeViews::Event::ET_MOUSE_RELEASED,
+ drag_path[drag_path.size() - 1], flags);
+
+ MessageLoop::current()->PostTask(FROM_HERE,
+ new InvokeTaskLaterTask(
+ new WindowDragResponseTask(this, message.routing_id())));
+ } else {
+ Send(new AutomationMsg_WindowDragResponse(message.routing_id(), true));
+ }
+}
+
+void AutomationProvider::WindowSimulateKeyPress(const IPC::Message& message,
+ int handle,
+ wchar_t key,
+ int flags) {
+ if (!window_tracker_->ContainsHandle(handle))
+ return;
+
+ // The key event is sent to whatever window is active.
+ ui_controls::SendKeyPress(key,
+ ((flags & ChromeViews::Event::EF_CONTROL_DOWN) ==
+ ChromeViews::Event::EF_CONTROL_DOWN),
+ ((flags & ChromeViews::Event::EF_SHIFT_DOWN) ==
+ ChromeViews::Event::EF_SHIFT_DOWN),
+ ((flags & ChromeViews::Event::EF_ALT_DOWN) ==
+ ChromeViews::Event::EF_ALT_DOWN));
+}
+
+void AutomationProvider::GetFocusedViewID(const IPC::Message& message,
+ int handle) {
+ int view_id = -1;
+ if (window_tracker_->ContainsHandle(handle)) {
+ HWND hwnd = window_tracker_->GetResource(handle);
+ ChromeViews::FocusManager* focus_manager =
+ ChromeViews::FocusManager::GetFocusManager(hwnd);
+ DCHECK(focus_manager);
+ ChromeViews::View* focused_view = focus_manager->GetFocusedView();
+ if (focused_view)
+ view_id = focused_view->GetID();
+ }
+ Send(new AutomationMsg_GetFocusedViewIDResponse(message.routing_id(),
+ view_id));
+}
+
+void AutomationProvider::SetWindowVisible(const IPC::Message& message,
+ int handle, bool visible) {
+ if (window_tracker_->ContainsHandle(handle)) {
+ HWND hwnd = window_tracker_->GetResource(handle);
+ ::ShowWindow(hwnd, visible ? SW_SHOW : SW_HIDE);
+ Send(new AutomationMsg_SetWindowVisibleResponse(message.routing_id(),
+ true));
+ } else {
+ Send(new AutomationMsg_SetWindowVisibleResponse(message.routing_id(),
+ false));
+ }
+}
+
+void AutomationProvider::IsWindowActive(const IPC::Message& message,
+ int handle) {
+ if (window_tracker_->ContainsHandle(handle)) {
+ HWND hwnd = window_tracker_->GetResource(handle);
+ bool is_active = ::GetForegroundWindow() == hwnd;
+ Send(new AutomationMsg_IsWindowActiveResponse(
+ message.routing_id(), true, is_active));
+ } else {
+ Send(new AutomationMsg_IsWindowActiveResponse(message.routing_id(),
+ false, false));
+ }
+}
+
+void AutomationProvider::ActivateWindow(const IPC::Message& message,
+ int handle) {
+ if (window_tracker_->ContainsHandle(handle)) {
+ ::SetActiveWindow(window_tracker_->GetResource(handle));
+ }
+}
+
+void AutomationProvider::GetTabCount(const IPC::Message& message, int handle) {
+ int tab_count = -1; // -1 is the error code
+
+ if (browser_tracker_->ContainsHandle(handle)) {
+ Browser* browser = browser_tracker_->GetResource(handle);
+ tab_count = browser->tab_count();
+ }
+
+ Send(new AutomationMsg_TabCountResponse(message.routing_id(), tab_count));
+}
+
+void AutomationProvider::GetTab(const IPC::Message& message,
+ int win_handle, int tab_index) {
+ void* iter = NULL;
+ int tab_handle = 0;
+ if (browser_tracker_->ContainsHandle(win_handle) && (tab_index >= 0)) {
+ Browser* browser = browser_tracker_->GetResource(win_handle);
+ if (tab_index < browser->tab_count()) {
+ TabContents* tab_contents =
+ browser->GetTabContentsAt(tab_index);
+ tab_handle = tab_tracker_->Add(tab_contents->controller());
+ }
+ }
+
+ Send(new AutomationMsg_TabResponse(message.routing_id(), tab_handle));
+}
+
+void AutomationProvider::GetTabTitle(const IPC::Message& message, int handle) {
+ int title_string_size = -1; // -1 is the error code
+ std::wstring title;
+ if (tab_tracker_->ContainsHandle(handle)) {
+ NavigationController* tab = tab_tracker_->GetResource(handle);
+ title = tab->GetActiveEntry()->GetTitle();
+ title_string_size = static_cast<int>(title.size());
+ }
+
+ Send(new AutomationMsg_TabTitleResponse(message.routing_id(),
+ title_string_size, title));
+}
+
+void AutomationProvider::HandleUnused(const IPC::Message& message, int handle) {
+ if (window_tracker_->ContainsHandle(handle)) {
+ window_tracker_->Remove(window_tracker_->GetResource(handle));
+ }
+}
+
+void AutomationProvider::OnChannelError() {
+ LOG(ERROR) << "AutomationProxy went away, shutting down app.";
+ delete this;
+}
+
+// TODO(brettw) change this to accept GURLs when history supports it
+void AutomationProvider::OnRedirectQueryComplete(
+ HistoryService::Handle request_handle,
+ GURL from_url,
+ bool success,
+ HistoryService::RedirectList* redirects) {
+ DCHECK(request_handle == redirect_query_);
+
+ // Respond to the pending request for the redirect list.
+ IPC::Message* msg = new IPC::Message(redirect_query_routing_id_,
+ AutomationMsg_RedirectsFromResponse::ID,
+ IPC::Message::PRIORITY_NORMAL);
+ if (success) {
+ msg->WriteInt(static_cast<int>(redirects->size()));
+ for (size_t i = 0; i < redirects->size(); i++)
+ IPC::ParamTraits<GURL>::Write(msg, redirects->at(i));
+ } else {
+ msg->WriteInt(-1); // Negative count indicates failure.
+ }
+
+ Send(msg);
+ redirect_query_ = NULL;
+}
+
+bool AutomationProvider::Send(IPC::Message* msg) {
+ if (connected_) {
+ DCHECK(channel_.get());
+ return channel_->Send(msg);
+ }
+ return false;
+}
+
+Browser* AutomationProvider::FindAndActivateTab(
+ NavigationController* controller) {
+ int tab_index;
+ Browser* browser = Browser::GetBrowserForController(controller, &tab_index);
+ if (browser)
+ browser->SelectTabContentsAt(tab_index, true);
+
+ return browser;
+}
+
+void AutomationProvider::GetCookies(const IPC::Message& message,
+ const GURL& url, int handle) {
+ std::string value;
+
+ if (url.is_valid() && tab_tracker_->ContainsHandle(handle)) {
+ NavigationController* tab = tab_tracker_->GetResource(handle);
+ value =
+ tab->profile()->GetRequestContext()->cookie_store()->GetCookies(url);
+ }
+
+ Send(new AutomationMsg_GetCookiesResponse(message.routing_id(),
+ static_cast<int>(value.size()), value));
+}
+
+void AutomationProvider::SetCookie(const IPC::Message& message,
+ const GURL& url,
+ const std::string value,
+ int handle) {
+ int response_value = -1;
+
+ if (url.is_valid() && tab_tracker_->ContainsHandle(handle)) {
+ NavigationController* tab = tab_tracker_->GetResource(handle);
+ URLRequestContext* context = tab->profile()->GetRequestContext();
+ if (context->cookie_store()->SetCookie(url, value))
+ response_value = 1;
+ }
+
+ Send(new AutomationMsg_SetCookieResponse(message.routing_id(),
+ response_value));
+}
+
+void AutomationProvider::GetTabURL(const IPC::Message& message, int handle) {
+ bool success = false;
+ GURL url;
+ if (tab_tracker_->ContainsHandle(handle)) {
+ NavigationController* tab = tab_tracker_->GetResource(handle);
+ // Return what the user would see in the location bar.
+ url = tab->GetActiveEntry()->GetDisplayURL();
+ success = true;
+ }
+
+ Send(new AutomationMsg_TabURLResponse(message.routing_id(), success, url));
+}
+
+void AutomationProvider::GetTabHWND(const IPC::Message& message, int handle) {
+ HWND tab_hwnd = NULL;
+
+ if (tab_tracker_->ContainsHandle(handle)) {
+ NavigationController* tab = tab_tracker_->GetResource(handle);
+ tab_hwnd = tab->active_contents()->GetContainerHWND();
+ }
+
+ Send(new AutomationMsg_TabHWNDResponse(message.routing_id(), tab_hwnd));
+}
+
+void AutomationProvider::GetTabProcessID(
+ const IPC::Message& message, int handle) {
+ int process_id = -1;
+
+ if (tab_tracker_->ContainsHandle(handle)) {
+ process_id = 0;
+ NavigationController* tab = tab_tracker_->GetResource(handle);
+ if (tab->active_contents()->AsWebContents()) {
+ WebContents* web_contents = tab->active_contents()->AsWebContents();
+ if (web_contents->process()) {
+ process_id =
+ process_util::GetProcId(web_contents->process()->process());
+ }
+ }
+ }
+
+ Send(new AutomationMsg_TabProcessIDResponse(message.routing_id(),
+ process_id));
+}
+
+void AutomationProvider::ApplyAccelerator(int handle, int id) {
+ if (browser_tracker_->ContainsHandle(handle)) {
+ Browser* browser = browser_tracker_->GetResource(handle);
+ browser->controller()->ExecuteCommand(id);
+ }
+}
+
+void AutomationProvider::ExecuteJavascript(const IPC::Message& message,
+ int handle,
+ const std::wstring& frame_xpath,
+ const std::wstring& script) {
+ bool succeeded = false;
+ if (tab_tracker_->ContainsHandle(handle)) {
+ NavigationController* tab = tab_tracker_->GetResource(handle);
+ TabContents* tab_contents = tab->active_contents();
+ if (tab_contents && tab_contents->type() == TAB_CONTENTS_WEB) {
+ WebContents* web_contents = tab_contents->AsWebContents();
+
+ // Set the routing id of this message with the controller.
+ // This routing id needs to be remembered for the reverse
+ // communication while sending back the response of
+ // this javascript execution.
+ std::wstring url;
+ SStringPrintf(&url,
+ L"javascript:void(window.domAutomationController.setAutomationId(%d));",
+ message.routing_id());
+
+ web_contents->ExecuteJavascriptInWebFrame(frame_xpath, url);
+ web_contents->ExecuteJavascriptInWebFrame(frame_xpath, script);
+ succeeded = true;
+ }
+ }
+
+ if (!succeeded) {
+ Send(new AutomationMsg_DomOperationResponse(message.routing_id(), ""));
+ }
+}
+
+void AutomationProvider::GetShelfVisibility(const IPC::Message& message,
+ int handle) {
+ bool visible = false;
+ if (tab_tracker_->ContainsHandle(handle)) {
+ NavigationController* tab = tab_tracker_->GetResource(handle);
+ TabContents* tab_contents = tab->active_contents();
+ if (tab_contents && tab_contents->type() == TAB_CONTENTS_WEB) {
+ WebContents* web_contents = tab_contents->AsWebContents();
+ visible = web_contents->IsDownloadShelfVisible();
+ }
+ }
+
+ Send(new AutomationMsg_ShelfVisibilityResponse(message.routing_id(),
+ visible));
+}
+
+void AutomationProvider::GetConstrainedWindowCount(const IPC::Message& message,
+ int handle) {
+ int count = -1; // -1 is the error code
+ if (tab_tracker_->ContainsHandle(handle)) {
+ NavigationController* nav_controller = tab_tracker_->GetResource(handle);
+ TabContents* tab_contents = nav_controller->active_contents();
+ if (tab_contents) {
+ count = static_cast<int>(tab_contents->child_windows_.size());
+ }
+ }
+
+ Send(new AutomationMsg_ConstrainedWindowCountResponse(message.routing_id(),
+ count));
+}
+
+void AutomationProvider::GetConstrainedWindow(const IPC::Message& message,
+ int handle, int index) {
+ int cwindow_handle = 0;
+ if (tab_tracker_->ContainsHandle(handle) && index >= 0) {
+ NavigationController* nav_controller =
+ tab_tracker_->GetResource(handle);
+ TabContents* tab = nav_controller->active_contents();
+ if (tab && index < static_cast<int>(tab->child_windows().size())) {
+ ConstrainedWindow* window = tab->child_windows()[index];
+ cwindow_handle = cwindow_tracker_->Add(window);
+ }
+ }
+
+ Send(new AutomationMsg_ConstrainedWindowResponse(message.routing_id(),
+ cwindow_handle));
+}
+
+void AutomationProvider::GetConstrainedTitle(const IPC::Message& message,
+ int handle) {
+ int title_string_size = -1; // -1 is the error code
+ std::wstring title;
+ if (cwindow_tracker_->ContainsHandle(handle)) {
+ ConstrainedWindow* window = cwindow_tracker_->GetResource(handle);
+ title = window->GetWindowTitle();
+ title_string_size = static_cast<int>(title.size());
+ }
+
+ Send(new AutomationMsg_ConstrainedTitleResponse(message.routing_id(),
+ title_string_size, title));
+}
+
+void AutomationProvider::GetConstrainedWindowBounds(const IPC::Message& message,
+ int handle) {
+ bool exists = false;
+ gfx::Rect rect(0, 0, 0, 0);
+ if (cwindow_tracker_->ContainsHandle(handle)) {
+ ConstrainedWindow* window = cwindow_tracker_->GetResource(handle);
+ if (window) {
+ exists = true;
+ rect = window->GetCurrentBounds();
+ }
+ }
+
+ Send(new AutomationMsg_ConstrainedWindowBoundsResponse(message.routing_id(),
+ exists, rect));
+}
+
+void AutomationProvider::HandleFindInPageRequest(
+ const IPC::Message& message, int handle, const std::wstring& find_request,
+ int forward, int match_case) {
+ if (!tab_tracker_->ContainsHandle(handle)) {
+ Send(new AutomationMsg_FindInPageResponse(message.routing_id(), -1));
+ return;
+ }
+
+ NavigationController* nav = tab_tracker_->GetResource(handle);
+ TabContents* tab_contents = nav->active_contents();
+
+ find_in_page_observer_.reset(new
+ FindInPageNotificationObserver(this, tab_contents, message.routing_id()));
+
+ // The explicit comparison to TRUE avoids a warning (C4800).
+ tab_contents->StartFinding(
+ FindInPageNotificationObserver::kFindInPageRequestId,
+ find_request, forward == TRUE, match_case == TRUE,
+ false); // Not a FindNext operation.
+}
+
+void AutomationProvider::HandleInspectElementRequest(
+ const IPC::Message& message, int handle, int x, int y) {
+ if (!tab_tracker_->ContainsHandle(handle)) {
+ Send(new AutomationMsg_InspectElementResponse(message.routing_id(), -1));
+ return;
+ }
+
+ NavigationController* nav = tab_tracker_->GetResource(handle);
+ TabContents* tab_contents = nav->active_contents();
+ if (tab_contents->type() == TAB_CONTENTS_WEB) {
+ WebContents* web_contents = tab_contents->AsWebContents();
+ web_contents->InspectElementAt(x, y);
+ inspect_element_routing_id_ = message.routing_id();
+ } else {
+ Send(new AutomationMsg_InspectElementResponse(message.routing_id(), -1));
+ }
+}
+
+void AutomationProvider::ReceivedInspectElementResponse(int num_resources) {
+ Send(new AutomationMsg_InspectElementResponse(inspect_element_routing_id_,
+ num_resources));
+}
+
+// Helper class for making changes to the URLRequest ProtocolFactory on the
+// IO thread.
+class SetFilteredInetTask : public Task {
+ public:
+ explicit SetFilteredInetTask(bool enabled) : enabled_(enabled) { }
+ virtual void Run() {
+ if (enabled_) {
+ URLRequestFilter::GetInstance()->ClearHandlers();
+
+ URLRequestFailedDnsJob::AddUITestUrls();
+ URLRequestSlowDownloadJob::AddUITestUrls();
+
+ std::wstring root_http;
+ PathService::Get(chrome::DIR_TEST_DATA, &root_http);
+ URLRequestMockHTTPJob::AddUITestUrls(root_http);
+ } else {
+ // Revert to the default handlers.
+ URLRequestFilter::GetInstance()->ClearHandlers();
+ }
+ }
+ private:
+ bool enabled_;
+};
+
+void AutomationProvider::SetFilteredInet(const IPC::Message& message,
+ bool enabled) {
+ // Since this involves changing the URLRequest ProtocolFactory, we want to
+ // run on the main thread.
+ g_browser_process->io_thread()->message_loop()->PostTask(FROM_HERE,
+ new SetFilteredInetTask(enabled));
+}
+
+void AutomationProvider::GetDownloadDirectory(const IPC::Message& message,
+ int handle) {
+ DLOG(INFO) << "Handling download directory request";
+ std::wstring download_directory;
+ if (tab_tracker_->ContainsHandle(handle)) {
+ NavigationController* tab = tab_tracker_->GetResource(handle);
+ DownloadManager* dlm = tab->profile()->GetDownloadManager();
+ DCHECK(dlm);
+ download_directory = dlm->download_path();
+ }
+
+ Send(new AutomationMsg_DownloadDirectoryResponse(message.routing_id(),
+ download_directory));
+}
+
+void AutomationProvider::OpenNewBrowserWindow(int show_command) {
+ // We may have no current browser windows open so don't rely on
+ // asking an existing browser to execute the IDC_NEWWINDOW command
+ Browser::OpenNewBrowserWindow(profile_, show_command);
+}
+
+void AutomationProvider::GetWindowForBrowser(const IPC::Message& message,
+ int browser_handle) {
+ bool success = false;
+ int window_handle = 0;
+
+ if (browser_tracker_->ContainsHandle(browser_handle)) {
+ Browser* browser = browser_tracker_->GetResource(browser_handle);
+ HWND hwnd = browser->GetTopLevelHWND();
+ // Add() returns the existing handle for the resource if any.
+ window_handle = window_tracker_->Add(hwnd);
+ success = true;
+ }
+ Send(new AutomationMsg_WindowForBrowserResponse(message.routing_id(),
+ success, window_handle));
+}
+
+void AutomationProvider::GetAutocompleteEditForBrowser(
+ const IPC::Message& message,
+ int browser_handle) {
+ bool success = false;
+ int autocomplete_edit_handle = 0;
+
+ if (browser_tracker_->ContainsHandle(browser_handle)) {
+ Browser* browser = browser_tracker_->GetResource(browser_handle);
+ LocationBarView* loc_bar_view = browser->GetLocationBarView();
+ AutocompleteEdit* autocomplete_edit = loc_bar_view->location_entry();
+ // Add() returns the existing handle for the resource if any.
+ autocomplete_edit_handle =
+ autocomplete_edit_tracker_->Add(autocomplete_edit);
+ success = true;
+ }
+ Send(new AutomationMsg_AutocompleteEditForBrowserResponse(
+ message.routing_id(), success, autocomplete_edit_handle));
+}
+
+void AutomationProvider::GetBrowserForWindow(const IPC::Message& message,
+ int window_handle) {
+ bool success = false;
+ int browser_handle = 0;
+
+ if (window_tracker_->ContainsHandle(window_handle)) {
+ HWND window = window_tracker_->GetResource(window_handle);
+ BrowserList::const_iterator iter = BrowserList::begin();
+ Browser* browser = NULL;
+ for (;iter != BrowserList::end(); ++iter) {
+ if (window == (*iter)->GetTopLevelHWND()) {
+ browser = *iter;
+ break;
+ }
+ }
+ if (browser) {
+ // Add() returns the existing handle for the resource if any.
+ browser_handle = browser_tracker_->Add(browser);
+ success = true;
+ }
+ }
+ Send(new AutomationMsg_BrowserForWindowResponse(message.routing_id(),
+ success, browser_handle));
+}
+
+void AutomationProvider::ShowInterstitialPage(const IPC::Message& message,
+ int tab_handle,
+ const std::string& html_text) {
+ if (tab_tracker_->ContainsHandle(tab_handle)) {
+ NavigationController* controller = tab_tracker_->GetResource(tab_handle);
+ TabContents* tab_contents = controller->active_contents();
+ if (tab_contents->type() == TAB_CONTENTS_WEB) {
+ AddNavigationStatusListener(controller,
+ new AutomationMsg_ShowInterstitialPageResponse(message.routing_id(),
+ true),
+ NULL);
+ WebContents* web_contents = tab_contents->AsWebContents();
+ web_contents->ShowInterstitialPage(html_text, NULL);
+ return;
+ }
+ }
+ Send(new AutomationMsg_ShowInterstitialPageResponse(message.routing_id(),
+ false));
+}
+
+void AutomationProvider::HideInterstitialPage(const IPC::Message& message,
+ int tab_handle) {
+ if (tab_tracker_->ContainsHandle(tab_handle)) {
+ NavigationController* controller = tab_tracker_->GetResource(tab_handle);
+ TabContents* tab_contents = controller->active_contents();
+ if (tab_contents->type() == TAB_CONTENTS_WEB) {
+ WebContents* web_contents = tab_contents->AsWebContents();
+ web_contents->HideInterstitialPage(false, false);
+ Send(new AutomationMsg_HideInterstitialPageResponse(message.routing_id(),
+ true));
+ return;
+ }
+ }
+ Send(new AutomationMsg_HideInterstitialPageResponse(message.routing_id(),
+ false));
+}
+
+void AutomationProvider::CloseTab(const IPC::Message& message,
+ int tab_handle,
+ bool wait_until_closed) {
+ if (tab_tracker_->ContainsHandle(tab_handle)) {
+ NavigationController* controller = tab_tracker_->GetResource(tab_handle);
+ int index;
+ Browser* browser = Browser::GetBrowserForController(controller, &index);
+ DCHECK(browser);
+ TabClosedNotificationObserver* observer =
+ new TabClosedNotificationObserver(browser, this, message.routing_id(),
+ wait_until_closed);
+ browser->CloseContents(controller->active_contents());
+ } else {
+ Send(new AutomationMsg_CloseTabResponse(message.routing_id(), false));
+ }
+}
+
+void AutomationProvider::CloseBrowser(const IPC::Message& message,
+ int browser_handle) {
+ if (browser_tracker_->ContainsHandle(browser_handle)) {
+ Browser* browser = browser_tracker_->GetResource(browser_handle);
+ new BrowserClosedNotificationObserver(browser, this, message.routing_id());
+ browser->frame()->Close();
+ } else {
+ NOTREACHED();
+ }
+}
+
+void AutomationProvider::CreateExternalTab(const IPC::Message& message) {
+ int tab_handle = 0;
+ HWND tab_container_window = NULL;
+ ExternalTabContainer *external_tab_container =
+ new ExternalTabContainer(this);
+ external_tab_container->Init(profile_);
+ TabContents* tab_contents = external_tab_container->tab_contents();
+ if (tab_contents) {
+ tab_handle = tab_tracker_->Add(tab_contents->controller());
+ tab_container_window = *external_tab_container;
+ }
+ Send(new AutomationMsg_CreateExternalTabResponse(message.routing_id(),
+ tab_container_window,
+ tab_handle));
+}
+
+void AutomationProvider::NavigateInExternalTab(const IPC::Message& message,
+ int handle, const GURL& url) {
+ bool status = false;
+
+ if (tab_tracker_->ContainsHandle(handle)) {
+ NavigationController* tab = tab_tracker_->GetResource(handle);
+ tab->LoadURL(url, PageTransition::TYPED);
+ status = true;
+ }
+
+ Send(new AutomationMsg_NavigateInExternalTabResponse(message.routing_id(),
+ status));
+}
+
+void AutomationProvider::SetAcceleratorsForTab(const IPC::Message& message,
+ int handle,
+ HACCEL accel_table,
+ int accel_entry_count) {
+ bool status = false;
+ if (tab_tracker_->ContainsHandle(handle)) {
+ NavigationController* tab = tab_tracker_->GetResource(handle);
+ TabContents* tab_contents = tab->GetTabContents(TAB_CONTENTS_WEB);
+ ExternalTabContainer* external_tab_container =
+ ExternalTabContainer::GetContainerForTab(
+ tab_contents->GetContainerHWND());
+ // This call is only valid on an externally hosted tab
+ if (external_tab_container) {
+ external_tab_container->SetAccelerators(accel_table,
+ accel_entry_count);
+ status = true;
+ }
+ }
+ Send(new AutomationMsg_SetAcceleratorsForTabResponse(message.routing_id(),
+ status));
+}
+
+void AutomationProvider::ProcessUnhandledAccelerator(
+ const IPC::Message& message, int handle, const MSG& msg) {
+ if (tab_tracker_->ContainsHandle(handle)) {
+ NavigationController* tab = tab_tracker_->GetResource(handle);
+ TabContents* tab_contents = tab->GetTabContents(TAB_CONTENTS_WEB);
+ ExternalTabContainer* external_tab_container =
+ ExternalTabContainer::GetContainerForTab(
+ tab_contents->GetContainerHWND());
+ // This call is only valid on an externally hosted tab
+ if (external_tab_container) {
+ external_tab_container->ProcessUnhandledAccelerator(msg);
+ }
+ }
+ // This message expects no response.
+}
+
+void AutomationProvider::WaitForTabToBeRestored(
+ const IPC::Message& message,
+ int tab_handle) {
+ if (tab_tracker_->ContainsHandle(tab_handle)) {
+ NavigationController* tab = tab_tracker_->GetResource(tab_handle);
+ restore_tracker_.reset(
+ new NavigationControllerRestoredObserver(this, tab,
+ message.routing_id()));
+ }
+}
+
+void AutomationProvider::GetSecurityState(const IPC::Message& message,
+ int handle) {
+ if (tab_tracker_->ContainsHandle(handle)) {
+ NavigationController* tab = tab_tracker_->GetResource(handle);
+ NavigationEntry* entry = tab->GetActiveEntry();
+ Send(new AutomationMsg_GetSecurityStateResponse(message.routing_id(), true,
+ entry->GetSecurityStyle(), entry->GetSSLCertStatus(),
+ entry->GetContentStatus()));
+ } else {
+ Send(new AutomationMsg_GetSecurityStateResponse(message.routing_id(), false,
+ SECURITY_STYLE_UNKNOWN,
+ 0, 0));
+ }
+}
+
+void AutomationProvider::GetPageType(const IPC::Message& message, int handle) {
+ if (tab_tracker_->ContainsHandle(handle)) {
+ NavigationController* tab = tab_tracker_->GetResource(handle);
+ NavigationEntry* entry = tab->GetActiveEntry();
+ NavigationEntry::PageType page_type = entry->GetPageType();
+ // In order to return the proper result when an interstitial is shown and
+ // no navigation entry were created for it we need to ask the WebContents.
+ if (page_type == NavigationEntry::NORMAL_PAGE &&
+ tab->active_contents()->AsWebContents() &&
+ tab->active_contents()->AsWebContents()->IsShowingInterstitialPage())
+ page_type = NavigationEntry::INTERSTITIAL_PAGE;
+
+ Send(new AutomationMsg_GetPageTypeResponse(message.routing_id(), true,
+ page_type));
+ } else {
+ Send(new AutomationMsg_GetPageTypeResponse(message.routing_id(), false,
+ NavigationEntry::NORMAL_PAGE));
+ }
+}
+
+void AutomationProvider::ActionOnSSLBlockingPage(const IPC::Message& message,
+ int handle, bool proceed) {
+ if (tab_tracker_->ContainsHandle(handle)) {
+ NavigationController* tab = tab_tracker_->GetResource(handle);
+ NavigationEntry* entry = tab->GetActiveEntry();
+ if (entry->GetPageType() == NavigationEntry::INTERSTITIAL_PAGE) {
+ TabContents* tab_contents = tab->GetTabContents(TAB_CONTENTS_WEB);
+ SSLBlockingPage* ssl_blocking_page =
+ SSLBlockingPage::GetSSLBlockingPage(tab_contents);
+ if (ssl_blocking_page) {
+ if (proceed) {
+ AddNavigationStatusListener(tab,
+ new AutomationMsg_ActionOnSSLBlockingPageResponse(
+ message.routing_id(), true),
+ new AutomationMsg_ActionOnSSLBlockingPageResponse(
+ message.routing_id(), true));
+ ssl_blocking_page->Proceed();
+ return;
+ }
+ ssl_blocking_page->DontProceed();
+ Send(new AutomationMsg_ActionOnSSLBlockingPageResponse(
+ message.routing_id(), true));
+ return;
+ }
+ }
+ }
+ // We failed.
+ Send(new AutomationMsg_ActionOnSSLBlockingPageResponse(message.routing_id(),
+ false));
+}
+
+void AutomationProvider::BringBrowserToFront(const IPC::Message& message,
+ int browser_handle) {
+ if (browser_tracker_->ContainsHandle(browser_handle)) {
+ Browser* browser = browser_tracker_->GetResource(browser_handle);
+ browser->MoveToFront(true);
+ Send(new AutomationMsg_BringBrowserToFrontResponse(message.routing_id(),
+ true));
+ } else {
+ Send(new AutomationMsg_BringBrowserToFrontResponse(message.routing_id(),
+ false));
+ }
+}
+
+void AutomationProvider::IsPageMenuCommandEnabled(const IPC::Message& message,
+ int browser_handle,
+ int message_num) {
+ if (browser_tracker_->ContainsHandle(browser_handle)) {
+ Browser* browser = browser_tracker_->GetResource(browser_handle);
+ bool menu_item_enabled =
+ browser->controller()->IsCommandEnabled(message_num);
+ Send(new AutomationMsg_IsPageMenuCommandEnabledResponse(
+ message.routing_id(), menu_item_enabled));
+ } else {
+ Send(new AutomationMsg_IsPageMenuCommandEnabledResponse(
+ message.routing_id(), false));
+ }
+}
+
+void AutomationProvider::PrintNow(const IPC::Message& message, int tab_handle) {
+ if (tab_tracker_->ContainsHandle(tab_handle)) {
+ NavigationController* tab = tab_tracker_->GetResource(tab_handle);
+ FindAndActivateTab(tab);
+ WebContents* const web_contents = tab->active_contents()->AsWebContents();
+ if (web_contents) {
+ notification_observer_list_.AddObserver(
+ new DocumentPrintedNotificationObserver(this, message.routing_id()));
+ if (web_contents->PrintNow())
+ return;
+ }
+ }
+ Send(new AutomationMsg_PrintNowResponse(message.routing_id(), false));
+}
+
+void AutomationProvider::SavePage(const IPC::Message& message,
+ int tab_handle,
+ const std::wstring& file_name,
+ const std::wstring& dir_path,
+ int type) {
+ if (!tab_tracker_->ContainsHandle(tab_handle)) {
+ Send(new AutomationMsg_SavePageResponse(message.routing_id(), false));
+ return;
+ }
+
+ NavigationController* nav = tab_tracker_->GetResource(tab_handle);
+ Browser* browser = FindAndActivateTab(nav);
+ DCHECK(browser);
+ if (!browser->IsCommandEnabled(IDC_SAVEPAGE)) {
+ Send(new AutomationMsg_SavePageResponse(message.routing_id(), false));
+ return;
+ }
+
+ TabContents* tab_contents = nav->active_contents();
+ if (tab_contents->type() != TAB_CONTENTS_WEB) {
+ Send(new AutomationMsg_SavePageResponse(message.routing_id(), false));
+ return;
+ }
+
+ SavePackage::SavePackageType save_type =
+ static_cast<SavePackage::SavePackageType>(type);
+ DCHECK(save_type >= SavePackage::SAVE_AS_ONLY_HTML &&
+ save_type <= SavePackage::SAVE_AS_COMPLETE_HTML);
+ tab_contents->AsWebContents()->SavePage(file_name, dir_path, save_type);
+
+ Send(new AutomationMsg_SavePageResponse(
+ message.routing_id(), true));
+}
+
+void AutomationProvider::GetAutocompleteEditText(const IPC::Message& message,
+ int autocomplete_edit_handle) {
+ bool success = false;
+ std::wstring text;
+ if (autocomplete_edit_tracker_->ContainsHandle(autocomplete_edit_handle)) {
+ AutocompleteEdit* edit = autocomplete_edit_tracker_->GetResource(
+ autocomplete_edit_handle);
+ text = edit->GetText();
+ success = true;
+ }
+ Send(new AutomationMsg_AutocompleteEditGetTextResponse(message.routing_id(),
+ success, text));
+}
+
+void AutomationProvider::SetAutocompleteEditText(const IPC::Message& message,
+ int autocomplete_edit_handle,
+ const std::wstring& text) {
+ bool success = false;
+ if (autocomplete_edit_tracker_->ContainsHandle(autocomplete_edit_handle)) {
+ AutocompleteEdit* edit = autocomplete_edit_tracker_->GetResource(
+ autocomplete_edit_handle);
+ edit->SetUserText(text);
+ success = true;
+ }
+ Send(new AutomationMsg_AutocompleteEditSetTextResponse(
+ message.routing_id(), success));
+}
+
+void AutomationProvider::AutocompleteEditGetMatches(
+ const IPC::Message& message,
+ int autocomplete_edit_handle) {
+ bool success = false;
+ std::vector<AutocompleteMatchData> matches;
+ if (autocomplete_edit_tracker_->ContainsHandle(autocomplete_edit_handle)) {
+ AutocompleteEdit* edit =
+ autocomplete_edit_tracker_->GetResource(autocomplete_edit_handle);
+ const AutocompleteResult* result = edit->latest_result();
+ for (AutocompleteResult::const_iterator i = result->begin();
+ i != result->end(); ++i)
+ matches.push_back(AutocompleteMatchData(*i));
+ success = true;
+ }
+ Send(new AutomationMsg_AutocompleteEditGetMatchesResponse(
+ message.routing_id(), success, matches));
+}
+
+void AutomationProvider::AutocompleteEditIsQueryInProgress(
+ const IPC::Message& message,
+ int autocomplete_edit_handle) {
+ bool success = false;
+ bool query_in_progress = false;
+ if (autocomplete_edit_tracker_->ContainsHandle(autocomplete_edit_handle)) {
+ AutocompleteEdit* edit =
+ autocomplete_edit_tracker_->GetResource(autocomplete_edit_handle);
+ query_in_progress = edit->query_in_progress();
+ success = true;
+ }
+ Send(new AutomationMsg_AutocompleteEditIsQueryInProgressResponse(
+ message.routing_id(), success, query_in_progress));
+}
+
+TestingAutomationProvider::TestingAutomationProvider(Profile* profile)
+ : AutomationProvider(profile) {
+ BrowserList::AddObserver(this);
+ NotificationService::current()->AddObserver(this, NOTIFY_SESSION_END,
+ NotificationService::AllSources());
+}
+
+TestingAutomationProvider::~TestingAutomationProvider() {
+ NotificationService::current()->RemoveObserver(this, NOTIFY_SESSION_END,
+ NotificationService::AllSources());
+ BrowserList::RemoveObserver(this);
+}
+
+void TestingAutomationProvider::OnChannelError() {
+ BrowserList::CloseAllBrowsers(true);
+ AutomationProvider::OnChannelError();
+}
+
+void TestingAutomationProvider::OnBrowserRemoving(const Browser* browser) {
+ // For backwards compatibility with the testing automation interface, we
+ // want the automation provider (and hence the process) to go away when the
+ // last browser goes away.
+ if (BrowserList::size() == 1) {
+ // If you change this, update Observer for NOTIFY_SESSION_END below.
+ MessageLoop::current()->ReleaseSoon(FROM_HERE, this);
+ }
+}
+
+void TestingAutomationProvider::Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ DCHECK(type == NOTIFY_SESSION_END);
+ // OnBrowserRemoving does a ReleaseLater. When session end is received we exit
+ // before the task runs resulting in this object not being deleted. This
+ // Release balance out the Release scheduled by OnBrowserRemoving.
+ Release();
+}
diff --git a/chrome/browser/automation/automation_provider.h b/chrome/browser/automation/automation_provider.h
new file mode 100644
index 0000000..249bc7e
--- /dev/null
+++ b/chrome/browser/automation/automation_provider.h
@@ -0,0 +1,379 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// This implements a browser-side endpoint for UI automation activity.
+// The client-side endpoint is implemented by AutomationProxy.
+// The entire lifetime of this object should be contained within that of
+// the BrowserProcess, and in particular the NotificationService that's
+// hung off of it.
+
+#ifndef CHROME_BROWSER_AUTOMATION_AUTOMATION_PROVIDER_H__
+#define CHROME_BROWSER_AUTOMATION_AUTOMATION_PROVIDER_H__
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include "chrome/browser/automation/automation_browser_tracker.h"
+#include "chrome/browser/automation/automation_constrained_window_tracker.h"
+#include "chrome/browser/automation/automation_tab_tracker.h"
+#include "chrome/browser/automation/automation_window_tracker.h"
+#include "chrome/browser/automation/automation_autocomplete_edit_tracker.h"
+#include "chrome/browser/browser_list.h"
+#include "chrome/browser/history/history.h"
+#include "chrome/common/ipc_channel.h"
+#include "chrome/common/ipc_message.h"
+#include "chrome/common/notification_service.h"
+
+class LoginHandler;
+class NavigationControllerRestoredObserver;
+
+class AutomationProvider : public base::RefCounted<AutomationProvider>,
+ public IPC::Channel::Listener,
+ public IPC::Message::Sender {
+ public:
+ AutomationProvider(Profile* profile);
+ virtual ~AutomationProvider();
+
+ // Establishes a connection to an automation client, if present.
+ // An AutomationProxy should be established (probably in a different process)
+ // before calling this.
+ void ConnectToChannel(const std::wstring& channel_id);
+
+ // Sets the number of tabs that we expect; when this number of tabs has
+ // loaded, an AutomationMsg_InitialLoadsComplete message is sent.
+ void SetExpectedTabCount(size_t expected_tabs);
+
+ // Add a listener for navigation status notification. Currently only
+ // navigation completion is observed; when the navigation completes, the
+ // completed_response object is sent; if the server requires authentication,
+ // we instead send the auth_needed_response object. A pointer to the added
+ // navigation observer is returned. This object should NOT be deleted and
+ // should be released by calling the corresponding
+ // RemoveNavigationStatusListener method.
+ NotificationObserver* AddNavigationStatusListener(
+ NavigationController* tab, IPC::Message* completed_response,
+ IPC::Message* auth_needed_response);
+ void RemoveNavigationStatusListener(NotificationObserver* obs);
+
+ // Add an observer for the TabStrip. Currently only Tab append is observed. A
+ // navigation listener is created on successful notification of tab append. A
+ // pointer to the added navigation observer is returned. This object should
+ // NOT be deleted and should be released by calling the corresponding
+ // RemoveTabStripObserver method.
+ NotificationObserver* AddTabStripObserver(Browser* parent,
+ int32 routing_id);
+ void RemoveTabStripObserver(NotificationObserver* obs);
+
+ // Get the index of a particular NavigationController object
+ // in the given parent window. This method uses
+ // TabStrip::GetIndexForNavigationController to get the index.
+ int GetIndexForNavigationController(const NavigationController* controller,
+ const Browser* parent) const;
+
+ // Add or remove a non-owning reference to a tab's LoginHandler. This is for
+ // when a login prompt is shown for HTTP/FTP authentication.
+ // TODO(mpcomplete): The login handling is a fairly special purpose feature.
+ // Eventually we'll probably want ways to interact with the ChromeView of the
+ // login window in a generic manner, such that it can be used for anything,
+ // not just logins.
+ void AddLoginHandler(NavigationController* tab, LoginHandler* handler);
+ void RemoveLoginHandler(NavigationController* tab);
+
+ // IPC implementations
+ virtual bool Send(IPC::Message* msg);
+ virtual void OnMessageReceived(const IPC::Message& msg);
+ virtual void OnChannelError();
+
+ // Received response from inspector controller
+ void ReceivedInspectElementResponse(int num_resources);
+
+ private:
+ // IPC Message callbacks.
+ void CloseBrowser(const IPC::Message& message, int handle);
+ void ActivateTab(const IPC::Message& message, int handle, int at_index);
+ void AppendTab(const IPC::Message& message, int handle, const GURL& url);
+ void CloseTab(const IPC::Message& message,
+ int tab_handle,
+ bool wait_until_closed);
+
+ void GetActiveTabIndex(const IPC::Message& message, int handle);
+ void GetCookies(const IPC::Message& message, const GURL& url, int handle);
+ void SetCookie(const IPC::Message& message,
+ const GURL& url,
+ const std::string value,
+ int handle);
+ void GetBrowserWindowCount(const IPC::Message& message);
+ void GetBrowserWindow(const IPC::Message& message, int index);
+ void GetLastActiveBrowserWindow(const IPC::Message& message);
+ void GetActiveWindow(const IPC::Message& message);
+ void GetWindowHWND(const IPC::Message& message, int handle);
+ void WindowGetViewBounds(const IPC::Message& message,
+ int handle,
+ int view_id,
+ bool screen_coordinates);
+ void WindowSimulateDrag(const IPC::Message& message,
+ int handle,
+ std::vector<POINT> drag_path,
+ int flags);
+ void WindowSimulateClick(const IPC::Message& message,
+ int handle,
+ POINT click,
+ int flags);
+ void WindowSimulateKeyPress(const IPC::Message& message,
+ int handle,
+ wchar_t key,
+ int flags);
+ void SetWindowVisible(const IPC::Message& message, int handle, bool visible);
+ void IsWindowActive(const IPC::Message& message, int handle);
+ void ActivateWindow(const IPC::Message& message, int handle);
+
+ void GetTabCount(const IPC::Message& message, int handle);
+ void GetTab(const IPC::Message& message, int win_handle, int tab_index);
+ void GetTabHWND(const IPC::Message& message, int handle);
+ void GetTabProcessID(const IPC::Message& message, int handle);
+ void GetTabTitle(const IPC::Message& message, int handle);
+ void GetTabURL(const IPC::Message& message, int handle);
+ void HandleUnused(const IPC::Message& message, int handle);
+ void NavigateToURL(const IPC::Message& message, int handle, const GURL& url);
+ void NavigationAsync(const IPC::Message& message,
+ int handle,
+ const GURL& url);
+ void GoBack(const IPC::Message& message, int handle);
+ void GoForward(const IPC::Message& message, int handle);
+ void Reload(const IPC::Message& message, int handle);
+ void SetAuth(const IPC::Message& message, int tab_handle,
+ const std::wstring& username, const std::wstring& password);
+ void CancelAuth(const IPC::Message& message, int tab_handle);
+ void NeedsAuth(const IPC::Message& message, int tab_handle);
+ void GetRedirectsFrom(const IPC::Message& message,
+ int tab_handle,
+ const GURL& source_url);
+ void ExecuteJavascript(const IPC::Message& message,
+ int handle,
+ const std::wstring& frame_xpath,
+ const std::wstring& script);
+ void GetShelfVisibility(const IPC::Message& message, int handle);
+ void SetFilteredInet(const IPC::Message& message, bool enabled);
+
+ void ScheduleMouseEvent(ChromeViews::View* view,
+ ChromeViews::Event::EventType type,
+ POINT point,
+ int flags);
+ void GetFocusedViewID(const IPC::Message& message, int handle);
+
+ // Helper function to find the browser window that contains a given
+ // NavigationController and activate that tab.
+ // Returns the Browser if found.
+ Browser* FindAndActivateTab(NavigationController* contents);
+
+ // Apply an accelerator with id (like IDC_BACK, IDC_FORWARD ...)
+ // to the Browser with given handle.
+ void ApplyAccelerator(int handle, int id);
+
+ void GetConstrainedWindowCount(const IPC::Message& message,
+ int handle);
+ void GetConstrainedWindow(const IPC::Message& message, int handle, int index);
+
+ void GetConstrainedTitle(const IPC::Message& message, int handle);
+
+ void GetConstrainedWindowBounds(const IPC::Message& message,
+ int handle);
+
+ // Responds to the FindInPage request, retrieves the search query parameters,
+ // launches an observer to listen for results and issues a StartFind request.
+ void HandleFindInPageRequest(const IPC::Message& message,
+ int handle,
+ const std::wstring& find_request,
+ int forward,
+ int match_case);
+
+ // Responds to InspectElement request
+ void HandleInspectElementRequest(const IPC::Message& message,
+ int handle,
+ int x,
+ int y);
+
+ void GetDownloadDirectory(const IPC::Message& message, int handle);
+
+ // Retrieves a Browser from a Window and vice-versa.
+ void GetWindowForBrowser(const IPC::Message& message, int window_handle);
+ void GetBrowserForWindow(const IPC::Message& message, int browser_handle);
+
+ void GetAutocompleteEditForBrowser(const IPC::Message& message,
+ int browser_handle);
+
+ void OpenNewBrowserWindow(int show_command);
+
+ void ShowInterstitialPage(const IPC::Message& message,
+ int tab_handle,
+ const std::string& html_text);
+ void HideInterstitialPage(const IPC::Message& message, int tab_handle);
+
+ void CreateExternalTab(const IPC::Message& message);
+ void NavigateInExternalTab(const IPC::Message& message, int handle,
+ const GURL& url);
+ // The container of an externally hosted tab calls this to reflect any
+ // accelerator keys that it did not process. This gives the tab a chance
+ // to handle the keys
+ void ProcessUnhandledAccelerator(const IPC::Message& message, int handle,
+ const MSG& msg);
+
+ // See comment in AutomationMsg_WaitForTabToBeRestored.
+ void WaitForTabToBeRestored(const IPC::Message& message, int tab_handle);
+
+ // This sets the keyboard accelerators to be used by an externally
+ // hosted tab. This call is not valid on a regular tab hosted within
+ // Chrome.
+ void SetAcceleratorsForTab(const IPC::Message& message, int handle,
+ HACCEL accel_table, int accel_entry_count);
+
+ // Gets the security state for the tab associated to the specified |handle|.
+ void GetSecurityState(const IPC::Message& message, int handle);
+
+ // Gets the page type for the tab associated to the specified |handle|.
+ void GetPageType(const IPC::Message& message, int handle);
+
+ // Simulates an action on the SSL blocking page at the tab specified by
+ // |handle|. If |proceed| is true, it is equivalent to the user pressing the
+ // 'Proceed' button, if false the 'Get me out of there button'.
+ // Not that this fails if the tab is not displaying a SSL blocking page.
+ void ActionOnSSLBlockingPage(const IPC::Message& message,
+ int handle,
+ bool proceed);
+
+ // Brings the browser window to the front and activates it.
+ void BringBrowserToFront(const IPC::Message& message, int browser_handle);
+
+ // Checks to see if a command on the browser's CommandController is enabled.
+ void IsPageMenuCommandEnabled(const IPC::Message& message,
+ int browser_handle,
+ int message_num);
+
+ // Prints the current tab immediately.
+ void PrintNow(const IPC::Message& message, int tab_handle);
+
+ // Save the current web page.
+ void SavePage(const IPC::Message& message,
+ int tab_handle,
+ const std::wstring& file_name,
+ const std::wstring& dir_path,
+ int type);
+
+ // Retrieves the visible text from the autocomplete edit.
+ void GetAutocompleteEditText(const IPC::Message& message,
+ int autocomplete_edit_handle);
+
+ // Sets the visible text from the autocomplete edit.
+ void SetAutocompleteEditText(const IPC::Message& message,
+ int autocomplete_edit_handle,
+ const std::wstring& text);
+
+ // Retrieves if a query to an autocomplete provider is in progress.
+ void AutocompleteEditIsQueryInProgress(const IPC::Message& message,
+ int autocomplete_edit_handle);
+
+ // Retrieves the individual autocomplete matches displayed by the popup.
+ void AutocompleteEditGetMatches(const IPC::Message& message,
+ int autocomplete_edit_handle);
+
+ // Callback for history redirect queries.
+ virtual void OnRedirectQueryComplete(
+ HistoryService::Handle request_handle,
+ GURL from_url,
+ bool success,
+ HistoryService::RedirectList* redirects);
+
+ typedef ObserverList<NotificationObserver> NotificationObserverList;
+ typedef std::map<NavigationController*, LoginHandler*> LoginHandlerMap;
+
+ bool connected_;
+ scoped_ptr<IPC::Channel> channel_;
+ scoped_ptr<NotificationObserver> initial_load_observer_;
+ scoped_ptr<NotificationObserver> new_tab_ui_load_observer_;
+ scoped_ptr<NotificationObserver> find_in_page_observer_;
+ scoped_ptr<NotificationObserver> dom_operation_observer_;
+ scoped_ptr<NotificationObserver> dom_inspector_observer_;
+ scoped_ptr<AutomationTabTracker> tab_tracker_;
+ scoped_ptr<AutomationConstrainedWindowTracker> cwindow_tracker_;
+ scoped_ptr<AutomationWindowTracker> window_tracker_;
+ scoped_ptr<AutomationBrowserTracker> browser_tracker_;
+ scoped_ptr<AutomationAutocompleteEditTracker> autocomplete_edit_tracker_;
+ scoped_ptr<NavigationControllerRestoredObserver> restore_tracker_;
+ LoginHandlerMap login_handler_map_;
+ NotificationObserverList notification_observer_list_;
+
+ // Handle for an in-process redirect query. We expect only one redirect query
+ // at a time (we should have only one caller, and it will block while waiting
+ // for the results) so there is only one handle. When non-0, indicates a
+ // query in progress. The routing ID will be set when the query is valid so
+ // we know where to send the response.
+ HistoryService::Handle redirect_query_;
+ int redirect_query_routing_id_;
+
+ // routing id for inspect element request so that we can send back the
+ // response later
+ int inspect_element_routing_id_;
+
+ // Consumer for asynchronous history queries.
+ CancelableRequestConsumer consumer_;
+
+ Profile* profile_;
+
+ DISALLOW_EVIL_CONSTRUCTORS(AutomationProvider);
+};
+
+// When life started, the AutomationProvider class was a singleton and was meant
+// only for UI tests. It had specific behavior (like for example, when the channel
+// was shut down. it closed all open Browsers). The new AutomationProvider serves
+// other purposes than just UI testing. This class is meant to provide the OLD
+// functionality for backward compatibility
+class TestingAutomationProvider : public AutomationProvider,
+ public BrowserList::Observer,
+ public NotificationObserver {
+ public:
+ explicit TestingAutomationProvider(Profile* profile);
+ virtual ~TestingAutomationProvider();
+
+ // BrowserList::Observer implementation
+ // Called immediately after a browser is added to the list
+ virtual void OnBrowserAdded(const Browser* browser) {
+ }
+ // Called immediately before a browser is removed from the list
+ virtual void OnBrowserRemoving(const Browser* browser);
+
+ // IPC implementations
+ virtual void OnChannelError();
+
+ private:
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details);
+};
+#endif // CHROME_BROWSER_AUTOMATION_AUTOMATION_PROVIDER_H__
diff --git a/chrome/browser/automation/automation_provider_list.cc b/chrome/browser/automation/automation_provider_list.cc
new file mode 100644
index 0000000..4d9bb93
--- /dev/null
+++ b/chrome/browser/automation/automation_provider_list.cc
@@ -0,0 +1,78 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "chrome/browser/automation/automation_provider_list.h"
+
+#include <algorithm>
+#include "base/logging.h"
+#include "chrome/browser/automation/automation_provider.h"
+
+AutomationProviderList* AutomationProviderList::instance_ = NULL;
+
+AutomationProviderList::AutomationProviderList() {
+}
+
+AutomationProviderList::~AutomationProviderList() {
+ iterator iter = automation_providers_.begin();
+ while (iter != automation_providers_.end()) {
+ AutomationProvider* provider = (*iter);
+ // Delete the entry first and update the iterator first because the d'tor
+ // of AutomationProvider will call RemoveProvider, making this iterator
+ // invalid
+ iter = automation_providers_.erase(iter);
+ g_browser_process->ReleaseModule();
+ delete provider;
+ }
+ instance_ = NULL;
+}
+
+bool AutomationProviderList::AddProvider(AutomationProvider* provider) {
+ automation_providers_.push_back(provider);
+ g_browser_process->AddRefModule();
+ return true;
+}
+
+bool AutomationProviderList::RemoveProvider(AutomationProvider* provider) {
+ const iterator remove_provider =
+ find(automation_providers_.begin(), automation_providers_.end(), provider);
+ if (remove_provider != automation_providers_.end()) {
+ automation_providers_.erase(remove_provider);
+ g_browser_process->ReleaseModule();
+ return true;
+ }
+ return false;
+}
+
+AutomationProviderList* AutomationProviderList::GetInstance() {
+ if (!instance_) {
+ instance_ = new AutomationProviderList;
+ }
+ DCHECK(NULL != instance_);
+ return instance_;
+}
diff --git a/chrome/browser/automation/automation_provider_list.h b/chrome/browser/automation/automation_provider_list.h
new file mode 100644
index 0000000..0397725
--- /dev/null
+++ b/chrome/browser/automation/automation_provider_list.h
@@ -0,0 +1,71 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#ifndef CHROME_BROWSER_AUTOMATION_AUTOMATION_PROVIDER_LIST_H__
+#define CHROME_BROWSER_AUTOMATION_AUTOMATION_PROVIDER_LIST_H__
+
+#include <vector>
+#include "base/basictypes.h"
+
+class AutomationProvider;
+
+// Stores a list of all AutomationProvider objects.
+class AutomationProviderList {
+ public:
+ ~AutomationProviderList();
+ typedef std::vector<AutomationProvider*> list_type;
+ typedef list_type::iterator iterator;
+ typedef list_type::const_iterator const_iterator;
+
+ // Adds and removes automation providers from the global list.
+ bool AddProvider(AutomationProvider* provider);
+ bool RemoveProvider(AutomationProvider* provider);
+
+ const_iterator begin() {
+ return automation_providers_.begin();
+ }
+
+ const_iterator end() {
+ return automation_providers_.end();
+ }
+
+ size_t size() {
+ return automation_providers_.size();
+ }
+
+ static AutomationProviderList* GetInstance();
+
+private:
+ AutomationProviderList();
+ list_type automation_providers_;
+ static AutomationProviderList* instance_;
+
+ DISALLOW_EVIL_CONSTRUCTORS(AutomationProviderList);
+};
+
+#endif // CHROME_BROWSER_AUTOMATION_AUTOMATION_PROVIDER_LIST_H__
diff --git a/chrome/browser/automation/automation_resource_tracker.cc b/chrome/browser/automation/automation_resource_tracker.cc
new file mode 100644
index 0000000..177f230
--- /dev/null
+++ b/chrome/browser/automation/automation_resource_tracker.cc
@@ -0,0 +1,107 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "chrome/browser/automation/automation_resource_tracker.h"
+
+#include "chrome/test/automation/automation_messages.h"
+
+int AutomationResourceTrackerImpl::AddImpl(void* resource) {
+ if (ContainsResourceImpl(resource))
+ return resource_to_handle_[resource];
+
+ int handle = GenerateHandle();
+ DCHECK(!ContainsHandleImpl(handle));
+
+ resource_to_handle_[resource] = handle;
+ handle_to_resource_[handle] = resource;
+
+ AddObserverTypeProxy(resource);
+
+ return handle;
+}
+
+void AutomationResourceTrackerImpl::RemoveImpl(void* resource) {
+ if (!ContainsResourceImpl(resource))
+ return;
+
+ int handle = resource_to_handle_[resource];
+ DCHECK(handle_to_resource_[handle] == resource);
+
+ RemoveObserverTypeProxy(resource);
+
+ resource_to_handle_.erase(resource);
+ handle_to_resource_.erase(handle);
+}
+
+int AutomationResourceTrackerImpl::GenerateHandle() {
+ static int handle = 0;
+ return ++handle;
+}
+
+bool AutomationResourceTrackerImpl::ContainsResourceImpl(void* resource) {
+ return resource_to_handle_.find(resource) != resource_to_handle_.end();
+}
+
+bool AutomationResourceTrackerImpl::ContainsHandleImpl(int handle) {
+ return handle_to_resource_.find(handle) != handle_to_resource_.end();
+}
+
+void AutomationResourceTrackerImpl::ClearAllMappingsImpl() {
+ while (!resource_to_handle_.empty()) {
+ RemoveImpl(resource_to_handle_.begin()->first);
+ }
+ cleared_mappings_ = true;
+}
+
+void* AutomationResourceTrackerImpl::GetResourceImpl(int handle) {
+ HandleToResourceMap::const_iterator iter = handle_to_resource_.find(handle);
+ if (iter == handle_to_resource_.end())
+ return NULL;
+
+ return iter->second;
+}
+
+int AutomationResourceTrackerImpl::GetHandleImpl(void* resource) {
+ ResourceToHandleMap::const_iterator iter =
+ resource_to_handle_.find(resource);
+ if (iter == resource_to_handle_.end())
+ return 0;
+
+ return iter->second;
+}
+
+void AutomationResourceTrackerImpl::HandleCloseNotification(void* resource) {
+ if (!ContainsResourceImpl(resource))
+ return;
+
+ sender_->Send(
+ new AutomationMsg_InvalidateHandle(0, resource_to_handle_[resource]));
+
+ RemoveImpl(resource);
+}
diff --git a/chrome/browser/automation/automation_resource_tracker.h b/chrome/browser/automation/automation_resource_tracker.h
new file mode 100644
index 0000000..f2380e9
--- /dev/null
+++ b/chrome/browser/automation/automation_resource_tracker.h
@@ -0,0 +1,180 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef CHROME_BROWSER_AUTOMATION_AUTOMATION_RESOURCE_TRACKER_H__
+#define CHROME_BROWSER_AUTOMATION_AUTOMATION_RESOURCE_TRACKER_H__
+
+#include <map>
+
+#include "base/basictypes.h"
+#include "chrome/common/ipc_message.h"
+#include "chrome/common/notification_service.h"
+
+// Template trick so that AutomationResourceTracker can be used with non-pointer
+// types.
+template <class T>
+struct AutomationResourceTraits {
+ typedef T ValueType;
+};
+
+template <class T>
+struct AutomationResourceTraits<T*> {
+ typedef T ValueType;
+};
+
+// This class exists for the sole purpose of allowing some of the implementation
+// of AutomationResourceTracker to live in a .cc file.
+class AutomationResourceTrackerImpl {
+public:
+ AutomationResourceTrackerImpl(IPC::Message::Sender* sender)
+ :sender_(sender), cleared_mappings_(false) {}
+
+ virtual ~AutomationResourceTrackerImpl() {}
+
+ // These need to be implemented in AutomationResourceTracker,
+ // since it needs to call the subclass's type-specific notification
+ // registration functions.
+ virtual void AddObserverTypeProxy(void* resource) = 0;
+ virtual void RemoveObserverTypeProxy(void* resource) = 0;
+
+ int AddImpl(void* resource);
+ void RemoveImpl(void* resource);
+ int GenerateHandle();
+ bool ContainsResourceImpl(void* resource);
+ bool ContainsHandleImpl(int handle);
+ void ClearAllMappingsImpl();
+ void* GetResourceImpl(int handle);
+ int GetHandleImpl(void* resource);
+ void HandleCloseNotification(void* resource);
+
+protected:
+ bool cleared_mappings_;
+ typedef std::map<void*, int> ResourceToHandleMap;
+ typedef std::map<int, void*> HandleToResourceMap;
+ ResourceToHandleMap resource_to_handle_;
+ HandleToResourceMap handle_to_resource_;
+
+private:
+ DISALLOW_EVIL_CONSTRUCTORS(AutomationResourceTrackerImpl);
+
+ IPC::Message::Sender* sender_;
+};
+
+// This template defines a superclass for an object that wants to track
+// a particular kind of application resource (like windows or tabs) for
+// automation purposes. The only things that a subclass should need to
+// define are AddObserver and RemoveObserver for the given resource's
+// close notifications, ***and a destructor that calls ClearAllMappings***.
+template <class T>
+class AutomationResourceTracker : public NotificationObserver,
+ private AutomationResourceTrackerImpl {
+ public:
+ AutomationResourceTracker(IPC::Message::Sender* automation)
+ : AutomationResourceTrackerImpl(automation) {}
+
+ virtual ~AutomationResourceTracker() {
+ // NOTE: Be sure to call ClearAllMappings() from the destructor of your
+ // subclass! It can't be called here, because it eventually uses
+ // the subclass's RemoveObserver, which no longer exists by the time
+ // this base class destructor is executed.
+ DCHECK(cleared_mappings_);
+ }
+
+ // Removes all mappings from this tracker, including unregistering from
+ // any associated resource notifications (via Remove calling RemoveObserver).
+ void ClearAllMappings() {
+ ClearAllMappingsImpl();
+ }
+
+ // The implementations for these should call the NotificationService
+ // to add and remove this object as an observer for the appropriate
+ // resource closing notification.
+ virtual void AddObserver(T resource) = 0;
+ virtual void RemoveObserver(T resource) = 0;
+
+ // Adds the given resource to this tracker, and returns a handle that
+ // can be used to refer to that resource. If the resource is already
+ // being tracked, the handle may be the same as one returned previously.
+ int Add(T resource) {
+ return AddImpl(resource);
+ }
+
+ // Removes the given resource from this tracker. If the resource is not
+ // currently present in the tracker, this is a no-op.
+ void Remove(T resource) {
+ RemoveImpl(resource);
+ }
+
+ // Returns true if this tracker currently tracks the resource pointed to
+ // by the parameter.
+ bool ContainsResource(T resource) {
+ return ContainsResourceImpl(resource);
+ }
+
+ // Returns true if this tracker currently tracks the given handle.
+ bool ContainsHandle(int handle) {
+ return ContainsHandleImpl(handle);
+ }
+
+ // Returns the resource pointer associated with a given handle, or NULL
+ // if that handle is not present in the mapping.
+ T GetResource(int handle) {
+ return static_cast<T>(GetResourceImpl(handle));
+ }
+
+ // Returns the handle associated with a given resource pointer, or 0 if
+ // the resource is not currently in the mapping.
+ int GetHandle(T resource) {
+ return GetHandleImpl(resource);
+ }
+
+ // NotificationObserver implementation--the only thing that this tracker
+ // does in response to notifications is to tell the AutomationProxy
+ // that the associated handle is now invalid.
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details){
+ T resource =
+ Source<typename AutomationResourceTraits<T>::ValueType>(source).ptr();
+
+ HandleCloseNotification(resource);
+ }
+ private:
+ // These proxy calls from the base Impl class to the template's subclss.
+ virtual void AddObserverTypeProxy(void* resource) {
+ AddObserver(static_cast<T>(resource));
+ }
+ virtual void RemoveObserverTypeProxy(void* resource) {
+ RemoveObserver(static_cast<T>(resource));
+ }
+
+ DISALLOW_EVIL_CONSTRUCTORS(AutomationResourceTracker);
+};
+
+#endif // CHROME_BROWSER_AUTOMATION_AUTOMATION_RESOURCE_TRACKER_H__
diff --git a/chrome/browser/automation/automation_tab_tracker.h b/chrome/browser/automation/automation_tab_tracker.h
new file mode 100644
index 0000000..6e9d930
--- /dev/null
+++ b/chrome/browser/automation/automation_tab_tracker.h
@@ -0,0 +1,67 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef CHROME_BROWSER_AUTOMATION_AUTOMATION_TAB_TRACKER_H__
+#define CHROME_BROWSER_AUTOMATION_AUTOMATION_TAB_TRACKER_H__
+
+#include "chrome/browser/automation/automation_resource_tracker.h"
+#include "chrome/browser/browser.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/navigation_controller.h"
+
+class AutomationTabTracker
+ : public AutomationResourceTracker<NavigationController*> {
+public:
+ AutomationTabTracker(IPC::Message::Sender* automation)
+ : AutomationResourceTracker(automation) {}
+
+ virtual ~AutomationTabTracker() {
+ ClearAllMappings();
+ }
+
+ virtual void AddObserver(NavigationController* resource) {
+ // This tab could either be a regular tab or an external tab
+ // Register for both notifications
+ NotificationService::current()->AddObserver(
+ this, NOTIFY_TAB_CLOSING, Source<NavigationController>(resource));
+ NotificationService::current()->AddObserver(
+ this, NOTIFY_EXTERNAL_TAB_CLOSED,
+ Source<NavigationController>(resource));
+ }
+
+ virtual void RemoveObserver(NavigationController* resource) {
+ NotificationService::current()->RemoveObserver(
+ this, NOTIFY_TAB_CLOSING, Source<NavigationController>(resource));
+ NotificationService::current()->RemoveObserver(
+ this, NOTIFY_EXTERNAL_TAB_CLOSED,
+ Source<NavigationController>(resource));
+ }
+};
+
+#endif // CHROME_BROWSER_AUTOMATION_AUTOMATION_TAB_TRACKER_H__
diff --git a/chrome/browser/automation/automation_window_tracker.h b/chrome/browser/automation/automation_window_tracker.h
new file mode 100644
index 0000000..d1f18a0
--- /dev/null
+++ b/chrome/browser/automation/automation_window_tracker.h
@@ -0,0 +1,56 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef CHROME_BROWSER_AUTOMATION_AUTOMATION_WINDOW_TRACKER_H__
+#define CHROME_BROWSER_AUTOMATION_AUTOMATION_WINDOW_TRACKER_H__
+
+#include "chrome/browser/automation/automation_resource_tracker.h"
+#include "chrome/views/hwnd_notification_source.h"
+
+class AutomationWindowTracker
+ : public AutomationResourceTracker<HWND> {
+ public:
+ AutomationWindowTracker(IPC::Message::Sender* automation) :
+ AutomationResourceTracker(automation) { }
+ virtual ~AutomationWindowTracker() {
+ ClearAllMappings();
+ }
+
+ virtual void AddObserver(HWND resource) {
+ NotificationService::current()->AddObserver(
+ this, NOTIFY_WINDOW_CLOSED, Source<HWND>(resource));
+ }
+
+ virtual void RemoveObserver(HWND resource) {
+ NotificationService::current()->RemoveObserver(
+ this, NOTIFY_WINDOW_CLOSED, Source<HWND>(resource));
+ }
+};
+
+#endif // CHROME_BROWSER_AUTOMATION_AUTOMATION_WINDOW_TRACKER_H__
diff --git a/chrome/browser/automation/ui_controls.cc b/chrome/browser/automation/ui_controls.cc
new file mode 100644
index 0000000..811bd89
--- /dev/null
+++ b/chrome/browser/automation/ui_controls.cc
@@ -0,0 +1,182 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "chrome/browser/automation/ui_controls.h"
+
+#include "base/logging.h"
+
+// Methods private to this file
+
+// Populate the INPUT structure with the appropriate keyboard event
+// parameters required by SendInput
+bool FillKeyboardInput(wchar_t key, INPUT* input, bool key_up) {
+ memset(input, 0, sizeof(INPUT));
+ input->type = INPUT_KEYBOARD;
+ input->ki.wVk = static_cast<WORD>(key);
+ input->ki.dwFlags = key_up ? KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP :
+ KEYEVENTF_EXTENDEDKEY;
+
+ return true;
+}
+
+// Send a key event (up/down)
+bool SendKeyEvent(wchar_t key, bool up) {
+ INPUT input = { 0 };
+
+ if (!FillKeyboardInput(key, &input, up))
+ return false;
+
+ if (!::SendInput(1, &input, sizeof(INPUT)))
+ return false;
+
+ return true;
+}
+
+namespace ui_controls {
+
+bool SendKeyPress(wchar_t key, bool control, bool shift, bool alt) {
+ INPUT input[8] = { 0 }; // 8, assuming all the modifiers are activated
+
+ int i = 0;
+ if (control) {
+ if (!FillKeyboardInput(VK_CONTROL, &input[i], false))
+ return false;
+ i++;
+ }
+
+ if (shift) {
+ if (!FillKeyboardInput(VK_SHIFT, &input[i], false))
+ return false;
+ i++;
+ }
+
+ if (alt) {
+ if (!FillKeyboardInput(VK_MENU, &input[i], false))
+ return false;
+ i++;
+ }
+
+ if (!FillKeyboardInput(key, &input[i], false))
+ return false;
+ i++;
+
+ if (!FillKeyboardInput(key, &input[i], true))
+ return false;
+ i++;
+
+ if (alt) {
+ if (!FillKeyboardInput(VK_MENU, &input[i], true))
+ return false;
+ i++;
+ }
+
+ if (shift) {
+ if (!FillKeyboardInput(VK_SHIFT, &input[i], true))
+ return false;
+ i++;
+ }
+
+ if (control) {
+ if (!FillKeyboardInput(VK_CONTROL, &input[i], true))
+ return false;
+ i++;
+ }
+
+
+ unsigned int rv = ::SendInput(i, input, sizeof(INPUT));
+
+ return rv == i;
+}
+
+bool SendKeyDown(wchar_t key) {
+ return SendKeyEvent(key, false);
+}
+
+bool SendKeyUp(wchar_t key) {
+ return SendKeyEvent(key, true);
+}
+
+bool SendMouseMove(long x, long y) {
+ INPUT input = { 0 };
+
+ int screen_width = ::GetSystemMetrics(SM_CXSCREEN) - 1;
+ int screen_height = ::GetSystemMetrics(SM_CYSCREEN) - 1;
+ LONG pixel_x = static_cast<LONG>(x * (65535.0f / screen_width));
+ LONG pixel_y = static_cast<LONG>(y * (65535.0f / screen_height));
+
+ input.type = INPUT_MOUSE;
+ input.mi.dwFlags = MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE;
+ input.mi.dx = pixel_x;
+ input.mi.dy = pixel_y;
+
+ if (!::SendInput(1, &input, sizeof(INPUT)))
+ return false;
+ return true;
+}
+
+bool SendMouseClick(MouseButton type) {
+
+ DWORD down_flags = MOUSEEVENTF_ABSOLUTE;
+ DWORD up_flags = MOUSEEVENTF_ABSOLUTE;
+
+ switch(type) {
+ case LEFT:
+ down_flags |= MOUSEEVENTF_LEFTDOWN;
+ up_flags |= MOUSEEVENTF_LEFTUP;
+
+ break;
+ case MIDDLE:
+ down_flags |= MOUSEEVENTF_MIDDLEDOWN;
+ up_flags |= MOUSEEVENTF_MIDDLEUP;
+
+ break;
+ case RIGHT:
+ down_flags |= MOUSEEVENTF_RIGHTDOWN;
+ up_flags |= MOUSEEVENTF_RIGHTUP;
+
+ break;
+ default:
+ NOTREACHED();
+ return false;
+ }
+
+ INPUT input = { 0 };
+ input.type = INPUT_MOUSE;
+ input.mi.dwFlags = down_flags;
+ if (!::SendInput(1, &input, sizeof(INPUT)))
+ return false;
+
+ input.mi.dwFlags = up_flags;
+ if (!::SendInput(1, &input, sizeof(INPUT)))
+ return false;
+
+ return true;
+}
+
+} // ui_controls
diff --git a/chrome/browser/automation/ui_controls.h b/chrome/browser/automation/ui_controls.h
new file mode 100644
index 0000000..4a655f5
--- /dev/null
+++ b/chrome/browser/automation/ui_controls.h
@@ -0,0 +1,62 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef CHROME_BROWSER_AUTOMATION_UI_CONTROLS_H__
+#define CHROME_BROWSER_AUTOMATION_UI_CONTROLS_H__
+
+#include <string>
+#include <wtypes.h>
+
+namespace ui_controls {
+
+// Send a key press with/without modifier keys.
+bool SendKeyPress(wchar_t key, bool control, bool shift, bool alt);
+
+// Send a key down event. Use VK_CONTROL for ctrl key,
+// VK_MENU for alt key and VK_SHIFT for shift key.
+// Refer MSDN for more virtual key codes.
+bool SendKeyDown(wchar_t key);
+bool SendKeyUp(wchar_t key);
+
+// Simulate a mouse move. (x,y) are absolute
+// screen coordinates.
+bool SendMouseMove(long x, long y);
+
+enum MouseButton {
+ LEFT = 0,
+ MIDDLE,
+ RIGHT,
+};
+
+// Simulate a single mouse click with given button type.
+bool SendMouseClick(MouseButton type);
+
+} // ui_controls
+
+#endif // CHROME_BROWSER_AUTOMATION_UI_CONTROLS_H__ \ No newline at end of file
diff --git a/chrome/browser/automation/url_request_failed_dns_job.cc b/chrome/browser/automation/url_request_failed_dns_job.cc
new file mode 100644
index 0000000..1272b6d
--- /dev/null
+++ b/chrome/browser/automation/url_request_failed_dns_job.cc
@@ -0,0 +1,61 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "chrome/browser/automation/url_request_failed_dns_job.h"
+
+#include "base/message_loop.h"
+#include "net/base/net_errors.h"
+#include "net/url_request/url_request.h"
+#include "net/url_request/url_request_filter.h"
+
+const wchar_t URLRequestFailedDnsJob::kTestUrl[] =
+ L"http://url.handled.by.fake.dns/";
+
+void URLRequestFailedDnsJob::Start() {
+ MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
+ this, &URLRequestFailedDnsJob::StartAsync));
+}
+
+/* static */
+void URLRequestFailedDnsJob::AddUITestUrls() {
+ URLRequestFilter* filter = URLRequestFilter::GetInstance();
+ filter->AddUrlHandler(GURL(kTestUrl),
+ &URLRequestFailedDnsJob::Factory);
+}
+
+/*static */
+URLRequestJob* URLRequestFailedDnsJob::Factory(URLRequest* request,
+ const std::string& scheme) {
+ return new URLRequestFailedDnsJob(request);
+}
+
+void URLRequestFailedDnsJob::StartAsync() {
+ NotifyStartError(URLRequestStatus(URLRequestStatus::FAILED,
+ net::ERR_NAME_NOT_RESOLVED));
+}
diff --git a/chrome/browser/automation/url_request_failed_dns_job.h b/chrome/browser/automation/url_request_failed_dns_job.h
new file mode 100644
index 0000000..1020ae3
--- /dev/null
+++ b/chrome/browser/automation/url_request_failed_dns_job.h
@@ -0,0 +1,58 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+// This class simulates what wininet does when a dns lookup fails.
+
+#ifndef CHROME_BROWSER_AUTOMATION_URL_REQUEST_FAILED_DNS_JOB_H__
+#define CHROME_BROWSER_AUTOMATION_URL_REQUEST_FAILED_DNS_JOB_H__
+
+#include "googleurl/src/gurl.h"
+#include "net/url_request/url_request_job.h"
+
+class URLRequestFailedDnsJob : public URLRequestJob {
+ public:
+ URLRequestFailedDnsJob(URLRequest* request)
+ : URLRequestJob(request) { }
+
+ virtual void Start();
+
+ static URLRequestJob* Factory(URLRequest* request,
+ const std::string& scheme);
+
+ // A test URL that can be used in UI tests.
+ static const wchar_t kTestUrl[];
+
+ // For UI tests: adds the testing URLs to the URLRequestFilter.
+ static void AddUITestUrls();
+
+ private:
+ // Simulate a DNS failure.
+ void StartAsync();
+};
+
+#endif // CHROME_BROWSER_AUTOMATION_URL_REQUEST_FAILED_DNS_JOB_H__
diff --git a/chrome/browser/automation/url_request_mock_http_job.cc b/chrome/browser/automation/url_request_mock_http_job.cc
new file mode 100644
index 0000000..5df0ed7
--- /dev/null
+++ b/chrome/browser/automation/url_request_mock_http_job.cc
@@ -0,0 +1,111 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <windows.h>
+
+#include "chrome/browser/automation/url_request_mock_http_job.h"
+
+#include "base/file_util.h"
+#include "base/message_loop.h"
+#include "base/string_util.h"
+#include "net/base/net_util.h"
+#include "net/url_request/url_request_filter.h"
+
+static const char kMockHostname[] = "mock.http";
+static const wchar_t kMockHeaderFileSuffix[] = L".mock-http-headers";
+
+std::wstring URLRequestMockHTTPJob::base_path_ = L"";
+
+/* static */
+URLRequestJob* URLRequestMockHTTPJob::Factory(URLRequest* request,
+ const std::string& scheme) {
+ std::wstring file_url(L"file:///");
+ file_url += base_path_;
+ const std::string& url = request->url().spec();
+ // Fix up the url to be the file url we're loading from disk.
+ std::string host_prefix("http://");
+ host_prefix.append(kMockHostname);
+ size_t host_prefix_len = host_prefix.length();
+ if (url.compare(0, host_prefix_len, host_prefix.data(),
+ host_prefix_len) == 0) {
+ file_url += UTF8ToWide(url.substr(host_prefix_len));
+ }
+
+ // Convert the file:/// URL to a path on disk.
+ std::wstring file_path;
+ net_util::FileURLToFilePath(GURL(file_url), &file_path);
+ URLRequestMockHTTPJob* job = new URLRequestMockHTTPJob(request);
+ job->file_path_ = file_path;
+ return job;
+}
+
+/* static */
+void URLRequestMockHTTPJob::AddUITestUrls(const std::wstring& base_path) {
+ base_path_ = base_path;
+
+ // Add kMockHostname to URLRequestFilter.
+ URLRequestFilter* filter = URLRequestFilter::GetInstance();
+ filter->AddHostnameHandler("http", kMockHostname,
+ URLRequestMockHTTPJob::Factory);
+}
+
+/* static */
+GURL URLRequestMockHTTPJob::GetMockUrl(const std::wstring& path) {
+ std::wstring url = L"http://";
+ url.append(UTF8ToWide(kMockHostname));
+ url.append(L"/");
+ url.append(path);
+ return GURL(url);
+}
+
+URLRequestMockHTTPJob::URLRequestMockHTTPJob(URLRequest* request)
+ : URLRequestFileJob(request) { }
+
+void URLRequestMockHTTPJob::GetResponseInfo(net::HttpResponseInfo* info) {
+ std::wstring header_file = file_path_ + kMockHeaderFileSuffix;
+ std::string raw_headers;
+ if (!file_util::ReadFileToString(header_file, &raw_headers))
+ return;
+
+ // ParseRawHeaders expects \0 to end each header line.
+ ReplaceSubstringsAfterOffset(&raw_headers, 0, "\n", std::string("\0", 1));
+ info->headers = new net::HttpResponseHeaders(raw_headers);
+}
+
+bool URLRequestMockHTTPJob::GetMimeType(std::string* mime_type) {
+ net::HttpResponseInfo info;
+ GetResponseInfo(&info);
+ return info.headers && info.headers->GetMimeType(mime_type);
+}
+
+bool URLRequestMockHTTPJob::GetCharset(std::string* charset) {
+ net::HttpResponseInfo info;
+ GetResponseInfo(&info);
+ return info.headers && info.headers->GetCharset(charset);
+}
diff --git a/chrome/browser/automation/url_request_mock_http_job.h b/chrome/browser/automation/url_request_mock_http_job.h
new file mode 100644
index 0000000..0c64587
--- /dev/null
+++ b/chrome/browser/automation/url_request_mock_http_job.h
@@ -0,0 +1,60 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// A URLRequestJob class that pulls the content and http headers from disk.
+
+#ifndef CHROME_BROWSER_AUTOMATION_URL_REQUEST_MOCK_HTTP_JOB_H__
+#define CHROME_BROWSER_AUTOMATION_URL_REQUEST_MOCK_HTTP_JOB_H__
+
+#include "net/url_request/url_request_file_job.h"
+
+class URLRequestMockHTTPJob : public URLRequestFileJob {
+ public:
+ URLRequestMockHTTPJob(URLRequest* request);
+ virtual ~URLRequestMockHTTPJob() { }
+
+ virtual bool GetMimeType(std::string* mime_type);
+ virtual bool GetCharset(std::string* charset);
+ virtual void GetResponseInfo(net::HttpResponseInfo* info);
+
+ static URLRequest::ProtocolFactory Factory;
+
+ // For UI tests: adds the testing URLs to the URLRequestFilter.
+ static void AddUITestUrls(const std::wstring& base_path);
+
+ // Given the path to a file relative to base_path_, construct a mock URL.
+ static GURL GetMockUrl(const std::wstring& path);
+
+ private:
+ // This is the file path leading to the root of the directory to use as the
+ // root of the http server.
+ static std::wstring base_path_;
+};
+
+# endif // CHROME_BROWSER_AUTOMATION_URL_REQUEST_MOCK_HTTP_JOB_H__
diff --git a/chrome/browser/automation/url_request_mock_net_error_job.cc b/chrome/browser/automation/url_request_mock_net_error_job.cc
new file mode 100644
index 0000000..06adfb7
--- /dev/null
+++ b/chrome/browser/automation/url_request_mock_net_error_job.cc
@@ -0,0 +1,125 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "chrome/browser/automation/url_request_mock_net_error_job.h"
+
+#include "base/file_util.h"
+#include "base/message_loop.h"
+#include "base/string_util.h"
+#include "net/base/net_util.h"
+#include "net/url_request/url_request_filter.h"
+
+// static
+URLRequestMockNetErrorJob::URLMockInfoMap
+ URLRequestMockNetErrorJob::url_mock_info_map_;
+
+// static
+void URLRequestMockNetErrorJob::AddMockedURL(const GURL& url,
+ const std::wstring& base,
+ const std::vector<int>& errors,
+ X509Certificate* ssl_cert) {
+#ifndef NDEBUG
+ URLMockInfoMap::const_iterator iter = url_mock_info_map_.find(url);
+ DCHECK(iter == url_mock_info_map_.end());
+#endif
+
+ url_mock_info_map_[url] = MockInfo(base, errors, ssl_cert);
+ URLRequestFilter::GetInstance()
+ ->AddUrlHandler(url, &URLRequestMockNetErrorJob::Factory);
+}
+
+// static
+void URLRequestMockNetErrorJob::RemoveMockedURL(const GURL& url) {
+ URLMockInfoMap::iterator iter = url_mock_info_map_.find(url);
+ DCHECK(iter != url_mock_info_map_.end());
+ url_mock_info_map_.erase(iter);
+ URLRequestFilter::GetInstance()->RemoveUrlHandler(url);
+}
+
+// static
+URLRequestJob* URLRequestMockNetErrorJob::Factory(URLRequest* request,
+ const std::string& scheme) {
+ GURL url = request->url();
+
+ URLMockInfoMap::const_iterator iter = url_mock_info_map_.find(url);
+ DCHECK(iter != url_mock_info_map_.end());
+
+ MockInfo mock_info = iter->second;
+ URLRequestMockNetErrorJob* job =
+ new URLRequestMockNetErrorJob(request, mock_info.errors,
+ mock_info.ssl_cert);
+
+ // URLRequestMockNetErrorJob derives from URLRequestFileJob. We set the
+ // file_path_ of the job so that the URLRequestFileJob methods will do the
+ // loading from the files.
+ std::wstring file_url(L"file:///");
+ file_url.append(mock_info.base);
+ file_url.append(UTF8ToWide(url.path()));
+ // Convert the file:/// URL to a path on disk.
+ std::wstring file_path;
+ net_util::FileURLToFilePath(GURL(file_url), &file_path);
+ job->file_path_ = file_path;
+ return job;
+}
+
+URLRequestMockNetErrorJob::URLRequestMockNetErrorJob(URLRequest* request,
+ const std::vector<int>& errors, X509Certificate* cert)
+ : URLRequestMockHTTPJob(request),
+ errors_(errors),
+ ssl_cert_(cert) {
+}
+
+URLRequestMockNetErrorJob::~URLRequestMockNetErrorJob() {
+}
+
+void URLRequestMockNetErrorJob::Start() {
+ MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
+ this, &URLRequestMockNetErrorJob::StartAsync));
+}
+
+void URLRequestMockNetErrorJob::StartAsync() {
+ if (errors_.empty()) {
+ URLRequestMockHTTPJob::Start();
+ } else {
+ int error = errors_[0];
+ errors_.erase(errors_.begin());
+
+ if (net::IsCertificateError(error)) {
+ DCHECK(ssl_cert_);
+ request_->delegate()->OnSSLCertificateError(request_, error,
+ ssl_cert_.get());
+ } else {
+ NotifyStartError(URLRequestStatus(URLRequestStatus::FAILED, error));
+ }
+ }
+}
+
+void URLRequestMockNetErrorJob::ContinueDespiteLastError() {
+ Start();
+}
diff --git a/chrome/browser/automation/url_request_mock_net_error_job.h b/chrome/browser/automation/url_request_mock_net_error_job.h
new file mode 100644
index 0000000..bee1c31
--- /dev/null
+++ b/chrome/browser/automation/url_request_mock_net_error_job.h
@@ -0,0 +1,95 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// A URLRequestJob class that simulates network errors (including https
+// related).
+// It is based on URLRequestMockHttpJob.
+
+#ifndef CHROME_BROWSER_AUTOMATION_URL_REQUEST_MOCK_NET_ERROR_H__
+#define CHROME_BROWSER_AUTOMATION_URL_REQUEST_MOCK_NET_ERROR_H__
+
+#include "chrome/browser/automation/url_request_mock_http_job.h"
+#include "net/base/net_errors.h"
+
+class URLRequestMockNetErrorJob : public URLRequestMockHTTPJob {
+ public:
+ URLRequestMockNetErrorJob(URLRequest* request,
+ const std::vector<int>& errors,
+ X509Certificate* ssl_cert);
+ virtual ~URLRequestMockNetErrorJob();
+
+ virtual void Start();
+ virtual void ContinueDespiteLastError();
+
+ // Add the specified URL to the list of URLs that should be mocked. When this
+ // URL is hit, the specified |errors| will be played. If any of these errors
+ // is a cert error, |ssl_cert| will be used as the ssl cert when notifying of
+ // the error. |ssl_cert| can be NULL if |errors| does not contain any cert
+ // errors. |base| is the location on disk where the file mocking the URL
+ // contents and http-headers should be retrieved from.
+ static void AddMockedURL(const GURL& url,
+ const std::wstring& base,
+ const std::vector<int>& errors,
+ X509Certificate* ssl_cert);
+
+ // Removes the specified |url| from the list of mocked urls.
+ static void RemoveMockedURL(const GURL& url);
+
+ private:
+ struct MockInfo {
+ MockInfo() : ssl_cert(NULL) { }
+ MockInfo(std::wstring base,
+ std::vector<int> errors,
+ X509Certificate* ssl_cert)
+ : base(base),
+ errors(errors),
+ ssl_cert(ssl_cert) { }
+
+ std::wstring base;
+ std::vector<int> errors;
+ scoped_refptr<X509Certificate> ssl_cert;
+ };
+
+ static URLRequest::ProtocolFactory Factory;
+
+ void StartAsync();
+
+ // The errors to simulate.
+ std::vector<int> errors_;
+
+ // The certificate to use for SSL errors.
+ scoped_refptr<X509Certificate> ssl_cert_;
+
+ typedef std::map<GURL, MockInfo> URLMockInfoMap;
+ static URLMockInfoMap url_mock_info_map_;
+
+ DISALLOW_EVIL_CONSTRUCTORS(URLRequestMockNetErrorJob);
+};
+
+#endif // #define CHROME_BROWSER_AUTOMATION_URL_REQUEST_MOCK_NET_ERROR_H__
diff --git a/chrome/browser/automation/url_request_slow_download_job.cc b/chrome/browser/automation/url_request_slow_download_job.cc
new file mode 100644
index 0000000..cac0cab
--- /dev/null
+++ b/chrome/browser/automation/url_request_slow_download_job.cc
@@ -0,0 +1,186 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "chrome/browser/automation/url_request_slow_download_job.h"
+
+#include "base/message_loop.h"
+#include "base/string_util.h"
+#include "net/url_request/url_request.h"
+#include "net/url_request/url_request_filter.h"
+
+const int kFirstDownloadSize = 1024 * 35;
+const int kSecondDownloadSize = 1024 * 10;
+
+const wchar_t URLRequestSlowDownloadJob::kUnknownSizeUrl[] =
+ L"http://url.handled.by.slow.download/download-unknown-size";
+const wchar_t URLRequestSlowDownloadJob::kKnownSizeUrl[] =
+ L"http://url.handled.by.slow.download/download-known-size";
+const wchar_t URLRequestSlowDownloadJob::kFinishDownloadUrl[] =
+ L"http://url.handled.by.slow.download/download-finish";
+
+std::vector<URLRequestSlowDownloadJob*>
+ URLRequestSlowDownloadJob::kPendingRequests;
+
+void URLRequestSlowDownloadJob::Start() {
+ MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(this,
+ &URLRequestSlowDownloadJob::StartAsync));
+}
+
+/* static */
+void URLRequestSlowDownloadJob::AddUITestUrls() {
+ URLRequestFilter* filter = URLRequestFilter::GetInstance();
+ filter->AddUrlHandler(GURL(kUnknownSizeUrl),
+ &URLRequestSlowDownloadJob::Factory);
+ filter->AddUrlHandler(GURL(kKnownSizeUrl),
+ &URLRequestSlowDownloadJob::Factory);
+ filter->AddUrlHandler(GURL(kFinishDownloadUrl),
+ &URLRequestSlowDownloadJob::Factory);
+}
+
+/*static */
+URLRequestJob* URLRequestSlowDownloadJob::Factory(URLRequest* request,
+ const std::string& scheme) {
+ URLRequestSlowDownloadJob* job = new URLRequestSlowDownloadJob(request);
+ if (request->url().spec() != WideToUTF8(kFinishDownloadUrl))
+ URLRequestSlowDownloadJob::kPendingRequests.push_back(job);
+ return job;
+}
+
+/* static */
+void URLRequestSlowDownloadJob::FinishPendingRequests() {
+ typedef std::vector<URLRequestSlowDownloadJob*> JobList;
+ for (JobList::iterator it = kPendingRequests.begin(); it !=
+ kPendingRequests.end(); ++it) {
+ (*it)->set_should_finish_download();
+ }
+ kPendingRequests.clear();
+}
+
+URLRequestSlowDownloadJob::URLRequestSlowDownloadJob(URLRequest* request)
+ : URLRequestJob(request),
+ first_download_size_remaining_(kFirstDownloadSize),
+ should_finish_download_(false),
+ should_send_second_chunk_(false) {
+}
+
+void URLRequestSlowDownloadJob::StartAsync() {
+ if (LowerCaseEqualsASCII(kFinishDownloadUrl, request_->url().spec().c_str()))
+ URLRequestSlowDownloadJob::FinishPendingRequests();
+
+ NotifyHeadersComplete();
+}
+
+bool URLRequestSlowDownloadJob::ReadRawData(char* buf, int buf_size,
+ int *bytes_read) {
+ if (LowerCaseEqualsASCII(kFinishDownloadUrl,
+ request_->url().spec().c_str())) {
+ *bytes_read = 0;
+ return true;
+ }
+
+ if (should_send_second_chunk_) {
+ DCHECK(buf_size > kSecondDownloadSize);
+ for (int i = 0; i < kSecondDownloadSize; ++i) {
+ buf[i] = '*';
+ }
+ *bytes_read = kSecondDownloadSize;
+ should_send_second_chunk_ = false;
+ return true;
+ }
+
+ if (first_download_size_remaining_ > 0) {
+ int send_size = std::min(first_download_size_remaining_, buf_size);
+ for (int i = 0; i < send_size; ++i) {
+ buf[i] = '*';
+ }
+ *bytes_read = send_size;
+ first_download_size_remaining_ -= send_size;
+
+ SetStatus(URLRequestStatus(URLRequestStatus::IO_PENDING, 0));
+ DCHECK(!is_done());
+ return true;
+ }
+
+ if (should_finish_download_) {
+ *bytes_read = 0;
+ return true;
+ }
+
+ // If we make it here, the first chunk has been sent and we need to wait
+ // until a request is made for kFinishDownloadUrl.
+ MessageLoop::current()->PostDelayedTask(FROM_HERE, NewRunnableMethod(
+ this, &URLRequestSlowDownloadJob::CheckDoneStatus), 100);
+ AddRef();
+
+ // Return false to signal there is pending data.
+ return false;
+}
+
+void URLRequestSlowDownloadJob::CheckDoneStatus() {
+ if (should_finish_download_) {
+ should_send_second_chunk_ = true;
+ SetStatus(URLRequestStatus());
+ NotifyReadComplete(kSecondDownloadSize);
+ Release();
+ } else {
+ MessageLoop::current()->PostDelayedTask(FROM_HERE, NewRunnableMethod(
+ this, &URLRequestSlowDownloadJob::CheckDoneStatus), 100);
+ }
+}
+
+void URLRequestSlowDownloadJob::GetResponseInfo(net::HttpResponseInfo* info) {
+ // Send back mock headers.
+ std::string raw_headers;
+ if (LowerCaseEqualsASCII(kFinishDownloadUrl,
+ request_->url().spec().c_str())) {
+ raw_headers.append(
+ "HTTP/1.1 200 OK\n"
+ "Content-type: text/plain\n");
+ } else {
+ raw_headers.append(
+ "HTTP/1.1 200 OK\n"
+ "Content-type: application/octet-stream\n"
+ "Cache-Control: max-age=0\n");
+
+ if (LowerCaseEqualsASCII(kKnownSizeUrl, request_->url().spec().c_str())) {
+ raw_headers.append(StringPrintf("Content-Length: %d\n",
+ kFirstDownloadSize + kSecondDownloadSize));
+ }
+ }
+
+ // ParseRawHeaders expects \0 to end each header line.
+ ReplaceSubstringsAfterOffset(&raw_headers, 0, "\n", std::string("\0", 1));
+ info->headers = new net::HttpResponseHeaders(raw_headers);
+}
+
+bool URLRequestSlowDownloadJob::GetMimeType(std::string* mime_type) {
+ net::HttpResponseInfo info;
+ GetResponseInfo(&info);
+ return info.headers && info.headers->GetMimeType(mime_type);
+}
diff --git a/chrome/browser/automation/url_request_slow_download_job.h b/chrome/browser/automation/url_request_slow_download_job.h
new file mode 100644
index 0000000..d05f850
--- /dev/null
+++ b/chrome/browser/automation/url_request_slow_download_job.h
@@ -0,0 +1,82 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+// This class simulates a slow download. This used in a UI test to test the
+// download manager. Requests to |kUnknownSizeUrl| and |kKnownSizeUrl| start
+// downloads that pause after the first
+
+#ifndef CHROME_BROWSER_AUTOMATION_URL_REQUEST_SLOW_DOWNLOAD_JOB_H__
+#define CHROME_BROWSER_AUTOMATION_URL_REQUEST_SLOW_DOWNLOAD_JOB_H__
+
+#include <vector>
+
+#include "googleurl/src/gurl.h"
+#include "net/url_request/url_request_job.h"
+
+class URLRequestSlowDownloadJob : public URLRequestJob {
+ public:
+ URLRequestSlowDownloadJob(URLRequest* request);
+ virtual ~URLRequestSlowDownloadJob() { }
+
+ // Timer callback, used to check to see if we should finish our download and
+ // send the second chunk.
+ void CheckDoneStatus();
+
+ // URLRequestJob methods
+ virtual void Start();
+ virtual bool GetMimeType(std::string* mime_type);
+ virtual void GetResponseInfo(net::HttpResponseInfo* info);
+ virtual bool ReadRawData(char* buf, int buf_size, int *bytes_read);
+
+ static URLRequestJob* Factory(URLRequest* request,
+ const std::string& scheme);
+
+ // Test URLs.
+ static const wchar_t kUnknownSizeUrl[];
+ static const wchar_t kKnownSizeUrl[];
+ static const wchar_t kFinishDownloadUrl[];
+
+ // For UI tests: adds the testing URLs to the URLRequestFilter.
+ static void AddUITestUrls();
+
+ private:
+ // Mark all pending requests to be finished. We keep track of pending
+ // requests in |kPendingRequests|.
+ static void FinishPendingRequests();
+ static std::vector<URLRequestSlowDownloadJob*> kPendingRequests;
+
+ void StartAsync();
+
+ void set_should_finish_download() { should_finish_download_ = true; }
+
+ int first_download_size_remaining_;
+ bool should_finish_download_;
+ bool should_send_second_chunk_;
+};
+
+#endif // CHROME_BROWSER_AUTOMATION_URL_REQUEST_SLOW_DOWNLOAD_JOB_H__