1 // Copyright 2014 The Chromium Authors
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 "components/nacl/renderer/file_downloader.h"
6
7 #include <utility>
8
9 #include "base/compiler_specific.h"
10 #include "base/functional/callback.h"
11 #include "components/nacl/renderer/nexe_load_manager.h"
12 #include "net/base/net_errors.h"
13 #include "third_party/blink/public/platform/web_url_error.h"
14 #include "third_party/blink/public/platform/web_url_response.h"
15 #include "third_party/blink/public/web/web_associated_url_loader.h"
16
17 namespace nacl {
18
FileDownloader(std::unique_ptr<blink::WebAssociatedURLLoader> url_loader,base::File file,StatusCallback status_cb,ProgressCallback progress_cb)19 FileDownloader::FileDownloader(
20 std::unique_ptr<blink::WebAssociatedURLLoader> url_loader,
21 base::File file,
22 StatusCallback status_cb,
23 ProgressCallback progress_cb)
24 : url_loader_(std::move(url_loader)),
25 file_(std::move(file)),
26 status_cb_(std::move(status_cb)),
27 progress_cb_(std::move(progress_cb)),
28 http_status_code_(-1),
29 total_bytes_received_(0),
30 total_bytes_to_be_received_(-1),
31 status_(SUCCESS) {
32 CHECK(!status_cb_.is_null());
33 }
34
~FileDownloader()35 FileDownloader::~FileDownloader() {
36 }
37
Load(const blink::WebURLRequest & request)38 void FileDownloader::Load(const blink::WebURLRequest& request) {
39 url_loader_->LoadAsynchronously(request, this);
40 }
41
DidReceiveResponse(const blink::WebURLResponse & response)42 void FileDownloader::DidReceiveResponse(const blink::WebURLResponse& response) {
43 http_status_code_ = response.HttpStatusCode();
44 if (http_status_code_ != 200)
45 status_ = FAILED;
46
47 // Set -1 if the content length is unknown. Set before issuing callback.
48 total_bytes_to_be_received_ = response.ExpectedContentLength();
49 if (!progress_cb_.is_null())
50 progress_cb_.Run(total_bytes_received_, total_bytes_to_be_received_);
51 }
52
DidReceiveData(base::span<const char> data)53 void FileDownloader::DidReceiveData(base::span<const char> data) {
54 if (status_ == SUCCESS) {
55 if (file_.Write(total_bytes_received_, base::as_bytes(data)) == -1) {
56 status_ = FAILED;
57 return;
58 }
59 total_bytes_received_ += data.size();
60 if (!progress_cb_.is_null())
61 progress_cb_.Run(total_bytes_received_, total_bytes_to_be_received_);
62 }
63 }
64
DidFinishLoading()65 void FileDownloader::DidFinishLoading() {
66 if (status_ == SUCCESS) {
67 // Seek back to the beginning of the file that was just written so it's
68 // easy for consumers to use.
69 if (file_.Seek(base::File::FROM_BEGIN, 0) != 0)
70 status_ = FAILED;
71 }
72 std::move(status_cb_).Run(status_, std::move(file_), http_status_code_);
73 delete this;
74 }
75
DidFail(const blink::WebURLError & error)76 void FileDownloader::DidFail(const blink::WebURLError& error) {
77 status_ = FAILED;
78 switch (error.reason()) {
79 case net::ERR_ACCESS_DENIED:
80 case net::ERR_NETWORK_ACCESS_DENIED:
81 status_ = ACCESS_DENIED;
82 break;
83 }
84
85 if (error.is_web_security_violation())
86 status_ = ACCESS_DENIED;
87
88 // Delete url_loader to prevent didFinishLoading from being called, which
89 // some implementations of blink::URLLoader will do after calling didFail.
90 url_loader_.reset();
91
92 std::move(status_cb_).Run(status_, std::move(file_), http_status_code_);
93 delete this;
94 }
95
96 } // namespace nacl
97