最近花了点时间看了看chromium加载网页的逻辑。由于这段内容较为复杂,现在只看了一部分。现将主资源的加载记录下来。
注:下面提到的文件,如果没有指明目录,则在third_party/WebKit目录下
1. ContentViewCore执行loadUrl之后,经过一些逻辑(这些逻辑比较简单,这里不做介绍),最终会走到:render_frame_impl.cc的方法:RenderFrameImpl::OnNavigate
该方法中,有代码:frame->loadRequest(request);
2. 上面方法在thirdparty/WebKit目录下,WebLocalFrameImpl.cpp文件中:WebFrameImpl::loadRequest
3. 接着走到:FrameLoader.cpp文件中,FrameLoader::load
4. 接着走到:同文件中方法:FrameLoader::loadWithNavigationAction
在该方法中,创建了DocumentLoader对象。且该对象的状态从:m_policyDocumentLoader变化为m_provisionalDocumentLoader
注:DocumentLoader对象的状态的再次改变是在方法:FrameLoader::commitProvisionalLoad()中:
m_documentLoader = m_provisionalDocumentLoader.release();
m_policyDocumentLoader = m_client->createDocumentLoader(m_frame, request, substituteData.isValid() ? substituteData : defaultSubstituteDataForURL(request.url()));
之后该DocumentLoader对象状态发生变化:
m_provisionalDocumentLoader = m_policyDocumentLoader.release();
5. 接着走到:DocumentLoader.cpp文件中方法: DocumentLoader::startLoadingMainResource()
该方法中有代码:m_mainResource = m_fetcher->fetchMainResource(cachedResourceRequest, m_substituteData);
6. 该代码是文件ResourceFetcher.cpp文件中方法:ResourceFetcher::fetchMainResource
7. 接着走到:同文件中的方法:ResourceFetcher::requestResource
该方法中有代码:resource = loadResource(type, request, request.charset()); 会创建Resouce对象。
紧接着有代码:resource->load(this, request.options());
8.上面方法是在文件:Resource.cpp中,Resource::load。
该方法中有代码:m_loader = ResourceLoader::create(fetcher, this, request, options);
m_loader->start();
创建了ResourceLoader对象。
9. 我们接着看 m_loader->start();。该代码是执行的ResourceLoader.cpp文件中方法:ResourceLoader::start()。
在该方法中有代码:m_host->willStartLoadingResource(m_request);
执行的是ResourceFetcher对象的方法:willStartLoadingResource
上面方法会调用文件ApplicationCacheHost.cpp中方法:willStartLoadingResource。
上面方法会调用content目录下文件:web_application_cache_host_impl.cc文件中方法:
WebApplicationCacheHostImpl::willStartSubResourceRequest。
继续看方法:ResourceLoader::start()。
该方法中有代码:m_loader = adoptPtr(blink::Platform::current()->createURLLoader());
这里创建了平台化的WebURLLoader对象。
createURLLoader()方法在文件content/下的blink_platform_impl.cc.
10. 是面创建的WebURLLoader对象是文件: .../src/content/下的文件web_url_loader_impl.cc
我们继续看该文件中的方法:loadAsynchronously
11. WebURLLoaderImpl::loadAsynchronously方法中有代码:context_->Start(request, NULL);
该Start方法在同文件中:void WebURLLoaderImpl::Context::Start
该方法中有代码:bridge_.reset(resource_dispatcher_->CreateBridge(request_info));
12. 上面方法会调用:content目录下:resource_dispatcher.cc文件中的方法:ResourceDispatcher::CreateBridge.
该方法会创建对象:IPCResourceLoaderBridge
13. 我们继续看10中提到的方法:WebURLLoaderImpl::Context::Start。该方法中有代码:bridge_->Start(this)
14. 通过11-12的解释,我们来看content目录下:IPCResourceLoaderBridge对象的Start方法。该方法是在content目录下文件:resource_dispatcher.cc中:IPCResourceLoaderBridge::Start(RequestPeer* peer)
15. 上面方法会发送消息,该消息处理是在content目录下文件:resource_dispatcher_host_impl.cc中方法:ResourceDispatcherHostImpl::OnRequestResource
16. 上面方法会执行同文件的方法:ResourceDispatcherHostImpl::BeginRequest(方法。
17. 上面方法会执行同文件的方法:ResourceDispatcherHostImpl::BeginRequestInternal方法。
18. 上面方法会执行同文件的方法:ResourceDispatcherHostImpl::StartLoading方法
19. 上面方法会调用content目录下文件:resource_loader.cc中方法:ResourceLoader::StartRequest()
20. 上面方法会调用同文件的方法:ResourceLoader::StartRequestInternal()。该方法中有代码:request_->Start();
该request_是.../src/net目录下文件url_request.cc对象。
21. 我们来看.../src/net目录下文件url_request.cc中方法: URLRequest::Start()
22. 上面方法会调用同文件中的方法:URLRequest::StartJob.该函数最后一行:job_->Start();
该job_是.../src/content目录下url_request_job.cc对象。
23. 上面方法又会调用同文件的方法: MaybeBeginDelivery();
24. 上面方法会调用同文件的方法:BeginDelivery
25. 上面方法会调用.../src/net/目录下文件:url_request_job.cc中的方法:URLRequestJob::NotifyRestartRequired
26. 上面方法调用.../src/net/目录下文件:url_request.cc中方法:URLRequest::Restart
27. 上面方法会调用同文件的方法:URLRequest::RestartWithJob
28. 上面方法调用同文件的方法:调用同文件方法:PrepareToRestart()将当前的job kill掉。
之后会调用:URLRequest::StartJob()
这次该文件中方法:job_->Start();
这次创建的job是url_request_job.cc对象。
关于这里,过程有些罗嗦。job创建和restart过程好几次。最后创建的是url_request_http_job.cc.我们这里看看其具体过程。
I/chromium( 2598): [url_request_job_manager.cc(50)] URLRequestJobManager::CreateJob
I/xxx ( 2598): Tab.java @@@@@@@@@@@@@@@ onPageStarted url is http://www.baidu.com/
I/chromium( 2598): [url_request_job_manager.cc(87)] vnbo URLRequestJobManager::CreateJob 000 job is 0x00485e60
I/chromium( 2598): [url_request_job.cc(506)] URLRequestJob::NotifyRestartRequired()
I/chromium( 2598): [url_request.cc(715)] URLRequest::Restart()
I/chromium( 2598): [url_request_job_manager.cc(50)] URLRequestJobManager::CreateJob
I/chromium( 2598): [url_request_job_manager.cc(96)] URLRequestJobManager::CreateJob job is 0x004977d8
I/chromium( 2598): [url_request_job.cc(53)] URLRequestJob::Kill() and job is 0x00485e60
I/chromium( 2598): [service_worker_url_request_job.cc(59)] ServiceWorkerURLRequestJob::Start()
I/chromium( 2598): [service_worker_url_request_job.cc(203)] ServiceWorkerURLRequestJob::MaybeStartRequest()
I/chromium( 2598): [service_worker_url_request_job.cc(203)] ServiceWorkerURLRequestJob::MaybeStartRequest()
I/chromium( 2598): [service_worker_url_request_job.cc(214)] ServiceWorkerURLRequestJob::StartRequest()
I/chromium( 2598): [service_worker_url_request_job.cc(224)] ServiceWorkerURLRequestJob::StartRequest() 1
I/chromium( 2598): [url_request_job.cc(506)] URLRequestJob::NotifyRestartRequired()
I/chromium( 2598): [url_request.cc(715)] URLRequest::Restart()
I/chromium( 2598): [url_request_job_manager.cc(50)] URLRequestJobManager::CreateJob
I/chromium( 2598): [url_request_job_manager.cc(87)] URLRequestJobManager::CreateJob 000 job is 0x00497a00
I/chromium( 2598): [url_request_job.cc(53)] URLRequestJob::Kill() and job is 0x004977d8
I/chromium( 2598): [url_request_job.cc(482)] URLRequestJob::CompleteNotifyDone()
I/chromium( 2598): [url_request_job.cc(506)] URLRequestJob::NotifyRestartRequired()
I/chromium( 2598): [url_request.cc(715)] URLRequest::Restart()
I/chromium( 2598): [url_request_job_manager.cc(50)] URLRequestJobManager::CreateJob
I/chromium( 2598): [url_request_job_manager.cc(96)] URLRequestJobManager::CreateJob job is 0x00000000
I/chromium( 2598): [url_request_http_job.cc(156)] URLRequestJob* URLRequestHttpJob::Factory
I/chromium( 2598): [url_request_job_manager.cc(106)] URLRequestJobManager::CreateJob job 2 is 0x00498848
I/chromium( 2598): [url_request_job.cc(53)] URLRequestJob::Kill() and job is 0x00497a00
为了查看该创建Job的过程,将jobManager中CreateJob方法贴出来
URLRequestJob* URLRequestJobManager::CreateJob(
URLRequest* request, NetworkDelegate* network_delegate) const {
DCHECK(IsAllowedThread());
LOG(INFO)<<" URLRequestJobManager::CreateJob";
// If we are given an invalid URL, then don't even try to inspect the scheme.
if (!request->url().is_valid()){
URLRequestJob* job = new URLRequestErrorJob(request, network_delegate, ERR_INVALID_URL);
LOG(INFO)<<" URLRequestJobManager::CreateJob 0 job is "<<job;
return job;
}
// return new URLRequestErrorJob(request, network_delegate, ERR_INVALID_URL);
// We do this here to avoid asking interceptors about unsupported schemes.
const URLRequestJobFactory* job_factory = NULL;
job_factory = request->context()->job_factory();
const std::string& scheme = request->url().scheme(); // already lowercase
if (!job_factory->IsHandledProtocol(scheme)) {
URLRequestJob* job = new URLRequestErrorJob(
request, network_delegate, ERR_UNKNOWN_URL_SCHEME);
LOG(INFO)<<" URLRequestJobManager::CreateJob 00 job is "<<job;
return job;
//return new URLRequestErrorJob(
// request, network_delegate, ERR_UNKNOWN_URL_SCHEME);
}
// THREAD-SAFETY NOTICE:
// We do not need to acquire the lock here since we are only reading our
// data structures. They should only be modified on the current thread.
// See if the request should be intercepted.
//
// TODO(pauljensen): Remove this when AppCacheInterceptor is a
// ProtocolHandler, see crbug.com/161547.
if (!(request->load_flags() & LOAD_DISABLE_INTERCEPT)) {
InterceptorList::const_iterator i;
for (i = interceptors_.begin(); i != interceptors_.end(); ++i) {
URLRequestJob* job = (*i)->MaybeIntercept(request, network_delegate);
if (job){
<strong><span style="color:#FF0000;">// note : the first job</span></strong>
LOG(INFO)<<"vnbo URLRequestJobManager::CreateJob 000 job is "<<job;
return job;
}
}
}
URLRequestJob* job = job_factory->MaybeCreateJobWithProtocolHandler(
scheme, request, network_delegate);
<span style="color:#FF0000;"><strong>// note : this second job</strong></span>
LOG(INFO)<<" URLRequestJobManager::CreateJob job is "<<job;
if (job)
return job;
// See if the request should be handled by a built-in protocol factory.
for (size_t i = 0; i < arraysize(kBuiltinFactories); ++i) {
if (scheme == kBuiltinFactories[i].scheme) {
URLRequestJob* job = (kBuiltinFactories[i].factory)(
request, network_delegate, scheme);
DCHECK(job); // The built-in factories are not expected to fail!
<span style="color:#FF0000;"><strong>// note : the third job</strong></span>
LOG(INFO)<<" URLRequestJobManager::CreateJob job 2 is "<<job;
return job;
}
}
// If we reached here, then it means that a registered protocol factory
// wasn't interested in handling the URL. That is fairly unexpected, and we
// don't have a specific error to report here :-(
LOG(WARNING) << "Failed to map: " << request->url().spec();
// return new URLRequestErrorJob(request, network_delegate, ERR_FAILED);
job = new URLRequestErrorJob(request, network_delegate, ERR_FAILED);
LOG(INFO)<<"vnbo URLRequestJobManager::CreateJob job 3 is "<<job;
return job;
}
29. 我们接着看:
URLRequestHttpJob::AddCookieHeaderAndStart()
30. 上面方法调用同文件的方法:URLRequestHttpJob::CheckCookiePolicyAndLoad
31. 上面方法调用同文件的方法:URLRequestHttpJob::DoStartTransaction()
32. 上面方法调用同文件的方法:URLRequestHttpJob::StartTransaction()。
33 . 上面方法调用同文件的方法:URLRequestHttpJob::StartTransactionInternal()
该方法中有代码:rv = transaction_->Start(
这里创建的是HttpCache::Transaction::Transaction对象。
注:在资源的加载的过程中,会有两类Transaction对象;一个是HttpCache::Transaction::Transaction对象,还有一个HttpNetworkTransaction::HttpNetworkTransaction对象。两者相互配合,才使的网页内容download下来。加载过程中,现将网页的header部分加载,然后再加载body部分。
我们继续看:rv = transaction_->Start(,该代码执行的是:src/net目录下,http_cache_transaction.cc文件中方法:HttpCache::Transaction::Start
在该方法中有代码:int rv = DoLoop(OK);
在这里会执行一系列操作,这里先不进行分析,我们先去找到如何创建和启动HttpNetworkTransaction::HttpNetworkTransaction对象。因为这个对象才是真正去加载网页的Transaction。
34. 在上面提到的方法HttpCache::Transaction::DoLoop中,有代码:
case STATE_SEND_REQUEST:
DCHECK_EQ(OK, rv);
rv = DoSendRequest();
break;
我们继续看代码:DoSendRequest()。在该方法中,有代码:
int rv = cache_->network_layer_->CreateTransaction(priority_,
&network_trans_); 这是创建HttpNetworkTransaction::HttpNetworkTransaction对象。
在该方法的后面有代码: rv = network_trans_->Start(request_, io_callback_, net_log_);
这是启动HttpNetworkTransaction::HttpNetworkTransaction对象。
35. 在对象HttpNetworkTransaction::HttpNetworkTransaction中Start方法中,会调用同文件的方法:
int HttpNetworkTransaction::DoLoop
这里面,会进行一些列调用。 会创建HttpStreamRequest和HttpStreamBase对象。
并调用方法DoReadHeaders、DoReadBody分别来下载网页的header部分和body部分。
36. 我们先看看DoReadHeaders方法:该方法中有代码:stream_->ReadResponseHeaders(io_callback_);
37. 该方法调用websocket_basic_handshake_stream.cc文件中方法:ReadResponseHeaders.
该方法中有代码:int rv = parser()->ReadResponseHeaders
38. 上面调用的是文件:http_stream_parser.cc中,方法:ReadResponseHeaders。这里有通过一些列调用,执行本文件中方法:
DoReadHeaders()。通过Socket,将网页的header部分读取出来:
connection_->socket()
->Read(read_buf_.get(), read_buf_->RemainingCapacity(), io_callback_);