LeechCraft 0.6.70-14794-g33744ae6ce
Modular cross-platform feature rich live environment.
Loading...
Searching...
No Matches
customcookiejar.cpp
Go to the documentation of this file.
1/**********************************************************************
2 * LeechCraft - modular cross-platform feature rich internet client.
3 * Copyright (C) 2006-2014 Georg Rudoy
4 *
5 * Distributed under the Boost Software License, Version 1.0.
6 * (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt)
7 **********************************************************************/
8
9#include "customcookiejar.h"
10#include <set>
11#include <algorithm>
12#include <QNetworkCookie>
13#include <QtDebug>
14#include <QDateTime>
15#include <QStringRef>
16#include <QtConcurrentRun>
17#include <util/sll/util.h>
19
20namespace LC::Util
21{
23 : QNetworkCookieJar (parent)
24 {
25 }
26
28 {
29 FilterTrackingCookies_ = filter;
30 }
31
32 void CustomCookieJar::SetEnabled (bool enabled)
33 {
34 Enabled_ = enabled;
35 }
36
38 {
39 MatchDomainExactly_ = enabled;
40 }
41
43 {
44 WL_ = list;
45 }
46
48 {
49 BL_ = list;
50 }
51
52 QByteArray CustomCookieJar::Save () const
53 {
54 auto cookies = allCookies ();
55 QByteArray result;
56 for (const auto& cookie : cookies)
57 {
58 result += cookie.toRawForm ();
59 result += "\n";
60 }
61 return result;
62 }
63
64 namespace
65 {
66 bool IsExpired (const QNetworkCookie& cookie, const QDateTime& now)
67 {
68 return !cookie.isSessionCookie () && cookie.expirationDate () < now;
69 }
70 }
71
72 void CustomCookieJar::Load (const QByteArray& data)
73 {
74 QList<QNetworkCookie> cookies, filteredCookies;
75 for (const auto& ba : data.split ('\n'))
76 cookies << QNetworkCookie::parseCookies (ba);
77
78 const auto& now = QDateTime::currentDateTime ();
79 for (const auto& cookie : cookies)
80 {
81 if (FilterTrackingCookies_ &&
82 cookie.name ().startsWith ("__utm"))
83 continue;
84
85 if (IsExpired (cookie, now))
86 continue;
87
88 filteredCookies << cookie;
89 }
90 emit cookiesAdded (filteredCookies);
91 setAllCookies (filteredCookies);
92 }
93
95 {
96 const auto& cookies = allCookies ();
98 const auto& now = QDateTime::currentDateTime ();
99 for (const auto& cookie : cookies)
100 {
101 if (IsExpired (cookie, now))
102 continue;
103
104 if (result.contains (cookie))
105 continue;
106
107 result << cookie;
108 }
109 qDebug () << Q_FUNC_INFO << cookies.size () << result.size ();
110 setAllCookies (result);
111 }
112
114 {
115 if (!Enabled_)
116 return {};
117
118 QList<QNetworkCookie> filtered;
119 for (const auto& cookie : QNetworkCookieJar::cookiesForUrl (url))
120 if (!filtered.contains (cookie))
121 filtered << cookie;
122 return filtered;
123 }
124
125 namespace
126 {
127 bool MatchDomain (const QString& rawDomain, const QString& rawCookieDomain)
128 {
129 auto normalize = [] (const QString& s)
130 {
131 return s.startsWith ('.') ? s.midRef (1) : QStringRef { &s };
132 };
133 const auto& domain = normalize (rawDomain);
134 const auto& cookieDomain = normalize (rawCookieDomain);
135
136 if (domain == cookieDomain)
137 return true;
138
139 const auto idx = domain.indexOf (cookieDomain);
140 return idx > 0 && domain.at (idx - 1) == '.';
141 }
142
143 bool Check (const QList<QRegExp>& list, const QString& str)
144 {
145 return std::any_of (list.begin (), list.end (),
146 [&str] (const auto& rx) { return str == rx.pattern () || rx.exactMatch (str); });
147 }
148
149 struct CookiesDiff
150 {
153 };
154
155 auto CookieToTuple (const QNetworkCookie& c)
156 {
157 return std::make_tuple (c.isHttpOnly (),
158 c.isSecure (),
159 c.isSessionCookie (),
160 c.name (),
161 c.domain (),
162 c.path (),
163 c.value (),
164 c.expirationDate ());
165 }
166
167 struct CookieLess
168 {
169 bool operator() (const QNetworkCookie& left, const QNetworkCookie& right) const
170 {
171 return CookieToTuple (left) < CookieToTuple (right);
172 }
173 };
174
175 CookiesDiff CheckDifferences (const QList<QNetworkCookie>& previousList,
176 const QList<QNetworkCookie>& currentList)
177 {
178 using Set_t = std::set<QNetworkCookie, CookieLess>;
179 Set_t previous { previousList.begin (), previousList.end () };
180 Set_t current { currentList.begin (), currentList.end () };
181
182 CookiesDiff diff;
183 std::set_difference (previous.begin (), previous.end (),
184 current.begin (), current.end (),
185 std::back_inserter (diff.Removed_),
186 CookieLess {});
187 std::set_difference (current.begin (), current.end (),
188 previous.begin (), previous.end (),
189 std::back_inserter (diff.Added_),
190 CookieLess {});
191 return diff;
192 }
193 }
194
195 bool CustomCookieJar::setCookiesFromUrl (const QList<QNetworkCookie>& cookieList, const QUrl& url)
196 {
197 if (!Enabled_)
198 return false;
199
200 QList<QNetworkCookie> filtered;
201 filtered.reserve (cookieList.size ());
202 for (auto cookie : cookieList)
203 {
204 if (cookie.domain ().isEmpty ())
205 cookie.setDomain (url.host ());
206
207 bool checkWhitelist = false;
208 const auto wlGuard = Util::MakeScopeGuard ([&]
209 {
210 if (checkWhitelist && Check (WL_, cookie.domain ()))
211 filtered << cookie;
212 });
213
214 if (MatchDomainExactly_ && !MatchDomain (url.host (), cookie.domain ()))
215 {
216 checkWhitelist = true;
217 continue;
218 }
219
220 if (FilterTrackingCookies_ &&
221 cookie.name ().startsWith ("__utm"))
222 {
223 checkWhitelist = true;
224 continue;
225 }
226
227 if (!Check (BL_, cookie.domain ()))
228 filtered << cookie;
229 }
230
231 const auto& existing = cookiesForUrl (url);
232 if (existing.isEmpty ())
233 emit cookiesAdded (filtered);
234 else
235 Util::Sequence (this, QtConcurrent::run (CheckDifferences, existing, filtered)) >>
236 [this] (const CookiesDiff& diff)
237 {
238 if (!diff.Removed_.isEmpty ())
239 emit cookiesRemoved (diff.Removed_);
240 if (!diff.Added_.isEmpty ())
241 emit cookiesAdded (diff.Added_);
242 };
243
244 return QNetworkCookieJar::setCookiesFromUrl (filtered, url);
245 }
246}
QList< QNetworkCookie > Added_
QList< QNetworkCookie > Removed_
detail::ScopeGuard< F > MakeScopeGuard(const F &f)
Returns an object performing passed function on scope exit.
Definition: util.h:136