您的位置:首页 > 理论基础 > 计算机网络

chromium中FTP网络资源的加载

2016-08-17 13:04 363 查看

FTP网络资源的加载

render进程的处理

我们在浏览器地址中输入ftp://ftp.sjtu.edu.cn/,来请求ftp数据。

此时windbg会中断,因为浏览器启动了一个render进程来渲染绘制。我们在render进程中如下下断

bu chrome_child!content::ResourceDispatcher::StartAsync


这个函数由render进程调用,用来和browser进程通信,通知browser来加载网络资源

int ResourceDispatcher::StartAsync(const RequestInfo& request_info,
ResourceRequestBody* request_body,
scoped_ptr<RequestPeer> peer) {
GURL frame_origin;
scoped_ptr<ResourceHostMsg_Request> request =
CreateRequest(request_info, request_body, &frame_origin);

// Compute a unique request_id for this renderer process.
int request_id = MakeRequestID();
pending_requests_[request_id] = make_scoped_ptr(new PendingRequestInfo(
std::move(peer), request->resource_type, request->origin_pid,
frame_origin, request->url, request_info.download_to_file));

if (resource_scheduling_filter_.get() &&
request_info.loading_web_task_runner) {
resource_scheduling_filter_->SetRequestIdTaskRunner(
request_id,
make_scoped_ptr(request_info.loading_web_task_runner->clone()));
}

message_sender_->Send(new ResourceHostMsg_RequestResource(
request_info.routing_id, request_id, *request));

return request_id;
}


通知browser进程的消息是ResourceHostMsg_RequestResource,我们来看一下render进程的调用情况

8:010> kc
# Call Site
00 chrome_child!content::ResourceDispatcher::StartAsync
01 chrome_child!content::WebURLLoaderImpl::Context::Start
02 chrome_child!blink::ResourceLoader::start
03 chrome_child!blink::Resource::load
04 chrome_child!blink::ResourceFetcher::requestResource
05 chrome_child!blink::RawResource::fetchMainResource
06 chrome_child!blink::DocumentLoader::startLoadingMainResource
07 chrome_child!blink::FrameLoader::startLoad
08 chrome_child!blink::FrameLoader::load
09 chrome_child!blink::WebLocalFrameImpl::load
0a chrome_child!content::RenderFrameImpl::NavigateInternal
0b chrome_child!content::RenderFrameImpl::OnNavigate
0c chrome_child!base::DispatchToMethodImpl
0d chrome_child!base::DispatchToMethod
0e chrome_child!IPC::DispatchToMethod
0f chrome_child!IPC::MessageT<FrameMsg_Navigate_Meta,std::tuple<content::CommonNavigationParams,content::StartNavigationParams,content::RequestNavigationParams>,void>::Dispatch<content::RenderFrameImpl,content::RenderFrameImpl,void,void (__cdecl content::RenderFrameImpl::*)(content::CommonNavigationParams const & __ptr64,content::StartNavigationParams const & __ptr64,content::RequestNavigationParams const & __ptr64) __ptr64>
10 chrome_child!content::RenderFrameImpl::OnMessageReceived
11 chrome_child!IPC::MessageRouter::RouteMessage
12 chrome_child!content::ChildThreadImpl::OnMessageReceived
13 chrome_child!IPC::ChannelProxy::Context::OnDispatchMessage
14 chrome_child!base::Callback<void __cdecl(void)>::Run
15 chrome_child!base::debug::TaskAnnotator::RunTask
16 chrome_child!scheduler::TaskQueueManager::ProcessTaskFromWorkQueue
17 chrome_child!scheduler::TaskQueueManager::DoWork
18 chrome_child!base::internal::RunnableAdapter<void (__cdecl scheduler::TaskQueueManager::*)(base::TimeTicks,bool)>::Run
19 chrome_child!base::internal::InvokeHelper<1,void,base::internal::RunnableAdapter<void (__cdecl scheduler::TaskQueueManager::*)(base::TimeTicks,bool) __ptr64> >::MakeItSo<base::WeakPtr<scheduler::TaskQueueManager>,base::TimeTicks const & __ptr64,bool const & __ptr64>
1a chrome_child!base::internal::Invoker<base::IndexSequence<0,1,2>,base::internal::BindState<base::internal::RunnableAdapter<void (__cdecl scheduler::TaskQueueManager::*)(base::TimeTicks,bool) __ptr64>,void __cdecl(scheduler::TaskQueueManager * __ptr64,base::TimeTicks,bool),base::WeakPtr<scheduler::TaskQueueManager>,base::TimeTicks,bool>,base::internal::InvokeHelper<1,void,base::internal::RunnableAdapter<void (__cdecl scheduler::TaskQueueManager::*)(base::TimeTicks,bool) __ptr64> >,void __cdecl(void)>::Run
1b chrome_child!base::Callback<void __cdecl(void)>::Run
1c chrome_child!base::debug::TaskAnnotator::RunTask
1d chrome_child!base::MessageLoop::RunTask
1e chrome_child!base::MessageLoop::DeferOrRunPendingTask
1f chrome_child!base::MessageLoop::DoWork
20 chrome_child!base::MessagePumpDefault::Run
21 chrome_child!base::MessageLoop::RunHandler
22 chrome_child!base::RunLoop::Run
23 chrome_child!base::MessageLoop::Run
24 chrome_child!content::RendererMain
25 chrome_child!content::RunNamedProcessTypeMain
26 chrome_child!content::ContentMainRunnerImpl::Run
27 chrome_child!content::ContentMain
28 chrome_child!ChromeMain
29 chrome!MainDllLoader::Launch
2a chrome!wWinMain
2b chrome!__tmainCRTStartup
2c kernel32!BaseThreadInitThunk
2d ntdll!RtlUserThreadStart


从上面可以看出,这是通过blink模块进行资源加载,而实际的任务通过browser进程。

browser进程的处理

ResourceLoader

我们到browser进程中的相应函数中下断,看看browser如何进行实际的资源加载和网络访问的。

bp chrome_7feee760000!content::ResourceDispatcherHostImpl::OnRequestResource


下断后,运行,中断。

0:019> kc
# Call Site
00 chrome_7feee760000!content::ResourceLoader::StartRequest
01 chrome_7feee760000!content::ResourceDispatcherHostImpl::StartLoading
02 chrome_7feee760000!content::ResourceDispatcherHostImpl::BeginRequestInternal
03 chrome_7feee760000!content::ResourceDispatcherHostImpl::BeginRequest
04 chrome_7feee760000!content::ResourceDispatcherHostImpl::OnRequestResource
05 chrome_7feee760000!base::DispatchToMethodImpl
06 chrome_7feee760000!base::DispatchToMethod
07 chrome_7feee760000!IPC::DispatchToMethod
08 chrome_7feee760000!IPC::MessageT<ResourceHostMsg_RequestResource_Meta,std::tuple<int,int,ResourceHostMsg_Request>,void>::Dispatch<content::ResourceDispatcherHostImpl,content::ResourceDispatcherHostImpl,void,void (__cdecl content::ResourceDispatcherHostImpl::*)(int,int,ResourceHostMsg_Request const & __ptr64) __ptr64>
09 chrome_7feee760000!content::ResourceDispatcherHostImpl::OnMessageReceived
0a chrome_7feee760000!content::BrowserMessageFilter::Internal::DispatchMessageW
0b chrome_7feee760000!content::BrowserMessageFilter::Internal::OnMessageReceived
0c chrome_7feee760000!IPC::`anonymous namespace'::TryFiltersImpl
0d chrome_7feee760000!IPC::MessageFilterRouter::TryFilters
0e chrome_7feee760000!IPC::ChannelProxy::Context::TryFilters
0f chrome_7feee760000!IPC::ChannelProxy::Context::OnMessageReceived
10 chrome_7feee760000!IPC::internal::ChannelReader::DispatchMessageW
11 chrome_7feee760000!IPC::internal::ChannelReader::HandleExternalMessage
12 chrome_7feee760000!IPC::internal::ChannelReader::HandleTranslatedMessage
13 chrome_7feee760000!IPC::internal::ChannelReader::TranslateInputData
14 chrome_7feee760000!IPC::internal::ChannelReader::AsyncReadComplete
15 chrome_7feee760000!IPC::ChannelWin::OnIOCompleted
16 chrome_7feee760000!base::MessagePumpForIO::WaitForIOCompletion
17 chrome_7feee760000!base::MessagePumpForIO::DoRunLoop
18 chrome_7feee760000!base::MessagePumpWin::Run
19 chrome_7feee760000!base::MessageLoop::RunHandler
1a chrome_7feee760000!base::RunLoop::Run
1b chrome_7feee760000!base::MessageLoop::Run
1c chrome_7feee760000!base::Thread::Run
1d chrome_7feee760000!content::BrowserThreadImpl::IOThreadRun
1e chrome_7feee760000!content::BrowserThreadImpl::Run
1f chrome_7feee760000!base::Thread::ThreadMain
20 chrome_7feee760000!base::`anonymous namespace'::ThreadFunc
21 kernel32!BaseThreadInitThunk
22 ntdll!RtlUserThreadStart


如上的堆栈示意,这是位于IO线程中,通过IPC的完成端口接收到来自render进程的消息,然后分发这个消息,遇到了浏览器的BrowserMessageFilter,将消息分发到ResourceDispatcherHostImpl来专门的处理这个消息,ResourceDispatcherHostImpl进一步的通过ResourceLoader来加载资源。

void ResourceLoader::StartRequest() {
if (delegate_->HandleExternalProtocol(this, request_->url())) {
CancelAndIgnore();
return;
}

// Give the handler a chance to delay the URLRequest from being started.
bool defer_start = false;
if (!handler_->OnWillStart(request_->url(), &defer_start)) {
Cancel();
return;
}

if (defer_start) {
deferred_stage_ = DEFERRED_START;
} else {
StartRequestInternal();
}
}


在ResourceLoader中有个延迟启动的策略,我们这个情况下就是延迟启动的。

URLRequest

不过无论是延迟启动还是正常的启动都是要创建URLrequest的。如下下断:

bp chrome_7feee760000!net::URLRequestFtpJob::Start


我们是个ftp协议,针对的是ftp的URLRequestFtpJob进行特殊的处理。

0:019> kc
# Call Site
00 chrome_7feee760000!net::FtpNetworkTransaction::Start
01 chrome_7feee760000!net::URLRequestFtpJob::StartFtpTransaction
02 chrome_7feee760000!net::URLRequestFtpJob::OnResolveProxyComplete
03 chrome_7feee760000!net::URLRequestFtpJob::Start
04 chrome_7feee760000!net::URLRequest::StartJob
05 chrome_7feee760000!net::URLRequest::BeforeRequestComplete
06 chrome_7feee760000!net::URLRequest::Start
07 chrome_7feee760000!content::ResourceLoader::StartRequestInternal
08 chrome_7feee760000!content::ResourceLoader::Resume
09 chrome_7feee760000!content::ThrottlingResourceHandler::ResumeStart
0a chrome_7feee760000!content::ThrottlingResourceHandler::Resume
0b chrome_7feee760000!base::internal::RunnableAdapter<void (__cdecl extensions::NativeMessageProcessHost::*)(int)>::Run
0c chrome_7feee760000!base::internal::InvokeHelper<1,void,base::internal::RunnableAdapter<void (__cdecl extensions::NativeMessageProcessHost::*)(int)> >::MakeItSo
0d chrome_7feee760000!base::internal::Invoker<base::IndexSequence<0>,base::internal::BindState<base::internal::RunnableAdapter<void (__cdecl extensions::NativeMessageProcessHost::*)(int) __ptr64>,void __cdecl(extensions::NativeMessageProcessHost * __ptr64,int),base::WeakPtr<extensions::NativeMessageProcessHost> >,base::internal::InvokeHelper<1,void,base::internal::RunnableAdapter<void (__cdecl extensions::NativeMessageProcessHost::*)(int) __ptr64> >,void __cdecl(int const & __ptr64)>::Run
0e chrome_7feee760000!base::Callback<void __cdecl(std::list<content::IndexedDBInfo,std::allocator<content::IndexedDBInfo> > const &)>::Run
0f chrome_7feee760000!base::internal::InvokeHelper<0,void,base::Callback<void __cdecl(std::list<content::IndexedDBInfo,std::allocator<content::IndexedDBInfo> > const &)> >::MakeItSo
10 chrome_7feee760000!base::internal::Invoker<base::IndexSequence<0>,base::internal::BindState<base::Callback<void __cdecl(std::list<content::IndexedDBInfo,std::allocator<content::IndexedDBInfo> > const & __ptr64)>,void __cdecl(std::list<content::IndexedDBInfo,std::allocator<content::IndexedDBInfo> > const & __ptr64),std::list<content::IndexedDBInfo,std::allocator<content::IndexedDBInfo> > & __ptr64>,base::internal::InvokeHelper<0,void,base::Callback<void __cdecl(std::list<content::IndexedDBInfo,std::allocator<content::IndexedDBInfo> > const & __ptr64)> >,void __cdecl(void)>::Run
11 chrome_7feee760000!base::Callback<void __cdecl(void)>::Run
12 chrome_7feee760000!base::debug::TaskAnnotator::RunTask
13 chrome_7feee760000!base::MessageLoop::RunTask
14 chrome_7feee760000!base::MessageLoop::DeferOrRunPendingTask
15 chrome_7feee760000!base::MessageLoop::DoWork
16 chrome_7feee760000!base::MessagePumpForIO::DoRunLoop
17 chrome_7feee760000!base::MessagePumpWin::Run
18 chrome_7feee760000!base::MessageLoop::RunHandler
19 chrome_7feee760000!base::RunLoop::Run
1a chrome_7feee760000!base::MessageLoop::Run
1b chrome_7feee760000!base::Thread::Run
1c chrome_7feee760000!content::BrowserThreadImpl::IOThreadRun
1d chrome_7feee760000!content::BrowserThreadImpl::Run
1e chrome_7feee760000!base::Thread::ThreadMain
1f chrome_7feee760000!base::`anonymous namespace'::ThreadFunc
20 kernel32!BaseThreadInitThunk
21 ntdll!RtlUserThreadStart


当URLRequest处理过后,会启动一个针对ftp的URLRequestFtpJob来继续处理,后者启动ftp的网络传输FtpNetworkTransaction。

void URLRequestFtpJob::StartFtpTransaction() {
// Create a transaction.
DCHECK(!ftp_transaction_);

ftp_request_info_.url = request_->url();
ftp_transaction_ = ftp_transaction_factory_->CreateTransaction();

int rv;
if (ftp_transaction_) {
rv = ftp_transaction_->Start(
&ftp_request_info_,
base::Bind(&URLRequestFtpJob::OnStartCompleted,
base::Unretained(this)),
request_->net_log());
if (rv == ERR_IO_PENDING)
return;
} else {
rv = ERR_FAILED;
}
// The transaction started synchronously, but we need to notify the
// URLRequest delegate via the message loop.
OnStartCompletedAsync(rv);
}


FtpNetworkTransaction

资源加载的启动过程

job启动ftp传输的时候,先使用ftp_transaction_factory_来创建一个网络传输。而这个成员变量是在创建URLRequestFtpJob的时候就传递了数据,传递者是URLRequest。

int FtpNetworkTransaction::Start(const FtpRequestInfo* request_info,
const CompletionCallback& callback,
const BoundNetLog& net_log) {
net_log_ = net_log;
request_ = request_info;

ctrl_response_buffer_.reset(new FtpCtrlResponseBuffer(net_log_));

if (request_->url.has_username()) {
base::string16 username;
base::string16 password;
GetIdentityFromURL(request_->url, &username, &password);
credentials_.Set(username, password);
} else {
credentials_.Set(base::ASCIIToUTF16("anonymous"),
base::ASCIIToUTF16("chrome@example.com"));
}

DetectTypecode();

next_state_ = STATE_CTRL_RESOLVE_HOST;
int rv = DoLoop(OK);
if (rv == ERR_IO_PENDING)
user_callback_ = callback;
return rv;
}


当网络传输创建完成后悔启动这个网络传输,设置用户名和密码,然后设置传输状态,首先就是要解析主机地址,设置状态为STATE_CTRL_RESOLVE_HOST,,进入状态循环处理函数。

FTP所要处理的状态如下:

enum State {
// Control connection states:
STATE_CTRL_RESOLVE_HOST,
STATE_CTRL_RESOLVE_HOST_COMPLETE,
STATE_CTRL_CONNECT,
STATE_CTRL_CONNECT_COMPLETE,
STATE_CTRL_READ,
STATE_CTRL_READ_COMPLETE,
STATE_CTRL_WRITE,
STATE_CTRL_WRITE_COMPLETE,
STATE_CTRL_WRITE_USER,
STATE_CTRL_WRITE_PASS,
STATE_CTRL_WRITE_SYST,
STATE_CTRL_WRITE_TYPE,
STATE_CTRL_WRITE_EPSV,
STATE_CTRL_WRITE_PASV,
STATE_CTRL_WRITE_PWD,
STATE_CTRL_WRITE_RETR,
STATE_CTRL_WRITE_SIZE,
STATE_CTRL_WRITE_CWD,
STATE_CTRL_WRITE_LIST,
STATE_CTRL_WRITE_QUIT,
// Data connection states:
STATE_DATA_CONNECT,
STATE_DATA_CONNECT_COMPLETE,
STATE_DATA_READ,
STATE_DATA_READ_COMPLETE,
STATE_NONE
};


分控制连接状态和数据连接状态,我们接触了第一个状态就是解析主机的状态,我们看这些状态,还有的状态是完成状态,当一种控制或数据完成后会设置一个完成状态,在完成状态的处理函数中进行必要的处理。

int FtpNetworkTransaction::DoLoop(int result) {
DCHECK(next_state_ != STATE_NONE);

int rv = result;
do {
State state = next_state_;
next_state_ = STATE_NONE;
switch (state) {
case STATE_CTRL_RESOLVE_HOST:
DCHECK(rv == OK);
rv = DoCtrlResolveHost();
break;
case STATE_CTRL_RESOLVE_HOST_COMPLETE:
rv = DoCtrlResolveHostComplete(rv);
break;
......

}
} while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE);
return rv;
}


而状态循环的函数是DoLoop,仿佛状态机的处理函数,我们当前的状态是解析主机状态,自然我们进入的函数是DoCtrlResolveHost。

int FtpNetworkTransaction::DoCtrlResolveHost() {
next_state_ = STATE_CTRL_RESOLVE_HOST_COMPLETE;

HostResolver::RequestInfo info(HostPortPair::FromURL(request_->url));
// No known referrer.
return resolver_.Resolve(
info,
DEFAULT_PRIORITY,
&addresses_,
base::Bind(&FtpNetworkTransaction::OnIOComplete, base::Unretained(this)),
net_log_);
}


函数中首先设置了下一跳状态为STATE_CTRL_RESOLVE_HOST_COMPLETE,然后使用resolver来解析主机地址,并设置了回调函数。我们在回调函数上下断。

void FtpNetworkTransaction::OnIOComplete(int result) {
int rv = DoLoop(result);
if (rv != ERR_IO_PENDING)
DoCallback(rv);
}
int FtpNetworkTransaction::DoCtrlResolveHostComplete(int result) {
if (result == OK)
next_state_ = STATE_CTRL_CONNECT;
return result;
}


当地址解析完成后,调用IO完成回调函数,函数中继续进行循环处理,处理下一状态,在解析主机完成函数中设置状态为控制连接状态,开始准备连接。

int FtpNetworkTransaction::DoCtrlConnect() {
next_state_ = STATE_CTRL_CONNECT_COMPLETE;
ctrl_socket_ = socket_factory_->CreateTransportClientSocket(
addresses_, net_log_.net_log(), net_log_.source());
net_log_.AddEvent(
NetLog::TYPE_FTP_CONTROL_CONNECTION,
ctrl_socket_->NetLog().source().ToEventParametersCallback());
return ctrl_socket_->Connect(io_callback_);
}


连接状态中创建传输客户端socket,这是一个控制socket,然后使用这个socket来连接主机,并设置连接完成回调。

当连接完成后会交互一些命令,就是上面的一列状态的处理。

当控制连接建立完成后,会建立数据连接,都这一切都准备好了之后,上层会调用读取操作。

资源加载的读取过程

启动完成后,ResourceLoader会进行持续的读取操作。

0:019> kc
# Call Site
00 chrome_7feee760000!net::FtpNetworkTransaction::Read
01 chrome_7feee760000!net::URLRequestFtpJob::ReadRawData
02 chrome_7feee760000!net::URLRequestJob::ReadRawDataHelper
03 chrome_7feee760000!net::URLRequestJob::Read
04 chrome_7feee760000!net::URLRequest::Read
05 chrome_7feee760000!content::ResourceLoader::ReadMore
06 chrome_7feee760000!content::ResourceLoader::StartReading
07 chrome_7feee760000!content::ResourceLoader::ResumeReading
08 chrome_7feee760000!base::internal::RunnableAdapter<void (__cdecl syncer_v2::SharedModelTypeProcessor::*)(void)>::Run
09 chrome_7feee760000!base::internal::InvokeHelper<1,void,base::internal::RunnableAdapter<void (__cdecl syncer_v2::SharedModelTypeProcessor::*)(void)> >::MakeItSo
0a chrome_7feee760000!base::internal::Invoker<base::IndexSequence<0>,base::internal::BindState<base::internal::RunnableAdapter<void (__cdecl syncer_v2::SharedModelTypeProcessor::*)(void) __ptr64>,void __cdecl(syncer_v2::SharedModelTypeProcessor * __ptr64),base::WeakPtr<syncer_v2::SharedModelTypeProcessor> >,base::internal::InvokeHelper<1,void,base::internal::RunnableAdapter<void (__cdecl syncer_v2::SharedModelTypeProcessor::*)(void) __ptr64> >,void __cdecl(void)>::Run
0b chrome_7feee760000!base::Callback<void __cdecl(void)>::Run
0c chrome_7feee760000!base::debug::TaskAnnotator::RunTask
0d chrome_7feee760000!base::MessageLoop::RunTask
0e chrome_7feee760000!base::MessageLoop::DeferOrRunPendingTask
0f chrome_7feee760000!base::MessageLoop::DoWork
10 chrome_7feee760000!base::MessagePumpForIO::DoRunLoop
11 chrome_7feee760000!base::MessagePumpWin::Run
12 chrome_7feee760000!base::MessageLoop::RunHandler
13 chrome_7feee760000!base::RunLoop::Run
14 chrome_7feee760000!base::MessageLoop::Run
15 chrome_7feee760000!base::Thread::Run
16 chrome_7feee760000!content::BrowserThreadImpl::IOThreadRun
17 chrome_7feee760000!content::BrowserThreadImpl::Run
18 chrome_7feee760000!base::Thread::ThreadMain
19 chrome_7feee760000!base::`anonymous namespace'::ThreadFunc
1a kernel32!BaseThreadInitThunk
1b ntdll!RtlUserThreadStart


int FtpNetworkTransaction::Read(IOBuffer* buf,
int buf_len,
const CompletionCallback& callback) {
DCHECK(buf);
DCHECK_GT(buf_len, 0);

read_data_buf_ = buf;
read_data_buf_len_ = buf_len;

next_state_ = STATE_DATA_READ;
int rv = DoLoop(OK);
if (rv == ERR_IO_PENDING)
user_callback_ = callback;
return rv;
}


函数中设置了状态,进入状态循环函数,处理数据读取。

int FtpNetworkTransaction::DoDataRead() {
DCHECK(read_data_buf_.get());
DCHECK_GT(read_data_buf_len_, 0);

if (data_socket_ == NULL || !data_socket_->IsConnected()) {
// If we don't destroy the data socket completely, some servers will wait
// for us (http://crbug.com/21127). The half-closed TCP connection needs
// to be closed on our side too.
data_socket_.reset();

if (ctrl_socket_->IsConnected()) {
// Wait for the server's response, we should get it before sending QUIT.
next_state_ = STATE_CTRL_READ;
return OK;
}

// We are no longer connected to the server, so just finish the transaction.
return Stop(OK);
}

next_state_ = STATE_DATA_READ_COMPLETE;
read_data_buf_->data()[0] = 0;
return data_socket_->Read(
read_data_buf_.get(), read_data_buf_len_, io_callback_);
}

int FtpNetworkTransaction::DoDataReadComplete(int result) {
return result;
}


数据读取函数使用data_socket进行读取,并设置了IO完成回调函数。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息