1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "net/http/http_response_info.h"
7 #include "base/logging.h"
8 #include "base/pickle.h"
9 #include "base/time/time.h"
10 #include "net/base/auth.h"
11 #include "net/base/io_buffer.h"
12 #include "net/base/net_errors.h"
13 #include "net/cert/signed_certificate_timestamp.h"
14 #include "net/cert/x509_certificate.h"
15 #include "net/http/http_response_headers.h"
16 #include "net/ssl/ssl_cert_request_info.h"
24 X509Certificate::PickleType
GetPickleTypeForVersion(int version
) {
27 return X509Certificate::PICKLETYPE_SINGLE_CERTIFICATE
;
29 return X509Certificate::PICKLETYPE_CERTIFICATE_CHAIN_V2
;
32 return X509Certificate::PICKLETYPE_CERTIFICATE_CHAIN_V3
;
38 // These values can be bit-wise combined to form the flags field of the
39 // serialized HttpResponseInfo.
41 // The version of the response info used when persisting response info.
42 RESPONSE_INFO_VERSION
= 3,
44 // The minimum version supported for deserializing response info.
45 RESPONSE_INFO_MINIMUM_VERSION
= 1,
47 // We reserve up to 8 bits for the version number.
48 RESPONSE_INFO_VERSION_MASK
= 0xFF,
50 // This bit is set if the response info has a cert at the end.
51 // Version 1 serialized only the end-entity certificate, while subsequent
52 // versions include the available certificate chain.
53 RESPONSE_INFO_HAS_CERT
= 1 << 8,
55 // This bit is set if the response info has a security-bits field (security
56 // strength, in bits, of the SSL connection) at the end.
57 RESPONSE_INFO_HAS_SECURITY_BITS
= 1 << 9,
59 // This bit is set if the response info has a cert status at the end.
60 RESPONSE_INFO_HAS_CERT_STATUS
= 1 << 10,
62 // This bit is set if the response info has vary header data.
63 RESPONSE_INFO_HAS_VARY_DATA
= 1 << 11,
65 // This bit is set if the request was cancelled before completion.
66 RESPONSE_INFO_TRUNCATED
= 1 << 12,
68 // This bit is set if the response was received via SPDY.
69 RESPONSE_INFO_WAS_SPDY
= 1 << 13,
71 // This bit is set if the request has NPN negotiated.
72 RESPONSE_INFO_WAS_NPN
= 1 << 14,
74 // This bit is set if the request was fetched via an explicit proxy.
75 RESPONSE_INFO_WAS_PROXY
= 1 << 15,
77 // This bit is set if the response info has an SSL connection status field.
78 // This contains the ciphersuite used to fetch the resource as well as the
79 // protocol version, compression method and whether SSLv3 fallback was used.
80 RESPONSE_INFO_HAS_SSL_CONNECTION_STATUS
= 1 << 16,
82 // This bit is set if the response info has protocol version.
83 RESPONSE_INFO_HAS_NPN_NEGOTIATED_PROTOCOL
= 1 << 17,
85 // This bit is set if the response info has connection info.
86 RESPONSE_INFO_HAS_CONNECTION_INFO
= 1 << 18,
88 // This bit is set if the request has http authentication.
89 RESPONSE_INFO_USE_HTTP_AUTHENTICATION
= 1 << 19,
91 // This bit is set if ssl_info has SCTs.
92 RESPONSE_INFO_HAS_SIGNED_CERTIFICATE_TIMESTAMPS
= 1 << 20,
94 RESPONSE_INFO_UNUSED_SINCE_PREFETCH
= 1 << 21,
96 // This bit is set if the response has a key-exchange-info field at the end.
97 RESPONSE_INFO_HAS_KEY_EXCHANGE_INFO
= 1 << 22,
99 // TODO(darin): Add other bits to indicate alternate request methods.
100 // For now, we don't support storing those.
103 HttpResponseInfo::HttpResponseInfo()
105 server_data_unavailable(false),
106 network_accessed(false),
107 was_fetched_via_spdy(false),
108 was_npn_negotiated(false),
109 was_fetched_via_proxy(false),
110 did_use_http_auth(false),
111 unused_since_prefetch(false),
112 async_revalidation_required(false),
113 connection_info(CONNECTION_INFO_UNKNOWN
) {}
115 HttpResponseInfo::HttpResponseInfo(const HttpResponseInfo
& rhs
)
116 : was_cached(rhs
.was_cached
),
117 server_data_unavailable(rhs
.server_data_unavailable
),
118 network_accessed(rhs
.network_accessed
),
119 was_fetched_via_spdy(rhs
.was_fetched_via_spdy
),
120 was_npn_negotiated(rhs
.was_npn_negotiated
),
121 was_fetched_via_proxy(rhs
.was_fetched_via_proxy
),
122 proxy_server(rhs
.proxy_server
),
123 did_use_http_auth(rhs
.did_use_http_auth
),
124 unused_since_prefetch(rhs
.unused_since_prefetch
),
125 async_revalidation_required(rhs
.async_revalidation_required
),
126 socket_address(rhs
.socket_address
),
127 npn_negotiated_protocol(rhs
.npn_negotiated_protocol
),
128 connection_info(rhs
.connection_info
),
129 request_time(rhs
.request_time
),
130 response_time(rhs
.response_time
),
131 auth_challenge(rhs
.auth_challenge
),
132 cert_request_info(rhs
.cert_request_info
),
133 ssl_info(rhs
.ssl_info
),
134 headers(rhs
.headers
),
135 vary_data(rhs
.vary_data
),
136 metadata(rhs
.metadata
) {}
138 HttpResponseInfo::~HttpResponseInfo() {
141 HttpResponseInfo
& HttpResponseInfo::operator=(const HttpResponseInfo
& rhs
) {
142 was_cached
= rhs
.was_cached
;
143 server_data_unavailable
= rhs
.server_data_unavailable
;
144 network_accessed
= rhs
.network_accessed
;
145 was_fetched_via_spdy
= rhs
.was_fetched_via_spdy
;
146 proxy_server
= rhs
.proxy_server
;
147 was_npn_negotiated
= rhs
.was_npn_negotiated
;
148 was_fetched_via_proxy
= rhs
.was_fetched_via_proxy
;
149 did_use_http_auth
= rhs
.did_use_http_auth
;
150 unused_since_prefetch
= rhs
.unused_since_prefetch
;
151 async_revalidation_required
= rhs
.async_revalidation_required
;
152 socket_address
= rhs
.socket_address
;
153 npn_negotiated_protocol
= rhs
.npn_negotiated_protocol
;
154 connection_info
= rhs
.connection_info
;
155 request_time
= rhs
.request_time
;
156 response_time
= rhs
.response_time
;
157 auth_challenge
= rhs
.auth_challenge
;
158 cert_request_info
= rhs
.cert_request_info
;
159 ssl_info
= rhs
.ssl_info
;
160 headers
= rhs
.headers
;
161 vary_data
= rhs
.vary_data
;
162 metadata
= rhs
.metadata
;
166 bool HttpResponseInfo::InitFromPickle(const base::Pickle
& pickle
,
167 bool* response_truncated
) {
168 base::PickleIterator
iter(pickle
);
170 // Read flags and verify version
172 if (!iter
.ReadInt(&flags
))
174 int version
= flags
& RESPONSE_INFO_VERSION_MASK
;
175 if (version
< RESPONSE_INFO_MINIMUM_VERSION
||
176 version
> RESPONSE_INFO_VERSION
) {
177 DLOG(ERROR
) << "unexpected response info version: " << version
;
183 if (!iter
.ReadInt64(&time_val
))
185 request_time
= Time::FromInternalValue(time_val
);
186 was_cached
= true; // Set status to show cache resurrection.
188 // Read response-time
189 if (!iter
.ReadInt64(&time_val
))
191 response_time
= Time::FromInternalValue(time_val
);
193 // Read response-headers
194 headers
= new HttpResponseHeaders(&iter
);
195 if (headers
->response_code() == -1)
199 if (flags
& RESPONSE_INFO_HAS_CERT
) {
200 X509Certificate::PickleType type
= GetPickleTypeForVersion(version
);
201 ssl_info
.cert
= X509Certificate::CreateFromPickle(&iter
, type
);
202 if (!ssl_info
.cert
.get())
205 if (flags
& RESPONSE_INFO_HAS_CERT_STATUS
) {
206 CertStatus cert_status
;
207 if (!iter
.ReadUInt32(&cert_status
))
209 ssl_info
.cert_status
= cert_status
;
211 if (flags
& RESPONSE_INFO_HAS_SECURITY_BITS
) {
213 if (!iter
.ReadInt(&security_bits
))
215 ssl_info
.security_bits
= security_bits
;
218 if (flags
& RESPONSE_INFO_HAS_SSL_CONNECTION_STATUS
) {
219 int connection_status
;
220 if (!iter
.ReadInt(&connection_status
))
222 ssl_info
.connection_status
= connection_status
;
225 if (flags
& RESPONSE_INFO_HAS_SIGNED_CERTIFICATE_TIMESTAMPS
) {
227 if (!iter
.ReadInt(&num_scts
))
229 for (int i
= 0; i
< num_scts
; ++i
) {
230 scoped_refptr
<ct::SignedCertificateTimestamp
> sct(
231 ct::SignedCertificateTimestamp::CreateFromPickle(&iter
));
233 if (!sct
.get() || !iter
.ReadUInt16(&status
))
235 ssl_info
.signed_certificate_timestamps
.push_back(
236 SignedCertificateTimestampAndStatus(
237 sct
, static_cast<ct::SCTVerifyStatus
>(status
)));
242 if (flags
& RESPONSE_INFO_HAS_VARY_DATA
) {
243 if (!vary_data
.InitFromPickle(&iter
))
247 // Read socket_address.
248 std::string socket_address_host
;
249 if (iter
.ReadString(&socket_address_host
)) {
250 // If the host was written, we always expect the port to follow.
251 uint16 socket_address_port
;
252 if (!iter
.ReadUInt16(&socket_address_port
))
254 socket_address
= HostPortPair(socket_address_host
, socket_address_port
);
255 } else if (version
> 1) {
256 // socket_address was not always present in version 1 of the response
257 // info, so we don't fail if it can't be read.
261 // Read protocol-version.
262 if (flags
& RESPONSE_INFO_HAS_NPN_NEGOTIATED_PROTOCOL
) {
263 if (!iter
.ReadString(&npn_negotiated_protocol
))
267 // Read connection info.
268 if (flags
& RESPONSE_INFO_HAS_CONNECTION_INFO
) {
270 if (!iter
.ReadInt(&value
))
273 if (value
> static_cast<int>(CONNECTION_INFO_UNKNOWN
) &&
274 value
< static_cast<int>(NUM_OF_CONNECTION_INFOS
)) {
275 connection_info
= static_cast<ConnectionInfo
>(value
);
279 // Read key_exchange_info
280 if (flags
& RESPONSE_INFO_HAS_KEY_EXCHANGE_INFO
) {
281 int key_exchange_info
;
282 if (!iter
.ReadInt(&key_exchange_info
))
284 ssl_info
.key_exchange_info
= key_exchange_info
;
287 was_fetched_via_spdy
= (flags
& RESPONSE_INFO_WAS_SPDY
) != 0;
289 was_npn_negotiated
= (flags
& RESPONSE_INFO_WAS_NPN
) != 0;
291 was_fetched_via_proxy
= (flags
& RESPONSE_INFO_WAS_PROXY
) != 0;
293 *response_truncated
= (flags
& RESPONSE_INFO_TRUNCATED
) != 0;
295 did_use_http_auth
= (flags
& RESPONSE_INFO_USE_HTTP_AUTHENTICATION
) != 0;
297 unused_since_prefetch
= (flags
& RESPONSE_INFO_UNUSED_SINCE_PREFETCH
) != 0;
302 void HttpResponseInfo::Persist(base::Pickle
* pickle
,
303 bool skip_transient_headers
,
304 bool response_truncated
) const {
305 int flags
= RESPONSE_INFO_VERSION
;
306 if (ssl_info
.is_valid()) {
307 flags
|= RESPONSE_INFO_HAS_CERT
;
308 flags
|= RESPONSE_INFO_HAS_CERT_STATUS
;
309 if (ssl_info
.security_bits
!= -1)
310 flags
|= RESPONSE_INFO_HAS_SECURITY_BITS
;
311 if (ssl_info
.key_exchange_info
!= 0)
312 flags
|= RESPONSE_INFO_HAS_KEY_EXCHANGE_INFO
;
313 if (ssl_info
.connection_status
!= 0)
314 flags
|= RESPONSE_INFO_HAS_SSL_CONNECTION_STATUS
;
316 if (vary_data
.is_valid())
317 flags
|= RESPONSE_INFO_HAS_VARY_DATA
;
318 if (response_truncated
)
319 flags
|= RESPONSE_INFO_TRUNCATED
;
320 if (was_fetched_via_spdy
)
321 flags
|= RESPONSE_INFO_WAS_SPDY
;
322 if (was_npn_negotiated
) {
323 flags
|= RESPONSE_INFO_WAS_NPN
;
324 flags
|= RESPONSE_INFO_HAS_NPN_NEGOTIATED_PROTOCOL
;
326 if (was_fetched_via_proxy
)
327 flags
|= RESPONSE_INFO_WAS_PROXY
;
328 if (connection_info
!= CONNECTION_INFO_UNKNOWN
)
329 flags
|= RESPONSE_INFO_HAS_CONNECTION_INFO
;
330 if (did_use_http_auth
)
331 flags
|= RESPONSE_INFO_USE_HTTP_AUTHENTICATION
;
332 if (unused_since_prefetch
)
333 flags
|= RESPONSE_INFO_UNUSED_SINCE_PREFETCH
;
334 if (!ssl_info
.signed_certificate_timestamps
.empty())
335 flags
|= RESPONSE_INFO_HAS_SIGNED_CERTIFICATE_TIMESTAMPS
;
337 pickle
->WriteInt(flags
);
338 pickle
->WriteInt64(request_time
.ToInternalValue());
339 pickle
->WriteInt64(response_time
.ToInternalValue());
341 HttpResponseHeaders::PersistOptions persist_options
=
342 HttpResponseHeaders::PERSIST_RAW
;
344 if (skip_transient_headers
) {
345 persist_options
= HttpResponseHeaders::PERSIST_SANS_COOKIES
|
346 HttpResponseHeaders::PERSIST_SANS_CHALLENGES
|
347 HttpResponseHeaders::PERSIST_SANS_HOP_BY_HOP
|
348 HttpResponseHeaders::PERSIST_SANS_NON_CACHEABLE
|
349 HttpResponseHeaders::PERSIST_SANS_RANGES
|
350 HttpResponseHeaders::PERSIST_SANS_SECURITY_STATE
;
353 headers
->Persist(pickle
, persist_options
);
355 if (ssl_info
.is_valid()) {
356 ssl_info
.cert
->Persist(pickle
);
357 pickle
->WriteUInt32(ssl_info
.cert_status
);
358 if (ssl_info
.security_bits
!= -1)
359 pickle
->WriteInt(ssl_info
.security_bits
);
360 if (ssl_info
.connection_status
!= 0)
361 pickle
->WriteInt(ssl_info
.connection_status
);
362 if (!ssl_info
.signed_certificate_timestamps
.empty()) {
363 pickle
->WriteInt(ssl_info
.signed_certificate_timestamps
.size());
364 for (SignedCertificateTimestampAndStatusList::const_iterator it
=
365 ssl_info
.signed_certificate_timestamps
.begin(); it
!=
366 ssl_info
.signed_certificate_timestamps
.end(); ++it
) {
367 it
->sct
->Persist(pickle
);
368 pickle
->WriteUInt16(static_cast<uint16
>(it
->status
));
373 if (vary_data
.is_valid())
374 vary_data
.Persist(pickle
);
376 pickle
->WriteString(socket_address
.host());
377 pickle
->WriteUInt16(socket_address
.port());
379 if (was_npn_negotiated
)
380 pickle
->WriteString(npn_negotiated_protocol
);
382 if (connection_info
!= CONNECTION_INFO_UNKNOWN
)
383 pickle
->WriteInt(static_cast<int>(connection_info
));
385 if (ssl_info
.is_valid() && ssl_info
.key_exchange_info
!= 0)
386 pickle
->WriteInt(ssl_info
.key_exchange_info
);
389 HttpResponseInfo::ConnectionInfo
HttpResponseInfo::ConnectionInfoFromNextProto(
390 NextProto next_proto
) {
391 switch (next_proto
) {
392 case kProtoDeprecatedSPDY2
:
393 return CONNECTION_INFO_DEPRECATED_SPDY2
;
396 return CONNECTION_INFO_SPDY3
;
398 return CONNECTION_INFO_HTTP2
;
399 case kProtoQUIC1SPDY3
:
400 return CONNECTION_INFO_QUIC1_SPDY3
;
408 return CONNECTION_INFO_UNKNOWN
;
412 std::string
HttpResponseInfo::ConnectionInfoToString(
413 ConnectionInfo connection_info
) {
414 switch (connection_info
) {
415 case CONNECTION_INFO_UNKNOWN
:
417 case CONNECTION_INFO_HTTP1
:
419 case CONNECTION_INFO_DEPRECATED_SPDY2
:
421 case CONNECTION_INFO_SPDY3
:
423 // Since ConnectionInfo is persisted to disk, deprecated values have to be
424 // handled. Note that h2-14 and h2-15 are essentially wire compatible with
426 // Intentional fallthrough.
427 case CONNECTION_INFO_HTTP2_14
:
428 case CONNECTION_INFO_HTTP2_15
:
429 case CONNECTION_INFO_HTTP2
:
431 case CONNECTION_INFO_QUIC1_SPDY3
:
432 return "quic/1+spdy/3";
433 case NUM_OF_CONNECTION_INFOS
: