Chromium Code Reviews| 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 |