Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(657)

Side by Side Diff: chrome/browser/extensions/api/webrequest/webrequest_api_helpers.cc

Issue 9701039: Refactor folders in chrome/browser/extensions/api (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: Small change to includes in extension_event_router.cc Created 8 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "chrome/browser/extensions/api/webrequest/webrequest_api_helpers.h"
6
7 #include "base/string_util.h"
8 #include "base/values.h"
9 #include "chrome/browser/extensions/api/webrequest/webrequest_api.h"
10 #include "chrome/common/url_constants.h"
11 #include "net/http/http_util.h"
12
13 namespace extension_webrequest_api_helpers {
14
15
16 EventResponseDelta::EventResponseDelta(
17 const std::string& extension_id, const base::Time& extension_install_time)
18 : extension_id(extension_id),
19 extension_install_time(extension_install_time),
20 cancel(false) {
21 }
22
23 EventResponseDelta::~EventResponseDelta() {
24 }
25
26
27 EventLogEntry::EventLogEntry(
28 net::NetLog::EventType event_type,
29 const scoped_refptr<net::NetLog::EventParameters>& params)
30 : event_type(event_type),
31 params(params) {
32 }
33
34 EventLogEntry::~EventLogEntry() {
35 }
36
37
38 // NetLog parameter to indicate the ID of the extension that caused an event.
39 class NetLogExtensionIdParameter : public net::NetLog::EventParameters {
40 public:
41 explicit NetLogExtensionIdParameter(const std::string& extension_id)
42 : extension_id_(extension_id) {}
43 virtual ~NetLogExtensionIdParameter() {}
44
45 virtual base::Value* ToValue() const OVERRIDE {
46 DictionaryValue* dict = new DictionaryValue();
47 dict->SetString("extension_id", extension_id_);
48 return dict;
49 }
50
51 private:
52 const std::string extension_id_;
53
54 DISALLOW_COPY_AND_ASSIGN(NetLogExtensionIdParameter);
55 };
56
57
58 // NetLog parameter to indicate that an extension modified a request.
59 class NetLogModificationParameter : public NetLogExtensionIdParameter {
60 public:
61 explicit NetLogModificationParameter(const std::string& extension_id)
62 : NetLogExtensionIdParameter(extension_id) {}
63 virtual ~NetLogModificationParameter() {}
64
65 virtual base::Value* ToValue() const OVERRIDE {
66 Value* parent = NetLogExtensionIdParameter::ToValue();
67 DCHECK(parent->IsType(Value::TYPE_DICTIONARY));
68 DictionaryValue* dict = static_cast<DictionaryValue*>(parent);
69 dict->Set("modified_headers", modified_headers_.DeepCopy());
70 dict->Set("deleted_headers", deleted_headers_.DeepCopy());
71 return dict;
72 }
73
74 void DeletedHeader(const std::string& key) {
75 deleted_headers_.Append(Value::CreateStringValue(key));
76 }
77
78 void ModifiedHeader(const std::string& key, const std::string& value) {
79 modified_headers_.Append(Value::CreateStringValue(key + ": " + value));
80 }
81
82 private:
83 ListValue modified_headers_;
84 ListValue deleted_headers_;
85
86 DISALLOW_COPY_AND_ASSIGN(NetLogModificationParameter);
87 };
88
89
90 bool InDecreasingExtensionInstallationTimeOrder(
91 const linked_ptr<EventResponseDelta>& a,
92 const linked_ptr<EventResponseDelta>& b) {
93 return a->extension_install_time > b->extension_install_time;
94 }
95
96 ListValue* StringToCharList(const std::string& s) {
97 ListValue* result = new ListValue;
98 for (size_t i = 0, n = s.size(); i < n; ++i) {
99 result->Append(
100 Value::CreateIntegerValue(
101 *reinterpret_cast<const unsigned char*>(&s[i])));
102 }
103 return result;
104 }
105
106 bool CharListToString(ListValue* list, std::string* out) {
107 if (!list)
108 return false;
109 const size_t list_length = list->GetSize();
110 out->resize(list_length);
111 int value = 0;
112 for (size_t i = 0; i < list_length; ++i) {
113 if (!list->GetInteger(i, &value) || value < 0 || value > 255)
114 return false;
115 unsigned char tmp = static_cast<unsigned char>(value);
116 (*out)[i] = *reinterpret_cast<char*>(&tmp);
117 }
118 return true;
119 }
120
121 EventResponseDelta* CalculateOnBeforeRequestDelta(
122 const std::string& extension_id,
123 const base::Time& extension_install_time,
124 bool cancel,
125 const GURL& new_url) {
126 EventResponseDelta* result =
127 new EventResponseDelta(extension_id, extension_install_time);
128 result->cancel = cancel;
129 result->new_url = new_url;
130 return result;
131 }
132
133 EventResponseDelta* CalculateOnBeforeSendHeadersDelta(
134 const std::string& extension_id,
135 const base::Time& extension_install_time,
136 bool cancel,
137 net::HttpRequestHeaders* old_headers,
138 net::HttpRequestHeaders* new_headers) {
139 EventResponseDelta* result =
140 new EventResponseDelta(extension_id, extension_install_time);
141 result->cancel = cancel;
142
143 // The event listener might not have passed any new headers if he
144 // just wanted to cancel the request.
145 if (new_headers) {
146 // Find deleted headers.
147 {
148 net::HttpRequestHeaders::Iterator i(*old_headers);
149 while (i.GetNext()) {
150 if (!new_headers->HasHeader(i.name())) {
151 result->deleted_request_headers.push_back(i.name());
152 }
153 }
154 }
155
156 // Find modified headers.
157 {
158 net::HttpRequestHeaders::Iterator i(*new_headers);
159 while (i.GetNext()) {
160 std::string value;
161 if (!old_headers->GetHeader(i.name(), &value) || i.value() != value) {
162 result->modified_request_headers.SetHeader(i.name(), i.value());
163 }
164 }
165 }
166 }
167 return result;
168 }
169
170 EventResponseDelta* CalculateOnHeadersReceivedDelta(
171 const std::string& extension_id,
172 const base::Time& extension_install_time,
173 bool cancel,
174 net::HttpResponseHeaders* old_response_headers,
175 ResponseHeaders* new_response_headers) {
176 EventResponseDelta* result =
177 new EventResponseDelta(extension_id, extension_install_time);
178 result->cancel = cancel;
179
180 if (!new_response_headers)
181 return result;
182
183 // Find deleted headers (header keys are treated case insensitively).
184 {
185 void* iter = NULL;
186 std::string name;
187 std::string value;
188 while (old_response_headers->EnumerateHeaderLines(&iter, &name, &value)) {
189 std::string name_lowercase(name);
190 StringToLowerASCII(&name_lowercase);
191
192 bool header_found = false;
193 for (ResponseHeaders::const_iterator i = new_response_headers->begin();
194 i != new_response_headers->end(); ++i) {
195 if (LowerCaseEqualsASCII(i->first, name_lowercase.c_str()) &&
196 value == i->second) {
197 header_found = true;
198 break;
199 }
200 }
201 if (!header_found)
202 result->deleted_response_headers.push_back(ResponseHeader(name, value));
203 }
204 }
205
206 // Find added headers (header keys are treated case insensitively).
207 {
208 for (ResponseHeaders::const_iterator i = new_response_headers->begin();
209 i != new_response_headers->end(); ++i) {
210 void* iter = NULL;
211 std::string value;
212 bool header_found = false;
213 while (old_response_headers->EnumerateHeader(&iter, i->first, &value) &&
214 !header_found) {
215 header_found = (value == i->second);
216 }
217 if (!header_found)
218 result->added_response_headers.push_back(*i);
219 }
220 }
221
222 return result;
223 }
224
225 EventResponseDelta* CalculateOnAuthRequiredDelta(
226 const std::string& extension_id,
227 const base::Time& extension_install_time,
228 bool cancel,
229 scoped_ptr<net::AuthCredentials>* auth_credentials) {
230 EventResponseDelta* result =
231 new EventResponseDelta(extension_id, extension_install_time);
232 result->cancel = cancel;
233 result->auth_credentials.swap(*auth_credentials);
234 return result;
235 }
236
237 void MergeCancelOfResponses(
238 const EventResponseDeltas& deltas,
239 bool* canceled,
240 EventLogEntries* event_log_entries) {
241 for (EventResponseDeltas::const_iterator i = deltas.begin();
242 i != deltas.end(); ++i) {
243 if ((*i)->cancel) {
244 *canceled = true;
245 EventLogEntry log_entry(
246 net::NetLog::TYPE_CHROME_EXTENSION_ABORTED_REQUEST,
247 make_scoped_refptr(
248 new NetLogExtensionIdParameter((*i)->extension_id)));
249 event_log_entries->push_back(log_entry);
250 break;
251 }
252 }
253 }
254
255 // Helper function for MergeOnBeforeRequestResponses() that allows considering
256 // only data:// urls. These are considered a special case of cancelling a
257 // request. This helper function allows us to ignore all other redirects
258 // in case any extension wants to cancel the request by redirecting to a
259 // data:// url.
260 // Returns whether a redirect occurred.
261 static bool MergeOnBeforeRequestResponsesHelper(
262 const EventResponseDeltas& deltas,
263 GURL* new_url,
264 std::set<std::string>* conflicting_extensions,
265 EventLogEntries* event_log_entries,
266 bool consider_only_data_scheme_urls) {
267 bool redirected = false;
268
269 EventResponseDeltas::const_iterator delta;
270 for (delta = deltas.begin(); delta != deltas.end(); ++delta) {
271 if ((*delta)->new_url.is_empty())
272 continue;
273 if (consider_only_data_scheme_urls &&
274 !(*delta)->new_url.SchemeIs(chrome::kDataScheme)) {
275 continue;
276 }
277
278 if (!redirected || *new_url == (*delta)->new_url) {
279 *new_url = (*delta)->new_url;
280 redirected = true;
281 EventLogEntry log_entry(
282 net::NetLog::TYPE_CHROME_EXTENSION_REDIRECTED_REQUEST,
283 make_scoped_refptr(
284 new NetLogExtensionIdParameter((*delta)->extension_id)));
285 event_log_entries->push_back(log_entry);
286 } else {
287 conflicting_extensions->insert((*delta)->extension_id);
288 EventLogEntry log_entry(
289 net::NetLog::TYPE_CHROME_EXTENSION_IGNORED_DUE_TO_CONFLICT,
290 make_scoped_refptr(
291 new NetLogExtensionIdParameter((*delta)->extension_id)));
292 event_log_entries->push_back(log_entry);
293 }
294 }
295 return redirected;
296 }
297
298 void MergeOnBeforeRequestResponses(
299 const EventResponseDeltas& deltas,
300 GURL* new_url,
301 std::set<std::string>* conflicting_extensions,
302 EventLogEntries* event_log_entries) {
303
304 // First handle only redirects to data:// URLs. These are a special case as
305 // they represent a way of cancelling a request.
306 if (MergeOnBeforeRequestResponsesHelper(
307 deltas, new_url, conflicting_extensions, event_log_entries, true)) {
308 // If any extension cancelled a request by redirecting to a data:// URL,
309 // we don't consider the other redirects.
310 return;
311 }
312
313 // Handle all other redirects.
314 MergeOnBeforeRequestResponsesHelper(
315 deltas, new_url, conflicting_extensions, event_log_entries, false);
316 }
317
318 void MergeOnBeforeSendHeadersResponses(
319 const EventResponseDeltas& deltas,
320 net::HttpRequestHeaders* request_headers,
321 std::set<std::string>* conflicting_extensions,
322 EventLogEntries* event_log_entries) {
323 EventResponseDeltas::const_iterator delta;
324
325 // Here we collect which headers we have removed or set to new values
326 // so far due to extensions of higher precedence.
327 std::set<std::string> removed_headers;
328 std::set<std::string> set_headers;
329
330 // We assume here that the deltas are sorted in decreasing extension
331 // precedence (i.e. decreasing extension installation time).
332 for (delta = deltas.begin(); delta != deltas.end(); ++delta) {
333 if ((*delta)->modified_request_headers.IsEmpty() &&
334 (*delta)->deleted_request_headers.empty()) {
335 continue;
336 }
337
338 scoped_refptr<NetLogModificationParameter> log(
339 new NetLogModificationParameter((*delta)->extension_id));
340
341 // Check whether any modification affects a request header that
342 // has been modified differently before. As deltas is sorted by decreasing
343 // extension installation order, this takes care of precedence.
344 bool extension_conflicts = false;
345 {
346 net::HttpRequestHeaders::Iterator modification(
347 (*delta)->modified_request_headers);
348 while (modification.GetNext() && !extension_conflicts) {
349 // This modification sets |key| to |value|.
350 const std::string& key = modification.name();
351 const std::string& value = modification.value();
352
353 // We must not delete anything that has been modified before.
354 if (removed_headers.find(key) != removed_headers.end())
355 extension_conflicts = true;
356
357 // We must not modify anything that has been set to a *different*
358 // value before.
359 if (set_headers.find(key) != set_headers.end()) {
360 std::string current_value;
361 if (!request_headers->GetHeader(key, &current_value) ||
362 current_value != value) {
363 extension_conflicts = true;
364 }
365 }
366 }
367 }
368
369 // Check whether any deletion affects a request header that has been
370 // modified before.
371 {
372 std::vector<std::string>::iterator key;
373 for (key = (*delta)->deleted_request_headers.begin();
374 key != (*delta)->deleted_request_headers.end() &&
375 !extension_conflicts;
376 ++key) {
377 if (set_headers.find(*key) != set_headers.end())
378 extension_conflicts = true;
379 }
380 }
381
382 // Now execute the modifications if there were no conflicts.
383 if (!extension_conflicts) {
384 // Copy all modifications into the original headers.
385 request_headers->MergeFrom((*delta)->modified_request_headers);
386 {
387 // Record which keys were changed.
388 net::HttpRequestHeaders::Iterator modification(
389 (*delta)->modified_request_headers);
390 while (modification.GetNext()) {
391 set_headers.insert(modification.name());
392 log->ModifiedHeader(modification.name(), modification.value());
393 }
394 }
395
396 // Perform all deletions and record which keys were deleted.
397 {
398 std::vector<std::string>::iterator key;
399 for (key = (*delta)->deleted_request_headers.begin();
400 key != (*delta)->deleted_request_headers.end();
401 ++key) {
402 request_headers->RemoveHeader(*key);
403 removed_headers.insert(*key);
404 log->DeletedHeader(*key);
405 }
406 }
407 EventLogEntry log_entry(
408 net::NetLog::TYPE_CHROME_EXTENSION_MODIFIED_HEADERS, log);
409 event_log_entries->push_back(log_entry);
410 } else {
411 conflicting_extensions->insert((*delta)->extension_id);
412 EventLogEntry log_entry(
413 net::NetLog::TYPE_CHROME_EXTENSION_IGNORED_DUE_TO_CONFLICT,
414 make_scoped_refptr(
415 new NetLogExtensionIdParameter((*delta)->extension_id)));
416 event_log_entries->push_back(log_entry);
417 }
418 }
419 }
420
421 // Converts the key of the (key, value) pair to lower case.
422 static ResponseHeader ToLowerCase(const ResponseHeader& header) {
423 std::string lower_key(header.first);
424 StringToLowerASCII(&lower_key);
425 return ResponseHeader(lower_key, header.second);
426 }
427
428 void MergeOnHeadersReceivedResponses(
429 const EventResponseDeltas& deltas,
430 const net::HttpResponseHeaders* original_response_headers,
431 scoped_refptr<net::HttpResponseHeaders>* override_response_headers,
432 std::set<std::string>* conflicting_extensions,
433 EventLogEntries* event_log_entries) {
434 EventResponseDeltas::const_iterator delta;
435
436 // Here we collect which headers we have removed or added so far due to
437 // extensions of higher precedence. Header keys are always stored as
438 // lower case.
439 std::set<ResponseHeader> removed_headers;
440 std::set<ResponseHeader> added_headers;
441
442 // We assume here that the deltas are sorted in decreasing extension
443 // precedence (i.e. decreasing extension installation time).
444 for (delta = deltas.begin(); delta != deltas.end(); ++delta) {
445 if ((*delta)->added_response_headers.empty() &&
446 (*delta)->deleted_response_headers.empty()) {
447 continue;
448 }
449
450 // Only create a copy if we really want to modify the response headers.
451 if (override_response_headers->get() == NULL) {
452 *override_response_headers = new net::HttpResponseHeaders(
453 original_response_headers->raw_headers());
454 }
455
456 // We consider modifications as pairs of (delete, add) operations.
457 // If a header is deleted twice by different extensions we assume that the
458 // intention was to modify it to different values and consider this a
459 // conflict. As deltas is sorted by decreasing extension installation order,
460 // this takes care of precedence.
461 bool extension_conflicts = false;
462 ResponseHeaders::const_iterator i;
463 for (i = (*delta)->deleted_response_headers.begin();
464 i != (*delta)->deleted_response_headers.end(); ++i) {
465 if (removed_headers.find(ToLowerCase(*i)) != removed_headers.end()) {
466 extension_conflicts = true;
467 break;
468 }
469 }
470
471 // Now execute the modifications if there were no conflicts.
472 if (!extension_conflicts) {
473 // Delete headers
474 {
475 for (i = (*delta)->deleted_response_headers.begin();
476 i != (*delta)->deleted_response_headers.end(); ++i) {
477 (*override_response_headers)->RemoveHeaderWithValue(i->first,
478 i->second);
479 removed_headers.insert(ToLowerCase(*i));
480 }
481 }
482
483 // Add headers.
484 {
485 for (i = (*delta)->added_response_headers.begin();
486 i != (*delta)->added_response_headers.end(); ++i) {
487 ResponseHeader lowercase_header(ToLowerCase(*i));
488 if (added_headers.find(lowercase_header) != added_headers.end())
489 continue;
490 added_headers.insert(lowercase_header);
491 (*override_response_headers)->AddHeader(i->first + ": " + i->second);
492 }
493 }
494 EventLogEntry log_entry(
495 net::NetLog::TYPE_CHROME_EXTENSION_MODIFIED_HEADERS,
496 make_scoped_refptr(
497 new NetLogModificationParameter((*delta)->extension_id)));
498 event_log_entries->push_back(log_entry);
499 } else {
500 conflicting_extensions->insert((*delta)->extension_id);
501 EventLogEntry log_entry(
502 net::NetLog::TYPE_CHROME_EXTENSION_IGNORED_DUE_TO_CONFLICT,
503 make_scoped_refptr(
504 new NetLogExtensionIdParameter((*delta)->extension_id)));
505 event_log_entries->push_back(log_entry);
506 }
507 }
508 }
509
510 bool MergeOnAuthRequiredResponses(
511 const EventResponseDeltas& deltas,
512 net::AuthCredentials* auth_credentials,
513 std::set<std::string>* conflicting_extensions,
514 EventLogEntries* event_log_entries) {
515 CHECK(auth_credentials);
516 bool credentials_set = false;
517
518 for (EventResponseDeltas::const_iterator delta = deltas.begin();
519 delta != deltas.end();
520 ++delta) {
521 if (!(*delta)->auth_credentials.get())
522 continue;
523 bool different =
524 auth_credentials->username() !=
525 (*delta)->auth_credentials->username() ||
526 auth_credentials->password() != (*delta)->auth_credentials->password();
527 if (credentials_set && different) {
528 conflicting_extensions->insert((*delta)->extension_id);
529 EventLogEntry log_entry(
530 net::NetLog::TYPE_CHROME_EXTENSION_IGNORED_DUE_TO_CONFLICT,
531 make_scoped_refptr(
532 new NetLogExtensionIdParameter((*delta)->extension_id)));
533 event_log_entries->push_back(log_entry);
534 } else {
535 EventLogEntry log_entry(
536 net::NetLog::TYPE_CHROME_EXTENSION_PROVIDE_AUTH_CREDENTIALS,
537 make_scoped_refptr(
538 new NetLogExtensionIdParameter((*delta)->extension_id)));
539 event_log_entries->push_back(log_entry);
540 *auth_credentials = *(*delta)->auth_credentials;
541 credentials_set = true;
542 }
543 }
544 return credentials_set;
545 }
546
547 } // namespace extension_webrequest_api_helpers
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698