1 // Copyright 2014 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "mojo/services/html_viewer/weburlloader_impl.h" 6 7 #include "base/bind.h" 8 #include "base/logging.h" 9 #include "base/strings/string_util.h" 10 #include "base/thread_task_runner_handle.h" 11 #include "mojo/common/common_type_converters.h" 12 #include "mojo/services/html_viewer/blink_url_request_type_converters.h" 13 #include "mojo/services/public/interfaces/network/network_service.mojom.h" 14 #include "net/base/net_errors.h" 15 #include "third_party/WebKit/public/platform/WebURLError.h" 16 #include "third_party/WebKit/public/platform/WebURLLoadTiming.h" 17 #include "third_party/WebKit/public/platform/WebURLLoaderClient.h" 18 #include "third_party/WebKit/public/platform/WebURLResponse.h" 19 20 namespace mojo { 21 namespace { 22 23 static blink::WebURLResponse::HTTPVersion StatusLineToHTTPVersion( 24 const String& status_line) { 25 if (status_line.is_null()) 26 return blink::WebURLResponse::HTTP_0_9; 27 28 if (StartsWithASCII(status_line, "HTTP/1.0", true)) 29 return blink::WebURLResponse::HTTP_1_0; 30 31 if (StartsWithASCII(status_line, "HTTP/1.1", true)) 32 return blink::WebURLResponse::HTTP_1_1; 33 34 return blink::WebURLResponse::Unknown; 35 } 36 37 blink::WebURLResponse ToWebURLResponse(const URLResponsePtr& url_response) { 38 blink::WebURLResponse result; 39 result.initialize(); 40 result.setURL(GURL(url_response->url)); 41 result.setMIMEType(blink::WebString::fromUTF8(url_response->mime_type)); 42 result.setTextEncodingName(blink::WebString::fromUTF8(url_response->charset)); 43 result.setHTTPVersion(StatusLineToHTTPVersion(url_response->status_line)); 44 result.setHTTPStatusCode(url_response->status_code); 45 46 // TODO(darin): Initialize timing properly. 47 blink::WebURLLoadTiming timing; 48 timing.initialize(); 49 result.setLoadTiming(timing); 50 51 for (size_t i = 0; i < url_response->headers.size(); ++i) { 52 const std::string& header_line = url_response->headers[i]; 53 size_t first_colon = header_line.find(":"); 54 55 if (first_colon == std::string::npos || first_colon == 0) 56 continue; 57 58 std::string value; 59 TrimWhitespaceASCII(header_line.substr(first_colon + 1), 60 base::TRIM_LEADING, 61 &value); 62 result.setHTTPHeaderField( 63 blink::WebString::fromUTF8(header_line.substr(0, first_colon)), 64 blink::WebString::fromUTF8(value)); 65 } 66 67 return result; 68 } 69 70 } // namespace 71 72 WebURLRequestExtraData::WebURLRequestExtraData() { 73 } 74 75 WebURLRequestExtraData::~WebURLRequestExtraData() { 76 } 77 78 WebURLLoaderImpl::WebURLLoaderImpl(NetworkService* network_service) 79 : client_(NULL), 80 weak_factory_(this) { 81 network_service->CreateURLLoader(Get(&url_loader_)); 82 } 83 84 WebURLLoaderImpl::~WebURLLoaderImpl() { 85 } 86 87 void WebURLLoaderImpl::loadSynchronously( 88 const blink::WebURLRequest& request, 89 blink::WebURLResponse& response, 90 blink::WebURLError& error, 91 blink::WebData& data) { 92 NOTIMPLEMENTED(); 93 } 94 95 void WebURLLoaderImpl::loadAsynchronously(const blink::WebURLRequest& request, 96 blink::WebURLLoaderClient* client) { 97 client_ = client; 98 url_ = request.url(); 99 100 URLRequestPtr url_request = URLRequest::From(request); 101 url_request->auto_follow_redirects = false; 102 103 if (request.extraData()) { 104 WebURLRequestExtraData* extra_data = 105 static_cast<WebURLRequestExtraData*>(request.extraData()); 106 base::ThreadTaskRunnerHandle::Get()->PostTask( 107 FROM_HERE, 108 base::Bind(&WebURLLoaderImpl::OnReceivedResponse, 109 weak_factory_.GetWeakPtr(), 110 base::Passed(&extra_data->synthetic_response))); 111 } else { 112 url_loader_->Start(url_request.Pass(), 113 base::Bind(&WebURLLoaderImpl::OnReceivedResponse, 114 weak_factory_.GetWeakPtr())); 115 } 116 } 117 118 void WebURLLoaderImpl::cancel() { 119 url_loader_.reset(); 120 response_body_stream_.reset(); 121 122 URLResponsePtr failed_response(URLResponse::New()); 123 failed_response->url = String::From(url_); 124 failed_response->error = NetworkError::New(); 125 failed_response->error->code = net::ERR_ABORTED; 126 127 base::ThreadTaskRunnerHandle::Get()->PostTask( 128 FROM_HERE, 129 base::Bind(&WebURLLoaderImpl::OnReceivedResponse, 130 weak_factory_.GetWeakPtr(), 131 base::Passed(&failed_response))); 132 } 133 134 void WebURLLoaderImpl::setDefersLoading(bool defers_loading) { 135 NOTIMPLEMENTED(); 136 } 137 138 void WebURLLoaderImpl::OnReceivedResponse(URLResponsePtr url_response) { 139 url_ = GURL(url_response->url); 140 141 if (url_response->error) { 142 OnReceivedError(url_response.Pass()); 143 } else if (url_response->redirect_url) { 144 OnReceivedRedirect(url_response.Pass()); 145 } else { 146 base::WeakPtr<WebURLLoaderImpl> self(weak_factory_.GetWeakPtr()); 147 client_->didReceiveResponse(this, ToWebURLResponse(url_response)); 148 149 // We may have been deleted during didReceiveResponse. 150 if (!self) 151 return; 152 153 // Start streaming data 154 response_body_stream_ = url_response->body.Pass(); 155 ReadMore(); 156 } 157 } 158 159 void WebURLLoaderImpl::OnReceivedError(URLResponsePtr url_response) { 160 blink::WebURLError web_error; 161 web_error.domain = blink::WebString::fromUTF8(net::kErrorDomain); 162 web_error.reason = url_response->error->code; 163 web_error.unreachableURL = GURL(url_response->url); 164 web_error.staleCopyInCache = false; 165 web_error.isCancellation = 166 url_response->error->code == net::ERR_ABORTED ? true : false; 167 168 client_->didFail(this, web_error); 169 } 170 171 void WebURLLoaderImpl::OnReceivedRedirect(URLResponsePtr url_response) { 172 blink::WebURLRequest new_request; 173 new_request.initialize(); 174 new_request.setURL(GURL(url_response->redirect_url)); 175 new_request.setHTTPMethod( 176 blink::WebString::fromUTF8(url_response->redirect_method)); 177 178 client_->willSendRequest(this, new_request, ToWebURLResponse(url_response)); 179 // TODO(darin): Check if new_request was rejected. 180 181 url_loader_->FollowRedirect( 182 base::Bind(&WebURLLoaderImpl::OnReceivedResponse, 183 weak_factory_.GetWeakPtr())); 184 } 185 186 void WebURLLoaderImpl::ReadMore() { 187 const void* buf; 188 uint32_t buf_size; 189 MojoResult rv = BeginReadDataRaw(response_body_stream_.get(), 190 &buf, 191 &buf_size, 192 MOJO_READ_DATA_FLAG_NONE); 193 if (rv == MOJO_RESULT_OK) { 194 client_->didReceiveData(this, static_cast<const char*>(buf), buf_size, -1); 195 EndReadDataRaw(response_body_stream_.get(), buf_size); 196 WaitToReadMore(); 197 } else if (rv == MOJO_RESULT_SHOULD_WAIT) { 198 WaitToReadMore(); 199 } else if (rv == MOJO_RESULT_FAILED_PRECONDITION) { 200 // We reached end-of-file. 201 double finish_time = base::Time::Now().ToDoubleT(); 202 client_->didFinishLoading( 203 this, 204 finish_time, 205 blink::WebURLLoaderClient::kUnknownEncodedDataLength); 206 } else { 207 // TODO(darin): Oops! 208 } 209 } 210 211 void WebURLLoaderImpl::WaitToReadMore() { 212 handle_watcher_.Start( 213 response_body_stream_.get(), 214 MOJO_HANDLE_SIGNAL_READABLE, 215 MOJO_DEADLINE_INDEFINITE, 216 base::Bind(&WebURLLoaderImpl::OnResponseBodyStreamReady, 217 weak_factory_.GetWeakPtr())); 218 } 219 220 void WebURLLoaderImpl::OnResponseBodyStreamReady(MojoResult result) { 221 ReadMore(); 222 } 223 224 } // namespace mojo 225