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/tools/package_manager/package_fetcher.h"
6
7 #include "base/bind.h"
8 #include "base/files/file_path.h"
9 #include "base/files/file_util.h"
10 #include "mojo/services/public/interfaces/network/url_loader.mojom.h"
11
12 namespace mojo {
13
PackageFetcher(NetworkService * network_service,PackageFetcherDelegate * delegate,const GURL & url)14 PackageFetcher::PackageFetcher(NetworkService* network_service,
15 PackageFetcherDelegate* delegate,
16 const GURL& url)
17 : delegate_(delegate),
18 url_(url) {
19 network_service->CreateURLLoader(Get(&loader_));
20
21 URLRequestPtr request(URLRequest::New());
22 request->url = url.spec();
23 request->auto_follow_redirects = true;
24
25 loader_->Start(request.Pass(),
26 base::Bind(&PackageFetcher::OnReceivedResponse,
27 base::Unretained(this)));
28 }
29
~PackageFetcher()30 PackageFetcher::~PackageFetcher() {
31 }
32
OnReceivedResponse(URLResponsePtr response)33 void PackageFetcher::OnReceivedResponse(URLResponsePtr response) {
34 if (response->error) {
35 printf("Got error %d (%s) for %s\n",
36 response->error->code,
37 response->error->description.get().c_str(),
38 url_.spec().c_str());
39 delegate_->FetchFailed(url_);
40 return;
41 }
42
43 if (!base::CreateTemporaryFile(&output_file_name_)) {
44 delegate_->FetchFailed(url_);
45 return;
46 }
47 output_file_.Initialize(output_file_name_,
48 base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE);
49 if (!output_file_.IsValid()) {
50 base::DeleteFile(output_file_name_, false);
51 delegate_->FetchFailed(url_);
52 // Danger: may be deleted now.
53 return;
54 }
55
56 body_ = response->body.Pass();
57 ReadData(MOJO_RESULT_OK);
58 // Danger: may be deleted now.
59 }
60
ReadData(MojoResult)61 void PackageFetcher::ReadData(MojoResult) {
62 char buf[4096];
63 uint32_t num_bytes = sizeof(buf);
64 MojoResult result = ReadDataRaw(body_.get(), buf, &num_bytes,
65 MOJO_READ_DATA_FLAG_NONE);
66 if (result == MOJO_RESULT_SHOULD_WAIT) {
67 WaitToReadMore();
68 } else if (result == MOJO_RESULT_OK) {
69 if (output_file_.WriteAtCurrentPos(buf, num_bytes) !=
70 static_cast<int>(num_bytes)) {
71 // Clean up the output file.
72 output_file_.Close();
73 base::DeleteFile(output_file_name_, false);
74
75 delegate_->FetchFailed(url_);
76 // Danger: may be deleted now.
77 return;
78 }
79 WaitToReadMore();
80 } else if (result == MOJO_RESULT_FAILED_PRECONDITION) {
81 // Done.
82 output_file_.Close();
83 delegate_->FetchSucceeded(url_, output_file_name_);
84 // Danger: may be deleted now.
85 }
86 }
87
WaitToReadMore()88 void PackageFetcher::WaitToReadMore() {
89 handle_watcher_.Start(
90 body_.get(),
91 MOJO_HANDLE_SIGNAL_READABLE,
92 MOJO_DEADLINE_INDEFINITE,
93 base::Bind(&PackageFetcher::ReadData, base::Unretained(this)));
94 }
95
96 } // namespace mojo
97