频道栏目
首页 > 程序开发 > 综合编程 > 其他综合 > 正文
chromium中FTP网络资源的加载
2016-08-18 09:42:02         来源:飞鸟的专栏  
收藏   我要投稿

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 peer) {
  GURL frame_origin;
  scoped_ptr 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,void>::Dispatch
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::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::Run
19 chrome_child!base::internal::InvokeHelper<1,void,base::internal::RunnableAdapter >::MakeItSo,base::TimeTicks const & __ptr64,bool const & __ptr64>
1a chrome_child!base::internal::Invoker,base::internal::BindState,void __cdecl(scheduler::TaskQueueManager * __ptr64,base::TimeTicks,bool),base::WeakPtr,base::TimeTicks,bool>,base::internal::InvokeHelper<1,void,base::internal::RunnableAdapter >,void __cdecl(void)>::Run
1b chrome_child!base::Callback::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,void>::Dispatch
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::Run
0c chrome_7feee760000!base::internal::InvokeHelper<1,void,base::internal::RunnableAdapter >::MakeItSo
0d chrome_7feee760000!base::internal::Invoker,base::internal::BindState,void __cdecl(extensions::NativeMessageProcessHost * __ptr64,int),base::WeakPtr >,base::internal::InvokeHelper<1,void,base::internal::RunnableAdapter >,void __cdecl(int const & __ptr64)>::Run
0e chrome_7feee760000!base::Callback > const &)>::Run
0f chrome_7feee760000!base::internal::InvokeHelper<0,void,base::Callback > const &)> >::MakeItSo
10 chrome_7feee760000!base::internal::Invoker,base::internal::BindState > const & __ptr64)>,void __cdecl(std::list > const & __ptr64),std::list > & __ptr64>,base::internal::InvokeHelper<0,void,base::Callback > const & __ptr64)> >,void __cdecl(void)>::Run
11 chrome_7feee760000!base::Callback::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::Run
09 chrome_7feee760000!base::internal::InvokeHelper<1,void,base::internal::RunnableAdapter >::MakeItSo
0a chrome_7feee760000!base::internal::Invoker,base::internal::BindState,void __cdecl(syncer_v2::SharedModelTypeProcessor * __ptr64),base::WeakPtr >,base::internal::InvokeHelper<1,void,base::internal::RunnableAdapter >,void __cdecl(void)>::Run
0b chrome_7feee760000!base::Callback::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 (https://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完成回调函数。

点击复制链接 与好友分享!回本站首页
相关TAG标签 网络资源
上一篇:SuperMap iObject常见问题解答集锦(九)
下一篇:Hadoop2.7.0学习——Windows下hadoop-eclipse-plugin-2.7.0插件使用
相关文章
图文推荐
点击排行

关于我们 | 联系我们 | 广告服务 | 投资合作 | 版权申明 | 在线帮助 | 网站地图 | 作品发布 | Vip技术培训 | 举报中心

版权所有: 红黑联盟--致力于做实用的IT技术学习网站