diff options
Diffstat (limited to 'chrome')
22 files changed, 881 insertions, 98 deletions
diff --git a/chrome/browser/automation/automation_provider.cc b/chrome/browser/automation/automation_provider.cc index 1217c1a..f386960 100755 --- a/chrome/browser/automation/automation_provider.cc +++ b/chrome/browser/automation/automation_provider.cc @@ -806,10 +806,12 @@ AutomationProvider::~AutomationProvider() { } void AutomationProvider::ConnectToChannel(const std::string& channel_id) { + automation_resource_message_filter_ = new AutomationResourceMessageFilter; channel_.reset( - new IPC::SyncChannel(channel_id, IPC::Channel::MODE_CLIENT, this, NULL, - g_browser_process->io_thread()->message_loop(), - true, g_browser_process->shutdown_event())); + new IPC::SyncChannel(channel_id, IPC::Channel::MODE_CLIENT, this, + automation_resource_message_filter_, + g_browser_process->io_thread()->message_loop(), + true, g_browser_process->shutdown_event())); scoped_ptr<FileVersionInfo> file_version_info( FileVersionInfo::CreateFileVersionInfoForCurrentModule()); std::string version_string; @@ -2390,8 +2392,8 @@ void AutomationProvider::CreateExternalTab(HWND parent, *tab_handle = 0; *tab_container_window = NULL; *tab_window = NULL; - ExternalTabContainer *external_tab_container = - new ExternalTabContainer(this); + ExternalTabContainer* external_tab_container = + new ExternalTabContainer(this, automation_resource_message_filter_); Profile* profile = incognito? profile_->GetOffTheRecordProfile() : profile_; external_tab_container->Init(profile, parent, dimensions, style); TabContents* tab_contents = external_tab_container->tab_contents(); diff --git a/chrome/browser/automation/automation_provider.h b/chrome/browser/automation/automation_provider.h index c83eaaa..3d90d04 100644 --- a/chrome/browser/automation/automation_provider.h +++ b/chrome/browser/automation/automation_provider.h @@ -19,6 +19,7 @@ #include "base/scoped_ptr.h" #include "chrome/browser/automation/automation_autocomplete_edit_tracker.h" #include "chrome/browser/automation/automation_browser_tracker.h" +#include "chrome/browser/automation/automation_resource_message_filter.h" #include "chrome/browser/automation/automation_tab_tracker.h" #include "chrome/browser/automation/automation_window_tracker.h" #include "chrome/browser/browser_list.h" @@ -487,6 +488,8 @@ class AutomationProvider : public base::RefCounted<AutomationProvider>, LoginHandlerMap login_handler_map_; PortContainerMap port_containers_; NotificationObserverList notification_observer_list_; + scoped_refptr<AutomationResourceMessageFilter> + automation_resource_message_filter_; // 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 diff --git a/chrome/browser/automation/automation_resource_message_filter.cc b/chrome/browser/automation/automation_resource_message_filter.cc new file mode 100644 index 0000000..15e5325 --- /dev/null +++ b/chrome/browser/automation/automation_resource_message_filter.cc @@ -0,0 +1,144 @@ +// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/automation/automation_resource_message_filter.h" + +#include "base/message_loop.h" +#include "chrome/browser/automation/url_request_automation_job.h" + + +MessageLoop* AutomationResourceMessageFilter::io_loop_ = NULL; +AutomationResourceMessageFilter::RenderViewMap + AutomationResourceMessageFilter::filtered_render_views_; + +AutomationResourceMessageFilter::AutomationResourceMessageFilter() + : channel_(NULL), unique_request_id_(1) { + URLRequestAutomationJob::InitializeInterceptor(); +} + +AutomationResourceMessageFilter::~AutomationResourceMessageFilter() { +} + +// Called on the IPC thread: +void AutomationResourceMessageFilter::OnFilterAdded(IPC::Channel* channel) { + DCHECK(channel_ == NULL); + channel_ = channel; + io_loop_ = MessageLoop::current(); +} + +// Called on the IPC thread: +void AutomationResourceMessageFilter::OnChannelConnected(int32 peer_pid) { +} + +// Called on the IPC thread: +void AutomationResourceMessageFilter::OnChannelClosing() { + channel_ = NULL; + request_map_.clear(); + filtered_render_views_.clear(); +} + +// Called on the IPC thread: +bool AutomationResourceMessageFilter::OnMessageReceived( + const IPC::Message& message) { + int request_id = URLRequestAutomationJob::MayFilterMessage(message); + if (request_id) { + RequestMap::iterator it = request_map_.find(request_id); + if (it != request_map_.end()) { + URLRequestAutomationJob* job = it->second; + DCHECK(job); + if (job) { + job->OnMessage(message); + return true; + } + } + } + + return false; +} + +// Called on the IPC thread: +bool AutomationResourceMessageFilter::Send(IPC::Message* message) { + // This has to be called on the IO thread. + DCHECK_EQ(io_loop_, MessageLoop::current()); + if (!channel_) { + delete message; + return false; + } + + return channel_->Send(message); +} + +bool AutomationResourceMessageFilter::RegisterRequest( + URLRequestAutomationJob* job) { + if (!job) { + NOTREACHED(); + return false; + } + + DCHECK_EQ(io_loop_, MessageLoop::current()); + DCHECK(request_map_.end() == request_map_.find(job->id())); + request_map_[job->id()] = job; + return true; +} + +void AutomationResourceMessageFilter::UnRegisterRequest( + URLRequestAutomationJob* job) { + DCHECK_EQ(io_loop_, MessageLoop::current()); + DCHECK(request_map_.find(job->id()) != request_map_.end()); + request_map_.erase(job->id()); +} + +bool AutomationResourceMessageFilter::RegisterRenderView( + int renderer_pid, int renderer_id, int tab_handle, + AutomationResourceMessageFilter* filter) { + if (!renderer_pid || !renderer_id || !tab_handle) { + NOTREACHED(); + return false; + } + + DCHECK(io_loop_); + io_loop_->PostTask(FROM_HERE, NewRunnableFunction( + AutomationResourceMessageFilter::RegisterRenderViewInIOThread, + renderer_pid, renderer_id, tab_handle, filter)); + return true; +} + +void AutomationResourceMessageFilter::UnRegisterRenderView( + int renderer_pid, int renderer_id) { + DCHECK(io_loop_); + io_loop_->PostTask(FROM_HERE, NewRunnableFunction( + AutomationResourceMessageFilter::UnRegisterRenderViewInIOThread, + renderer_pid, renderer_id)); +} + +void AutomationResourceMessageFilter::RegisterRenderViewInIOThread( + int renderer_pid, int renderer_id, + int tab_handle, AutomationResourceMessageFilter* filter) { + DCHECK(filtered_render_views_.find(RendererId(renderer_pid, renderer_id)) == + filtered_render_views_.end()); + filtered_render_views_[RendererId(renderer_pid, renderer_id)] = + AutomationDetails(tab_handle, filter); +} + +void AutomationResourceMessageFilter::UnRegisterRenderViewInIOThread( + int renderer_pid, int renderer_id) { + DCHECK(filtered_render_views_.find(RendererId(renderer_pid, renderer_id)) != + filtered_render_views_.end()); + filtered_render_views_.erase(RendererId(renderer_pid, renderer_id)); +} + +bool AutomationResourceMessageFilter::LookupRegisteredRenderView( + int renderer_pid, int renderer_id, AutomationDetails* details) { + bool found = false; + RenderViewMap::iterator it = filtered_render_views_.find(RendererId( + renderer_pid, renderer_id)); + if (it != filtered_render_views_.end()) { + found = true; + if (details) + *details = it->second; + } + + return found; +} + diff --git a/chrome/browser/automation/automation_resource_message_filter.h b/chrome/browser/automation/automation_resource_message_filter.h new file mode 100644 index 0000000..7bec5ca --- /dev/null +++ b/chrome/browser/automation/automation_resource_message_filter.h @@ -0,0 +1,110 @@ +// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_AUTOMATION_AUTOMATION_RESOURCE_MSG_FILTER_H_ +#define CHROME_BROWSER_AUTOMATION_AUTOMATION_RESOURCE_MSG_FILTER_H_ + +#include <map> + +#include "base/lock.h" +#include "base/platform_thread.h" +#include "chrome/common/ipc_channel_proxy.h" + +class URLRequestAutomationJob; +class MessageLoop; + +// This class filters out incoming automation IPC messages for network +// requests and processes them on the IPC thread. As a result, network +// requests are not delayed by costly UI processing that may be occurring +// on the main thread of the browser. It also means that any hangs in +// starting a network request will not interfere with browser UI. +class AutomationResourceMessageFilter + : public IPC::ChannelProxy::MessageFilter, + public IPC::Message::Sender { + public: + // Information needed to send IPCs through automation. + struct AutomationDetails { + AutomationDetails() : tab_handle(0) {} + AutomationDetails(int tab, AutomationResourceMessageFilter* flt) + : tab_handle(tab), filter(flt) { + } + + int tab_handle; + scoped_refptr<AutomationResourceMessageFilter> filter; + }; + + // Create the filter. + AutomationResourceMessageFilter(); + virtual ~AutomationResourceMessageFilter(); + + int NewRequestId() { + return unique_request_id_++; + } + + // IPC::ChannelProxy::MessageFilter methods: + virtual void OnFilterAdded(IPC::Channel* channel); + virtual void OnChannelConnected(int32 peer_pid); + virtual void OnChannelClosing(); + virtual bool OnMessageReceived(const IPC::Message& message); + + // ResourceDispatcherHost::Receiver methods: + virtual bool Send(IPC::Message* message); + + // Add request to the list of outstanding requests. + bool RegisterRequest(URLRequestAutomationJob* job); + + // Remove request from the list of outstanding requests. + void UnRegisterRequest(URLRequestAutomationJob* job); + + // Can be called from the UI thread. + static bool RegisterRenderView(int renderer_pid, int renderer_id, + int tab_handle, AutomationResourceMessageFilter* filter); + static void UnRegisterRenderView(int renderer_pid, int renderer_id); + + // Called only on the IO thread. + static bool LookupRegisteredRenderView( + int renderer_pid, int renderer_id, AutomationDetails* details); + + protected: + static void RegisterRenderViewInIOThread(int renderer_pid, int renderer_id, + int tab_handle, AutomationResourceMessageFilter* filter); + static void UnRegisterRenderViewInIOThread(int renderer_pid, int renderer_id); + + private: + // A unique renderer id is a combination of renderer process id and + // it's routing id. + struct RendererId { + int pid_; + int id_; + + RendererId() : pid_(0), id_(0) {} + RendererId(int pid, int id) : pid_(pid), id_(id) {} + + bool operator < (const RendererId& rhs) const { + return ((pid_ == rhs.pid_) ? (id_ < rhs.id_) : (pid_ < rhs.pid_)); + } + }; + + typedef std::map<RendererId, AutomationDetails> RenderViewMap; + typedef std::map<int, scoped_refptr<URLRequestAutomationJob> > RequestMap; + + // The channel associated with the automation connection. This pointer is not + // owned by this class. + IPC::Channel* channel_; + static MessageLoop* io_loop_; + + // A unique request id per automation channel. + int unique_request_id_; + + // Map of outstanding requests. + RequestMap request_map_; + + // Map of render views interested in diverting url requests over automation. + static RenderViewMap filtered_render_views_; + + DISALLOW_COPY_AND_ASSIGN(AutomationResourceMessageFilter); +}; + +#endif // CHROME_BROWSER_AUTOMATION_AUTOMATION_RESOURCE_MSG_FILTER_H_ + diff --git a/chrome/browser/automation/url_request_automation_job.cc b/chrome/browser/automation/url_request_automation_job.cc new file mode 100644 index 0000000..6ab7f87 --- /dev/null +++ b/chrome/browser/automation/url_request_automation_job.cc @@ -0,0 +1,289 @@ +// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/automation/url_request_automation_job.h" + +#include "base/message_loop.h" +#include "chrome/browser/automation/automation_resource_message_filter.h" +#include "chrome/browser/renderer_host/render_view_host.h" +#include "chrome/browser/renderer_host/resource_dispatcher_host.h" +#include "chrome/test/automation/automation_messages.h" +#include "net/base/io_buffer.h" +#include "net/base/net_errors.h" +#include "net/url_request/url_request.h" + + +// This class manages the interception of network requests for automation. +// It looks at the request, and creates an intercept job if it indicates +// that it should use automation channel. +// NOTE: All methods must be called on the IO thread. +class AutomationRequestInterceptor : public URLRequest::Interceptor { + public: + AutomationRequestInterceptor() { + URLRequest::RegisterRequestInterceptor(this); + } + + virtual ~AutomationRequestInterceptor() { + URLRequest::UnregisterRequestInterceptor(this); + } + + // URLRequest::Interceptor + virtual URLRequestJob* MaybeIntercept(URLRequest* request); + + private: + DISALLOW_COPY_AND_ASSIGN(AutomationRequestInterceptor); +}; + +URLRequestJob* AutomationRequestInterceptor::MaybeIntercept( + URLRequest* request) { + ResourceDispatcherHost::ExtraRequestInfo* request_info = + ResourceDispatcherHost::ExtraInfoForRequest(request); + if (request_info) { + AutomationResourceMessageFilter::AutomationDetails details; + if (AutomationResourceMessageFilter::LookupRegisteredRenderView( + request_info->process_id, request_info->route_id, &details)) { + URLRequestAutomationJob* job = new URLRequestAutomationJob(request, + details.tab_handle, details.filter); + return job; + } + } + + return NULL; +} + +static URLRequest::Interceptor* GetAutomationRequestInterceptor() { + return Singleton<AutomationRequestInterceptor>::get(); +} + +int URLRequestAutomationJob::instance_count_ = 0; + +URLRequestAutomationJob::URLRequestAutomationJob( + URLRequest* request, int tab, AutomationResourceMessageFilter* filter) + : URLRequestJob(request), id_(0), tab_(tab), message_filter_(filter), + pending_buf_size_(0) { + DLOG(INFO) << "URLRequestAutomationJob create. Count: " << ++instance_count_; + if (message_filter_) { + id_ = message_filter_->NewRequestId(); + DCHECK(id_); + } else { + NOTREACHED(); + } +} + +URLRequestAutomationJob::~URLRequestAutomationJob() { + DLOG(INFO) << "URLRequestAutomationJob delete. Count: " << --instance_count_; + Cleanup(); +} + +bool URLRequestAutomationJob::InitializeInterceptor() { + // AutomationRequestInterceptor will register itself when it + // is first created. + URLRequest::Interceptor* interceptor = GetAutomationRequestInterceptor(); + return (interceptor != NULL); +} + +// URLRequestJob Implementation. +void URLRequestAutomationJob::Start() { + // Start reading asynchronously so that all error reporting and data + // callbacks happen as they would for network requests. + MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod( + this, &URLRequestAutomationJob::StartAsync)); +} + +void URLRequestAutomationJob::Kill() { + message_filter_->Send(new AutomationMsg_RequestEnd(0, tab_, id_, + URLRequestStatus(URLRequestStatus::CANCELED, 0))); + DisconnectFromMessageFilter(); + URLRequestJob::Kill(); +} + +bool URLRequestAutomationJob::ReadRawData( + net::IOBuffer* buf, int buf_size, int* bytes_read) { + DLOG(INFO) << "URLRequestAutomationJob: " << + request_->url().spec() << " - read pending: " << buf_size; + pending_buf_ = buf; + pending_buf_size_ = buf_size; + + message_filter_->Send(new AutomationMsg_RequestRead(0, tab_, id_, + buf_size)); + SetStatus(URLRequestStatus(URLRequestStatus::IO_PENDING, 0)); + return false; +} + +bool URLRequestAutomationJob::GetMimeType(std::string* mime_type) const { + if (!mime_type_.empty()) { + *mime_type = mime_type_; + } else if (headers_) { + headers_->GetMimeType(mime_type); + } + + return (!mime_type->empty()); +} + +bool URLRequestAutomationJob::GetCharset(std::string* charset) { + if (headers_) + return headers_->GetCharset(charset); + return false; +} + +void URLRequestAutomationJob::GetResponseInfo(net::HttpResponseInfo* info) { + if (headers_) + info->headers = headers_; + if (request_->url().SchemeIsSecure()) { + // TODO(joshia): fill up SSL related fields. + } +} + +int URLRequestAutomationJob::GetResponseCode() const { + if (headers_) + return headers_->response_code(); + + static const int kDefaultResponseCode = 200; + return kDefaultResponseCode; +} + +bool URLRequestAutomationJob::IsRedirectResponse( + GURL* location, int* http_status_code) { + if (!request_->response_headers()) + return false; + + std::string value; + if (!request_->response_headers()->IsRedirect(&value)) + return false; + + *location = request_->url().Resolve(value); + *http_status_code = request_->response_headers()->response_code(); + return true; +} + +int URLRequestAutomationJob::MayFilterMessage(const IPC::Message& message) { + switch (message.type()) { + case AutomationMsg_RequestStarted::ID: + case AutomationMsg_RequestData::ID: + case AutomationMsg_RequestEnd::ID: { + void* iter = NULL; + int tab = 0; + int id = 0; + if (message.ReadInt(&iter, &tab) && message.ReadInt(&iter, &id)) { + DCHECK(id); + return id; + } + break; + } + } + + return 0; +} + +void URLRequestAutomationJob::OnMessage(const IPC::Message& message) { + IPC_BEGIN_MESSAGE_MAP(URLRequestAutomationJob, message) + IPC_MESSAGE_HANDLER(AutomationMsg_RequestStarted, OnRequestStarted) + IPC_MESSAGE_HANDLER(AutomationMsg_RequestData, OnDataAvailable) + IPC_MESSAGE_HANDLER(AutomationMsg_RequestEnd, OnRequestEnd) + IPC_END_MESSAGE_MAP() +} + +void URLRequestAutomationJob::OnRequestStarted( + int tab, int id, const IPC::AutomationURLResponse& response) { + DLOG(INFO) << "URLRequestAutomationJob: " << + request_->url().spec() << " - response started."; + set_expected_content_size(response.content_length); + mime_type_ = response.mime_type; + + if (!response.headers.empty()) + headers_ = new net::HttpResponseHeaders(response.headers); + + NotifyHeadersComplete(); +} + +void URLRequestAutomationJob::OnDataAvailable( + int tab, int id, const std::string& bytes) { + DLOG(INFO) << "URLRequestAutomationJob: " << + request_->url().spec() << " - data available, Size: " << bytes.size(); + DCHECK(!bytes.empty()); + + // The request completed, and we have all the data. + // Clear any IO pending status. + SetStatus(URLRequestStatus()); + + if (pending_buf_ && pending_buf_->data()) { + DCHECK_GE(pending_buf_size_, bytes.size()); + const int bytes_to_copy = std::min(bytes.size(), pending_buf_size_); + memcpy(pending_buf_->data(), &bytes[0], bytes_to_copy); + + pending_buf_ = NULL; + pending_buf_size_ = 0; + + NotifyReadComplete(bytes_to_copy); + } +} + +void URLRequestAutomationJob::OnRequestEnd( + int tab, int id, const URLRequestStatus& status) { + DLOG(INFO) << "URLRequestAutomationJob: " << + request_->url().spec() << " - request end. Status: " << status.status(); + + DisconnectFromMessageFilter(); + NotifyDone(status); + + // Reset any pending reads. + if (pending_buf_) { + pending_buf_ = NULL; + pending_buf_size_ = 0; + NotifyReadComplete(0); + } +} + +void URLRequestAutomationJob::Cleanup() { + headers_ = NULL; + mime_type_.erase(); + + id_ = 0; + tab_ = 0; + + DCHECK(message_filter_ == NULL); + DisconnectFromMessageFilter(); + + pending_buf_ = NULL; + pending_buf_size_ = 0; +} + +void URLRequestAutomationJob::StartAsync() { + DLOG(INFO) << "URLRequestAutomationJob: start request: " << + request_->url().spec(); + + // If the job is cancelled before we got a chance to start it + // we have nothing much to do here. + if (is_done()) + return; + + if (!request_) { + NotifyStartError(URLRequestStatus(URLRequestStatus::FAILED, + net::ERR_FAILED)); + return; + } + + // Register this request with automation message filter. + message_filter_->RegisterRequest(this); + + // Ask automation to start this request. + IPC::AutomationURLRequest automation_request = { + request_->url().spec(), + request_->method(), + request_->referrer(), + request_->extra_request_headers() + }; + + DCHECK(message_filter_); + message_filter_->Send(new AutomationMsg_RequestStart(0, tab_, id_, + automation_request)); +} + +void URLRequestAutomationJob::DisconnectFromMessageFilter() { + if (message_filter_) { + message_filter_->UnRegisterRequest(this); + message_filter_ = NULL; + } +} + diff --git a/chrome/browser/automation/url_request_automation_job.h b/chrome/browser/automation/url_request_automation_job.h new file mode 100644 index 0000000..db61781 --- /dev/null +++ b/chrome/browser/automation/url_request_automation_job.h @@ -0,0 +1,79 @@ +// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// This class simulates what wininet does when a dns lookup fails. + +#ifndef CHROME_BROWSER_AUTOMATION_AUTOMATION_URL_REQUEST_JOB_H_ +#define CHROME_BROWSER_AUTOMATION_AUTOMATION_URL_REQUEST_JOB_H_ + +#include "chrome/common/ref_counted_util.h" +#include "net/http/http_response_headers.h" +#include "net/url_request/url_request_job.h" + +class AutomationResourceMessageFilter; + +namespace IPC { +class Message; +struct AutomationURLResponse; +}; + +// URLRequestJob implementation that loads the resources using +// automation. +class URLRequestAutomationJob : public URLRequestJob { + public: + URLRequestAutomationJob( + URLRequest* request, int tab, AutomationResourceMessageFilter* filter); + virtual ~URLRequestAutomationJob(); + + // Register an interceptor for URL requests. + static bool InitializeInterceptor(); + + // URLRequestJob methods. + virtual void Start(); + virtual void Kill(); + virtual bool GetMimeType(std::string* mime_type) const; + virtual bool GetCharset(std::string* charset); + virtual void GetResponseInfo(net::HttpResponseInfo* info); + virtual int GetResponseCode() const; + virtual bool IsRedirectResponse(GURL* location, int* http_status_code); + + // Peek and process automation messages for URL requests. + static int MayFilterMessage(const IPC::Message& message); + void OnMessage(const IPC::Message& message); + + int id() const { + return id_; + } + + protected: + // Protected URLRequestJob override. + virtual bool ReadRawData(net::IOBuffer* buf, int buf_size, int* bytes_read); + + void StartAsync(); + void Cleanup(); + void DisconnectFromMessageFilter(); + + // IPC message handlers. + void OnRequestStarted(int tab, int id, + const IPC::AutomationURLResponse& response); + void OnDataAvailable(int tab, int id, const std::string& bytes); + void OnRequestEnd(int tab, int id, const URLRequestStatus& status); + + private: + int id_; + int tab_; + scoped_refptr<AutomationResourceMessageFilter> message_filter_; + + scoped_refptr<net::IOBuffer> pending_buf_; + size_t pending_buf_size_; + + std::string mime_type_; + scoped_refptr<net::HttpResponseHeaders> headers_; + + static int instance_count_; + + DISALLOW_COPY_AND_ASSIGN(URLRequestAutomationJob); +}; + +#endif // CHROME_BROWSER_AUTOMATION_AUTOMATION_URL_REQUEST_JOB_H_ + diff --git a/chrome/browser/external_tab_container.cc b/chrome/browser/external_tab_container.cc index 62b6a3f..732aead 100644 --- a/chrome/browser/external_tab_container.cc +++ b/chrome/browser/external_tab_container.cc @@ -31,14 +31,16 @@ static const wchar_t kWindowObjectKey[] = L"ChromeWindowObject"; // member variables are now obsolete and we don't use them. // We need to remove them. ExternalTabContainer::ExternalTabContainer( - AutomationProvider* automation) + AutomationProvider* automation, AutomationResourceMessageFilter* filter) : automation_(automation), tab_contents_(NULL), external_accel_table_(NULL), external_accel_entry_count_(0), tab_contents_container_(NULL), tab_handle_(0), - ignore_next_load_notification_(false) { + ignore_next_load_notification_(false), + automation_resource_message_filter_(filter), + load_requests_via_automation_(false) { } ExternalTabContainer::~ExternalTabContainer() { @@ -86,6 +88,11 @@ bool ExternalTabContainer::Init(Profile* profile, Source<NavigationController>(controller)); registrar_.Add(this, NotificationType::LOAD_STOP, Source<NavigationController>(controller)); + registrar_.Add(this, NotificationType::RENDER_VIEW_HOST_CREATED_FOR_TAB, + Source<TabContents>(tab_contents_)); + registrar_.Add(this, NotificationType::RENDER_VIEW_HOST_DELETED, + Source<TabContents>(tab_contents_)); + NotificationService::current()->Notify( NotificationType::EXTERNAL_TAB_CREATED, Source<NavigationController>(controller), @@ -350,6 +357,27 @@ void ExternalTabContainer::Observe(NotificationType type, ignore_next_load_notification_ = true; break; } + case NotificationType::RENDER_VIEW_HOST_CREATED_FOR_TAB: { + if (load_requests_via_automation_) { + RenderViewHost* rvh = Details<RenderViewHost>(details).ptr(); + if (rvh) { + AutomationResourceMessageFilter::RegisterRenderView( + rvh->process()->pid(), rvh->routing_id(), tab_handle_, + automation_resource_message_filter_); + } + } + break; + } + case NotificationType::RENDER_VIEW_HOST_DELETED: { + if (load_requests_via_automation_) { + RenderViewHost* rvh = Details<RenderViewHost>(details).ptr(); + if (rvh) { + AutomationResourceMessageFilter::UnRegisterRenderView( + rvh->process()->pid(), rvh->routing_id()); + } + } + break; + } default: NOTREACHED(); } @@ -407,6 +435,7 @@ bool ExternalTabContainer::ProcessKeyStroke(HWND window, UINT message, // ExternalTabContainer, private: void ExternalTabContainer::Uninitialize(HWND window) { + registrar_.RemoveAll(); if (tab_contents_) { NotificationService::current()->Notify( NotificationType::EXTERNAL_TAB_CLOSED, diff --git a/chrome/browser/external_tab_container.h b/chrome/browser/external_tab_container.h index 3037847..e69283c 100644 --- a/chrome/browser/external_tab_container.h +++ b/chrome/browser/external_tab_container.h @@ -7,6 +7,7 @@ #include <vector> +#include "chrome/browser/automation/automation_resource_message_filter.h" #include "chrome/browser/tab_contents/tab_contents_delegate.h" #include "chrome/common/notification_observer.h" #include "chrome/common/notification_registrar.h" @@ -27,7 +28,8 @@ class ExternalTabContainer : public TabContentsDelegate, public views::WidgetWin, public views::KeystrokeListener { public: - explicit ExternalTabContainer(AutomationProvider* automation); + ExternalTabContainer(AutomationProvider* automation, + AutomationResourceMessageFilter* filter); ~ExternalTabContainer(); TabContents* tab_contents() const { return tab_contents_; } @@ -140,6 +142,12 @@ class ExternalTabContainer : public TabContentsDelegate, scoped_ptr<RenderViewContextMenuExternalWin> external_context_menu_; + // A message filter to load resources via automation + AutomationResourceMessageFilter* automation_resource_message_filter_; + + // If all the url requests for this tab are to be loaded via automation. + bool load_requests_via_automation_; + DISALLOW_COPY_AND_ASSIGN(ExternalTabContainer); }; diff --git a/chrome/browser/renderer_host/render_view_host.cc b/chrome/browser/renderer_host/render_view_host.cc index 43de151..84f13d6 100644 --- a/chrome/browser/renderer_host/render_view_host.cc +++ b/chrome/browser/renderer_host/render_view_host.cc @@ -123,6 +123,8 @@ RenderViewHost::RenderViewHost(SiteInstance* instance, } RenderViewHost::~RenderViewHost() { + delegate()->RenderViewDeleted(this); + DevToolsManager* devtools_manager = DevToolsManager::GetInstance(); if (devtools_manager) // NULL in tests devtools_manager->UnregisterDevToolsClientHostFor(this); @@ -130,11 +132,6 @@ RenderViewHost::~RenderViewHost() { // Be sure to clean up any leftover state from cross-site requests. Singleton<CrossSiteRequestManager>()->SetHasPendingCrossSiteRequest( process()->pid(), routing_id(), false); - - NotificationService::current()->Notify( - NotificationType::RENDER_VIEW_HOST_DELETED, - Source<RenderViewHost>(this), - NotificationService::NoDetails()); } void RenderViewHost::Observe(NotificationType type, diff --git a/chrome/browser/renderer_host/render_view_host_delegate.h b/chrome/browser/renderer_host/render_view_host_delegate.h index b1992e8..28e9fdc 100644 --- a/chrome/browser/renderer_host/render_view_host_delegate.h +++ b/chrome/browser/renderer_host/render_view_host_delegate.h @@ -315,6 +315,10 @@ class RenderViewHostDelegate { // The RenderView died somehow (crashed or was killed by the user). virtual void RenderViewGone(RenderViewHost* render_view_host) {} + // The RenderView is going to be deleted. This is called when each + // RenderView is going to be destroyed + virtual void RenderViewDeleted(RenderViewHost* render_view_host) { } + // The RenderView was navigated to a different page. virtual void DidNavigate(RenderViewHost* render_view_host, const ViewHostMsg_FrameNavigate_Params& params) {} diff --git a/chrome/browser/tab_contents/render_view_host_manager.cc b/chrome/browser/tab_contents/render_view_host_manager.cc index fba410d..28f5a95 100644 --- a/chrome/browser/tab_contents/render_view_host_manager.cc +++ b/chrome/browser/tab_contents/render_view_host_manager.cc @@ -34,8 +34,6 @@ RenderViewHostManager::RenderViewHostManager( render_view_host_(NULL), pending_render_view_host_(NULL), interstitial_page_(NULL) { - registrar_.Add(this, NotificationType::RENDER_VIEW_HOST_DELETED, - NotificationService::AllSources()); } RenderViewHostManager::~RenderViewHostManager() { @@ -258,18 +256,6 @@ void RenderViewHostManager::OnJavaScriptMessageBoxWindowDestroyed() { render_view_host_->JavaScriptMessageBoxWindowDestroyed(); } -void RenderViewHostManager::Observe(NotificationType type, - const NotificationSource& source, - const NotificationDetails& details) { - // Debugging code to help isolate - // http://code.google.com/p/chromium/issues/detail?id=6316 . We should never - // reference a RVH that is about to be deleted. - RenderViewHost* deleted_rvh = Source<RenderViewHost>(source).ptr(); - CHECK(deleted_rvh); - CHECK(render_view_host_ != deleted_rvh); - CHECK(pending_render_view_host_ != deleted_rvh); -} - bool RenderViewHostManager::ShouldTransitionCrossSite() { // True if we are using process-per-site-instance (default) or // process-per-site (kProcessPerSite). @@ -301,7 +287,6 @@ bool RenderViewHostManager::ShouldSwapProcessesForNavigation( new_entry->url().SchemeIs(chrome::kExtensionScheme)) if (cur_entry->url().GetOrigin() != new_entry->url().GetOrigin()) return true; - return false; } diff --git a/chrome/browser/tab_contents/render_view_host_manager.h b/chrome/browser/tab_contents/render_view_host_manager.h index 6823512..a725d16 100644 --- a/chrome/browser/tab_contents/render_view_host_manager.h +++ b/chrome/browser/tab_contents/render_view_host_manager.h @@ -23,7 +23,7 @@ class SiteInstance; // Manages RenderViewHosts for a TabContents. Normally there is only one and // it is easy to do. But we can also have transitions of processes (and hence // RenderViewHosts) that can get complex. -class RenderViewHostManager : public NotificationObserver { +class RenderViewHostManager { public: // Functions implemented by our owner that we need. // @@ -172,10 +172,6 @@ class RenderViewHostManager : public NotificationObserver { return interstitial_page_; } - virtual void Observe(NotificationType type, - const NotificationSource& source, - const NotificationDetails& details); - private: friend class TestTabContents; diff --git a/chrome/browser/tab_contents/tab_contents.cc b/chrome/browser/tab_contents/tab_contents.cc index de13654..b417f34 100644 --- a/chrome/browser/tab_contents/tab_contents.cc +++ b/chrome/browser/tab_contents/tab_contents.cc @@ -1714,6 +1714,11 @@ TabContents* TabContents::GetAsTabContents() { } void TabContents::RenderViewCreated(RenderViewHost* render_view_host) { + NotificationService::current()->Notify( + NotificationType::RENDER_VIEW_HOST_CREATED_FOR_TAB, + Source<TabContents>(this), + Details<RenderViewHost>(render_view_host)); + NavigationEntry* entry = controller_.GetActiveEntry(); if (!entry) return; @@ -1764,6 +1769,13 @@ void TabContents::RenderViewGone(RenderViewHost* rvh) { HungRendererDialog::HideForTabContents(this); } +void TabContents::RenderViewDeleted(RenderViewHost* rvh) { + NotificationService::current()->Notify( + NotificationType::RENDER_VIEW_HOST_DELETED, + Source<TabContents>(this), + Details<RenderViewHost>(rvh)); +} + void TabContents::DidNavigate(RenderViewHost* rvh, const ViewHostMsg_FrameNavigate_Params& params) { if (PageTransition::IsMainFrame(params.transition)) diff --git a/chrome/browser/tab_contents/tab_contents.h b/chrome/browser/tab_contents/tab_contents.h index 7597003..6b8f417 100644 --- a/chrome/browser/tab_contents/tab_contents.h +++ b/chrome/browser/tab_contents/tab_contents.h @@ -781,6 +781,7 @@ class TabContents : public PageNavigator, virtual void RenderViewCreated(RenderViewHost* render_view_host); virtual void RenderViewReady(RenderViewHost* render_view_host); virtual void RenderViewGone(RenderViewHost* render_view_host); + virtual void RenderViewDeleted(RenderViewHost* render_view_host); virtual void DidNavigate(RenderViewHost* render_view_host, const ViewHostMsg_FrameNavigate_Params& params); virtual void UpdateState(RenderViewHost* render_view_host, diff --git a/chrome/chrome.gyp b/chrome/chrome.gyp index 8dcb0fa..4eb8b1f 100644 --- a/chrome/chrome.gyp +++ b/chrome/chrome.gyp @@ -616,9 +616,13 @@ 'browser/automation/automation_provider_list_generic.cc', 'browser/automation/automation_provider_list_mac.mm', 'browser/automation/automation_provider_list.h', + 'browser/automation/automation_resource_message_filter.cc', + 'browser/automation/automation_resource_message_filter.h', 'browser/automation/automation_resource_tracker.cc', 'browser/automation/automation_resource_tracker.h', 'browser/automation/automation_tab_tracker.h', + 'browser/automation/url_request_automation_job.cc', + 'browser/automation/url_request_automation_job.h', 'browser/automation/automation_window_tracker.h', 'browser/automation/extension_port_container.cc', 'browser/automation/extension_port_container.h', diff --git a/chrome/common/ipc_message_utils.h b/chrome/common/ipc_message_utils.h index 53c7974..c63eb6c 100644 --- a/chrome/common/ipc_message_utils.h +++ b/chrome/common/ipc_message_utils.h @@ -21,6 +21,7 @@ #include "chrome/common/ipc_sync_message.h" #include "chrome/common/thumbnail_score.h" #include "chrome/common/transport_dib.h" +#include "net/url_request/url_request_status.h" #include "webkit/glue/webcursor.h" #include "webkit/glue/window_open_disposition.h" @@ -943,6 +944,58 @@ struct ParamTraits<TransportDIB::Id> { }; #endif +// Traits for URLRequestStatus +template <> +struct ParamTraits<URLRequestStatus> { + typedef URLRequestStatus param_type; + static void Write(Message* m, const param_type& p) { + WriteParam(m, static_cast<int>(p.status())); + WriteParam(m, p.os_error()); + } + static bool Read(const Message* m, void** iter, param_type* r) { + int status, os_error; + if (!ReadParam(m, iter, &status) || + !ReadParam(m, iter, &os_error)) + return false; + r->set_status(static_cast<URLRequestStatus::Status>(status)); + r->set_os_error(os_error); + return true; + } + static void Log(const param_type& p, std::wstring* l) { + std::wstring status; + switch (p.status()) { + case URLRequestStatus::SUCCESS: + status = L"SUCCESS"; + break; + case URLRequestStatus::IO_PENDING: + status = L"IO_PENDING "; + break; + case URLRequestStatus::HANDLED_EXTERNALLY: + status = L"HANDLED_EXTERNALLY"; + break; + case URLRequestStatus::CANCELED: + status = L"CANCELED"; + break; + case URLRequestStatus::FAILED: + status = L"FAILED"; + break; + default: + status = L"UNKNOWN"; + break; + } + if (p.status() == URLRequestStatus::FAILED) + l->append(L"("); + + LogParam(status, l); + + if (p.status() == URLRequestStatus::FAILED) { + l->append(L", "); + LogParam(p.os_error(), l); + l->append(L")"); + } + } +}; + template <> struct ParamTraits<Message> { static void Write(Message* m, const Message& p) { diff --git a/chrome/common/net/url_request_intercept_job.cc b/chrome/common/net/url_request_intercept_job.cc index bb5dd8c..af1c8c7 100644 --- a/chrome/common/net/url_request_intercept_job.cc +++ b/chrome/common/net/url_request_intercept_job.cc @@ -101,10 +101,25 @@ bool URLRequestInterceptJob::GetCharset(std::string* charset) { return request_->response_headers()->GetCharset(charset); } -bool URLRequestInterceptJob::GetContentEncoding(std::string* encoding_type) { - // TODO(darin): what if there are multiple content encodings? - return request_->response_headers()->EnumerateHeader(NULL, "Content-Encoding", - encoding_type); +bool URLRequestInterceptJob::GetContentEncodings( + std::vector<Filter::FilterType>* encoding_types) { + DCHECK(encoding_types->empty()); + if (!request_->response_headers()) + return false; + + std::string encoding_type; + void* iter = NULL; + while (request_->response_headers()->EnumerateHeader( + &iter, "Content-Encoding", &encoding_type)) { + encoding_types->push_back(Filter::ConvertEncodingToType(encoding_type)); + } + + // Even if encoding types are empty, there is a chance that we need to add + // some decoding, as some proxies strip encoding completely. In such cases, + // we may need to add (for example) SDCH filtering (when the context suggests + // it is appropriate). + Filter::FixupEncodingTypes(*this, encoding_types); + return !encoding_types->empty(); } void URLRequestInterceptJob::GetResponseInfo(net::HttpResponseInfo* info) { diff --git a/chrome/common/net/url_request_intercept_job.h b/chrome/common/net/url_request_intercept_job.h index 73f354d..07db154 100644 --- a/chrome/common/net/url_request_intercept_job.h +++ b/chrome/common/net/url_request_intercept_job.h @@ -35,18 +35,22 @@ class URLRequestInterceptJob // URLRequestJob virtual void Start(); virtual void Kill(); - virtual bool ReadRawData(net::IOBuffer* buf, int buf_size, int* bytes_read); virtual bool GetMimeType(std::string* mime_type) const; virtual bool GetCharset(std::string* charset); virtual void GetResponseInfo(net::HttpResponseInfo* info); virtual int GetResponseCode() const; - virtual bool GetContentEncoding(std::string* encoding_type); + virtual bool GetContentEncodings( + std::vector<Filter::FilterType>* encoding_types); virtual bool IsRedirectResponse(GURL* location, int* http_status_code); // NotificationObserver virtual void Observe(NotificationType type, const NotificationSource& source, const NotificationDetails& details); + + protected: + virtual bool ReadRawData(net::IOBuffer* buf, int buf_size, int* bytes_read); + private: void StartAsync(); void DetachPlugin(); diff --git a/chrome/common/notification_type.h b/chrome/common/notification_type.h index f8e6a81..f222972 100644 --- a/chrome/common/notification_type.h +++ b/chrome/common/notification_type.h @@ -284,11 +284,11 @@ class NotificationType { TAB_CONTENTS_DESTROYED, // A RenderViewHost was created for a TabContents. The source is the - // RenderViewHostManager who owns it, and the details is the RenderViewHost - // pointer. Note that the source will be NULL in some cases for testing, - // when there is no RVHManager. + // associated TabContents, and the details is the RenderViewHost + // pointer. RENDER_VIEW_HOST_CREATED_FOR_TAB, + // Stuff inside the tabs --------------------------------------------------- // This message is sent after a constrained window has been closed. The @@ -329,6 +329,9 @@ class NotificationType { // the RenderWidgetHost, the details are not used. RENDER_WIDGET_HOST_DESTROYED, + // Sent from ~RenderViewHost. The source is the RenderViewHost. + RENDER_VIEW_HOST_DELETED, + // Indicates a RenderWidgetHost has been hidden or restored. The source is // the RWH whose visibility changed, the details is a bool set to true if // the new state is "visible." @@ -592,9 +595,6 @@ class NotificationType { // Debugging --------------------------------------------------------------- - // Sent from ~RenderViewHost. The source is the RenderViewHost. - RENDER_VIEW_HOST_DELETED, - // Count (must be last) ---------------------------------------------------- // Used to determine the number of notification types. Not valid as // a type parameter when registering for or posting notifications. diff --git a/chrome/common/render_messages.h b/chrome/common/render_messages.h index b2fd1f9..829a8ed 100644 --- a/chrome/common/render_messages.h +++ b/chrome/common/render_messages.h @@ -25,7 +25,6 @@ #include "media/audio/audio_output.h" #include "net/base/upload_data.h" #include "net/http/http_response_headers.h" -#include "net/url_request/url_request_status.h" #include "webkit/glue/autofill_form.h" #include "webkit/glue/context_menu.h" #include "webkit/glue/form_data.h" @@ -1246,58 +1245,6 @@ struct ParamTraits<ViewHostMsg_Resource_Request> { } }; -// Traits for URLRequestStatus -template <> -struct ParamTraits<URLRequestStatus> { - typedef URLRequestStatus param_type; - static void Write(Message* m, const param_type& p) { - WriteParam(m, static_cast<int>(p.status())); - WriteParam(m, p.os_error()); - } - static bool Read(const Message* m, void** iter, param_type* r) { - int status, os_error; - if (!ReadParam(m, iter, &status) || - !ReadParam(m, iter, &os_error)) - return false; - r->set_status(static_cast<URLRequestStatus::Status>(status)); - r->set_os_error(os_error); - return true; - } - static void Log(const param_type& p, std::wstring* l) { - std::wstring status; - switch (p.status()) { - case URLRequestStatus::SUCCESS: - status = L"SUCCESS"; - break; - case URLRequestStatus::IO_PENDING: - status = L"IO_PENDING "; - break; - case URLRequestStatus::HANDLED_EXTERNALLY: - status = L"HANDLED_EXTERNALLY"; - break; - case URLRequestStatus::CANCELED: - status = L"CANCELED"; - break; - case URLRequestStatus::FAILED: - status = L"FAILED"; - break; - default: - status = L"UNKNOWN"; - break; - } - if (p.status() == URLRequestStatus::FAILED) - l->append(L"("); - - LogParam(status, l); - - if (p.status() == URLRequestStatus::FAILED) { - l->append(L", "); - LogParam(p.os_error(), l); - l->append(L")"); - } - } -}; - template <> struct ParamTraits<scoped_refptr<net::HttpResponseHeaders> > { typedef scoped_refptr<net::HttpResponseHeaders> param_type; diff --git a/chrome/test/automation/automation_messages.h b/chrome/test/automation/automation_messages.h index 6c198c9..f19a74f 100644 --- a/chrome/test/automation/automation_messages.h +++ b/chrome/test/automation/automation_messages.h @@ -223,6 +223,78 @@ struct ParamTraits<Reposition_Params> { }; #endif // defined(OS_WIN) +struct AutomationURLRequest { + std::string url; + std::string method; + std::string referrer; + std::string extra_request_headers; +}; + +// Traits for AutomationURLRequest structure to pack/unpack. +template <> +struct ParamTraits<AutomationURLRequest> { + typedef AutomationURLRequest param_type; + static void Write(Message* m, const param_type& p) { + WriteParam(m, p.url); + WriteParam(m, p.method); + WriteParam(m, p.referrer); + WriteParam(m, p.extra_request_headers); + } + static bool Read(const Message* m, void** iter, param_type* p) { + return ReadParam(m, iter, &p->url) && + ReadParam(m, iter, &p->method) && + ReadParam(m, iter, &p->referrer) && + ReadParam(m, iter, &p->extra_request_headers); + } + static void Log(const param_type& p, std::wstring* l) { + l->append(L"("); + LogParam(p.url, l); + l->append(L", "); + LogParam(p.method, l); + l->append(L", "); + LogParam(p.referrer, l); + l->append(L", "); + LogParam(p.extra_request_headers, l); + l->append(L")"); + } +}; + +struct AutomationURLResponse { + std::string mime_type; + std::string headers; + int64 content_length; + base::Time last_modified; +}; + +// Traits for AutomationURLRequest structure to pack/unpack. +template <> +struct ParamTraits<AutomationURLResponse> { + typedef AutomationURLResponse param_type; + static void Write(Message* m, const param_type& p) { + WriteParam(m, p.mime_type); + WriteParam(m, p.headers); + WriteParam(m, p.content_length); + WriteParam(m, p.last_modified); + } + static bool Read(const Message* m, void** iter, param_type* p) { + return ReadParam(m, iter, &p->mime_type) && + ReadParam(m, iter, &p->headers) && + ReadParam(m, iter, &p->content_length) && + ReadParam(m, iter, &p->last_modified); + } + static void Log(const param_type& p, std::wstring* l) { + l->append(L"("); + LogParam(p.mime_type, l); + l->append(L", "); + LogParam(p.headers, l); + l->append(L", "); + LogParam(p.content_length, l); + l->append(L", "); + LogParam(p.last_modified, l); + l->append(L")"); + } +}; + } // namespace IPC #define MESSAGES_INTERNAL_FILE \ diff --git a/chrome/test/automation/automation_messages_internal.h b/chrome/test/automation/automation_messages_internal.h index 66b898e..1eac286 100644 --- a/chrome/test/automation/automation_messages_internal.h +++ b/chrome/test/automation/automation_messages_internal.h @@ -944,4 +944,33 @@ IPC_BEGIN_MESSAGES(Automation) int /* selected_command */) #endif // OS_WIN + // A URL request to be fetched via automation + IPC_MESSAGE_ROUTED3(AutomationMsg_RequestStart, + int /* tab_handle */, + int /* request_id */, + IPC::AutomationURLRequest /* request */) + + // Read data from a URL request to be fetched via automation + IPC_MESSAGE_ROUTED3(AutomationMsg_RequestRead, + int /* tab_handle */, + int /* request_id */, + int /* bytes_to_read */) + + // Response to a AutomationMsg_RequestStart message + IPC_MESSAGE_ROUTED3(AutomationMsg_RequestStarted, + int /* tab_handle */, + int /* request_id */, + IPC::AutomationURLResponse /* response */) + + // Data read via automation + IPC_MESSAGE_ROUTED3(AutomationMsg_RequestData, + int /* tab_handle */, + int /* request_id */, + std::string /* data */) + + IPC_MESSAGE_ROUTED3(AutomationMsg_RequestEnd, + int /* tab_handle */, + int /* request_id */, + URLRequestStatus /* status */) + IPC_END_MESSAGES(Automation) |