Use the async loading path for synchronous XMLHttpRequest
This patch removes the need for a special synchronous loading IPC
message to support synchronous XMLHttpRequests. Instead a task to
perform the load is posted to the thread pool while the main thread is
blocked on a WaitableEvent.
A Clone message has been added to URLLoaderFactory to support creating
a pipe that can be used off of the main thread. The SyncLoad message is
removed as it is no longer used.
Change-Id: Ic2fc68d8b03564bf9a8e5ea991467cc38a6aa4c7
Reviewed-on: https://chromium-review.googlesource.com/603776
Commit-Queue: Reilly Grant <[email protected]>
Reviewed-by: Robert Sesek <[email protected]>
Reviewed-by: Kinuko Yasuda <[email protected]>
Reviewed-by: John Abd-El-Malek <[email protected]>
Cr-Commit-Position: refs/heads/master@{#493606}
diff --git a/content/child/sync_load_context.cc b/content/child/sync_load_context.cc
new file mode 100644
index 0000000..e7ee0fc
--- /dev/null
+++ b/content/child/sync_load_context.cc
@@ -0,0 +1,115 @@
+// Copyright 2017 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 "content/child/sync_load_context.h"
+
+#include <string>
+
+#include "base/logging.h"
+#include "base/synchronization/waitable_event.h"
+#include "content/child/sync_load_response.h"
+#include "content/public/common/resource_request.h"
+#include "content/public/common/resource_response_info.h"
+#include "content/public/common/url_loader_throttle.h"
+#include "net/url_request/redirect_info.h"
+
+namespace content {
+
+// static
+void SyncLoadContext::StartAsyncWithWaitableEvent(
+ std::unique_ptr<ResourceRequest> request,
+ int routing_id,
+ const url::Origin& frame_origin,
+ mojom::URLLoaderFactoryPtrInfo url_loader_factory_pipe,
+ SyncLoadResponse* response,
+ base::WaitableEvent* event) {
+ auto* context = new SyncLoadContext(
+ request.get(), std::move(url_loader_factory_pipe), response, event);
+ // TODO(reillyg): Support throttles.
+ std::vector<std::unique_ptr<URLLoaderThrottle>> throttles;
+
+ context->request_id_ = context->resource_dispatcher_->StartAsync(
+ std::move(request), routing_id, nullptr, frame_origin, true /* is_sync */,
+ base::WrapUnique(context), blink::WebURLRequest::LoadingIPCType::kMojo,
+ context->url_loader_factory_.get(), std::move(throttles),
+ mojo::ScopedDataPipeConsumerHandle());
+}
+
+SyncLoadContext::SyncLoadContext(
+ ResourceRequest* request,
+ mojom::URLLoaderFactoryPtrInfo url_loader_factory,
+ SyncLoadResponse* response,
+ base::WaitableEvent* event)
+ : response_(response), event_(event) {
+ url_loader_factory_.Bind(std::move(url_loader_factory));
+
+ // Constructs a new ResourceDispatcher specifically for this request.
+ resource_dispatcher_ = base::MakeUnique<ResourceDispatcher>(
+ nullptr, base::ThreadTaskRunnerHandle::Get());
+
+ // Initialize the final URL with the original request URL. It will be
+ // overwritten on redirects.
+ response_->url = request->url;
+}
+
+SyncLoadContext::~SyncLoadContext() {}
+
+void SyncLoadContext::OnUploadProgress(uint64_t position, uint64_t size) {}
+
+bool SyncLoadContext::OnReceivedRedirect(const net::RedirectInfo& redirect_info,
+ const ResourceResponseInfo& info) {
+ if (redirect_info.new_url.GetOrigin() != response_->url.GetOrigin()) {
+ LOG(ERROR) << "Cross origin redirect denied";
+ response_->error_code = net::ERR_ABORTED;
+ event_->Signal();
+
+ // Returning false here will cause the request to be cancelled and this
+ // object deleted.
+ return false;
+ }
+
+ response_->url = redirect_info.new_url;
+ return true;
+}
+
+void SyncLoadContext::OnReceivedResponse(const ResourceResponseInfo& info) {
+ response_->headers = info.headers;
+ response_->mime_type = info.mime_type;
+ response_->charset = info.charset;
+ response_->request_time = info.request_time;
+ response_->response_time = info.response_time;
+ response_->load_timing = info.load_timing;
+ response_->devtools_info = info.devtools_info;
+ response_->download_file_path = info.download_file_path;
+ response_->socket_address = info.socket_address;
+}
+
+void SyncLoadContext::OnDownloadedData(int len, int encoded_data_length) {
+ // This method is only called when RequestInfo::download_to_file is true which
+ // is not allowed when processing a synchronous request.
+ NOTREACHED();
+}
+
+void SyncLoadContext::OnReceivedData(std::unique_ptr<ReceivedData> data) {
+ response_->data.append(data->payload(), data->length());
+}
+
+void SyncLoadContext::OnTransferSizeUpdated(int transfer_size_diff) {}
+
+void SyncLoadContext::OnCompletedRequest(int error_code,
+ bool stale_copy_in_cache,
+ const base::TimeTicks& completion_time,
+ int64_t total_transfer_size,
+ int64_t encoded_body_size,
+ int64_t decoded_body_size) {
+ response_->error_code = error_code;
+ response_->encoded_data_length = total_transfer_size;
+ response_->encoded_body_length = encoded_body_size;
+ event_->Signal();
+
+ // This will indirectly cause this object to be deleted.
+ resource_dispatcher_->RemovePendingRequest(request_id_);
+}
+
+} // namespace content