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/download/database/download_db_conversions.h"
6 
7 #include <utility>
8 #include "base/logging.h"
9 #include "base/pickle.h"
10 
11 namespace download {
12 
DownloadEntryFromProto(const download_pb::DownloadEntry & proto)13 DownloadEntry DownloadDBConversions::DownloadEntryFromProto(
14     const download_pb::DownloadEntry& proto) {
15   DownloadEntry entry;
16   entry.guid = proto.guid();
17   entry.request_origin = proto.request_origin();
18   entry.download_source = DownloadSourceFromProto(proto.download_source());
19   entry.ukm_download_id = proto.ukm_download_id();
20   entry.bytes_wasted = proto.bytes_wasted();
21   entry.fetch_error_body = proto.fetch_error_body();
22   for (const auto& header : proto.request_headers()) {
23     entry.request_headers.emplace_back(HttpRequestHeaderFromProto(header));
24   }
25   return entry;
26 }
27 
DownloadEntryToProto(const DownloadEntry & entry)28 download_pb::DownloadEntry DownloadDBConversions::DownloadEntryToProto(
29     const DownloadEntry& entry) {
30   download_pb::DownloadEntry proto;
31   proto.set_guid(entry.guid);
32   proto.set_request_origin(entry.request_origin);
33   proto.set_download_source(DownloadSourceToProto(entry.download_source));
34   proto.set_ukm_download_id(entry.ukm_download_id);
35   proto.set_bytes_wasted(entry.bytes_wasted);
36   proto.set_fetch_error_body(entry.fetch_error_body);
37   for (const auto& header : entry.request_headers) {
38     auto* proto_header = proto.add_request_headers();
39     *proto_header = HttpRequestHeaderToProto(header);
40   }
41   return proto;
42 }
43 
44 // static
DownloadSourceFromProto(download_pb::DownloadSource download_source)45 DownloadSource DownloadDBConversions::DownloadSourceFromProto(
46     download_pb::DownloadSource download_source) {
47   switch (download_source) {
48     case download_pb::DownloadSource::UNKNOWN:
49       return DownloadSource::UNKNOWN;
50     case download_pb::DownloadSource::NAVIGATION:
51       return DownloadSource::NAVIGATION;
52     case download_pb::DownloadSource::DRAG_AND_DROP:
53       return DownloadSource::DRAG_AND_DROP;
54     case download_pb::DownloadSource::FROM_RENDERER:
55       return DownloadSource::FROM_RENDERER;
56     case download_pb::DownloadSource::EXTENSION_API:
57       return DownloadSource::EXTENSION_API;
58     case download_pb::DownloadSource::EXTENSION_INSTALLER:
59       return DownloadSource::EXTENSION_INSTALLER;
60     case download_pb::DownloadSource::INTERNAL_API:
61       return DownloadSource::INTERNAL_API;
62     case download_pb::DownloadSource::WEB_CONTENTS_API:
63       return DownloadSource::WEB_CONTENTS_API;
64     case download_pb::DownloadSource::OFFLINE_PAGE:
65       return DownloadSource::OFFLINE_PAGE;
66     case download_pb::DownloadSource::CONTEXT_MENU:
67       return DownloadSource::CONTEXT_MENU;
68     case download_pb::DownloadSource::RETRY:
69       return DownloadSource::RETRY;
70   }
71   NOTREACHED();
72   return DownloadSource::UNKNOWN;
73 }
74 
75 // static
DownloadSourceToProto(DownloadSource download_source)76 download_pb::DownloadSource DownloadDBConversions::DownloadSourceToProto(
77     DownloadSource download_source) {
78   switch (download_source) {
79     case DownloadSource::UNKNOWN:
80       return download_pb::DownloadSource::UNKNOWN;
81     case DownloadSource::NAVIGATION:
82       return download_pb::DownloadSource::NAVIGATION;
83     case DownloadSource::DRAG_AND_DROP:
84       return download_pb::DownloadSource::DRAG_AND_DROP;
85     case DownloadSource::FROM_RENDERER:
86       return download_pb::DownloadSource::FROM_RENDERER;
87     case DownloadSource::EXTENSION_API:
88       return download_pb::DownloadSource::EXTENSION_API;
89     case DownloadSource::EXTENSION_INSTALLER:
90       return download_pb::DownloadSource::EXTENSION_INSTALLER;
91     case DownloadSource::INTERNAL_API:
92       return download_pb::DownloadSource::INTERNAL_API;
93     case DownloadSource::WEB_CONTENTS_API:
94       return download_pb::DownloadSource::WEB_CONTENTS_API;
95     case DownloadSource::OFFLINE_PAGE:
96       return download_pb::DownloadSource::OFFLINE_PAGE;
97     case DownloadSource::CONTEXT_MENU:
98       return download_pb::DownloadSource::CONTEXT_MENU;
99     case DownloadSource::RETRY:
100       return download_pb::DownloadSource::RETRY;
101   }
102   NOTREACHED();
103   return download_pb::DownloadSource::UNKNOWN;
104 }
105 
DownloadEntriesFromProto(const download_pb::DownloadEntries & proto)106 std::vector<DownloadEntry> DownloadDBConversions::DownloadEntriesFromProto(
107     const download_pb::DownloadEntries& proto) {
108   std::vector<DownloadEntry> entries;
109   for (int i = 0; i < proto.entries_size(); i++)
110     entries.push_back(DownloadEntryFromProto(proto.entries(i)));
111   return entries;
112 }
113 
DownloadEntriesToProto(const std::vector<DownloadEntry> & entries)114 download_pb::DownloadEntries DownloadDBConversions::DownloadEntriesToProto(
115     const std::vector<DownloadEntry>& entries) {
116   download_pb::DownloadEntries proto;
117   for (size_t i = 0; i < entries.size(); i++) {
118     download_pb::DownloadEntry* proto_entry = proto.add_entries();
119     *proto_entry = DownloadEntryToProto(entries[i]);
120   }
121   return proto;
122 }
123 
124 // static
HttpRequestHeaderToProto(const std::pair<std::string,std::string> & header)125 download_pb::HttpRequestHeader DownloadDBConversions::HttpRequestHeaderToProto(
126     const std::pair<std::string, std::string>& header) {
127   download_pb::HttpRequestHeader proto;
128   if (header.first.empty())
129     return proto;
130 
131   proto.set_key(header.first);
132   proto.set_value(header.second);
133   return proto;
134 }
135 
136 // static
137 std::pair<std::string, std::string>
HttpRequestHeaderFromProto(const download_pb::HttpRequestHeader & proto)138 DownloadDBConversions::HttpRequestHeaderFromProto(
139     const download_pb::HttpRequestHeader& proto) {
140   if (proto.key().empty())
141     return std::pair<std::string, std::string>();
142 
143   return std::make_pair(proto.key(), proto.value());
144 }
145 
146 // static
InProgressInfoToProto(const InProgressInfo & in_progress_info)147 download_pb::InProgressInfo DownloadDBConversions::InProgressInfoToProto(
148     const InProgressInfo& in_progress_info) {
149   download_pb::InProgressInfo proto;
150   for (size_t i = 0; i < in_progress_info.url_chain.size(); ++i)
151     proto.add_url_chain(in_progress_info.url_chain[i].spec());
152   proto.set_referrer_url(in_progress_info.referrer_url.spec());
153   proto.set_site_url(in_progress_info.site_url.spec());
154   proto.set_tab_url(in_progress_info.tab_url.spec());
155   proto.set_tab_referrer_url(in_progress_info.tab_referrer_url.spec());
156   proto.set_fetch_error_body(in_progress_info.fetch_error_body);
157   for (const auto& header : in_progress_info.request_headers) {
158     auto* proto_header = proto.add_request_headers();
159     *proto_header = HttpRequestHeaderToProto(header);
160   }
161   proto.set_etag(in_progress_info.etag);
162   proto.set_last_modified(in_progress_info.last_modified);
163   proto.set_mime_type(in_progress_info.mime_type);
164   proto.set_original_mime_type(in_progress_info.original_mime_type);
165   proto.set_total_bytes(in_progress_info.total_bytes);
166   base::Pickle current_path;
167   in_progress_info.current_path.WriteToPickle(&current_path);
168   proto.set_current_path(current_path.data(), current_path.size());
169   base::Pickle target_path;
170   in_progress_info.target_path.WriteToPickle(&target_path);
171   proto.set_target_path(target_path.data(), target_path.size());
172   proto.set_received_bytes(in_progress_info.received_bytes);
173   proto.set_start_time(
174       in_progress_info.start_time.is_null()
175           ? -1
176           : in_progress_info.start_time.ToDeltaSinceWindowsEpoch()
177                 .InMilliseconds());
178   proto.set_end_time(in_progress_info.end_time.is_null()
179                          ? -1
180                          : in_progress_info.end_time.ToDeltaSinceWindowsEpoch()
181                                .InMilliseconds());
182   for (size_t i = 0; i < in_progress_info.received_slices.size(); ++i) {
183     download_pb::ReceivedSlice* slice = proto.add_received_slices();
184     slice->set_received_bytes(
185         in_progress_info.received_slices[i].received_bytes);
186     slice->set_offset(in_progress_info.received_slices[i].offset);
187     slice->set_finished(in_progress_info.received_slices[i].finished);
188   }
189   proto.set_hash(in_progress_info.hash);
190   proto.set_transient(in_progress_info.transient);
191   proto.set_state(in_progress_info.state);
192   proto.set_danger_type(in_progress_info.danger_type);
193   proto.set_interrupt_reason(in_progress_info.interrupt_reason);
194   proto.set_paused(in_progress_info.paused);
195   proto.set_metered(in_progress_info.metered);
196   proto.set_bytes_wasted(in_progress_info.bytes_wasted);
197   proto.set_auto_resume_count(in_progress_info.auto_resume_count);
198   return proto;
199 }
200 
201 // static
InProgressInfoFromProto(const download_pb::InProgressInfo & proto)202 InProgressInfo DownloadDBConversions::InProgressInfoFromProto(
203     const download_pb::InProgressInfo& proto) {
204   InProgressInfo info;
205   for (const auto& url : proto.url_chain())
206     info.url_chain.emplace_back(url);
207   info.referrer_url = GURL(proto.referrer_url());
208   info.site_url = GURL(proto.site_url());
209   info.tab_url = GURL(proto.tab_url());
210   info.tab_referrer_url = GURL(proto.tab_referrer_url());
211   info.fetch_error_body = proto.fetch_error_body();
212   for (const auto& header : proto.request_headers())
213     info.request_headers.emplace_back(HttpRequestHeaderFromProto(header));
214   info.etag = proto.etag();
215   info.last_modified = proto.last_modified();
216   info.mime_type = proto.mime_type();
217   info.original_mime_type = proto.original_mime_type();
218   info.total_bytes = proto.total_bytes();
219   base::PickleIterator current_path(
220       base::Pickle(proto.current_path().data(), proto.current_path().size()));
221   info.current_path.ReadFromPickle(&current_path);
222   base::PickleIterator target_path(
223       base::Pickle(proto.target_path().data(), proto.target_path().size()));
224   info.target_path.ReadFromPickle(&target_path);
225   info.received_bytes = proto.received_bytes();
226   info.start_time =
227       proto.start_time() == -1
228           ? base::Time()
229           : base::Time::FromDeltaSinceWindowsEpoch(
230                 base::TimeDelta::FromMilliseconds(proto.start_time()));
231   info.end_time =
232       proto.end_time() == -1
233           ? base::Time()
234           : base::Time::FromDeltaSinceWindowsEpoch(
235                 base::TimeDelta::FromMilliseconds(proto.end_time()));
236 
237   for (int i = 0; i < proto.received_slices_size(); ++i) {
238     info.received_slices.emplace_back(proto.received_slices(i).offset(),
239                                       proto.received_slices(i).received_bytes(),
240                                       proto.received_slices(i).finished());
241   }
242   info.hash = proto.hash();
243   info.transient = proto.transient();
244   info.state = static_cast<DownloadItem::DownloadState>(proto.state());
245   info.danger_type = static_cast<DownloadDangerType>(proto.danger_type());
246   info.interrupt_reason =
247       static_cast<DownloadInterruptReason>(proto.interrupt_reason());
248   info.paused = proto.paused();
249   info.metered = proto.metered();
250   info.bytes_wasted = proto.bytes_wasted();
251   info.auto_resume_count = proto.auto_resume_count();
252   return info;
253 }
254 
UkmInfoFromProto(const download_pb::UkmInfo & proto)255 UkmInfo DownloadDBConversions::UkmInfoFromProto(
256     const download_pb::UkmInfo& proto) {
257   UkmInfo info;
258   info.download_source = DownloadSourceFromProto(proto.download_source());
259   info.ukm_download_id = proto.ukm_download_id();
260   return info;
261 }
262 
UkmInfoToProto(const UkmInfo & info)263 download_pb::UkmInfo DownloadDBConversions::UkmInfoToProto(
264     const UkmInfo& info) {
265   download_pb::UkmInfo proto;
266   proto.set_download_source(DownloadSourceToProto(info.download_source));
267   proto.set_ukm_download_id(info.ukm_download_id);
268   return proto;
269 }
270 
DownloadInfoFromProto(const download_pb::DownloadInfo & proto)271 DownloadInfo DownloadDBConversions::DownloadInfoFromProto(
272     const download_pb::DownloadInfo& proto) {
273   DownloadInfo info;
274   info.guid = proto.guid();
275   info.id = proto.id();
276   if (proto.has_ukm_info())
277     info.ukm_info = UkmInfoFromProto(proto.ukm_info());
278   if (proto.has_in_progress_info())
279     info.in_progress_info = InProgressInfoFromProto(proto.in_progress_info());
280   return info;
281 }
282 
DownloadInfoToProto(const DownloadInfo & info)283 download_pb::DownloadInfo DownloadDBConversions::DownloadInfoToProto(
284     const DownloadInfo& info) {
285   download_pb::DownloadInfo proto;
286   proto.set_guid(info.guid);
287   proto.set_id(info.id);
288   if (info.ukm_info.has_value()) {
289     auto ukm_info = std::make_unique<download_pb::UkmInfo>(
290         UkmInfoToProto(info.ukm_info.value()));
291     proto.set_allocated_ukm_info(ukm_info.release());
292   }
293   if (info.in_progress_info.has_value()) {
294     auto in_progress_info = std::make_unique<download_pb::InProgressInfo>(
295         InProgressInfoToProto(info.in_progress_info.value()));
296     proto.set_allocated_in_progress_info(in_progress_info.release());
297   }
298   return proto;
299 }
300 
DownloadDBEntryFromProto(const download_pb::DownloadDBEntry & proto)301 DownloadDBEntry DownloadDBConversions::DownloadDBEntryFromProto(
302     const download_pb::DownloadDBEntry& proto) {
303   DownloadDBEntry entry;
304   if (proto.has_download_info())
305     entry.download_info = DownloadInfoFromProto(proto.download_info());
306   return entry;
307 }
308 
DownloadDBEntryToProto(const DownloadDBEntry & info)309 download_pb::DownloadDBEntry DownloadDBConversions::DownloadDBEntryToProto(
310     const DownloadDBEntry& info) {
311   download_pb::DownloadDBEntry proto;
312   if (info.download_info.has_value()) {
313     auto download_info = std::make_unique<download_pb::DownloadInfo>(
314         DownloadInfoToProto(info.download_info.value()));
315     proto.set_allocated_download_info(download_info.release());
316   }
317   return proto;
318 }
319 
DownloadDBEntryFromDownloadEntry(const DownloadEntry & entry)320 DownloadDBEntry DownloadDBConversions::DownloadDBEntryFromDownloadEntry(
321     const DownloadEntry& entry) {
322   DownloadDBEntry db_entry;
323   DownloadInfo download_info;
324   download_info.guid = entry.guid;
325 
326   UkmInfo ukm_info(entry.download_source, entry.ukm_download_id);
327 
328   InProgressInfo in_progress_info;
329   in_progress_info.fetch_error_body = entry.fetch_error_body;
330   in_progress_info.request_headers = entry.request_headers;
331 
332   download_info.ukm_info = ukm_info;
333   download_info.in_progress_info = in_progress_info;
334   db_entry.download_info = download_info;
335   return db_entry;
336 }
337 
338 }  // namespace download
339