Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code

Delta Between Two Patch Sets: compiled/subscription/DownloadableSubscription.cpp

Issue 29606600: Issue 5146 - Implement DownloadableSubscription parsing in C++ (Closed) Base URL: https://hg.adblockplus.org/adblockpluscore/
Left Patch Set: Now all test pass (almost unchanged). Addressed many issues. Created Dec. 1, 2017, 2:41 a.m.
Right Patch Set: Removed Md5sum and associated code Created Aug. 14, 2018, 12:38 p.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
Left: Side by side diff | Download
Right: Side by side diff | Download
« no previous file with change/comment | « compiled/subscription/DownloadableSubscription.h ('k') | compiled/subscription/Subscription.h » ('j') | no next file with change/comment »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
1 /* 1 /*
2 * This file is part of Adblock Plus <https://adblockplus.org/>, 2 * This file is part of Adblock Plus <https://adblockplus.org/>,
3 * Copyright (C) 2006-present eyeo GmbH 3 * Copyright (C) 2006-present eyeo GmbH
4 * 4 *
5 * Adblock Plus is free software: you can redistribute it and/or modify 5 * Adblock Plus is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 3 as 6 * it under the terms of the GNU General Public License version 3 as
7 * published by the Free Software Foundation. 7 * published by the Free Software Foundation.
8 * 8 *
9 * Adblock Plus is distributed in the hope that it will be useful, 9 * Adblock Plus is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details. 12 * GNU General Public License for more details.
13 * 13 *
14 * You should have received a copy of the GNU General Public License 14 * You should have received a copy of the GNU General Public License
15 * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>. 15 * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
16 */ 16 */
17 17
18 #include <cwctype> 18 #include <cwctype>
19 #include <limits> 19 #include <limits>
20 20
21 #include "DownloadableSubscription.h" 21 #include "DownloadableSubscription.h"
22 #include "../Base64.h"
23 #include "../FilterNotifier.h" 22 #include "../FilterNotifier.h"
24 #include "../StringScanner.h" 23 #include "../StringScanner.h"
25 #include "../filter/CommentFilter.h" 24 #include "../filter/CommentFilter.h"
25
26 ABP_NS_USING
26 27
27 namespace { 28 namespace {
28 constexpr int MILLIS_IN_HOUR = 60 * 60 * 1000; 29 constexpr int MILLIS_IN_HOUR = 60 * 60 * 1000;
29 constexpr int MILLIS_IN_DAY = 24 * MILLIS_IN_HOUR; 30 constexpr int MILLIS_IN_DAY = 24 * MILLIS_IN_HOUR;
30 // limits 31 // limits
31 constexpr int64_t MAX_HOUR = std::numeric_limits<int64_t>::max() / MILLIS_IN_H OUR; 32 constexpr int64_t MAX_HOUR = std::numeric_limits<int64_t>::max() / MILLIS_IN_H OUR;
32 constexpr int64_t MAX_DAY = std::numeric_limits<int64_t>::max() / MILLIS_IN_DA Y; 33 constexpr int64_t MAX_DAY = std::numeric_limits<int64_t>::max() / MILLIS_IN_DA Y;
33 34
34 typedef std::pair<DependentString, DependentString> Param; 35 typedef std::pair<DependentString, DependentString> Param;
35 36
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
86 } 87 }
87 88
88 DownloadableSubscription_Parser::DownloadableSubscription_Parser() 89 DownloadableSubscription_Parser::DownloadableSubscription_Parser()
89 : mFirstLine(true) 90 : mFirstLine(true)
90 { 91 {
91 annotate_address(this, "DownloadableSubscription_Parser"); 92 annotate_address(this, "DownloadableSubscription_Parser");
92 } 93 }
93 94
94 namespace { 95 namespace {
95 const DependentString ADBLOCK_HEADER(u"[Adblock"_str); 96 const DependentString ADBLOCK_HEADER(u"[Adblock"_str);
96
97 // Only check for trailing base64 padding. There should be at most 2 '='.
98 // In that case return a truncated string.
99 DependentString CleanUpChecksum(const String& checksum)
100 {
101 const auto len = checksum.length();
102 if ((len > 22 && len <= 24) &&
103 (checksum[22] == u'=' && (len == 23 || checksum[23] == u'=')))
104 return DependentString(checksum, 0, 22);
105 return DependentString(checksum);
106 }
107 } 97 }
108 98
109 void DownloadableSubscription_Parser::Process(const String& line) 99 void DownloadableSubscription_Parser::Process(const String& line)
110 { 100 {
111 bool isHeader = false; 101 bool isHeader = false;
112 bool doChecksum = true;
113 isHeader = line.find(ADBLOCK_HEADER) != String::npos; 102 isHeader = line.find(ADBLOCK_HEADER) != String::npos;
114 auto param = ParseParam(line); 103 if (!isHeader)
115 if (!param.first.is_invalid()) 104 {
116 { 105 auto param = ParseParam(line);
117 if (param.first == u"checksum"_str) 106 if (param.first.is_invalid())
118 { 107 mFiltersText.emplace_back(line);
119 mParams[param.first] = CleanUpChecksum(param.second);
120 doChecksum = false;
121 }
122 else 108 else
123 mParams[param.first] = param.second; 109 mParams[param.first] = param.second;
124 } 110 }
125 // Checksum is an MD5 checksum (base64-encoded without the trailing "=") of
126 // all lines in UTF-8 without the checksum line, joined with "\n".
127 if (doChecksum)
128 {
129 if (!mFirstLine)
130 mChecksum.Update((const uint8_t*)"\n", 1);
131 else
132 mFirstLine = false;
133 mChecksum.Update(line);
134 }
135 if (param.first.is_invalid() && !isHeader)
136 mFiltersText.emplace_back(line);
137 } 111 }
138 112
139 int64_t DownloadableSubscription_Parser::ParseExpires(const String& expires) 113 int64_t DownloadableSubscription_Parser::ParseExpires(const String& expires)
140 { 114 {
141 bool isHour = false; 115 bool isHour = false;
142 StringScanner scanner(expires); 116 StringScanner scanner(expires);
143 String::size_type numStart = 0; 117 String::size_type numStart = 0;
144 String::size_type numLen = 0; 118 String::size_type numLen = 0;
145 while(!scanner.done()) 119 while(!scanner.done())
146 { 120 {
(...skipping 11 matching lines...) Expand all
158 } 132 }
159 else 133 else
160 { 134 {
161 if (numLen) 135 if (numLen)
162 scanner.back(); 136 scanner.back();
163 break; 137 break;
164 } 138 }
165 } 139 }
166 140
167 DependentString numStr(expires, numStart, numLen); 141 DependentString numStr(expires, numStart, numLen);
168 int64_t num = numStr.toInt<int64_t>(); 142 int64_t num = lexical_cast<int64_t>(numStr);
169 if (num == 0) 143 if (num == 0)
170 return 0; 144 return 0;
171 145
172 while (!scanner.done()) 146 while (!scanner.done())
173 { 147 {
174 auto ch = scanner.next(); 148 auto ch = scanner.next();
175 if (std::iswspace(ch)) 149 if (std::iswspace(ch))
176 continue; 150 continue;
177 151
178 if (ch == u'h') 152 if (ch == u'h')
179 isHour = true; 153 isHour = true;
180 154
181 // assume we are done here. The rest is ignored. 155 // assume we are done here. The rest is ignored.
182 break; 156 break;
183 } 157 }
184 // check for overflow. 158 // check for overflow.
185 if ((isHour && (num > MAX_HOUR)) || (num > MAX_DAY)) 159 if ((isHour && (num > MAX_HOUR)) || (num > MAX_DAY))
186 return 0; 160 return 0;
187 161
188 num *= isHour ? MILLIS_IN_HOUR : MILLIS_IN_DAY; 162 num *= isHour ? MILLIS_IN_HOUR : MILLIS_IN_DAY;
189 return num; 163 return num;
190 } 164 }
191 165
192 bool DownloadableSubscription_Parser::VerifyChecksum()
193 {
194 if (!mParams.find(u"checksum"_str))
195 return true;
196
197 if (mB64Checksum.is_invalid())
198 {
199 uint8_t checksum[MD5::CHECKSUM_LENGTH];
200 mChecksum.Final(checksum);
201 mB64Checksum = ToBase64(checksum, MD5::CHECKSUM_LENGTH);
202 }
203 return (mParams[u"checksum"_str] == mB64Checksum);
204 }
205
206 int64_t DownloadableSubscription_Parser::Finalize(DownloadableSubscription& subs cription) 166 int64_t DownloadableSubscription_Parser::Finalize(DownloadableSubscription& subs cription)
207 { 167 {
208 if (mB64Checksum.is_invalid())
209 VerifyChecksum(); // here we ignore the checksum, but we calculate it.
210
211 auto entry = mParams.find(u"title"_str); 168 auto entry = mParams.find(u"title"_str);
212 if (entry) 169 if (entry)
213 { 170 {
214 subscription.SetTitle(entry->second); 171 subscription.SetTitle(entry->second);
215 subscription.SetFixedTitle(true); 172 subscription.SetFixedTitle(true);
216 } 173 }
217 else 174 else
218 subscription.SetFixedTitle(false); 175 subscription.SetFixedTitle(false);
219 176
220 int32_t version = 0; 177 int32_t version = 0;
221 entry = mParams.find(u"version"_str); 178 entry = mParams.find(u"version"_str);
222 if (entry) 179 if (entry)
223 version = entry->second.toInt<int32_t>(); 180 version = lexical_cast<int32_t>(entry->second);
224 subscription.SetDataRevision(version); 181 subscription.SetDataRevision(version);
225 182
226 int64_t expires = 0; 183 int64_t expires = 0;
227 entry = mParams.find(u"expires"_str); 184 entry = mParams.find(u"expires"_str);
228 if (entry) 185 if (entry)
229 expires = ParseExpires(entry->second); 186 expires = ParseExpires(entry->second);
230 187
231 FilterNotifier::SubscriptionChange( 188 FilterNotifier::SubscriptionChange(
232 FilterNotifier::Topic::SUBSCRIPTION_BEFORE_FILTERS_REPLACED, 189 FilterNotifier::Topic::SUBSCRIPTION_BEFORE_FILTERS_REPLACED,
233 subscription); 190 subscription);
(...skipping 25 matching lines...) Expand all
259 return emptyString; 216 return emptyString;
260 } 217 }
261 218
262 const String& DownloadableSubscription_Parser::GetHomepage() const 219 const String& DownloadableSubscription_Parser::GetHomepage() const
263 { 220 {
264 auto entry = mParams.find(u"homepage"_str); 221 auto entry = mParams.find(u"homepage"_str);
265 if (entry) 222 if (entry)
266 return entry->second; 223 return entry->second;
267 return emptyString; 224 return emptyString;
268 } 225 }
226
227 ABP_NS_USING
269 228
270 DownloadableSubscription::DownloadableSubscription(const String& id) 229 DownloadableSubscription::DownloadableSubscription(const String& id)
271 : Subscription(classType, id), mFixedTitle(false), mLastCheck(0), 230 : Subscription(classType, id), mFixedTitle(false), mLastCheck(0),
272 mHardExpiration(0), mSoftExpiration(0), mLastDownload(0), mLastSuccess(0), 231 mHardExpiration(0), mSoftExpiration(0), mLastDownload(0), mLastSuccess(0),
273 mErrorCount(0), mDataRevision(0), mDownloadCount(0) 232 mErrorCount(0), mDataRevision(0), mDownloadCount(0)
274 { 233 {
275 SetTitle(id); 234 SetTitle(id);
276 } 235 }
277 236
278 DownloadableSubscription_Parser* DownloadableSubscription::ParseDownload() 237 DownloadableSubscription_Parser* DownloadableSubscription::ParseDownload()
279 { 238 {
280 return new DownloadableSubscription_Parser(); 239 return new DownloadableSubscription_Parser();
281 } 240 }
282 241
283 OwnedString DownloadableSubscription::Serialize() const 242 OwnedString DownloadableSubscription::Serialize() const
284 { 243 {
285 OwnedString result(Subscription::Serialize()); 244 OwnedString result(Subscription::Serialize());
286 if (mFixedTitle) 245 if (mFixedTitle)
287 result.append(u"fixedTitle=true\n"_str); 246 result.append(ABP_TEXT("fixedTitle=true\n"_str));
288 if (!mHomepage.empty()) 247 if (!mHomepage.empty())
289 { 248 {
290 result.append(u"homepage="_str); 249 result.append(ABP_TEXT("homepage="_str));
291 result.append(mHomepage); 250 result.append(mHomepage);
292 result.append(u'\n'); 251 result.append(ABP_TEXT('\n'));
293 } 252 }
294 if (mLastCheck) 253 if (mLastCheck)
295 { 254 {
296 result.append(u"lastCheck="_str); 255 result.append(ABP_TEXT("lastCheck="_str));
297 result.append(mLastCheck); 256 result.append(mLastCheck);
298 result.append(u'\n'); 257 result.append(ABP_TEXT('\n'));
299 } 258 }
300 if (mHardExpiration) 259 if (mHardExpiration)
301 { 260 {
302 result.append(u"expires="_str); 261 result.append(ABP_TEXT("expires="_str));
303 result.append(mHardExpiration); 262 result.append(mHardExpiration);
304 result.append(u'\n'); 263 result.append(ABP_TEXT('\n'));
305 } 264 }
306 if (mSoftExpiration) 265 if (mSoftExpiration)
307 { 266 {
308 result.append(u"softExpiration="_str); 267 result.append(ABP_TEXT("softExpiration="_str));
309 result.append(mSoftExpiration); 268 result.append(mSoftExpiration);
310 result.append(u'\n'); 269 result.append(ABP_TEXT('\n'));
311 } 270 }
312 if (mLastDownload) 271 if (mLastDownload)
313 { 272 {
314 result.append(u"lastDownload="_str); 273 result.append(ABP_TEXT("lastDownload="_str));
315 result.append(mLastDownload); 274 result.append(mLastDownload);
316 result.append(u'\n'); 275 result.append(ABP_TEXT('\n'));
317 } 276 }
318 if (!mDownloadStatus.empty()) 277 if (!mDownloadStatus.empty())
319 { 278 {
320 result.append(u"downloadStatus="_str); 279 result.append(ABP_TEXT("downloadStatus="_str));
321 result.append(mDownloadStatus); 280 result.append(mDownloadStatus);
322 result.append(u'\n'); 281 result.append(ABP_TEXT('\n'));
323 } 282 }
324 if (mLastSuccess) 283 if (mLastSuccess)
325 { 284 {
326 result.append(u"lastSuccess="_str); 285 result.append(ABP_TEXT("lastSuccess="_str));
327 result.append(mLastSuccess); 286 result.append(mLastSuccess);
328 result.append(u'\n'); 287 result.append(ABP_TEXT('\n'));
329 } 288 }
330 if (mErrorCount) 289 if (mErrorCount)
331 { 290 {
332 result.append(u"errors="_str); 291 result.append(ABP_TEXT("errors="_str));
333 result.append(mErrorCount); 292 result.append(mErrorCount);
334 result.append(u'\n'); 293 result.append(ABP_TEXT('\n'));
335 } 294 }
336 if (mDataRevision) 295 if (mDataRevision)
337 { 296 {
338 result.append(u"version="_str); 297 result.append(ABP_TEXT("version="_str));
339 result.append(mDataRevision); 298 result.append(mDataRevision);
340 result.append(u'\n'); 299 result.append(ABP_TEXT('\n'));
341 } 300 }
342 if (!mRequiredVersion.empty()) 301 if (!mRequiredVersion.empty())
343 { 302 {
344 result.append(u"requiredVersion="_str); 303 result.append(ABP_TEXT("requiredVersion="_str));
345 result.append(mRequiredVersion); 304 result.append(mRequiredVersion);
346 result.append(u'\n'); 305 result.append(ABP_TEXT('\n'));
347 } 306 }
348 if (mDownloadCount) 307 if (mDownloadCount)
349 { 308 {
350 result.append(u"downloadCount="_str); 309 result.append(ABP_TEXT("downloadCount="_str));
351 result.append(mDownloadCount); 310 result.append(mDownloadCount);
352 result.append(u'\n'); 311 result.append(ABP_TEXT('\n'));
353 } 312 }
354 return result; 313 return result;
355 } 314 }
LEFTRIGHT

Powered by Google App Engine
This is Rietveld