OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2017 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 "components/offline_pages/core/prefetch/generate_page_bundle_request.h" | |
6 | |
7 #include "base/bind.h" | |
8 #include "base/location.h" | |
9 #include "base/logging.h" | |
10 #include "base/strings/string_util.h" | |
11 #include "components/offline_pages/core/prefetch/prefetch_request_fetcher.h" | |
12 #include "components/offline_pages/core/prefetch/proto/offline_pages.pb.h" | |
13 #include "components/offline_pages/core/prefetch/proto/operation.pb.h" | |
14 #include "net/url_request/url_request_context_getter.h" | |
15 #include "url/gurl.h" | |
16 | |
17 namespace offline_pages { | |
18 | |
19 namespace { | |
20 // TODO(jianli): Update when server is ready. | |
21 const GURL kOfflinePrefetchServiceUrl( | |
22 "http://localhost:12345/v1:GeneratePageBundle"); | |
23 } | |
24 | |
25 GeneratePageBundleRequest::GeneratePageBundleRequest( | |
26 const std::string& user_agent, | |
27 const std::string& gcm_registration_id, | |
28 int max_bundle_size_bytes, | |
29 const std::vector<std::string>& page_urls, | |
dewittj
2017/05/11 21:51:48
why is this strings and not GURL?
| |
30 net::URLRequestContextGetter* request_context_getter, | |
31 const FinishedCallback& callback) | |
32 : callback_(callback) { | |
33 proto::GeneratePageBundleRequest request; | |
34 request.set_user_agent(user_agent); | |
35 request.set_max_bundle_size_bytes(max_bundle_size_bytes); | |
36 request.set_output_format(proto::FORMAT_MHTML); | |
37 request.set_gcm_registration_id(gcm_registration_id); | |
38 | |
39 for (const auto& page_url : page_urls) { | |
40 proto::PageParameters* page = request.add_pages(); | |
41 page->set_url(page_url); | |
42 page->set_transformation(proto::NO_TRANSFORMATION); | |
43 } | |
44 | |
45 std::string upload_data; | |
46 request.SerializeToString(&upload_data); | |
47 | |
48 fetcher_.reset(new PrefetchRequestFetcher( | |
49 kOfflinePrefetchServiceUrl, upload_data, request_context_getter, | |
50 base::Bind(&GeneratePageBundleRequest::OnCompleted, | |
51 // Fetcher is owned by this instance. | |
52 base::Unretained(this)))); | |
53 } | |
54 | |
55 GeneratePageBundleRequest::~GeneratePageBundleRequest() {} | |
56 | |
57 void GeneratePageBundleRequest::OnCompleted(RequestStatus status, | |
58 const std::string& data) { | |
59 proto::Operation operation; | |
60 if (!operation.ParseFromString(data)) { | |
61 DVLOG(1) << "Failed to parse GeneratePageBundle response"; | |
62 NotifyParsingFailure(); | |
63 return; | |
64 } | |
65 | |
66 if (operation.done()) | |
67 ParseDoneOperationResponse(operation); | |
68 else | |
69 ParsePendingOperationResponse(operation); | |
70 } | |
71 | |
72 void GeneratePageBundleRequest::ParseDoneOperationResponse( | |
73 const proto::Operation& operation) { | |
74 if (operation.result_case() == proto::Operation::kError) { | |
dewittj
2017/05/11 18:46:43
kError is not defined?
jianli
2017/05/11 20:45:14
It is defined in the generated file operation.pb.h
| |
75 DVLOG(1) << "Error found in GeneratePageBundle response"; | |
76 NotifyParsingFailure(); | |
77 return; | |
78 } | |
79 | |
80 DCHECK_EQ(proto::Operation::kResponse, operation.result_case()); | |
81 ParsePageBundleInAnyData(operation.response()); | |
82 } | |
83 | |
84 void GeneratePageBundleRequest::ParsePendingOperationResponse( | |
85 const proto::Operation& operation) { | |
86 if (!operation.has_metadata()) { | |
87 DVLOG(1) << "metadata not found in GeneratePageBundle response"; | |
dewittj
2017/05/11 18:46:43
Is metadata guaranteed?
jianli
2017/05/11 20:45:14
Yes. The server will return something in metadata
| |
88 NotifyParsingFailure(); | |
89 return; | |
90 } | |
91 ParsePageBundleInAnyData(operation.metadata()); | |
92 } | |
93 | |
94 void GeneratePageBundleRequest::ParsePageBundleInAnyData( | |
95 const proto::Any& any_data) { | |
96 if (!base::StartsWith(any_data.type_url(), "type.googleapis.com/", | |
97 base::CompareCase::SENSITIVE) && | |
98 !base::EndsWith(any_data.type_url(), ".PageBundle", | |
99 base::CompareCase::SENSITIVE)) { | |
100 DVLOG(1) << "Wrong type url in any data"; | |
101 NotifyParsingFailure(); | |
102 return; | |
103 } | |
104 | |
105 proto::PageBundle page_bundle; | |
106 if (!page_bundle.ParseFromString(any_data.value())) { | |
107 DVLOG(1) << "Failed to parse PageBundle in any data"; | |
108 NotifyParsingFailure(); | |
109 return; | |
110 } | |
111 | |
112 if (!page_bundle.archives_size()) { | |
113 DVLOG(1) << "No archive in PageBundle"; | |
114 NotifyParsingFailure(); | |
115 return; | |
116 } | |
117 | |
118 std::vector<PageInfo> pages; | |
119 for (int i = 0; i < page_bundle.archives_size(); ++i) { | |
120 const proto::Archive& archive = page_bundle.archives(i); | |
121 | |
122 if (!archive.page_infos_size()) { | |
123 DVLOG(1) << "No page in archive"; | |
124 NotifyParsingFailure(); | |
125 return; | |
126 } | |
127 | |
128 // Only one page is available in PageInfos. | |
129 const proto::PageInfo& page_info = archive.page_infos(0); | |
130 | |
131 if (page_info.url().empty()) { | |
132 DVLOG(1) << "Empty page url"; | |
133 NotifyParsingFailure(); | |
134 return; | |
135 } | |
136 | |
137 PageInfo page; | |
138 page.url = page_info.url(); | |
139 page.redirect_url = page_info.redirect_url(); | |
140 if (page_info.has_status()) { | |
141 switch (page_info.status().code()) { | |
142 case proto::OK: | |
143 page.status = RenderStatus::RENDERED; | |
144 break; | |
145 case proto::NOT_FOUND: | |
146 page.status = RenderStatus::PENDING_TO_RENDER; | |
147 break; | |
148 case proto::FAILED_PRECONDITION: | |
149 page.status = RenderStatus::EXCEEDED_LIMIT; | |
150 break; | |
151 case proto::UNKNOWN: | |
152 page.status = RenderStatus::FAILED_TO_RENDER; | |
153 break; | |
154 default: | |
155 NOTREACHED(); | |
156 break; | |
157 } | |
158 } else { | |
159 page.status = RenderStatus::RENDERED; | |
160 } | |
161 | |
162 if (page.status == RenderStatus::RENDERED) { | |
163 page.body_name = archive.body_name(); | |
164 page.body_length = archive.body_length(); | |
165 page.render_time = | |
166 base::Time::FromJavaTime(page_info.render_time().seconds() * 1000 + | |
167 page_info.render_time().nanos() / 1000000); | |
168 } | |
169 | |
170 DVLOG(1) << "Got page " << page.url << " " << static_cast<int>(page.status) | |
171 << " " << page.body_name << " " << page.body_length; | |
172 pages.push_back(page); | |
173 } | |
174 | |
175 callback_.Run(RequestStatus::SUCCESS, pages); | |
176 } | |
177 | |
178 void GeneratePageBundleRequest::NotifyParsingFailure() { | |
179 callback_.Run(RequestStatus::SHOULD_RETRY_WITH_BACKOFF, | |
180 std::vector<PageInfo>()); | |
181 } | |
182 | |
183 } // offline_pages | |
OLD | NEW |