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