Cookies這部分的源碼位于net/cookies與net/extras中,代碼量不算多的,但是感覺其中有點(diǎn)細(xì)節(jié),如果不是結(jié)合著對應(yīng)的需求去看,確實(shí)沒辦法把所有細(xì)節(jié)都看透,所以就只看了一下大概的實(shí)現(xiàn)原理與基本流程。
本來是想放點(diǎn)基本介紹的,但是感覺太拖節(jié)奏了,而且應(yīng)該基本屬于常識,就不浪費(fèi)篇幅了。
同樣由于篇幅問題,就不放源碼了,不然就成了代碼縫里夾文字了。
0.代碼結(jié)構(gòu)
net::CanonicalCookie類存儲單條cookie,里面包含了key/value/domain/expire/priority等常見或不常見的字段。
cookies主體功能都在CookieMonster類中,實(shí)現(xiàn)了CookieStore接口,通過該接口與URLRequestJob等進(jìn)行交互。每個(gè)chrome用戶的cookie都是獨(dú)立的,實(shí)例地址保存在其Profile對應(yīng)的URLRequestContext中(此外,chrome-extension://有它自己的CookieMonster實(shí)例)。
cookies通過sqlite數(shù)據(jù)庫保存在本地,具體見net::SQLitePersistentCookieStore類。
其他net/cookies目錄下還有一堆輔助性質(zhì)的代碼。
1.CookieMonster
其實(shí)這個(gè)類主要實(shí)現(xiàn)的就是內(nèi)存中對cookie的增刪改查,最重要的就是GetCookieList與SetCookie的接口。為了不因?yàn)閿?shù)據(jù)庫的原因阻塞IO線程(或許還有其他的原因),跟cookie操作有關(guān)的對外接口都是異步的。
使用了std::multimap來存儲所有的cookie,其中map的key對應(yīng)的是網(wǎng)站的一級域名,例如sina.com.cn/baidu.com,value則是單條的cookie(CanonicalCookie);GetCookiesList的時(shí)候會先從URL解析出一級域名,從map中拿出所有相同域名的cookie再進(jìn)一步進(jìn)行過濾。
這里值得一提的就幾點(diǎn)吧:
1.對過期cookies的刪除(訪問時(shí)發(fā)現(xiàn)過期了再刪除,算是常規(guī)操作了吧,redis中也有類似的),不需要定時(shí)檢查有沒有過期了的需要清理的cookies;
2.cookie的加載,為了優(yōu)化第一個(gè)網(wǎng)頁的加載速度,cookies并不是在啟動(dòng)時(shí)一股腦的從數(shù)據(jù)庫里全部加載到內(nèi)存中的,而是依次加載各個(gè)一級域名的cookie,這樣先加載完畢的域名就可以先使用了。
3.cookie的GC,根據(jù)總cookie數(shù)、單域名cookie數(shù)、最后訪問時(shí)間、是否HTTPS、優(yōu)先級等進(jìn)行垃圾清理。每次SetCookie操作后會進(jìn)行。
2.數(shù)據(jù)庫
cookie數(shù)據(jù)庫就是user data中每個(gè)用戶對應(yīng)目錄下的cookies文件,可以隨便找個(gè)sqlite客戶端打開看看是啥樣子的,有個(gè)概念。當(dāng)然了win下是看不到值的,為了安全考慮,值進(jìn)行了加密處理。
代碼位于net/extras/sqlite/sqlite_persistent_cookie_store.cc,從IO線程過來的數(shù)據(jù)庫操作請求會投放到線程池中進(jìn)行處理,寫這坨東西屬于體力活,可以看的也就幾點(diǎn):
1.如何進(jìn)行分域名加載,上面說過;
2.批量操作優(yōu)化,將多個(gè)增刪改請求打包在同一個(gè)事務(wù)進(jìn)行處理;
3.cookie存儲時(shí)是如何加解密的;
3.其他
CookieMonsterChangeDispatcher,監(jiān)聽cookies改變,可以用于登錄監(jiān)聽;
third-party cookies機(jī)制,這個(gè)待后續(xù)研究;
如何解析出TLDs(Top level domain),這個(gè)是瀏覽器里有一個(gè)列表的;