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

Side by Side Diff: compiled/subscription/DownloadableSubscription.cpp

Issue 29606600: Issue 5146 - Implement DownloadableSubscription parsing in C++ (Closed) Base URL: https://hg.adblockplus.org/adblockpluscore/
Patch Set: Added md5 checksum. Reorganized some code. Created Nov. 28, 2017, 10:46 p.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View unified diff | Download patch
« no previous file with comments | « compiled/subscription/DownloadableSubscription.h ('k') | compiled/subscription/Subscription.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 /* 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>
19
18 #include "DownloadableSubscription.h" 20 #include "DownloadableSubscription.h"
21 #include "../Base64.h"
22 #include "../FilterNotifier.h"
23 #include "../StringScanner.h"
24 #include "../filter/CommentFilter.h"
25
26 namespace {
27 constexpr int MILLIS_IN_HOUR = 60 * 60 * 1000;
28 constexpr int MILLIS_IN_DAY = 24 * MILLIS_IN_HOUR;
29 // limits
30 constexpr int MAX_HOUR = 2^31 / MILLIS_IN_HOUR;
31 constexpr int MAX_DAY = 2^31 / MILLIS_IN_DAY;
32
33 typedef std::pair<DependentString, DependentString> Param;
34
35 Param ParseParam(const String& text)
36 {
37 Param param;
38
39 if (text[0] == u'!')
40 {
41 bool foundColon = false;
42 String::size_type beginParam = 0;
43 String::size_type endParam = 0;
44 String::size_type beginValue = 0;
45 for (String::size_type i = 1; i < text.length(); i++)
46 {
47 switch (text[i])
48 {
49 case ' ':
50 case '\t':
51 if (beginParam > 0 && !foundColon)
52 {
53 endParam = i - 1;
54 }
55 break;
56 case ':':
57 foundColon = true;
58 break;
59 default:
60 if (foundColon)
61 {
62 beginValue = i;
63 }
64 else
65 {
66 if (beginParam == 0)
67 beginParam = i;
68 }
69 break;
70 }
71 if (beginValue > 0)
72 break;
73 }
74 if (beginValue > 0)
75 {
76 param.first = DependentString(text, beginParam, endParam - beginParam);
77 param.first.toLower();
78 param.second = DependentString(
79 text, beginValue, text.length() - 1 - beginValue);
80 }
81 }
82 return param;
83 }
84 }
85
86 DownloadableSubscription_Parser::DownloadableSubscription_Parser(DownloadableSub scription& sub)
87 : mSubscription(&sub), mFirstLine(true)
88 {
89 }
90
91 void DownloadableSubscription_Parser::Process(const String& line)
92 {
93 bool doChecksum = true;
94 auto param = ParseParam(line);
95 if (!param.first.is_invalid())
96 {
97 if (param.first == u"checksum"_str)
98 doChecksum = false;
99 mParams[param.first] = param.second;
100 }
101 // Checksum is an MD5 checksum (base64-encoded without the trailing "=") of
102 // all lines in UTF-8 without the checksum line, joined with "\n".
103 if (doChecksum)
104 {
105 if (!mFirstLine)
106 mChecksum.Update((const uint8_t*)"\n", 1);
107 else
108 mFirstLine = false;
109 mChecksum.Update(line);
110 }
111 if (param.first.is_invalid())
112 mFiltersText.emplace_back(line, false);
113 }
114
115 int DownloadableSubscription_Parser::ParseExpires(const String& expires)
116 {
117 bool isHour = false;
118 StringScanner scanner(expires);
119 String::size_type numStart = 0;
120 String::size_type numLen = 0;
121 while(!scanner.done())
122 {
123 auto ch = scanner.next();
124 if (std::iswdigit(ch))
125 {
126 if (numLen == 0)
127 numStart = scanner.position();
128 numLen++;
129 }
130 else if (std::iswspace(ch))
131 {
132 if (numLen)
133 break;
134 }
135 else
136 {
137 if (numLen)
138 scanner.back();
139 break;
140 }
141 }
142
143 DependentString numStr(expires, numStart, numLen);
144 int num = numStr.toInt();
145 if (num == 0)
146 return 0;
147
148 while (!scanner.done())
149 {
150 auto ch = scanner.next();
151 if (std::iswspace(ch))
152 continue;
153 if (ch == u'h')
154 {
155 isHour = true;
156 // assume we are done here. The rest is ignored.
157 break;
158 }
159 }
160 // check for overflow.
161 if ((isHour && (num > MAX_HOUR)) || (num > MAX_DAY))
162 return 0;
163
164 num *= isHour ? MILLIS_IN_HOUR : MILLIS_IN_DAY;
165 return num;
166 }
167
168 int DownloadableSubscription_Parser::Finalize()
169 {
170 uint8_t checksum[MD5::CHECKSUM_LENGTH];
171 mChecksum.Final(checksum);
172 auto b64checksum = ToBase64(checksum, MD5::CHECKSUM_LENGTH);
173 if (mParams[u"checksum"_str] != b64checksum)
174 {
175 // XXX error
176 }
177
178 auto entry = mParams.find(u"title"_str);
179 if (entry)
180 {
181 mSubscription->SetTitle(entry->second);
182 mSubscription->SetFixedTitle(true);
183 }
184 else
185 mSubscription->SetFixedTitle(false);
186
187 int version = 0;
188 entry = mParams.find(u"version"_str);
189 if (entry)
190 version = entry->second.toInt();
191 mSubscription->SetDataRevision(version);
192
193 int expires = 0;
194 entry = mParams.find(u"expires"_str);
195 if (entry)
196 expires = ParseExpires(entry->second);
197
198 FilterNotifier::SubscriptionChange(
199 FilterNotifier::Topic::SUBSCRIPTION_BEFORE_FILTERS_REPLACED,
200 *mSubscription);
201
202 Subscription::Filters filters;
203 for (auto text : mFiltersText)
204 filters.emplace_back(Filter::FromText(text), false);
205
206 auto oldFilters = std::move(mSubscription->GetFilters());
207 mSubscription->GetFilters() = std::move(filters);
208 FilterNotifier::SubscriptionChange(
209 FilterNotifier::Topic::SUBSCRIPTION_FILTERS_REPLACED, *mSubscription);
210
211 return expires;
212 }
213
214 namespace {
215 DependentString emptyString = u""_str;
216 }
217
218 const String& DownloadableSubscription_Parser::GetRedirect() const
219 {
220 auto entry = mParams.find(u"redirect"_str);
221 if (entry)
222 return entry->second;
223 return emptyString;
224 }
225
226 const String& DownloadableSubscription_Parser::GetHomepage() const
227 {
228 auto entry = mParams.find(u"homepage"_str);
229 if (entry)
230 return entry->second;
231 return emptyString;
232 }
19 233
20 DownloadableSubscription::DownloadableSubscription(const String& id) 234 DownloadableSubscription::DownloadableSubscription(const String& id)
21 : Subscription(classType, id), mFixedTitle(false), mLastCheck(0), 235 : Subscription(classType, id), mFixedTitle(false), mLastCheck(0),
22 mHardExpiration(0), mSoftExpiration(0), mLastDownload(0), mLastSuccess(0), 236 mHardExpiration(0), mSoftExpiration(0), mLastDownload(0), mLastSuccess(0),
23 mErrorCount(0), mDataRevision(0), mDownloadCount(0) 237 mErrorCount(0), mDataRevision(0), mDownloadCount(0)
24 { 238 {
25 SetTitle(id); 239 SetTitle(id);
26 } 240 }
27 241
242 DownloadableSubscription_Parser* DownloadableSubscription::ParseDownload()
243 {
244 return new DownloadableSubscription_Parser(*this);
245 }
246
28 OwnedString DownloadableSubscription::Serialize() const 247 OwnedString DownloadableSubscription::Serialize() const
29 { 248 {
30 OwnedString result(Subscription::Serialize()); 249 OwnedString result(Subscription::Serialize());
31 if (mFixedTitle) 250 if (mFixedTitle)
32 result.append(u"fixedTitle=true\n"_str); 251 result.append(u"fixedTitle=true\n"_str);
33 if (!mHomepage.empty()) 252 if (!mHomepage.empty())
34 { 253 {
35 result.append(u"homepage="_str); 254 result.append(u"homepage="_str);
36 result.append(mHomepage); 255 result.append(mHomepage);
37 result.append(u'\n'); 256 result.append(u'\n');
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
91 result.append(u'\n'); 310 result.append(u'\n');
92 } 311 }
93 if (mDownloadCount) 312 if (mDownloadCount)
94 { 313 {
95 result.append(u"downloadCount="_str); 314 result.append(u"downloadCount="_str);
96 result.append(mDownloadCount); 315 result.append(mDownloadCount);
97 result.append(u'\n'); 316 result.append(u'\n');
98 } 317 }
99 return result; 318 return result;
100 } 319 }
OLDNEW
« no previous file with comments | « compiled/subscription/DownloadableSubscription.h ('k') | compiled/subscription/Subscription.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld