| LEFT | RIGHT | 
|---|
| 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 "ElemHide.h" | 18 #include "ElemHide.h" | 
| 19 | 19 | 
| 20 DependentString ElemHide_SelectorList::SelectorAt(size_t idx) const | 20 OwnedString ElemHide_SelectorList::SelectorAt(size_t idx) const | 
| 21 { | 21 { | 
| 22   return DependentString(mSelectors[idx]->GetSelector()); | 22   return mSelectors[idx]->GetSelector(); | 
| 23 } | 23 } | 
| 24 | 24 | 
| 25 const String& ElemHide_SelectorList::FilterKeyAt(size_t idx) const | 25 const String& ElemHide_SelectorList::FilterKeyAt(size_t idx) const | 
| 26 { | 26 { | 
| 27   return mSelectors[idx]->GetText(); | 27   return mSelectors[idx]->GetText(); | 
| 28 } | 28 } | 
| 29 |  | 
| 30 ElemHide* ElemHide::mInstance = new ElemHide(); |  | 
| 31 | 29 | 
| 32 void ElemHide::Clear() | 30 void ElemHide::Clear() | 
| 33 { | 31 { | 
| 34   mFilters.clear(); | 32   mFilters.clear(); | 
| 35   mExceptions.clear(); | 33   mExceptions.clear(); | 
| 36   mFiltersByDomain.clear(); | 34   mFiltersByDomain.clear(); | 
| 37   mKnownExceptions.clear(); | 35   mKnownExceptions.clear(); | 
| 38 } | 36 } | 
| 39 | 37 | 
| 40 namespace { | 38 namespace | 
| 41 | 39 { | 
| 42   ActiveFilter::DomainMap* DefaultDomains() | 40   const ActiveFilter::DomainMap defaultDomains = | 
| 43   { | 41   { | 
| 44     static ActiveFilter::DomainMap defaultDomains; | 42     { ActiveFilter::DEFAULT_DOMAIN, true } | 
| 45     if (defaultDomains.empty()) | 43   }; | 
| 46       defaultDomains[u""_str] = true; | 44 } | 
| 47     return &defaultDomains; | 45 | 
| 48   } | 46 void ElemHide::AddToFiltersByDomain(const ElemHideBasePtr& filter) | 
| 49 | 47 { | 
| 50 } | 48   const auto* domains = filter->GetDomains(); | 
| 51 |  | 
| 52 void ElemHide::AddToFiltersByDomain(ElemHideBase& filter) |  | 
| 53 { |  | 
| 54   auto domains = filter.GetDomains(); |  | 
| 55   if (!domains) | 49   if (!domains) | 
| 56     domains = DefaultDomains(); | 50     domains = &defaultDomains; | 
| 57 | 51 | 
| 58   DependentString text(filter.GetText()); | 52   DependentString text(filter->GetText()); | 
| 59   for (auto& domain : *domains) | 53   for (const auto& domain : *domains) | 
| 60   { | 54   { | 
| 61     auto& filters = mFiltersByDomain[domain.first]; | 55     auto& filters = mFiltersByDomain[domain.first]; | 
| 62     if (domain.second) | 56     if (domain.second) | 
| 63       filters[text] = ElemHideBasePtr(&filter); | 57       filters[text] = filter; | 
| 64     else | 58     else | 
| 65     { | 59       filters[text] = ElemHideBasePtr(); | 
| 66       auto iter = filters.find(text); |  | 
| 67       if (iter != filters.end()) |  | 
| 68         filters.erase(iter); |  | 
| 69     } |  | 
| 70   } | 60   } | 
| 71 } | 61 } | 
| 72 | 62 | 
| 73 void ElemHide::Add(ElemHideBase& filter) | 63 void ElemHide::Add(ElemHideBase& filter) | 
| 74 { | 64 { | 
| 75   // we must ensure we have the right class. | 65   // we must ensure we have the right class. | 
| 76   // This is an error, but we might get Invalid filters. | 66   // This is an error, but we might get Invalid filters. | 
| 77   if (!filter.As<ElemHideBase>()) | 67   if (!filter.As<ElemHideBase>()) | 
| 78     return; | 68     return; | 
| 79 | 69 | 
| 80   DependentString text(filter.GetText()); | 70   DependentString text(filter.GetText()); | 
| 81   if (filter.mType == Filter::Type::ELEMHIDEEXCEPTION) | 71   if (filter.mType == Filter::Type::ELEMHIDEEXCEPTION) | 
| 82   { | 72   { | 
| 83     if (mKnownExceptions.find(text)) | 73     if (mKnownExceptions.find(text)) | 
| 84       return; | 74       return; | 
| 85 | 75 | 
| 86     auto selector = filter.GetSelector(); | 76     auto selector = filter.GetSelector(); | 
| 87     mExceptions[selector].push_back( | 77     mExceptions[selector].emplace_back(filter.As<ElemHideException>()); | 
| 88       ElemHideExceptionPtr(filter.As<ElemHideException>())); | 78 | 
| 89 | 79     // Selector is no longer unconditional | 
| 90     // Selector is not longer unconditional | 80     auto entry = mUnconditionalSelectors.find(selector); | 
| 91     mUnconditionalSelectors.erase(text); | 81     if (entry && entry->second) | 
| 92     mUnconditionalSelectorsCache.reset(); | 82     { | 
|  | 83       AddToFiltersByDomain(entry->second); | 
|  | 84       mUnconditionalSelectors.erase(selector); | 
|  | 85       mUnconditionalSelectorsCache.reset(); | 
|  | 86     } | 
| 93     mKnownExceptions.insert(text); | 87     mKnownExceptions.insert(text); | 
| 94   } | 88   } | 
| 95   else | 89   else | 
| 96   { | 90   { | 
| 97     if (mFilters.find(text)) | 91     if (mFilters.find(text)) | 
| 98       return; | 92       return; | 
| 99 | 93 | 
| 100     mFilters[text] = ElemHideBasePtr(filter.As<ElemHideBase>()); | 94     auto selector = filter.GetSelector(); | 
|  | 95     mFilters[text] = &filter; | 
| 101     if (!((filter.GetDomains() && filter.GetDomains()->size()) || | 96     if (!((filter.GetDomains() && filter.GetDomains()->size()) || | 
| 102           mExceptions.find(filter.GetSelector()))) | 97           mExceptions.find(selector))) | 
| 103     { | 98     { | 
| 104       // The new filter's selector is unconditionally applied to all domains | 99       // The new filter's selector is unconditionally applied to all domains | 
| 105       mUnconditionalSelectors.insert(text); | 100       mUnconditionalSelectors[selector] = ElemHideBasePtr(&filter); | 
| 106       mUnconditionalSelectorsCache.reset(); | 101       mUnconditionalSelectorsCache.reset(); | 
| 107     } | 102     } | 
| 108     else | 103     else | 
| 109       AddToFiltersByDomain(filter); | 104       AddToFiltersByDomain(ElemHideBasePtr(&filter)); | 
| 110   } | 105   } | 
| 111 } | 106 } | 
| 112 | 107 | 
| 113 void ElemHide::Remove(ElemHideBase& filter) | 108 void ElemHide::Remove(ElemHideBase& filter) | 
| 114 { | 109 { | 
| 115   DependentString text(filter.GetText()); | 110   DependentString text(filter.GetText()); | 
| 116 | 111 | 
| 117   if (filter.mType == Filter::Type::ELEMHIDEEXCEPTION) | 112   auto selector = filter.GetSelector(); | 
|  | 113   auto exceptionFilter = filter.As<ElemHideException>(); | 
|  | 114   if (exceptionFilter) | 
| 118   { | 115   { | 
| 119     // never seen the exception. | 116     // never seen the exception. | 
| 120     if (!mKnownExceptions.find(text)) | 117     if (!mKnownExceptions.find(text)) | 
| 121       return; | 118       return; | 
| 122 | 119 | 
| 123     auto selector = filter.GetSelector(); |  | 
| 124     auto& list = mExceptions[selector]; | 120     auto& list = mExceptions[selector]; | 
| 125     auto iter = std::find( | 121     auto iter = std::find(list.begin(), list.end(), | 
| 126       list.begin(), list.end(), | 122                           ElemHideExceptionPtr(exceptionFilter)); | 
| 127       ElemHideExceptionPtr(filter.As<ElemHideException>())); |  | 
| 128     if (iter != list.end()) | 123     if (iter != list.end()) | 
| 129       list.erase(iter); | 124       list.erase(iter); | 
| 130     mKnownExceptions.erase(text); | 125     mKnownExceptions.erase(text); | 
| 131   } | 126   } | 
| 132   else | 127   else | 
| 133   { | 128   { | 
| 134     if (!mFilters.find(text)) | 129     if (!mFilters.find(text)) | 
| 135       return; | 130       return; | 
| 136 | 131 | 
| 137     if (mUnconditionalSelectors.find(text)) | 132     if (mUnconditionalSelectors.find(selector)) | 
| 138     { | 133     { | 
| 139       mUnconditionalSelectors.erase(text); | 134       mUnconditionalSelectors.erase(selector); | 
| 140       mUnconditionalSelectorsCache.reset(); | 135       mUnconditionalSelectorsCache.reset(); | 
| 141     } | 136     } | 
| 142     else | 137     else | 
| 143     { | 138     { | 
| 144       auto domains = filter.GetDomains(); | 139       const auto* domains = filter.GetDomains(); | 
| 145       for (auto domain : *domains) | 140       if (!domains) | 
|  | 141         domains = &defaultDomains; | 
|  | 142 | 
|  | 143       for (const auto& domain : *domains) | 
| 146       { | 144       { | 
| 147         auto& list = mFiltersByDomain[domain.first]; | 145         auto& list = mFiltersByDomain[domain.first]; | 
| 148         list.erase(text); | 146         list.erase(text); | 
| 149       } | 147       } | 
| 150     } | 148     } | 
| 151 | 149 | 
| 152     mFilters.erase(text); | 150     mFilters.erase(text); | 
| 153   } | 151   } | 
| 154 } | 152 } | 
| 155 | 153 | 
| 156 ElemHideException* ElemHide::GetException(const ElemHideBase& filter, | 154 ElemHideException* ElemHide::GetException(const ElemHideBase& filter, | 
| 157                                           DependentString& docDomain) const | 155                                           DependentString& docDomain) const | 
| 158 { | 156 { | 
| 159   auto exception = mExceptions.find(filter.GetSelector()); | 157   auto exception = mExceptions.find(filter.GetSelector()); | 
| 160   if (!exception) | 158   if (!exception) | 
| 161     return nullptr; | 159     return nullptr; | 
| 162 | 160 | 
| 163   auto& list = exception->second; | 161   auto& list = exception->second; | 
| 164   for (auto iter = list.rbegin(); iter != list.rend(); iter++) | 162   for (auto iter = list.rbegin(); iter != list.rend(); iter++) | 
| 165   { | 163   { | 
| 166     DependentString domain(docDomain); | 164     DependentString domain(docDomain); | 
| 167     if ((*iter)->IsActiveOnDomain(domain, u""_str)) | 165     if (*iter && (*iter)->IsActiveOnDomain(domain)) | 
| 168     { | 166     { | 
| 169       ElemHideExceptionPtr filter(*iter); | 167       ElemHideExceptionPtr filter(*iter); | 
| 170       return filter.release(); | 168       return filter.release(); | 
| 171     } | 169     } | 
| 172   } | 170   } | 
| 173 | 171 | 
| 174   return nullptr; | 172   return nullptr; | 
| 175 } | 173 } | 
| 176 | 174 | 
| 177 ElemHide_SelectorList* ElemHide::GetUnconditionalSelectors() const | 175 ElemHide_SelectorList* ElemHide::GetUnconditionalSelectors() const | 
| 178 { | 176 { | 
| 179   if (!mUnconditionalSelectorsCache) | 177   if (!mUnconditionalSelectorsCache) | 
| 180   { | 178   { | 
| 181     mUnconditionalSelectorsCache = intrusive_ptr<ElemHide_SelectorList>(new Elem
     Hide_SelectorList, false); | 179     mUnconditionalSelectorsCache = | 
|  | 180       intrusive_ptr<ElemHide_SelectorList>(new ElemHide_SelectorList(), false); | 
| 182     annotate_address(mUnconditionalSelectorsCache.get(), "ElemHide_SelectorList"
     ); | 181     annotate_address(mUnconditionalSelectorsCache.get(), "ElemHide_SelectorList"
     ); | 
| 183     for (auto unconditional : mUnconditionalSelectors) | 182     for (const auto& unconditional : mUnconditionalSelectors) | 
| 184     { | 183     { | 
| 185       auto filter = mFilters.find(unconditional.first); | 184       if (!(unconditional.is_deleted() || unconditional.is_invalid())) | 
| 186       if (filter) | 185       { | 
| 187         mUnconditionalSelectorsCache->push_back(filter->second); | 186         auto entry = mFilters.find(unconditional.second->GetText()); | 
|  | 187         if (entry) | 
|  | 188           mUnconditionalSelectorsCache->push_back(entry->second); | 
|  | 189       } | 
| 188     } | 190     } | 
| 189   } | 191   } | 
| 190   return intrusive_ptr<ElemHide_SelectorList>(mUnconditionalSelectorsCache).rele
     ase(); | 192   return intrusive_ptr<ElemHide_SelectorList>(mUnconditionalSelectorsCache).rele
     ase(); | 
| 191 } | 193 } | 
| 192 | 194 | 
| 193 ElemHide_SelectorList* ElemHide::GetSelectorsForDomain(const String& domain, | 195 ElemHide_SelectorList* ElemHide::GetSelectorsForDomain(const String& domain, | 
| 194   Criteria criteria) const | 196   Criteria criteria) const | 
| 195 { | 197 { | 
| 196   intrusive_ptr<ElemHide_SelectorList> selectors(new ElemHide_SelectorList); | 198   intrusive_ptr<ElemHide_SelectorList> selectors(new ElemHide_SelectorList()); | 
| 197   annotate_address(selectors.get(), "ElemHide_SelectorList"); | 199   annotate_address(selectors.get(), "ElemHide_SelectorList"); | 
| 198 | 200 | 
| 199   if (criteria < NO_UNCONDITIONAL) | 201   if (criteria < NO_UNCONDITIONAL) | 
| 200     selectors->append(GetUnconditionalSelectors()); | 202   { | 
| 201 | 203     intrusive_ptr<ElemHide_SelectorList> selector(GetUnconditionalSelectors()); | 
| 202   bool specificOnly = (criteria >= SPECIFIC_ONLY); | 204     selectors->append(*selector); | 
|  | 205   } | 
|  | 206 | 
|  | 207   bool specificOnly = criteria >= SPECIFIC_ONLY; | 
| 203   StringSet seenFilters; | 208   StringSet seenFilters; | 
| 204   DependentString docDomain(domain); | 209   DependentString docDomain(domain); | 
| 205 | 210 | 
| 206   DependentString currentDomain(domain); | 211   DependentString currentDomain(domain); | 
| 207   while (true) | 212   while (true) | 
| 208   { | 213   { | 
| 209     if (specificOnly && currentDomain.empty()) | 214     if (specificOnly && currentDomain.empty()) | 
| 210       break; | 215       break; | 
| 211 | 216 | 
| 212     auto filters = mFiltersByDomain.find(currentDomain); | 217     auto filters = mFiltersByDomain.find(currentDomain); | 
| 213     if (filters) | 218     if (filters) | 
| 214     { | 219     { | 
| 215       for (auto& entry : filters->second) | 220       for (const auto& entry : filters->second) | 
| 216       { | 221       { | 
| 217         if (entry.first.is_invalid()) | 222         if (entry.first.is_invalid() || entry.first.is_deleted()) | 
| 218           continue; | 223           continue; | 
| 219 | 224 | 
| 220         if (seenFilters.find(entry.first)) | 225         if (seenFilters.find(entry.first)) | 
| 221           continue; | 226           continue; | 
| 222         seenFilters.insert(entry.first); | 227         seenFilters.insert(entry.first); | 
| 223 | 228 | 
| 224         auto filter = entry.second; | 229         auto filter = entry.second; | 
| 225         if (filter && !GetException(*filter, docDomain)) | 230         if (filter && !GetException(*filter, docDomain)) | 
| 226           selectors->push_back(filter); | 231           selectors->push_back(filter); | 
| 227       } | 232       } | 
| 228     } | 233     } | 
| 229 | 234 | 
| 230     if (currentDomain.empty()) | 235     if (currentDomain.empty()) | 
| 231       break; | 236       break; | 
| 232 | 237 | 
| 233     auto nextDot = currentDomain.find('.'); | 238     auto nextDot = currentDomain.find(u'.'); | 
| 234     currentDomain = nextDot == String::npos ? | 239     currentDomain = nextDot == String::npos ? | 
| 235       u""_str : DependentString(currentDomain, nextDot + 1); | 240       u""_str : DependentString(currentDomain, nextDot + 1); | 
| 236   } | 241   } | 
| 237 | 242 | 
| 238   return selectors.release(); | 243   return selectors.release(); | 
| 239 } | 244 } | 
| LEFT | RIGHT | 
|---|