Index: chrome/browser/extensions/extension_webrequest_api.cc |
diff --git a/chrome/browser/extensions/extension_webrequest_api.cc b/chrome/browser/extensions/extension_webrequest_api.cc |
index 36ee72c7d9e8df807b8ae64a070ebc63077957b4..50f26bedb3ad99a2cd34078b70b0593b252411fc 100644 |
--- a/chrome/browser/extensions/extension_webrequest_api.cc |
+++ b/chrome/browser/extensions/extension_webrequest_api.cc |
@@ -303,6 +303,10 @@ struct ExtensionWebRequestEventRouter::BlockedRequest { |
// for OnBeforeSendHeaders. |
net::HttpRequestHeaders* request_headers; |
+ // If non-empty, this contains the auth credentials that may be filled in. |
+ // Only valid for OnAuthRequired. |
+ net::AuthCredentials* auth_credentials; |
+ |
// Time the request was paused. Used for logging purposes. |
base::Time blocking_time; |
@@ -316,7 +320,8 @@ struct ExtensionWebRequestEventRouter::BlockedRequest { |
net_log(NULL), |
callback(NULL), |
new_url(NULL), |
- request_headers(NULL) {} |
+ request_headers(NULL), |
+ auth_credentials(NULL) {} |
}; |
bool ExtensionWebRequestEventRouter::RequestFilter::InitFromValue( |
@@ -585,25 +590,29 @@ void ExtensionWebRequestEventRouter::OnSendHeaders( |
DispatchEvent(profile, request, listeners, args); |
} |
-void ExtensionWebRequestEventRouter::OnAuthRequired( |
+int ExtensionWebRequestEventRouter::OnAuthRequired( |
void* profile, |
ExtensionInfoMap* extension_info_map, |
net::URLRequest* request, |
- const net::AuthChallengeInfo& auth_info) { |
+ const net::AuthChallengeInfo& auth_info, |
+ net::CompletionCallback* callback, |
+ net::AuthCredentials* credentials) { |
+ // No profile means that this is for authentication challenges in the |
+ // system context. Skip in that case. |
if (!profile) |
- return; |
+ return net::OK; |
base::Time time(base::Time::Now()); |
if (!HasWebRequestScheme(request->url())) |
- return; |
+ return net::OK; |
int extra_info_spec = 0; |
std::vector<const EventListener*> listeners = |
GetMatchingListeners(profile, extension_info_map, |
keys::kOnAuthRequired, request, &extra_info_spec); |
if (listeners.empty()) |
- return; |
+ return net::OK; |
ListValue args; |
DictionaryValue* dict = new DictionaryValue(); |
@@ -620,7 +629,7 @@ void ExtensionWebRequestEventRouter::OnAuthRequired( |
challenger->SetInteger(keys::kPortKey, auth_info.challenger.port()); |
dict->Set(keys::kChallengerKey, challenger); |
dict->SetDouble(keys::kTimeStampKey, time.ToDoubleT() * 1000); |
- if (extra_info_spec & ExtraInfoSpec::REQUEST_HEADERS) { |
+ if (extra_info_spec & ExtraInfoSpec::RESPONSE_HEADERS) { |
dict->Set(keys::kResponseHeadersKey, |
GetResponseHeadersList(request->response_headers())); |
} |
@@ -628,7 +637,13 @@ void ExtensionWebRequestEventRouter::OnAuthRequired( |
dict->Set(keys::kStatusLineKey, GetStatusLine(request->response_headers())); |
args.Append(dict); |
- DispatchEvent(profile, request, listeners, args); |
+ if (DispatchEvent(profile, request, listeners, args)) { |
+ blocked_requests_[request->identifier()].event = kOnAuthRequired; |
+ blocked_requests_[request->identifier()].callback = callback; |
+ blocked_requests_[request->identifier()].auth_credentials = credentials; |
+ return net::ERR_IO_PENDING; |
+ } |
+ return net::OK; |
} |
void ExtensionWebRequestEventRouter::OnBeforeRedirect( |
@@ -1124,6 +1139,9 @@ linked_ptr<ExtensionWebRequestEventRouter::EventResponseDelta> |
} |
} |
+ if (blocked_request->event == kOnAuthRequired) |
+ result->auth_credentials.swap(response->auth_credentials); |
+ |
return result; |
} |
@@ -1255,6 +1273,28 @@ void ExtensionWebRequestEventRouter::MergeOnBeforeSendHeadersResponses( |
} |
} |
+void ExtensionWebRequestEventRouter::MergeOnAuthRequiredResponses( |
+ BlockedRequest* request, |
+ std::list<std::string>* conflicting_extensions) const { |
+ CHECK(request); |
+ CHECK(request->auth_credentials); |
+ bool credentials_set = false; |
+ |
+ const EventResponseDeltas& deltas = request->response_deltas; |
+ for (EventResponseDeltas::const_iterator it = deltas.begin(); |
+ it != deltas.end(); |
+ ++it) { |
+ if (!(*it)->auth_credentials.get()) |
+ continue; |
+ if (credentials_set) { |
+ conflicting_extensions->push_back((*it)->extension_id); |
+ } else { |
+ *request->auth_credentials = *(*it)->auth_credentials; |
+ credentials_set = true; |
+ } |
+ } |
+} |
+ |
void ExtensionWebRequestEventRouter::DecrementBlockCount( |
void* profile, |
const std::string& extension_id, |
@@ -1310,6 +1350,9 @@ void ExtensionWebRequestEventRouter::DecrementBlockCount( |
CHECK(blocked_request.callback); |
MergeOnBeforeSendHeadersResponses(&blocked_request, |
&conflicting_extensions); |
+ } else if (blocked_request.event == kOnAuthRequired) { |
+ CHECK(blocked_request.callback); |
+ MergeOnAuthRequiredResponses(&blocked_request, &conflicting_extensions); |
} else { |
NOTREACHED(); |
} |
@@ -1490,6 +1533,21 @@ bool WebRequestEventHandled::RunImpl() { |
response->request_headers->SetHeader(name, value); |
} |
} |
+ |
+ if (value->HasKey(keys::kAuthCredentialsKey)) { |
+ DictionaryValue* credentials_value = NULL; |
+ EXTENSION_FUNCTION_VALIDATE(value->GetDictionary( |
+ keys::kAuthCredentialsKey, |
+ &credentials_value)); |
+ response->auth_credentials.reset(new net::AuthCredentials()); |
+ EXTENSION_FUNCTION_VALIDATE( |
+ credentials_value->GetString(keys::kUsernameKey, |
+ &response->auth_credentials->username)); |
+ EXTENSION_FUNCTION_VALIDATE( |
+ credentials_value->GetString(keys::kPasswordKey, |
+ &response->auth_credentials->password)); |
+ response->auth_credentials->is_valid = true; |
+ } |
} |
ExtensionWebRequestEventRouter::GetInstance()->OnEventHandled( |