chromium中HTTP網絡資源的加載過程

chromium中HTTP網絡資源的加載主要分兩部分,一部分是緩存的網絡資源,一部分是線上的網絡資源。

我們訪問http網頁的時候,首先訪問httpcache,看緩存中的數據是否有效,如果有效,那麼我們加載這個數據,如果無效,那麼我們訪問網絡去重新加載資源,當然chromium中HTTP網絡資源的加載並沒有說起來這麼簡單,實際上架構設計還是比較複雜的。首先我們先看看HttpCache::Transaction的相關設計及實現,研究一下緩存的處理。

HttpCache::Transaction

在源碼分析之前,我們先看一個小示例,從使用者的角度看看cache的使用過程,那麼就需要一個切入點。

情景分析

首先我們在windbg中啓動chromium,然後設置多進程調試。

0:000> .childdbg 1
Processes created by the current process will be debugged
0:000> g

運行後待程序穩定後,中斷到調試器,之後在主進程上下斷

0:011> bp chrome_7feed810000!net::HttpCache::Transaction::Start

之後運行起來,然後在瀏覽器的地址窗口中輸入一個字符“c”,這是我假定的設置的,因爲瀏覽器的地址窗口默認設置了百度的搜索引擎,當用戶輸入一個字符的時候會觸發一次搜索。而實際上確實是這樣。當輸入字符後,我的程序中斷了。

0:028> kc
 # Call Site
00 chrome_7feed810000!net::HttpCache::Transaction::Start
01 chrome_7feed810000!net::URLRequestHttpJob::StartTransactionInternal
02 chrome_7feed810000!net::URLRequestHttpJob::MaybeStartTransactionInternal
03 chrome_7feed810000!net::URLRequestHttpJob::StartTransaction
04 chrome_7feed810000!net::URLRequestHttpJob::SetCookieHeaderAndStart
05 chrome_7feed810000!base::internal::RunnableAdapter<void (__cdecl LocalDataContainer::*)(std::list<content::CacheStorageUsageInfo,std::allocator<content::CacheStorageUsageInfo> > const &)>::Run
06 chrome_7feed810000!base::internal::InvokeHelper<1,void,base::internal::RunnableAdapter<void (__cdecl LocalDataContainer::*)(std::list<content::CacheStorageUsageInfo,std::allocator<content::CacheStorageUsageInfo> > const &)> >::MakeItSo
07 chrome_7feed810000!base::internal::Invoker<base::IndexSequence<0>,base::internal::BindState<base::internal::RunnableAdapter<void (__cdecl LocalDataContainer::*)(std::list<content::CacheStorageUsageInfo,std::allocator<content::CacheStorageUsageInfo> > const & __ptr64) __ptr64>,void __cdecl(LocalDataContainer * __ptr64,std::list<content::CacheStorageUsageInfo,std::allocator<content::CacheStorageUsageInfo> > const & __ptr64),base::WeakPtr<LocalDataContainer> >,base::internal::InvokeHelper<1,void,base::internal::RunnableAdapter<void (__cdecl LocalDataContainer::*)(std::list<content::CacheStorageUsageInfo,std::allocator<content::CacheStorageUsageInfo> > const & __ptr64) __ptr64> >,void __cdecl(std::list<content::CacheStorageUsageInfo,std::allocator<content::CacheStorageUsageInfo> > const & __ptr64)>::Run
08 chrome_7feed810000!base::Callback<void __cdecl(void)>::Run
09 chrome_7feed810000!net::CookieMonster::CookieMonsterTask::InvokeCallback
0a chrome_7feed810000!net::CookieMonster::GetCookieListWithOptionsTask::Run
0b chrome_7feed810000!net::CookieMonster::DoCookieTaskForURL
0c chrome_7feed810000!net::CookieMonster::GetCookieListWithOptionsAsync
0d chrome_7feed810000!net::URLRequestHttpJob::AddCookieHeaderAndStart
0e chrome_7feed810000!net::URLRequestHttpJob::Start
0f chrome_7feed810000!net::URLRequest::StartJob
10 chrome_7feed810000!net::URLRequest::BeforeRequestComplete
11 chrome_7feed810000!net::URLRequest::Start
12 chrome_7feed810000!net::URLFetcherCore::StartURLRequest
13 chrome_7feed810000!net::URLFetcherCore::StartURLRequestWhenAppropriate
14 chrome_7feed810000!net::URLFetcherCore::DidInitializeWriter
15 chrome_7feed810000!net::URLFetcherCore::StartOnIOThread
16 chrome_7feed810000!base::Callback<void __cdecl(void)>::Run
17 chrome_7feed810000!base::debug::TaskAnnotator::RunTask
18 chrome_7feed810000!base::MessageLoop::RunTask
19 chrome_7feed810000!base::MessageLoop::DeferOrRunPendingTask
1a chrome_7feed810000!base::MessageLoop::DoWork
1b chrome_7feed810000!base::MessagePumpForIO::DoRunLoop
1c chrome_7feed810000!base::MessagePumpWin::Run
1d chrome_7feed810000!base::MessageLoop::RunHandler
1e chrome_7feed810000!base::RunLoop::Run
1f chrome_7feed810000!base::MessageLoop::Run
20 chrome_7feed810000!base::Thread::Run
21 chrome_7feed810000!content::BrowserThreadImpl::IOThreadRun
22 chrome_7feed810000!content::BrowserThreadImpl::Run
23 chrome_7feed810000!base::Thread::ThreadMain
24 chrome_7feed810000!base::`anonymous namespace'::ThreadFunc
25 kernel32!BaseThreadInitThunk
26 ntdll!RtlUserThreadStart

研究一下堆棧信息,其實就已經知道了大抵上的調用層次,這個請求的方式和我之前介紹過的chromium中FTP網絡資源的加載 文章中很相似。

在一個IO線程中啓動了URL的加載請求,這是一個內部請求,使用的是URLFetcherCore,然後啓動URLRequest,之後開啓一個特定的job,在這裏這個job是URLRequestHttpJob,之後啓動一個傳輸,而這個傳輸就是我們要說的HttpCache::Transaction,內部數據的請求基於HttpCache。

0:028> ~~[1244]s;.frame 0n0;dv /t /v
chrome_7feed810000!net::HttpCache::Transaction::Start:
000007fe`ee46c6e4 48895c2410      mov     qword ptr [rsp+10h],rbx ss:00000000`0961c408=0000000012695a60
00 00000000`0961c3f8 000007fe`ee4bf027 chrome_7feed810000!net::HttpCache::Transaction::Start [c:\b\build\slave\win64\build\src\net\http\http_cache_transaction.cc @ 254]
@rcx              class net::HttpCache::Transaction * this = 0x00000000`1269c170
@rdx              struct net::HttpRequestInfo * request = 0x00000000`12695c28
@r8               class base::Callback<void __cdecl(int)> * callback = 0x00000000`12695d40
@r9               class net::BoundNetLog * net_log = 0x00000000`12691ec8
<unavailable>     int rv = <value unavailable>
0:028> dx -id 0,0 -r1 (*((chrome_7feed810000!net::HttpRequestInfo *)0x12695c28))
(*((chrome_7feed810000!net::HttpRequestInfo *)0x12695c28))                 [Type: net::HttpRequestInfo]
    [+0x000] url              [Type: GURL]
    [+0x078] method           : "GET" [Type: std::basic_string<char,std::char_traits<char>,std::allocator<char> >]
    [+0x098] extra_headers    [Type: net::HttpRequestHeaders]
    [+0x0b0] upload_data_stream : 0x0 [Type: net::UploadDataStream *]
    [+0x0b8] load_flags       : 64
    [+0x0bc] motivation       : NORMAL_MOTIVATION (2) [Type: net::HttpRequestInfo::RequestMotivation]
    [+0x0c0] privacy_mode     : PRIVACY_MODE_DISABLED (0) [Type: net::PrivacyMode]
0:028> dx -id 0,0 -r1 (*((chrome_7feed810000!GURL *)0x12695c28))
(*((chrome_7feed810000!GURL *)0x12695c28))                 [Type: GURL]
    [+0x000] spec_            : "http://suggestion.baidu.com/su?wd=c&action=opensearch&ie=UTF-8" [Type: std::basic_string<char,std::char_traits<char>,std::allocator<char> >]
    [+0x020] is_valid_        : true
    [+0x028] parsed_          [Type: url::Parsed]
    [+0x070] inner_url_       [Type: scoped_ptr<GURL,std::default_delete<GURL> >]

接着,我們來看一下,當我們在瀏覽器中輸入一個字符的時候,瀏覽器的一個URL的請求過程,上面的網址就是要請求的URL,“http://suggestion.baidu.com/su?wd=c&action=opensearch&ie=UTF-8”,這是一個http GET命令。Opensearch 字符”c”.
當然,瀏覽器地址欄的結果數據的提供過程並不是我們討論的主題,我們是通過這個切入點去詳細瞭解其中一點,http網絡資源的加載過程。

源碼分析

HttpCache::Transaction::Start

上面我們看到了最後一個函數棧,是一個緩存傳輸啓動的過程,我們從這裏開始,已知的一點是我們向啓動函數中傳遞了請求信息,包含了URL和method。

int HttpCache::Transaction::Start(const HttpRequestInfo* request,
                                  const CompletionCallback& callback,
                                  const BoundNetLog& net_log) {
......

  if (!cache_.get())
    return ERR_UNEXPECTED;

  SetRequest(net_log, request);

  // We have to wait until the backend is initialized so we start the SM.
  next_state_ = STATE_GET_BACKEND;
  int rv = DoLoop(OK);

  // Setting this here allows us to check for the existence of a callback_ to
  // determine if we are still inside Start.
  if (rv == ERR_IO_PENDING)
    callback_ = callback;

  return rv;
}

我們來看一下源碼,這裏我們設置了下一跳狀態,然後啓動狀態機循環,這裏多少和FTP資源的加載有些相似,FTP的加載要較爲簡單些。

HttpCache::Transaction::State

  enum State {
    // Normally, states are traversed in approximately this order.
    STATE_NONE,
    STATE_GET_BACKEND,
    STATE_GET_BACKEND_COMPLETE,
    STATE_INIT_ENTRY,
    STATE_OPEN_ENTRY,
    STATE_OPEN_ENTRY_COMPLETE,
    STATE_DOOM_ENTRY,
    STATE_DOOM_ENTRY_COMPLETE,
    STATE_CREATE_ENTRY,
    STATE_CREATE_ENTRY_COMPLETE,
    STATE_ADD_TO_ENTRY,
    STATE_ADD_TO_ENTRY_COMPLETE,
    .....
    }

HttpCache的傳輸過程也是狀態改變的過程,狀態比較多,情況就比較多。
chromium源碼作者還是比較貼心的,在源碼狀態機循環函數前以註釋的方式列出了各種情況。

// 1. Not-cached entry:
//   Start():
//   GetBackend* -> InitEntry -> OpenEntry* -> CreateEntry* -> AddToEntry* ->
//   SendRequest* -> SuccessfulSendRequest -> OverwriteCachedResponse ->
//   CacheWriteResponse* -> TruncateCachedData* -> TruncateCachedMetadata* ->
//   PartialHeadersReceived
//
//   Read():
//   NetworkRead* -> CacheWriteData*
//
// 2. Cached entry, no validation:
//   Start():
//   GetBackend* -> InitEntry -> OpenEntry* -> AddToEntry* -> CacheReadResponse*
//   -> CacheDispatchValidation -> BeginPartialCacheValidation() ->
//   BeginCacheValidation() -> SetupEntryForRead()
//
//   Read():
//   CacheReadData*
//
// 3. Cached entry, validation (304):
//   Start():
//   GetBackend* -> InitEntry -> OpenEntry* -> AddToEntry* -> CacheReadResponse*
//   -> CacheDispatchValidation -> BeginPartialCacheValidation() ->
//   BeginCacheValidation() -> SendRequest* -> SuccessfulSendRequest ->
//   UpdateCachedResponse -> CacheWriteUpdatedResponse* ->
//   UpdateCachedResponseComplete -> OverwriteCachedResponse ->
//   PartialHeadersReceived
//
//   Read():
//   CacheReadData*
//
// 4. Cached entry, validation and replace (200):
//   Start():
//   GetBackend* -> InitEntry -> OpenEntry* -> AddToEntry* -> CacheReadResponse*
//   -> CacheDispatchValidation -> BeginPartialCacheValidation() ->
//   BeginCacheValidation() -> SendRequest* -> SuccessfulSendRequest ->
//   OverwriteCachedResponse -> CacheWriteResponse* -> DoTruncateCachedData* ->
//   TruncateCachedMetadata* -> PartialHeadersReceived
//
//   Read():
//   NetworkRead* -> CacheWriteData*
//
// 5. Sparse entry, partially cached, byte range request:
//   Start():
//   GetBackend* -> InitEntry -> OpenEntry* -> AddToEntry* -> CacheReadResponse*
//   -> CacheDispatchValidation -> BeginPartialCacheValidation() ->
//   CacheQueryData* -> ValidateEntryHeadersAndContinue() ->
//   StartPartialCacheValidation -> CompletePartialCacheValidation ->
//   BeginCacheValidation() -> SendRequest* -> SuccessfulSendRequest ->
//   UpdateCachedResponse -> CacheWriteUpdatedResponse* ->
//   UpdateCachedResponseComplete -> OverwriteCachedResponse ->
//   PartialHeadersReceived
//
//   Read() 1:
//   NetworkRead* -> CacheWriteData*
//
//   Read() 2:
//   NetworkRead* -> CacheWriteData* -> StartPartialCacheValidation ->
//   CompletePartialCacheValidation -> CacheReadData* ->
//
//   Read() 3:
//   CacheReadData* -> StartPartialCacheValidation ->
//   CompletePartialCacheValidation -> BeginCacheValidation() -> SendRequest* ->
//   SuccessfulSendRequest -> UpdateCachedResponse* -> OverwriteCachedResponse
//   -> PartialHeadersReceived -> NetworkRead* -> CacheWriteData*
//
// 6. HEAD. Not-cached entry:
//   Pass through. Don't save a HEAD by itself.
//   Start():
//   GetBackend* -> InitEntry -> OpenEntry* -> SendRequest*
//
// 7. HEAD. Cached entry, no validation:
//   Start():
//   The same flow as for a GET request (example #2)
//
//   Read():
//   CacheReadData (returns 0)
//
// 8. HEAD. Cached entry, validation (304):
//   The request updates the stored headers.
//   Start(): Same as for a GET request (example #3)
//
//   Read():
//   CacheReadData (returns 0)
//
// 9. HEAD. Cached entry, validation and replace (200):
//   Pass through. The request dooms the old entry, as a HEAD won't be stored by
//   itself.
//   Start():
//   GetBackend* -> InitEntry -> OpenEntry* -> AddToEntry* -> CacheReadResponse*
//   -> CacheDispatchValidation -> BeginPartialCacheValidation() ->
//   BeginCacheValidation() -> SendRequest* -> SuccessfulSendRequest ->
//   OverwriteCachedResponse
//
// 10. HEAD. Sparse entry, partially cached:
//   Serve the request from the cache, as long as it doesn't require
//   revalidation. Ignore missing ranges when deciding to revalidate. If the
//   entry requires revalidation, ignore the whole request and go to full pass
//   through (the result of the HEAD request will NOT update the entry).
//
//   Start(): Basically the same as example 7, as we never create a partial_
//   object for this request.
//
// 11. Prefetch, not-cached entry:
//   The same as example 1. The "unused_since_prefetch" bit is stored as true in
//   UpdateCachedResponse.
//
// 12. Prefetch, cached entry:
//   Like examples 2-4, only CacheToggleUnusedSincePrefetch* is inserted between
//   CacheReadResponse* and CacheDispatchValidation if the unused_since_prefetch
//   bit is unset.
//
// 13. Cached entry less than 5 minutes old, unused_since_prefetch is true:
//   Skip validation, similar to example 2.
//   GetBackend* -> InitEntry -> OpenEntry* -> AddToEntry* -> CacheReadResponse*
//   -> CacheToggleUnusedSincePrefetch* -> CacheDispatchValidation ->
//   BeginPartialCacheValidation() -> BeginCacheValidation() ->
//   SetupEntryForRead()
//
//   Read():
//   CacheReadData*
//
// 14. Cached entry more than 5 minutes old, unused_since_prefetch is true:
//   Like examples 2-4, only CacheToggleUnusedSincePrefetch* is inserted between
//   CacheReadResponse* and CacheDispatchValidation.

簡要看看,一般的緩存傳輸基本上都要經歷的過程是獲取Backend,然後初始化Entry,之後打開,然後從中加載進來,之後進行驗證,後面的過程就有些不一樣了。自然,從地址欄中輸入單個字符引發搜索,URL資源請求也就符合其中一種情況。

操作Backend準備Cache數據

base::WeakPtr<HttpCache> cache_;
int HttpCache::Transaction::DoGetBackend() {
  cache_pending_ = true;
  next_state_ = STATE_GET_BACKEND_COMPLETE;
  net_log_.BeginEvent(NetLog::TYPE_HTTP_CACHE_GET_BACKEND);
  return cache_->GetBackendForTransaction(this);
}
int HttpCache::Transaction::DoInitEntry() {
  DCHECK(!new_entry_);

  if (!cache_.get())
    return ERR_UNEXPECTED;

  if (mode_ == WRITE) {
    next_state_ = STATE_DOOM_ENTRY;
    return OK;
  }

  next_state_ = STATE_OPEN_ENTRY;
  return OK;
}
int HttpCache::Transaction::DoOpenEntry() {
  DCHECK(!new_entry_);
  next_state_ = STATE_OPEN_ENTRY_COMPLETE;
  cache_pending_ = true;
  net_log_.BeginEvent(NetLog::TYPE_HTTP_CACHE_OPEN_ENTRY);
  first_cache_access_since_ = TimeTicks::Now();
  return cache_->OpenEntry(cache_key_, &new_entry_, this);
}

Httpcache的傳輸實際上操作httpCache來完成具體的功能,做前期的準備工作,最後通過cache_key_,來查詢某一項。

[+0x3a0] cache_key_       : "http://suggestion.baidu.com/su?wd=c&action=opensearch&ie=UTF-8" 

這裏面的cache_key_其實就是URL,在HttpCache中URL唯一檢索資源,就是通過這個key值來找到對應的Entry。

int HttpCache::Transaction::DoAddToEntry() {
  DCHECK(new_entry_);
  cache_pending_ = true;
  next_state_ = STATE_ADD_TO_ENTRY_COMPLETE;
  net_log_.BeginEvent(NetLog::TYPE_HTTP_CACHE_ADD_TO_ENTRY);
  DCHECK(entry_lock_waiting_since_.is_null());
  entry_lock_waiting_since_ = TimeTicks::Now();
  int rv = cache_->AddTransactionToEntry(new_entry_, this);
  if (rv == ERR_IO_PENDING) {
    if (bypass_lock_for_test_) {
      OnAddToEntryTimeout(entry_lock_waiting_since_);
    } else {
      int timeout_milliseconds = 20 * 1000;
      if (partial_ && new_entry_->writer &&
          new_entry_->writer->range_requested_) {

        timeout_milliseconds = 25;
      }
      base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
          FROM_HERE,
          base::Bind(&HttpCache::Transaction::OnAddToEntryTimeout,
                     weak_factory_.GetWeakPtr(), entry_lock_waiting_since_),
          TimeDelta::FromMilliseconds(timeout_milliseconds));
    }
  }
  return rv;
}

當我們找到對應的項後,我們具體的加載這個項的數據,如果返回IO_PENDING,那麼設置超時回調函數。設置下一狀態爲STATE_ADD_TO_ENTRY_COMPLETE,在完成函數中,設置下一跳狀態,記錄處理時間。

HttpCache::Transaction Read Entry and validation

int HttpCache::Transaction::DoCacheReadResponse() {
  DCHECK(entry_);
  next_state_ = STATE_CACHE_READ_RESPONSE_COMPLETE;

  io_buf_len_ = entry_->disk_entry->GetDataSize(kResponseInfoIndex);
  read_buf_ = new IOBuffer(io_buf_len_);

  net_log_.BeginEvent(NetLog::TYPE_HTTP_CACHE_READ_INFO);
  return entry_->disk_entry->ReadData(kResponseInfoIndex, 0, read_buf_.get(),
                                      io_buf_len_, io_callback_);
}

當一切都準備完成後,開始從緩存中讀取數據,函數中設置下一跳,然後從entry中獲取到緩存的大小,申請空間,之後操作entry來讀取數據。

int HttpCache::Transaction::DoCacheDispatchValidation() {
  int result = ERR_FAILED;
  switch (mode_) {
    case READ:
      UpdateTransactionPattern(PATTERN_ENTRY_USED);
      result = BeginCacheRead();
      break;
    case READ_WRITE:
      result = BeginPartialCacheValidation();
      break;
    case UPDATE:
      result = BeginExternallyConditionalizedRequest();
      break;
    case WRITE:
    default:
      NOTREACHED();
  }
  return result;
}

當我們讀取完數據後,就開始了驗證數據的過程。這裏是個讀寫的情況。在派發驗證的過程中,跳過了驗證,符合上面的情況2,Cached entry, no validation。

HttpCache::Transaction 數據讀取

當我們準備cache,操作並查找到對應的項,然後讀取項,之後判斷是否驗證項,如果這都通過了之後,下層會通知上層來提取數據。

0:026> kc
 # Call Site
00 chrome_7feed900000!net::HttpCache::Transaction::DoCacheReadData
01 chrome_7feed900000!net::HttpCache::Transaction::DoLoop
02 chrome_7feed900000!net::HttpCache::Transaction::Read
03 chrome_7feed900000!net::URLRequestHttpJob::ReadRawData
04 chrome_7feed900000!net::URLRequestJob::ReadRawDataHelper
05 chrome_7feed900000!net::URLRequestJob::Read
06 chrome_7feed900000!net::URLRequest::Read
07 chrome_7feed900000!net::URLFetcherCore::ReadResponse
08 chrome_7feed900000!net::URLFetcherCore::OnResponseStarted
09 chrome_7feed900000!net::URLRequest::NotifyResponseStarted
0a chrome_7feed900000!net::URLRequestJob::NotifyHeadersComplete
0b chrome_7feed900000!net::URLRequestHttpJob::NotifyHeadersComplete
0c chrome_7feed900000!net::URLRequestHttpJob::SaveCookiesAndNotifyHeadersComplete
0d chrome_7feed900000!net::URLRequestHttpJob::OnStartCompleted
0e chrome_7feed900000!base::Callback<void __cdecl(int)>::Run
0f chrome_7feed900000!net::HttpCache::Transaction::DoLoop
10 chrome_7feed900000!base::internal::RunnableAdapter<void (__cdecl extensions::NativeMessageProcessHost::*)(int)>::Run
11 chrome_7feed900000!base::internal::InvokeHelper<1,void,base::internal::RunnableAdapter<void (__cdecl extensions::NativeMessageProcessHost::*)(int)> >::MakeItSo
12 chrome_7feed900000!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
13 chrome_7feed900000!base::Callback<void __cdecl(int)>::Run
14 chrome_7feed900000!disk_cache::InFlightBackendIO::OnOperationComplete
15 chrome_7feed900000!disk_cache::BackgroundIO::OnIOSignalled
16 chrome_7feed900000!base::Callback<void __cdecl(void)>::Run
17 chrome_7feed900000!base::debug::TaskAnnotator::RunTask
18 chrome_7feed900000!base::MessageLoop::RunTask
19 chrome_7feed900000!base::MessageLoop::DeferOrRunPendingTask
1a chrome_7feed900000!base::MessageLoop::DoWork
1b chrome_7feed900000!base::MessagePumpForIO::DoRunLoop
1c chrome_7feed900000!base::MessagePumpWin::Run
1d chrome_7feed900000!base::MessageLoop::RunHandler
1e chrome_7feed900000!base::RunLoop::Run
1f chrome_7feed900000!base::MessageLoop::Run
20 chrome_7feed900000!base::Thread::Run
21 chrome_7feed900000!content::BrowserThreadImpl::IOThreadRun
22 chrome_7feed900000!content::BrowserThreadImpl::Run
23 chrome_7feed900000!base::Thread::ThreadMain
24 chrome_7feed900000!base::`anonymous namespace'::ThreadFunc
25 kernel32!BaseThreadInitThunk
26 ntdll!RtlUserThreadStart

disk_cache 是HttpCache實際存儲在硬盤上的數據組織結構,當完成後通知URLRequestHttpJob啓動完成,然後再通過HttpCache進行讀取數據。

int HttpCache::Transaction::DoCacheReadData() {
  if (request_->method == "HEAD")
    return 0;

  DCHECK(entry_);
  next_state_ = STATE_CACHE_READ_DATA_COMPLETE;

  if (net_log_.IsCapturing())
    net_log_.BeginEvent(NetLog::TYPE_HTTP_CACHE_READ_DATA);
  if (partial_) {
    return partial_->CacheRead(entry_->disk_entry, read_buf_.get(), io_buf_len_,
                               io_callback_);
  }

  return entry_->disk_entry->ReadData(kResponseContentIndex, read_offset_,
                                      read_buf_.get(), io_buf_len_,
                                      io_callback_);
}

而數據的讀取操作的實際處理也是通過disk_cache進行實際的數據處理,這裏HttpCache做中間的一個傳輸的過程。

HttpCache::Transaction 小結

這裏簡要介紹了HttpCache的傳輸過程,僅介紹了其中的一種情況(Cached entry, no validation ),當我們在地址欄中輸入字符的時候,會觸發一個URL的請求,而這個請求事先也是要通過HttpCache的傳輸的,請求去查詢cache中的項,然後讀取出來,在驗證的時候跳過了驗證機制,之後開始讀取實際的數據,完成數據的傳輸。

HttpNetworkTransaction

上面我們分析了HttpCache的傳輸方式,如果HttpCache中沒有我們要查閱的數據呢,因爲我們要訪問的是一個我們從沒有訪問過的URL,又或者我們訪問的cache數據已經失效了,那麼怎麼辦呢,此時就要通過網絡來加載數據,需要通過http網絡傳輸來完成具體的數據加載。

情景分析

現假設我們訪問chromium中FTP網絡資源的加載 這篇文章,我的HttpCache中並沒有這個URL相關的信息,我們可以在瀏覽器的地址欄中輸入chrome://cache/ 來看HttpCache的存儲情況。
我們沒有這個緩存,目前我們符合上面的情況一,當我們檢索cache後發現沒有數據,那麼我們要啓動網絡傳輸的請求。

0:026> kc
 # Call Site
00 chrome_7feed900000!net::HttpNetworkTransaction::Start
01 chrome_7feed900000!DevToolsNetworkTransaction::Start
02 chrome_7feed900000!net::HttpCache::Transaction::DoSendRequest
03 chrome_7feed900000!net::HttpCache::Transaction::DoLoop
04 chrome_7feed900000!base::internal::RunnableAdapter<void (__cdecl extensions::NativeMessageProcessHost::*)(int)>::Run
05 chrome_7feed900000!base::internal::InvokeHelper<1,void,base::internal::RunnableAdapter<void (__cdecl extensions::NativeMessageProcessHost::*)(int)> >::MakeItSo
06 chrome_7feed900000!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
07 chrome_7feed900000!base::Callback<void __cdecl(int)>::Run
08 chrome_7feed900000!net::HttpCache::WorkItem::NotifyTransaction
09 chrome_7feed900000!net::HttpCache::OnIOComplete
0a chrome_7feed900000!net::HttpCache::OnPendingOpComplete
0b chrome_7feed900000!base::Callback<void __cdecl(int)>::Run
0c chrome_7feed900000!disk_cache::InFlightBackendIO::OnOperationComplete
0d chrome_7feed900000!disk_cache::BackgroundIO::OnIOSignalled
0e chrome_7feed900000!base::Callback<void __cdecl(void)>::Run
0f chrome_7feed900000!base::debug::TaskAnnotator::RunTask
10 chrome_7feed900000!base::MessageLoop::RunTask
11 chrome_7feed900000!base::MessageLoop::DeferOrRunPendingTask
12 chrome_7feed900000!base::MessageLoop::DoWork
13 chrome_7feed900000!base::MessagePumpForIO::DoRunLoop
14 chrome_7feed900000!base::MessagePumpWin::Run
15 chrome_7feed900000!base::MessageLoop::RunHandler
16 chrome_7feed900000!base::RunLoop::Run
17 chrome_7feed900000!base::MessageLoop::Run
18 chrome_7feed900000!base::Thread::Run
19 chrome_7feed900000!content::BrowserThreadImpl::IOThreadRun
1a chrome_7feed900000!content::BrowserThreadImpl::Run
1b chrome_7feed900000!base::Thread::ThreadMain
1c chrome_7feed900000!base::`anonymous namespace'::ThreadFunc
1d kernel32!BaseThreadInitThunk
1e ntdll!RtlUserThreadStart

我們看一下局部變量信息,看看運行時的狀態

0:026> ~~[10c4]s;.frame 0n0;dv /t /v
chrome_7feed900000!net::HttpNetworkTransaction::Start:
000007fe`ee58d66c 48895c2410      mov     qword ptr [rsp+10h],rbx ss:00000000`0914e158=000000000aec6610
00 00000000`0914e148 000007fe`ee28f812 chrome_7feed900000!net::HttpNetworkTransaction::Start [c:\b\build\slave\win64\build\src\net\http\http_network_transaction.cc @ 191]
@rcx              class net::HttpNetworkTransaction * this = 0x00000000`11a21640
@rdx              struct net::HttpRequestInfo * request_info = 0x00000000`0aac8ff8
@r8               class base::Callback<void __cdecl(int)> * callback = 0x00000000`11d18b80
@r9               class net::BoundNetLog * net_log = 0x00000000`11d187a0
<unavailable>     int rv = <value unavailable>
0:026> dx -id 0,0 -r1 (*((chrome_7feed900000!net::HttpRequestInfo *)0xaac8ff8))
(*((chrome_7feed900000!net::HttpRequestInfo *)0xaac8ff8))                 [Type: net::HttpRequestInfo]
    [+0x000] url              [Type: GURL]
    [+0x078] method           : "GET" [Type: std::basic_string<char,std::char_traits<char>,std::allocator<char> >]
    [+0x098] extra_headers    [Type: net::HttpRequestHeaders]
    [+0x0b0] upload_data_stream : 0x0 [Type: net::UploadDataStream *]
    [+0x0b8] load_flags       : 4352
    [+0x0bc] motivation       : NORMAL_MOTIVATION (2) [Type: net::HttpRequestInfo::RequestMotivation]
    [+0x0c0] privacy_mode     : PRIVACY_MODE_DISABLED (0) [Type: net::PrivacyMode]
0:026> dx -id 0,0 -r1 (*((chrome_7feed900000!GURL *)0xaac8ff8))
(*((chrome_7feed900000!GURL *)0xaac8ff8))                 [Type: GURL]
    [+0x000] spec_            : "http://blog.csdn.net/feiniao251314/article/details/52230012" [Type: std::basic_string<char,std::char_traits<char>,std::allocator<char> >]
    [+0x020] is_valid_        : true
    [+0x028] parsed_          [Type: url::Parsed]
    [+0x070] inner_url_       [Type: scoped_ptr<GURL,std::default_delete<GURL> >]

在cache中沒有找到URL相關的資源,那麼我們將請求信息傳遞到HttpNetworkTransaction中,試圖通過網絡來請求數據。

源碼分析

在源碼分析之前,我們看一下HttpNetworkTransaction的狀態,根據狀態,我們大體上就能瞭解網絡HttpNetworkTransaction要處理的網絡情況

HttpNetworkTransaction::State

  enum State {
    STATE_NOTIFY_BEFORE_CREATE_STREAM,
    STATE_CREATE_STREAM,
    STATE_CREATE_STREAM_COMPLETE,
    STATE_INIT_STREAM,
    STATE_INIT_STREAM_COMPLETE,
    STATE_GENERATE_PROXY_AUTH_TOKEN,
    STATE_GENERATE_PROXY_AUTH_TOKEN_COMPLETE,
    STATE_GENERATE_SERVER_AUTH_TOKEN,
    STATE_GENERATE_SERVER_AUTH_TOKEN_COMPLETE,
    STATE_GET_TOKEN_BINDING_KEY,
    STATE_GET_TOKEN_BINDING_KEY_COMPLETE,
    STATE_INIT_REQUEST_BODY,
    STATE_INIT_REQUEST_BODY_COMPLETE,
    STATE_BUILD_REQUEST,
    STATE_BUILD_REQUEST_COMPLETE,
    STATE_SEND_REQUEST,
    STATE_SEND_REQUEST_COMPLETE,
    STATE_READ_HEADERS,
    STATE_READ_HEADERS_COMPLETE,
    STATE_READ_BODY,
    STATE_READ_BODY_COMPLETE,
    STATE_DRAIN_BODY_FOR_AUTH_RESTART,
    STATE_DRAIN_BODY_FOR_AUTH_RESTART_COMPLETE,
    STATE_NONE
  };

狀態要比HttpCache要少許多,和ftp網絡傳輸狀態相當。分創建,初始化,生成key,初始化請求,建立請求,發送請求,讀取請求等等。我們從中簡要分析其中的過程。

啓動與初始化

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

.......
  next_state_ = STATE_NOTIFY_BEFORE_CREATE_STREAM;
  int rv = DoLoop(OK);
  if (rv == ERR_IO_PENDING)
    callback_ = callback;
  return rv;
}

int HttpNetworkTransaction::DoNotifyBeforeCreateStream() {
  next_state_ = STATE_CREATE_STREAM;
  bool defer = false;
  if (!before_network_start_callback_.is_null())
    before_network_start_callback_.Run(&defer);
  if (!defer)
    return OK;
  return ERR_IO_PENDING;
}

int HttpNetworkTransaction::DoCreateStream() {
  // TODO(mmenke): Remove ScopedTracker below once crbug.com/424359 is fixed.
  tracked_objects::ScopedTracker tracking_profile(
      FROM_HERE_WITH_EXPLICIT_FUNCTION(
          "424359 HttpNetworkTransaction::DoCreateStream"));

  response_.network_accessed = true;

  next_state_ = STATE_CREATE_STREAM_COMPLETE;
  if (ForWebSocketHandshake()) {
    stream_request_.reset(
        session_->http_stream_factory_for_websocket()
            ->RequestWebSocketHandshakeStream(
                  *request_,
                  priority_,
                  server_ssl_config_,
                  proxy_ssl_config_,
                  this,
                  websocket_handshake_stream_base_create_helper_,
                  net_log_));
  } else {
    stream_request_.reset(
        session_->http_stream_factory()->RequestStream(
            *request_,
            priority_,
            server_ssl_config_,
            proxy_ssl_config_,
            this,
            net_log_));
  }
  DCHECK(stream_request_.get());
  return ERR_IO_PENDING;
}

創建比較簡單,使用會話session_來創建一個請求Stream,內部創建了socket,我們暫且不向下深挖,暫時先分析http這一層次的傳輸過程,下面給出創建socket的堆棧示意:

0:026> kc
 # Call Site
00 chrome_7feed900000!net::CreatePlatformSocket
01 chrome_7feed900000!net::UDPSocketWin::Open
02 chrome_7feed900000!net::UDPClientSocket::Connect
03 chrome_7feed900000!net::`anonymous namespace'::IsGloballyReachable
04 chrome_7feed900000!net::HostResolverImpl::IsIPv6Reachable
05 chrome_7feed900000!net::HostResolverImpl::GetEffectiveKeyForRequest
06 chrome_7feed900000!net::HostResolverImpl::Resolve
07 chrome_7feed900000!net::SingleRequestHostResolver::Resolve
08 chrome_7feed900000!net::TransportConnectJobHelper::DoResolveHost
09 chrome_7feed900000!net::TransportConnectJob::DoResolveHost
0a chrome_7feed900000!net::TransportConnectJobHelper::DoLoop<net::TransportConnectJob>
0b chrome_7feed900000!net::ConnectJob::Connect
0c chrome_7feed900000!net::internal::ClientSocketPoolBaseHelper::RequestSocketInternal
0d chrome_7feed900000!net::internal::ClientSocketPoolBaseHelper::RequestSocket
0e chrome_7feed900000!net::ClientSocketPoolBase<net::TransportSocketParams>::RequestSocket
0f chrome_7feed900000!net::ClientSocketHandle::Init<net::SSLClientSocketPool>
10 chrome_7feed900000!net::`anonymous namespace'::InitSocketPoolHelper
11 chrome_7feed900000!net::InitSocketHandleForHttpRequest
12 chrome_7feed900000!net::HttpStreamFactoryImpl::Job::DoInitConnection
13 chrome_7feed900000!net::HttpStreamFactoryImpl::Job::DoLoop
14 chrome_7feed900000!net::HttpStreamFactoryImpl::Job::RunLoop
15 chrome_7feed900000!net::HttpStreamFactoryImpl::RequestStreamInternal
16 chrome_7feed900000!net::HttpStreamFactoryImpl::RequestStream
17 chrome_7feed900000!net::HttpNetworkTransaction::DoCreateStream
18 chrome_7feed900000!net::HttpNetworkTransaction::DoLoop
19 chrome_7feed900000!net::HttpNetworkTransaction::Start
1a chrome_7feed900000!DevToolsNetworkTransaction::Start
1b chrome_7feed900000!net::HttpCache::Transaction::DoSendRequest
1c chrome_7feed900000!net::HttpCache::Transaction::DoLoop
1d chrome_7feed900000!base::internal::RunnableAdapter<void (__cdecl extensions::NativeMessageProcessHost::*)(int)>::Run
1e chrome_7feed900000!base::internal::InvokeHelper<1,void,base::internal::RunnableAdapter<void (__cdecl extensions::NativeMessageProcessHost::*)(int)> >::MakeItSo
1f chrome_7feed900000!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
20 chrome_7feed900000!base::Callback<void __cdecl(int)>::Run
21 chrome_7feed900000!net::HttpCache::WorkItem::NotifyTransaction
22 chrome_7feed900000!net::HttpCache::OnIOComplete
23 chrome_7feed900000!net::HttpCache::OnPendingOpComplete
24 chrome_7feed900000!base::Callback<void __cdecl(int)>::Run
25 chrome_7feed900000!disk_cache::InFlightBackendIO::OnOperationComplete
26 chrome_7feed900000!disk_cache::BackgroundIO::OnIOSignalled
27 chrome_7feed900000!base::Callback<void __cdecl(void)>::Run
28 chrome_7feed900000!base::debug::TaskAnnotator::RunTask
29 chrome_7feed900000!base::MessageLoop::RunTask
2a chrome_7feed900000!base::MessageLoop::DeferOrRunPendingTask
2b chrome_7feed900000!base::MessageLoop::DoWork
2c chrome_7feed900000!base::MessagePumpForIO::DoRunLoop
2d chrome_7feed900000!base::MessagePumpWin::Run
2e chrome_7feed900000!base::MessageLoop::RunHandler
2f chrome_7feed900000!base::RunLoop::Run
30 chrome_7feed900000!base::MessageLoop::Run
31 chrome_7feed900000!base::Thread::Run
32 chrome_7feed900000!content::BrowserThreadImpl::IOThreadRun
33 chrome_7feed900000!content::BrowserThreadImpl::Run
34 chrome_7feed900000!base::Thread::ThreadMain
35 chrome_7feed900000!base::`anonymous namespace'::ThreadFunc
36 kernel32!BaseThreadInitThunk
37 ntdll!RtlUserThreadStart
int HttpNetworkTransaction::DoInitStream() {
  DCHECK(stream_.get());
  next_state_ = STATE_INIT_STREAM_COMPLETE;

  stream_->GetRemoteEndpoint(&remote_endpoint_);

  return stream_->InitializeStream(request_, priority_, net_log_, io_callback_);
}

創建請求完成後,初始化Stream,然後生成服務器和客戶端的Token.

發送請求

int HttpNetworkTransaction::DoSendRequest() {
  // TODO(mmenke): Remove ScopedTracker below once crbug.com/424359 is fixed.
  tracked_objects::ScopedTracker tracking_profile(
      FROM_HERE_WITH_EXPLICIT_FUNCTION(
          "424359 HttpNetworkTransaction::DoSendRequest"));

  send_start_time_ = base::TimeTicks::Now();
  next_state_ = STATE_SEND_REQUEST_COMPLETE;

  return stream_->SendRequest(request_headers_, &response_, io_callback_);
}

這裏我們可以查看一下request_headers_的相關信息,目前是connection請求。

0:025> dx -id 0,0 -r1 (*((chrome_7fee4550000!net::HttpRequestHeaders::HeaderKeyValuePair *)0x114f49e0))
(*((chrome_7fee4550000!net::HttpRequestHeaders::HeaderKeyValuePair *)0x114f49e0))                 [Type: net::HttpRequestHeaders::HeaderKeyValuePair]
    [+0x000] key              : "Host" [Type: std::basic_string<char,std::char_traits<char>,std::allocator<char> >]
    [+0x020] value            : "blog.csdn.net" [Type: std::basic_string<char,std::char_traits<char>,std::allocator<char> >]
0:025> dx -id 0,0 -r1 (*((chrome_7fee4550000!net::HttpRequestHeaders::HeaderKeyValuePair *)0x114f4a20))
(*((chrome_7fee4550000!net::HttpRequestHeaders::HeaderKeyValuePair *)0x114f4a20))                 [Type: net::HttpRequestHeaders::HeaderKeyValuePair]
    [+0x000] key              : "Connection" [Type: std::basic_string<char,std::char_traits<char>,std::allocator<char> >]
    [+0x020] value            : "keep-alive" [Type: std::basic_string<char,std::char_traits<char>,std::allocator<char> >]
0:025> dx -id 0,0 -r1 (*((chrome_7fee4550000!net::HttpRequestHeaders::HeaderKeyValuePair *)0x114f4a60))
(*((chrome_7fee4550000!net::HttpRequestHeaders::HeaderKeyValuePair *)0x114f4a60))                 [Type: net::HttpRequestHeaders::HeaderKeyValuePair]
    [+0x000] key              : "Accept" [Type: std::basic_string<char,std::char_traits<char>,std::allocator<char> >]
    [+0x020] value            : "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8" [Type: std::basic_string<char,std::char_traits<char>,std::allocator<char> >]

接收數據

int HttpNetworkTransaction::DoSendRequestComplete(int result) {
  send_end_time_ = base::TimeTicks::Now();
  if (result < 0)
    return HandleIOError(result);
  next_state_ = STATE_READ_HEADERS;
  return OK;
}

int HttpNetworkTransaction::DoReadHeaders() {
  next_state_ = STATE_READ_HEADERS_COMPLETE;
  return stream_->ReadResponseHeaders(io_callback_);
}

當發送請求完成後,會設置下一跳狀態爲讀取頭部狀態,然後返回狀態循環,開始讀取頭部信息。

HttpNetworkTransaction 小結

當在HttpCache中無法獲取到有效信息的時候,那麼就會生成一個HttpNetworkTransaction請求,通過網絡來請求最新數據,HttpNetworkTransaction負責建立連接,初始化終端,發送和接收數據,將數據組織好。

網絡請求結果的轉儲

上面我們說了HttpCache::transaction和HttpNetworkTransaction的情況,一個是本地緩存傳輸,一個是網絡數據傳輸,當本地數據無效的時候,會請求網絡傳輸,而當網絡傳輸完畢的時候會通知本地緩存處理。

情景分析

我們可以如下下斷

0:025> bp chrome_7fee4550000!net::HttpCache::Transaction::DoSuccessfulSendRequest

這樣,當HttpNetworkTransaction傳輸完成的時候,會中斷到調試器,這樣跟蹤一下,看看實際的運行過程。
下面是堆棧示意。

0:025> kc
 # Call Site
00 chrome_7fee4550000!net::HttpCache::Transaction::DoSuccessfulSendRequest
01 chrome_7fee4550000!net::HttpCache::Transaction::DoLoop
02 chrome_7fee4550000!base::internal::RunnableAdapter<void (__cdecl extensions::NativeMessageProcessHost::*)(int)>::Run
03 chrome_7fee4550000!base::internal::InvokeHelper<1,void,base::internal::RunnableAdapter<void (__cdecl extensions::NativeMessageProcessHost::*)(int)> >::MakeItSo
04 chrome_7fee4550000!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
05 chrome_7fee4550000!base::Callback<void __cdecl(int)>::Run
06 chrome_7fee4550000!net::HttpNetworkTransaction::DoCallback
07 chrome_7fee4550000!net::HttpNetworkTransaction::OnIOComplete
08 chrome_7fee4550000!net::HttpNetworkTransaction::OnStreamReady
09 chrome_7fee4550000!net::HttpStreamFactoryImpl::Job::OnStreamReadyCallback
0a chrome_7fee4550000!base::internal::RunnableAdapter<void (__cdecl browser_sync::BookmarkModelAssociator::*)(void)>::Run
0b chrome_7fee4550000!base::internal::InvokeHelper<1,void,base::internal::RunnableAdapter<void (__cdecl browser_sync::BookmarkModelAssociator::*)(void)> >::MakeItSo
0c chrome_7fee4550000!base::internal::Invoker<base::IndexSequence<0>,base::internal::BindState<base::internal::RunnableAdapter<void (__cdecl browser_sync::BookmarkModelAssociator::*)(void) __ptr64>,void __cdecl(browser_sync::BookmarkModelAssociator * __ptr64),base::WeakPtr<browser_sync::BookmarkModelAssociator> >,base::internal::InvokeHelper<1,void,base::internal::RunnableAdapter<void (__cdecl browser_sync::BookmarkModelAssociator::*)(void) __ptr64> >,void __cdecl(void)>::Run
0d chrome_7fee4550000!base::Callback<void __cdecl(void)>::Run
0e chrome_7fee4550000!base::debug::TaskAnnotator::RunTask
0f chrome_7fee4550000!base::MessageLoop::RunTask
10 chrome_7fee4550000!base::MessageLoop::DeferOrRunPendingTask
11 chrome_7fee4550000!base::MessageLoop::DoWork
12 chrome_7fee4550000!base::MessagePumpForIO::DoRunLoop
13 chrome_7fee4550000!base::MessagePumpWin::Run
14 chrome_7fee4550000!base::MessageLoop::RunHandler
15 chrome_7fee4550000!base::RunLoop::Run
16 chrome_7fee4550000!base::MessageLoop::Run
17 chrome_7fee4550000!base::Thread::Run
18 chrome_7fee4550000!content::BrowserThreadImpl::IOThreadRun
19 chrome_7fee4550000!content::BrowserThreadImpl::Run
1a chrome_7fee4550000!base::Thread::ThreadMain
1b chrome_7fee4550000!base::`anonymous namespace'::ThreadFunc
1c kernel32!BaseThreadInitThunk
1d ntdll!RtlUserThreadStart

在HttpNetworkTransaction完成的時候會調用callback,這個是在啓動HttpNetworkTransaction請求的時候設置的,完成時回調到HttpCache::transaction,進行數據的轉儲處理。

源碼分析

調用過程

// 1. Not-cached entry:
//   Start():
//   GetBackend* -> InitEntry -> OpenEntry* -> CreateEntry* -> AddToEntry* ->
//   SendRequest* -> SuccessfulSendRequest -> OverwriteCachedResponse ->
//   CacheWriteResponse* -> TruncateCachedData* -> TruncateCachedMetadata* ->
//   PartialHeadersReceived
//
//   Read():
//   NetworkRead* -> CacheWriteData*

我們回顧一下情況一,如上,我們收到了HttpNetworkTransaction請求完成後,會重寫緩存,但是我們的緩存中並沒有這一項,就沒有實際的重寫操作,而是進行下一狀態,STATE_CACHE_WRITE_RESPONSE.

int HttpCache::Transaction::DoCacheWriteResponse() {
  next_state_ = STATE_CACHE_WRITE_RESPONSE_COMPLETE;
  return WriteResponseInfoToEntry(truncated_);
}

這一狀態的處理就是實際的寫響應信息到HttpCache的Entry中。


int HttpCache::Transaction::WriteResponseInfoToEntry(bool truncated) {
  if (!entry_)
    return OK;
......
  bool skip_transient_headers = true;
  scoped_refptr<PickledIOBuffer> data(new PickledIOBuffer());
  response_.Persist(data->pickle(), skip_transient_headers, truncated);
  data->Done();

  io_buf_len_ = data->pickle()->size();
  return entry_->disk_entry->WriteData(kResponseInfoIndex, 0, data.get(),
                                       io_buf_len_, io_callback_, true);
}

在這個函數中實際的寫數據操作通過Entry來實現,將數據寫到disk_cache中。

轉儲小結

就是這樣,當HttpCache中沒有有效數據的時候,就通過HttpNetworkTransaction請求網絡數據,當網絡數據請求完畢時,回調到HttpCache::transaction中將數據存儲到HttpCache中,以便下次讀取。

樣本的版本信息

chrome 50.0.2661.87

符號路徑:
https://chromium-browser-symsrv.commondatastorage.googleapis.com

源碼網站:
www.chromium.org

感謝chromium項目相關作者及人員。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章