New attempt at landing the resource_dispatcher_host.cc splitting (broke the build on Friday).

TBR=darin
Review URL: http://codereview.chromium.org/15801

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@7400 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/chrome/browser/browser.scons b/chrome/browser/browser.scons
index 8b6105b..abfb6ff 100644
--- a/chrome/browser/browser.scons
+++ b/chrome/browser/browser.scons
@@ -244,8 +244,16 @@
       'render_view_host_manager.cc',
       'render_widget_helper.cc',
       'render_widget_host.cc',
-      'repost_Form_warning_dialog.cc',
-      'resource_dispatcher_host.cc',
+      'renderer_host/async_resource_handler.cc',
+      'renderer_host/buffered_resource_handler.cc',
+      'renderer_host/cross_site_resource_handler.cc',
+      'renderer_host/download_resource_handler.cc',
+      'renderer_host/download_throttling_resource_handler.cc',
+      'renderer_host/resource_dispatcher_host.cc',
+      'renderer_host/safe_browsing_resource_handler.cc',
+      'renderer_host/save_file_resource_handler.cc',
+      'renderer_host/sync_resource_handler.cc',
+      'repost_form_warning_dialog.cc',
       'resource_message_filter.cc',
       'rlz/rlz.cc',
       'safe_browsing/protocol_manager.cc',
diff --git a/chrome/browser/browser.vcproj b/chrome/browser/browser.vcproj
index 387f8ee..61ad12a7 100644
--- a/chrome/browser/browser.vcproj
+++ b/chrome/browser/browser.vcproj
@@ -554,14 +554,6 @@
 				>
 			</File>
 			<File
-				RelativePath=".\resource_dispatcher_host.cc"
-				>
-			</File>
-			<File
-				RelativePath=".\resource_dispatcher_host.h"
-				>
-			</File>
-			<File
 				RelativePath=".\resource_message_filter.cc"
 				>
 			</File>
@@ -2254,6 +2246,104 @@
 				>
 			</File>
 		</Filter>
+		<Filter
+			Name="Renderer Host"
+			>
+			<File
+				RelativePath=".\renderer_host\async_resource_handler.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\renderer_host\async_resource_handler.h"
+				>
+			</File>
+			<File
+				RelativePath=".\renderer_host\buffered_resource_handler.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\renderer_host\buffered_resource_handler.h"
+				>
+			</File>
+			<File
+				RelativePath=".\renderer_host\cross_site_resource_handler.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\renderer_host\cross_site_resource_handler.h"
+				>
+			</File>
+			<File
+				RelativePath=".\renderer_host\download_resource_handler.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\renderer_host\download_resource_handler.h"
+				>
+			</File>
+			<File
+				RelativePath=".\renderer_host\download_throttling_resource_handler.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\renderer_host\download_throttling_resource_handler.h"
+				>
+			</File>
+			<File
+				RelativePath=".\renderer_host\resource_dispatcher_host.cc"
+				>
+				<FileConfiguration
+					Name="Debug|Win32"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						ObjectFile="$(IntDir)\$(InputName)1.obj"
+						XMLDocumentationFileName="$(IntDir)\$(InputName)1.xdc"
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release|Win32"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						ObjectFile="$(IntDir)\$(InputName)1.obj"
+						XMLDocumentationFileName="$(IntDir)\$(InputName)1.xdc"
+					/>
+				</FileConfiguration>
+			</File>
+			<File
+				RelativePath=".\renderer_host\resource_dispatcher_host.h"
+				>
+			</File>
+			<File
+				RelativePath=".\renderer_host\resource_handler.h"
+				>
+			</File>
+			<File
+				RelativePath=".\renderer_host\safe_browsing_resource_handler.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\renderer_host\safe_browsing_resource_handler.h"
+				>
+			</File>
+			<File
+				RelativePath=".\renderer_host\save_file_resource_handler.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\renderer_host\save_file_resource_handler.h"
+				>
+			</File>
+			<File
+				RelativePath=".\renderer_host\sync_resource_handler.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\renderer_host\sync_resource_handler.h"
+				>
+			</File>
+		</Filter>
 		<File
 			RelativePath=".\browser_trial.cc"
 			>
diff --git a/chrome/browser/browser_process.h b/chrome/browser/browser_process.h
index 221f491..18ce8be 100644
--- a/chrome/browser/browser_process.h
+++ b/chrome/browser/browser_process.h
@@ -16,7 +16,7 @@
 #include "base/basictypes.h"
 #include "base/message_loop.h"
 #if defined(OS_WIN)
-#include "chrome/browser/resource_dispatcher_host.h"
+#include "chrome/browser/renderer_host/resource_dispatcher_host.h"
 #endif  // defined(OS_WIN)
 
 class AutomationProviderList;
diff --git a/chrome/browser/browser_process_impl.cc b/chrome/browser/browser_process_impl.cc
index 3d3e8a5..904de03 100644
--- a/chrome/browser/browser_process_impl.cc
+++ b/chrome/browser/browser_process_impl.cc
@@ -19,7 +19,7 @@
 #include "chrome/browser/printing/print_job_manager.h"
 #include "chrome/browser/profile_manager.h"
 #include "chrome/browser/render_process_host.h"
-#include "chrome/browser/resource_dispatcher_host.h"
+#include "chrome/browser/renderer_host/resource_dispatcher_host.h"
 #include "chrome/browser/safe_browsing/safe_browsing_service.h"
 #include "chrome/browser/debugger/debugger_wrapper.h"
 #include "chrome/common/chrome_paths.h"
diff --git a/chrome/browser/download/download_file.cc b/chrome/browser/download/download_file.cc
index 2a5e6125..b06be046 100644
--- a/chrome/browser/download/download_file.cc
+++ b/chrome/browser/download/download_file.cc
@@ -15,7 +15,7 @@
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/download/download_manager.h"
 #include "chrome/browser/profile.h"
-#include "chrome/browser/resource_dispatcher_host.h"
+#include "chrome/browser/renderer_host/resource_dispatcher_host.h"
 #include "chrome/browser/tab_util.h"
 #include "chrome/browser/web_contents.h"
 #include "chrome/common/chrome_paths.h"
diff --git a/chrome/browser/download/download_manager.cc b/chrome/browser/download/download_manager.cc
index adf62d3..b4bdea9 100644
--- a/chrome/browser/download/download_manager.cc
+++ b/chrome/browser/download/download_manager.cc
@@ -24,7 +24,7 @@
 #include "chrome/browser/profile.h"
 #include "chrome/browser/render_process_host.h"
 #include "chrome/browser/render_view_host.h"
-#include "chrome/browser/resource_dispatcher_host.h"
+#include "chrome/browser/renderer_host/resource_dispatcher_host.h"
 #include "chrome/browser/tab_util.h"
 #include "chrome/browser/web_contents.h"
 #include "chrome/common/chrome_paths.h"
diff --git a/chrome/browser/download/save_file_manager.cc b/chrome/browser/download/save_file_manager.cc
index 631b55d..41607ea8 100644
--- a/chrome/browser/download/save_file_manager.cc
+++ b/chrome/browser/download/save_file_manager.cc
@@ -15,7 +15,7 @@
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/download/save_file.h"
 #include "chrome/browser/download/save_package.h"
-#include "chrome/browser/resource_dispatcher_host.h"
+#include "chrome/browser/renderer_host/resource_dispatcher_host.h"
 #include "chrome/browser/tab_contents.h"
 #include "chrome/browser/tab_util.h"
 #include "chrome/browser/web_contents.h"
diff --git a/chrome/browser/download/save_package.cc b/chrome/browser/download/save_package.cc
index 9eaf7fc..d01d2d7 100644
--- a/chrome/browser/download/save_package.cc
+++ b/chrome/browser/download/save_package.cc
@@ -21,7 +21,7 @@
 #include "chrome/browser/render_process_host.h"
 #include "chrome/browser/render_view_host.h"
 #include "chrome/browser/render_view_host_delegate.h"
-#include "chrome/browser/resource_dispatcher_host.h"
+#include "chrome/browser/renderer_host/resource_dispatcher_host.h"
 #include "chrome/browser/tab_util.h"
 #include "chrome/browser/web_contents.h"
 #include "chrome/browser/views/download_shelf_view.h"
diff --git a/chrome/browser/login_prompt.cc b/chrome/browser/login_prompt.cc
index db9d775..24fd24f 100644
--- a/chrome/browser/login_prompt.cc
+++ b/chrome/browser/login_prompt.cc
@@ -13,7 +13,7 @@
 #include "chrome/browser/navigation_controller.h"
 #include "chrome/browser/password_manager.h"
 #include "chrome/browser/render_process_host.h"
-#include "chrome/browser/resource_dispatcher_host.h"
+#include "chrome/browser/renderer_host/resource_dispatcher_host.h"
 #include "chrome/browser/web_contents.h"
 #include "chrome/browser/tab_util.h"
 #include "chrome/browser/views/login_view.h"
diff --git a/chrome/browser/plugin_process_host.cc b/chrome/browser/plugin_process_host.cc
index 323fa93..4dcb107a 100644
--- a/chrome/browser/plugin_process_host.cc
+++ b/chrome/browser/plugin_process_host.cc
@@ -21,7 +21,7 @@
 #include "chrome/browser/plugin_service.h"
 #include "chrome/browser/profile.h"
 #include "chrome/browser/render_process_host.h"
-#include "chrome/browser/resource_dispatcher_host.h"
+#include "chrome/browser/renderer_host/resource_dispatcher_host.h"
 #include "chrome/browser/sandbox_policy.h"
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/chrome_plugin_lib.h"
diff --git a/chrome/browser/render_widget_helper.cc b/chrome/browser/render_widget_helper.cc
index 4b87080..0d761416 100644
--- a/chrome/browser/render_widget_helper.cc
+++ b/chrome/browser/render_widget_helper.cc
@@ -7,7 +7,7 @@
 #include "base/thread.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/render_process_host.h"
-#include "chrome/browser/resource_dispatcher_host.h"
+#include "chrome/browser/renderer_host/resource_dispatcher_host.h"
 
 using base::TimeDelta;
 using base::TimeTicks;
diff --git a/chrome/browser/renderer_host/async_resource_handler.cc b/chrome/browser/renderer_host/async_resource_handler.cc
new file mode 100644
index 0000000..2708a22
--- /dev/null
+++ b/chrome/browser/renderer_host/async_resource_handler.cc
@@ -0,0 +1,109 @@
+// Copyright (c) 2006-2008 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/renderer_host/async_resource_handler.h"
+
+base::SharedMemory* AsyncResourceHandler::spare_read_buffer_;
+
+AsyncResourceHandler::AsyncResourceHandler(
+    ResourceDispatcherHost::Receiver* receiver,
+    int render_process_host_id,
+    int routing_id,
+    HANDLE render_process,
+    const GURL& url,
+    ResourceDispatcherHost* resource_dispatcher_host)
+    : receiver_(receiver),
+      render_process_host_id_(render_process_host_id),
+      routing_id_(routing_id),
+      render_process_(render_process),
+      rdh_(resource_dispatcher_host) {
+}
+
+bool AsyncResourceHandler::OnUploadProgress(int request_id,
+                                            uint64 position,
+                                            uint64 size) {
+  return receiver_->Send(new ViewMsg_Resource_UploadProgress(routing_id_,
+                                                             request_id,
+                                                             position, size));
+}
+
+bool AsyncResourceHandler::OnRequestRedirected(int request_id,
+                                               const GURL& new_url) {
+  return receiver_->Send(new ViewMsg_Resource_ReceivedRedirect(routing_id_,
+                                                               request_id,
+                                                               new_url));
+}
+
+bool AsyncResourceHandler::OnResponseStarted(int request_id,
+                                             ResourceResponse* response) {
+  receiver_->Send(new ViewMsg_Resource_ReceivedResponse(
+      routing_id_, request_id, response->response_head));
+  return true;
+}
+
+bool AsyncResourceHandler::OnWillRead(int request_id,
+                                      char** buf, int* buf_size,
+                                      int min_size) {
+  DCHECK(min_size == -1);
+  static const int kReadBufSize = 32768;
+  if (spare_read_buffer_) {
+    read_buffer_.reset(spare_read_buffer_);
+    spare_read_buffer_ = NULL;
+  } else {
+    read_buffer_.reset(new base::SharedMemory);
+    if (!read_buffer_->Create(std::wstring(), false, false, kReadBufSize))
+      return false;
+    if (!read_buffer_->Map(kReadBufSize))
+      return false;
+  }
+  *buf = static_cast<char*>(read_buffer_->memory());
+  *buf_size = kReadBufSize;
+  return true;
+}
+
+bool AsyncResourceHandler::OnReadCompleted(int request_id, int* bytes_read) {
+  if (!*bytes_read)
+    return true;
+  DCHECK(read_buffer_.get());
+
+  if (!rdh_->WillSendData(render_process_host_id_, request_id)) {
+    // We should not send this data now, we have too many pending requests.
+    return true;
+  }
+
+  base::SharedMemoryHandle handle;
+  if (!read_buffer_->GiveToProcess(render_process_, &handle)) {
+    // We wrongfully incremented the pending data count. Fake an ACK message
+    // to fix this. We can't move this call above the WillSendData because
+    // it's killing our read_buffer_, and we don't want that when we pause
+    // the request.
+    rdh_->OnDataReceivedACK(render_process_host_id_, request_id);
+    return false;
+  }
+
+  receiver_->Send(new ViewMsg_Resource_DataReceived(
+      routing_id_, request_id, handle, *bytes_read));
+
+  return true;
+}
+
+bool AsyncResourceHandler::OnResponseCompleted(int request_id,
+                                               const URLRequestStatus& status) {
+  receiver_->Send(new ViewMsg_Resource_RequestComplete(routing_id_,
+                                                       request_id, status));
+
+  // If we still have a read buffer, then see about caching it for later...
+  if (spare_read_buffer_) {
+    read_buffer_.reset();
+  } else if (read_buffer_.get() && read_buffer_->memory()) {
+    spare_read_buffer_ = read_buffer_.release();
+  }
+  return true;
+}
+
+// static
+void AsyncResourceHandler::GlobalCleanup() {
+  delete spare_read_buffer_;
+  spare_read_buffer_ = NULL;
+}
diff --git a/chrome/browser/renderer_host/async_resource_handler.h b/chrome/browser/renderer_host/async_resource_handler.h
new file mode 100644
index 0000000..5d24b75
--- /dev/null
+++ b/chrome/browser/renderer_host/async_resource_handler.h
@@ -0,0 +1,50 @@
+// Copyright (c) 2006-2008 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_RENDERER_HOST_ASYNC_RESOURCE_HANDLER_H_
+#define CHROME_BROWSER_RENDERER_HOST_ASYNC_RESOURCE_HANDLER_H_
+
+#include "chrome/browser/renderer_host/resource_dispatcher_host.h"
+#include "chrome/browser/renderer_host/resource_handler.h"
+
+class base::SharedMemory;
+
+// Used to complete an asynchronous resource request in response to resource
+// load events from the resource dispatcher host.
+class AsyncResourceHandler : public ResourceHandler {
+ public:
+  AsyncResourceHandler(ResourceDispatcherHost::Receiver* receiver,
+                       int render_process_host_id,
+                       int routing_id,
+                       HANDLE render_process,
+                       const GURL& url,
+                       ResourceDispatcherHost* resource_dispatcher_host);
+
+  // ResourceHandler implementation:
+  bool OnUploadProgress(int request_id, uint64 position, uint64 size);
+  bool OnRequestRedirected(int request_id, const GURL& new_url);
+  bool OnResponseStarted(int request_id, ResourceResponse* response);
+  bool OnWillRead(int request_id, char** buf, int* buf_size, int min_size);
+  bool OnReadCompleted(int request_id, int* bytes_read);
+  bool OnResponseCompleted(int request_id, const URLRequestStatus& status);
+
+  static void GlobalCleanup();
+
+ private:
+  // When reading, we don't know if we are going to get EOF (0 bytes read), so
+  // we typically have a buffer that we allocated but did not use.  We keep
+  // this buffer around for the next read as a small optimization.
+  static base::SharedMemory* spare_read_buffer_;
+
+  scoped_ptr<base::SharedMemory> read_buffer_;
+  ResourceDispatcherHost::Receiver* receiver_;
+  int render_process_host_id_;
+  int routing_id_;
+  HANDLE render_process_;
+  ResourceDispatcherHost* rdh_;
+
+  DISALLOW_COPY_AND_ASSIGN(AsyncResourceHandler);
+};
+
+#endif  // CHROME_BROWSER_RENDERER_HOST_ASYNC_RESOURCE_HANDLER_H_
diff --git a/chrome/browser/renderer_host/buffered_resource_handler.cc b/chrome/browser/renderer_host/buffered_resource_handler.cc
new file mode 100644
index 0000000..ae9fa35
--- /dev/null
+++ b/chrome/browser/renderer_host/buffered_resource_handler.cc
@@ -0,0 +1,231 @@
+// Copyright (c) 2006-2008 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/renderer_host/buffered_resource_handler.h"
+
+#include "net/base/mime_sniffer.h"
+#include "chrome/browser/renderer_host/download_throttling_resource_handler.h"
+#include "chrome/browser/renderer_host/resource_dispatcher_host.h"
+
+BufferedResourceHandler::BufferedResourceHandler(ResourceHandler* handler,
+                                                 ResourceDispatcherHost* host,
+                                                 URLRequest* request)
+    : real_handler_(handler),
+      host_(host),
+      request_(request),
+      bytes_read_(0),
+      sniff_content_(false),
+      should_buffer_(false),
+      buffering_(false),
+      finished_(false) {
+}
+
+bool BufferedResourceHandler::OnUploadProgress(int request_id,
+                                               uint64 position,
+                                               uint64 size) {
+  return real_handler_->OnUploadProgress(request_id, position, size);
+}
+
+bool BufferedResourceHandler::OnRequestRedirected(int request_id,
+                                                  const GURL& new_url) {
+  return real_handler_->OnRequestRedirected(request_id, new_url);
+}
+
+bool BufferedResourceHandler::OnResponseStarted(int request_id,
+                                                ResourceResponse* response) {
+  response_ = response;
+  if (!DelayResponse())
+    return CompleteResponseStarted(request_id, false);
+  return true;
+}
+
+
+bool BufferedResourceHandler::OnResponseCompleted(
+    int request_id, const URLRequestStatus& status) {
+  return real_handler_->OnResponseCompleted(request_id, status);
+}
+
+// We'll let the original event handler provide a buffer, and reuse it for
+// subsequent reads until we're done buffering.
+bool BufferedResourceHandler::OnWillRead(int request_id,
+                                         char** buf, int* buf_size,
+                                         int min_size) {
+  if (buffering_) {
+    *buf = read_buffer_ + bytes_read_;
+    *buf_size = read_buffer_size_ - bytes_read_;
+    DCHECK(*buf_size > 0);
+    return true;
+  }
+
+  if (finished_)
+    return false;
+
+  bool ret = real_handler_->OnWillRead(request_id, buf, buf_size, min_size);
+  read_buffer_ = *buf;
+  read_buffer_size_ = *buf_size;
+  bytes_read_ = 0;
+  return ret;
+}
+
+bool BufferedResourceHandler::OnReadCompleted(int request_id, int* bytes_read) {
+  ResourceDispatcherHost::ExtraRequestInfo* info =
+      ResourceDispatcherHost::ExtraInfoForRequest(request_);
+
+  if (sniff_content_ || should_buffer_) {
+    if (KeepBuffering(*bytes_read))
+      return true;
+
+    LOG(INFO) << "Finished buffering " << request_->url().spec();
+    sniff_content_ = should_buffer_ = false;
+    *bytes_read = bytes_read_;
+
+    // Done buffering, send the pending ResponseStarted event.
+    if (!CompleteResponseStarted(request_id, true))
+      return false;
+  }
+
+  return real_handler_->OnReadCompleted(request_id, bytes_read);
+}
+
+bool BufferedResourceHandler::DelayResponse() {
+  std::string mime_type;
+  request_->GetMimeType(&mime_type);
+
+  std::string content_type_options;
+  request_->GetResponseHeaderByName("x-content-type-options",
+                                    &content_type_options);
+  if (content_type_options != "nosniff" &&
+      net::ShouldSniffMimeType(request_->url(), mime_type)) {
+    // We're going to look at the data before deciding what the content type
+    // is.  That means we need to delay sending the ResponseStarted message
+    // over the IPC channel.
+    sniff_content_ = true;
+    LOG(INFO) << "To buffer: " << request_->url().spec();
+    return true;
+  }
+
+  if (ShouldBuffer(request_->url(), mime_type)) {
+    // This is a temporary fix for the fact that webkit expects to have
+    // enough data to decode the doctype in order to select the rendering
+    // mode.
+    should_buffer_ = true;
+    LOG(INFO) << "To buffer: " << request_->url().spec();
+    return true;
+  }
+  return false;
+}
+
+bool BufferedResourceHandler::ShouldBuffer(const GURL& url,
+                                           const std::string& mime_type) {
+  // We are willing to buffer for HTTP and HTTPS.
+  bool sniffable_scheme = url.is_empty() ||
+                          url.SchemeIs("http") ||
+                          url.SchemeIs("https");
+  if (!sniffable_scheme)
+    return false;
+
+  // Today, the only reason to buffer the request is to fix the doctype decoding
+  // performed by webkit: if there is not enough data it will go to quirks mode.
+  // We only expect the doctype check to apply to html documents.
+  return mime_type == "text/html";
+}
+
+bool BufferedResourceHandler::KeepBuffering(int bytes_read) {
+  DCHECK(read_buffer_);
+  bytes_read_ += bytes_read;
+  finished_ = (bytes_read == 0);
+
+  if (sniff_content_) {
+    std::string type_hint, new_type;
+    request_->GetMimeType(&type_hint);
+
+    if (!net::SniffMimeType(read_buffer_, bytes_read_, request_->url(),
+                            type_hint, &new_type)) {
+      // SniffMimeType() returns false if there is not enough data to determine
+      // the mime type. However, even if it returns false, it returns a new type
+      // that is probably better than the current one.
+      DCHECK(bytes_read_ < 512 /*kMaxBytesToSniff*/);
+      if (!finished_) {
+        buffering_ = true;
+        return true;
+      }
+    }
+    sniff_content_ = false;
+    response_->response_head.mime_type.assign(new_type);
+
+    // We just sniffed the mime type, maybe there is a doctype to process.
+    if (ShouldBuffer(request_->url(), new_type))
+      should_buffer_ = true;
+  }
+
+  if (!finished_ && should_buffer_) {
+    if (!DidBufferEnough(bytes_read_)) {
+      buffering_ = true;
+      return true;
+    }
+  }
+  buffering_ = false;
+  return false;
+}
+
+bool BufferedResourceHandler::CompleteResponseStarted(int request_id,
+                                                      bool in_complete) {
+  // Check to see if we should forward the data from this request to the
+  // download thread.
+  // TODO(paulg): Only download if the context from the renderer allows it.
+  std::string content_disposition;
+  request_->GetResponseHeaderByName("content-disposition",
+                                    &content_disposition);
+
+  ResourceDispatcherHost::ExtraRequestInfo* info =
+      ResourceDispatcherHost::ExtraInfoForRequest(request_);
+
+  if (info->allow_download &&
+      host_->ShouldDownload(response_->response_head.mime_type,
+                            content_disposition)) {
+    if (response_->response_head.headers &&  // Can be NULL if FTP.
+        response_->response_head.headers->response_code() / 100 != 2) {
+      // The response code indicates that this is an error page, but we don't
+      // know how to display the content.  We follow Firefox here and show our
+      // own error page instead of triggering a download.
+      // TODO(abarth): We should abstract the response_code test, but this kind
+      //               of check is scattered throughout our codebase.
+      request_->CancelWithError(net::ERR_FILE_NOT_FOUND);
+      return false;
+    }
+
+    info->is_download = true;
+
+    scoped_refptr<DownloadThrottlingResourceHandler> download_handler =
+        new DownloadThrottlingResourceHandler(host_,
+                                           request_,
+                                           request_->url().spec(),
+                                           info->render_process_host_id,
+                                           info->render_view_id,
+                                           request_id,
+                                           in_complete);
+    if (bytes_read_) {
+      // a Read has already occurred and we need to copy the data into the
+      // EventHandler.
+      char *buf = NULL;
+      int buf_len = 0;
+      download_handler->OnWillRead(request_id, &buf, &buf_len, bytes_read_);
+      CHECK((buf_len >= bytes_read_) && (bytes_read_ >= 0));
+      memcpy(buf, read_buffer_, bytes_read_);
+    }
+    // Update the renderer with the response headers which will cause it to
+    // cancel the request.
+    // TODO(paulg): Send the renderer a response that indicates that the request
+    //              will be handled by an external source (the browser).
+    real_handler_->OnResponseStarted(info->request_id, response_);
+    real_handler_ = download_handler;
+  }
+  return real_handler_->OnResponseStarted(request_id, response_);
+}
+
+bool BufferedResourceHandler::DidBufferEnough(int bytes_read) {
+  const int kRequiredLength = 256;
+
+  return bytes_read >= kRequiredLength;
+}
diff --git a/chrome/browser/renderer_host/buffered_resource_handler.h b/chrome/browser/renderer_host/buffered_resource_handler.h
new file mode 100644
index 0000000..0b832a9
--- /dev/null
+++ b/chrome/browser/renderer_host/buffered_resource_handler.h
@@ -0,0 +1,62 @@
+// Copyright (c) 2006-2008 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_RENDERER_HOST_BUFFERED_RESOURCE_HANDLER_H_
+#define CHROME_BROWSER_RENDERER_HOST_BUFFERED_RESOURCE_HANDLER_H_
+
+#include <string>
+
+#include "chrome/browser/renderer_host/resource_handler.h"
+
+class ResourceDispatcherHost;
+
+// Used to buffer a request until enough data has been received.
+class BufferedResourceHandler : public ResourceHandler {
+ public:
+  BufferedResourceHandler(ResourceHandler* handler,
+                          ResourceDispatcherHost* host,
+                          URLRequest* request);
+
+  // ResourceHandler implementation:
+  bool OnUploadProgress(int request_id, uint64 position, uint64 size);
+  bool OnRequestRedirected(int request_id, const GURL& new_url);
+  bool OnResponseStarted(int request_id, ResourceResponse* response);
+  bool OnWillRead(int request_id, char** buf, int* buf_size, int min_size);
+  bool OnReadCompleted(int request_id, int* bytes_read);
+  bool OnResponseCompleted(int request_id, const URLRequestStatus& status);
+
+ private:
+  // Returns true if we should delay OnResponseStarted forwarding.
+  bool DelayResponse();
+
+  // Returns true if there will be a need to parse the DocType of the document
+  // to determine the right way to handle it.
+  bool ShouldBuffer(const GURL& url, const std::string& mime_type);
+
+  // Returns true if there is enough information to process the DocType.
+  bool DidBufferEnough(int bytes_read);
+
+  // Returns true if we have to keep buffering data.
+  bool KeepBuffering(int bytes_read);
+
+  // Sends a pending OnResponseStarted notification. |in_complete| is true if
+  // this is invoked from |OnResponseCompleted|.
+  bool CompleteResponseStarted(int request_id, bool in_complete);
+
+  scoped_refptr<ResourceHandler> real_handler_;
+  scoped_refptr<ResourceResponse> response_;
+  ResourceDispatcherHost* host_;
+  URLRequest* request_;
+  char* read_buffer_;
+  int read_buffer_size_;
+  int bytes_read_;
+  bool sniff_content_;
+  bool should_buffer_;
+  bool buffering_;
+  bool finished_;
+
+  DISALLOW_COPY_AND_ASSIGN(BufferedResourceHandler);
+};
+
+#endif  // CHROME_BROWSER_RENDERER_HOST_BUFFERED_RESOURCE_HANDLER_H_
diff --git a/chrome/browser/renderer_host/cross_site_resource_handler.cc b/chrome/browser/renderer_host/cross_site_resource_handler.cc
new file mode 100644
index 0000000..aaf579b
--- /dev/null
+++ b/chrome/browser/renderer_host/cross_site_resource_handler.cc
@@ -0,0 +1,218 @@
+// Copyright (c) 2006-2008 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/renderer_host/cross_site_resource_handler.h"
+
+#include "chrome/browser/render_view_host.h"
+
+namespace {
+// Task to notify the WebContents that a cross-site response has begun, so that
+// WebContents can tell the old page to run its onunload handler.
+class CrossSiteNotifyTabTask : public Task {
+ public:
+  CrossSiteNotifyTabTask(int render_process_host_id,
+                         int render_view_id,
+                         int request_id)
+    : render_process_host_id_(render_process_host_id),
+      render_view_id_(render_view_id),
+      request_id_(request_id) {}
+
+  void Run() {
+    RenderViewHost* view =
+        RenderViewHost::FromID(render_process_host_id_, render_view_id_);
+    if (view) {
+      view->OnCrossSiteResponse(render_process_host_id_, request_id_);
+    } else {
+      // The view couldn't be found.
+      // TODO(creis): Should notify the IO thread to proceed anyway, using
+      // ResourceDispatcherHost::OnClosePageACK.
+    }
+  }
+
+ private:
+  int render_process_host_id_;
+  int render_view_id_;
+  int request_id_;
+};
+}
+
+CrossSiteResourceHandler::CrossSiteResourceHandler(
+    ResourceHandler* handler,
+    int render_process_host_id,
+    int render_view_id,
+    ResourceDispatcherHost* resource_dispatcher_host)
+    : next_handler_(handler),
+      render_process_host_id_(render_process_host_id),
+      render_view_id_(render_view_id),
+      has_started_response_(false),
+      in_cross_site_transition_(false),
+      request_id_(-1),
+      completed_during_transition_(false),
+      completed_status_(),
+      response_(NULL),
+      rdh_(resource_dispatcher_host) {}
+
+bool CrossSiteResourceHandler::OnRequestRedirected(int request_id,
+                                                   const GURL& new_url) {
+  // We should not have started the transition before being redirected.
+  DCHECK(!in_cross_site_transition_);
+  return next_handler_->OnRequestRedirected(request_id, new_url);
+}
+
+bool CrossSiteResourceHandler::OnResponseStarted(int request_id,
+                                                 ResourceResponse* response) {
+  // At this point, we know that the response is safe to send back to the
+  // renderer: it is not a download, and it has passed the SSL and safe
+  // browsing checks.
+  // We should not have already started the transition before now.
+  DCHECK(!in_cross_site_transition_);
+  has_started_response_ = true;
+
+  // Look up the request and associated info.
+  ResourceDispatcherHost::GlobalRequestID global_id(render_process_host_id_,
+                                                    request_id);
+  URLRequest* request = rdh_->GetURLRequest(global_id);
+  if (!request) {
+    DLOG(WARNING) << "Request wasn't found";
+    return false;
+  }
+  ResourceDispatcherHost::ExtraRequestInfo* info =
+      ResourceDispatcherHost::ExtraInfoForRequest(request);
+
+  // If this is a download, just pass the response through without doing a
+  // cross-site check.  The renderer will see it is a download and abort the
+  // request.
+  if (info->is_download) {
+    return next_handler_->OnResponseStarted(request_id, response);
+  }
+
+  // Tell the renderer to run the onunload event handler, and wait for the
+  // reply.
+  StartCrossSiteTransition(request_id, response, global_id);
+  return true;
+}
+
+bool CrossSiteResourceHandler::OnWillRead(int request_id,
+                                          char** buf, int* buf_size,
+                                          int min_size) {
+  return next_handler_->OnWillRead(request_id, buf, buf_size, min_size);
+}
+
+bool CrossSiteResourceHandler::OnReadCompleted(int request_id,
+                                               int* bytes_read) {
+  if (!in_cross_site_transition_) {
+    return next_handler_->OnReadCompleted(request_id, bytes_read);
+  }
+  return true;
+}
+
+bool CrossSiteResourceHandler::OnResponseCompleted(
+    int request_id,
+    const URLRequestStatus& status) {
+  if (!in_cross_site_transition_) {
+    if (has_started_response_) {
+      // We've already completed the transition, so just pass it through.
+      return next_handler_->OnResponseCompleted(request_id, status);
+    } else {
+      // Some types of failures will call OnResponseCompleted without calling
+      // CrossSiteResourceHandler::OnResponseStarted.  We should wait now for
+      // the cross-site transition.  Also continue with the logic below to
+      // remember that we completed during the cross-site transition.
+      ResourceDispatcherHost::GlobalRequestID global_id(render_process_host_id_,
+                                                        request_id);
+      StartCrossSiteTransition(request_id, NULL, global_id);
+    }
+  }
+
+  // We have to buffer the call until after the transition completes.
+  completed_during_transition_ = true;
+  completed_status_ = status;
+
+  // Return false to tell RDH not to notify the world or clean up the
+  // pending request.  We will do so in ResumeResponse.
+  return false;
+}
+
+// We can now send the response to the new renderer, which will cause
+// WebContents to swap in the new renderer and destroy the old one.
+void CrossSiteResourceHandler::ResumeResponse() {
+  DCHECK(request_id_ != -1);
+  DCHECK(in_cross_site_transition_);
+  in_cross_site_transition_ = false;
+
+  // Find the request for this response.
+  ResourceDispatcherHost::GlobalRequestID global_id(render_process_host_id_,
+                                                    request_id_);
+  URLRequest* request = rdh_->GetURLRequest(global_id);
+  if (!request) {
+    DLOG(WARNING) << "Resuming a request that wasn't found";
+    return;
+  }
+  ResourceDispatcherHost::ExtraRequestInfo* info =
+      ResourceDispatcherHost::ExtraInfoForRequest(request);
+
+  if (has_started_response_) {
+    // Send OnResponseStarted to the new renderer.
+    DCHECK(response_);
+    next_handler_->OnResponseStarted(request_id_, response_);
+
+    // Unpause the request to resume reading.  Any further reads will be
+    // directed toward the new renderer.
+    rdh_->PauseRequest(render_process_host_id_, request_id_, false);
+  }
+
+  // Remove ourselves from the ExtraRequestInfo.
+  info->cross_site_handler = NULL;
+
+  // If the response completed during the transition, notify the next
+  // event handler.
+  if (completed_during_transition_) {
+    next_handler_->OnResponseCompleted(request_id_, completed_status_);
+
+    // Since we didn't notify the world or clean up the pending request in
+    // RDH::OnResponseCompleted during the transition, we should do it now.
+    rdh_->NotifyResponseCompleted(request, render_process_host_id_);
+    rdh_->RemovePendingRequest(render_process_host_id_, request_id_);
+  }
+}
+
+// Prepare to render the cross-site response in a new RenderViewHost, by
+// telling the old RenderViewHost to run its onunload handler.
+void CrossSiteResourceHandler::StartCrossSiteTransition(
+    int request_id,
+    ResourceResponse* response,
+    ResourceDispatcherHost::GlobalRequestID global_id) {
+  in_cross_site_transition_ = true;
+  request_id_ = request_id;
+  response_ = response;
+
+  // Store this handler on the ExtraRequestInfo, so that RDH can call our
+  // ResumeResponse method when the close ACK is received.
+  URLRequest* request = rdh_->GetURLRequest(global_id);
+  if (!request) {
+    DLOG(WARNING) << "Cross site response for a request that wasn't found";
+    return;
+  }
+  ResourceDispatcherHost::ExtraRequestInfo* info =
+      ResourceDispatcherHost::ExtraInfoForRequest(request);
+  info->cross_site_handler = this;
+
+  if (has_started_response_) {
+    // Pause the request until the old renderer is finished and the new
+    // renderer is ready.
+    rdh_->PauseRequest(render_process_host_id_, request_id, true);
+  }
+  // If our OnResponseStarted wasn't called, then we're being called by
+  // OnResponseCompleted after a failure.  We don't need to pause, because
+  // there will be no reads.
+
+  // Tell the tab responsible for this request that a cross-site response is
+  // starting, so that it can tell its old renderer to run its onunload
+  // handler now.  We will wait to hear the corresponding ClosePage_ACK.
+  CrossSiteNotifyTabTask* task =
+      new CrossSiteNotifyTabTask(render_process_host_id_,
+                                 render_view_id_,
+                                 request_id);
+  rdh_->ui_loop()->PostTask(FROM_HERE, task);
+}
diff --git a/chrome/browser/renderer_host/cross_site_resource_handler.h b/chrome/browser/renderer_host/cross_site_resource_handler.h
new file mode 100644
index 0000000..7801352
--- /dev/null
+++ b/chrome/browser/renderer_host/cross_site_resource_handler.h
@@ -0,0 +1,57 @@
+// Copyright (c) 2006-2008 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_RENDERER_HOST_CROSS_SITE_RESOURCE_HANDLER_H_
+#define CHROME_BROWSER_RENDERER_HOST_CROSS_SITE_RESOURCE_HANDLER_H_
+
+#include "chrome/browser/renderer_host/resource_dispatcher_host.h"
+#include "chrome/browser/renderer_host/resource_handler.h"
+
+// Ensures that cross-site responses are delayed until the onunload handler of
+// the previous page is allowed to run.  This handler wraps an
+// AsyncEventHandler, and it sits inside SafeBrowsing and Buffered event
+// handlers.  This is important, so that it can intercept OnResponseStarted
+// after we determine that a response is safe and not a download.
+class CrossSiteResourceHandler : public ResourceHandler {
+ public:
+  CrossSiteResourceHandler(ResourceHandler* handler,
+                           int render_process_host_id,
+                           int render_view_id,
+                           ResourceDispatcherHost* resource_dispatcher_host);
+
+  // ResourceHandler implementation:
+  bool OnRequestRedirected(int request_id, const GURL& new_url);
+  bool OnResponseStarted(int request_id,
+                         ResourceResponse* response);
+  bool OnWillRead(int request_id, char** buf, int* buf_size, int min_size);
+  bool OnReadCompleted(int request_id, int* bytes_read);
+  bool OnResponseCompleted(int request_id, const URLRequestStatus& status);
+
+  // We can now send the response to the new renderer, which will cause
+  // WebContents to swap in the new renderer and destroy the old one.
+  void ResumeResponse();
+
+ private:
+  // Prepare to render the cross-site response in a new RenderViewHost, by
+  // telling the old RenderViewHost to run its onunload handler.
+  void StartCrossSiteTransition(
+      int request_id,
+      ResourceResponse* response,
+      ResourceDispatcherHost::GlobalRequestID global_id);
+
+  scoped_refptr<ResourceHandler> next_handler_;
+  int render_process_host_id_;
+  int render_view_id_;
+  bool has_started_response_;
+  bool in_cross_site_transition_;
+  int request_id_;
+  bool completed_during_transition_;
+  URLRequestStatus completed_status_;
+  ResourceResponse* response_;
+  ResourceDispatcherHost* rdh_;
+
+  DISALLOW_COPY_AND_ASSIGN(CrossSiteResourceHandler);
+};
+
+#endif  // CHROME_BROWSER_RENDERER_HOST_CROSS_SITE_RESOURCE_HANDLER_H_
diff --git a/chrome/browser/renderer_host/download_resource_handler.cc b/chrome/browser/renderer_host/download_resource_handler.cc
new file mode 100644
index 0000000..13e74573
--- /dev/null
+++ b/chrome/browser/renderer_host/download_resource_handler.cc
@@ -0,0 +1,169 @@
+// Copyright (c) 2006-2008 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/renderer_host/download_resource_handler.h"
+
+#include "chrome/browser/download/download_file.h"
+#include "chrome/browser/download/download_manager.h"
+#include "chrome/browser/renderer_host/resource_dispatcher_host.h"
+
+DownloadResourceHandler::DownloadResourceHandler(ResourceDispatcherHost* rdh,
+                                                 int render_process_host_id,
+                                                 int render_view_id,
+                                                 int request_id,
+                                                 const std::string& url,
+                                                 DownloadFileManager* manager,
+                                                 URLRequest* request,
+                                                 bool save_as)
+    : download_id_(-1),
+      global_id_(ResourceDispatcherHost::GlobalRequestID(render_process_host_id,
+                                                         request_id)),
+      render_view_id_(render_view_id),
+      read_buffer_(NULL),
+      url_(UTF8ToWide(url)),
+      content_length_(0),
+      download_manager_(manager),
+      request_(request),
+      save_as_(save_as),
+      buffer_(new DownloadBuffer),
+      rdh_(rdh),
+      is_paused_(false) {
+}
+
+// Not needed, as this event handler ought to be the final resource.
+bool DownloadResourceHandler::OnRequestRedirected(int request_id,
+                                                  const GURL& url) {
+  url_ = UTF8ToWide(url.spec());
+  return true;
+}
+
+// Send the download creation information to the download thread.
+bool DownloadResourceHandler::OnResponseStarted(int request_id,
+                                                ResourceResponse* response) {
+  std::string content_disposition;
+  request_->GetResponseHeaderByName("content-disposition",
+                                    &content_disposition);
+  set_content_disposition(content_disposition);
+  set_content_length(response->response_head.content_length);
+
+  download_id_ = download_manager_->GetNextId();
+  // |download_manager_| consumes (deletes):
+  DownloadCreateInfo* info = new DownloadCreateInfo;
+  info->url = url_;
+  info->start_time = base::Time::Now();
+  info->received_bytes = 0;
+  info->total_bytes = content_length_;
+  info->state = DownloadItem::IN_PROGRESS;
+  info->download_id = download_id_;
+  info->render_process_id = global_id_.render_process_host_id;
+  info->render_view_id = render_view_id_;
+  info->request_id = global_id_.request_id;
+  info->content_disposition = content_disposition_;
+  info->mime_type = response->response_head.mime_type;
+  info->save_as = save_as_;
+  info->is_dangerous = false;
+  download_manager_->file_loop()->PostTask(FROM_HERE,
+      NewRunnableMethod(download_manager_,
+                        &DownloadFileManager::StartDownload,
+                        info));
+  return true;
+}
+
+// Create a new buffer, which will be handed to the download thread for file
+// writing and deletion.
+bool DownloadResourceHandler::OnWillRead(int request_id,
+                                         char** buf, int* buf_size,
+                                         int min_size) {
+  DCHECK(buf && buf_size);
+  if (!read_buffer_) {
+    *buf_size = min_size < 0 ? kReadBufSize : min_size;
+    read_buffer_ = new char[*buf_size];
+  }
+  *buf = read_buffer_;
+  return true;
+}
+
+// Pass the buffer to the download file writer.
+bool DownloadResourceHandler::OnReadCompleted(int request_id, int* bytes_read) {
+  if (!*bytes_read)
+    return true;
+  DCHECK(read_buffer_);
+  AutoLock auto_lock(buffer_->lock);
+  bool need_update = buffer_->contents.empty();
+  buffer_->contents.push_back(std::make_pair(read_buffer_, *bytes_read));
+  if (need_update) {
+    download_manager_->file_loop()->PostTask(FROM_HERE,
+        NewRunnableMethod(download_manager_,
+                          &DownloadFileManager::UpdateDownload,
+                          download_id_,
+                          buffer_));
+  }
+  read_buffer_ = NULL;
+
+  // We schedule a pause outside of the read loop if there is too much file
+  // writing work to do.
+  if (buffer_->contents.size() > kLoadsToWrite)
+    StartPauseTimer();
+
+  return true;
+}
+
+bool DownloadResourceHandler::OnResponseCompleted(
+    int request_id,
+    const URLRequestStatus& status) {
+  download_manager_->file_loop()->PostTask(FROM_HERE,
+      NewRunnableMethod(download_manager_,
+                        &DownloadFileManager::DownloadFinished,
+                        download_id_,
+                        buffer_));
+  delete [] read_buffer_;
+
+  // 'buffer_' is deleted by the DownloadFileManager.
+  buffer_ = NULL;
+  return true;
+}
+
+// If the content-length header is not present (or contains something other
+// than numbers), the incoming content_length is -1 (unknown size).
+// Set the content length to 0 to indicate unknown size to DownloadManager.
+void DownloadResourceHandler::set_content_length(const int64& content_length) {
+  content_length_ = 0;
+  if (content_length > 0)
+    content_length_ = content_length;
+}
+
+void DownloadResourceHandler::set_content_disposition(
+    const std::string& content_disposition) {
+  content_disposition_ = content_disposition;
+}
+
+void DownloadResourceHandler::CheckWriteProgress() {
+  if (!buffer_)
+    return;  // The download completed while we were waiting to run.
+
+  size_t contents_size;
+  {
+    AutoLock lock(buffer_->lock);
+    contents_size = buffer_->contents.size();
+  }
+
+  bool should_pause = contents_size > kLoadsToWrite;
+
+  // We'll come back later and see if it's okay to unpause the request.
+  if (should_pause)
+    StartPauseTimer();
+
+  if (is_paused_ != should_pause) {
+    rdh_->PauseRequest(global_id_.render_process_host_id,
+                       global_id_.request_id,
+                       should_pause);
+    is_paused_ = should_pause;
+  }
+}
+
+void DownloadResourceHandler::StartPauseTimer() {
+  if (!pause_timer_.IsRunning())
+    pause_timer_.Start(base::TimeDelta::FromMilliseconds(kThrottleTimeMs), this,
+                       &DownloadResourceHandler::CheckWriteProgress);
+}
diff --git a/chrome/browser/renderer_host/download_resource_handler.h b/chrome/browser/renderer_host/download_resource_handler.h
new file mode 100644
index 0000000..52f6c947
--- /dev/null
+++ b/chrome/browser/renderer_host/download_resource_handler.h
@@ -0,0 +1,75 @@
+// Copyright (c) 2006-2008 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_RENDERER_HOST_DOWNLOAD_RESOURCE_HANDLER_H_
+#define CHROME_BROWSER_RENDERER_HOST_DOWNLOAD_RESOURCE_HANDLER_H_
+
+#include <string>
+
+#include "chrome/browser/renderer_host/resource_dispatcher_host.h"
+#include "chrome/browser/renderer_host/resource_handler.h"
+
+struct DownloadBuffer;
+
+// Forwards data to the download thread.
+class DownloadResourceHandler : public ResourceHandler {
+ public:
+  DownloadResourceHandler(ResourceDispatcherHost* rdh,
+                          int render_process_host_id,
+                          int render_view_id,
+                          int request_id,
+                          const std::string& url,
+                          DownloadFileManager* manager,
+                          URLRequest* request,
+                          bool save_as);
+
+  // Not needed, as this event handler ought to be the final resource.
+  bool OnRequestRedirected(int request_id, const GURL& url);
+
+  // Send the download creation information to the download thread.
+  bool OnResponseStarted(int request_id, ResourceResponse* response);
+
+  // Create a new buffer, which will be handed to the download thread for file
+  // writing and deletion.
+  bool OnWillRead(int request_id, char** buf, int* buf_size, int min_size);
+
+  bool OnReadCompleted(int request_id, int* bytes_read);
+
+  bool OnResponseCompleted(int request_id, const URLRequestStatus& status);
+
+  // If the content-length header is not present (or contains something other
+  // than numbers), the incoming content_length is -1 (unknown size).
+  // Set the content length to 0 to indicate unknown size to DownloadManager.
+  void set_content_length(const int64& content_length);
+
+  void set_content_disposition(const std::string& content_disposition);
+
+  void CheckWriteProgress();
+
+ private:
+  void StartPauseTimer();
+
+  int download_id_;
+  ResourceDispatcherHost::GlobalRequestID global_id_;
+  int render_view_id_;
+  char* read_buffer_;
+  std::string content_disposition_;
+  std::wstring url_;
+  int64 content_length_;
+  DownloadFileManager* download_manager_;
+  URLRequest* request_;
+  bool save_as_;  // Request was initiated via "Save As" by the user.
+  DownloadBuffer* buffer_;
+  ResourceDispatcherHost* rdh_;
+  bool is_paused_;
+  base::OneShotTimer<DownloadResourceHandler> pause_timer_;
+
+  static const int kReadBufSize = 32768;  // bytes
+  static const int kLoadsToWrite = 100;  // number of data buffers queued
+  static const int kThrottleTimeMs = 200;  // milliseconds
+
+  DISALLOW_COPY_AND_ASSIGN(DownloadResourceHandler);
+};
+
+#endif  // CHROME_BROWSER_RENDERER_HOST_DOWNLOAD_RESOURCE_HANDLER_H_
diff --git a/chrome/browser/renderer_host/download_throttling_resource_handler.cc b/chrome/browser/renderer_host/download_throttling_resource_handler.cc
new file mode 100644
index 0000000..07b81645
--- /dev/null
+++ b/chrome/browser/renderer_host/download_throttling_resource_handler.cc
@@ -0,0 +1,145 @@
+// Copyright (c) 2006-2008 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/renderer_host/download_throttling_resource_handler.h"
+
+#include "chrome/browser/renderer_host/download_resource_handler.h"
+
+DownloadThrottlingResourceHandler::DownloadThrottlingResourceHandler(
+    ResourceDispatcherHost* host,
+    URLRequest* request,
+    const std::string& url,
+    int render_process_host_id,
+    int render_view_id,
+    int request_id,
+    bool in_complete)
+    : host_(host),
+      request_(request),
+      url_(url),
+      render_process_host_id_(render_process_host_id),
+      render_view_id_(render_view_id),
+      request_id_(request_id),
+      tmp_buffer_length_(0),
+      ignore_on_read_complete_(in_complete) {
+  // Pause the request.
+  host_->PauseRequest(render_process_host_id_, request_id_, true);
+  host_->download_request_manager()->CanDownloadOnIOThread(
+      render_process_host_id_, render_view_id, this);
+ }
+
+DownloadThrottlingResourceHandler::~DownloadThrottlingResourceHandler() {
+}
+
+bool DownloadThrottlingResourceHandler::OnUploadProgress(int request_id,
+                                                         uint64 position,
+                                                         uint64 size) {
+  if (download_handler_.get())
+    return download_handler_->OnUploadProgress(request_id, position, size);
+  return true;
+}
+
+bool DownloadThrottlingResourceHandler::OnRequestRedirected(int request_id,
+                                                            const GURL& url) {
+  if (download_handler_.get())
+    return download_handler_->OnRequestRedirected(request_id, url);
+  url_ = url.spec();
+  return true;
+}
+
+bool DownloadThrottlingResourceHandler::OnResponseStarted(
+    int request_id,
+    ResourceResponse* response) {
+  if (download_handler_.get())
+    return download_handler_->OnResponseStarted(request_id, response);
+  response_ = response;
+  return true;
+}
+
+bool DownloadThrottlingResourceHandler::OnWillRead(int request_id,
+                                                   char** buf,
+                                                   int* buf_size,
+                                                   int min_size) {
+  if (download_handler_.get())
+    return download_handler_->OnWillRead(request_id, buf, buf_size, min_size);
+
+  // We should only have this invoked once, as such we only deal with one
+  // tmp buffer.
+  DCHECK(!tmp_buffer_.get());
+  if (min_size < 0)
+    min_size = 1024;
+  tmp_buffer_.reset(new char[min_size]);
+  *buf = tmp_buffer_.get();
+  *buf_size = min_size;
+  return true;
+}
+
+bool DownloadThrottlingResourceHandler::OnReadCompleted(int request_id,
+                                                        int* bytes_read) {
+  if (ignore_on_read_complete_) {
+    // See comments above definition for details on this.
+    ignore_on_read_complete_ = false;
+    return true;
+  }
+  if (!*bytes_read)
+    return true;
+
+  if (tmp_buffer_.get()) {
+    DCHECK(!tmp_buffer_length_);
+    tmp_buffer_length_ = *bytes_read;
+    if (download_handler_.get())
+      CopyTmpBufferToDownloadHandler();
+    return true;
+  }
+  if (download_handler_.get())
+    return download_handler_->OnReadCompleted(request_id, bytes_read);
+  return true;
+}
+
+bool DownloadThrottlingResourceHandler::OnResponseCompleted(
+    int request_id,
+    const URLRequestStatus& status) {
+  if (download_handler_.get())
+    return download_handler_->OnResponseCompleted(request_id, status);
+  NOTREACHED();
+  return true;
+}
+
+void DownloadThrottlingResourceHandler::CancelDownload() {
+  host_->CancelRequest(render_process_host_id_, request_id_, false);
+}
+
+void DownloadThrottlingResourceHandler::ContinueDownload() {
+  DCHECK(!download_handler_.get());
+  download_handler_ =
+      new DownloadResourceHandler(host_,
+                                  render_process_host_id_,
+                                  render_view_id_,
+                                  request_id_,
+                                  url_,
+                                  host_->download_file_manager(),
+                                  request_,
+                                  false);
+  if (response_.get())
+    download_handler_->OnResponseStarted(request_id_, response_.get());
+
+  if (tmp_buffer_length_)
+    CopyTmpBufferToDownloadHandler();
+
+  // And let the request continue.
+  host_->PauseRequest(render_process_host_id_, request_id_, false);
+}
+
+void DownloadThrottlingResourceHandler::CopyTmpBufferToDownloadHandler() {
+  // Copy over the tmp buffer.
+  char* buffer;
+  int buf_size;
+  if (download_handler_->OnWillRead(request_id_, &buffer, &buf_size,
+                                    tmp_buffer_length_)) {
+    CHECK(buf_size >= tmp_buffer_length_);
+    memcpy(buffer, tmp_buffer_.get(), tmp_buffer_length_);
+    download_handler_->OnReadCompleted(request_id_, &tmp_buffer_length_);
+  }
+  tmp_buffer_length_ = 0;
+  tmp_buffer_.reset();
+}
diff --git a/chrome/browser/renderer_host/download_throttling_resource_handler.h b/chrome/browser/renderer_host/download_throttling_resource_handler.h
new file mode 100644
index 0000000..177f4fd
--- /dev/null
+++ b/chrome/browser/renderer_host/download_throttling_resource_handler.h
@@ -0,0 +1,87 @@
+// Copyright (c) 2006-2008 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_RENDERER_HOST_DOWNLOAD_THROTTLING_RESOURCE_HANDLER_H_
+#define CHROME_BROWSER_RENDERER_HOST_DOWNLOAD_THROTTLING_RESOURCE_HANDLER_H_
+
+#include <string>
+
+#include "chrome/browser/renderer_host/resource_handler.h"
+#include "chrome/browser/download/download_request_manager.h"
+
+class DownloadResourceHandler;
+class ResourceDispatcherHost;
+
+// DownloadThrottlingResourceHandler is used to determine if a download should
+// be allowed. When a DownloadThrottlingResourceHandler is created it pauses the
+// download and asks the DownloadRequestManager if the download should be
+// allowed. The DownloadRequestManager notifies us asynchronously as to whether
+// the download is allowed or not. If the download is allowed the request is
+// resumed, a DownloadResourceHandler is created and all EventHandler methods
+// are delegated to it. If the download is not allowed the request is canceled.
+
+class DownloadThrottlingResourceHandler
+    : public ResourceHandler,
+      public DownloadRequestManager::Callback {
+ public:
+  DownloadThrottlingResourceHandler(ResourceDispatcherHost* host,
+                                    URLRequest* request,
+                                    const std::string& url,
+                                    int render_process_host_id,
+                                    int render_view_id,
+                                    int request_id,
+                                    bool in_complete);
+  virtual ~DownloadThrottlingResourceHandler();
+
+  // ResourceHanlder implementation:
+  virtual bool OnUploadProgress(int request_id,
+                                uint64 position,
+                                uint64 size);
+  virtual bool OnRequestRedirected(int request_id, const GURL& url);
+  virtual bool OnResponseStarted(int request_id, ResourceResponse* response);
+  virtual bool OnWillRead(int request_id,
+                          char** buf,
+                          int* buf_size,
+                          int min_size);
+  virtual bool OnReadCompleted(int request_id, int* bytes_read);
+  virtual bool OnResponseCompleted(int request_id,
+                                   const URLRequestStatus& status);
+
+  // DownloadRequestManager::Callback implementation:
+  void CancelDownload();
+  void ContinueDownload();
+
+ private:
+  void CopyTmpBufferToDownloadHandler();
+
+  ResourceDispatcherHost* host_;
+  URLRequest* request_;
+  std::string url_;
+  int render_process_host_id_;
+  int render_view_id_;
+  int request_id_;
+
+  // Handles the actual download. This is only created if the download is
+  // allowed to continue.
+  scoped_refptr<DownloadResourceHandler> download_handler_;
+
+  // Response supplied to OnResponseStarted. Only non-null if OnResponseStarted
+  // is invoked.
+  scoped_refptr<ResourceResponse> response_;
+
+  // If we're created by way of BufferedEventHandler we'll get one request for
+  // a buffer. This is that buffer.
+  scoped_array<char> tmp_buffer_;
+  int tmp_buffer_length_;
+
+  // If true the next call to OnReadCompleted is ignored. This is used if we're
+  // paused during a call to OnReadCompleted. Pausing during OnReadCompleted
+  // results in two calls to OnReadCompleted for the same data. This make sure
+  // we ignore one of them.
+  bool ignore_on_read_complete_;
+
+  DISALLOW_COPY_AND_ASSIGN(DownloadThrottlingResourceHandler);
+};
+
+#endif  // CHROME_BROWSER_RENDERER_HOST_DOWNLOAD_THROTTLING_RESOURCE_HANDLER_H_
diff --git a/chrome/browser/renderer_host/resource_dispatcher_host.cc b/chrome/browser/renderer_host/resource_dispatcher_host.cc
new file mode 100644
index 0000000..f746429
--- /dev/null
+++ b/chrome/browser/renderer_host/resource_dispatcher_host.cc
@@ -0,0 +1,1217 @@
+// Copyright (c) 2006-2008 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.
+
+// See http://dev.chromium.org/developers/design-documents/multi-process-resource-loading
+
+#include <vector>
+
+#include "chrome/browser/renderer_host/resource_dispatcher_host.h"
+
+#include "base/message_loop.h"
+#include "base/scoped_ptr.h"
+#include "base/time.h"
+#include "chrome/browser/cert_store.h"
+#include "chrome/browser/cross_site_request_manager.h"
+#include "chrome/browser/download/download_file.h"
+#include "chrome/browser/download/download_manager.h"
+#include "chrome/browser/download/download_request_manager.h"
+#include "chrome/browser/download/save_file_manager.h"
+#include "chrome/browser/external_protocol_handler.h"
+#include "chrome/browser/login_prompt.h"
+#include "chrome/browser/plugin_service.h"
+#include "chrome/browser/render_view_host.h"
+#include "chrome/browser/render_view_host_delegate.h"
+#include "chrome/browser/renderer_host/async_resource_handler.h"
+#include "chrome/browser/renderer_host/buffered_resource_handler.h"
+#include "chrome/browser/renderer_host/cross_site_resource_handler.h"
+#include "chrome/browser/renderer_host/download_resource_handler.h"
+#include "chrome/browser/renderer_host/safe_browsing_resource_handler.h"
+#include "chrome/browser/renderer_host/save_file_resource_handler.h"
+#include "chrome/browser/renderer_host/sync_resource_handler.h"
+#include "chrome/browser/renderer_security_policy.h"
+#include "chrome/browser/resource_request_details.h"
+#include "chrome/browser/safe_browsing/safe_browsing_service.h"
+#include "chrome/browser/tab_util.h"
+#include "chrome/browser/web_contents.h"
+#include "chrome/common/notification_source.h"
+#include "chrome/common/notification_types.h"
+#include "chrome/common/render_messages.h"
+#include "chrome/common/stl_util-inl.h"
+#include "net/base/auth.h"
+#include "net/base/cert_status_flags.h"
+#include "net/base/load_flags.h"
+#include "net/base/mime_util.h"
+#include "net/base/net_errors.h"
+#include "net/url_request/url_request.h"
+
+// Uncomment to enable logging of request traffic.
+//#define LOG_RESOURCE_DISPATCHER_REQUESTS
+
+#ifdef LOG_RESOURCE_DISPATCHER_REQUESTS
+# define RESOURCE_LOG(stuff) LOG(INFO) << stuff
+#else
+# define RESOURCE_LOG(stuff)
+#endif
+
+using base::Time;
+using base::TimeDelta;
+using base::TimeTicks;
+
+// ----------------------------------------------------------------------------
+
+// The interval for calls to ResourceDispatcherHost::UpdateLoadStates
+static const int kUpdateLoadStatesIntervalMsec = 100;
+
+// Maximum number of pending data messages sent to the renderer at any
+// given time for a given request.
+static const int kMaxPendingDataMessages = 20;
+
+// A ShutdownTask proxies a shutdown task from the UI thread to the IO thread.
+// It should be constructed on the UI thread and run in the IO thread.
+class ResourceDispatcherHost::ShutdownTask : public Task {
+ public:
+  explicit ShutdownTask(ResourceDispatcherHost* resource_dispatcher_host)
+      : rdh_(resource_dispatcher_host) { }
+
+  void Run() {
+    rdh_->OnShutdown();
+  }
+
+ private:
+  ResourceDispatcherHost* rdh_;
+};
+
+namespace {
+
+// Consults the RendererSecurity policy to determine whether the
+// ResourceDispatcherHost should service this request.  A request might be
+// disallowed if the renderer is not authorized to restrive the request URL or
+// if the renderer is attempting to upload an unauthorized file.
+bool ShouldServiceRequest(int render_process_host_id,
+                          const ViewHostMsg_Resource_Request& request_data)  {
+  // TODO(mpcomplete): remove this when http://b/viewIssue?id=1080959 is fixed.
+  if (render_process_host_id == -1)
+    return true;
+
+  RendererSecurityPolicy* policy = RendererSecurityPolicy::GetInstance();
+
+  // Check if the renderer is permitted to request the requested URL.
+  if (!policy->CanRequestURL(render_process_host_id, request_data.url)) {
+    LOG(INFO) << "Denied unauthorized request for " <<
+        request_data.url.possibly_invalid_spec();
+    return false;
+  }
+
+  // Check if the renderer is permitted to upload the requested files.
+  const std::vector<net::UploadData::Element>& uploads =
+      request_data.upload_content;
+  std::vector<net::UploadData::Element>::const_iterator iter;
+  for (iter = uploads.begin(); iter != uploads.end(); ++iter) {
+    if (iter->type() == net::UploadData::TYPE_FILE &&
+        !policy->CanUploadFile(render_process_host_id, iter->file_path())) {
+      NOTREACHED() << "Denied unauthorized upload of " << iter->file_path();
+      return false;
+    }
+  }
+
+  return true;
+}
+
+}  // namespace
+
+ResourceDispatcherHost::ResourceDispatcherHost(MessageLoop* io_loop)
+    : ui_loop_(MessageLoop::current()),
+      io_loop_(io_loop),
+      download_file_manager_(new DownloadFileManager(ui_loop_, this)),
+      download_request_manager_(new DownloadRequestManager(io_loop, ui_loop_)),
+      save_file_manager_(new SaveFileManager(ui_loop_, io_loop, this)),
+      safe_browsing_(new SafeBrowsingService),
+      request_id_(-1),
+      plugin_service_(PluginService::GetInstance()),
+      method_runner_(this),
+      is_shutdown_(false) {
+}
+
+ResourceDispatcherHost::~ResourceDispatcherHost() {
+  AsyncResourceHandler::GlobalCleanup();
+  STLDeleteValues(&pending_requests_);
+}
+
+void ResourceDispatcherHost::Initialize() {
+  DCHECK(MessageLoop::current() == ui_loop_);
+  download_file_manager_->Initialize();
+  safe_browsing_->Initialize(io_loop_);
+}
+
+void ResourceDispatcherHost::Shutdown() {
+  DCHECK(MessageLoop::current() == ui_loop_);
+  io_loop_->PostTask(FROM_HERE, new ShutdownTask(this));
+}
+
+void ResourceDispatcherHost::OnShutdown() {
+  DCHECK(MessageLoop::current() == io_loop_);
+  is_shutdown_ = true;
+  STLDeleteValues(&pending_requests_);
+  // Make sure we shutdown the timer now, otherwise by the time our destructor
+  // runs if the timer is still running the Task is deleted twice (once by
+  // the MessageLoop and the second time by RepeatingTimer).
+  update_load_states_timer_.Stop();
+}
+
+bool ResourceDispatcherHost::HandleExternalProtocol(int request_id,
+                                                    int render_process_host_id,
+                                                    int tab_contents_id,
+                                                    const GURL& url,
+                                                    ResourceType::Type type,
+                                                    ResourceHandler* handler) {
+  if (!ResourceType::IsFrame(type) || URLRequest::IsHandledURL(url))
+    return false;
+
+  ui_loop_->PostTask(FROM_HERE, NewRunnableFunction(
+      &ExternalProtocolHandler::LaunchUrl, url, render_process_host_id,
+      tab_contents_id));
+
+  handler->OnResponseCompleted(request_id, URLRequestStatus(
+                                               URLRequestStatus::FAILED,
+                                               net::ERR_ABORTED));
+  return true;
+}
+
+void ResourceDispatcherHost::BeginRequest(
+    Receiver* receiver,
+    HANDLE render_process_handle,
+    int render_process_host_id,
+    int render_view_id,
+    int request_id,
+    const ViewHostMsg_Resource_Request& request_data,
+    URLRequestContext* request_context,
+    IPC::Message* sync_result) {
+  if (is_shutdown_ ||
+      !ShouldServiceRequest(render_process_host_id, request_data)) {
+    // Tell the renderer that this request was disallowed.
+    receiver->Send(new ViewMsg_Resource_RequestComplete(
+        render_view_id,
+        request_id,
+        URLRequestStatus(URLRequestStatus::FAILED, net::ERR_ABORTED)));
+    return;
+  }
+
+  // Ensure the Chrome plugins are loaded, as they may intercept network
+  // requests.  Does nothing if they are already loaded.
+  // TODO(mpcomplete): This takes 200 ms!  Investigate parallelizing this by
+  // starting the load earlier in a BG thread.
+  plugin_service_->LoadChromePlugins(this);
+
+  // Construct the event handler.
+  scoped_refptr<ResourceHandler> handler;
+  if (sync_result) {
+    handler = new SyncResourceHandler(receiver, request_data.url, sync_result);
+  } else {
+    handler = new AsyncResourceHandler(receiver,
+                                       render_process_host_id,
+                                       render_view_id,
+                                       render_process_handle,
+                                       request_data.url,
+                                       this);
+  }
+
+  if (HandleExternalProtocol(request_id, render_process_host_id, render_view_id,
+                             request_data.url, request_data.resource_type,
+                             handler)) {
+    return;
+  }
+
+  // Construct the request.
+  URLRequest* request = new URLRequest(request_data.url, this);
+  request->set_method(request_data.method);
+  request->set_policy_url(request_data.policy_url);
+  request->set_referrer(request_data.referrer.spec());
+  request->SetExtraRequestHeaders(request_data.headers);
+  request->set_load_flags(request_data.load_flags);
+  request->set_context(request_context);
+  request->set_origin_pid(request_data.origin_pid);
+
+  // Set upload data.
+  uint64 upload_size = 0;
+  if (!request_data.upload_content.empty()) {
+    scoped_refptr<net::UploadData> upload = new net::UploadData();
+    upload->set_elements(request_data.upload_content);  // Deep copy.
+    request->set_upload(upload);
+    upload_size = upload->GetContentLength();
+  }
+
+  // Install a CrossSiteResourceHandler if this request is coming from a
+  // RenderViewHost with a pending cross-site request.  We only check this for
+  // MAIN_FRAME requests.
+  // TODO(mpcomplete): remove "render_process_host_id != -1"
+  //                   when http://b/viewIssue?id=1080959 is fixed.
+  if (request_data.resource_type == ResourceType::MAIN_FRAME &&
+      render_process_host_id != -1 &&
+      Singleton<CrossSiteRequestManager>::get()->
+          HasPendingCrossSiteRequest(render_process_host_id, render_view_id)) {
+    // Wrap the event handler to be sure the current page's onunload handler
+    // has a chance to run before we render the new page.
+    handler = new CrossSiteResourceHandler(handler,
+                                           render_process_host_id,
+                                           render_view_id,
+                                           this);
+  }
+
+  if (safe_browsing_->enabled() &&
+      safe_browsing_->CanCheckUrl(request_data.url)) {
+    handler = new SafeBrowsingResourceHandler(handler,
+                                              render_process_host_id,
+                                              render_view_id,
+                                              request_data.url,
+                                              request_data.resource_type,
+                                              safe_browsing_,
+                                              this);
+  }
+
+  // Insert a buffered event handler before the actual one.
+  handler = new BufferedResourceHandler(handler, this, request);
+
+  // Make extra info and read footer (contains request ID).
+  ExtraRequestInfo* extra_info =
+      new ExtraRequestInfo(handler,
+                           request_id,
+                           render_process_host_id,
+                           render_view_id,
+                           request_data.mixed_content,
+                           request_data.resource_type,
+                           upload_size);
+  extra_info->allow_download =
+      ResourceType::IsFrame(request_data.resource_type);
+  request->set_user_data(extra_info);  // takes pointer ownership
+
+  BeginRequestInternal(request, request_data.mixed_content);
+}
+
+// We are explicitly forcing the download of 'url'.
+void ResourceDispatcherHost::BeginDownload(const GURL& url,
+                                           const GURL& referrer,
+                                           int render_process_host_id,
+                                           int render_view_id,
+                                           URLRequestContext* request_context) {
+  if (is_shutdown_)
+    return;
+
+  // Check if the renderer is permitted to request the requested URL.
+  //
+  // TODO(mpcomplete): remove "render_process_host_id != -1"
+  //                   when http://b/viewIssue?id=1080959 is fixed.
+  if (render_process_host_id != -1 &&
+      !RendererSecurityPolicy::GetInstance()->
+          CanRequestURL(render_process_host_id, url)) {
+    LOG(INFO) << "Denied unauthorized download request for " <<
+        url.possibly_invalid_spec();
+    return;
+  }
+
+  // Ensure the Chrome plugins are loaded, as they may intercept network
+  // requests.  Does nothing if they are already loaded.
+  plugin_service_->LoadChromePlugins(this);
+  URLRequest* request = new URLRequest(url, this);
+
+  request_id_--;
+
+  scoped_refptr<ResourceHandler> handler =
+      new DownloadResourceHandler(this,
+                                  render_process_host_id,
+                                  render_view_id,
+                                  request_id_,
+                                  url.spec(),
+                                  download_file_manager_.get(),
+                                  request,
+                                  true);
+
+
+  if (safe_browsing_->enabled() && safe_browsing_->CanCheckUrl(url)) {
+    handler = new SafeBrowsingResourceHandler(handler,
+                                              render_process_host_id,
+                                              render_view_id,
+                                              url,
+                                              ResourceType::MAIN_FRAME,
+                                              safe_browsing_,
+                                              this);
+  }
+
+  bool known_proto = URLRequest::IsHandledURL(url);
+  if (!known_proto) {
+    CHECK(false);
+  }
+
+  request->set_method("GET");
+  request->set_referrer(referrer.spec());
+  request->set_context(request_context);
+
+  ExtraRequestInfo* extra_info =
+      new ExtraRequestInfo(handler,
+                           request_id_,
+                           render_process_host_id,
+                           render_view_id,
+                           false,  // Downloads are not considered mixed-content
+                           ResourceType::SUB_RESOURCE,
+                           0 /* upload_size */ );
+  extra_info->allow_download = true;
+  extra_info->is_download = true;
+  request->set_user_data(extra_info);  // Takes pointer ownership.
+
+  BeginRequestInternal(request, false);
+}
+
+// This function is only used for saving feature.
+void ResourceDispatcherHost::BeginSaveFile(const GURL& url,
+                                           const GURL& referrer,
+                                           int render_process_host_id,
+                                           int render_view_id,
+                                           URLRequestContext* request_context) {
+  if (is_shutdown_)
+    return;
+
+  // Ensure the Chrome plugins are loaded, as they may intercept network
+  // requests.  Does nothing if they are already loaded.
+  plugin_service_->LoadChromePlugins(this);
+
+  scoped_refptr<ResourceHandler> handler =
+      new SaveFileResourceHandler(render_process_host_id,
+                                  render_view_id,
+                                  url.spec(),
+                                  save_file_manager_.get());
+  request_id_--;
+
+  bool known_proto = URLRequest::IsHandledURL(url);
+  if (!known_proto) {
+    // Since any URLs which have non-standard scheme have been filtered
+    // by save manager(see GURL::SchemeIsStandard). This situation
+    // should not happen.
+    NOTREACHED();
+    return;
+  }
+
+  URLRequest* request = new URLRequest(url, this);
+  request->set_method("GET");
+  request->set_referrer(referrer.spec());
+  // So far, for saving page, we need fetch content from cache, in the
+  // future, maybe we can use a configuration to configure this behavior.
+  request->set_load_flags(net::LOAD_ONLY_FROM_CACHE);
+  request->set_context(request_context);
+
+  ExtraRequestInfo* extra_info =
+      new ExtraRequestInfo(handler,
+                           request_id_,
+                           render_process_host_id,
+                           render_view_id,
+                           false,
+                           ResourceType::SUB_RESOURCE,
+                           0 /* upload_size */);
+  // Just saving some resources we need, disallow downloading.
+  extra_info->allow_download = false;
+  extra_info->is_download = false;
+  request->set_user_data(extra_info);  // Takes pointer ownership.
+
+  BeginRequestInternal(request, false);
+}
+
+void ResourceDispatcherHost::CancelRequest(int render_process_host_id,
+                                           int request_id,
+                                           bool from_renderer) {
+  CancelRequest(render_process_host_id, request_id, from_renderer, true);
+}
+
+void ResourceDispatcherHost::CancelRequest(int render_process_host_id,
+                                           int request_id,
+                                           bool from_renderer,
+                                           bool allow_delete) {
+  PendingRequestList::iterator i = pending_requests_.find(
+      GlobalRequestID(render_process_host_id, request_id));
+  if (i == pending_requests_.end()) {
+    // We probably want to remove this warning eventually, but I wanted to be
+    // able to notice when this happens during initial development since it
+    // should be rare and may indicate a bug.
+    DLOG(WARNING) << "Canceling a request that wasn't found";
+    return;
+  }
+
+  // WebKit will send us a cancel for downloads since it no longer handles them.
+  // In this case, ignore the cancel since we handle downloads in the browser.
+  ExtraRequestInfo* info = ExtraInfoForRequest(i->second);
+  if (!from_renderer || !info->is_download) {
+    if (info->login_handler) {
+      info->login_handler->OnRequestCancelled();
+      info->login_handler = NULL;
+    }
+    if (!i->second->is_pending() && allow_delete) {
+      // No io is pending, canceling the request won't notify us of anything,
+      // so we explicitly remove it.
+      // TODO: removing the request in this manner means we're not notifying
+      // anyone. We need make sure the event handlers and others are notified
+      // so that everything is cleaned up properly.
+      RemovePendingRequest(info->render_process_host_id, info->request_id);
+    } else {
+      i->second->Cancel();
+    }
+  }
+
+  // Do not remove from the pending requests, as the request will still
+  // call AllDataReceived, and may even have more data before it does
+  // that.
+}
+
+void ResourceDispatcherHost::OnDataReceivedACK(int render_process_host_id,
+                                               int request_id) {
+  PendingRequestList::iterator i = pending_requests_.find(
+      GlobalRequestID(render_process_host_id, request_id));
+  if (i == pending_requests_.end())
+    return;
+
+  ExtraRequestInfo* info = ExtraInfoForRequest(i->second);
+
+  // Decrement the number of pending data messages.
+  info->pending_data_count--;
+
+  // If the pending data count was higher than the max, resume the request.
+  if (info->pending_data_count == kMaxPendingDataMessages) {
+    // Decrement the pending data count one more time because we also
+    // incremented it before pausing the request.
+    info->pending_data_count--;
+
+    // Resume the request.
+    PauseRequest(render_process_host_id, request_id, false);
+  }
+}
+
+void ResourceDispatcherHost::OnUploadProgressACK(int render_process_host_id,
+                                                 int request_id) {
+  PendingRequestList::iterator i = pending_requests_.find(
+      GlobalRequestID(render_process_host_id, request_id));
+  if (i == pending_requests_.end())
+    return;
+
+  ExtraRequestInfo* info = ExtraInfoForRequest(i->second);
+  info->waiting_for_upload_progress_ack = false;
+}
+
+bool ResourceDispatcherHost::WillSendData(int render_process_host_id,
+                                          int request_id) {
+  PendingRequestList::iterator i = pending_requests_.find(
+      GlobalRequestID(render_process_host_id, request_id));
+  if (i == pending_requests_.end()) {
+    NOTREACHED() << L"WillSendData for invalid request";
+    return false;
+  }
+
+  ExtraRequestInfo* info = ExtraInfoForRequest(i->second);
+
+  info->pending_data_count++;
+  if (info->pending_data_count > kMaxPendingDataMessages) {
+    // We reached the max number of data messages that can be sent to
+    // the renderer for a given request. Pause the request and wait for
+    // the renderer to start processing them before resuming it.
+    PauseRequest(render_process_host_id, request_id, true);
+    return false;
+  }
+
+  return true;
+}
+
+void ResourceDispatcherHost::PauseRequest(int render_process_host_id,
+                                          int request_id,
+                                          bool pause) {
+  GlobalRequestID global_id(render_process_host_id, request_id);
+  PendingRequestList::iterator i = pending_requests_.find(global_id);
+  if (i == pending_requests_.end()) {
+    DLOG(WARNING) << "Pausing a request that wasn't found";
+    return;
+  }
+
+  ExtraRequestInfo* info = ExtraInfoForRequest(i->second);
+
+  int pause_count = info->pause_count + (pause ? 1 : -1);
+  if (pause_count < 0) {
+    NOTREACHED();  // Unbalanced call to pause.
+    return;
+  }
+  info->pause_count = pause_count;
+
+  RESOURCE_LOG("To pause (" << pause << "): " << i->second->url().spec());
+
+  // If we're resuming, kick the request to start reading again. Run the read
+  // asynchronously to avoid recursion problems.
+  if (info->pause_count == 0) {
+    MessageLoop::current()->PostTask(FROM_HERE,
+        method_runner_.NewRunnableMethod(
+            &ResourceDispatcherHost::ResumeRequest, global_id));
+  }
+}
+
+void ResourceDispatcherHost::OnClosePageACK(int render_process_host_id,
+                                            int request_id) {
+  GlobalRequestID global_id(render_process_host_id, request_id);
+  PendingRequestList::iterator i = pending_requests_.find(global_id);
+  if (i == pending_requests_.end()) {
+    // If there are no matching pending requests, then this is not a
+    // cross-site navigation and we are just closing the tab/browser.
+    ui_loop_->PostTask(FROM_HERE, NewRunnableFunction(
+        &RenderViewHost::ClosePageIgnoringUnloadEvents,
+        render_process_host_id,
+        request_id));
+    return;
+  }
+
+  ExtraRequestInfo* info = ExtraInfoForRequest(i->second);
+  if (info->cross_site_handler) {
+    info->cross_site_handler->ResumeResponse();
+  }
+}
+
+// The object died, so cancel and detach all requests associated with it except
+// for downloads, which belong to the browser process even if initiated via a
+// renderer.
+void ResourceDispatcherHost::CancelRequestsForProcess(
+    int render_process_host_id) {
+  CancelRequestsForRenderView(render_process_host_id, -1 /* cancel all */);
+}
+
+void ResourceDispatcherHost::CancelRequestsForRenderView(
+    int render_process_host_id,
+    int render_view_id) {
+  // Since pending_requests_ is a map, we first build up a list of all of the
+  // matching requests to be cancelled, and then we cancel them.  Since there
+  // may be more than one request to cancel, we cannot simply hold onto the map
+  // iterators found in the first loop.
+
+  // Find the global ID of all matching elements.
+  std::vector<GlobalRequestID> matching_requests;
+  for (PendingRequestList::const_iterator i = pending_requests_.begin();
+       i != pending_requests_.end(); ++i) {
+    if (i->first.render_process_host_id == render_process_host_id) {
+      ExtraRequestInfo* info = ExtraInfoForRequest(i->second);
+      if (!info->is_download && (render_view_id == -1 ||
+                                 render_view_id == info->render_view_id)) {
+        matching_requests.push_back(
+            GlobalRequestID(render_process_host_id, i->first.request_id));
+      }
+    }
+  }
+
+  // Remove matches.
+  for (size_t i = 0; i < matching_requests.size(); ++i) {
+    PendingRequestList::iterator iter =
+        pending_requests_.find(matching_requests[i]);
+    // Although every matching request was in pending_requests_ when we built
+    // matching_requests, it is normal for a matching request to be not found
+    // in pending_requests_ after we have removed some matching requests from
+    // pending_requests_.  For example, deleting a URLRequest that has
+    // exclusive (write) access to an HTTP cache entry may unblock another
+    // URLRequest that needs exclusive access to the same cache entry, and
+    // that URLRequest may complete and remove itself from pending_requests_.
+    // So we need to check that iter is not equal to pending_requests_.end().
+    if (iter != pending_requests_.end())
+      RemovePendingRequest(iter);
+  }
+}
+
+// Cancels the request and removes it from the list.
+void ResourceDispatcherHost::RemovePendingRequest(int render_process_host_id,
+                                                  int request_id) {
+  PendingRequestList::iterator i = pending_requests_.find(
+      GlobalRequestID(render_process_host_id, request_id));
+  if (i == pending_requests_.end()) {
+    NOTREACHED() << "Trying to remove a request that's not here";
+    return;
+  }
+  RemovePendingRequest(i);
+}
+
+void ResourceDispatcherHost::RemovePendingRequest(
+    const PendingRequestList::iterator& iter) {
+  // Notify the login handler that this request object is going away.
+  ExtraRequestInfo* info = ExtraInfoForRequest(iter->second);
+  if (info && info->login_handler)
+    info->login_handler->OnRequestCancelled();
+
+  delete iter->second;
+  pending_requests_.erase(iter);
+
+  // If we have no more pending requests, then stop the load state monitor
+  if (pending_requests_.empty())
+    update_load_states_timer_.Stop();
+}
+
+// URLRequest::Delegate -------------------------------------------------------
+
+void ResourceDispatcherHost::OnReceivedRedirect(URLRequest* request,
+                                                const GURL& new_url) {
+  RESOURCE_LOG("OnReceivedRedirect: " << request->url().spec());
+  ExtraRequestInfo* info = ExtraInfoForRequest(request);
+
+  DCHECK(request->status().is_success());
+
+  // TODO(mpcomplete): remove this when http://b/viewIssue?id=1080959 is fixed.
+  if (info->render_process_host_id != -1 &&
+      !RendererSecurityPolicy::GetInstance()->
+          CanRequestURL(info->render_process_host_id, new_url)) {
+    LOG(INFO) << "Denied unauthorized request for " <<
+        new_url.possibly_invalid_spec();
+
+    // Tell the renderer that this request was disallowed.
+    CancelRequest(info->render_process_host_id, info->request_id, false);
+    return;
+  }
+
+  NofityReceivedRedirect(request, info->render_process_host_id, new_url);
+
+  if (HandleExternalProtocol(info->request_id, info->render_process_host_id,
+                             info->render_view_id, new_url,
+                             info->resource_type, info->resource_handler)) {
+    // The request is complete so we can remove it.
+    RemovePendingRequest(info->render_process_host_id, info->request_id);
+    return;
+  }
+
+  if (!info->resource_handler->OnRequestRedirected(info->request_id, new_url))
+    CancelRequest(info->render_process_host_id, info->request_id, false);
+}
+
+void ResourceDispatcherHost::OnAuthRequired(
+    URLRequest* request,
+    net::AuthChallengeInfo* auth_info) {
+  // Create a login dialog on the UI thread to get authentication data,
+  // or pull from cache and continue on the IO thread.
+  // TODO(mpcomplete): We should block the parent tab while waiting for
+  // authentication.
+  // That would also solve the problem of the URLRequest being cancelled
+  // before we receive authentication.
+  ExtraRequestInfo* info = ExtraInfoForRequest(request);
+  DCHECK(!info->login_handler) <<
+      "OnAuthRequired called with login_handler pending";
+  info->login_handler = CreateLoginPrompt(auth_info, request, ui_loop_);
+}
+
+void ResourceDispatcherHost::OnSSLCertificateError(
+    URLRequest* request,
+    int cert_error,
+    net::X509Certificate* cert) {
+  DCHECK(request);
+  SSLManager::OnSSLCertificateError(this, request, cert_error, cert, ui_loop_);
+}
+
+void ResourceDispatcherHost::OnResponseStarted(URLRequest* request) {
+  RESOURCE_LOG("OnResponseStarted: " << request->url().spec());
+  ExtraRequestInfo* info = ExtraInfoForRequest(request);
+  if (PauseRequestIfNeeded(info)) {
+    RESOURCE_LOG("OnResponseStarted pausing: " << request->url().spec());
+    return;
+  }
+
+  if (request->status().is_success()) {
+    // We want to send a final upload progress message prior to sending
+    // the response complete message even if we're waiting for an ack to
+    // to a previous upload progress message.
+    info->waiting_for_upload_progress_ack = false;
+    MaybeUpdateUploadProgress(info, request);
+
+    if (!CompleteResponseStarted(request)) {
+      CancelRequest(info->render_process_host_id, info->request_id, false);
+    } else {
+      // Start reading.
+      int bytes_read = 0;
+      if (Read(request, &bytes_read)) {
+        OnReadCompleted(request, bytes_read);
+      } else if (!request->status().is_io_pending()) {
+        DCHECK(!info->is_paused);
+        // If the error is not an IO pending, then we're done reading.
+        OnResponseCompleted(request);
+      }
+    }
+  } else {
+    OnResponseCompleted(request);
+  }
+}
+
+bool ResourceDispatcherHost::CompleteResponseStarted(URLRequest* request) {
+  ExtraRequestInfo* info = ExtraInfoForRequest(request);
+
+  scoped_refptr<ResourceResponse> response(new ResourceResponse);
+
+  response->response_head.status = request->status();
+  response->response_head.request_time = request->request_time();
+  response->response_head.response_time = request->response_time();
+  response->response_head.headers = request->response_headers();
+  request->GetCharset(&response->response_head.charset);
+  response->response_head.filter_policy = info->filter_policy;
+  response->response_head.content_length = request->GetExpectedContentSize();
+  request->GetMimeType(&response->response_head.mime_type);
+
+  if (request->ssl_info().cert) {
+    int cert_id =
+        CertStore::GetSharedInstance()->StoreCert(
+            request->ssl_info().cert,
+            info->render_process_host_id);
+    int cert_status = request->ssl_info().cert_status;
+    // EV certificate verification could be expensive.  We don't want to spend
+    // time performing EV certificate verification on all resources because
+    // EV status is irrelevant to sub-frames and sub-resources.  So we call
+    // IsEV here rather than in the network layer because the network layer
+    // doesn't know the resource type.
+    if (info->resource_type == ResourceType::MAIN_FRAME &&
+        request->ssl_info().cert->IsEV(cert_status))
+      cert_status |= net::CERT_STATUS_IS_EV;
+
+    response->response_head.security_info =
+        SSLManager::SerializeSecurityInfo(cert_id,
+                                          cert_status,
+                                          request->ssl_info().security_bits);
+  } else {
+    // We should not have any SSL state.
+    DCHECK(!request->ssl_info().cert_status &&
+           (request->ssl_info().security_bits == -1 ||
+           request->ssl_info().security_bits == 0));
+  }
+
+  NotifyResponseStarted(request, info->render_process_host_id);
+  return info->resource_handler->OnResponseStarted(info->request_id,
+                                                   response.get());
+}
+
+void ResourceDispatcherHost::BeginRequestInternal(URLRequest* request,
+                                                  bool mixed_content) {
+  ExtraRequestInfo* info = ExtraInfoForRequest(request);
+  GlobalRequestID global_id(info->render_process_host_id, info->request_id);
+  pending_requests_[global_id] = request;
+  if (mixed_content) {
+    // We don't start the request in that case.  The SSLManager will potentially
+    // change the request (potentially to indicate its content should be
+    // filtered) and start it itself.
+    SSLManager::OnMixedContentRequest(this, request, ui_loop_);
+    return;
+  }
+  request->Start();
+
+  // Make sure we have the load state monitor running
+  if (!update_load_states_timer_.IsRunning()) {
+    update_load_states_timer_.Start(
+        TimeDelta::FromMilliseconds(kUpdateLoadStatesIntervalMsec),
+        this, &ResourceDispatcherHost::UpdateLoadStates);
+  }
+}
+
+// This test mirrors the decision that WebKit makes in
+// WebFrameLoaderClient::dispatchDecidePolicyForMIMEType.
+// static.
+bool ResourceDispatcherHost::ShouldDownload(
+    const std::string& mime_type, const std::string& content_disposition) {
+  std::string type = StringToLowerASCII(mime_type);
+  std::string disposition = StringToLowerASCII(content_disposition);
+
+  // First, examine content-disposition.
+  if (!disposition.empty()) {
+    bool should_download = true;
+
+    // Some broken sites just send ...
+    //    Content-Disposition: ; filename="file"
+    // ... screen those out here.
+    if (disposition[0] == ';')
+      should_download = false;
+
+    if (disposition.compare(0, 6, "inline") == 0)
+      should_download = false;
+
+    // Some broken sites just send ...
+    //    Content-Disposition: filename="file"
+    // ... without a disposition token... Screen those out.
+    if (disposition.compare(0, 8, "filename") == 0)
+      should_download = false;
+
+    // Also in use is Content-Disposition: name="file"
+    if (disposition.compare(0, 4, "name") == 0)
+      should_download = false;
+
+    // We have a content-disposition of "attachment" or unknown.
+    // RFC 2183, section 2.8 says that an unknown disposition
+    // value should be treated as "attachment".
+    if (should_download)
+      return true;
+  }
+
+  // MIME type checking.
+  if (net::IsSupportedMimeType(type))
+    return false;
+
+  // Finally, check the plugin service.
+  bool allow_wildcard = false;
+  return !plugin_service_->HavePluginFor(type, allow_wildcard);
+}
+
+bool ResourceDispatcherHost::PauseRequestIfNeeded(ExtraRequestInfo* info) {
+  if (info->pause_count > 0)
+    info->is_paused = true;
+
+  return info->is_paused;
+}
+
+void ResourceDispatcherHost::ResumeRequest(const GlobalRequestID& request_id) {
+  PendingRequestList::iterator i = pending_requests_.find(request_id);
+  if (i == pending_requests_.end())  // The request may have been destroyed
+    return;
+
+  URLRequest* request = i->second;
+  ExtraRequestInfo* info = ExtraInfoForRequest(request);
+  if (!info->is_paused)
+    return;
+
+  RESOURCE_LOG("Resuming: " << i->second->url().spec());
+
+  info->is_paused = false;
+
+  if (info->has_started_reading)
+    OnReadCompleted(i->second, info->paused_read_bytes);
+  else
+    OnResponseStarted(i->second);
+}
+
+bool ResourceDispatcherHost::Read(URLRequest* request, int* bytes_read) {
+  ExtraRequestInfo* info = ExtraInfoForRequest(request);
+  DCHECK(!info->is_paused);
+
+  char* buf;
+  int buf_size;
+  if (!info->resource_handler->OnWillRead(info->request_id,
+                                          &buf, &buf_size, -1)) {
+    return false;
+  }
+
+  DCHECK(buf);
+  DCHECK(buf_size > 0);
+
+  info->has_started_reading = true;
+  return request->Read(buf, buf_size, bytes_read);
+}
+
+void ResourceDispatcherHost::OnReadCompleted(URLRequest* request,
+                                             int bytes_read) {
+  DCHECK(request);
+  RESOURCE_LOG("OnReadCompleted: " << request->url().spec());
+  ExtraRequestInfo* info = ExtraInfoForRequest(request);
+  if (PauseRequestIfNeeded(info)) {
+    info->paused_read_bytes = bytes_read;
+    RESOURCE_LOG("OnReadCompleted pausing: " << request->url().spec());
+    return;
+  }
+
+  if (request->status().is_success() && CompleteRead(request, &bytes_read)) {
+    // The request can be paused if we realize that the renderer is not
+    // servicing messages fast enough.
+    if (info->pause_count == 0 &&
+        Read(request, &bytes_read) &&
+        request->status().is_success()) {
+      if (bytes_read == 0) {
+        CompleteRead(request, &bytes_read);
+      } else {
+        // Force the next CompleteRead / Read pair to run as a separate task.
+        // This avoids a fast, large network request from monopolizing the IO
+        // thread and starving other IO operations from running.
+        info->paused_read_bytes = bytes_read;
+        info->is_paused = true;
+        GlobalRequestID id(info->render_process_host_id, info->request_id);
+        MessageLoop::current()->PostTask(
+            FROM_HERE,
+            method_runner_.NewRunnableMethod(
+                &ResourceDispatcherHost::ResumeRequest, id));
+        return;
+      }
+    }
+  }
+
+  if (PauseRequestIfNeeded(info)) {
+    info->paused_read_bytes = bytes_read;
+    RESOURCE_LOG("OnReadCompleted (CompleteRead) pausing: " <<
+                 request->url().spec());
+    return;
+  }
+
+  // If the status is not IO pending then we've either finished (success) or we
+  // had an error.  Either way, we're done!
+  if (!request->status().is_io_pending())
+    OnResponseCompleted(request);
+}
+
+bool ResourceDispatcherHost::CompleteRead(URLRequest* request,
+                                          int* bytes_read) {
+  if (!request->status().is_success()) {
+    NOTREACHED();
+    return false;
+  }
+
+  ExtraRequestInfo* info = ExtraInfoForRequest(request);
+
+  if (!info->resource_handler->OnReadCompleted(info->request_id, bytes_read)) {
+    // Pass in false as the last arg to indicate we don't want |request|
+    // deleted. We do this as callers of us assume |request| is valid after we
+    // return.
+    CancelRequest(info->render_process_host_id, info->request_id, false, false);
+    return false;
+  }
+
+  return *bytes_read != 0;
+}
+
+void ResourceDispatcherHost::OnResponseCompleted(URLRequest* request) {
+  RESOURCE_LOG("OnResponseCompleted: " << request->url().spec());
+  ExtraRequestInfo* info = ExtraInfoForRequest(request);
+
+  if (info->resource_handler->OnResponseCompleted(info->request_id,
+                                                  request->status())) {
+    NotifyResponseCompleted(request, info->render_process_host_id);
+
+    // The request is complete so we can remove it.
+    RemovePendingRequest(info->render_process_host_id, info->request_id);
+  }
+  // If the handler's OnResponseCompleted returns false, we are deferring the
+  // call until later.  We will notify the world and clean up when we resume.
+}
+
+void ResourceDispatcherHost::AddObserver(Observer* obs) {
+  observer_list_.AddObserver(obs);
+}
+
+void ResourceDispatcherHost::RemoveObserver(Observer* obs) {
+  observer_list_.RemoveObserver(obs);
+}
+
+URLRequest* ResourceDispatcherHost::GetURLRequest(
+    GlobalRequestID request_id) const {
+  // This should be running in the IO loop. io_loop_ can be NULL during the
+  // unit_tests.
+  DCHECK(MessageLoop::current() == io_loop_ && io_loop_);
+
+  PendingRequestList::const_iterator i = pending_requests_.find(request_id);
+  if (i == pending_requests_.end())
+    return NULL;
+
+  return i->second;
+}
+
+// A NotificationTask proxies a resource dispatcher notification from the IO
+// thread to the UI thread.  It should be constructed on the IO thread and run
+// in the UI thread.  Takes ownership of |details|.
+class NotificationTask : public Task {
+ public:
+  NotificationTask(NotificationType type,
+                   URLRequest* request,
+                   ResourceRequestDetails* details)
+  : type_(type),
+    details_(details) {
+    if (!tab_util::GetTabContentsID(request,
+                                    &render_process_host_id_,
+                                    &tab_contents_id_))
+      NOTREACHED();
+  }
+
+  void Run() {
+    // Find the tab associated with this request.
+    TabContents* tab_contents =
+        tab_util::GetWebContentsByID(render_process_host_id_, tab_contents_id_);
+
+    if (tab_contents) {
+      // Issue the notification.
+      NotificationService::current()->
+          Notify(type_,
+                 Source<NavigationController>(tab_contents->controller()),
+                 Details<ResourceRequestDetails>(details_.get()));
+    }
+  }
+
+ private:
+  // These IDs let us find the correct tab on the UI thread.
+  int render_process_host_id_;
+  int tab_contents_id_;
+
+  // The type and details of the notification.
+  NotificationType type_;
+  scoped_ptr<ResourceRequestDetails> details_;
+};
+
+static int GetCertID(URLRequest* request, int render_process_host_id) {
+  if (request->ssl_info().cert) {
+    return CertStore::GetSharedInstance()->StoreCert(request->ssl_info().cert,
+                                                     render_process_host_id);
+  }
+  // If there is no SSL info attached to this request, we must either be a non
+  // secure request, or the request has been canceled or failed (before the SSL
+  // info was populated), or the response is an error (we have seen 403, 404,
+  // and 501) made up by the proxy.
+  DCHECK(!request->url().SchemeIsSecure() ||
+         (request->status().status() == URLRequestStatus::CANCELED) ||
+         (request->status().status() == URLRequestStatus::FAILED) ||
+         ((request->response_headers()->response_code() >= 400) &&
+         (request->response_headers()->response_code() <= 599)));
+  return 0;
+}
+
+void ResourceDispatcherHost::NotifyResponseStarted(URLRequest* request,
+                                                   int render_process_host_id) {
+  // Notify the observers on the IO thread.
+  FOR_EACH_OBSERVER(Observer, observer_list_, OnRequestStarted(this, request));
+
+  // Notify the observers on the UI thread.
+  ui_loop_->PostTask(FROM_HERE,
+      new NotificationTask(NOTIFY_RESOURCE_RESPONSE_STARTED, request,
+                           new ResourceRequestDetails(request,
+                               GetCertID(request, render_process_host_id))));
+}
+
+void ResourceDispatcherHost::NotifyResponseCompleted(
+    URLRequest* request,
+    int render_process_host_id) {
+  // Notify the observers on the IO thread.
+  FOR_EACH_OBSERVER(Observer, observer_list_,
+                    OnResponseCompleted(this, request));
+
+  // Notify the observers on the UI thread.
+  ui_loop_->PostTask(FROM_HERE,
+      new NotificationTask(NOTIFY_RESOURCE_RESPONSE_COMPLETED, request,
+                           new ResourceRequestDetails(request,
+                               GetCertID(request, render_process_host_id))));
+}
+
+void ResourceDispatcherHost::NofityReceivedRedirect(URLRequest* request,
+                                                    int render_process_host_id,
+                                                    const GURL& new_url) {
+  // Notify the observers on the IO thread.
+  FOR_EACH_OBSERVER(Observer, observer_list_,
+                    OnReceivedRedirect(this, request, new_url));
+
+  int cert_id = GetCertID(request, render_process_host_id);
+
+  // Notify the observers on the UI thread.
+  ui_loop_->PostTask(FROM_HERE,
+      new NotificationTask(NOTIFY_RESOURCE_RECEIVED_REDIRECT, request,
+                           new ResourceRedirectDetails(request,
+                                                       cert_id,
+                                                       new_url)));
+}
+
+namespace {
+
+// This function attempts to return the "more interesting" load state of |a|
+// and |b|.  We don't have temporal information about these load states
+// (meaning we don't know when we transitioned into these states), so we just
+// rank them according to how "interesting" the states are.
+//
+// We take advantage of the fact that the load states are an enumeration listed
+// in the order in which they occur during the lifetime of a request, so we can
+// regard states with larger numeric values as being further along toward
+// completion.  We regard those states as more interesting to report since they
+// represent progress.
+//
+// For example, by this measure "tranferring data" is a more interesting state
+// than "resolving host" because when we are transferring data we are actually
+// doing something that corresponds to changes that the user might observe,
+// whereas waiting for a host name to resolve implies being stuck.
+//
+net::LoadState MoreInterestingLoadState(net::LoadState a, net::LoadState b) {
+  return (a < b) ? b : a;
+}
+
+// Carries information about a load state change.
+struct LoadInfo {
+  GURL url;
+  net::LoadState load_state;
+};
+
+// Map from ProcessID+ViewID pair to LoadState
+typedef std::map<std::pair<int, int>, LoadInfo> LoadInfoMap;
+
+// Used to marshall calls to LoadStateChanged from the IO to UI threads.  We do
+// them all as a single task to avoid spamming the UI thread.
+class LoadInfoUpdateTask : public Task {
+ public:
+  virtual void Run() {
+    LoadInfoMap::const_iterator i;
+    for (i = info_map.begin(); i != info_map.end(); ++i) {
+      RenderViewHost* view =
+          RenderViewHost::FromID(i->first.first, i->first.second);
+      if (view)  // The view could be gone at this point.
+        view->LoadStateChanged(i->second.url, i->second.load_state);
+    }
+  }
+  LoadInfoMap info_map;
+};
+
+}  // namespace
+
+void ResourceDispatcherHost::UpdateLoadStates() {
+  // Populate this map with load state changes, and then send them on to the UI
+  // thread where they can be passed along to the respective RVHs.
+  LoadInfoMap info_map;
+
+  PendingRequestList::const_iterator i;
+  for (i = pending_requests_.begin(); i != pending_requests_.end(); ++i) {
+    URLRequest* request = i->second;
+    net::LoadState load_state = request->GetLoadState();
+    ExtraRequestInfo* info = ExtraInfoForRequest(request);
+
+    // We also poll for upload progress on this timer and send upload
+    // progress ipc messages to the plugin process.
+    MaybeUpdateUploadProgress(info, request);
+
+    if (info->last_load_state != load_state) {
+      info->last_load_state = load_state;
+
+      std::pair<int, int> key(info->render_process_host_id,
+                              info->render_view_id);
+      net::LoadState to_insert;
+      LoadInfoMap::iterator existing = info_map.find(key);
+      if (existing == info_map.end()) {
+        to_insert = load_state;
+      } else {
+        to_insert =
+            MoreInterestingLoadState(existing->second.load_state, load_state);
+        if (to_insert == existing->second.load_state)
+          continue;
+      }
+      LoadInfo& load_info = info_map[key];
+      load_info.url = request->url();
+      load_info.load_state = to_insert;
+    }
+  }
+
+  if (info_map.empty())
+    return;
+
+  LoadInfoUpdateTask* task = new LoadInfoUpdateTask;
+  task->info_map.swap(info_map);
+  ui_loop_->PostTask(FROM_HERE, task);
+}
+
+void ResourceDispatcherHost::MaybeUpdateUploadProgress(ExtraRequestInfo *info,
+                                                       URLRequest *request) {
+  if (!info->upload_size || info->waiting_for_upload_progress_ack ||
+      !(request->load_flags() & net::LOAD_ENABLE_UPLOAD_PROGRESS))
+    return;
+
+  uint64 size = info->upload_size;
+  uint64 position = request->GetUploadProgress();
+  if (position == info->last_upload_position)
+    return;  // no progress made since last time
+
+  const uint64 kHalfPercentIncrements = 200;
+  const TimeDelta kOneSecond = TimeDelta::FromMilliseconds(1000);
+
+  uint64 amt_since_last = position - info->last_upload_position;
+  TimeDelta time_since_last = TimeTicks::Now() - info->last_upload_ticks;
+
+  bool is_finished = (size == position);
+  bool enough_new_progress = (amt_since_last > (size / kHalfPercentIncrements));
+  bool too_much_time_passed = time_since_last > kOneSecond;
+
+  if (is_finished || enough_new_progress || too_much_time_passed) {
+    info->resource_handler->OnUploadProgress(info->request_id, position, size);
+    info->waiting_for_upload_progress_ack = true;
+    info->last_upload_ticks = TimeTicks::Now();
+    info->last_upload_position = position;
+  }
+}
diff --git a/chrome/browser/resource_dispatcher_host.h b/chrome/browser/renderer_host/resource_dispatcher_host.h
similarity index 84%
rename from chrome/browser/resource_dispatcher_host.h
rename to chrome/browser/renderer_host/resource_dispatcher_host.h
index fd6b5d2..f0b7f94e 100644
--- a/chrome/browser/resource_dispatcher_host.h
+++ b/chrome/browser/renderer_host/resource_dispatcher_host.h
@@ -9,8 +9,8 @@
 //
 // See http://dev.chromium.org/developers/design-documents/multi-process-resource-loading
 
-#ifndef CHROME_BROWSER_RESOURCE_DISPATCHER_HOST_H__
-#define CHROME_BROWSER_RESOURCE_DISPATCHER_HOST_H__
+#ifndef CHROME_BROWSER_RENDERER_HOST_RESOURCE_DISPATCHER_HOST_H_
+#define CHROME_BROWSER_RENDERER_HOST_RESOURCE_DISPATCHER_HOST_H_
 
 #include <map>
 #include <string>
@@ -18,14 +18,14 @@
 #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/browser/renderer_host/resource_handler.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 CrossSiteResourceHandler;
 class DownloadFileManager;
 class DownloadRequestManager;
 class LoginHandler;
@@ -33,56 +33,11 @@
 class PluginService;
 class SafeBrowsingService;
 class SaveFileManager;
-class TabContents;
 class URLRequestContext;
 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. A return value of false cancels the request, true continues
-    // reading data.
-    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
@@ -97,22 +52,18 @@
   // 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 class ResourceDispatcherHost;
    public:
-    ExtraRequestInfo(EventHandler* handler,
+    ExtraRequestInfo(ResourceHandler* 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),
+        : resource_handler(handler),
           cross_site_handler(NULL),
           login_handler(NULL),
           request_id(request_id),
@@ -133,13 +84,13 @@
           paused_read_bytes(0) {
     }
 
-    // Top-level EventHandler servicing this request.
-    scoped_refptr<EventHandler> event_handler;
+    // Top-level ResourceHandler servicing this request.
+    scoped_refptr<ResourceHandler> resource_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;
+    // CrossSiteResourceHandler for this request, if it is a cross-site request.
+    // (NULL otherwise.)  This handler is part of the chain of ResourceHandlers
+    // pointed to by resource_handler.
+    CrossSiteResourceHandler* cross_site_handler;
 
     LoginHandler* login_handler;
 
@@ -361,15 +312,18 @@
   // Retrieves a URLRequest.  Must be called from the IO thread.
   URLRequest* GetURLRequest(GlobalRequestID request_id) const;
 
+  // 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);
+
+  // Notify our observers that a request has been cancelled.
+  void NotifyResponseCompleted(URLRequest* request, int render_process_host_id);
+
+  void RemovePendingRequest(int render_process_host_id, int request_id);
+
  private:
-  class AsyncEventHandler;
-  class BufferedEventHandler;
-  class CrossSiteNotifyTabTask;
-  class DownloadEventHandler;
-  class DownloadThrottlingEventHandler;
-  class SaveFileEventHandler;
   class ShutdownTask;
-  class SyncEventHandler;
 
   friend class ShutdownTask;
 
@@ -416,12 +370,6 @@
   // 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);
   // Deletes the pending request identified by the iterator passed in.
   // This function will invalidate the iterator passed in. Callers should
   // not rely on this iterator being valid on return.
@@ -430,9 +378,6 @@
   // 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,
@@ -445,7 +390,7 @@
                               int tab_contents_id,
                               const GURL& url,
                               ResourceType::Type resource_type,
-                              EventHandler* handler);
+                              ResourceHandler* handler);
 
   void UpdateLoadStates();
 
@@ -495,7 +440,7 @@
   // True if the resource dispatcher host has been shut down.
   bool is_shutdown_;
 
-  DISALLOW_EVIL_CONSTRUCTORS(ResourceDispatcherHost);
+  DISALLOW_COPY_AND_ASSIGN(ResourceDispatcherHost);
 };
 
-#endif  // CHROME_BROWSER_RESOURCE_DISPATCHER_HOST_H__
+#endif  // CHROME_BROWSER_RENDERER_HOST_RESOURCE_DISPATCHER_HOST_H_
diff --git a/chrome/browser/resource_dispatcher_host_uitest.cc b/chrome/browser/renderer_host/resource_dispatcher_host_uitest.cc
similarity index 98%
rename from chrome/browser/resource_dispatcher_host_uitest.cc
rename to chrome/browser/renderer_host/resource_dispatcher_host_uitest.cc
index 82735dc80..6d276ee 100644
--- a/chrome/browser/resource_dispatcher_host_uitest.cc
+++ b/chrome/browser/renderer_host/resource_dispatcher_host_uitest.cc
@@ -127,7 +127,7 @@
   // (the bug would make this step hang the renderer).
   bool timed_out = false;
   tab->NavigateToURLWithTimeout(server.TestServerPageW(L"files/title2.html"),
-                                action_max_timeout_ms(),
+                                kWaitForActionMaxMsec,
                                 &timed_out);
   EXPECT_FALSE(timed_out);
 
@@ -263,7 +263,7 @@
   std::wstring redirect_url = L"javascript:window.location='" +
       ASCIIToWide(test_url.possibly_invalid_spec()) + L"'";
   tab->NavigateToURLAsync(GURL(redirect_url));
-  Sleep(action_timeout_ms());  // Wait for JavaScript redirect to happen.
+  Sleep(kWaitForActionMsec);  // Wait for JavaScript redirect to happen.
   EXPECT_TRUE(tab->GetTabTitle(&tab_title));
   EXPECT_EQ(L"Title Of Awesomeness", tab_title);
 }
diff --git a/chrome/browser/resource_dispatcher_host_unittest.cc b/chrome/browser/renderer_host/resource_dispatcher_host_unittest.cc
similarity index 99%
rename from chrome/browser/resource_dispatcher_host_unittest.cc
rename to chrome/browser/renderer_host/resource_dispatcher_host_unittest.cc
index 7002b41..8ae6e1a 100644
--- a/chrome/browser/resource_dispatcher_host_unittest.cc
+++ b/chrome/browser/renderer_host/resource_dispatcher_host_unittest.cc
@@ -6,7 +6,7 @@
 
 #include "base/message_loop.h"
 #include "chrome/browser/renderer_security_policy.h"
-#include "chrome/browser/resource_dispatcher_host.h"
+#include "chrome/browser/renderer_host/resource_dispatcher_host.h"
 #include "chrome/common/render_messages.h"
 #include "net/url_request/url_request.h"
 #include "net/url_request/url_request_job.h"
diff --git a/chrome/browser/renderer_host/resource_handler.h b/chrome/browser/renderer_host/resource_handler.h
new file mode 100644
index 0000000..a6955c7
--- /dev/null
+++ b/chrome/browser/renderer_host/resource_handler.h
@@ -0,0 +1,67 @@
+// Copyright (c) 2006-2008 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 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://dev.chromium.org/developers/design-documents/multi-process-resource-loading
+
+#ifndef CHROME_BROWSER_RENDERER_HOST_RESOURCE_HANDLER_H_
+#define CHROME_BROWSER_RENDERER_HOST_RESOURCE_HANDLER_H_
+
+#include "base/basictypes.h"
+#include "base/ref_counted.h"
+#include "chrome/common/render_messages.h"
+#include "googleurl/src/gurl.h"
+#include "net/url_request/url_request.h"
+
+// Simple wrapper that refcounts ViewMsg_Resource_ResponseHead.
+struct ResourceResponse : public base::RefCounted<ResourceResponse> {
+  ViewMsg_Resource_ResponseHead response_head;
+};
+
+// 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 ResourceHandler : public base::RefCounted<ResourceHandler> {
+ public:
+  virtual ~ResourceHandler() {}
+
+  // 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,
+                                 ResourceResponse* 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. A return value of false cancels the request, true continues
+  // reading data.
+  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;
+};
+
+#endif  // CHROME_BROWSER_RENDERER_HOST_RESOURCE_HANDLER_H_
diff --git a/chrome/browser/renderer_host/safe_browsing_resource_handler.cc b/chrome/browser/renderer_host/safe_browsing_resource_handler.cc
new file mode 100644
index 0000000..d9e70a40
--- /dev/null
+++ b/chrome/browser/renderer_host/safe_browsing_resource_handler.cc
@@ -0,0 +1,179 @@
+// Copyright (c) 2006-2008 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/renderer_host/safe_browsing_resource_handler.h"
+
+#include "chrome/browser/renderer_host/resource_dispatcher_host.h"
+
+// Maximum time to wait for a gethash response from the Safe Browsing servers.
+static const int kMaxGetHashMs = 1000;
+
+SafeBrowsingResourceHandler::SafeBrowsingResourceHandler(
+    ResourceHandler* handler,
+    int render_process_host_id,
+    int render_view_id,
+    const GURL& url,
+    ResourceType::Type resource_type,
+    SafeBrowsingService* safe_browsing,
+    ResourceDispatcherHost* resource_dispatcher_host)
+    : next_handler_(handler),
+      render_process_host_id_(render_process_host_id),
+      render_view_id_(render_view_id),
+      paused_request_id_(-1),
+      safe_browsing_(safe_browsing),
+      in_safe_browsing_check_(false),
+      displaying_blocking_page_(false),
+      rdh_(resource_dispatcher_host),
+      queued_error_request_id_(-1),
+      resource_type_(resource_type) {
+  if (safe_browsing_->CheckUrl(url, this)) {
+    safe_browsing_result_ = SafeBrowsingService::URL_SAFE;
+    safe_browsing_->LogPauseDelay(base::TimeDelta());  // No delay.
+  } else {
+    AddRef();
+    in_safe_browsing_check_ = true;
+    // Can't pause now because it's too early, so we'll do it in OnWillRead.
+  }
+}
+
+bool SafeBrowsingResourceHandler::OnUploadProgress(int request_id,
+                                                   uint64 position,
+                                                   uint64 size) {
+  return next_handler_->OnUploadProgress(request_id, position, size);
+}
+
+bool SafeBrowsingResourceHandler::OnRequestRedirected(int request_id,
+                                                      const GURL& new_url) {
+  if (in_safe_browsing_check_) {
+    Release();
+    in_safe_browsing_check_ = false;
+    safe_browsing_->CancelCheck(this);
+  }
+
+  if (safe_browsing_->CheckUrl(new_url, this)) {
+    safe_browsing_result_ = SafeBrowsingService::URL_SAFE;
+    safe_browsing_->LogPauseDelay(base::TimeDelta());  // No delay.
+  } else {
+    AddRef();
+    in_safe_browsing_check_ = true;
+    // Can't pause now because it's too early, so we'll do it in OnWillRead.
+  }
+
+  return next_handler_->OnRequestRedirected(request_id, new_url);
+}
+
+bool SafeBrowsingResourceHandler::OnResponseStarted(
+    int request_id, ResourceResponse* response) {
+  return next_handler_->OnResponseStarted(request_id, response);
+}
+
+void SafeBrowsingResourceHandler::OnGetHashTimeout() {
+  if (!in_safe_browsing_check_)
+    return;
+
+  safe_browsing_->CancelCheck(this);
+  OnUrlCheckResult(GURL::EmptyGURL(), SafeBrowsingService::URL_SAFE);
+}
+
+bool SafeBrowsingResourceHandler::OnWillRead(int request_id,
+                                             char** buf, int* buf_size,
+                                             int min_size) {
+  if (in_safe_browsing_check_ && pause_time_.is_null()) {
+    pause_time_ = base::Time::Now();
+    MessageLoop::current()->PostDelayedTask(
+        FROM_HERE,
+        NewRunnableMethod(this, &SafeBrowsingResourceHandler::OnGetHashTimeout),
+        kMaxGetHashMs);
+  }
+
+  if (in_safe_browsing_check_ || displaying_blocking_page_) {
+    rdh_->PauseRequest(render_process_host_id_, request_id, true);
+    paused_request_id_ = request_id;
+  }
+
+  return next_handler_->OnWillRead(request_id, buf, buf_size, min_size);
+}
+
+bool SafeBrowsingResourceHandler::OnReadCompleted(int request_id,
+                                                  int* bytes_read) {
+  return next_handler_->OnReadCompleted(request_id, bytes_read);
+}
+
+bool SafeBrowsingResourceHandler::OnResponseCompleted(
+    int request_id, const URLRequestStatus& status) {
+  if ((in_safe_browsing_check_ ||
+       safe_browsing_result_ != SafeBrowsingService::URL_SAFE) &&
+      status.status() == URLRequestStatus::FAILED &&
+      status.os_error() == net::ERR_NAME_NOT_RESOLVED) {
+    // Got a DNS error while the safebrowsing check is in progress or we
+    // already know that the site is unsafe.  Don't show the the dns error
+    // page.
+    queued_error_.reset(new URLRequestStatus(status));
+    queued_error_request_id_ = request_id;
+    return true;
+  }
+
+  return next_handler_->OnResponseCompleted(request_id, status);
+}
+
+// SafeBrowsingService::Client implementation, called on the IO thread once
+// the URL has been classified.
+void SafeBrowsingResourceHandler::OnUrlCheckResult(
+    const GURL& url, SafeBrowsingService::UrlCheckResult result) {
+  DCHECK(in_safe_browsing_check_);
+  DCHECK(!displaying_blocking_page_);
+
+  safe_browsing_result_ = result;
+  in_safe_browsing_check_ = false;
+
+  if (result == SafeBrowsingService::URL_SAFE) {
+    if (paused_request_id_ != -1) {
+      rdh_->PauseRequest(render_process_host_id_, paused_request_id_, false);
+      paused_request_id_ = -1;
+    }
+
+    base::TimeDelta pause_delta;
+    if (!pause_time_.is_null())
+      pause_delta = base::Time::Now() - pause_time_;
+    safe_browsing_->LogPauseDelay(pause_delta);
+
+    if (queued_error_.get()) {
+      next_handler_->OnResponseCompleted(
+          queued_error_request_id_, *queued_error_.get());
+      queued_error_.reset();
+    }
+
+    Release();
+  } else {
+    displaying_blocking_page_ = true;
+    safe_browsing_->DisplayBlockingPage(
+        url, resource_type_, result, this, rdh_->ui_loop(),
+        render_process_host_id_, render_view_id_);
+  }
+}
+
+// SafeBrowsingService::Client implementation, called on the IO thread when
+// the user has decided to proceed with the current request, or go back.
+void SafeBrowsingResourceHandler::OnBlockingPageComplete(bool proceed) {
+  DCHECK(displaying_blocking_page_);
+  displaying_blocking_page_ = false;
+
+  if (proceed) {
+    safe_browsing_result_ = SafeBrowsingService::URL_SAFE;
+    if (paused_request_id_ != -1) {
+      rdh_->PauseRequest(render_process_host_id_, paused_request_id_, false);
+      paused_request_id_ = -1;
+    }
+
+    if (queued_error_.get()) {
+      next_handler_->OnResponseCompleted(
+          queued_error_request_id_, *queued_error_.get());
+      queued_error_.reset();
+    }
+  } else {
+    rdh_->CancelRequest(render_process_host_id_, paused_request_id_, false);
+  }
+
+  Release();
+}
diff --git a/chrome/browser/renderer_host/safe_browsing_resource_handler.h b/chrome/browser/renderer_host/safe_browsing_resource_handler.h
new file mode 100644
index 0000000..244df8b
--- /dev/null
+++ b/chrome/browser/renderer_host/safe_browsing_resource_handler.h
@@ -0,0 +1,63 @@
+// Copyright (c) 2006-2008 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_RENDERER_HOST_SAFE_BROWSING_RESOURCE_HANDLER_H_
+#define CHROME_BROWSER_RENDERER_HOST_SAFE_BROWSING_RESOURCE_HANDLER_H_
+
+#include "base/time.h"
+#include "chrome/browser/renderer_host/resource_handler.h"
+#include "chrome/browser/safe_browsing/safe_browsing_service.h"
+
+class ResourceDispatcherHost;
+
+// Checks that a url is safe.
+class SafeBrowsingResourceHandler : public ResourceHandler,
+                                    public SafeBrowsingService::Client {
+ public:
+  SafeBrowsingResourceHandler(ResourceHandler* handler,
+                              int render_process_host_id,
+                              int render_view_id,
+                              const GURL& url,
+                              ResourceType::Type resource_type,
+                              SafeBrowsingService* safe_browsing,
+                              ResourceDispatcherHost* resource_dispatcher_host);
+
+  // ResourceHandler implementation:
+  bool OnUploadProgress(int request_id, uint64 position, uint64 size);
+  bool OnRequestRedirected(int request_id, const GURL& new_url);
+  bool OnResponseStarted(int request_id, ResourceResponse* response);
+  void OnGetHashTimeout();
+  bool OnWillRead(int request_id, char** buf, int* buf_size, int min_size);
+  bool OnReadCompleted(int request_id, int* bytes_read);
+  bool OnResponseCompleted(int request_id, const URLRequestStatus& status);
+
+  // SafeBrowsingService::Client implementation, called on the IO thread once
+  // the URL has been classified.
+  void OnUrlCheckResult(const GURL& url,
+                        SafeBrowsingService::UrlCheckResult result);
+
+  // SafeBrowsingService::Client implementation, called on the IO thread when
+  // the user has decided to proceed with the current request, or go back.
+  void OnBlockingPageComplete(bool proceed);
+
+ private:
+  scoped_refptr<ResourceHandler> next_handler_;
+  int render_process_host_id_;
+  int render_view_id_;
+  int paused_request_id_;  // -1 if not paused
+  bool in_safe_browsing_check_;
+  bool displaying_blocking_page_;
+  SafeBrowsingService::UrlCheckResult safe_browsing_result_;
+  scoped_refptr<SafeBrowsingService> safe_browsing_;
+  scoped_ptr<URLRequestStatus> queued_error_;
+  int queued_error_request_id_;
+  ResourceDispatcherHost* rdh_;
+  base::Time pause_time_;
+  ResourceType::Type resource_type_;
+
+  DISALLOW_COPY_AND_ASSIGN(SafeBrowsingResourceHandler);
+};
+
+
+#endif  // CHROME_BROWSER_RENDERER_HOST_SAFE_BROWSING_RESOURCE_HANDLER_H_
diff --git a/chrome/browser/renderer_host/save_file_resource_handler.cc b/chrome/browser/renderer_host/save_file_resource_handler.cc
new file mode 100644
index 0000000..420b28a
--- /dev/null
+++ b/chrome/browser/renderer_host/save_file_resource_handler.cc
@@ -0,0 +1,85 @@
+// Copyright (c) 2006-2008 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/renderer_host/save_file_resource_handler.h"
+
+#include "chrome/browser/download/save_file_manager.h"
+
+SaveFileResourceHandler::SaveFileResourceHandler(int render_process_host_id,
+                                                 int render_view_id,
+                                                 const std::string& url,
+                                                 SaveFileManager* manager)
+    : save_id_(-1),
+      render_process_id_(render_process_host_id),
+      render_view_id_(render_view_id),
+      read_buffer_(NULL),
+      url_(UTF8ToWide(url)),
+      content_length_(0),
+      save_manager_(manager) {
+}
+
+bool SaveFileResourceHandler::OnRequestRedirected(int request_id,
+                                                  const GURL& url) {
+  final_url_ = UTF8ToWide(url.spec());
+  return true;
+}
+
+bool SaveFileResourceHandler::OnResponseStarted(int request_id,
+                                                ResourceResponse* response) {
+  save_id_ = save_manager_->GetNextId();
+  // |save_manager_| consumes (deletes):
+  SaveFileCreateInfo* info = new SaveFileCreateInfo;
+  info->url = url_;
+  info->final_url = final_url_;
+  info->total_bytes = content_length_;
+  info->save_id = save_id_;
+  info->render_process_id = render_process_id_;
+  info->render_view_id = render_view_id_;
+  info->request_id = request_id;
+  info->content_disposition = content_disposition_;
+  info->save_source = SaveFileCreateInfo::SAVE_FILE_FROM_NET;
+  save_manager_->GetSaveLoop()->PostTask(FROM_HERE,
+      NewRunnableMethod(save_manager_,
+                        &SaveFileManager::StartSave,
+                        info));
+  return true;
+}
+
+bool SaveFileResourceHandler::OnWillRead(int request_id,
+                                         char** buf, int* buf_size,
+                                         int min_size) {
+  DCHECK(buf && buf_size);
+  if (!read_buffer_) {
+    *buf_size = min_size < 0 ? kReadBufSize : min_size;
+    read_buffer_ = new char[*buf_size];
+  }
+  *buf = read_buffer_;
+  return true;
+}
+
+bool SaveFileResourceHandler::OnReadCompleted(int request_id, int* bytes_read) {
+  DCHECK(read_buffer_);
+  save_manager_->GetSaveLoop()->PostTask(FROM_HERE,
+      NewRunnableMethod(save_manager_,
+                        &SaveFileManager::UpdateSaveProgress,
+                        save_id_,
+                        read_buffer_,
+                        *bytes_read));
+  read_buffer_ = NULL;
+  return true;
+}
+
+bool SaveFileResourceHandler::OnResponseCompleted(
+    int request_id,
+    const URLRequestStatus& status) {
+  save_manager_->GetSaveLoop()->PostTask(FROM_HERE,
+      NewRunnableMethod(save_manager_,
+                        &SaveFileManager::SaveFinished,
+                        save_id_,
+                        url_,
+                        render_process_id_,
+                        status.is_success() && !status.is_io_pending()));
+  delete [] read_buffer_;
+  return true;
+}
diff --git a/chrome/browser/renderer_host/save_file_resource_handler.h b/chrome/browser/renderer_host/save_file_resource_handler.h
new file mode 100644
index 0000000..87f06ae
--- /dev/null
+++ b/chrome/browser/renderer_host/save_file_resource_handler.h
@@ -0,0 +1,64 @@
+// Copyright (c) 2006-2008 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_RENDERER_HOST_SAVE_FILE_RESOURCE_HANDLER_H_
+#define CHROME_BROWSER_RENDERER_HOST_SAVE_FILE_RESOURCE_HANDLER_H_
+
+#include <string>
+
+#include "chrome/browser/renderer_host/resource_handler.h"
+
+class SaveFileManager;
+
+// Forwards data to the save thread.
+class SaveFileResourceHandler : public ResourceHandler {
+ public:
+  SaveFileResourceHandler(int render_process_host_id,
+                          int render_view_id,
+                          const std::string& url,
+                          SaveFileManager* manager);
+
+  // Saves the redirected URL to final_url_, we need to use the original
+  // URL to match original request.
+  bool OnRequestRedirected(int request_id, const GURL& url);
+
+  // Sends the download creation information to the download thread.
+  bool OnResponseStarted(int request_id, ResourceResponse* response);
+
+  // Creates a new buffer, which will be handed to the download thread for file
+  // writing and deletion.
+  bool OnWillRead(int request_id, char** buf, int* buf_size, int min_size);
+
+  // Passes the buffer to the download file writer.
+  bool OnReadCompleted(int request_id, int* bytes_read);
+
+  bool OnResponseCompleted(int request_id, const URLRequestStatus& status);
+
+  // If the content-length header is not present (or contains something other
+  // than numbers), StringToInt64 returns 0, which indicates 'unknown size' and
+  // is handled correctly by the SaveManager.
+  void set_content_length(const std::string& content_length) {
+    content_length_ = StringToInt64(content_length);
+  }
+
+  void set_content_disposition(const std::string& content_disposition) {
+    content_disposition_ = content_disposition;
+  }
+
+ private:
+  int save_id_;
+  int render_process_id_;
+  int render_view_id_;
+  char* read_buffer_;
+  std::string content_disposition_;
+  std::wstring url_;
+  std::wstring final_url_;
+  int64 content_length_;
+  SaveFileManager* save_manager_;
+
+  static const int kReadBufSize = 32768;  // bytes
+
+  DISALLOW_COPY_AND_ASSIGN(SaveFileResourceHandler);
+};
+#endif  // CHROME_BROWSER_RENDERER_HOST_SAVE_FILE_RESOURCE_HANDLER_H_
diff --git a/chrome/browser/renderer_host/sync_resource_handler.cc b/chrome/browser/renderer_host/sync_resource_handler.cc
new file mode 100644
index 0000000..aace1c1
--- /dev/null
+++ b/chrome/browser/renderer_host/sync_resource_handler.cc
@@ -0,0 +1,54 @@
+// Copyright (c) 2006-2008 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/renderer_host/sync_resource_handler.h"
+
+SyncResourceHandler::SyncResourceHandler(
+    ResourceDispatcherHost::Receiver* receiver,
+    const GURL& url,
+    IPC::Message* result_message)
+    : receiver_(receiver),
+      result_message_(result_message) {
+  result_.final_url = url;
+  result_.filter_policy = FilterPolicy::DONT_FILTER;
+}
+
+bool SyncResourceHandler::OnRequestRedirected(int request_id,
+                                              const GURL& new_url) {
+  result_.final_url = new_url;
+  return true;
+}
+
+bool SyncResourceHandler::OnResponseStarted(int request_id,
+                                            ResourceResponse* response) {
+  // We don't care about copying the status here.
+  result_.headers = response->response_head.headers;
+  result_.mime_type = response->response_head.mime_type;
+  result_.charset = response->response_head.charset;
+  return true;
+}
+
+bool SyncResourceHandler::OnWillRead(int request_id,
+                                     char** buf, int* buf_size, int min_size) {
+  DCHECK(min_size == -1);
+  *buf = read_buffer_;
+  *buf_size = kReadBufSize;
+  return true;
+}
+
+bool SyncResourceHandler::OnReadCompleted(int request_id, int* bytes_read) {
+  if (!*bytes_read)
+    return true;
+  result_.data.append(read_buffer_, *bytes_read);
+  return true;
+}
+
+bool SyncResourceHandler::OnResponseCompleted(int request_id,
+                                              const URLRequestStatus& status) {
+  result_.status = status;
+
+  ViewHostMsg_SyncLoad::WriteReplyParams(result_message_, result_);
+  receiver_->Send(result_message_);
+  return true;
+}
diff --git a/chrome/browser/renderer_host/sync_resource_handler.h b/chrome/browser/renderer_host/sync_resource_handler.h
new file mode 100644
index 0000000..81a6078
--- /dev/null
+++ b/chrome/browser/renderer_host/sync_resource_handler.h
@@ -0,0 +1,34 @@
+// Copyright (c) 2006-2008 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_RENDERER_HOST_SYNC_RESOURCE_HANDLER_H_
+#define CHROME_BROWSER_RENDERER_HOST_SYNC_RESOURCE_HANDLER_H_
+
+#include "chrome/browser/renderer_host/resource_dispatcher_host.h"
+#include "chrome/browser/renderer_host/resource_handler.h"
+
+// Used to complete a synchronous resource request in response to resource load
+// events from the resource dispatcher host.
+class SyncResourceHandler : public ResourceHandler {
+ public:
+  SyncResourceHandler(ResourceDispatcherHost::Receiver* receiver,
+                      const GURL& url,
+                      IPC::Message* result_message);
+
+  bool OnRequestRedirected(int request_id, const GURL& new_url);
+  bool OnResponseStarted(int request_id, ResourceResponse* response);
+  bool OnWillRead(int request_id, char** buf, int* buf_size, int min_size);
+  bool OnReadCompleted(int request_id, int* bytes_read);
+  bool OnResponseCompleted(int request_id, const URLRequestStatus& status);
+
+ private:
+  enum { kReadBufSize = 3840 };
+  char read_buffer_[kReadBufSize];
+
+  ViewHostMsg_SyncLoad_Result result_;
+  ResourceDispatcherHost::Receiver* receiver_;
+  IPC::Message* result_message_;
+};
+
+#endif  // CHROME_BROWSER_RENDERER_HOST_SYNC_RESOURCE_HANDLER_H_
diff --git a/chrome/browser/resource_dispatcher_host.cc b/chrome/browser/resource_dispatcher_host.cc
deleted file mode 100644
index 042f178..0000000
--- a/chrome/browser/resource_dispatcher_host.cc
+++ /dev/null
@@ -1,2524 +0,0 @@
-// Copyright (c) 2006-2008 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.
-
-// See http://dev.chromium.org/developers/design-documents/multi-process-resource-loading
-
-#include <vector>
-
-#include "chrome/browser/resource_dispatcher_host.h"
-
-#include "base/message_loop.h"
-#include "base/scoped_ptr.h"
-#include "base/time.h"
-#include "chrome/browser/cert_store.h"
-#include "chrome/browser/cross_site_request_manager.h"
-#include "chrome/browser/download/download_file.h"
-#include "chrome/browser/download/download_manager.h"
-#include "chrome/browser/download/download_request_manager.h"
-#include "chrome/browser/download/save_file_manager.h"
-#include "chrome/browser/external_protocol_handler.h"
-#include "chrome/browser/login_prompt.h"
-#include "chrome/browser/plugin_service.h"
-#include "chrome/browser/renderer_security_policy.h"
-#include "chrome/browser/render_view_host.h"
-#include "chrome/browser/render_view_host_delegate.h"
-#include "chrome/browser/resource_request_details.h"
-#include "chrome/browser/safe_browsing/safe_browsing_service.h"
-#include "chrome/browser/tab_util.h"
-#include "chrome/browser/web_contents.h"
-#include "chrome/common/notification_source.h"
-#include "chrome/common/notification_types.h"
-#include "chrome/common/render_messages.h"
-#include "chrome/common/stl_util-inl.h"
-#include "net/base/auth.h"
-#include "net/base/cert_status_flags.h"
-#include "net/base/load_flags.h"
-#include "net/base/mime_sniffer.h"
-#include "net/base/mime_util.h"
-#include "net/base/net_errors.h"
-#include "net/url_request/url_request.h"
-
-// Uncomment to enable logging of request traffic.
-//#define LOG_RESOURCE_DISPATCHER_REQUESTS
-
-#ifdef LOG_RESOURCE_DISPATCHER_REQUESTS
-# define RESOURCE_LOG(stuff) LOG(INFO) << stuff
-#else
-# define RESOURCE_LOG(stuff)
-#endif
-
-using base::Time;
-using base::TimeDelta;
-using base::TimeTicks;
-
-// ----------------------------------------------------------------------------
-
-// The interval for calls to ResourceDispatcherHost::UpdateLoadStates
-static const int kUpdateLoadStatesIntervalMsec = 100;
-
-// Maximum number of pending data messages sent to the renderer at any
-// given time for a given request.
-static const int kMaxPendingDataMessages = 20;
-
-// Maximum time to wait for a gethash response from the Safe Browsing servers.
-static const int kMaxGetHashMs = 1000;
-
-// ----------------------------------------------------------------------------
-// ResourceDispatcherHost::Response
-
-struct ResourceDispatcherHost::Response : public base::RefCounted<Response> {
-  ViewMsg_Resource_ResponseHead response_head;
-};
-
-// ----------------------------------------------------------------------------
-// ResourceDispatcherHost::AsyncEventHandler
-
-// Used to complete an asynchronous resource request in response to resource
-// load events from the resource dispatcher host.
-class ResourceDispatcherHost::AsyncEventHandler
-    : public ResourceDispatcherHost::EventHandler {
- public:
-  AsyncEventHandler(ResourceDispatcherHost::Receiver* receiver,
-                    int render_process_host_id,
-                    int routing_id,
-                    HANDLE render_process,
-                    const GURL& url,
-                    ResourceDispatcherHost* resource_dispatcher_host)
-      : receiver_(receiver),
-        render_process_host_id_(render_process_host_id),
-        routing_id_(routing_id),
-        render_process_(render_process),
-        rdh_(resource_dispatcher_host) { }
-
-  static void GlobalCleanup() {
-    delete spare_read_buffer_;
-    spare_read_buffer_ = NULL;
-  }
-
-  bool OnUploadProgress(int request_id, uint64 position, uint64 size) {
-    return receiver_->Send(new ViewMsg_Resource_UploadProgress(
-        routing_id_, request_id, position, size));
-  }
-
-  bool OnRequestRedirected(int request_id, const GURL& new_url) {
-    return receiver_->Send(new ViewMsg_Resource_ReceivedRedirect(
-        routing_id_, request_id, new_url));
-  }
-
-  bool OnResponseStarted(int request_id, Response* response) {
-    receiver_->Send(new ViewMsg_Resource_ReceivedResponse(
-        routing_id_, request_id, response->response_head));
-    return true;
-  }
-
-  bool OnWillRead(int request_id, char** buf, int* buf_size, int min_size) {
-    DCHECK(min_size == -1);
-    static const int kReadBufSize = 32768;
-    if (spare_read_buffer_) {
-      read_buffer_.reset(spare_read_buffer_);
-      spare_read_buffer_ = NULL;
-    } else {
-      read_buffer_.reset(new base::SharedMemory);
-      if (!read_buffer_->Create(std::wstring(), false, false, kReadBufSize))
-        return false;
-      if (!read_buffer_->Map(kReadBufSize))
-        return false;
-    }
-    *buf = static_cast<char*>(read_buffer_->memory());
-    *buf_size = kReadBufSize;
-    return true;
-  }
-
-  bool OnReadCompleted(int request_id, int* bytes_read) {
-    if (!*bytes_read)
-      return true;
-    DCHECK(read_buffer_.get());
-
-    if (!rdh_->WillSendData(render_process_host_id_, request_id)) {
-      // We should not send this data now, we have too many pending requests.
-      return true;
-    }
-
-    base::SharedMemoryHandle handle;
-    if (!read_buffer_->GiveToProcess(render_process_, &handle)) {
-      // We wrongfully incremented the pending data count. Fake an ACK message
-      // to fix this. We can't move this call above the WillSendData because
-      // it's killing our read_buffer_, and we don't want that when we pause
-      // the request.
-      rdh_->OnDataReceivedACK(render_process_host_id_, request_id);
-      return false;
-    }
-
-    receiver_->Send(new ViewMsg_Resource_DataReceived(
-        routing_id_, request_id, handle, *bytes_read));
-
-    return true;
-  }
-
-  bool OnResponseCompleted(int request_id, const URLRequestStatus& status) {
-    receiver_->Send(new ViewMsg_Resource_RequestComplete(
-        routing_id_, request_id, status));
-
-    // If we still have a read buffer, then see about caching it for later...
-    if (spare_read_buffer_) {
-      read_buffer_.reset();
-    } else if (read_buffer_.get() && read_buffer_->memory()) {
-      spare_read_buffer_ = read_buffer_.release();
-    }
-    return true;
-  }
-
- private:
-  // When reading, we don't know if we are going to get EOF (0 bytes read), so
-  // we typically have a buffer that we allocated but did not use.  We keep
-  // this buffer around for the next read as a small optimization.
-  static base::SharedMemory* spare_read_buffer_;
-
-  scoped_ptr<base::SharedMemory> read_buffer_;
-  ResourceDispatcherHost::Receiver* receiver_;
-  int render_process_host_id_;
-  int routing_id_;
-  HANDLE render_process_;
-  ResourceDispatcherHost* rdh_;
-};
-
-base::SharedMemory*
-    ResourceDispatcherHost::AsyncEventHandler::spare_read_buffer_;
-
-// ----------------------------------------------------------------------------
-// ResourceDispatcherHost::SyncEventHandler
-
-// Used to complete a synchronous resource request in response to resource load
-// events from the resource dispatcher host.
-class ResourceDispatcherHost::SyncEventHandler
-    : public ResourceDispatcherHost::EventHandler {
- public:
-  SyncEventHandler(ResourceDispatcherHost::Receiver* receiver,
-                   const GURL& url,
-                   IPC::Message* result_message)
-      : receiver_(receiver),
-        result_message_(result_message) {
-    result_.final_url = url;
-    result_.filter_policy = FilterPolicy::DONT_FILTER;
-  }
-
-  bool OnRequestRedirected(int request_id, const GURL& new_url) {
-    result_.final_url = new_url;
-    return true;
-  }
-
-  bool OnResponseStarted(int request_id, Response* response) {
-    // We don't care about copying the status here.
-    result_.headers = response->response_head.headers;
-    result_.mime_type = response->response_head.mime_type;
-    result_.charset = response->response_head.charset;
-    return true;
-  }
-
-  bool OnWillRead(int request_id, char** buf, int* buf_size, int min_size) {
-    DCHECK(min_size == -1);
-    *buf = read_buffer_;
-    *buf_size = kReadBufSize;
-    return true;
-  }
-
-  bool OnReadCompleted(int request_id, int* bytes_read) {
-    if (!*bytes_read)
-      return true;
-    result_.data.append(read_buffer_, *bytes_read);
-    return true;
-  }
-
-  bool OnResponseCompleted(int request_id, const URLRequestStatus& status) {
-    result_.status = status;
-
-    ViewHostMsg_SyncLoad::WriteReplyParams(result_message_, result_);
-    receiver_->Send(result_message_);
-    return true;
-  }
-
- private:
-  enum { kReadBufSize = 3840 };
-  char read_buffer_[kReadBufSize];
-
-  ViewHostMsg_SyncLoad_Result result_;
-  ResourceDispatcherHost::Receiver* receiver_;
-  IPC::Message* result_message_;
-};
-
-// ----------------------------------------------------------------------------
-// ResourceDispatcherHost::DownloadEventHandler
-// Forwards data to the download thread.
-
-class ResourceDispatcherHost::DownloadEventHandler
-    : public ResourceDispatcherHost::EventHandler {
- public:
-  DownloadEventHandler(ResourceDispatcherHost* rdh,
-                       int render_process_host_id,
-                       int render_view_id,
-                       int request_id,
-                       const std::string& url,
-                       DownloadFileManager* manager,
-                       URLRequest* request,
-                       bool save_as)
-      : download_id_(-1),
-        global_id_(render_process_host_id, request_id),
-        render_view_id_(render_view_id),
-        read_buffer_(NULL),
-        url_(UTF8ToWide(url)),
-        content_length_(0),
-        download_manager_(manager),
-        request_(request),
-        save_as_(save_as),
-        buffer_(new DownloadBuffer),
-        rdh_(rdh),
-        is_paused_(false) {
-  }
-
-  // Not needed, as this event handler ought to be the final resource.
-  bool OnRequestRedirected(int request_id, const GURL& url) {
-    url_ = UTF8ToWide(url.spec());
-    return true;
-  }
-
-  // Send the download creation information to the download thread.
-  bool OnResponseStarted(int request_id, Response* response) {
-    std::string content_disposition;
-    request_->GetResponseHeaderByName("content-disposition",
-                                      &content_disposition);
-    set_content_disposition(content_disposition);
-    set_content_length(response->response_head.content_length);
-
-    download_id_ = download_manager_->GetNextId();
-    // |download_manager_| consumes (deletes):
-    DownloadCreateInfo* info = new DownloadCreateInfo;
-    info->url = url_;
-    info->start_time = Time::Now();
-    info->received_bytes = 0;
-    info->total_bytes = content_length_;
-    info->state = DownloadItem::IN_PROGRESS;
-    info->download_id = download_id_;
-    info->render_process_id = global_id_.render_process_host_id;
-    info->render_view_id = render_view_id_;
-    info->request_id = global_id_.request_id;
-    info->content_disposition = content_disposition_;
-    info->mime_type = response->response_head.mime_type;
-    info->save_as = save_as_;
-    info->is_dangerous = false;
-    download_manager_->file_loop()->PostTask(FROM_HERE,
-        NewRunnableMethod(download_manager_,
-                          &DownloadFileManager::StartDownload,
-                          info));
-    return true;
-  }
-
-  // Create a new buffer, which will be handed to the download thread for file
-  // writing and deletion.
-  bool OnWillRead(int request_id, char** buf, int* buf_size, int min_size) {
-    DCHECK(buf && buf_size);
-    if (!read_buffer_) {
-      *buf_size = min_size < 0 ? kReadBufSize : min_size;
-      read_buffer_ = new char[*buf_size];
-    }
-    *buf = read_buffer_;
-    return true;
-  }
-
-  // Pass the buffer to the download file writer.
-  bool OnReadCompleted(int request_id, int* bytes_read) {
-    if (!*bytes_read)
-      return true;
-    DCHECK(read_buffer_);
-    AutoLock auto_lock(buffer_->lock);
-    bool need_update = buffer_->contents.empty();
-    buffer_->contents.push_back(std::make_pair(read_buffer_, *bytes_read));
-    if (need_update) {
-      download_manager_->file_loop()->PostTask(FROM_HERE,
-          NewRunnableMethod(download_manager_,
-                            &DownloadFileManager::UpdateDownload,
-                            download_id_,
-                            buffer_));
-    }
-    read_buffer_ = NULL;
-
-    // We schedule a pause outside of the read loop if there is too much file
-    // writing work to do.
-    if (buffer_->contents.size() > kLoadsToWrite)
-      StartPauseTimer();
-
-    return true;
-  }
-
-  bool OnResponseCompleted(int request_id, const URLRequestStatus& status) {
-    download_manager_->file_loop()->PostTask(FROM_HERE,
-        NewRunnableMethod(download_manager_,
-                          &DownloadFileManager::DownloadFinished,
-                          download_id_,
-                          buffer_));
-    delete [] read_buffer_;
-
-    // 'buffer_' is deleted by the DownloadFileManager.
-    buffer_ = NULL;
-    return true;
-  }
-
-  // If the content-length header is not present (or contains something other
-  // than numbers), the incoming content_length is -1 (unknown size).
-  // Set the content length to 0 to indicate unknown size to DownloadManager.
-  void set_content_length(const int64& content_length) {
-    content_length_ = 0;
-    if (content_length > 0)
-      content_length_ = content_length;
-  }
-
-  void set_content_disposition(const std::string& content_disposition) {
-    content_disposition_ = content_disposition;
-  }
-
-  void CheckWriteProgress() {
-    if (!buffer_)
-      return;  // The download completed while we were waiting to run.
-
-    size_t contents_size;
-    {
-      AutoLock lock(buffer_->lock);
-      contents_size = buffer_->contents.size();
-    }
-
-    bool should_pause = contents_size > kLoadsToWrite;
-
-    // We'll come back later and see if it's okay to unpause the request.
-    if (should_pause)
-      StartPauseTimer();
-
-    if (is_paused_ != should_pause) {
-      rdh_->PauseRequest(global_id_.render_process_host_id,
-                         global_id_.request_id,
-                         should_pause);
-      is_paused_ = should_pause;
-    }
-  }
-
- private:
-  void StartPauseTimer() {
-    if (!pause_timer_.IsRunning())
-      pause_timer_.Start(TimeDelta::FromMilliseconds(kThrottleTimeMs), this,
-                         &DownloadEventHandler::CheckWriteProgress);
-  }
-
-  int download_id_;
-  ResourceDispatcherHost::GlobalRequestID global_id_;
-  int render_view_id_;
-  char* read_buffer_;
-  std::string content_disposition_;
-  std::wstring url_;
-  int64 content_length_;
-  DownloadFileManager* download_manager_;
-  URLRequest* request_;
-  bool save_as_;  // Request was initiated via "Save As" by the user.
-  DownloadBuffer* buffer_;
-  ResourceDispatcherHost* rdh_;
-  bool is_paused_;
-  base::OneShotTimer<DownloadEventHandler> pause_timer_;
-
-  static const int kReadBufSize = 32768;  // bytes
-  static const int kLoadsToWrite = 100;  // number of data buffers queued
-  static const int kThrottleTimeMs = 200;  // milliseconds
-
-  DISALLOW_EVIL_CONSTRUCTORS(DownloadEventHandler);
-};
-
-// DownloadThrottlingEventHandler----------------------------------------------
-
-// DownloadThrottlingEventHandler is used to determine if a download should be
-// allowed. When a DownloadThrottlingEventHandler is created it pauses the
-// download and asks the DownloadRequestManager if the download should be
-// allowed. The DownloadRequestManager notifies us asynchronously as to whether
-// the download is allowed or not. If the download is allowed the request is
-// resumed, a DownloadEventHandler is created and all EventHandler methods are
-// delegated to it. If the download is not allowed the request is canceled.
-
-class ResourceDispatcherHost::DownloadThrottlingEventHandler :
-    public ResourceDispatcherHost::EventHandler,
-    public DownloadRequestManager::Callback {
- public:
-  DownloadThrottlingEventHandler(ResourceDispatcherHost* host,
-                                 URLRequest* request,
-                                 const std::string& url,
-                                 int render_process_host_id,
-                                 int render_view_id,
-                                 int request_id,
-                                 bool in_complete)
-      : host_(host),
-        request_(request),
-        url_(url),
-        render_process_host_id_(render_process_host_id),
-        render_view_id_(render_view_id),
-        request_id_(request_id),
-        tmp_buffer_length_(0),
-        ignore_on_read_complete_(in_complete) {
-    // Pause the request.
-    host_->PauseRequest(render_process_host_id_, request_id_, true);
-    host_->download_request_manager()->CanDownloadOnIOThread(
-        render_process_host_id_, render_view_id, this);
-   }
-
-  virtual ~DownloadThrottlingEventHandler() {}
-
-  virtual bool OnUploadProgress(int request_id,
-                                uint64 position,
-                                uint64 size) {
-    if (download_handler_.get())
-      return download_handler_->OnUploadProgress(request_id, position, size);
-    return true;
-  }
-
-  virtual bool OnRequestRedirected(int request_id, const GURL& url) {
-    if (download_handler_.get())
-      return download_handler_->OnRequestRedirected(request_id, url);
-    url_ = url.spec();
-    return true;
-  }
-
-  virtual bool OnResponseStarted(int request_id, Response* response) {
-    if (download_handler_.get())
-      return download_handler_->OnResponseStarted(request_id, response);
-    response_ = response;
-    return true;
-  }
-
-  virtual bool OnWillRead(int request_id,
-                          char** buf,
-                          int* buf_size,
-                          int min_size) {
-    if (download_handler_.get())
-      return download_handler_->OnWillRead(request_id, buf, buf_size, min_size);
-
-    // We should only have this invoked once, as such we only deal with one
-    // tmp buffer.
-    DCHECK(!tmp_buffer_.get());
-    if (min_size < 0)
-      min_size = 1024;
-    tmp_buffer_.reset(new char[min_size]);
-    *buf = tmp_buffer_.get();
-    *buf_size = min_size;
-    return true;
-  }
-
-  virtual bool OnReadCompleted(int request_id, int* bytes_read) {
-    if (ignore_on_read_complete_) {
-      // See comments above definition for details on this.
-      ignore_on_read_complete_ = false;
-      return true;
-    }
-    if (!*bytes_read)
-      return true;
-
-    if (tmp_buffer_.get()) {
-      DCHECK(!tmp_buffer_length_);
-      tmp_buffer_length_ = *bytes_read;
-      if (download_handler_.get())
-        CopyTmpBufferToDownloadHandler();
-      return true;
-    }
-    if (download_handler_.get())
-      return download_handler_->OnReadCompleted(request_id, bytes_read);
-    return true;
-  }
-
-  virtual bool OnResponseCompleted(int request_id,
-                                   const URLRequestStatus& status) {
-    if (download_handler_.get())
-      return download_handler_->OnResponseCompleted(request_id, status);
-    NOTREACHED();
-    return true;
-  }
-
-  void CancelDownload() {
-    host_->CancelRequest(render_process_host_id_, request_id_, false);
-  }
-
-  void ContinueDownload() {
-    DCHECK(!download_handler_.get());
-    download_handler_ =
-        new DownloadEventHandler(host_,
-                                 render_process_host_id_,
-                                 render_view_id_,
-                                 request_id_,
-                                 url_,
-                                 host_->download_file_manager(),
-                                 request_,
-                                 false);
-    if (response_.get())
-      download_handler_->OnResponseStarted(request_id_, response_.get());
-
-    if (tmp_buffer_length_)
-      CopyTmpBufferToDownloadHandler();
-
-    // And let the request continue.
-    host_->PauseRequest(render_process_host_id_, request_id_, false);
-  }
-
- private:
-  void CopyTmpBufferToDownloadHandler() {
-    // Copy over the tmp buffer.
-    char* buffer;
-    int buf_size;
-    if (download_handler_->OnWillRead(request_id_, &buffer, &buf_size,
-                                      tmp_buffer_length_)) {
-      CHECK(buf_size >= tmp_buffer_length_);
-      memcpy(buffer, tmp_buffer_.get(), tmp_buffer_length_);
-      download_handler_->OnReadCompleted(request_id_, &tmp_buffer_length_);
-    }
-    tmp_buffer_length_ = 0;
-    tmp_buffer_.reset();
-  }
-
-  ResourceDispatcherHost* host_;
-  URLRequest* request_;
-  std::string url_;
-  int render_process_host_id_;
-  int render_view_id_;
-  int request_id_;
-
-  // Handles the actual download. This is only created if the download is
-  // allowed to continue.
-  scoped_refptr<DownloadEventHandler> download_handler_;
-
-  // Response supplied to OnResponseStarted. Only non-null if OnResponseStarted
-  // is invoked.
-  scoped_refptr<Response> response_;
-
-  // If we're created by way of BufferedEventHandler we'll get one request for
-  // a buffer. This is that buffer.
-  scoped_array<char> tmp_buffer_;
-  int tmp_buffer_length_;
-
-  // If true the next call to OnReadCompleted is ignored. This is used if we're
-  // paused during a call to OnReadCompleted. Pausing during OnReadCompleted
-  // results in two calls to OnReadCompleted for the same data. This make sure
-  // we ignore one of them.
-  bool ignore_on_read_complete_;
-
-  DISALLOW_COPY_AND_ASSIGN(DownloadThrottlingEventHandler);
-};
-
-
-// ----------------------------------------------------------------------------
-
-// Checks that a url is safe.
-class SafeBrowsingEventHandler
-    : public ResourceDispatcherHost::EventHandler,
-      public SafeBrowsingService::Client {
- public:
-  SafeBrowsingEventHandler(ResourceDispatcherHost::EventHandler* handler,
-                           int render_process_host_id,
-                           int render_view_id,
-                           const GURL& url,
-                           ResourceType::Type resource_type,
-                           SafeBrowsingService* safe_browsing,
-                           ResourceDispatcherHost* resource_dispatcher_host)
-      : next_handler_(handler),
-        render_process_host_id_(render_process_host_id),
-        render_view_id_(render_view_id),
-        paused_request_id_(-1),
-        safe_browsing_(safe_browsing),
-        in_safe_browsing_check_(false),
-        displaying_blocking_page_(false),
-        rdh_(resource_dispatcher_host),
-        queued_error_request_id_(-1),
-        resource_type_(resource_type) {
-    if (safe_browsing_->CheckUrl(url, this)) {
-      safe_browsing_result_ = SafeBrowsingService::URL_SAFE;
-      safe_browsing_->LogPauseDelay(TimeDelta());  // No delay.
-    } else {
-      AddRef();
-      in_safe_browsing_check_ = true;
-      // Can't pause now because it's too early, so we'll do it in OnWillRead.
-    }
-  }
-
-  bool OnUploadProgress(int request_id, uint64 position, uint64 size) {
-    return next_handler_->OnUploadProgress(request_id, position, size);
-  }
-
-  bool OnRequestRedirected(int request_id, const GURL& new_url) {
-    if (in_safe_browsing_check_) {
-      Release();
-      in_safe_browsing_check_ = false;
-      safe_browsing_->CancelCheck(this);
-    }
-
-    if (safe_browsing_->CheckUrl(new_url, this)) {
-      safe_browsing_result_ = SafeBrowsingService::URL_SAFE;
-      safe_browsing_->LogPauseDelay(TimeDelta());  // No delay.
-    } else {
-      AddRef();
-      in_safe_browsing_check_ = true;
-      // Can't pause now because it's too early, so we'll do it in OnWillRead.
-    }
-
-    return next_handler_->OnRequestRedirected(request_id, new_url);
-  }
-
-  bool OnResponseStarted(int request_id,
-                         ResourceDispatcherHost::Response* response) {
-    return next_handler_->OnResponseStarted(request_id, response);
-  }
-
-  void OnGetHashTimeout() {
-    if (!in_safe_browsing_check_)
-      return;
-
-    safe_browsing_->CancelCheck(this);
-    OnUrlCheckResult(GURL::EmptyGURL(), SafeBrowsingService::URL_SAFE);
-  }
-
-  bool OnWillRead(int request_id, char** buf, int* buf_size, int min_size) {
-    if (in_safe_browsing_check_ && pause_time_.is_null()) {
-      pause_time_ = Time::Now();
-      MessageLoop::current()->PostDelayedTask(
-          FROM_HERE,
-          NewRunnableMethod(this, &SafeBrowsingEventHandler::OnGetHashTimeout),
-          kMaxGetHashMs);
-    }
-
-    if (in_safe_browsing_check_ || displaying_blocking_page_) {
-      rdh_->PauseRequest(render_process_host_id_, request_id, true);
-      paused_request_id_ = request_id;
-    }
-
-    return next_handler_->OnWillRead(request_id, buf, buf_size, min_size);
-  }
-
-  bool OnReadCompleted(int request_id, int* bytes_read) {
-    return next_handler_->OnReadCompleted(request_id, bytes_read);
-  }
-
-  bool OnResponseCompleted(int request_id, const URLRequestStatus& status) {
-    if ((in_safe_browsing_check_ ||
-         safe_browsing_result_ != SafeBrowsingService::URL_SAFE) &&
-        status.status() == URLRequestStatus::FAILED &&
-        status.os_error() == net::ERR_NAME_NOT_RESOLVED) {
-      // Got a DNS error while the safebrowsing check is in progress or we
-      // already know that the site is unsafe.  Don't show the the dns error
-      // page.
-      queued_error_.reset(new URLRequestStatus(status));
-      queued_error_request_id_ = request_id;
-      return true;
-    }
-
-    return next_handler_->OnResponseCompleted(request_id, status);
-  }
-
-  // SafeBrowsingService::Client implementation, called on the IO thread once
-  // the URL has been classified.
-  void OnUrlCheckResult(const GURL& url,
-                        SafeBrowsingService::UrlCheckResult result) {
-    DCHECK(in_safe_browsing_check_);
-    DCHECK(!displaying_blocking_page_);
-
-    safe_browsing_result_ = result;
-    in_safe_browsing_check_ = false;
-
-    if (result == SafeBrowsingService::URL_SAFE) {
-      if (paused_request_id_ != -1) {
-        rdh_->PauseRequest(render_process_host_id_, paused_request_id_, false);
-        paused_request_id_ = -1;
-      }
-
-      TimeDelta pause_delta;
-      if (!pause_time_.is_null())
-        pause_delta = Time::Now() - pause_time_;
-      safe_browsing_->LogPauseDelay(pause_delta);
-
-      if (queued_error_.get()) {
-        next_handler_->OnResponseCompleted(
-            queued_error_request_id_, *queued_error_.get());
-        queued_error_.reset();
-      }
-
-      Release();
-    } else {
-      displaying_blocking_page_ = true;
-      safe_browsing_->DisplayBlockingPage(
-          url, resource_type_, result, this, rdh_->ui_loop(),
-          render_process_host_id_, render_view_id_);
-    }
-  }
-
-  // SafeBrowsingService::Client implementation, called on the IO thread when
-  // the user has decided to proceed with the current request, or go back.
-  void OnBlockingPageComplete(bool proceed) {
-    DCHECK(displaying_blocking_page_);
-    displaying_blocking_page_ = false;
-
-    if (proceed) {
-      safe_browsing_result_ = SafeBrowsingService::URL_SAFE;
-      if (paused_request_id_ != -1) {
-        rdh_->PauseRequest(render_process_host_id_, paused_request_id_, false);
-        paused_request_id_ = -1;
-      }
-
-      if (queued_error_.get()) {
-        next_handler_->OnResponseCompleted(
-            queued_error_request_id_, *queued_error_.get());
-        queued_error_.reset();
-      }
-    } else {
-      rdh_->CancelRequest(render_process_host_id_, paused_request_id_, false);
-    }
-
-    Release();
-  }
-
- private:
-  scoped_refptr<ResourceDispatcherHost::EventHandler> next_handler_;
-  int render_process_host_id_;
-  int render_view_id_;
-  int paused_request_id_;  // -1 if not paused
-  bool in_safe_browsing_check_;
-  bool displaying_blocking_page_;
-  SafeBrowsingService::UrlCheckResult safe_browsing_result_;
-  scoped_refptr<SafeBrowsingService> safe_browsing_;
-  scoped_ptr<URLRequestStatus> queued_error_;
-  int queued_error_request_id_;
-  ResourceDispatcherHost* rdh_;
-  Time pause_time_;
-  ResourceType::Type resource_type_;
-};
-
-// ----------------------------------------------------------------------------
-// ResourceDispatcherHost::CrossSiteEventHandler
-
-// Task to notify the WebContents that a cross-site response has begun, so that
-// WebContents can tell the old page to run its onunload handler.
-class ResourceDispatcherHost::CrossSiteNotifyTabTask : public Task {
- public:
-  CrossSiteNotifyTabTask(int render_process_host_id,
-                         int render_view_id,
-                         int request_id)
-    : render_process_host_id_(render_process_host_id),
-      render_view_id_(render_view_id),
-      request_id_(request_id) {}
-
-  void Run() {
-    RenderViewHost* view =
-        RenderViewHost::FromID(render_process_host_id_, render_view_id_);
-    if (view) {
-      view->OnCrossSiteResponse(render_process_host_id_, request_id_);
-    } else {
-      // The view couldn't be found.
-      // TODO(creis): Should notify the IO thread to proceed anyway, using
-      // ResourceDispatcherHost::OnClosePageACK.
-    }
-  }
-
- private:
-  int render_process_host_id_;
-  int render_view_id_;
-  int request_id_;
-};
-
-// Ensures that cross-site responses are delayed until the onunload handler of
-// the previous page is allowed to run.  This handler wraps an
-// AsyncEventHandler, and it sits inside SafeBrowsing and Buffered event
-// handlers.  This is important, so that it can intercept OnResponseStarted
-// after we determine that a response is safe and not a download.
-class ResourceDispatcherHost::CrossSiteEventHandler
-    : public ResourceDispatcherHost::EventHandler {
- public:
-  CrossSiteEventHandler(ResourceDispatcherHost::EventHandler* handler,
-                        int render_process_host_id,
-                        int render_view_id,
-                        ResourceDispatcherHost* resource_dispatcher_host)
-      : next_handler_(handler),
-        render_process_host_id_(render_process_host_id),
-        render_view_id_(render_view_id),
-        has_started_response_(false),
-        in_cross_site_transition_(false),
-        request_id_(-1),
-        completed_during_transition_(false),
-        completed_status_(),
-        response_(NULL),
-        rdh_(resource_dispatcher_host) {}
-
-  bool OnRequestRedirected(int request_id, const GURL& new_url) {
-    // We should not have started the transition before being redirected.
-    DCHECK(!in_cross_site_transition_);
-    return next_handler_->OnRequestRedirected(request_id, new_url);
-  }
-
-  bool OnResponseStarted(int request_id,
-                         ResourceDispatcherHost::Response* response) {
-    // At this point, we know that the response is safe to send back to the
-    // renderer: it is not a download, and it has passed the SSL and safe
-    // browsing checks.
-    // We should not have already started the transition before now.
-    DCHECK(!in_cross_site_transition_);
-    has_started_response_ = true;
-
-    // Look up the request and associated info.
-    GlobalRequestID global_id(render_process_host_id_, request_id);
-    URLRequest* request = rdh_->GetURLRequest(global_id);
-    if (!request) {
-      DLOG(WARNING) << "Request wasn't found";
-      return false;
-    }
-    ExtraRequestInfo* info = ExtraInfoForRequest(request);
-
-    // If this is a download, just pass the response through without doing a
-    // cross-site check.  The renderer will see it is a download and abort the
-    // request.
-    if (info->is_download) {
-      return next_handler_->OnResponseStarted(request_id, response);
-    }
-
-    // Tell the renderer to run the onunload event handler, and wait for the
-    // reply.
-    StartCrossSiteTransition(request_id, response, global_id);
-    return true;
-  }
-
-  bool OnWillRead(int request_id, char** buf, int* buf_size, int min_size) {
-    return next_handler_->OnWillRead(request_id, buf, buf_size, min_size);
-  }
-
-  bool OnReadCompleted(int request_id, int* bytes_read) {
-    if (!in_cross_site_transition_) {
-      return next_handler_->OnReadCompleted(request_id, bytes_read);
-    }
-    return true;
-  }
-
-  bool OnResponseCompleted(int request_id, const URLRequestStatus& status) {
-    if (!in_cross_site_transition_) {
-      if (has_started_response_) {
-        // We've already completed the transition, so just pass it through.
-        return next_handler_->OnResponseCompleted(request_id, status);
-      } else {
-        // Some types of failures will call OnResponseCompleted without calling
-        // CrossSiteEventHandler::OnResponseStarted.  We should wait now for
-        // the cross-site transition.  Also continue with the logic below to
-        // remember that we completed during the cross-site transition.
-        GlobalRequestID global_id(render_process_host_id_, request_id);
-        StartCrossSiteTransition(request_id, NULL, global_id);
-      }
-    }
-
-    // We have to buffer the call until after the transition completes.
-    completed_during_transition_ = true;
-    completed_status_ = status;
-
-    // Return false to tell RDH not to notify the world or clean up the
-    // pending request.  We will do so in ResumeResponse.
-    return false;
-  }
-
-  // We can now send the response to the new renderer, which will cause
-  // WebContents to swap in the new renderer and destroy the old one.
-  void ResumeResponse() {
-    DCHECK(request_id_ != -1);
-    DCHECK(in_cross_site_transition_);
-    in_cross_site_transition_ = false;
-
-    // Find the request for this response.
-    GlobalRequestID global_id(render_process_host_id_, request_id_);
-    URLRequest* request = rdh_->GetURLRequest(global_id);
-    if (!request) {
-      DLOG(WARNING) << "Resuming a request that wasn't found";
-      return;
-    }
-    ExtraRequestInfo* info = ExtraInfoForRequest(request);
-
-    if (has_started_response_) {
-      // Send OnResponseStarted to the new renderer.
-      DCHECK(response_);
-      next_handler_->OnResponseStarted(request_id_, response_);
-
-      // Unpause the request to resume reading.  Any further reads will be
-      // directed toward the new renderer.
-      rdh_->PauseRequest(render_process_host_id_, request_id_, false);
-    }
-
-    // Remove ourselves from the ExtraRequestInfo.
-    info->cross_site_handler = NULL;
-
-    // If the response completed during the transition, notify the next
-    // event handler.
-    if (completed_during_transition_) {
-      next_handler_->OnResponseCompleted(request_id_, completed_status_);
-
-      // Since we didn't notify the world or clean up the pending request in
-      // RDH::OnResponseCompleted during the transition, we should do it now.
-      rdh_->NotifyResponseCompleted(request, render_process_host_id_);
-      rdh_->RemovePendingRequest(render_process_host_id_, request_id_);
-    }
-  }
-
- private:
-  // Prepare to render the cross-site response in a new RenderViewHost, by
-  // telling the old RenderViewHost to run its onunload handler.
-  void StartCrossSiteTransition(int request_id,
-                                ResourceDispatcherHost::Response* response,
-                                GlobalRequestID global_id) {
-    in_cross_site_transition_ = true;
-    request_id_ = request_id;
-    response_ = response;
-
-    // Store this handler on the ExtraRequestInfo, so that RDH can call our
-    // ResumeResponse method when the close ACK is received.
-    URLRequest* request = rdh_->GetURLRequest(global_id);
-    if (!request) {
-      DLOG(WARNING) << "Cross site response for a request that wasn't found";
-      return;
-    }
-    ExtraRequestInfo* info = ExtraInfoForRequest(request);
-    info->cross_site_handler = this;
-
-    if (has_started_response_) {
-      // Pause the request until the old renderer is finished and the new
-      // renderer is ready.
-      rdh_->PauseRequest(render_process_host_id_, request_id, true);
-    }
-    // If our OnResponseStarted wasn't called, then we're being called by
-    // OnResponseCompleted after a failure.  We don't need to pause, because
-    // there will be no reads.
-
-    // Tell the tab responsible for this request that a cross-site response is
-    // starting, so that it can tell its old renderer to run its onunload
-    // handler now.  We will wait to hear the corresponding ClosePage_ACK.
-    ResourceDispatcherHost::CrossSiteNotifyTabTask* task =
-        new CrossSiteNotifyTabTask(render_process_host_id_,
-                                   render_view_id_,
-                                   request_id);
-    rdh_->ui_loop()->PostTask(FROM_HERE, task);
-  }
-
-  scoped_refptr<ResourceDispatcherHost::EventHandler> next_handler_;
-  int render_process_host_id_;
-  int render_view_id_;
-  bool has_started_response_;
-  bool in_cross_site_transition_;
-  int request_id_;
-  bool completed_during_transition_;
-  URLRequestStatus completed_status_;
-  ResourceDispatcherHost::Response* response_;
-  ResourceDispatcherHost* rdh_;
-};
-
-// ----------------------------------------------------------------------------
-// ResourceDispatcherHost::BufferedEventHandler
-
-// Used to buffer a request until enough data has been received.
-class ResourceDispatcherHost::BufferedEventHandler
-    : public ResourceDispatcherHost::EventHandler {
- public:
-  BufferedEventHandler(ResourceDispatcherHost::EventHandler* handler,
-                       ResourceDispatcherHost* host, URLRequest* request)
-    : real_handler_(handler),
-      host_(host),
-      request_(request),
-      bytes_read_(0),
-      sniff_content_(false),
-      should_buffer_(false),
-      buffering_(false),
-      finished_(false) {}
-
-  bool OnUploadProgress(int request_id, uint64 position, uint64 size) {
-    return real_handler_->OnUploadProgress(request_id, position, size);
-  }
-
-  bool OnRequestRedirected(int request_id, const GURL& new_url) {
-    return real_handler_->OnRequestRedirected(request_id, new_url);
-  }
-
-  bool OnResponseStarted(int request_id, Response* response) {
-    response_ = response;
-    if (!DelayResponse())
-      return CompleteResponseStarted(request_id, false);
-    return true;
-  }
-
-  bool OnWillRead(int request_id, char** buf, int* buf_size, int min_size);
-  bool OnReadCompleted(int request_id, int* bytes_read);
-
-  bool OnResponseCompleted(int request_id, const URLRequestStatus& status) {
-    return real_handler_->OnResponseCompleted(request_id, status);
-  }
-
- private:
-  // Returns true if we should delay OnResponseStarted forwarding.
-  bool DelayResponse();
-
-  // Returns true if there will be a need to parse the DocType of the document
-  // to determine the right way to handle it.
-  bool ShouldBuffer(const GURL& url, const std::string& mime_type);
-
-  // Returns true if there is enough information to process the DocType.
-  bool DidBufferEnough(int bytes_read) {
-    const int kRequiredLength = 256;
-
-    return bytes_read >= kRequiredLength;
-  }
-
-  // Returns true if we have to keep buffering data.
-  bool KeepBuffering(int bytes_read);
-
-  // Sends a pending OnResponseStarted notification. |in_complete| is true if
-  // this is invoked from |OnResponseCompleted|.
-  bool CompleteResponseStarted(int request_id, bool in_complete);
-
-  scoped_refptr<ResourceDispatcherHost::EventHandler> real_handler_;
-  scoped_refptr<Response> response_;
-  ResourceDispatcherHost* host_;
-  URLRequest* request_;
-  char* read_buffer_;
-  int read_buffer_size_;
-  int bytes_read_;
-  bool sniff_content_;
-  bool should_buffer_;
-  bool buffering_;
-  bool finished_;
-
-  DISALLOW_EVIL_CONSTRUCTORS(BufferedEventHandler);
-};
-
-// We'll let the original event handler provide a buffer, and reuse it for
-// subsequent reads until we're done buffering.
-bool ResourceDispatcherHost::BufferedEventHandler::OnWillRead(
-    int request_id, char** buf, int* buf_size, int min_size) {
-  if (buffering_) {
-    *buf = read_buffer_ + bytes_read_;
-    *buf_size = read_buffer_size_ - bytes_read_;
-    DCHECK(*buf_size > 0);
-    return true;
-  }
-
-  if (finished_)
-    return false;
-
-  bool ret = real_handler_->OnWillRead(request_id, buf, buf_size, min_size);
-  read_buffer_ = *buf;
-  read_buffer_size_ = *buf_size;
-  bytes_read_ = 0;
-  return ret;
-}
-
-bool ResourceDispatcherHost::BufferedEventHandler::OnReadCompleted(
-    int request_id, int* bytes_read) {
-  ResourceDispatcherHost::ExtraRequestInfo* info =
-      ResourceDispatcherHost::ExtraInfoForRequest(request_);
-
-  if (sniff_content_ || should_buffer_) {
-    if (KeepBuffering(*bytes_read))
-      return true;
-
-    LOG(INFO) << "Finished buffering " << request_->url().spec();
-    sniff_content_ = should_buffer_ = false;
-    *bytes_read = bytes_read_;
-
-    // Done buffering, send the pending ResponseStarted event.
-    if (!CompleteResponseStarted(request_id, true))
-      return false;
-  }
-
-  return real_handler_->OnReadCompleted(request_id, bytes_read);
-}
-
-bool ResourceDispatcherHost::BufferedEventHandler::DelayResponse() {
-  std::string mime_type;
-  request_->GetMimeType(&mime_type);
-
-  std::string content_type_options;
-  request_->GetResponseHeaderByName("x-content-type-options",
-                                    &content_type_options);
-  if (content_type_options != "nosniff" &&
-      net::ShouldSniffMimeType(request_->url(), mime_type)) {
-    // We're going to look at the data before deciding what the content type
-    // is.  That means we need to delay sending the ResponseStarted message
-    // over the IPC channel.
-    sniff_content_ = true;
-    LOG(INFO) << "To buffer: " << request_->url().spec();
-    return true;
-  }
-
-  if (ShouldBuffer(request_->url(), mime_type)) {
-    // This is a temporary fix for the fact that webkit expects to have
-    // enough data to decode the doctype in order to select the rendering
-    // mode.
-    should_buffer_ = true;
-    LOG(INFO) << "To buffer: " << request_->url().spec();
-    return true;
-  }
-  return false;
-}
-
-bool ResourceDispatcherHost::BufferedEventHandler::ShouldBuffer(
-    const GURL& url, const std::string& mime_type) {
-  // We are willing to buffer for HTTP and HTTPS.
-  bool sniffable_scheme = url.is_empty() ||
-                          url.SchemeIs("http") ||
-                          url.SchemeIs("https");
-  if (!sniffable_scheme)
-    return false;
-
-  // Today, the only reason to buffer the request is to fix the doctype decoding
-  // performed by webkit: if there is not enough data it will go to quirks mode.
-  // We only expect the doctype check to apply to html documents.
-  return mime_type == "text/html";
-}
-
-bool ResourceDispatcherHost::BufferedEventHandler::KeepBuffering(
-    int bytes_read) {
-  DCHECK(read_buffer_);
-  bytes_read_ += bytes_read;
-  finished_ = (bytes_read == 0);
-
-  if (sniff_content_) {
-    std::string type_hint, new_type;
-    request_->GetMimeType(&type_hint);
-
-    if (!net::SniffMimeType(read_buffer_, bytes_read_, request_->url(),
-                            type_hint, &new_type)) {
-      // SniffMimeType() returns false if there is not enough data to determine
-      // the mime type. However, even if it returns false, it returns a new type
-      // that is probably better than the current one.
-      DCHECK(bytes_read_ < 512 /*kMaxBytesToSniff*/);
-      if (!finished_) {
-        buffering_ = true;
-        return true;
-      }
-    }
-    sniff_content_ = false;
-    response_->response_head.mime_type.assign(new_type);
-
-    // We just sniffed the mime type, maybe there is a doctype to process.
-    if (ShouldBuffer(request_->url(), new_type))
-      should_buffer_ = true;
-  }
-
-  if (!finished_ && should_buffer_) {
-    if (!DidBufferEnough(bytes_read_)) {
-      buffering_ = true;
-      return true;
-    }
-  }
-  buffering_ = false;
-  return false;
-}
-
-bool ResourceDispatcherHost::BufferedEventHandler::CompleteResponseStarted(
-    int request_id,
-    bool in_complete) {
-  // Check to see if we should forward the data from this request to the
-  // download thread.
-  // TODO(paulg): Only download if the context from the renderer allows it.
-  std::string content_disposition;
-  request_->GetResponseHeaderByName("content-disposition",
-                                    &content_disposition);
-
-  ResourceDispatcherHost::ExtraRequestInfo* info =
-      ResourceDispatcherHost::ExtraInfoForRequest(request_);
-
-  if (info->allow_download &&
-      host_->ShouldDownload(response_->response_head.mime_type,
-                            content_disposition)) {
-    if (response_->response_head.headers &&  // Can be NULL if FTP.
-        response_->response_head.headers->response_code() / 100 != 2) {
-      // The response code indicates that this is an error page, but we don't
-      // know how to display the content.  We follow Firefox here and show our
-      // own error page instead of triggering a download.
-      // TODO(abarth): We should abstract the response_code test, but this kind
-      //               of check is scattered throughout our codebase.
-      request_->CancelWithError(net::ERR_FILE_NOT_FOUND);
-      return false;
-    }
-
-    info->is_download = true;
-
-    scoped_refptr<DownloadThrottlingEventHandler> download_handler =
-        new DownloadThrottlingEventHandler(host_,
-                                           request_,
-                                           request_->url().spec(),
-                                           info->render_process_host_id,
-                                           info->render_view_id,
-                                           request_id,
-                                           in_complete);
-    if (bytes_read_) {
-      // a Read has already occurred and we need to copy the data into the
-      // EventHandler.
-      char *buf = NULL;
-      int buf_len = 0;
-      download_handler->OnWillRead(request_id, &buf, &buf_len, bytes_read_);
-      CHECK((buf_len >= bytes_read_) && (bytes_read_ >= 0));
-      memcpy(buf, read_buffer_, bytes_read_);
-    }
-    // Update the renderer with the response headers which will cause it to
-    // cancel the request.
-    // TODO(paulg): Send the renderer a response that indicates that the request
-    //              will be handled by an external source (the browser).
-    real_handler_->OnResponseStarted(info->request_id, response_);
-    real_handler_ = download_handler;
-  }
-  return real_handler_->OnResponseStarted(request_id, response_);
-}
-
-namespace {
-
-// Consults the RendererSecurity policy to determine whether the
-// ResourceDispatcherHost should service this request.  A request might be
-// disallowed if the renderer is not authorized to restrive the request URL or
-// if the renderer is attempting to upload an unauthorized file.
-bool ShouldServiceRequest(int render_process_host_id,
-                          const ViewHostMsg_Resource_Request& request_data)  {
-  // TODO(mpcomplete): remove this when http://b/viewIssue?id=1080959 is fixed.
-  if (render_process_host_id == -1)
-    return true;
-
-  RendererSecurityPolicy* policy = RendererSecurityPolicy::GetInstance();
-
-  // Check if the renderer is permitted to request the requested URL.
-  if (!policy->CanRequestURL(render_process_host_id, request_data.url)) {
-    LOG(INFO) << "Denied unauthorized request for " <<
-        request_data.url.possibly_invalid_spec();
-    return false;
-  }
-
-  // Check if the renderer is permitted to upload the requested files.
-  const std::vector<net::UploadData::Element>& uploads =
-      request_data.upload_content;
-  for (std::vector<net::UploadData::Element>::const_iterator iter(uploads.begin());
-      iter != uploads.end(); ++iter) {
-    if (iter->type() == net::UploadData::TYPE_FILE &&
-        !policy->CanUploadFile(render_process_host_id, iter->file_path())) {
-      NOTREACHED() << "Denied unauthorized upload of " << iter->file_path();
-      return false;
-    }
-  }
-
-  return true;
-}
-
-}  // namespace
-
-// ----------------------------------------------------------------------------
-// ResourceDispatcherHost::SaveFileEventHandler
-// Forwards data to the save thread.
-class ResourceDispatcherHost::SaveFileEventHandler
-    : public ResourceDispatcherHost::EventHandler {
- public:
-  SaveFileEventHandler(int render_process_host_id,
-                       int render_view_id,
-                       const std::string& url,
-                       SaveFileManager* manager)
-      : save_id_(-1),
-        render_process_id_(render_process_host_id),
-        render_view_id_(render_view_id),
-        read_buffer_(NULL),
-        url_(UTF8ToWide(url)),
-        content_length_(0),
-        save_manager_(manager) {
-  }
-
-  // Save the redirected URL to final_url_, we need to use the original
-  // URL to match original request.
-  bool OnRequestRedirected(int request_id, const GURL& url) {
-    final_url_ = UTF8ToWide(url.spec());
-    return true;
-  }
-
-  // Send the download creation information to the download thread.
-  bool OnResponseStarted(int request_id, Response* response) {
-    save_id_ = save_manager_->GetNextId();
-    // |save_manager_| consumes (deletes):
-    SaveFileCreateInfo* info = new SaveFileCreateInfo;
-    info->url = url_;
-    info->final_url = final_url_;
-    info->total_bytes = content_length_;
-    info->save_id = save_id_;
-    info->render_process_id = render_process_id_;
-    info->render_view_id = render_view_id_;
-    info->request_id = request_id;
-    info->content_disposition = content_disposition_;
-    info->save_source = SaveFileCreateInfo::SAVE_FILE_FROM_NET;
-    save_manager_->GetSaveLoop()->PostTask(FROM_HERE,
-        NewRunnableMethod(save_manager_,
-                          &SaveFileManager::StartSave,
-                          info));
-    return true;
-  }
-
-  // Create a new buffer, which will be handed to the download thread for file
-  // writing and deletion.
-  bool OnWillRead(int request_id, char** buf, int* buf_size, int min_size) {
-    DCHECK(buf && buf_size);
-    if (!read_buffer_) {
-      *buf_size = min_size < 0 ? kReadBufSize : min_size;
-      read_buffer_ = new char[*buf_size];
-    }
-    *buf = read_buffer_;
-    return true;
-  }
-
-  // Pass the buffer to the download file writer.
-  bool OnReadCompleted(int request_id, int* bytes_read) {
-    DCHECK(read_buffer_);
-    save_manager_->GetSaveLoop()->PostTask(FROM_HERE,
-        NewRunnableMethod(save_manager_,
-                          &SaveFileManager::UpdateSaveProgress,
-                          save_id_,
-                          read_buffer_,
-                          *bytes_read));
-    read_buffer_ = NULL;
-    return true;
-  }
-
-  bool OnResponseCompleted(int request_id, const URLRequestStatus& status) {
-    save_manager_->GetSaveLoop()->PostTask(FROM_HERE,
-        NewRunnableMethod(save_manager_,
-                          &SaveFileManager::SaveFinished,
-                          save_id_,
-                          url_,
-                          render_process_id_,
-                          status.is_success() && !status.is_io_pending()));
-    delete [] read_buffer_;
-    return true;
-  }
-
-  // If the content-length header is not present (or contains something other
-  // than numbers), StringToInt64 returns 0, which indicates 'unknown size' and
-  // is handled correctly by the SaveManager.
-  void set_content_length(const std::string& content_length) {
-    content_length_ = StringToInt64(content_length);
-  }
-
-  void set_content_disposition(const std::string& content_disposition) {
-    content_disposition_ = content_disposition;
-  }
-
- private:
-  int save_id_;
-  int render_process_id_;
-  int render_view_id_;
-  char* read_buffer_;
-  std::string content_disposition_;
-  std::wstring url_;
-  std::wstring final_url_;
-  int64 content_length_;
-  SaveFileManager* save_manager_;
-
-  static const int kReadBufSize = 32768;  // bytes
-
-  DISALLOW_EVIL_CONSTRUCTORS(SaveFileEventHandler);
-};
-
-// ----------------------------------------------------------------------------
-// ResourceDispatcherHost
-
-ResourceDispatcherHost::ResourceDispatcherHost(MessageLoop* io_loop)
-    : ui_loop_(MessageLoop::current()),
-      io_loop_(io_loop),
-      download_file_manager_(new DownloadFileManager(ui_loop_, this)),
-      download_request_manager_(new DownloadRequestManager(io_loop, ui_loop_)),
-      save_file_manager_(new SaveFileManager(ui_loop_, io_loop, this)),
-      safe_browsing_(new SafeBrowsingService),
-      request_id_(-1),
-      plugin_service_(PluginService::GetInstance()),
-      method_runner_(this),
-      is_shutdown_(false) {
-}
-
-ResourceDispatcherHost::~ResourceDispatcherHost() {
-  AsyncEventHandler::GlobalCleanup();
-  STLDeleteValues(&pending_requests_);
-}
-
-void ResourceDispatcherHost::Initialize() {
-  DCHECK(MessageLoop::current() == ui_loop_);
-  download_file_manager_->Initialize();
-  safe_browsing_->Initialize(io_loop_);
-}
-
-// A ShutdownTask proxies a shutdown task from the UI thread to the IO thread.
-// It should be constructed on the UI thread and run in the IO thread.
-class ResourceDispatcherHost::ShutdownTask : public Task {
- public:
-  explicit ShutdownTask(ResourceDispatcherHost* resource_dispatcher_host)
-      : rdh_(resource_dispatcher_host) { }
-
-  void Run() {
-    rdh_->OnShutdown();
-  }
-
- private:
-  ResourceDispatcherHost* rdh_;
-};
-
-void ResourceDispatcherHost::Shutdown() {
-  DCHECK(MessageLoop::current() == ui_loop_);
-  io_loop_->PostTask(FROM_HERE, new ShutdownTask(this));
-}
-
-void ResourceDispatcherHost::OnShutdown() {
-  DCHECK(MessageLoop::current() == io_loop_);
-  is_shutdown_ = true;
-  STLDeleteValues(&pending_requests_);
-  // Make sure we shutdown the timer now, otherwise by the time our destructor
-  // runs if the timer is still running the Task is deleted twice (once by
-  // the MessageLoop and the second time by RepeatingTimer).
-  update_load_states_timer_.Stop();
-}
-
-bool ResourceDispatcherHost::HandleExternalProtocol(int request_id,
-                                                    int render_process_host_id,
-                                                    int tab_contents_id,
-                                                    const GURL& url,
-                                                    ResourceType::Type type,
-                                                    EventHandler* handler) {
-  if (!ResourceType::IsFrame(type) || URLRequest::IsHandledURL(url))
-    return false;
-
-  ui_loop_->PostTask(FROM_HERE, NewRunnableFunction(
-      &ExternalProtocolHandler::LaunchUrl, url, render_process_host_id,
-      tab_contents_id));
-
-  handler->OnResponseCompleted(request_id, URLRequestStatus(
-                                               URLRequestStatus::FAILED,
-                                               net::ERR_ABORTED));
-  return true;
-}
-
-void ResourceDispatcherHost::BeginRequest(
-    Receiver* receiver,
-    HANDLE render_process_handle,
-    int render_process_host_id,
-    int render_view_id,
-    int request_id,
-    const ViewHostMsg_Resource_Request& request_data,
-    URLRequestContext* request_context,
-    IPC::Message* sync_result) {
-  if (is_shutdown_ ||
-      !ShouldServiceRequest(render_process_host_id, request_data)) {
-    // Tell the renderer that this request was disallowed.
-    receiver->Send(new ViewMsg_Resource_RequestComplete(
-        render_view_id,
-        request_id,
-        URLRequestStatus(URLRequestStatus::FAILED, net::ERR_ABORTED)));
-    return;
-  }
-
-  // Ensure the Chrome plugins are loaded, as they may intercept network
-  // requests.  Does nothing if they are already loaded.
-  // TODO(mpcomplete): This takes 200 ms!  Investigate parallelizing this by
-  // starting the load earlier in a BG thread.
-  plugin_service_->LoadChromePlugins(this);
-
-  // Construct the event handler.
-  scoped_refptr<EventHandler> handler;
-  if (sync_result) {
-    handler = new SyncEventHandler(receiver, request_data.url, sync_result);
-  } else {
-    handler = new AsyncEventHandler(receiver,
-                                    render_process_host_id,
-                                    render_view_id,
-                                    render_process_handle,
-                                    request_data.url,
-                                    this);
-  }
-
-  if (HandleExternalProtocol(request_id, render_process_host_id, render_view_id,
-                             request_data.url, request_data.resource_type,
-                             handler)) {
-    return;
-  }
-
-  // Construct the request.
-  URLRequest* request = new URLRequest(request_data.url, this);
-  request->set_method(request_data.method);
-  request->set_policy_url(request_data.policy_url);
-  request->set_referrer(request_data.referrer.spec());
-  request->SetExtraRequestHeaders(request_data.headers);
-  request->set_load_flags(request_data.load_flags);
-  request->set_context(request_context);
-  request->set_origin_pid(request_data.origin_pid);
-
-  // Set upload data.
-  uint64 upload_size = 0;
-  if (!request_data.upload_content.empty()) {
-    scoped_refptr<net::UploadData> upload = new net::UploadData();
-    upload->set_elements(request_data.upload_content);  // Deep copy.
-    request->set_upload(upload);
-    upload_size = upload->GetContentLength();
-  }
-
-  // Install a CrossSiteEventHandler if this request is coming from a
-  // RenderViewHost with a pending cross-site request.  We only check this for
-  // MAIN_FRAME requests.
-  // TODO(mpcomplete): remove "render_process_host_id != -1"
-  //                   when http://b/viewIssue?id=1080959 is fixed.
-  if (request_data.resource_type == ResourceType::MAIN_FRAME &&
-      render_process_host_id != -1 &&
-      Singleton<CrossSiteRequestManager>::get()->
-          HasPendingCrossSiteRequest(render_process_host_id, render_view_id)) {
-    // Wrap the event handler to be sure the current page's onunload handler
-    // has a chance to run before we render the new page.
-    handler = new CrossSiteEventHandler(handler,
-                                        render_process_host_id,
-                                        render_view_id,
-                                        this);
-  }
-
-  if (safe_browsing_->enabled() &&
-      safe_browsing_->CanCheckUrl(request_data.url)) {
-    handler = new SafeBrowsingEventHandler(handler,
-                                           render_process_host_id,
-                                           render_view_id,
-                                           request_data.url,
-                                           request_data.resource_type,
-                                           safe_browsing_,
-                                           this);
-  }
-
-  // Insert a buffered event handler before the actual one.
-  handler = new BufferedEventHandler(handler, this, request);
-
-  // Make extra info and read footer (contains request ID).
-  ExtraRequestInfo* extra_info =
-      new ExtraRequestInfo(handler,
-                           request_id,
-                           render_process_host_id,
-                           render_view_id,
-                           request_data.mixed_content,
-                           request_data.resource_type,
-                           upload_size);
-  extra_info->allow_download =
-      ResourceType::IsFrame(request_data.resource_type);
-  request->set_user_data(extra_info);  // takes pointer ownership
-
-  BeginRequestInternal(request, request_data.mixed_content);
-}
-
-// We are explicitly forcing the download of 'url'.
-void ResourceDispatcherHost::BeginDownload(const GURL& url,
-                                           const GURL& referrer,
-                                           int render_process_host_id,
-                                           int render_view_id,
-                                           URLRequestContext* request_context) {
-  if (is_shutdown_)
-    return;
-
-  if (!URLRequest::IsHandledURL(url))
-    return;
-
-  // Check if the renderer is permitted to request the requested URL.
-  //
-  // TODO(mpcomplete): remove "render_process_host_id != -1"
-  //                   when http://b/viewIssue?id=1080959 is fixed.
-  if (render_process_host_id != -1 &&
-      !RendererSecurityPolicy::GetInstance()->
-          CanRequestURL(render_process_host_id, url)) {
-    LOG(INFO) << "Denied unauthorized download request for " <<
-        url.possibly_invalid_spec();
-    return;
-  }
-
-  // Ensure the Chrome plugins are loaded, as they may intercept network
-  // requests.  Does nothing if they are already loaded.
-  plugin_service_->LoadChromePlugins(this);
-  URLRequest* request = new URLRequest(url, this);
-
-  request_id_--;
-
-  scoped_refptr<EventHandler> handler =
-      new DownloadEventHandler(this,
-                               render_process_host_id,
-                               render_view_id,
-                               request_id_,
-                               url.spec(),
-                               download_file_manager_.get(),
-                               request,
-                               true);
-
-
-  if (safe_browsing_->enabled() && safe_browsing_->CanCheckUrl(url)) {
-    handler = new SafeBrowsingEventHandler(handler,
-                                           render_process_host_id,
-                                           render_view_id,
-                                           url,
-                                           ResourceType::MAIN_FRAME,
-                                           safe_browsing_,
-                                           this);
-  }
-
-  request->set_method("GET");
-  request->set_referrer(referrer.spec());
-  request->set_context(request_context);
-
-  ExtraRequestInfo* extra_info =
-      new ExtraRequestInfo(handler,
-                           request_id_,
-                           render_process_host_id,
-                           render_view_id,
-                           false,  // Downloads are not considered mixed-content
-                           ResourceType::SUB_RESOURCE,
-                           0 /* upload_size */ );
-  extra_info->allow_download = true;
-  extra_info->is_download = true;
-  request->set_user_data(extra_info);  // Takes pointer ownership.
-
-  BeginRequestInternal(request, false);
-}
-
-// This function is only used for saving feature.
-void ResourceDispatcherHost::BeginSaveFile(const GURL& url,
-                                           const GURL& referrer,
-                                           int render_process_host_id,
-                                           int render_view_id,
-                                           URLRequestContext* request_context) {
-  if (is_shutdown_)
-    return;
-
-  // Ensure the Chrome plugins are loaded, as they may intercept network
-  // requests.  Does nothing if they are already loaded.
-  plugin_service_->LoadChromePlugins(this);
-
-  scoped_refptr<EventHandler> handler =
-      new SaveFileEventHandler(render_process_host_id,
-                               render_view_id,
-                               url.spec(),
-                               save_file_manager_.get());
-  request_id_--;
-
-  bool known_proto = URLRequest::IsHandledURL(url);
-  if (!known_proto) {
-    // Since any URLs which have non-standard scheme have been filtered
-    // by save manager(see GURL::SchemeIsStandard). This situation
-    // should not happen.
-    NOTREACHED();
-    return;
-  }
-
-  URLRequest* request = new URLRequest(url, this);
-  request->set_method("GET");
-  request->set_referrer(referrer.spec());
-  // So far, for saving page, we need fetch content from cache, in the
-  // future, maybe we can use a configuration to configure this behavior.
-  request->set_load_flags(net::LOAD_ONLY_FROM_CACHE);
-  request->set_context(request_context);
-
-  ExtraRequestInfo* extra_info =
-      new ExtraRequestInfo(handler,
-                           request_id_,
-                           render_process_host_id,
-                           render_view_id,
-                           false,
-                           ResourceType::SUB_RESOURCE,
-                           0 /* upload_size */);
-  // Just saving some resources we need, disallow downloading.
-  extra_info->allow_download = false;
-  extra_info->is_download = false;
-  request->set_user_data(extra_info);  // Takes pointer ownership.
-
-  BeginRequestInternal(request, false);
-}
-
-void ResourceDispatcherHost::CancelRequest(int render_process_host_id,
-                                           int request_id,
-                                           bool from_renderer) {
-  CancelRequest(render_process_host_id, request_id, from_renderer, true);
-}
-
-void ResourceDispatcherHost::CancelRequest(int render_process_host_id,
-                                           int request_id,
-                                           bool from_renderer,
-                                           bool allow_delete) {
-  PendingRequestList::iterator i = pending_requests_.find(
-      GlobalRequestID(render_process_host_id, request_id));
-  if (i == pending_requests_.end()) {
-    // We probably want to remove this warning eventually, but I wanted to be
-    // able to notice when this happens during initial development since it
-    // should be rare and may indicate a bug.
-    DLOG(WARNING) << "Canceling a request that wasn't found";
-    return;
-  }
-
-  // WebKit will send us a cancel for downloads since it no longer handles them.
-  // In this case, ignore the cancel since we handle downloads in the browser.
-  ExtraRequestInfo* info = ExtraInfoForRequest(i->second);
-  if (!from_renderer || !info->is_download) {
-    if (info->login_handler) {
-      info->login_handler->OnRequestCancelled();
-      info->login_handler = NULL;
-    }
-    if (!i->second->is_pending() && allow_delete) {
-      // No io is pending, canceling the request won't notify us of anything,
-      // so we explicitly remove it.
-      // TODO: removing the request in this manner means we're not notifying
-      // anyone. We need make sure the event handlers and others are notified
-      // so that everything is cleaned up properly.
-      RemovePendingRequest(info->render_process_host_id, info->request_id);
-    } else {
-      i->second->Cancel();
-    }
-  }
-
-  // Do not remove from the pending requests, as the request will still
-  // call AllDataReceived, and may even have more data before it does
-  // that.
-}
-
-void ResourceDispatcherHost::OnDataReceivedACK(int render_process_host_id,
-                                               int request_id) {
-  PendingRequestList::iterator i = pending_requests_.find(
-      GlobalRequestID(render_process_host_id, request_id));
-  if (i == pending_requests_.end())
-    return;
-
-  ExtraRequestInfo* info = ExtraInfoForRequest(i->second);
-
-  // Decrement the number of pending data messages.
-  info->pending_data_count--;
-
-  // If the pending data count was higher than the max, resume the request.
-  if (info->pending_data_count == kMaxPendingDataMessages) {
-    // Decrement the pending data count one more time because we also
-    // incremented it before pausing the request.
-    info->pending_data_count--;
-
-    // Resume the request.
-    PauseRequest(render_process_host_id, request_id, false);
-  }
-}
-
-void ResourceDispatcherHost::OnUploadProgressACK(int render_process_host_id,
-                                                 int request_id) {
-  PendingRequestList::iterator i = pending_requests_.find(
-      GlobalRequestID(render_process_host_id, request_id));
-  if (i == pending_requests_.end())
-    return;
-
-  ExtraRequestInfo* info = ExtraInfoForRequest(i->second);
-  info->waiting_for_upload_progress_ack = false;
-}
-
-bool ResourceDispatcherHost::WillSendData(int render_process_host_id,
-                                          int request_id) {
-  PendingRequestList::iterator i = pending_requests_.find(
-      GlobalRequestID(render_process_host_id, request_id));
-  if (i == pending_requests_.end()) {
-    NOTREACHED() << L"WillSendData for invalid request";
-    return false;
-  }
-
-  ExtraRequestInfo* info = ExtraInfoForRequest(i->second);
-
-  info->pending_data_count++;
-  if (info->pending_data_count > kMaxPendingDataMessages) {
-    // We reached the max number of data messages that can be sent to
-    // the renderer for a given request. Pause the request and wait for
-    // the renderer to start processing them before resuming it.
-    PauseRequest(render_process_host_id, request_id, true);
-    return false;
-  }
-
-  return true;
-}
-
-void ResourceDispatcherHost::PauseRequest(int render_process_host_id,
-                                          int request_id,
-                                          bool pause) {
-  GlobalRequestID global_id(render_process_host_id, request_id);
-  PendingRequestList::iterator i = pending_requests_.find(global_id);
-  if (i == pending_requests_.end()) {
-    DLOG(WARNING) << "Pausing a request that wasn't found";
-    return;
-  }
-
-  ExtraRequestInfo* info = ExtraInfoForRequest(i->second);
-
-  int pause_count = info->pause_count + (pause ? 1 : -1);
-  if (pause_count < 0) {
-    NOTREACHED();  // Unbalanced call to pause.
-    return;
-  }
-  info->pause_count = pause_count;
-
-  RESOURCE_LOG("To pause (" << pause << "): " << i->second->url().spec());
-
-  // If we're resuming, kick the request to start reading again. Run the read
-  // asynchronously to avoid recursion problems.
-  if (info->pause_count == 0) {
-    MessageLoop::current()->PostTask(FROM_HERE,
-        method_runner_.NewRunnableMethod(
-            &ResourceDispatcherHost::ResumeRequest, global_id));
-  }
-}
-
-void ResourceDispatcherHost::OnClosePageACK(int render_process_host_id,
-                                            int request_id) {
-  GlobalRequestID global_id(render_process_host_id, request_id);
-  PendingRequestList::iterator i = pending_requests_.find(global_id);
-  if (i == pending_requests_.end()) {
-    // If there are no matching pending requests, then this is not a
-    // cross-site navigation and we are just closing the tab/browser.
-    ui_loop_->PostTask(FROM_HERE, NewRunnableFunction(
-        &RenderViewHost::ClosePageIgnoringUnloadEvents,
-        render_process_host_id,
-        request_id));
-    return;
-  }
-
-  ExtraRequestInfo* info = ExtraInfoForRequest(i->second);
-  if (info->cross_site_handler) {
-    info->cross_site_handler->ResumeResponse();
-  }
-}
-
-// The object died, so cancel and detach all requests associated with it except
-// for downloads, which belong to the browser process even if initiated via a
-// renderer.
-void ResourceDispatcherHost::CancelRequestsForProcess(
-    int render_process_host_id) {
-  CancelRequestsForRenderView(render_process_host_id, -1 /* cancel all */);
-}
-
-void ResourceDispatcherHost::CancelRequestsForRenderView(
-    int render_process_host_id,
-    int render_view_id) {
-  // Since pending_requests_ is a map, we first build up a list of all of the
-  // matching requests to be cancelled, and then we cancel them.  Since there
-  // may be more than one request to cancel, we cannot simply hold onto the map
-  // iterators found in the first loop.
-
-  // Find the global ID of all matching elements.
-  std::vector<GlobalRequestID> matching_requests;
-  for (PendingRequestList::const_iterator i = pending_requests_.begin();
-       i != pending_requests_.end(); ++i) {
-    if (i->first.render_process_host_id == render_process_host_id) {
-      ExtraRequestInfo* info = ExtraInfoForRequest(i->second);
-      if (!info->is_download && (render_view_id == -1 ||
-                                 render_view_id == info->render_view_id)) {
-        matching_requests.push_back(i->first);
-      }
-    }
-  }
-
-  // Remove matches.
-  for (size_t i = 0; i < matching_requests.size(); ++i) {
-    PendingRequestList::iterator iter =
-        pending_requests_.find(matching_requests[i]);
-    // Although every matching request was in pending_requests_ when we built
-    // matching_requests, it is normal for a matching request to be not found
-    // in pending_requests_ after we have removed some matching requests from
-    // pending_requests_.  For example, deleting a URLRequest that has
-    // exclusive (write) access to an HTTP cache entry may unblock another
-    // URLRequest that needs exclusive access to the same cache entry, and
-    // that URLRequest may complete and remove itself from pending_requests_.
-    // So we need to check that iter is not equal to pending_requests_.end().
-    if (iter != pending_requests_.end())
-      RemovePendingRequest(iter);
-  }
-}
-
-// Cancels the request and removes it from the list.
-void ResourceDispatcherHost::RemovePendingRequest(int render_process_host_id,
-                                                  int request_id) {
-  PendingRequestList::iterator i = pending_requests_.find(
-      GlobalRequestID(render_process_host_id, request_id));
-  if (i == pending_requests_.end()) {
-    NOTREACHED() << "Trying to remove a request that's not here";
-    return;
-  }
-  RemovePendingRequest(i);
-}
-
-void ResourceDispatcherHost::RemovePendingRequest(
-    const PendingRequestList::iterator& iter) {
-  // Notify the login handler that this request object is going away.
-  ExtraRequestInfo* info = ExtraInfoForRequest(iter->second);
-  if (info && info->login_handler)
-    info->login_handler->OnRequestCancelled();
-
-  delete iter->second;
-  pending_requests_.erase(iter);
-
-  // If we have no more pending requests, then stop the load state monitor
-  if (pending_requests_.empty())
-    update_load_states_timer_.Stop();
-}
-
-// URLRequest::Delegate -------------------------------------------------------
-
-void ResourceDispatcherHost::OnReceivedRedirect(URLRequest* request,
-                                                const GURL& new_url) {
-  RESOURCE_LOG("OnReceivedRedirect: " << request->url().spec());
-  ExtraRequestInfo* info = ExtraInfoForRequest(request);
-
-  DCHECK(request->status().is_success());
-
-  // TODO(mpcomplete): remove this when http://b/viewIssue?id=1080959 is fixed.
-  if (info->render_process_host_id != -1 &&
-      !RendererSecurityPolicy::GetInstance()->
-          CanRequestURL(info->render_process_host_id, new_url)) {
-    LOG(INFO) << "Denied unauthorized request for " <<
-        new_url.possibly_invalid_spec();
-
-    // Tell the renderer that this request was disallowed.
-    CancelRequest(info->render_process_host_id, info->request_id, false);
-    return;
-  }
-
-  NofityReceivedRedirect(request, info->render_process_host_id, new_url);
-
-  if (HandleExternalProtocol(info->request_id, info->render_process_host_id,
-                             info->render_view_id, new_url,
-                             info->resource_type, info->event_handler)) {
-    // The request is complete so we can remove it.
-    RemovePendingRequest(info->render_process_host_id, info->request_id);
-    return;
-  }
-
-  if (!info->event_handler->OnRequestRedirected(info->request_id, new_url))
-    CancelRequest(info->render_process_host_id, info->request_id, false);
-}
-
-void ResourceDispatcherHost::OnAuthRequired(
-    URLRequest* request,
-    net::AuthChallengeInfo* auth_info) {
-  // Create a login dialog on the UI thread to get authentication data,
-  // or pull from cache and continue on the IO thread.
-  // TODO(mpcomplete): We should block the parent tab while waiting for
-  // authentication.
-  // That would also solve the problem of the URLRequest being cancelled
-  // before we receive authentication.
-  ExtraRequestInfo* info = ExtraInfoForRequest(request);
-  DCHECK(!info->login_handler) <<
-      "OnAuthRequired called with login_handler pending";
-  info->login_handler = CreateLoginPrompt(auth_info, request, ui_loop_);
-}
-
-void ResourceDispatcherHost::OnSSLCertificateError(
-    URLRequest* request,
-    int cert_error,
-    net::X509Certificate* cert) {
-  DCHECK(request);
-  SSLManager::OnSSLCertificateError(this, request, cert_error, cert, ui_loop_);
-}
-
-void ResourceDispatcherHost::OnResponseStarted(URLRequest* request) {
-  RESOURCE_LOG("OnResponseStarted: " << request->url().spec());
-  ExtraRequestInfo* info = ExtraInfoForRequest(request);
-  if (PauseRequestIfNeeded(info)) {
-    RESOURCE_LOG("OnResponseStarted pausing: " << request->url().spec());
-    return;
-  }
-
-  if (request->status().is_success()) {
-    // We want to send a final upload progress message prior to sending
-    // the response complete message even if we're waiting for an ack to
-    // to a previous upload progress message.
-    info->waiting_for_upload_progress_ack = false;
-    MaybeUpdateUploadProgress(info, request);
-
-    if (!CompleteResponseStarted(request)) {
-      CancelRequest(info->render_process_host_id, info->request_id, false);
-    } else {
-      // Start reading.
-      int bytes_read = 0;
-      if (Read(request, &bytes_read)) {
-        OnReadCompleted(request, bytes_read);
-      } else if (!request->status().is_io_pending()) {
-        DCHECK(!info->is_paused);
-        // If the error is not an IO pending, then we're done reading.
-        OnResponseCompleted(request);
-      }
-    }
-  } else {
-    OnResponseCompleted(request);
-  }
-}
-
-bool ResourceDispatcherHost::CompleteResponseStarted(URLRequest* request) {
-  ExtraRequestInfo* info = ExtraInfoForRequest(request);
-
-  scoped_refptr<Response> response(new Response);
-
-  response->response_head.status = request->status();
-  response->response_head.request_time = request->request_time();
-  response->response_head.response_time = request->response_time();
-  response->response_head.headers = request->response_headers();
-  request->GetCharset(&response->response_head.charset);
-  response->response_head.filter_policy = info->filter_policy;
-  response->response_head.content_length = request->GetExpectedContentSize();
-  request->GetMimeType(&response->response_head.mime_type);
-
-  if (request->ssl_info().cert) {
-    int cert_id =
-        CertStore::GetSharedInstance()->StoreCert(
-            request->ssl_info().cert,
-            info->render_process_host_id);
-    int cert_status = request->ssl_info().cert_status;
-    // EV certificate verification could be expensive.  We don't want to spend
-    // time performing EV certificate verification on all resources because
-    // EV status is irrelevant to sub-frames and sub-resources.  So we call
-    // IsEV here rather than in the network layer because the network layer
-    // doesn't know the resource type.
-    if (info->resource_type == ResourceType::MAIN_FRAME &&
-        request->ssl_info().cert->IsEV(cert_status))
-      cert_status |= net::CERT_STATUS_IS_EV;
-
-    response->response_head.security_info =
-        SSLManager::SerializeSecurityInfo(cert_id,
-                                          cert_status,
-                                          request->ssl_info().security_bits);
-  } else {
-    // We should not have any SSL state.
-    DCHECK(!request->ssl_info().cert_status &&
-           (request->ssl_info().security_bits == -1 ||
-           request->ssl_info().security_bits == 0));
-  }
-
-  NotifyResponseStarted(request, info->render_process_host_id);
-  return info->event_handler->OnResponseStarted(info->request_id,
-                                                response.get());
-}
-
-void ResourceDispatcherHost::BeginRequestInternal(URLRequest* request,
-                                                  bool mixed_content) {
-  ExtraRequestInfo* info = ExtraInfoForRequest(request);
-  GlobalRequestID global_id(info->render_process_host_id, info->request_id);
-  pending_requests_[global_id] = request;
-  if (mixed_content) {
-    // We don't start the request in that case.  The SSLManager will potentially
-    // change the request (potentially to indicate its content should be
-    // filtered) and start it itself.
-    SSLManager::OnMixedContentRequest(this, request, ui_loop_);
-    return;
-  }
-  request->Start();
-
-  // Make sure we have the load state monitor running
-  if (!update_load_states_timer_.IsRunning()) {
-    update_load_states_timer_.Start(
-        TimeDelta::FromMilliseconds(kUpdateLoadStatesIntervalMsec),
-        this, &ResourceDispatcherHost::UpdateLoadStates);
-  }
-}
-
-// This test mirrors the decision that WebKit makes in
-// WebFrameLoaderClient::dispatchDecidePolicyForMIMEType.
-// static.
-bool ResourceDispatcherHost::ShouldDownload(
-    const std::string& mime_type, const std::string& content_disposition) {
-  std::string type = StringToLowerASCII(mime_type);
-  std::string disposition = StringToLowerASCII(content_disposition);
-
-  // First, examine content-disposition.
-  if (!disposition.empty()) {
-    bool should_download = true;
-
-    // Some broken sites just send ...
-    //    Content-Disposition: ; filename="file"
-    // ... screen those out here.
-    if (disposition[0] == ';')
-      should_download = false;
-
-    if (disposition.compare(0, 6, "inline") == 0)
-      should_download = false;
-
-    // Some broken sites just send ...
-    //    Content-Disposition: filename="file"
-    // ... without a disposition token... Screen those out.
-    if (disposition.compare(0, 8, "filename") == 0)
-      should_download = false;
-
-    // Also in use is Content-Disposition: name="file"
-    if (disposition.compare(0, 4, "name") == 0)
-      should_download = false;
-
-    // We have a content-disposition of "attachment" or unknown.
-    // RFC 2183, section 2.8 says that an unknown disposition
-    // value should be treated as "attachment".
-    if (should_download)
-      return true;
-  }
-
-  // MIME type checking.
-  if (net::IsSupportedMimeType(type))
-    return false;
-
-  // Finally, check the plugin service.
-  bool allow_wildcard = false;
-  return !plugin_service_->HavePluginFor(type, allow_wildcard);
-}
-
-bool ResourceDispatcherHost::PauseRequestIfNeeded(ExtraRequestInfo* info) {
-  if (info->pause_count > 0)
-    info->is_paused = true;
-
-  return info->is_paused;
-}
-
-void ResourceDispatcherHost::ResumeRequest(const GlobalRequestID& request_id) {
-  PendingRequestList::iterator i = pending_requests_.find(request_id);
-  if (i == pending_requests_.end())  // The request may have been destroyed
-    return;
-
-  URLRequest* request = i->second;
-  ExtraRequestInfo* info = ExtraInfoForRequest(request);
-  if (!info->is_paused)
-    return;
-
-  RESOURCE_LOG("Resuming: " << i->second->url().spec());
-
-  info->is_paused = false;
-
-  if (info->has_started_reading)
-    OnReadCompleted(i->second, info->paused_read_bytes);
-  else
-    OnResponseStarted(i->second);
-}
-
-bool ResourceDispatcherHost::Read(URLRequest* request, int* bytes_read) {
-  ExtraRequestInfo* info = ExtraInfoForRequest(request);
-  DCHECK(!info->is_paused);
-
-  char* buf;
-  int buf_size;
-  if (!info->event_handler->OnWillRead(info->request_id, &buf, &buf_size, -1))
-    return false;
-
-  DCHECK(buf);
-  DCHECK(buf_size > 0);
-
-  info->has_started_reading = true;
-  return request->Read(buf, buf_size, bytes_read);
-}
-
-void ResourceDispatcherHost::OnReadCompleted(URLRequest* request,
-                                             int bytes_read) {
-  DCHECK(request);
-  RESOURCE_LOG("OnReadCompleted: " << request->url().spec());
-  ExtraRequestInfo* info = ExtraInfoForRequest(request);
-  if (PauseRequestIfNeeded(info)) {
-    info->paused_read_bytes = bytes_read;
-    RESOURCE_LOG("OnReadCompleted pausing: " << request->url().spec());
-    return;
-  }
-
-  if (request->status().is_success() && CompleteRead(request, &bytes_read)) {
-    // The request can be paused if we realize that the renderer is not
-    // servicing messages fast enough.
-    if (info->pause_count == 0 &&
-        Read(request, &bytes_read) &&
-        request->status().is_success()) {
-      if (bytes_read == 0) {
-        CompleteRead(request, &bytes_read);
-      } else {
-        // Force the next CompleteRead / Read pair to run as a separate task.
-        // This avoids a fast, large network request from monopolizing the IO
-        // thread and starving other IO operations from running.
-        info->paused_read_bytes = bytes_read;
-        info->is_paused = true;
-        GlobalRequestID id(info->render_process_host_id, info->request_id);
-        MessageLoop::current()->PostTask(
-            FROM_HERE,
-            method_runner_.NewRunnableMethod(
-                &ResourceDispatcherHost::ResumeRequest, id));
-        return;
-      }
-    }
-  }
-
-  if (PauseRequestIfNeeded(info)) {
-    info->paused_read_bytes = bytes_read;
-    RESOURCE_LOG("OnReadCompleted (CompleteRead) pausing: " <<
-                 request->url().spec());
-    return;
-  }
-
-  // If the status is not IO pending then we've either finished (success) or we
-  // had an error.  Either way, we're done!
-  if (!request->status().is_io_pending())
-    OnResponseCompleted(request);
-}
-
-bool ResourceDispatcherHost::CompleteRead(URLRequest* request,
-                                          int* bytes_read) {
-  if (!request->status().is_success()) {
-    NOTREACHED();
-    return false;
-  }
-
-  ExtraRequestInfo* info = ExtraInfoForRequest(request);
-
-  if (!info->event_handler->OnReadCompleted(info->request_id, bytes_read)) {
-    // Pass in false as the last arg to indicate we don't want |request|
-    // deleted. We do this as callers of us assume |request| is valid after we
-    // return.
-    CancelRequest(info->render_process_host_id, info->request_id, false, false);
-    return false;
-  }
-
-  return *bytes_read != 0;
-}
-
-void ResourceDispatcherHost::OnResponseCompleted(URLRequest* request) {
-  RESOURCE_LOG("OnResponseCompleted: " << request->url().spec());
-  ExtraRequestInfo* info = ExtraInfoForRequest(request);
-
-  if (info->event_handler->OnResponseCompleted(info->request_id,
-                                               request->status())) {
-    NotifyResponseCompleted(request, info->render_process_host_id);
-
-    // The request is complete so we can remove it.
-    RemovePendingRequest(info->render_process_host_id, info->request_id);
-  }
-  // If the handler's OnResponseCompleted returns false, we are deferring the
-  // call until later.  We will notify the world and clean up when we resume.
-}
-
-void ResourceDispatcherHost::AddObserver(Observer* obs) {
-  observer_list_.AddObserver(obs);
-}
-
-void ResourceDispatcherHost::RemoveObserver(Observer* obs) {
-  observer_list_.RemoveObserver(obs);
-}
-
-URLRequest* ResourceDispatcherHost::GetURLRequest(
-    GlobalRequestID request_id) const {
-  // This should be running in the IO loop. io_loop_ can be NULL during the
-  // unit_tests.
-  DCHECK(MessageLoop::current() == io_loop_ && io_loop_);
-
-  PendingRequestList::const_iterator i = pending_requests_.find(request_id);
-  if (i == pending_requests_.end())
-    return NULL;
-
-  return i->second;
-}
-
-// A NotificationTask proxies a resource dispatcher notification from the IO
-// thread to the UI thread.  It should be constructed on the IO thread and run
-// in the UI thread.  Takes ownership of |details|.
-class NotificationTask : public Task {
- public:
-  NotificationTask(NotificationType type,
-                   URLRequest* request,
-                   ResourceRequestDetails* details)
-  : type_(type),
-    details_(details) {
-    if (!tab_util::GetTabContentsID(request,
-                                    &render_process_host_id_,
-                                    &tab_contents_id_))
-      NOTREACHED();
-  }
-
-  void Run() {
-    // Find the tab associated with this request.
-    WebContents* web_contents =
-        tab_util::GetWebContentsByID(render_process_host_id_, tab_contents_id_);
-
-    if (web_contents) {
-      // Issue the notification.
-      NotificationService::current()->
-          Notify(type_,
-                 Source<NavigationController>(web_contents->controller()),
-                 Details<ResourceRequestDetails>(details_.get()));
-    }
-  }
-
- private:
-  // These IDs let us find the correct tab on the UI thread.
-  int render_process_host_id_;
-  int tab_contents_id_;
-
-  // The type and details of the notification.
-  NotificationType type_;
-  scoped_ptr<ResourceRequestDetails> details_;
-};
-
-static int GetCertID(URLRequest* request, int render_process_host_id) {
-  if (request->ssl_info().cert) {
-    return CertStore::GetSharedInstance()->StoreCert(request->ssl_info().cert,
-                                                     render_process_host_id);
-  }
-  // If there is no SSL info attached to this request, we must either be a non
-  // secure request, or the request has been canceled or failed (before the SSL
-  // info was populated), or the response is an error (we have seen 403, 404,
-  // and 501) made up by the proxy.
-  DCHECK(!request->url().SchemeIsSecure() ||
-         (request->status().status() == URLRequestStatus::CANCELED) ||
-         (request->status().status() == URLRequestStatus::FAILED) ||
-         ((request->response_headers()->response_code() >= 400) &&
-         (request->response_headers()->response_code() <= 599)));
-  return 0;
-}
-
-void ResourceDispatcherHost::NotifyResponseStarted(URLRequest* request,
-                                                   int render_process_host_id) {
-  // Notify the observers on the IO thread.
-  FOR_EACH_OBSERVER(Observer, observer_list_, OnRequestStarted(this, request));
-
-  // Notify the observers on the UI thread.
-  ui_loop_->PostTask(FROM_HERE,
-      new NotificationTask(NOTIFY_RESOURCE_RESPONSE_STARTED, request,
-                           new ResourceRequestDetails(request,
-                               GetCertID(request, render_process_host_id))));
-}
-
-void ResourceDispatcherHost::NotifyResponseCompleted(
-    URLRequest* request,
-    int render_process_host_id) {
-  // Notify the observers on the IO thread.
-  FOR_EACH_OBSERVER(Observer, observer_list_,
-                    OnResponseCompleted(this, request));
-
-  // Notify the observers on the UI thread.
-  ui_loop_->PostTask(FROM_HERE,
-      new NotificationTask(NOTIFY_RESOURCE_RESPONSE_COMPLETED, request,
-                           new ResourceRequestDetails(request,
-                               GetCertID(request, render_process_host_id))));
-}
-
-void ResourceDispatcherHost::NofityReceivedRedirect(URLRequest* request,
-                                                    int render_process_host_id,
-                                                    const GURL& new_url) {
-  // Notify the observers on the IO thread.
-  FOR_EACH_OBSERVER(Observer, observer_list_,
-                    OnReceivedRedirect(this, request, new_url));
-
-  int cert_id = GetCertID(request, render_process_host_id);
-
-  // Notify the observers on the UI thread.
-  ui_loop_->PostTask(FROM_HERE,
-      new NotificationTask(NOTIFY_RESOURCE_RECEIVED_REDIRECT, request,
-                           new ResourceRedirectDetails(request,
-                                                       cert_id,
-                                                       new_url)));
-}
-
-namespace {
-
-// This function attempts to return the "more interesting" load state of |a|
-// and |b|.  We don't have temporal information about these load states
-// (meaning we don't know when we transitioned into these states), so we just
-// rank them according to how "interesting" the states are.
-//
-// We take advantage of the fact that the load states are an enumeration listed
-// in the order in which they occur during the lifetime of a request, so we can
-// regard states with larger numeric values as being further along toward
-// completion.  We regard those states as more interesting to report since they
-// represent progress.
-//
-// For example, by this measure "tranferring data" is a more interesting state
-// than "resolving host" because when we are transferring data we are actually
-// doing something that corresponds to changes that the user might observe,
-// whereas waiting for a host name to resolve implies being stuck.
-//
-net::LoadState MoreInterestingLoadState(net::LoadState a, net::LoadState b) {
-  return (a < b) ? b : a;
-}
-
-// Carries information about a load state change.
-struct LoadInfo {
-  GURL url;
-  net::LoadState load_state;
-};
-
-// Map from ProcessID+ViewID pair to LoadState
-typedef std::map<std::pair<int, int>, LoadInfo> LoadInfoMap;
-
-// Used to marshall calls to LoadStateChanged from the IO to UI threads.  We do
-// them all as a single task to avoid spamming the UI thread.
-class LoadInfoUpdateTask : public Task {
- public:
-  virtual void Run() {
-    LoadInfoMap::const_iterator i;
-    for (i = info_map.begin(); i != info_map.end(); ++i) {
-      RenderViewHost* view =
-          RenderViewHost::FromID(i->first.first, i->first.second);
-      if (view)  // The view could be gone at this point.
-        view->LoadStateChanged(i->second.url, i->second.load_state);
-    }
-  }
-  LoadInfoMap info_map;
-};
-
-}  // namespace
-
-void ResourceDispatcherHost::UpdateLoadStates() {
-  // Populate this map with load state changes, and then send them on to the UI
-  // thread where they can be passed along to the respective RVHs.
-  LoadInfoMap info_map;
-
-  PendingRequestList::const_iterator i;
-  for (i = pending_requests_.begin(); i != pending_requests_.end(); ++i) {
-    URLRequest* request = i->second;
-    net::LoadState load_state = request->GetLoadState();
-    ExtraRequestInfo* info = ExtraInfoForRequest(request);
-
-    // We also poll for upload progress on this timer and send upload
-    // progress ipc messages to the plugin process.
-    MaybeUpdateUploadProgress(info, request);
-
-    if (info->last_load_state != load_state) {
-      info->last_load_state = load_state;
-
-      std::pair<int, int> key(info->render_process_host_id,
-                              info->render_view_id);
-      net::LoadState to_insert;
-      LoadInfoMap::iterator existing = info_map.find(key);
-      if (existing == info_map.end()) {
-        to_insert = load_state;
-      } else {
-        to_insert =
-            MoreInterestingLoadState(existing->second.load_state, load_state);
-        if (to_insert == existing->second.load_state)
-          continue;
-      }
-      LoadInfo& load_info = info_map[key];
-      load_info.url = request->url();
-      load_info.load_state = to_insert;
-    }
-  }
-
-  if (info_map.empty())
-    return;
-
-  LoadInfoUpdateTask* task = new LoadInfoUpdateTask;
-  task->info_map.swap(info_map);
-  ui_loop_->PostTask(FROM_HERE, task);
-}
-
-void ResourceDispatcherHost::MaybeUpdateUploadProgress(ExtraRequestInfo *info,
-                                                       URLRequest *request) {
-  if (!info->upload_size || info->waiting_for_upload_progress_ack ||
-      !(request->load_flags() & net::LOAD_ENABLE_UPLOAD_PROGRESS))
-    return;
-
-  uint64 size = info->upload_size;
-  uint64 position = request->GetUploadProgress();
-  if (position == info->last_upload_position)
-    return;  // no progress made since last time
-
-  const uint64 kHalfPercentIncrements = 200;
-  const TimeDelta kOneSecond = TimeDelta::FromMilliseconds(1000);
-
-  uint64 amt_since_last = position - info->last_upload_position;
-  TimeDelta time_since_last = TimeTicks::Now() - info->last_upload_ticks;
-
-  bool is_finished = (size == position);
-  bool enough_new_progress = (amt_since_last > (size / kHalfPercentIncrements));
-  bool too_much_time_passed = time_since_last > kOneSecond;
-
-  if (is_finished || enough_new_progress || too_much_time_passed) {
-    info->event_handler->OnUploadProgress(info->request_id, position, size);
-    info->waiting_for_upload_progress_ack = true;
-    info->last_upload_ticks = TimeTicks::Now();
-    info->last_upload_position = position;
-  }
-}
diff --git a/chrome/browser/resource_message_filter.h b/chrome/browser/resource_message_filter.h
index 0322953..44f0fd2c3 100644
--- a/chrome/browser/resource_message_filter.h
+++ b/chrome/browser/resource_message_filter.h
@@ -9,7 +9,7 @@
 #include "base/gfx/rect.h"
 #include "base/gfx/native_widget_types.h"
 #include "base/ref_counted.h"
-#include "chrome/browser/resource_dispatcher_host.h"
+#include "chrome/browser/renderer_host/resource_dispatcher_host.h"
 #include "chrome/common/ipc_channel_proxy.h"
 #include "chrome/common/notification_service.h"
 #include "webkit/glue/cache_manager.h"
diff --git a/chrome/browser/resource_request_details.h b/chrome/browser/resource_request_details.h
index 39e8eaa4..e4a4d9dc 100644
--- a/chrome/browser/resource_request_details.h
+++ b/chrome/browser/resource_request_details.h
@@ -13,7 +13,7 @@
 
 #include "base/basictypes.h"
 #include "chrome/browser/cert_store.h"
-#include "chrome/browser/resource_dispatcher_host.h"
+#include "chrome/browser/renderer_host/resource_dispatcher_host.h"
 #include "googleurl/src/gurl.h"
 #include "net/url_request/url_request.h"
 #include "net/url_request/url_request_status.h"
diff --git a/chrome/browser/ssl_manager.h b/chrome/browser/ssl_manager.h
index 43b71c22..2f08a93 100644
--- a/chrome/browser/ssl_manager.h
+++ b/chrome/browser/ssl_manager.h
@@ -12,8 +12,8 @@
 #include "base/observer_list.h"
 #include "base/ref_counted.h"
 #include "chrome/browser/provisional_load_details.h"
-#include "chrome/browser/resource_dispatcher_host.h"
 #include "chrome/browser/security_style.h"
+#include "chrome/browser/renderer_host/resource_dispatcher_host.h"
 #include "chrome/common/notification_registrar.h"
 #include "chrome/common/notification_service.h"
 #include "chrome/common/render_messages.h"
diff --git a/chrome/browser/tab_util.cc b/chrome/browser/tab_util.cc
index 863b38d4..ecb7c84 100644
--- a/chrome/browser/tab_util.cc
+++ b/chrome/browser/tab_util.cc
@@ -6,7 +6,7 @@
 
 #include "chrome/browser/render_view_host.h"
 #include "chrome/browser/render_process_host.h"
-#include "chrome/browser/resource_dispatcher_host.h"
+#include "chrome/browser/renderer_host/resource_dispatcher_host.h"
 #include "chrome/browser/web_contents.h"
 #include "net/url_request/url_request.h"
 
diff --git a/chrome/browser/views/options/advanced_contents_view.cc b/chrome/browser/views/options/advanced_contents_view.cc
index c8f7d46..e63526b 100644
--- a/chrome/browser/views/options/advanced_contents_view.cc
+++ b/chrome/browser/views/options/advanced_contents_view.cc
@@ -23,7 +23,6 @@
 #include "chrome/browser/gears_integration.h"
 #include "chrome/browser/metrics_service.h"
 #include "chrome/browser/net/dns_global.h"
-#include "chrome/browser/resource_dispatcher_host.h"
 #include "chrome/browser/safe_browsing/safe_browsing_service.h"
 #include "chrome/browser/views/options/cookies_view.h"
 #include "chrome/browser/views/options/language_combobox_model.h"
diff --git a/chrome/test/perf/perftests.vcproj b/chrome/test/perf/perftests.vcproj
index 89cbba1a5..36460def 100644
--- a/chrome/test/perf/perftests.vcproj
+++ b/chrome/test/perf/perftests.vcproj
@@ -18,7 +18,7 @@
 		<Configuration
 			Name="Debug|Win32"
 			ConfigurationType="1"
-			InheritedPropertySheets="$(SolutionDir)..\build\common.vsprops;$(SolutionDir)..\build\debug.vsprops;$(SolutionDir)..\third_party\icu38\build\using_icu.vsprops;$(SolutionDir)..\third_party\libxml\build\using_libxml.vsprops;$(SolutionDir)..\testing\using_gtest.vsprops"
+			InheritedPropertySheets="$(SolutionDir)..\build\common.vsprops;$(SolutionDir)..\build\debug.vsprops;$(SolutionDir)..\third_party\icu38\build\using_icu.vsprops;$(SolutionDir)..\third_party\libxml\build\using_libxml.vsprops;$(SolutionDir)..\testing\using_gtest.vsprops;$(SolutionDir)..\skia\using_skia.vsprops"
 			>
 			<Tool
 				Name="VCPreBuildEventTool"
@@ -81,7 +81,7 @@
 		<Configuration
 			Name="Release|Win32"
 			ConfigurationType="1"
-			InheritedPropertySheets="$(SolutionDir)..\build\common.vsprops;$(SolutionDir)..\build\release.vsprops;$(SolutionDir)..\third_party\icu38\build\using_icu.vsprops;$(SolutionDir)..\third_party\libxml\build\using_libxml.vsprops;$(SolutionDir)..\testing\using_gtest.vsprops"
+			InheritedPropertySheets="$(SolutionDir)..\build\common.vsprops;$(SolutionDir)..\build\release.vsprops;$(SolutionDir)..\third_party\icu38\build\using_icu.vsprops;$(SolutionDir)..\third_party\libxml\build\using_libxml.vsprops;$(SolutionDir)..\testing\using_gtest.vsprops;$(SolutionDir)..\skia\using_skia.vsprops"
 			>
 			<Tool
 				Name="VCPreBuildEventTool"
diff --git a/chrome/test/ui/ui_tests.vcproj b/chrome/test/ui/ui_tests.vcproj
index 5fda197..9d5bdb1 100644
--- a/chrome/test/ui/ui_tests.vcproj
+++ b/chrome/test/ui/ui_tests.vcproj
@@ -362,7 +362,7 @@
 			Name="TestResourceDispatcherHost"
 			>
 			<File
-				RelativePath="..\..\browser\resource_dispatcher_host_uitest.cc"
+				RelativePath="..\..\browser\renderer_host\resource_dispatcher_host_uitest.cc"
 				>
 			</File>
 		</Filter>
diff --git a/chrome/test/unit/unittests.vcproj b/chrome/test/unit/unittests.vcproj
index b7c7da1..449e8223 100644
--- a/chrome/test/unit/unittests.vcproj
+++ b/chrome/test/unit/unittests.vcproj
@@ -290,8 +290,26 @@
 			Name="TestResourceDispatcher"
 			>
 			<File
-				RelativePath="..\..\browser\resource_dispatcher_host_unittest.cc"
+				RelativePath="..\..\browser\renderer_host\resource_dispatcher_host_unittest.cc"
 				>
+				<FileConfiguration
+					Name="Debug|Win32"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						ObjectFile="$(IntDir)\$(InputName)1.obj"
+						XMLDocumentationFileName="$(IntDir)\$(InputName)1.xdc"
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release|Win32"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						ObjectFile="$(IntDir)\$(InputName)1.obj"
+						XMLDocumentationFileName="$(IntDir)\$(InputName)1.xdc"
+					/>
+				</FileConfiguration>
 			</File>
 			<File
 				RelativePath="..\..\common\resource_dispatcher_unittest.cc"