| // Copyright 2014 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 "sky/services/platform/weburlloader_impl.h" |
| |
| #include "base/bind.h" |
| #include "base/logging.h" |
| #include "base/strings/string_util.h" |
| #include "base/thread_task_runner_handle.h" |
| #include "mojo/common/common_type_converters.h" |
| #include "mojo/services/network/public/interfaces/network_service.mojom.h" |
| #include "sky/engine/public/platform/WebURLError.h" |
| #include "sky/engine/public/platform/WebURLLoadTiming.h" |
| #include "sky/engine/public/platform/WebURLLoaderClient.h" |
| #include "sky/engine/public/platform/WebURLResponse.h" |
| #include "sky/services/platform/net_constants.h" |
| #include "sky/services/platform/url_request_types.h" |
| |
| namespace sky { |
| namespace { |
| |
| static blink::WebURLResponse::HTTPVersion StatusLineToHTTPVersion( |
| const mojo::String& status_line) { |
| if (status_line.is_null()) |
| return blink::WebURLResponse::HTTP_0_9; |
| |
| if (StartsWithASCII(status_line, "HTTP/1.0", true)) |
| return blink::WebURLResponse::HTTP_1_0; |
| |
| if (StartsWithASCII(status_line, "HTTP/1.1", true)) |
| return blink::WebURLResponse::HTTP_1_1; |
| |
| return blink::WebURLResponse::Unknown; |
| } |
| |
| blink::WebURLResponse ToWebURLResponse(const mojo::URLResponsePtr& url_response) { |
| blink::WebURLResponse result; |
| result.initialize(); |
| result.setURL(GURL(url_response->url)); |
| result.setMIMEType(blink::WebString::fromUTF8(url_response->mime_type)); |
| result.setTextEncodingName(blink::WebString::fromUTF8(url_response->charset)); |
| result.setHTTPVersion(StatusLineToHTTPVersion(url_response->status_line)); |
| result.setHTTPStatusCode(url_response->status_code); |
| |
| // TODO(darin): Initialize timing properly. |
| blink::WebURLLoadTiming timing; |
| timing.initialize(); |
| result.setLoadTiming(timing); |
| |
| for (size_t i = 0; i < url_response->headers.size(); ++i) { |
| const std::string& header_line = url_response->headers[i]; |
| size_t first_colon = header_line.find(":"); |
| |
| if (first_colon == std::string::npos || first_colon == 0) |
| continue; |
| |
| std::string value; |
| TrimWhitespaceASCII(header_line.substr(first_colon + 1), |
| base::TRIM_LEADING, |
| &value); |
| result.setHTTPHeaderField( |
| blink::WebString::fromUTF8(header_line.substr(0, first_colon)), |
| blink::WebString::fromUTF8(value)); |
| } |
| |
| return result; |
| } |
| |
| } // namespace |
| |
| WebURLLoaderImpl::WebURLLoaderImpl(mojo::NetworkService* network_service) |
| : client_(NULL), |
| weak_factory_(this) { |
| network_service->CreateURLLoader(GetProxy(&url_loader_)); |
| } |
| |
| WebURLLoaderImpl::~WebURLLoaderImpl() { |
| } |
| |
| void WebURLLoaderImpl::loadAsynchronously(const blink::WebURLRequest& request, |
| blink::WebURLLoaderClient* client) { |
| client_ = client; |
| url_ = request.url(); |
| |
| mojo::URLRequestPtr url_request = mojo::URLRequest::From(request); |
| url_request->auto_follow_redirects = false; |
| url_loader_->Start(url_request.Pass(), |
| base::Bind(&WebURLLoaderImpl::OnReceivedResponse, |
| weak_factory_.GetWeakPtr())); |
| } |
| |
| void WebURLLoaderImpl::cancel() { |
| url_loader_.reset(); |
| response_body_stream_.reset(); |
| |
| mojo::URLResponsePtr failed_response(mojo::URLResponse::New()); |
| failed_response->url = mojo::String::From(url_); |
| failed_response->error = mojo::NetworkError::New(); |
| failed_response->error->code = kNetErrorAborted; |
| |
| base::ThreadTaskRunnerHandle::Get()->PostTask( |
| FROM_HERE, |
| base::Bind(&WebURLLoaderImpl::OnReceivedResponse, |
| weak_factory_.GetWeakPtr(), |
| base::Passed(&failed_response))); |
| } |
| |
| void WebURLLoaderImpl::OnReceivedResponse(mojo::URLResponsePtr url_response) { |
| url_ = GURL(url_response->url); |
| |
| if (url_response->error) { |
| OnReceivedError(url_response.Pass()); |
| } else if (url_response->redirect_url) { |
| OnReceivedRedirect(url_response.Pass()); |
| } else { |
| base::WeakPtr<WebURLLoaderImpl> self(weak_factory_.GetWeakPtr()); |
| client_->didReceiveResponse(this, ToWebURLResponse(url_response)); |
| |
| // We may have been deleted during didReceiveResponse. |
| if (!self) |
| return; |
| |
| // Start streaming data |
| response_body_stream_ = url_response->body.Pass(); |
| ReadMore(); |
| } |
| } |
| |
| void WebURLLoaderImpl::OnReceivedError(mojo::URLResponsePtr url_response) { |
| blink::WebURLError web_error; |
| web_error.domain = blink::WebString::fromUTF8(kNetErrorDomain); |
| web_error.reason = url_response->error->code; |
| web_error.unreachableURL = GURL(url_response->url); |
| web_error.staleCopyInCache = false; |
| web_error.isCancellation = |
| url_response->error->code == kNetErrorAborted ? true : false; |
| |
| client_->didFail(this, web_error); |
| } |
| |
| void WebURLLoaderImpl::OnReceivedRedirect(mojo::URLResponsePtr url_response) { |
| blink::WebURLRequest new_request; |
| new_request.initialize(); |
| new_request.setURL(GURL(url_response->redirect_url)); |
| new_request.setHTTPMethod( |
| blink::WebString::fromUTF8(url_response->redirect_method)); |
| |
| client_->willSendRequest(this, new_request, ToWebURLResponse(url_response)); |
| // TODO(darin): Check if new_request was rejected. |
| |
| url_loader_->FollowRedirect( |
| base::Bind(&WebURLLoaderImpl::OnReceivedResponse, |
| weak_factory_.GetWeakPtr())); |
| } |
| |
| void WebURLLoaderImpl::ReadMore() { |
| const void* buf; |
| uint32_t buf_size; |
| MojoResult rv = mojo::BeginReadDataRaw(response_body_stream_.get(), |
| &buf, |
| &buf_size, |
| MOJO_READ_DATA_FLAG_NONE); |
| if (rv == MOJO_RESULT_OK) { |
| client_->didReceiveData(this, static_cast<const char*>(buf), buf_size, -1); |
| EndReadDataRaw(response_body_stream_.get(), buf_size); |
| WaitToReadMore(); |
| } else if (rv == MOJO_RESULT_SHOULD_WAIT) { |
| WaitToReadMore(); |
| } else if (rv == MOJO_RESULT_FAILED_PRECONDITION) { |
| // We reached end-of-file. |
| double finish_time = base::Time::Now().ToDoubleT(); |
| client_->didFinishLoading( |
| this, |
| finish_time, |
| blink::WebURLLoaderClient::kUnknownEncodedDataLength); |
| } else { |
| // TODO(darin): Oops! |
| } |
| } |
| |
| void WebURLLoaderImpl::WaitToReadMore() { |
| handle_watcher_.Start( |
| response_body_stream_.get(), |
| MOJO_HANDLE_SIGNAL_READABLE, |
| MOJO_DEADLINE_INDEFINITE, |
| base::Bind(&WebURLLoaderImpl::OnResponseBodyStreamReady, |
| weak_factory_.GetWeakPtr())); |
| } |
| |
| void WebURLLoaderImpl::OnResponseBodyStreamReady(MojoResult result) { |
| ReadMore(); |
| } |
| |
| } // namespace sky |