OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/extensions/api/web_request/web_request_api.h" | 5 #include "chrome/browser/extensions/api/web_request/web_request_api.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 | 8 |
9 #include "base/bind.h" | 9 #include "base/bind.h" |
10 #include "base/bind_helpers.h" | 10 #include "base/bind_helpers.h" |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
76 using extensions::web_navigation_api_helpers::GetFrameId; | 76 using extensions::web_navigation_api_helpers::GetFrameId; |
77 | 77 |
78 namespace helpers = extension_web_request_api_helpers; | 78 namespace helpers = extension_web_request_api_helpers; |
79 namespace keys = extension_web_request_api_constants; | 79 namespace keys = extension_web_request_api_constants; |
80 namespace web_request = extensions::api::web_request; | 80 namespace web_request = extensions::api::web_request; |
81 namespace declarative_keys = extensions::declarative_webrequest_constants; | 81 namespace declarative_keys = extensions::declarative_webrequest_constants; |
82 namespace activitylog = activity_log_web_request_constants; | 82 namespace activitylog = activity_log_web_request_constants; |
83 | 83 |
84 namespace { | 84 namespace { |
85 | 85 |
| 86 const char kWebRequest[] = "webRequest"; |
| 87 const char kWebView[] = "webview"; |
| 88 |
86 // List of all the webRequest events. | 89 // List of all the webRequest events. |
87 const char* const kWebRequestEvents[] = { | 90 const char* const kWebRequestEvents[] = { |
88 keys::kOnBeforeRedirectEvent, | 91 keys::kOnBeforeRedirectEvent, |
89 keys::kOnBeforeRequestEvent, | 92 keys::kOnBeforeRequestEvent, |
90 keys::kOnBeforeSendHeadersEvent, | 93 keys::kOnBeforeSendHeadersEvent, |
91 keys::kOnCompletedEvent, | 94 keys::kOnCompletedEvent, |
92 keys::kOnErrorOccurredEvent, | 95 keys::kOnErrorOccurredEvent, |
93 keys::kOnSendHeadersEvent, | 96 keys::kOnSendHeadersEvent, |
94 keys::kOnAuthRequiredEvent, | 97 keys::kOnAuthRequiredEvent, |
95 keys::kOnResponseStartedEvent, | 98 keys::kOnResponseStartedEvent, |
(...skipping 24 matching lines...) Expand all Loading... |
120 case ExtensionWebRequestEventRouter::kOnErrorOccurred: | 123 case ExtensionWebRequestEventRouter::kOnErrorOccurred: |
121 return keys::kOnErrorOccurred; | 124 return keys::kOnErrorOccurred; |
122 case ExtensionWebRequestEventRouter::kOnCompleted: | 125 case ExtensionWebRequestEventRouter::kOnCompleted: |
123 return keys::kOnCompleted; | 126 return keys::kOnCompleted; |
124 } | 127 } |
125 NOTREACHED(); | 128 NOTREACHED(); |
126 return "Not reached"; | 129 return "Not reached"; |
127 } | 130 } |
128 | 131 |
129 bool IsWebRequestEvent(const std::string& event_name) { | 132 bool IsWebRequestEvent(const std::string& event_name) { |
| 133 std::string web_request_event_name(event_name); |
| 134 if (web_request_event_name.find(kWebView) != std::string::npos) |
| 135 web_request_event_name.replace(0, sizeof(kWebView) - 1, kWebRequest); |
130 return std::find(kWebRequestEvents, ARRAYEND(kWebRequestEvents), | 136 return std::find(kWebRequestEvents, ARRAYEND(kWebRequestEvents), |
131 event_name) != ARRAYEND(kWebRequestEvents); | 137 web_request_event_name) != ARRAYEND(kWebRequestEvents); |
132 } | 138 } |
133 | 139 |
134 // Returns whether |request| has been triggered by an extension in | 140 // Returns whether |request| has been triggered by an extension in |
135 // |extension_info_map|. | 141 // |extension_info_map|. |
136 bool IsRequestFromExtension(const net::URLRequest* request, | 142 bool IsRequestFromExtension(const net::URLRequest* request, |
137 const ExtensionInfoMap* extension_info_map) { | 143 const ExtensionInfoMap* extension_info_map) { |
138 // |extension_info_map| is NULL for system-level requests. | 144 // |extension_info_map| is NULL for system-level requests. |
139 if (!extension_info_map) | 145 if (!extension_info_map) |
140 return false; | 146 return false; |
141 | 147 |
(...skipping 213 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
355 // added. | 361 // added. |
356 // NOTE(benjhayden) New APIs should not use this sub_event_name trick! It does | 362 // NOTE(benjhayden) New APIs should not use this sub_event_name trick! It does |
357 // not play well with event pages. See downloads.onDeterminingFilename and | 363 // not play well with event pages. See downloads.onDeterminingFilename and |
358 // ExtensionDownloadsEventRouter for an alternative approach. | 364 // ExtensionDownloadsEventRouter for an alternative approach. |
359 struct ExtensionWebRequestEventRouter::EventListener { | 365 struct ExtensionWebRequestEventRouter::EventListener { |
360 std::string extension_id; | 366 std::string extension_id; |
361 std::string extension_name; | 367 std::string extension_name; |
362 std::string sub_event_name; | 368 std::string sub_event_name; |
363 RequestFilter filter; | 369 RequestFilter filter; |
364 int extra_info_spec; | 370 int extra_info_spec; |
365 int target_process_id; | 371 int embedder_process_id; |
366 int target_route_id; | 372 int web_view_instance_id; |
367 base::WeakPtr<IPC::Sender> ipc_sender; | 373 base::WeakPtr<IPC::Sender> ipc_sender; |
368 mutable std::set<uint64> blocked_requests; | 374 mutable std::set<uint64> blocked_requests; |
369 | 375 |
370 // Comparator to work with std::set. | 376 // Comparator to work with std::set. |
371 bool operator<(const EventListener& that) const { | 377 bool operator<(const EventListener& that) const { |
372 if (extension_id < that.extension_id) | 378 if (extension_id < that.extension_id) |
373 return true; | 379 return true; |
374 if (extension_id == that.extension_id && | 380 if (extension_id == that.extension_id && |
375 sub_event_name < that.sub_event_name) | 381 sub_event_name < that.sub_event_name) |
376 return true; | 382 return true; |
(...skipping 739 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1116 } | 1122 } |
1117 | 1123 |
1118 bool ExtensionWebRequestEventRouter::AddEventListener( | 1124 bool ExtensionWebRequestEventRouter::AddEventListener( |
1119 void* profile, | 1125 void* profile, |
1120 const std::string& extension_id, | 1126 const std::string& extension_id, |
1121 const std::string& extension_name, | 1127 const std::string& extension_name, |
1122 const std::string& event_name, | 1128 const std::string& event_name, |
1123 const std::string& sub_event_name, | 1129 const std::string& sub_event_name, |
1124 const RequestFilter& filter, | 1130 const RequestFilter& filter, |
1125 int extra_info_spec, | 1131 int extra_info_spec, |
1126 int target_process_id, | 1132 int embedder_process_id, |
1127 int target_route_id, | 1133 int web_view_instance_id, |
1128 base::WeakPtr<IPC::Sender> ipc_sender) { | 1134 base::WeakPtr<IPC::Sender> ipc_sender) { |
| 1135 |
1129 if (!IsWebRequestEvent(event_name)) | 1136 if (!IsWebRequestEvent(event_name)) |
1130 return false; | 1137 return false; |
1131 | 1138 |
1132 EventListener listener; | 1139 EventListener listener; |
1133 listener.extension_id = extension_id; | 1140 listener.extension_id = extension_id; |
1134 listener.extension_name = extension_name; | 1141 listener.extension_name = extension_name; |
1135 listener.sub_event_name = sub_event_name; | 1142 listener.sub_event_name = sub_event_name; |
1136 listener.filter = filter; | 1143 listener.filter = filter; |
1137 listener.extra_info_spec = extra_info_spec; | 1144 listener.extra_info_spec = extra_info_spec; |
1138 listener.ipc_sender = ipc_sender; | 1145 listener.ipc_sender = ipc_sender; |
1139 listener.target_process_id = target_process_id; | 1146 listener.embedder_process_id = embedder_process_id; |
1140 listener.target_route_id = target_route_id; | 1147 listener.web_view_instance_id = web_view_instance_id; |
1141 | 1148 |
1142 if (listeners_[profile][event_name].count(listener) != 0u) { | 1149 if (listeners_[profile][event_name].count(listener) != 0u) { |
1143 // This is likely an abuse of the API by a malicious extension. | 1150 // This is likely an abuse of the API by a malicious extension. |
1144 return false; | 1151 return false; |
1145 } | 1152 } |
1146 listeners_[profile][event_name].insert(listener); | 1153 listeners_[profile][event_name].insert(listener); |
1147 return true; | 1154 return true; |
1148 } | 1155 } |
1149 | 1156 |
1150 void ExtensionWebRequestEventRouter::RemoveEventListener( | 1157 void ExtensionWebRequestEventRouter::RemoveEventListener( |
(...skipping 25 matching lines...) Expand all Loading... |
1176 for (std::set<uint64>::iterator it = found->blocked_requests.begin(); | 1183 for (std::set<uint64>::iterator it = found->blocked_requests.begin(); |
1177 it != found->blocked_requests.end(); ++it) { | 1184 it != found->blocked_requests.end(); ++it) { |
1178 DecrementBlockCount(profile, extension_id, event_name, *it, NULL); | 1185 DecrementBlockCount(profile, extension_id, event_name, *it, NULL); |
1179 } | 1186 } |
1180 | 1187 |
1181 listeners_[profile][event_name].erase(listener); | 1188 listeners_[profile][event_name].erase(listener); |
1182 | 1189 |
1183 helpers::ClearCacheOnNavigation(); | 1190 helpers::ClearCacheOnNavigation(); |
1184 } | 1191 } |
1185 | 1192 |
| 1193 void ExtensionWebRequestEventRouter::RemoveWebViewEventListeners( |
| 1194 void* profile, |
| 1195 const std::string& extension_id, |
| 1196 int embedder_process_id, |
| 1197 int web_view_instance_id) { |
| 1198 // Iterate over all listeners of all WebRequest events to delete |
| 1199 // any listeners that belong to the provided <webview>. |
| 1200 bool found_listeners = false; |
| 1201 ListenerMapForProfile& map_for_profile = listeners_[profile]; |
| 1202 for (ListenerMapForProfile::iterator event_iter = map_for_profile.begin(); |
| 1203 event_iter != map_for_profile.end(); ++event_iter) { |
| 1204 std::vector<EventListener> listeners_to_delete; |
| 1205 const std::string& event_name = event_iter->first; |
| 1206 std::set<EventListener>& listeners = event_iter->second; |
| 1207 for (std::set<EventListener>::iterator listener_iter = listeners.begin(); |
| 1208 listener_iter != listeners.end(); ++listener_iter) { |
| 1209 const EventListener& listener = *listener_iter; |
| 1210 if (listener.embedder_process_id == embedder_process_id && |
| 1211 listener.web_view_instance_id == web_view_instance_id) |
| 1212 listeners_to_delete.push_back(listener); |
| 1213 } |
| 1214 for (size_t i = 0; i < listeners_to_delete.size(); ++i) { |
| 1215 found_listeners = true; |
| 1216 EventListener& listener = listeners_to_delete[i]; |
| 1217 listeners.erase(listeners_to_delete[i]); |
| 1218 // Unblock any request that this event listener may have been blocking. |
| 1219 for (std::set<uint64>::iterator it = listener.blocked_requests.begin(); |
| 1220 it != listener.blocked_requests.end(); ++it) { |
| 1221 DecrementBlockCount(profile, extension_id, event_name, *it, NULL); |
| 1222 } |
| 1223 } |
| 1224 } |
| 1225 if (found_listeners) |
| 1226 helpers::ClearCacheOnNavigation(); |
| 1227 } |
| 1228 |
1186 void ExtensionWebRequestEventRouter::OnOTRProfileCreated( | 1229 void ExtensionWebRequestEventRouter::OnOTRProfileCreated( |
1187 void* original_profile, void* otr_profile) { | 1230 void* original_profile, void* otr_profile) { |
1188 cross_profile_map_[original_profile] = otr_profile; | 1231 cross_profile_map_[original_profile] = otr_profile; |
1189 cross_profile_map_[otr_profile] = original_profile; | 1232 cross_profile_map_[otr_profile] = original_profile; |
1190 } | 1233 } |
1191 | 1234 |
1192 void ExtensionWebRequestEventRouter::OnOTRProfileDestroyed( | 1235 void ExtensionWebRequestEventRouter::OnOTRProfileDestroyed( |
1193 void* original_profile, void* otr_profile) { | 1236 void* original_profile, void* otr_profile) { |
1194 cross_profile_map_.erase(otr_profile); | 1237 cross_profile_map_.erase(otr_profile); |
1195 cross_profile_map_.erase(original_profile); | 1238 cross_profile_map_.erase(original_profile); |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1253 int tab_id, | 1296 int tab_id, |
1254 int window_id, | 1297 int window_id, |
1255 int render_process_host_id, | 1298 int render_process_host_id, |
1256 int routing_id, | 1299 int routing_id, |
1257 ResourceType::Type resource_type, | 1300 ResourceType::Type resource_type, |
1258 bool is_async_request, | 1301 bool is_async_request, |
1259 bool is_request_from_extension, | 1302 bool is_request_from_extension, |
1260 int* extra_info_spec, | 1303 int* extra_info_spec, |
1261 std::vector<const ExtensionWebRequestEventRouter::EventListener*>* | 1304 std::vector<const ExtensionWebRequestEventRouter::EventListener*>* |
1262 matching_listeners) { | 1305 matching_listeners) { |
| 1306 std::string web_request_event_name(event_name); |
1263 ExtensionRendererState::WebViewInfo web_view_info; | 1307 ExtensionRendererState::WebViewInfo web_view_info; |
1264 bool is_guest = ExtensionRendererState::GetInstance()-> | 1308 bool is_guest = ExtensionRendererState::GetInstance()-> |
1265 GetWebViewInfo(render_process_host_id, routing_id, &web_view_info); | 1309 GetWebViewInfo(render_process_host_id, routing_id, &web_view_info); |
1266 std::set<EventListener>& listeners = listeners_[profile][event_name]; | 1310 if (is_guest) |
| 1311 web_request_event_name.replace(0, sizeof(kWebRequest) - 1, kWebView); |
| 1312 |
| 1313 std::set<EventListener>& listeners = |
| 1314 listeners_[profile][web_request_event_name]; |
1267 for (std::set<EventListener>::iterator it = listeners.begin(); | 1315 for (std::set<EventListener>::iterator it = listeners.begin(); |
1268 it != listeners.end(); ++it) { | 1316 it != listeners.end(); ++it) { |
1269 if (!it->ipc_sender.get()) { | 1317 if (!it->ipc_sender.get()) { |
1270 // The IPC sender has been deleted. This listener will be removed soon | 1318 // The IPC sender has been deleted. This listener will be removed soon |
1271 // via a call to RemoveEventListener. For now, just skip it. | 1319 // via a call to RemoveEventListener. For now, just skip it. |
1272 continue; | 1320 continue; |
1273 } | 1321 } |
1274 | 1322 |
1275 if (is_guest && (it->target_process_id != render_process_host_id|| | 1323 if (is_guest && |
1276 it->target_route_id != routing_id)) | 1324 (it->embedder_process_id != web_view_info.embedder_process_id || |
| 1325 it->web_view_instance_id != web_view_info.web_view_instance_id)) |
1277 continue; | 1326 continue; |
1278 | 1327 |
1279 if (!it->filter.urls.is_empty() && !it->filter.urls.MatchesURL(url)) | 1328 if (!it->filter.urls.is_empty() && !it->filter.urls.MatchesURL(url)) |
1280 continue; | 1329 continue; |
1281 if (it->filter.tab_id != -1 && tab_id != it->filter.tab_id) | 1330 if (it->filter.tab_id != -1 && tab_id != it->filter.tab_id) |
1282 continue; | 1331 continue; |
1283 if (it->filter.window_id != -1 && window_id != it->filter.window_id) | 1332 if (it->filter.window_id != -1 && window_id != it->filter.window_id) |
1284 continue; | 1333 continue; |
1285 if (!it->filter.types.empty() && | 1334 if (!it->filter.types.empty() && |
1286 std::find(it->filter.types.begin(), it->filter.types.end(), | 1335 std::find(it->filter.types.begin(), it->filter.types.end(), |
1287 resource_type) == it->filter.types.end()) | 1336 resource_type) == it->filter.types.end()) |
1288 continue; | 1337 continue; |
1289 | 1338 |
1290 if (!WebRequestPermissions::CanExtensionAccessURL( | 1339 if (!is_guest && !WebRequestPermissions::CanExtensionAccessURL( |
1291 extension_info_map, it->extension_id, url, crosses_incognito, | 1340 extension_info_map, it->extension_id, url, crosses_incognito, |
1292 WebRequestPermissions::REQUIRE_HOST_PERMISSION)) | 1341 WebRequestPermissions::REQUIRE_HOST_PERMISSION)) |
1293 continue; | 1342 continue; |
1294 | 1343 |
1295 bool blocking_listener = | 1344 bool blocking_listener = |
1296 (it->extra_info_spec & | 1345 (it->extra_info_spec & |
1297 (ExtraInfoSpec::BLOCKING | ExtraInfoSpec::ASYNC_BLOCKING)) != 0; | 1346 (ExtraInfoSpec::BLOCKING | ExtraInfoSpec::ASYNC_BLOCKING)) != 0; |
1298 | 1347 |
1299 // We do not want to notify extensions about XHR requests that are | 1348 // We do not want to notify extensions about XHR requests that are |
1300 // triggered by themselves. This is a workaround to prevent deadlocks | 1349 // triggered by themselves. This is a workaround to prevent deadlocks |
(...skipping 667 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1968 ExtensionWebRequestEventRouter::ExtraInfoSpec::InitFromValue( | 2017 ExtensionWebRequestEventRouter::ExtraInfoSpec::InitFromValue( |
1969 *value, &extra_info_spec)); | 2018 *value, &extra_info_spec)); |
1970 } | 2019 } |
1971 | 2020 |
1972 std::string event_name; | 2021 std::string event_name; |
1973 EXTENSION_FUNCTION_VALIDATE(args_->GetString(3, &event_name)); | 2022 EXTENSION_FUNCTION_VALIDATE(args_->GetString(3, &event_name)); |
1974 | 2023 |
1975 std::string sub_event_name; | 2024 std::string sub_event_name; |
1976 EXTENSION_FUNCTION_VALIDATE(args_->GetString(4, &sub_event_name)); | 2025 EXTENSION_FUNCTION_VALIDATE(args_->GetString(4, &sub_event_name)); |
1977 | 2026 |
| 2027 int web_view_instance_id = 0; |
| 2028 EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(5, &web_view_instance_id)); |
| 2029 |
| 2030 base::WeakPtr<ChromeRenderMessageFilter> ipc_sender = ipc_sender_weak(); |
| 2031 |
| 2032 int embedder_process_id = |
| 2033 ipc_sender.get() ? ipc_sender->render_process_id() : -1; |
| 2034 |
1978 const Extension* extension = | 2035 const Extension* extension = |
1979 extension_info_map()->extensions().GetByID(extension_id()); | 2036 extension_info_map()->extensions().GetByID(extension_id()); |
1980 std::string extension_name = extension ? extension->name() : extension_id(); | 2037 std::string extension_name = extension ? extension->name() : extension_id(); |
1981 | 2038 |
| 2039 bool is_guest = web_view_instance_id != 0; |
1982 // We check automatically whether the extension has the 'webRequest' | 2040 // We check automatically whether the extension has the 'webRequest' |
1983 // permission. For blocking calls we require the additional permission | 2041 // permission. For blocking calls we require the additional permission |
1984 // 'webRequestBlocking'. | 2042 // 'webRequestBlocking'. |
1985 if ((extra_info_spec & | 2043 if ((!is_guest && extra_info_spec & |
1986 (ExtensionWebRequestEventRouter::ExtraInfoSpec::BLOCKING | | 2044 (ExtensionWebRequestEventRouter::ExtraInfoSpec::BLOCKING | |
1987 ExtensionWebRequestEventRouter::ExtraInfoSpec::ASYNC_BLOCKING)) && | 2045 ExtensionWebRequestEventRouter::ExtraInfoSpec::ASYNC_BLOCKING)) && |
1988 !extension->HasAPIPermission( | 2046 !extension->HasAPIPermission( |
1989 extensions::APIPermission::kWebRequestBlocking)) { | 2047 extensions::APIPermission::kWebRequestBlocking)) { |
1990 error_ = keys::kBlockingPermissionRequired; | 2048 error_ = keys::kBlockingPermissionRequired; |
1991 return false; | 2049 return false; |
1992 } | 2050 } |
1993 | 2051 |
1994 // We allow to subscribe to patterns that are broader than the host | 2052 // We allow to subscribe to patterns that are broader than the host |
1995 // permissions. E.g., we could subscribe to http://www.example.com/* | 2053 // permissions. E.g., we could subscribe to http://www.example.com/* |
1996 // while having host permissions for http://www.example.com/foo/* and | 2054 // while having host permissions for http://www.example.com/foo/* and |
1997 // http://www.example.com/bar/*. | 2055 // http://www.example.com/bar/*. |
1998 // For this reason we do only a coarse check here to warn the extension | 2056 // For this reason we do only a coarse check here to warn the extension |
1999 // developer if he does something obviously wrong. | 2057 // developer if he does something obviously wrong. |
2000 if (extension->GetEffectiveHostPermissions().is_empty()) { | 2058 if (!is_guest && extension->GetEffectiveHostPermissions().is_empty()) { |
2001 error_ = keys::kHostPermissionsRequired; | 2059 error_ = keys::kHostPermissionsRequired; |
2002 return false; | 2060 return false; |
2003 } | 2061 } |
2004 | 2062 |
2005 bool success = | 2063 bool success = |
2006 ExtensionWebRequestEventRouter::GetInstance()->AddEventListener( | 2064 ExtensionWebRequestEventRouter::GetInstance()->AddEventListener( |
2007 profile_id(), extension_id(), extension_name, | 2065 profile_id(), extension_id(), extension_name, |
2008 event_name, sub_event_name, filter, | 2066 event_name, sub_event_name, filter, extra_info_spec, |
2009 extra_info_spec, -1, -1, ipc_sender_weak()); | 2067 embedder_process_id, web_view_instance_id, ipc_sender_weak()); |
2010 EXTENSION_FUNCTION_VALIDATE(success); | 2068 EXTENSION_FUNCTION_VALIDATE(success); |
2011 | 2069 |
2012 helpers::ClearCacheOnNavigation(); | 2070 helpers::ClearCacheOnNavigation(); |
2013 | 2071 |
2014 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind( | 2072 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind( |
2015 &helpers::NotifyWebRequestAPIUsed, | 2073 &helpers::NotifyWebRequestAPIUsed, |
2016 profile_id(), make_scoped_refptr(GetExtension()))); | 2074 profile_id(), make_scoped_refptr(GetExtension()))); |
2017 | 2075 |
2018 return true; | 2076 return true; |
2019 } | 2077 } |
(...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2179 } else if ((*it)->name().find("AdBlock") != std::string::npos) { | 2237 } else if ((*it)->name().find("AdBlock") != std::string::npos) { |
2180 adblock = true; | 2238 adblock = true; |
2181 } else { | 2239 } else { |
2182 other = true; | 2240 other = true; |
2183 } | 2241 } |
2184 } | 2242 } |
2185 } | 2243 } |
2186 | 2244 |
2187 host->Send(new ExtensionMsg_UsingWebRequestAPI(adblock, adblock_plus, other)); | 2245 host->Send(new ExtensionMsg_UsingWebRequestAPI(adblock, adblock_plus, other)); |
2188 } | 2246 } |
OLD | NEW |