diff options
author | initial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-07-26 23:55:29 +0000 |
---|---|---|
committer | initial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-07-26 23:55:29 +0000 |
commit | 09911bf300f1a419907a9412154760efd0b7abc3 (patch) | |
tree | f131325fb4e2ad12c6d3504ab75b16dd92facfed /chrome/browser/resource_dispatcher_host.h | |
parent | 586acc5fe142f498261f52c66862fa417c3d52d2 (diff) | |
download | chromium_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/resource_dispatcher_host.h')
-rw-r--r-- | chrome/browser/resource_dispatcher_host.h | 506 |
1 files changed, 506 insertions, 0 deletions
diff --git a/chrome/browser/resource_dispatcher_host.h b/chrome/browser/resource_dispatcher_host.h new file mode 100644 index 0000000..52c876b --- /dev/null +++ b/chrome/browser/resource_dispatcher_host.h @@ -0,0 +1,506 @@ +// 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 is the browser side of the resource dispatcher, it receives requests +// from the RenderProcessHosts, and dispatches them to URLRequests. It then +// fowards the messages from the URLRequests back to the correct process for +// handling. +// +// See http://wiki.corp.google.com/twiki/bin/view/Main/ChromeMultiProcessResourceLoading + +#ifndef CHROME_BROWSER_RESOURCE_DISPATCHER_HOST_H__ +#define CHROME_BROWSER_RESOURCE_DISPATCHER_HOST_H__ + +#include <map> +#include <string> + +#include "base/logging.h" +#include "base/observer_list.h" +#include "base/ref_counted.h" +#include "base/shared_memory.h" +#include "base/task.h" +#include "base/timer.h" +#include "chrome/common/filter_policy.h" +#include "chrome/common/ipc_message.h" +#include "net/url_request/url_request.h" +#include "webkit/glue/resource_type.h" + +class DownloadFileManager; +class SaveFileManager; +class MessageLoop; +class PluginService; +class SafeBrowsingService; +class TabContents; +class URLRequestContext; +class LoginHandler; +struct ViewHostMsg_Resource_Request; +struct ViewMsg_Resource_ResponseHead; + +class ResourceDispatcherHost : public URLRequest::Delegate { + public: + // Simple wrapper that refcounts ViewMsg_Resource_ResponseHead. + struct Response; + + // The resource dispatcher host uses this interface to push load events to the + // renderer, allowing for differences in the types of IPC messages generated. + // See the implementations of this interface defined below. + class EventHandler : public base::RefCounted<EventHandler> { + public: + virtual ~EventHandler() {} + + // Called as upload progress is made. + virtual bool OnUploadProgress(int request_id, + uint64 position, + uint64 size) { + return true; + } + + // The request was redirected to a new URL. + virtual bool OnRequestRedirected(int request_id, const GURL& url) = 0; + + // Response headers and meta data are available. + virtual bool OnResponseStarted(int request_id, Response* response) = 0; + + // Data will be read for the response. Upon success, this method places the + // size and address of the buffer where the data is to be written in its + // out-params. This call will be followed by either OnReadCompleted or + // OnResponseCompleted, at which point the buffer may be recycled. + virtual bool OnWillRead(int request_id, + char** buf, + int* buf_size, + int min_size) = 0; + + // Data (*bytes_read bytes) was written into the buffer provided by + // OnWillRead. + virtual bool OnReadCompleted(int request_id, int* bytes_read) = 0; + + // The response is complete. The final response status is given. + // Returns false if the handler is deferring the call to a later time. + virtual bool OnResponseCompleted(int request_id, + const URLRequestStatus& status) = 0; + }; + + // Implemented by the client of ResourceDispatcherHost to receive messages in + // response to a resource load. The messages are intended to be forwarded to + // the ResourceDispatcher in the renderer process via an IPC channel that the + // client manages. + // + // NOTE: This class unfortunately cannot be named 'Delegate' because that + // conflicts with the name of ResourceDispatcherHost's base class. + // + // If the receiver is unable to send a given message (i.e., if Send returns + // false), then the ResourceDispatcherHost assumes the receiver has failed, + // and the given request will be dropped. (This happens, for example, when a + // renderer crashes and the channel dies). + typedef IPC::Message::Sender Receiver; + + // Forward declaration of CrossSiteEventHandler, so that it can be referenced + // in ExtraRequestInfo. + class CrossSiteEventHandler; + + // Holds the data we would like to associate with each request + class ExtraRequestInfo : public URLRequest::UserData { + friend ResourceDispatcherHost; + public: + ExtraRequestInfo(EventHandler* handler, + int request_id, + int render_process_host_id, + int render_view_id, + bool mixed_content, + ResourceType::Type resource_type, + uint64 upload_size) + : event_handler(handler), + cross_site_handler(NULL), + login_handler(NULL), + request_id(request_id), + render_process_host_id(render_process_host_id), + render_view_id(render_view_id), + is_download(false), + pause_count(0), + mixed_content(mixed_content), + resource_type(resource_type), + filter_policy(FilterPolicy::DONT_FILTER), + last_load_state(net::LOAD_STATE_IDLE), + pending_data_count(0), + upload_size(upload_size), + last_upload_position(0), + waiting_for_upload_progress_ack(false), + is_paused(false), + has_started_reading(false), + paused_read_bytes(0) { + } + + // Top-level EventHandler servicing this request. + scoped_refptr<EventHandler> event_handler; + + // CrossSiteEventHandler for this request, if it is a cross-site request. + // (NULL otherwise.) This handler is part of the chain of EventHandlers + // pointed to by event_handler. + CrossSiteEventHandler* cross_site_handler; + + LoginHandler* login_handler; + + int request_id; + + int render_process_host_id; + + int render_view_id; + + int pending_data_count; + + // Downloads allowed only as a top level request. + bool allow_download; + + // Whether this is a download. + bool is_download; + + // The number of clients that have called pause on this request. + int pause_count; + + // Whether this request is served over HTTP and the main page was served + // over HTTPS. + bool mixed_content; + + ResourceType::Type resource_type; + + // Whether the content for this request should be filtered (on the renderer + // side) to make it more secure: images are stamped, frame content is + // replaced with an error message and all other resources are entirely + // filtered out. + FilterPolicy::Type filter_policy; + + net::LoadState last_load_state; + + uint64 upload_size; + + uint64 last_upload_position; + + TimeTicks last_upload_ticks; + + bool waiting_for_upload_progress_ack; + + private: + // Request is temporarily not handling network data. Should be used only + // by the ResourceDispatcherHost, not the event handlers. + bool is_paused; + + // Whether this request has started reading any bytes from the response + // yet. Will be true after the first (unpaused) call to Read. + bool has_started_reading; + + // How many bytes have been read while this request has been paused. + int paused_read_bytes; + }; + + class Observer { + public: + virtual void OnRequestStarted(ResourceDispatcherHost* resource_dispatcher, + URLRequest* request) = 0; + virtual void OnResponseCompleted(ResourceDispatcherHost* resource_dispatcher, + URLRequest* request) = 0; + virtual void OnReceivedRedirect(ResourceDispatcherHost* resource_dispatcher, + URLRequest* request, + const GURL& new_url) = 0; + }; + + // Uniquely identifies a URLRequest. + struct GlobalRequestID { + GlobalRequestID() : render_process_host_id(-1), request_id(-1) { + } + GlobalRequestID(int render_process_host_id, int request_id) + : render_process_host_id(render_process_host_id), + request_id(request_id) { + } + + int render_process_host_id; + int request_id; + + bool operator<(const GlobalRequestID& other) const { + if (render_process_host_id == other.render_process_host_id) + return request_id < other.request_id; + return render_process_host_id < other.render_process_host_id; + } + }; + + explicit ResourceDispatcherHost(MessageLoop* io_loop); + ~ResourceDispatcherHost(); + + void Initialize(); + + // Puts the resource dispatcher host in an inactive state (unable to begin + // new requests). Cancels all pending requests. + void Shutdown(); + + // Begins a resource request with the given params on behalf of the specified + // render view. Responses will be dispatched through the given receiver. The + // RenderProcessHost ID is used to lookup TabContents from routing_id's. + // request_context is the cookie/cache context to be used for this request. + // + // If sync_result is non-null, then a SyncLoad reply will be generated, else + // a normal asynchronous set of response messages will be generated. + // + void BeginRequest(Receiver* receiver, + HANDLE render_process_handle, + int render_process_host_id, + int render_view_id, + int request_id, + const ViewHostMsg_Resource_Request& request, + URLRequestContext* request_context, + IPC::Message* sync_result); + + // Initiate a download from the browser process (as opposed to a resource + // request from the renderer). + void BeginDownload(const GURL& url, + const GURL& referrer, + int render_process_host_id, + int render_view_id, + URLRequestContext* request_context); + + // Initiate a save file from the browser process (as opposed to a resource + // request from the renderer). + void BeginSaveFile(const GURL& url, + const GURL& referrer, + int render_process_host_id, + int render_view_id, + URLRequestContext* request_context); + + // Cancels the given request if it still exists. We ignore cancels from the + // renderer in the event of a download. + void CancelRequest(int render_process_host_id, + int request_id, + bool from_renderer); + + // Decrements the pending_data_count for the request and resumes + // the request if it was paused due to too many pending data + // messages sent. + void OnDataReceivedACK(int render_process_host_id, int request_id); + + // Resets the waiting_for_upload_progress_ack flag. + void OnUploadProgressACK(int render_process_host_id, int request_id); + + // Returns true if it's ok to send the data. If there are already too many + // data messages pending, it pauses the request and returns false. In this + // case the caller should not send the data. + bool WillSendData(int render_process_host_id, int request_id); + + // Pauses or resumes network activity for a particular request. + void PauseRequest(int render_process_host_id, int request_id, bool pause); + + // Returns the number of pending requests. This is designed for the unittests + int pending_requests() const { + return static_cast<int>(pending_requests_.size()); + } + + DownloadFileManager* download_file_manager() const { + return download_file_manager_; + } + + SaveFileManager* save_file_manager() const { + return save_file_manager_; + } + + SafeBrowsingService* safe_browsing_service() const { + return safe_browsing_; + } + + MessageLoop* ui_loop() const { return ui_loop_; } + + // Called when the onunload handler for a cross-site request has finished. + void OnClosePageACK(int render_process_host_id, int request_id, + bool is_closing_browser); + + // Force cancels any pending requests for the given process. + void CancelRequestsForProcess(int render_process_host_id); + + // Force cancels any pending requests for the given render view. This method + // acts like CancelRequestsForProcess when render_view_id is -1. + void CancelRequestsForRenderView(int render_process_host_id, + int render_view_id); + + // URLRequest::Delegate + virtual void OnReceivedRedirect(URLRequest* request, + const GURL& new_url); + virtual void OnAuthRequired(URLRequest* request, + AuthChallengeInfo* auth_info); + virtual void OnSSLCertificateError(URLRequest* request, + int cert_error, + X509Certificate* cert); + virtual void OnResponseStarted(URLRequest* request); + virtual void OnReadCompleted(URLRequest* request, int bytes_read); + void OnResponseCompleted(URLRequest* request); + + // Helper function to get our extra data out of a request. The given request + // must have been one we created so that it has the proper extra data pointer. + static ExtraRequestInfo* ExtraInfoForRequest(URLRequest* request) { + ExtraRequestInfo* r = static_cast<ExtraRequestInfo*>(request->user_data()); + DLOG_IF(WARNING, !r) << "Request doesn't seem to have our data"; + return r; + } + + static const ExtraRequestInfo* ExtraInfoForRequest(const URLRequest* request) { + const ExtraRequestInfo* r = + static_cast<const ExtraRequestInfo*>(request->user_data()); + DLOG_IF(WARNING, !r) << "Request doesn't seem to have our data"; + return r; + } + + // Add an observer. The observer will be called on the IO thread. To + // observe resource events on the UI thread, subscribe to the + // NOTIFY_RESOURCE_* notifications of the notification service. + void AddObserver(Observer* obs); + + // Remove an observer. + void RemoveObserver(Observer* obs); + + // Retrieves a URLRequest. Must be called from the IO thread. + URLRequest* GetURLRequest(GlobalRequestID request_id) const; + + private: + class AsyncEventHandler; + class SyncEventHandler; + class CrossSiteNotifyTabTask; + class DownloadEventHandler; + class BufferedEventHandler; + class SaveFileEventHandler; + class ShutdownTask; + + friend class ShutdownTask; + + // A shutdown helper that runs on the IO thread. + void OnShutdown(); + + // Returns true if the request is paused. + bool PauseRequestIfNeeded(ExtraRequestInfo* info); + + // Resumes the given request by calling OnResponseStarted or OnReadCompleted. + void ResumeRequest(const GlobalRequestID& request_id); + + // Reads data from the response using our internal buffer as async IO. + // Returns true if data is available immediately, false otherwise. If the + // return value is false, we will receive a OnReadComplete() callback later. + bool Read(URLRequest *, int *bytes_read); + + // Internal function to finish an async IO which has completed. Returns + // true if there is more data to read (e.g. we haven't read EOF yet and + // no errors have occurred). + bool CompleteRead(URLRequest *, int* bytes_read); + + // Internal function to finish handling the ResponseStarted message. Returns + // true on success. + bool CompleteResponseStarted(URLRequest* request); + + // Helper function for regular and download requests. + void BeginRequestInternal(URLRequest* request, bool mixed_content); + + // The list of all requests that we have pending. This list is not really + // optimized, and assumes that we have relatively few requests pending at once + // since some operations require brute-force searching of the list. + // + // It may be enhanced in the future to provide some kind of prioritization + // mechanism. We should also consider a hashtable or binary tree if it turns + // out we have a lot of things here. + typedef std::map<GlobalRequestID,URLRequest*> PendingRequestList; + + // A test to determining whether a given request should be forwarded to the + // download thread. + bool ShouldDownload(const std::string& mime_type, + const std::string& content_disposition); + + void RemovePendingRequest(int render_process_host_id, int request_id); + void RemovePendingRequest(PendingRequestList::iterator& iter); + + // Notify our observers that we started receiving a response for a request. + void NotifyResponseStarted(URLRequest* request, int render_process_host_id); + + // Notify our observers that a request has been cancelled. + void NotifyResponseCompleted(URLRequest* request, int render_process_host_id); + + // Notify our observers that a request has been redirected. + void NofityReceivedRedirect(URLRequest* request, + int render_process_host_id, + const GURL& new_url); + + // Tries to handle the url with an external protocol. If the request is + // handled, the function returns true. False otherwise. + bool HandleExternalProtocol(int request_id, + int render_process_host_id, + int tab_contents_id, + const GURL& url, + ResourceType::Type resource_type, + EventHandler* handler); + + void UpdateLoadStates(); + + void MaybeUpdateUploadProgress(ExtraRequestInfo *info, URLRequest *request); + + PendingRequestList pending_requests_; + + // We cache the UI message loop so we can create new UI-related objects on it. + MessageLoop* ui_loop_; + + // We cache the IO loop to ensure that GetURLRequest is only called from the + // IO thread. + MessageLoop* io_loop_; + + // A timer that periodically calls UpdateLoadStates while pending_requests_ + // is not empty. + RepeatingTimer update_load_states_timer_; + + // We own the download file writing thread and manager + scoped_refptr<DownloadFileManager> download_file_manager_; + + // We own the save file manager. + scoped_refptr<SaveFileManager> save_file_manager_; + + scoped_refptr<SafeBrowsingService> safe_browsing_; + + // Request ID for non-renderer initiated requests. request_ids generated by + // the renderer process are counted up from 0, while browser created requests + // start at -2 and go down from there. (We need to start at -2 because -1 is + // used as a special value all over the resource_dispatcher_host for + // uninitialized variables.) This way, we no longer have the unlikely (but + // observed in the real world!) event where we have two requests with the same + // request_id_. + int request_id_; + + // List of objects observing resource dispatching. + ObserverList<Observer> observer_list_; + + PluginService* plugin_service_; + + // For running tasks. + ScopedRunnableMethodFactory<ResourceDispatcherHost> method_runner_; + + // True if the resource dispatcher host has been shut down. + bool is_shutdown_; + + DISALLOW_EVIL_CONSTRUCTORS(ResourceDispatcherHost); +}; + +#endif // CHROME_BROWSER_RESOURCE_DISPATCHER_HOST_H__ |