Add support for GetAuthCredentials (fixes issue #2718, see issue #2622).

When NetworkService is enabled requests created using CefFrame::CreateURLRequest
will call CefRequestHandler::GetAuthCredentials for the associated browser after
calling CefURLRequestClient::GetAuthCredentials if that call returns false.
This commit is contained in:
Marshall Greenblatt
2019-07-12 16:44:43 -04:00
parent ac2cc54e13
commit 3f1ebebde5
30 changed files with 859 additions and 77 deletions

View File

@ -22,12 +22,88 @@
#include "base/memory/weak_ptr.h"
#include "base/message_loop/message_loop.h"
#include "base/strings/string_util.h"
#include "content/public/browser/global_request_id.h"
#include "content/public/browser/render_frame_host.h"
#include "net/base/net_errors.h"
#include "net/http/http_response_headers.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
#include "services/network/public/cpp/simple_url_loader.h"
#include "services/network/public/cpp/simple_url_loader_stream_consumer.h"
namespace {
const int32_t kInitialRequestID = -2;
// Request ID for requests initiated by CefBrowserURLRequest. request_ids
// generated by child processes are counted up from 0, while browser
// created requests start at -2 and go down from there. (We need to start at -2
// because -1 is used as a special value all over the resource_dispatcher_host
// for uninitialized variables.) The resource_dispatcher_host code path is not
// used when NetworkService is enabled so it's safe to repurpose the -2 and
// below range here.
// This method is only called on the UI thread.
int32_t MakeRequestID() {
static int32_t request_id = kInitialRequestID;
return --request_id;
}
// Manages the mapping of request IDs to request objects.
class RequestManager {
public:
RequestManager() {}
~RequestManager() { DCHECK(map_.empty()); }
void Add(int32_t request_id,
CefRefPtr<CefBrowserURLRequest> request,
CefRefPtr<CefURLRequestClient> client) {
DCHECK_LE(request_id, kInitialRequestID);
base::AutoLock lock_scope(lock_);
DCHECK(map_.find(request_id) == map_.end());
map_.insert(std::make_pair(request_id, std::make_pair(request, client)));
}
void Remove(int32_t request_id) {
if (request_id > kInitialRequestID)
return;
base::AutoLock lock_scope(lock_);
RequestMap::iterator it = map_.find(request_id);
DCHECK(it != map_.end());
map_.erase(it);
}
base::Optional<CefBrowserURLRequest::RequestInfo> Get(int32_t request_id) {
if (request_id > kInitialRequestID)
return base::nullopt;
base::AutoLock lock_scope(lock_);
RequestMap::const_iterator it = map_.find(request_id);
if (it != map_.end()) {
return it->second;
}
return base::nullopt;
}
private:
base::Lock lock_;
using RequestMap = std::map<int32_t, CefBrowserURLRequest::RequestInfo>;
RequestMap map_;
DISALLOW_COPY_AND_ASSIGN(RequestManager);
};
#if DCHECK_IS_ON()
// Because of DCHECK()s in the object destructor.
base::LazyInstance<RequestManager>::DestructorAtExit g_manager =
LAZY_INSTANCE_INITIALIZER;
#else
base::LazyInstance<RequestManager>::Leaky g_manager = LAZY_INSTANCE_INITIALIZER;
#endif
} // namespace
// CefBrowserURLRequest::Context ----------------------------------------------
class CefBrowserURLRequest::Context
@ -113,6 +189,7 @@ class CefBrowserURLRequest::Context
request_context_impl->GetBrowserContext();
DCHECK(browser_context);
int render_frame_id = MSG_ROUTING_NONE;
scoped_refptr<net_service::URLLoaderFactoryGetter> loader_factory_getter;
if (frame) {
// The request will be associated with this frame/browser if it's valid,
@ -120,6 +197,14 @@ class CefBrowserURLRequest::Context
content::RenderFrameHost* rfh =
static_cast<CefFrameHostImpl*>(frame.get())->GetRenderFrameHost();
if (rfh) {
// In cases where authentication is required this value will be passed
// as the |routing_id| parameter to
// NetworkServiceClient::OnAuthRequired. Despite the naming the
// GetWebContents method in network_service_client.cc expects it to be a
// FrameTreeNodeId. The |process_id| parameter will always be
// network::mojom::kBrowserProcessId (value 0) for these requests.
render_frame_id = rfh->GetFrameTreeNodeId();
loader_factory_getter =
net_service::URLLoaderFactoryGetter::Create(rfh, browser_context);
}
@ -132,10 +217,12 @@ class CefBrowserURLRequest::Context
FROM_HERE,
base::BindOnce(
&CefBrowserURLRequest::Context::ContinueOnOriginatingThread, self,
loader_factory_getter));
render_frame_id, MakeRequestID(), loader_factory_getter));
}
void ContinueOnOriginatingThread(
int render_frame_id,
int32_t request_id,
scoped_refptr<net_service::URLLoaderFactoryGetter>
loader_factory_getter) {
DCHECK(CalledOnValidThread());
@ -163,6 +250,8 @@ class CefBrowserURLRequest::Context
static_cast<CefRequestImpl*>(request_.get())
->Get(resource_request.get(), false);
resource_request->render_frame_id = render_frame_id;
// SimpleURLLoader is picky about the body contents. Try to populate them
// correctly below.
auto request_body = resource_request->request_body;
@ -187,6 +276,11 @@ class CefBrowserURLRequest::Context
loader_ = network::SimpleURLLoader::Create(std::move(resource_request),
NO_TRAFFIC_ANNOTATION_YET);
// Associate the request with |request_id|.
request_id_ = request_id;
loader_->SetRequestId(request_id);
g_manager.Get().Add(request_id, url_request_, client_);
if (request_body) {
if (request_body->elements()->size() == 1) {
const auto& element = (*request_body->elements())[0];
@ -294,6 +388,7 @@ class CefBrowserURLRequest::Context
DCHECK(request_->GetFlags() | UR_FLAG_STOP_ON_REDIRECT);
response_->SetReadOnly(false);
response_->SetURL(redirect_info.new_url.spec());
response_->SetResponseHeaders(*response_head.headers);
response_->SetReadOnly(true);
@ -403,6 +498,8 @@ class CefBrowserURLRequest::Context
DCHECK(CalledOnValidThread());
DCHECK(url_request_);
g_manager.Get().Remove(request_id_);
client_ = nullptr;
request_context_ = nullptr;
@ -439,6 +536,8 @@ class CefBrowserURLRequest::Context
scoped_refptr<net_service::URLLoaderFactoryGetter> loader_factory_getter_;
std::unique_ptr<network::SimpleURLLoader> loader_;
int32_t request_id_ = 0;
CefURLRequest::Status status_ = UR_IO_PENDING;
CefRefPtr<CefResponseImpl> response_;
bool response_was_cached_ = false;
@ -453,6 +552,22 @@ class CefBrowserURLRequest::Context
// CefBrowserURLRequest -------------------------------------------------------
// static
base::Optional<CefBrowserURLRequest::RequestInfo>
CefBrowserURLRequest::FromRequestID(int32_t request_id) {
return g_manager.Get().Get(request_id);
}
// static
base::Optional<CefBrowserURLRequest::RequestInfo>
CefBrowserURLRequest::FromRequestID(
const content::GlobalRequestID& request_id) {
if (request_id.child_id == network::mojom::kBrowserProcessId) {
return FromRequestID(request_id.request_id);
}
return base::nullopt;
}
CefBrowserURLRequest::CefBrowserURLRequest(
CefRefPtr<CefFrame> frame,
CefRefPtr<CefRequest> request,