LeechCraft  0.6.70-13729-g7046a9d2a7
Modular cross-platform feature rich live environment.
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  * Boost Software License - Version 1.0 - August 17th, 2003
6  *
7  * Permission is hereby granted, free of charge, to any person or organization
8  * obtaining a copy of the software and accompanying documentation covered by
9  * this license (the "Software") to use, reproduce, display, distribute,
10  * execute, and transmit the Software, and to prepare derivative works of the
11  * Software, and to permit third-parties to whom the Software is furnished to
12  * do so, all subject to the following:
13  *
14  * The copyright notices in the Software and this entire statement, including
15  * the above license grant, this restriction and the following disclaimer,
16  * must be included in all copies of the Software, in whole or in part, and
17  * all derivative works of the Software, unless such copies or derivative
18  * works are solely in the form of machine-executable object code generated by
19  * a source language processor.
20  *
21  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23  * FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
24  * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
25  * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
26  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27  * DEALINGS IN THE SOFTWARE.
28  **********************************************************************/
29 
30 #include "customcookiejar.h"
31 #include <set>
32 #include <algorithm>
33 #include <QNetworkCookie>
34 #include <QtDebug>
35 #include <QDateTime>
36 #include <QtConcurrentRun>
37 #include <util/sll/util.h>
38 #include <util/threads/futures.h>
39 
40 namespace LC
41 {
42 namespace Util
43 {
45  : QNetworkCookieJar (parent)
46  {
47  }
48 
50  {
51  FilterTrackingCookies_ = filter;
52  }
53 
54  void CustomCookieJar::SetEnabled (bool enabled)
55  {
56  Enabled_ = enabled;
57  }
58 
60  {
61  MatchDomainExactly_ = enabled;
62  }
63 
65  {
66  WL_ = list;
67  }
68 
70  {
71  BL_ = list;
72  }
73 
74  QByteArray CustomCookieJar::Save () const
75  {
76  auto cookies = allCookies ();
77  QByteArray result;
78  for (const auto& cookie : cookies)
79  {
80  result += cookie.toRawForm ();
81  result += "\n";
82  }
83  return result;
84  }
85 
86  namespace
87  {
88  bool IsExpired (const QNetworkCookie& cookie, const QDateTime& now)
89  {
90  return !cookie.isSessionCookie () && cookie.expirationDate () < now;
91  }
92  }
93 
94  void CustomCookieJar::Load (const QByteArray& data)
95  {
96  QList<QNetworkCookie> cookies, filteredCookies;
97  for (const auto& ba : data.split ('\n'))
98  cookies << QNetworkCookie::parseCookies (ba);
99 
100  const auto& now = QDateTime::currentDateTime ();
101  for (const auto& cookie : cookies)
102  {
103  if (FilterTrackingCookies_ &&
104  cookie.name ().startsWith ("__utm"))
105  continue;
106 
107  if (IsExpired (cookie, now))
108  continue;
109 
110  filteredCookies << cookie;
111  }
112  emit cookiesAdded (filteredCookies);
113  setAllCookies (filteredCookies);
114  }
115 
117  {
118  const auto& cookies = allCookies ();
119  QList<QNetworkCookie> result;
120  const auto& now = QDateTime::currentDateTime ();
121  for (const auto& cookie : cookies)
122  {
123  if (IsExpired (cookie, now))
124  continue;
125 
126  if (result.contains (cookie))
127  continue;
128 
129  result << cookie;
130  }
131  qDebug () << Q_FUNC_INFO << cookies.size () << result.size ();
132  setAllCookies (result);
133  }
134 
136  {
137  if (!Enabled_)
138  return {};
139 
140  QList<QNetworkCookie> filtered;
141  for (const auto& cookie : QNetworkCookieJar::cookiesForUrl (url))
142  if (!filtered.contains (cookie))
143  filtered << cookie;
144  return filtered;
145  }
146 
147  namespace
148  {
149  bool MatchDomain (QString domain, QString cookieDomain)
150  {
151  auto normalize = [] (QString& s)
152  {
153  if (s.startsWith ('.'))
154  s = s.mid (1);
155  };
156  normalize (domain);
157  normalize (cookieDomain);
158 
159  if (domain == cookieDomain)
160  return true;
161 
162  const auto idx = domain.indexOf (cookieDomain);
163  return idx > 0 && domain.at (idx - 1) == '.';
164  }
165 
166  bool Check (const QList<QRegExp>& list, const QString& str)
167  {
168  for (auto& rx : list)
169  if (str == rx.pattern () || rx.exactMatch (str))
170  return true;
171 
172  return false;
173  }
174 
175  struct CookiesDiff
176  {
179  };
180 
181  auto CookieToTuple (const QNetworkCookie& c)
182  {
183  return std::make_tuple (c.isHttpOnly (),
184  c.isSecure (),
185  c.isSessionCookie (),
186  c.name (),
187  c.domain (),
188  c.path (),
189  c.value (),
190  c.expirationDate ());
191  }
192 
193  struct CookieLess
194  {
195  bool operator() (const QNetworkCookie& left, const QNetworkCookie& right) const
196  {
197  return CookieToTuple (left) < CookieToTuple (right);
198  }
199  };
200 
201  CookiesDiff CheckDifferences (const QList<QNetworkCookie>& previousList,
202  const QList<QNetworkCookie>& currentList)
203  {
204  using Set_t = std::set<QNetworkCookie, CookieLess>;
205  Set_t previous { previousList.begin (), previousList.end () };
206  Set_t current { currentList.begin (), currentList.end () };
207 
208  CookiesDiff diff;
209  std::set_difference (previous.begin (), previous.end (),
210  current.begin (), current.end (),
211  std::back_inserter (diff.Removed_),
212  CookieLess {});
213  std::set_difference (current.begin (), current.end (),
214  previous.begin (), previous.end (),
215  std::back_inserter (diff.Added_),
216  CookieLess {});
217  return diff;
218  }
219  }
220 
221  bool CustomCookieJar::setCookiesFromUrl (const QList<QNetworkCookie>& cookieList, const QUrl& url)
222  {
223  if (!Enabled_)
224  return false;
225 
226  QList<QNetworkCookie> filtered;
227  filtered.reserve (cookieList.size ());
228  for (auto cookie : cookieList)
229  {
230  if (cookie.domain ().isEmpty ())
231  cookie.setDomain (url.host ());
232 
233  bool checkWhitelist = false;
234  const auto wlGuard = Util::MakeScopeGuard ([&]
235  {
236  if (checkWhitelist && Check (WL_, cookie.domain ()))
237  filtered << cookie;
238  });
239 
240  if (MatchDomainExactly_ && !MatchDomain (url.host (), cookie.domain ()))
241  {
242  checkWhitelist = true;
243  continue;
244  }
245 
246  if (FilterTrackingCookies_ &&
247  cookie.name ().startsWith ("__utm"))
248  {
249  checkWhitelist = true;
250  continue;
251  }
252 
253  if (!Check (BL_, cookie.domain ()))
254  filtered << cookie;
255  }
256 
257  const auto& existing = cookiesForUrl (url);
258  if (existing.isEmpty ())
259  emit cookiesAdded (filtered);
260  else
261  Util::Sequence (this, QtConcurrent::run (CheckDifferences, existing, filtered)) >>
262  [this] (const CookiesDiff& diff)
263  {
264  if (!diff.Removed_.isEmpty ())
265  emit cookiesRemoved (diff.Removed_);
266  if (!diff.Added_.isEmpty ())
267  emit cookiesAdded (diff.Added_);
268  };
269 
270  return QNetworkCookieJar::setCookiesFromUrl (filtered, url);
271  }
272 }
273 }
QList< QNetworkCookie > Removed_
detail::ScopeGuard< F > MakeScopeGuard(const F &f)
Returns an object performing passed function on scope exit.
Definition: util.h:157
QList< QNetworkCookie > Added_
Definition: constants.h:35