Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(392)

Side by Side Diff: shell/application_manager/network_fetcher.cc

Issue 1276073004: Offline By Default (Closed) Base URL: https://github.com/domokit/mojo.git@master
Patch Set: Add missing explicits. Created 5 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « shell/application_manager/network_fetcher.h ('k') | shell/url_response_disk_cache_loader.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "shell/application_manager/network_fetcher.h" 5 #include "shell/application_manager/network_fetcher.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/command_line.h" 8 #include "base/command_line.h"
9 #include "base/files/file.h" 9 #include "base/files/file.h"
10 #include "base/files/file_path.h" 10 #include "base/files/file_path.h"
(...skipping 14 matching lines...) Expand all
25 namespace shell { 25 namespace shell {
26 26
27 namespace { 27 namespace {
28 #if defined(OS_LINUX) 28 #if defined(OS_LINUX)
29 char kArchitecture[] = "linux-x64"; 29 char kArchitecture[] = "linux-x64";
30 #elif defined(OS_ANDROID) 30 #elif defined(OS_ANDROID)
31 char kArchitecture[] = "android-arm"; 31 char kArchitecture[] = "android-arm";
32 #else 32 #else
33 #error "Unsupported." 33 #error "Unsupported."
34 #endif 34 #endif
35
36 // The delay to wait before trying to update an application after having served
37 // it from the cache.
38 const uint32_t kUpdateApplicationDelayInSeconds = 60;
39
40 base::FilePath ToFilePath(const mojo::Array<uint8_t>& array) {
41 return base::FilePath(
42 std::string(reinterpret_cast<const char*>(&array.front()), array.size()));
43 }
44
45 void IgnoreResult(bool result) {}
46
47 mojo::URLRequestPtr GetRequest(const GURL& url, bool disable_cache) {
48 mojo::URLRequestPtr request(mojo::URLRequest::New());
49 request->url = mojo::String::From(url);
50 request->auto_follow_redirects = false;
51 if (disable_cache)
52 request->cache_mode = mojo::URLRequest::CACHE_MODE_BYPASS_CACHE;
53 auto architecture_header = mojo::HttpHeader::New();
54 architecture_header->name = "X-Architecture";
55 architecture_header->value = kArchitecture;
56 mojo::Array<mojo::HttpHeaderPtr> headers;
57 headers.push_back(architecture_header.Pass());
58 request->headers = headers.Pass();
59
60 return request.Pass();
61 }
62
63 // This class is self owned and will delete itself after having tried to update
64 // the application cache.
65 class ApplicationUpdater : public base::MessageLoop::DestructionObserver {
66 public:
67 ApplicationUpdater(const GURL& url,
68 const base::TimeDelta& update_delay,
69 mojo::URLResponseDiskCache* url_response_disk_cache,
70 mojo::NetworkService* network_service);
71 ~ApplicationUpdater() override;
72
73 private:
74 // DestructionObserver
75 void WillDestroyCurrentMessageLoop() override;
76
77 void UpdateApplication();
78 void OnLoadComplete(mojo::URLResponsePtr response);
79
80 GURL url_;
81 base::TimeDelta update_delay_;
82 mojo::URLResponseDiskCache* url_response_disk_cache_;
83 mojo::NetworkService* network_service_;
84 mojo::URLLoaderPtr url_loader_;
35 }; 85 };
36 86
87 ApplicationUpdater::ApplicationUpdater(
88 const GURL& url,
89 const base::TimeDelta& update_delay,
90 mojo::URLResponseDiskCache* url_response_disk_cache,
91 mojo::NetworkService* network_service)
92 : url_(url),
93 update_delay_(update_delay),
94 url_response_disk_cache_(url_response_disk_cache),
95 network_service_(network_service) {
96 base::MessageLoop::current()->AddDestructionObserver(this);
97 base::MessageLoop::current()->PostDelayedTask(
98 FROM_HERE, base::Bind(&ApplicationUpdater::UpdateApplication,
99 base::Unretained(this)),
100 update_delay_);
101 }
102
103 ApplicationUpdater::~ApplicationUpdater() {
104 base::MessageLoop::current()->RemoveDestructionObserver(this);
105 }
106
107 void ApplicationUpdater::WillDestroyCurrentMessageLoop() {
108 delete this;
109 }
110
111 void ApplicationUpdater::UpdateApplication() {
112 network_service_->CreateURLLoader(GetProxy(&url_loader_));
113 url_loader_->Start(
114 GetRequest(url_, false),
115 base::Bind(&ApplicationUpdater::OnLoadComplete, base::Unretained(this)));
116 }
117
118 void ApplicationUpdater::OnLoadComplete(mojo::URLResponsePtr response) {
119 url_response_disk_cache_->Update(response.Pass());
120 delete this;
121 }
122
123 } // namespace
124
37 NetworkFetcher::NetworkFetcher( 125 NetworkFetcher::NetworkFetcher(
38 bool disable_cache, 126 bool disable_cache,
39 const GURL& url, 127 const GURL& url,
40 mojo::URLResponseDiskCache* url_response_disk_cache, 128 mojo::URLResponseDiskCache* url_response_disk_cache,
41 mojo::NetworkService* network_service, 129 mojo::NetworkService* network_service,
42 const FetchCallback& loader_callback) 130 const FetchCallback& loader_callback)
43 : Fetcher(loader_callback), 131 : Fetcher(loader_callback),
44 disable_cache_(disable_cache), 132 disable_cache_(disable_cache),
45 url_(url), 133 url_(url),
46 url_response_disk_cache_(url_response_disk_cache), 134 url_response_disk_cache_(url_response_disk_cache),
47 network_service_(network_service), 135 network_service_(network_service),
48 weak_ptr_factory_(this) { 136 weak_ptr_factory_(this) {
49 StartNetworkRequest(FROM_NETWORK); 137 if (CanLoadDirectlyFromCache()) {
138 LoadFromCache(true);
139 } else {
140 StartNetworkRequest();
141 }
50 } 142 }
51 143
52 NetworkFetcher::~NetworkFetcher() { 144 NetworkFetcher::~NetworkFetcher() {
53 } 145 }
54 146
55 const GURL& NetworkFetcher::GetURL() const { 147 const GURL& NetworkFetcher::GetURL() const {
56 return url_; 148 return url_;
57 } 149 }
58 150
59 GURL NetworkFetcher::GetRedirectURL() const { 151 GURL NetworkFetcher::GetRedirectURL() const {
60 if (!response_) 152 if (!response_)
61 return GURL::EmptyGURL(); 153 return GURL::EmptyGURL();
62 154
63 if (response_->redirect_url.is_null()) 155 if (response_->redirect_url.is_null())
64 return GURL::EmptyGURL(); 156 return GURL::EmptyGURL();
65 157
66 return GURL(response_->redirect_url); 158 return GURL(response_->redirect_url);
67 } 159 }
68 160
69 mojo::URLResponsePtr NetworkFetcher::AsURLResponse( 161 mojo::URLResponsePtr NetworkFetcher::AsURLResponse(
70 base::TaskRunner* task_runner, 162 base::TaskRunner* task_runner,
71 uint32_t skip) { 163 uint32_t skip) {
72 if (skip != 0) { 164 DCHECK(response_);
73 MojoResult result = ReadDataRaw( 165 DCHECK(!path_.empty());
74 response_->body.get(), nullptr, &skip, 166 mojo::DataPipe data_pipe;
75 MOJO_READ_DATA_FLAG_ALL_OR_NONE | MOJO_READ_DATA_FLAG_DISCARD); 167 response_->body = data_pipe.consumer_handle.Pass();
76 DCHECK_EQ(result, MOJO_RESULT_OK); 168 mojo::common::CopyFromFile(path_, data_pipe.producer_handle.Pass(), skip,
77 } 169 task_runner, base::Bind(&IgnoreResult));
78 return response_.Pass(); 170 return response_.Pass();
79 } 171 }
80 172
81 void NetworkFetcher::RecordCacheToURLMapping(const base::FilePath& path,
82 const GURL& url) {
83 // This is used to extract symbols on android.
84 // TODO(eseidel): All users of this log should move to using the map file.
85 LOG(INFO) << "Caching mojo app " << url << " at " << path.value();
86
87 base::FilePath temp_dir;
88 base::GetTempDir(&temp_dir);
89 base::ProcessId pid = base::Process::Current().Pid();
90 std::string map_name = base::StringPrintf("mojo_shell.%d.maps", pid);
91 base::FilePath map_path = temp_dir.Append(map_name);
92
93 // TODO(eseidel): Paths or URLs with spaces will need quoting.
94 std::string map_entry =
95 base::StringPrintf("%s %s\n", path.value().c_str(), url.spec().c_str());
96 // TODO(eseidel): AppendToFile is missing O_CREAT, crbug.com/450696
97 if (!PathExists(map_path))
98 base::WriteFile(map_path, map_entry.data(), map_entry.length());
99 else
100 base::AppendToFile(map_path, map_entry.data(), map_entry.length());
101 }
102
103 void NetworkFetcher::OnFileRetrievedFromCache(
104 base::Callback<void(const base::FilePath&, bool)> callback,
105 mojo::Array<uint8_t> path_as_array,
106 mojo::Array<uint8_t> cache_dir) {
107 bool success = !path_as_array.is_null();
108 if (success) {
109 path_ = base::FilePath(std::string(
110 reinterpret_cast<char*>(&path_as_array.front()), path_as_array.size()));
111 RecordCacheToURLMapping(path_, url_);
112 }
113
114 base::MessageLoop::current()->PostTask(FROM_HERE,
115 base::Bind(callback, path_, success));
116 }
117
118 void NetworkFetcher::AsPath( 173 void NetworkFetcher::AsPath(
119 base::TaskRunner* task_runner, 174 base::TaskRunner* task_runner,
120 base::Callback<void(const base::FilePath&, bool)> callback) { 175 base::Callback<void(const base::FilePath&, bool)> callback) {
121 // This should only called once, when we have a response. 176 // This should only called once, when we have a response.
122 DCHECK(response_.get()); 177 DCHECK(response_.get());
123 178
124 url_response_disk_cache_->GetFile( 179 base::MessageLoop::current()->PostTask(
125 response_.Pass(), base::Bind(&NetworkFetcher::OnFileRetrievedFromCache, 180 FROM_HERE, base::Bind(callback, path_, base::PathExists(path_)));
126 weak_ptr_factory_.GetWeakPtr(), callback)); 181 response_.reset();
182 return;
127 } 183 }
128 184
129 std::string NetworkFetcher::MimeType() { 185 std::string NetworkFetcher::MimeType() {
130 return response_->mime_type; 186 return response_->mime_type;
131 } 187 }
132 188
133 bool NetworkFetcher::HasMojoMagic() { 189 bool NetworkFetcher::HasMojoMagic() {
134 std::string magic; 190 return Fetcher::HasMojoMagic(path_);
135 return BlockingPeekNBytes(response_->body.get(), &magic, strlen(kMojoMagic),
136 kPeekTimeout) &&
137 magic == kMojoMagic;
138 } 191 }
139 192
140 bool NetworkFetcher::PeekFirstLine(std::string* line) { 193 bool NetworkFetcher::PeekFirstLine(std::string* line) {
141 return BlockingPeekLine(response_->body.get(), line, kMaxShebangLength, 194 return Fetcher::PeekFirstLine(path_, line);
142 kPeekTimeout);
143 } 195 }
144 196
145 void NetworkFetcher::StartNetworkRequest(RequestType request_type) { 197 bool NetworkFetcher::CanLoadDirectlyFromCache() {
198 if (disable_cache_)
199 return false;
200
201 const std::string& host = url_.host();
202 return !(host == "localhost" || host == "127.0.0.1" || host == "[::1]");
203 }
204
205 void NetworkFetcher::LoadFromCache(bool schedule_update) {
206 url_response_disk_cache_->Get(
207 mojo::String::From(url_),
208 base::Bind(&NetworkFetcher::OnCachedResponseReceived,
209 base::Unretained(this), schedule_update));
210 }
211
212 void NetworkFetcher::OnCachedResponseReceived(
213 bool schedule_update,
214 mojo::URLResponsePtr response,
215 mojo::Array<uint8_t> path_as_array,
216 mojo::Array<uint8_t> cache_dir) {
217 if (!response) {
218 // Not in cache, loading from net.
219 StartNetworkRequest();
220 return;
221 }
222 if (schedule_update) {
223 // The response has been found in the cache. Plan updating the application.
224 new ApplicationUpdater(
225 url_, base::TimeDelta::FromSeconds(kUpdateApplicationDelayInSeconds),
226 url_response_disk_cache_, network_service_);
227 }
228 response_ = response.Pass();
229 path_ = ToFilePath(path_as_array);
230 RecordCacheToURLMapping(path_, url_);
231 loader_callback_.Run(make_scoped_ptr(this));
232 }
233
234 void NetworkFetcher::StartNetworkRequest() {
146 TRACE_EVENT_ASYNC_BEGIN1("mojo_shell", "NetworkFetcher::NetworkRequest", this, 235 TRACE_EVENT_ASYNC_BEGIN1("mojo_shell", "NetworkFetcher::NetworkRequest", this,
147 "url", url_.spec()); 236 "url", url_.spec());
148 mojo::URLRequestPtr request(mojo::URLRequest::New());
149 request->url = mojo::String::From(url_);
150 request->auto_follow_redirects = false;
151 if (disable_cache_)
152 request->cache_mode = mojo::URLRequest::CACHE_MODE_BYPASS_CACHE;
153 auto header = mojo::HttpHeader::New();
154 header->name = "X-Architecture";
155 header->value = kArchitecture;
156 mojo::Array<mojo::HttpHeaderPtr> headers;
157 headers.push_back(header.Pass());
158 request->headers = headers.Pass();
159
160 network_service_->CreateURLLoader(GetProxy(&url_loader_)); 237 network_service_->CreateURLLoader(GetProxy(&url_loader_));
161 url_loader_->Start(request.Pass(), 238 url_loader_->Start(GetRequest(url_, disable_cache_),
162 base::Bind(&NetworkFetcher::OnLoadComplete, 239 base::Bind(&NetworkFetcher::OnLoadComplete,
163 weak_ptr_factory_.GetWeakPtr(), request_type)); 240 weak_ptr_factory_.GetWeakPtr()));
164 } 241 }
165 242
166 void NetworkFetcher::OnLoadComplete(RequestType request_type, 243 void NetworkFetcher::OnLoadComplete(mojo::URLResponsePtr response) {
167 mojo::URLResponsePtr response) {
168 TRACE_EVENT_ASYNC_END0("mojo_shell", "NetworkFetcher::NetworkRequest", this); 244 TRACE_EVENT_ASYNC_END0("mojo_shell", "NetworkFetcher::NetworkRequest", this);
169 scoped_ptr<Fetcher> owner(this);
170 if (response->error) { 245 if (response->error) {
171 LOG(ERROR) << "Error (" << response->error->code << ": " 246 LOG(ERROR) << "Error (" << response->error->code << ": "
172 << response->error->description << ") while fetching " 247 << response->error->description << ") while fetching "
173 << response->url; 248 << response->url;
174 if (request_type == FROM_NETWORK) { 249 loader_callback_.Run(nullptr);
175 StartNetworkRequest(FROM_CACHE); 250 delete this;
176 } else {
177 loader_callback_.Run(nullptr);
178 }
179 return; 251 return;
180 } 252 }
181 253
182 if (response->status_code >= 400 && response->status_code < 600) { 254 if (response->status_code >= 400 && response->status_code < 600) {
183 LOG(ERROR) << "Error (" << response->status_code << ": " 255 LOG(ERROR) << "Error (" << response->status_code << ": "
184 << response->status_line << "): " 256 << response->status_line << "): "
185 << "while fetching " << response->url; 257 << "while fetching " << response->url;
186 loader_callback_.Run(nullptr); 258 loader_callback_.Run(nullptr);
259 delete this;
187 return; 260 return;
188 } 261 }
189 262
190 response_ = response.Pass(); 263 if (!response->redirect_url.is_null()) {
191 loader_callback_.Run(owner.Pass()); 264 response_ = response.Pass();
265 loader_callback_.Run(make_scoped_ptr(this));
266 return;
267 }
268
269 url_response_disk_cache_->UpdateAndGet(
270 response.Pass(), base::Bind(&NetworkFetcher::OnFileSavedToCache,
271 weak_ptr_factory_.GetWeakPtr()));
272 }
273
274 void NetworkFetcher::OnFileSavedToCache(mojo::Array<uint8_t> path_as_array,
275 mojo::Array<uint8_t> cache_dir) {
276 if (!path_as_array) {
277 LOG(WARNING) << "Error when retrieving content from cache for: "
278 << url_.spec();
279 loader_callback_.Run(nullptr);
280 delete this;
281 return;
282 }
283 LoadFromCache(false);
284 }
285
286 void NetworkFetcher::RecordCacheToURLMapping(const base::FilePath& path,
287 const GURL& url) {
288 // This is used to extract symbols on android.
289 // TODO(eseidel): All users of this log should move to using the map file.
290 LOG(INFO) << "Caching mojo app " << url << " at " << path.value();
291
292 base::FilePath temp_dir;
293 base::GetTempDir(&temp_dir);
294 base::ProcessId pid = base::Process::Current().Pid();
295 std::string map_name = base::StringPrintf("mojo_shell.%d.maps", pid);
296 base::FilePath map_path = temp_dir.Append(map_name);
297
298 // TODO(eseidel): Paths or URLs with spaces will need quoting.
299 std::string map_entry =
300 base::StringPrintf("%s %s\n", path.value().c_str(), url.spec().c_str());
301 // TODO(eseidel): AppendToFile is missing O_CREAT, crbug.com/450696
302 if (!PathExists(map_path)) {
303 base::WriteFile(map_path, map_entry.data(), map_entry.length());
304 } else {
305 base::AppendToFile(map_path, map_entry.data(), map_entry.length());
306 }
192 } 307 }
193 308
194 } // namespace shell 309 } // namespace shell
OLDNEW
« no previous file with comments | « shell/application_manager/network_fetcher.h ('k') | shell/url_response_disk_cache_loader.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698