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

Side by Side Diff: chrome/browser/extensions/extension_webrequest_api.cc

Issue 8015004: webRequest.onAuthRequired listeners can provide authentication credentials. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Handle multiple blocking onAuthRequired Created 9 years, 3 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 | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 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/extension_webrequest_api.h" 5 #include "chrome/browser/extensions/extension_webrequest_api.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 8
9 #include "base/json/json_writer.h" 9 #include "base/json/json_writer.h"
10 #include "base/metrics/histogram.h" 10 #include "base/metrics/histogram.h"
(...skipping 285 matching lines...) Expand 10 before | Expand all | Expand 10 after
296 net::CompletionCallback* callback; 296 net::CompletionCallback* callback;
297 297
298 // If non-empty, this contains the new URL that the request will redirect to. 298 // If non-empty, this contains the new URL that the request will redirect to.
299 // Only valid for OnBeforeRequest. 299 // Only valid for OnBeforeRequest.
300 GURL* new_url; 300 GURL* new_url;
301 301
302 // The request headers that will be issued along with this request. Only valid 302 // The request headers that will be issued along with this request. Only valid
303 // for OnBeforeSendHeaders. 303 // for OnBeforeSendHeaders.
304 net::HttpRequestHeaders* request_headers; 304 net::HttpRequestHeaders* request_headers;
305 305
306 // If non-empty, this contains the auth credentials that may be filled in.
307 // Only valid for OnAuthRequired.
308 net::AuthCredentials* auth_credentials;
309
306 // Time the request was paused. Used for logging purposes. 310 // Time the request was paused. Used for logging purposes.
307 base::Time blocking_time; 311 base::Time blocking_time;
308 312
309 // Changes requested by extensions. 313 // Changes requested by extensions.
310 EventResponseDeltas response_deltas; 314 EventResponseDeltas response_deltas;
311 315
312 BlockedRequest() 316 BlockedRequest()
313 : request(NULL), 317 : request(NULL),
314 event(kInvalidEvent), 318 event(kInvalidEvent),
315 num_handlers_blocking(0), 319 num_handlers_blocking(0),
316 net_log(NULL), 320 net_log(NULL),
317 callback(NULL), 321 callback(NULL),
318 new_url(NULL), 322 new_url(NULL),
319 request_headers(NULL) {} 323 request_headers(NULL),
324 auth_credentials(NULL) {}
320 }; 325 };
321 326
322 bool ExtensionWebRequestEventRouter::RequestFilter::InitFromValue( 327 bool ExtensionWebRequestEventRouter::RequestFilter::InitFromValue(
323 const DictionaryValue& value, std::string* error) { 328 const DictionaryValue& value, std::string* error) {
324 for (DictionaryValue::key_iterator key = value.begin_keys(); 329 for (DictionaryValue::key_iterator key = value.begin_keys();
325 key != value.end_keys(); ++key) { 330 key != value.end_keys(); ++key) {
326 if (*key == "urls") { 331 if (*key == "urls") {
327 ListValue* urls_value = NULL; 332 ListValue* urls_value = NULL;
328 if (!value.GetList("urls", &urls_value)) 333 if (!value.GetList("urls", &urls_value))
329 return false; 334 return false;
(...skipping 248 matching lines...) Expand 10 before | Expand all | Expand 10 after
578 dict->SetString(keys::kUrlKey, request->url().spec()); 583 dict->SetString(keys::kUrlKey, request->url().spec());
579 dict->SetDouble(keys::kTimeStampKey, time.ToDoubleT() * 1000); 584 dict->SetDouble(keys::kTimeStampKey, time.ToDoubleT() * 1000);
580 if (extra_info_spec & ExtraInfoSpec::REQUEST_HEADERS) 585 if (extra_info_spec & ExtraInfoSpec::REQUEST_HEADERS)
581 dict->Set(keys::kRequestHeadersKey, GetRequestHeadersList(headers)); 586 dict->Set(keys::kRequestHeadersKey, GetRequestHeadersList(headers));
582 // TODO(battre): support "request line". 587 // TODO(battre): support "request line".
583 args.Append(dict); 588 args.Append(dict);
584 589
585 DispatchEvent(profile, request, listeners, args); 590 DispatchEvent(profile, request, listeners, args);
586 } 591 }
587 592
588 void ExtensionWebRequestEventRouter::OnAuthRequired( 593 int ExtensionWebRequestEventRouter::OnAuthRequired(
589 void* profile, 594 void* profile,
590 ExtensionInfoMap* extension_info_map, 595 ExtensionInfoMap* extension_info_map,
591 net::URLRequest* request, 596 net::URLRequest* request,
592 const net::AuthChallengeInfo& auth_info) { 597 const net::AuthChallengeInfo& auth_info,
598 net::CompletionCallback* callback,
599 net::AuthCredentials* credentials) {
600 // No profile means that this is for authentication challenges in the
601 // system context. Skip in that case.
593 if (!profile) 602 if (!profile)
594 return; 603 return net::OK;
595 604
596 base::Time time(base::Time::Now()); 605 base::Time time(base::Time::Now());
597 606
598 if (!HasWebRequestScheme(request->url())) 607 if (!HasWebRequestScheme(request->url()))
599 return; 608 return net::OK;
600 609
601 int extra_info_spec = 0; 610 int extra_info_spec = 0;
602 std::vector<const EventListener*> listeners = 611 std::vector<const EventListener*> listeners =
603 GetMatchingListeners(profile, extension_info_map, 612 GetMatchingListeners(profile, extension_info_map,
604 keys::kOnAuthRequired, request, &extra_info_spec); 613 keys::kOnAuthRequired, request, &extra_info_spec);
605 if (listeners.empty()) 614 if (listeners.empty())
606 return; 615 return net::OK;
607 616
608 ListValue args; 617 ListValue args;
609 DictionaryValue* dict = new DictionaryValue(); 618 DictionaryValue* dict = new DictionaryValue();
610 dict->SetString(keys::kRequestIdKey, 619 dict->SetString(keys::kRequestIdKey,
611 base::Uint64ToString(request->identifier())); 620 base::Uint64ToString(request->identifier()));
612 dict->SetString(keys::kUrlKey, request->url().spec()); 621 dict->SetString(keys::kUrlKey, request->url().spec());
613 dict->SetBoolean(keys::kIsProxyKey, auth_info.is_proxy); 622 dict->SetBoolean(keys::kIsProxyKey, auth_info.is_proxy);
614 if (!auth_info.scheme.empty()) 623 if (!auth_info.scheme.empty())
615 dict->SetString(keys::kSchemeKey, auth_info.scheme); 624 dict->SetString(keys::kSchemeKey, auth_info.scheme);
616 if (!auth_info.realm.empty()) 625 if (!auth_info.realm.empty())
617 dict->SetString(keys::kRealmKey, auth_info.realm); 626 dict->SetString(keys::kRealmKey, auth_info.realm);
618 DictionaryValue* challenger = new DictionaryValue(); 627 DictionaryValue* challenger = new DictionaryValue();
619 challenger->SetString(keys::kHostKey, auth_info.challenger.host()); 628 challenger->SetString(keys::kHostKey, auth_info.challenger.host());
620 challenger->SetInteger(keys::kPortKey, auth_info.challenger.port()); 629 challenger->SetInteger(keys::kPortKey, auth_info.challenger.port());
621 dict->Set(keys::kChallengerKey, challenger); 630 dict->Set(keys::kChallengerKey, challenger);
622 dict->SetDouble(keys::kTimeStampKey, time.ToDoubleT() * 1000); 631 dict->SetDouble(keys::kTimeStampKey, time.ToDoubleT() * 1000);
623 if (extra_info_spec & ExtraInfoSpec::REQUEST_HEADERS) { 632 if (extra_info_spec & ExtraInfoSpec::RESPONSE_HEADERS) {
624 dict->Set(keys::kResponseHeadersKey, 633 dict->Set(keys::kResponseHeadersKey,
625 GetResponseHeadersList(request->response_headers())); 634 GetResponseHeadersList(request->response_headers()));
626 } 635 }
627 if (extra_info_spec & ExtraInfoSpec::STATUS_LINE) 636 if (extra_info_spec & ExtraInfoSpec::STATUS_LINE)
628 dict->Set(keys::kStatusLineKey, GetStatusLine(request->response_headers())); 637 dict->Set(keys::kStatusLineKey, GetStatusLine(request->response_headers()));
629 args.Append(dict); 638 args.Append(dict);
630 639
631 DispatchEvent(profile, request, listeners, args); 640 if (DispatchEvent(profile, request, listeners, args)) {
641 blocked_requests_[request->identifier()].event = kOnAuthRequired;
642 blocked_requests_[request->identifier()].callback = callback;
643 blocked_requests_[request->identifier()].auth_credentials = credentials;
644 return net::ERR_IO_PENDING;
645 }
646 return net::OK;
632 } 647 }
633 648
634 void ExtensionWebRequestEventRouter::OnBeforeRedirect( 649 void ExtensionWebRequestEventRouter::OnBeforeRedirect(
635 void* profile, 650 void* profile,
636 ExtensionInfoMap* extension_info_map, 651 ExtensionInfoMap* extension_info_map,
637 net::URLRequest* request, 652 net::URLRequest* request,
638 const GURL& new_location) { 653 const GURL& new_location) {
639 if (!profile) 654 if (!profile)
640 return; 655 return;
641 656
(...skipping 475 matching lines...) Expand 10 before | Expand all | Expand 10 after
1117 net::HttpRequestHeaders::Iterator i(*new_headers); 1132 net::HttpRequestHeaders::Iterator i(*new_headers);
1118 while (i.GetNext()) { 1133 while (i.GetNext()) {
1119 std::string value; 1134 std::string value;
1120 if (!old_headers->GetHeader(i.name(), &value) || i.value() != value) { 1135 if (!old_headers->GetHeader(i.name(), &value) || i.value() != value) {
1121 result->modified_request_headers.SetHeader(i.name(), i.value()); 1136 result->modified_request_headers.SetHeader(i.name(), i.value());
1122 } 1137 }
1123 } 1138 }
1124 } 1139 }
1125 } 1140 }
1126 1141
1142 if (blocked_request->event == kOnAuthRequired)
1143 result->auth_credentials.swap(response->auth_credentials);
1144
1127 return result; 1145 return result;
1128 } 1146 }
1129 1147
1130 void ExtensionWebRequestEventRouter::MergeOnBeforeRequestResponses( 1148 void ExtensionWebRequestEventRouter::MergeOnBeforeRequestResponses(
1131 BlockedRequest* request, 1149 BlockedRequest* request,
1132 std::list<std::string>* conflicting_extensions) const { 1150 std::list<std::string>* conflicting_extensions) const {
1133 EventResponseDeltas::iterator delta; 1151 EventResponseDeltas::iterator delta;
1134 EventResponseDeltas& deltas = request->response_deltas; 1152 EventResponseDeltas& deltas = request->response_deltas;
1135 1153
1136 bool redirected = false; 1154 bool redirected = false;
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after
1248 } else { 1266 } else {
1249 conflicting_extensions->push_back((*delta)->extension_id); 1267 conflicting_extensions->push_back((*delta)->extension_id);
1250 request->net_log->AddEvent( 1268 request->net_log->AddEvent(
1251 net::NetLog::TYPE_CHROME_EXTENSION_IGNORED_DUE_TO_CONFLICT, 1269 net::NetLog::TYPE_CHROME_EXTENSION_IGNORED_DUE_TO_CONFLICT,
1252 make_scoped_refptr( 1270 make_scoped_refptr(
1253 new NetLogExtensionIdParameter((*delta)->extension_id))); 1271 new NetLogExtensionIdParameter((*delta)->extension_id)));
1254 } 1272 }
1255 } 1273 }
1256 } 1274 }
1257 1275
1276 void ExtensionWebRequestEventRouter::MergeOnAuthRequiredResponses(
1277 BlockedRequest* request,
1278 std::list<std::string>* conflicting_extensions) const {
1279 CHECK(request);
1280 CHECK(request->auth_credentials);
1281 bool credentials_set = false;
1282
1283 const EventResponseDeltas& deltas = request->response_deltas;
1284 for (EventResponseDeltas::const_iterator it = deltas.begin();
1285 it != deltas.end();
1286 ++it) {
1287 if (!(*it)->auth_credentials.get())
1288 continue;
1289 if (credentials_set) {
1290 conflicting_extensions->push_back((*it)->extension_id);
1291 } else {
1292 *request->auth_credentials = *(*it)->auth_credentials;
1293 credentials_set = true;
1294 }
1295 }
1296 }
1297
1258 void ExtensionWebRequestEventRouter::DecrementBlockCount( 1298 void ExtensionWebRequestEventRouter::DecrementBlockCount(
1259 void* profile, 1299 void* profile,
1260 const std::string& extension_id, 1300 const std::string& extension_id,
1261 const std::string& event_name, 1301 const std::string& event_name,
1262 uint64 request_id, 1302 uint64 request_id,
1263 EventResponse* response) { 1303 EventResponse* response) {
1264 scoped_ptr<EventResponse> response_scoped(response); 1304 scoped_ptr<EventResponse> response_scoped(response);
1265 1305
1266 // It's possible that this request was deleted, or cancelled by a previous 1306 // It's possible that this request was deleted, or cancelled by a previous
1267 // event handler. If so, ignore this response. 1307 // event handler. If so, ignore this response.
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
1303 deltas.sort(&InDecreasingExtensionInstallationTimeOrder); 1343 deltas.sort(&InDecreasingExtensionInstallationTimeOrder);
1304 std::list<std::string> conflicting_extensions; 1344 std::list<std::string> conflicting_extensions;
1305 1345
1306 if (blocked_request.event == kOnBeforeRequest) { 1346 if (blocked_request.event == kOnBeforeRequest) {
1307 CHECK(blocked_request.callback); 1347 CHECK(blocked_request.callback);
1308 MergeOnBeforeRequestResponses(&blocked_request, &conflicting_extensions); 1348 MergeOnBeforeRequestResponses(&blocked_request, &conflicting_extensions);
1309 } else if (blocked_request.event == kOnBeforeSendHeaders) { 1349 } else if (blocked_request.event == kOnBeforeSendHeaders) {
1310 CHECK(blocked_request.callback); 1350 CHECK(blocked_request.callback);
1311 MergeOnBeforeSendHeadersResponses(&blocked_request, 1351 MergeOnBeforeSendHeadersResponses(&blocked_request,
1312 &conflicting_extensions); 1352 &conflicting_extensions);
1353 } else if (blocked_request.event == kOnAuthRequired) {
1354 CHECK(blocked_request.callback);
1355 MergeOnAuthRequiredResponses(&blocked_request, &conflicting_extensions);
1313 } else { 1356 } else {
1314 NOTREACHED(); 1357 NOTREACHED();
1315 } 1358 }
1316 std::list<std::string>::iterator conflict_iter; 1359 std::list<std::string>::iterator conflict_iter;
1317 for (conflict_iter = conflicting_extensions.begin(); 1360 for (conflict_iter = conflicting_extensions.begin();
1318 conflict_iter != conflicting_extensions.end(); 1361 conflict_iter != conflicting_extensions.end();
1319 ++conflict_iter) { 1362 ++conflict_iter) {
1320 // TODO(mpcomplete): Do some fancy notification in the UI. 1363 // TODO(mpcomplete): Do some fancy notification in the UI.
1321 LOG(ERROR) << "Extension " << *conflict_iter << " was ignored in " 1364 LOG(ERROR) << "Extension " << *conflict_iter << " was ignored in "
1322 "webRequest API because of conflicting request " 1365 "webRequest API because of conflicting request "
(...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after
1483 EXTENSION_FUNCTION_VALIDATE( 1526 EXTENSION_FUNCTION_VALIDATE(
1484 request_headers_value->GetDictionary(i, &header_value)); 1527 request_headers_value->GetDictionary(i, &header_value));
1485 EXTENSION_FUNCTION_VALIDATE( 1528 EXTENSION_FUNCTION_VALIDATE(
1486 header_value->GetString(keys::kHeaderNameKey, &name)); 1529 header_value->GetString(keys::kHeaderNameKey, &name));
1487 EXTENSION_FUNCTION_VALIDATE( 1530 EXTENSION_FUNCTION_VALIDATE(
1488 header_value->GetString(keys::kHeaderValueKey, &value)); 1531 header_value->GetString(keys::kHeaderValueKey, &value));
1489 1532
1490 response->request_headers->SetHeader(name, value); 1533 response->request_headers->SetHeader(name, value);
1491 } 1534 }
1492 } 1535 }
1536
1537 if (value->HasKey(keys::kAuthCredentialsKey)) {
1538 DictionaryValue* credentials_value = NULL;
1539 EXTENSION_FUNCTION_VALIDATE(value->GetDictionary(
1540 keys::kAuthCredentialsKey,
1541 &credentials_value));
1542 response->auth_credentials.reset(new net::AuthCredentials());
1543 EXTENSION_FUNCTION_VALIDATE(
1544 credentials_value->GetString(keys::kUsernameKey,
1545 &response->auth_credentials->username));
1546 EXTENSION_FUNCTION_VALIDATE(
1547 credentials_value->GetString(keys::kPasswordKey,
1548 &response->auth_credentials->password));
1549 response->auth_credentials->is_valid = true;
1550 }
1493 } 1551 }
1494 1552
1495 ExtensionWebRequestEventRouter::GetInstance()->OnEventHandled( 1553 ExtensionWebRequestEventRouter::GetInstance()->OnEventHandled(
1496 profile(), extension_id(), event_name, sub_event_name, request_id, 1554 profile(), extension_id(), event_name, sub_event_name, request_id,
1497 response.release()); 1555 response.release());
1498 1556
1499 return true; 1557 return true;
1500 } 1558 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698