Cronet http-header相关逻辑梳理

背景

本章梳理Cronet对于http header的处理逻辑。包含Android & iOS两个平台。

梳理结论

在Cronet里针对常见http header做的处理,梳理结果如下。
其中分为多个级别。P0代表最高优先级,以及P1、P2,优先级随着降低,Cronet会按照最高优先级逐级判断是否满足,并执行响应的操作。

iTerm iOS Android 备注
Referer P0:用户
P1:默认不会设置
P2:如果发生Redirect,如果用户set过,还是以用户为准,否则为空
无法设置

原因是只能通过URLRequest.cc中的setReferrer来设置Referer,手动在header中set会被扔掉,除非像iOS那样做了转换(header->setReferrer)
如果用户set的Referer不符合GURL规则, 则会被扔掉,相当于没set
User-Agent 忽略用户set header,使用默认UA P0:用户
P1:系统默认值
Accept P0:用户
P1:默认为*/*
P0:用户
无默认值
Cookie Network_delegate配置 P0:只有用户手动set header才生效
Host P0:首次请求以用户为准(如果用户set了),Redirect以跳转后的host为准

P1:如用户未设置,默认取当前的hostname
同iOS
Accept-Encoding P0:用户
P1:默认为gzip, deflate
同iOS
其他 P0:用户
P1:某些条件成立才会有默认值,否则无该字段
同iOS 例如:Transfer-Encoding

Content-Length

Pragma

Cache-Control

代码分析

我在这里分为适配层 和 native层。

  • 适配层主要是与平台相关的代码和对上层接口。
  • native层为主要实现逻辑。

适配层

适配层 - iOS端

设置header

1
2
3
4
5
6
7
8
9
// 初始header来源于用户设置NSURLRequest,这里就不细讲了
// crn_http_protocol_handle.mm
void HttpProtocolHandlerCore::Start(id<CRNNetworkClientProtocol> base_client) {
//...
    net_request_ = context->CreateRequest(url, DEFAULT_PRIORITY, this).release();
    // 将NSURLSession中的header copy 到 URLRequest中去
    CopyHttpHeaders(request_, net_request_);
//...
}

iOS拷贝header至native层

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
// 实际上调用的是protocol_handle_util.mm 中的 CopyHttpHeaders方法
// protocol_handle_util.mm
void CopyHttpHeaders(NSURLRequest* in_request, URLRequest* out_request) {
DCHECK(out_request->extra_request_headers().IsEmpty());
NSDictionary* headers = [in_request allHTTPHeaderFields];
HttpRequestHeaders net_headers;
NSString* key;
for (key in headers) {
// 如果是Referer,转化为SetReferrer方法,因为直接放在header中会被抹掉,底下代码会讲到,Android就没有做这种转化,所以Referer在Android是失效的
if ([key isEqualToString:@"Referer"]) {
// The referrer must be set through the set_referrer method rather than as
// a header.
out_request->SetReferrer(
base::SysNSStringToUTF8([headers objectForKey:key]));
// If the referrer is explicitly set, we don't want the network stack to
// strip it.
out_request->set_referrer_policy(URLRequest::NEVER_CLEAR_REFERRER);
continue;
}
// (Baidu Modified)
// Use custom User-Agent set from user.
// Refer to iCafe:mobi-lib-1403.
// 原生处理是扔掉用户set的User-Agent,我们改为以用户set的为准
// if (![key isEqualToString:@"User-Agent"]) {
// The user agent string is added by the network stack, and might be
// different from the one provided by UIWebView. Do not copy it.
// (Baidu Deleted End)
NSString* value = [headers objectForKey:key];
net_headers.SetHeader(base::SysNSStringToUTF8(key),
base::SysNSStringToUTF8(value));
// (Baidu Modified End)
}
// Set default values for some missing headers.
// The "Accept" header is defined by Webkit on the desktop version.
// 如果用户没有set Accept,则设置默认值,Android没有默认值
net_headers.SetHeaderIfMissing("Accept", "*/*");
// The custom NSURLProtocol example from Apple adds a default "Content-Type"
// header for non-empty POST requests. This suggests that this header can be
// missing, and Chrome network stack does not add it by itself.
if (out_request->has_upload() && out_request->method() == "POST") {
DLOG_IF(WARNING, !net_headers.HasHeader(HttpRequestHeaders::kContentType))
<< "Missing \"Content-Type\" header in POST request.";
net_headers.SetHeaderIfMissing(HttpRequestHeaders::kContentType,
"application/x-www-form-urlencoded");
}
// 将处理过的header set进url_request中去
out_request->SetExtraRequestHeaders(net_headers);
}

iOS对全局header的设置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
// 对User-Agent有全局默认设置
void CronetEngine::InitializeOnNetworkThread() {
// 对于webview请求,获取webview的标准user-agent(eg. Mozilla5.0/xxx).
std::string webview_ua = web::BuildUserAgentFromProduct(std::string(""));
// 如果user_agent_partial为真(通过setUserAgent接口的第二个参数设置),则将用户setUserAgent的第一个参数Append到默认UA中
if (user_agent_partial()) {
// 对于普通请求把cpu和os info 增添到用户穿进来的UA中
user_agent_.append(std::string(" ") + web::BuildOSCpuInfo());
// 对于webview请求,在默认webview的UA上添加用户传进来的UA
webview_ua = web::BuildUserAgentFromProduct(user_agent_);
} else if (user_agent_.empty()) {
// If user has not set any User-Agent, using the default User-Agent.
// Get appName and version from Info.plist that makes the User-Agent
// standardized.
// These codes refer to AFNetworking/3.1.0.
// 如果用户没有调用过setUserAgent,则我们构造出一个 AppName + cpu_os_info的UA出来
NSString *appName = nil;
appName = [NSString stringWithFormat:@"%@/%@ ",[[NSBundle mainBundle]
infoDictionary][(__bridge NSString *)kCFBundleExecutableKey] ?:
[[NSBundle mainBundle] infoDictionary][(__bridge NSString *)
kCFBundleIdentifierKey], [[NSBundle mainBundle] infoDictionary]
[@"CFBundleShortVersionString"] ?: [[NSBundle mainBundle]
infoDictionary][(__bridge NSString *)kCFBundleVersionKey]];
user_agent_ = base::SysNSStringToUTF8(appName) + web::BuildOSCpuInfo();
}
// If it is Webview, we use custom User-Agent set from user firstly.
// 如果用户自定义了webveiw的UA,则使用用户的,否则把TurboNet的UA写进NSUserDefaults
if ([[NSUserDefaults standardUserDefaults] objectForKey:@"UserAgent"] == nil) {
// Set the user agent through NSUserDefaults. This sets it for both
// UIWebView and WkWebViews, and javascript calls to navigator.userAgent
// returns this value.
[[NSUserDefaults standardUserDefaults] registerDefaults:@{
@"UserAgent" : [NSString stringWithUTF8String:webview_ua.c_str()]
}];
}
// ...
// User Agent.
// 将user_agent_设置到了native层的context中去了,在native层的应用下面会讲
context_builder.set_user_agent(user_agent());
}

iOS 对cookie的处理逻辑

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 对cookie存储有一些配置
// turbonet_engine.mm
void TurboNetEngine::InitializeOnNetworkThread() {
// 注释也讲到了,在Android里是关闭CookieStore的
// 在iOS中,CookieStore是把response中set-cookie携带的值写进了NSHTTPCookieStorage,下次请求时会尝试从里面读出来作为cookie
// 要使用CookieStore还需要NetworkDelegate中的开关是打开的,下面会讲
// In Android, disable net::CookieStore and net::ChannelIDService.
// context_builder.SetCookieAndChannelIdStores(nullptr, nullptr);
// Cookies and ChannelID. iOS needs cookie in WebView.
cookie_store_ = net::CookieStoreIOS::CreateCookieStore(
[NSHTTPCookieStorage sharedHTTPCookieStorage]);
channel_id_service_ = base::WrapUnique(
new net::ChannelIDService(new net::DefaultChannelIDStore(nullptr),
base::WorkerPool::GetTaskRunner(true)));
cookie_store_->SetChannelIDServiceID(channel_id_service_->GetUniqueID());
context_builder.SetCookieAndChannelIdStores(std::move(cookie_store_),
std::move(channel_id_service_));
}

适配层 - Android
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
// CrontUrlRequest.java
@Override
// 适配层提供的header设置方法,由CronetUrlRequest类的mRequestHeaders存储
public void addHeader(String header, String value) {
checkNotStarted();
if (header == null) {
throw new NullPointerException("Invalid header name.");
}
if (value == null) {
throw new NullPointerException("Invalid header value.");
}
mRequestHeaders.add(new AbstractMap.SimpleImmutableEntry<String, String>(header, value));
}
@Override
// 调用request的start时,会将mRequestHeaders copy到native层去
public void start() {
for (Map.Entry<String, String> header : mRequestHeaders) {
if (header.getKey().equalsIgnoreCase("Content-Type")
&& !header.getValue().isEmpty()) {
hasContentType = true;
}
if (!nativeAddRequestHeader(
mUrlRequestAdapter, header.getKey(), header.getValue())) {
throw new IllegalArgumentException(
"Invalid header " + header.getKey() + "=" + header.getValue());
}
}
}

Android将header拷贝至native层

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
//cronet_url_request_adapter.cc
// 在native的adapter类中,把java传下来的header 存储在了 initial_request_headers_
jboolean CronetURLRequestAdapter::AddRequestHeader(
JNIEnv* env,
const JavaParamRef<jobject>& jcaller,
const JavaParamRef<jstring>& jname,
const JavaParamRef<jstring>& jvalue) {
DCHECK(!context_->IsOnNetworkThread());
std::string name(base::android::ConvertJavaStringToUTF8(env, jname));
std::string value(base::android::ConvertJavaStringToUTF8(env, jvalue));
if (!net::HttpUtil::IsValidHeaderName(name) ||
!net::HttpUtil::IsValidHeaderValue(value)) {
return JNI_FALSE;
}
// Limit the size of hostname in request Header
const size_t max_host_length = 4096;
if (base::LowerCaseEqualsASCII(name, "host")) {
std::string host;
base::TrimWhitespaceASCII(value, base::TRIM_ALL, &host);
if (host.size() > max_host_length || !IsValidHost(host)) {
return JNI_FALSE;
} else {
initial_request_headers_.SetHeader(name, host);
return JNI_TRUE;
}
}
initial_request_headers_.SetHeader(name, value);
return JNI_TRUE;
}
// 在start的时候,把initial_request_headers_塞进了url_request中,至此,跟iOS中的实现都走向了最后同一目标
void CronetURLRequestAdapter::StartOnNetworkThread() {
url_request_->SetExtraRequestHeaders(initial_request_headers_);
}

Android对User-Agent的特别设置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
// 对User-Agent有全局默认设置
// CronetEngine.java
// 用户传入自定义的UA
public Builder setUserAgent(String userAgent) {
mUserAgent = userAgent;
return this;
}
// 取系统默认的UA,只在用户没有设置自定义UA才生效
public String getDefaultUserAgent() {
return UserAgent.from(mContext);
}
// 在engine进行创建的时候,对默认UA进行设置,如果存在用户自定义的,优先设置用户自定义的,否则取系统默认值
public CronetEngine build() {
if (getUserAgent() == null) {
setUserAgent(getDefaultUserAgent());
}
//...
}
// CronetUrlRequestContext.java
// 在cronetEngine的集成类中把默认的UserAgent设置到了UrlRequestContextConfig中(只有Android有config)
static long createNativeUrlRequestContextConfig(
final Context context, CronetEngine.Builder builder) {
final long urlRequestContextConfig = nativeCreateRequestContextConfig(
builder.getUserAgent(), builder.storagePath(), builder.quicEnabled(),
builder.getDefaultQuicUserAgentId(context), builder.http2Enabled(),
builder.sdchEnabled(), builder.dataReductionProxyKey(),
builder.dataReductionProxyPrimaryProxy(), builder.dataReductionProxyFallbackProxy(),
builder.dataReductionProxySecureProxyCheckUrl(), builder.cacheDisabled(),
builder.httpCacheMode(), builder.httpCacheMaxSize(), builder.experimentalOptions(),
builder.mockCertVerifier(), builder.networkQualityEstimatorEnabled());
//...
}
// url_request_context_config.cc
// 在URLRequestContextConfig中会将默认UA进一步下放到url_request_context中
void URLRequestContextConfig::ConfigureURLRequestContextBuilder(
net::URLRequestContextBuilder* context_builder,
net::NetLog* net_log,
const scoped_refptr<base::SequencedTaskRunner>& file_task_runner) {
//...
// 如果是采用新接口TurboNet,则默认UA来自于bdconfig,相当于CronetEngine的setUserAgent失效了
#if defined(BAIDU_TURBONET_PACKAGE)
context_builder->set_user_agent(bd_config.base.user_agent);
context_builder->SetSpdyAndQuicEnabled(bd_config.base.http2_enabled,
bd_config.base.quic_enabled);
// 如果还是老的那套Cronet,则采用CronetEngine传下来的UA
#else
context_builder->set_user_agent(user_agent);
context_builder->SetSpdyAndQuicEnabled(enable_spdy, enable_quic);
}

Android对cookie的设置

1
2
3
4
5
6
7
8
9
// cronet_url_request_context_adapter.cc
// 在初始化native层的context时,传了一个nullptr的CookieStore下去,实际上就是不启用CookieStore了
void CronetURLRequestContextAdapter::InitializeOnNetworkThread(
std::unique_ptr<URLRequestContextConfig> config,
const base::android::ScopedJavaGlobalRef<jobject>&
jcronet_url_request_context) {
// Disable net::CookieStore and net::ChannelIDService.
context_builder.SetCookieAndChannelIdStores(nullptr, nullptr);
}

native层

设置header

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
// url_request.cc
// 适配层调用的就是SetExtraRequestHeaders接口,将headers拷贝给了url_request中的extra_request_headers_
void URLRequest::SetExtraRequestHeaders(
const HttpRequestHeaders& headers) {
DCHECK(!is_pending_);
extra_request_headers_ = headers;
// NOTE: This method will likely become non-trivial once the other setters
// for request headers are implemented.
}
// Start时,又将extra_request_headers_灌入到了url_request_http_job中去了
void URLRequest::StartJob(URLRequestJob* job) {
job_.reset(job);
job_->SetExtraRequestHeaders(extra_request_headers_);
job_->SetPriority(priority_);
}
// url_request_http_job.cc
// 承接url_request.cc,对header进行了拷贝,放到了job的request_info_.extra_headers中
void URLRequestHttpJob::SetExtraRequestHeaders(
const HttpRequestHeaders& headers) {
DCHECK(!transaction_.get()) << "cannot change once started";
request_info_.extra_headers.CopyFrom(headers);
}
// 在job的start方法中,对header做了一些处理
void URLRequestHttpJob::Start() {
// 如注释,会把已经存在于header中的Referer字段抹掉,所以通过header来设置Referer在Android是行不通的
// Strip Referer from request_info_.extra_headers to prevent, e.g., plugins
// from overriding headers that are controlled using other means. Otherwise a
// plugin could set a referrer although sending the referrer is inhibited.
request_info_.extra_headers.RemoveHeader(HttpRequestHeaders::kReferer);
// 如果referer存在并且是符合规则的,则将referer设置到header中(此referer是通过SetReferer方法设置进来的)
// 故iOS在header中set referer行得通(适配层代码见上面)
// Our consumer should have made sure that this is a safe referrer. See for
// instance WebCore::FrameLoader::HideReferrer.
if (referrer.is_valid()) {
request_info_.extra_headers.SetHeader(HttpRequestHeaders::kReferer,
referrer.spec());
}
AddExtraHeaders();
}
void URLRequestHttpJob::AddExtraHeaders() {
//...
// 里面代码较长,就不粘贴了,主要是一些逻辑判断来确定是否set一些默认header
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
// http_network_transaction.cc
// job start后就进入到transaction了,这里还会对一些默认的header做一些特殊设置
int HttpNetworkTransaction::BuildRequestHeaders(
bool using_http_proxy_without_tunnel) {
// 对一些header做补充,例如把Connection设置为keep-alive
// (Baidu Added)
const std::string& host_name =
request_->use_super_pipe ? GetHostAndOptionalPort(request_->origin_url)
: GetHostAndOptionalPort(request_->url);
// (Baidu Added End)
// (Baidu Modified)
request_headers_.SetHeader(HttpRequestHeaders::kHost, host_name.c_str());
// (Baidu Modified End)
// For compat with HTTP/1.0 servers and proxies:
if (using_http_proxy_without_tunnel) {
request_headers_.SetHeader(HttpRequestHeaders::kProxyConnection,
"keep-alive");
} else {
request_headers_.SetHeader(HttpRequestHeaders::kConnection, "keep-alive");
}
// Add a content length header?
if (request_->upload_data_stream) {
if (request_->upload_data_stream->is_chunked()) {
request_headers_.SetHeader(
HttpRequestHeaders::kTransferEncoding, "chunked");
} else {
request_headers_.SetHeader(
HttpRequestHeaders::kContentLength,
base::Uint64ToString(request_->upload_data_stream->size()));
}
} else if (request_->method == "POST" || request_->method == "PUT") {
// An empty POST/PUT request still needs a content length. As for HEAD,
// IE and Safari also add a content length header. Presumably it is to
// support sending a HEAD request to an URL that only expects to be sent a
// POST or some other method that normally would have a message body.
// Firefox (40.0) does not send the header, and RFC 7230 & 7231
// specify that it should not be sent due to undefined behavior.
request_headers_.SetHeader(HttpRequestHeaders::kContentLength, "0");
}
// ...
// 注意request_headers_是transaction自己搞的一些header,最后会将它与request_->extra_headers进行合并(其实就是上面的request_info_.extra_headers)
// 并且以request_->extra_headers中的为准,如果有冲突的key
request_headers_.MergeFrom(request_->extra_headers);
}

native层对User-Agent的特别设置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
// url_request_context_builder.cc
// 在build native层的context时,会把全局ua包一下再设置到storage(这是个对URLRequestContext的封装)中去
std::unique_ptr<URLRequestContext> URLRequestContextBuilder::Build() {
storage->set_http_user_agent_settings(base::WrapUnique(
new StaticHttpUserAgentSettings(accept_language_, user_agent_)));
}
// url_request_context_storage.cc
// 在storage中,实际上把该set_http_user_agent_settings塞到了URLRequestContext中
void URLRequestContextStorage::set_http_user_agent_settings(
std::unique_ptr<HttpUserAgentSettings> http_user_agent_settings) {
context_->set_http_user_agent_settings(http_user_agent_settings.get());
http_user_agent_settings_ = std::move(http_user_agent_settings);
}
// URLRequestHttpJob
// 在build job的时候,会把URLRequestContext中的http_user_agent_settings,塞给job
URLRequestJob* URLRequestHttpJob::Factory(URLRequest* request,
NetworkDelegate* network_delegate,
const std::string& scheme) {
DCHECK(scheme == "http" || scheme == "https" || scheme == "ws" ||
scheme == "wss");
if (!request->context()->http_transaction_factory()) {
NOTREACHED() << "requires a valid context";
return new URLRequestErrorJob(
request, network_delegate, ERR_INVALID_ARGUMENT);
}
URLRequestRedirectJob* redirect =
MaybeInternallyRedirect(request, network_delegate);
if (redirect)
return redirect;
return new URLRequestHttpJob(request,
network_delegate,
request->context()->http_user_agent_settings());
}
void URLRequestHttpJob::Start() {
// 通过SetHeaderIfMissing,如果用户已经set了UA,则使用用户UA,否则使用默认的UA(上述层层传下来的值)
// (Baidu Modified)
// For network detect request, do not build default User-Agent header.
std::string host;
request_info_.extra_headers.GetHeader(HttpRequestHeaders::kHost, &host);
if (host.compare(kSuperPipeHostName) != 0) {
request_info_.extra_headers.SetHeaderIfMissing(
HttpRequestHeaders::kUserAgent,
http_user_agent_settings_ ? http_user_agent_settings_->GetUserAgent()
: std::string());
}
// (Baidu Modified End)
}

native层对cookie的设置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
// url_request_context_builder.cc
// 从双端适配层代码看,cookie的设置最终都落到了这里,将cookie_store传到build中,最终再传给context
void URLRequestContextBuilder::SetCookieAndChannelIdStores(
std::unique_ptr<CookieStore> cookie_store,
std::unique_ptr<ChannelIDService> channel_id_service) {
cookie_store_set_by_client_ = true;
// If |cookie_store| is NULL, |channel_id_service| must be NULL too.
DCHECK(cookie_store || !channel_id_service);
cookie_store_ = std::move(cookie_store);
channel_id_service_ = std::move(channel_id_service);
}
// url_request_http_job.cc
// 真正对cookie的获取是在job中
void URLRequestHttpJob::AddCookieHeaderAndStart() {
  // If the request was destroyed, then there is no more work to do.
  if (!request_)
    return;
 
  CookieStore* cookie_store = request_->context()->cookie_store();
 // 如果cookie_store不存在就没戏,因此Android是不会进入到if中的逻辑
  if (cookie_store && !(request_info_.load_flags & LOAD_DO_NOT_SEND_COOKIES)) {
    CookieOptions options;
    options.set_include_httponly();
 
    // Set SameSiteCookieMode according to the rules laid out in
    // https://tools.ietf.org/html/draft-west-first-party-cookies:
    //
    // * Include both "strict" and "lax" same-site cookies if the request's
    //   |url|, |initiator|, and |first_party_for_cookies| all have the same
    //   registrable domain.
    //
    // * Include only "lax" same-site cookies if the request's |URL| and
    //   |first_party_for_cookies| have the same registrable domain, _and_ the
    //   request's |method| is "safe" ("GET" or "HEAD").
    //
    //   Note that this will generally be the case only for cross-site requests
    //   which target a top-level browsing context.
    //
    // * Otherwise, do not include same-site cookies.
    url::Origin requested_origin(request_->url());
    url::Origin site_for_cookies(request_->first_party_for_cookies());
 
    if (registry_controlled_domains::SameDomainOrHost(
            requested_origin, site_for_cookies,
            registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES)) {
      if (registry_controlled_domains::SameDomainOrHost(
              requested_origin, request_->initiator(),
              registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES)) {
        options.set_same_site_cookie_mode(
            CookieOptions::SameSiteCookieMode::INCLUDE_STRICT_AND_LAX);
      } else if (IsMethodSafe(request_->method())) {
        options.set_same_site_cookie_mode(
            CookieOptions::SameSiteCookieMode::INCLUDE_LAX);
      }
    }
    // 调用cookie_store的方法异步获取cookie
    cookie_store->GetCookieListWithOptionsAsync(
        request_->url(), options,
        base::Bind(&URLRequestHttpJob::SetCookieHeaderAndStart,
                   weak_factory_.GetWeakPtr()));
  } else {
    DoStartTransaction();
  }
}
 
 
// 对cookie的获取
void URLRequestHttpJob::SetCookieHeaderAndStart(const CookieList& cookie_list) {
  // 只有满足CanGetCookies才能真正把cookie set进去,CanGetCookies由创建context时传入的network_delegate中的同名方法决定,这里不赘述了
  // 在TurboNet2.0之前network_delegate中的CanGetCookies在双端都是关闭的,现在iOS端开启了
  if (cookie_list.size() && CanGetCookies(cookie_list)) {
  // (Baidu Modified)
  // 原生的写的是SetHeader,意味着从cookie_store(iOS其实是从NSHTTPCookieStorage)获取的cookie会覆盖用户手动set的cookie
  // 现在是改为SetHeaderIfMissing,以用户设置的为最高优先级
  // If user has set cookie in header, then uses the original cookie.
  // request_info_.extra_headers.SetHeader(
    //    HttpRequestHeaders::kCookie, CookieStore::BuildCookieLine(cookie_list));
  // (Baidu Deleted End)
  request_info_.extra_headers.SetHeaderIfMissing(
      HttpRequestHeaders::kCookie, CookieStore::BuildCookieLine(cookie_list));
  // (Baidu Modified End)
    // Disable privacy mode as we are sending cookies anyway.
    request_info_.privacy_mode = PRIVACY_MODE_DISABLED;
  }
  DoStartTransaction();
}
 
 
 
// 对cookie的写入
// 收到的Response中如果携带了set-cookie,意味着服务端要求我们将该cookie写入本地,并在之后的请求中携带它
// 这里还是调用的CookieStore的方法进行写入,也有CanSetCookie方法进行控制,之前在双端都关闭(返回false),现在iOS开启了CanSetCookie(返回true)
// CanSetCookie也是在对应的network_delegate中进行的控制
void URLRequestHttpJob::SaveCookiesAndNotifyHeadersComplete(int result) {
  // End of the call started in OnStartCompleted.
  OnCallToDelegateComplete();
 
  if (result != OK) {
    std::string source("delegate");
    request_->net_log().AddEvent(NetLog::TYPE_CANCELLED,
                                 NetLog::StringCallback("source", &source));
    NotifyStartError(URLRequestStatus(URLRequestStatus::FAILED, result));
    return;
  }
 
  std::vector<std::string> response_cookies;
  FetchResponseCookies(&response_cookies);
 
  base::Time response_date;
  if (!GetResponseHeaders()->GetDateValue(&response_date))
    response_date = base::Time();
 
  if (!(request_info_.load_flags & LOAD_DO_NOT_SAVE_COOKIES) &&
      request_->context()->cookie_store()) {
    CookieOptions options;
    options.set_include_httponly();
    options.set_server_time(response_date);
 
    if (network_delegate() &&
        network_delegate()->AreStrictSecureCookiesEnabled()) {
      options.set_enforce_strict_secure();
    }
 
    // Set all cookies, without waiting for them to be set. Any subsequent read
    // will see the combined result of all cookie operation.
    for (const std::string& cookie : response_cookies) {
      if (!CanSetCookie(cookie, &options))
        continue;
      request_->context()->cookie_store()->SetCookieWithOptionsAsync(
          request_->url(), cookie, options, CookieStore::SetCookiesCallback());
    }
  }
 
  NotifyHeadersComplete();
}

发生Redirect对header影响

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
// url_request.cc
 
// Redirect时会对部分header进行抹除
int URLRequest::Redirect(const RedirectInfo& redirect_info) {
if (redirect_info.new_method != method_) {
    // TODO(davidben): This logic still needs to be replicated at the consumers.
    if (method_ == "POST") {
      // If being switched from POST, must remove Origin header.
      // TODO(jww): This is Origin header removal is probably layering violation
      // and
      // should be refactored into //content. See https://crbug.com/471397.
      extra_request_headers_.RemoveHeader(HttpRequestHeaders::kOrigin);
    }
    // The inclusion of a multipart Content-Type header can cause problems with
    // some
    // servers:
    // http://code.google.com/p/chromium/issues/detail?id=843
    extra_request_headers_.RemoveHeader(HttpRequestHeaders::kContentLength);
    extra_request_headers_.RemoveHeader(HttpRequestHeaders::kContentType);
    upload_data_stream_.reset();
    method_ = redirect_info.new_method;
  }
 
  // Cross-origin redirects should not result in an Origin header value that is
  // equal to the original request's Origin header. This is necessary to prevent
  // a reflection of POST requests to bypass CSRF protections. If the header was
  // not set to "null", a POST request from origin A to a malicious origin M
  // could be redirected by M back to A.
  //
  // This behavior is specified in step 1 of step 10 of the 301, 302, 303, 307,
  // 308 block of step 5 of Section 4.2 of Fetch[1] (which supercedes the
  // behavior outlined in RFC 6454[2].
  //
  // [1]: https://fetch.spec.whatwg.org/#concept-http-fetch
  // [2]: https://tools.ietf.org/html/rfc6454#section-7
  //
  // TODO(jww): This is a layering violation and should be refactored somewhere
  // up into //net's embedder. https://crbug.com/471397
  if (!url::Origin(redirect_info.new_url)
           .IsSameOriginWith(url::Origin(url())) &&
      extra_request_headers_.HasHeader(HttpRequestHeaders::kOrigin)) {
    extra_request_headers_.SetHeader(HttpRequestHeaders::kOrigin,
                                     url::Origin().Serialize());
  }
 
  // 这个地方是我们手动加的,主动抹除用户设置的Host,否则跳转后的Host依然是旧的
  // Fix redirect 'Host' header error issue,
  // The new URL had a different domain, but was set with the old 'Host' header
  if (!url::Origin(redirect_info.new_url)
           .IsSameOriginWith(url::Origin(url())) &&
      extra_request_headers_.HasHeader(HttpRequestHeaders::kHost)) {
    extra_request_headers_.RemoveHeader(HttpRequestHeaders::kHost);
  }
}