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/x509_certificate.h"
14 #include "net/http/http_response_headers.h"
15 #include "net/ssl/ssl_cert_request_info.h"
23 X509Certificate::PickleType
GetPickleTypeForVersion(int version
) {
26 return X509Certificate::PICKLETYPE_SINGLE_CERTIFICATE
;
28 return X509Certificate::PICKLETYPE_CERTIFICATE_CHAIN_V2
;
31 return X509Certificate::PICKLETYPE_CERTIFICATE_CHAIN_V3
;
37 // These values can be bit-wise combined to form the flags field of the
38 // serialized HttpResponseInfo.
40 // The version of the response info used when persisting response info.
41 RESPONSE_INFO_VERSION
= 3,
43 // The minimum version supported for deserializing response info.
44 RESPONSE_INFO_MINIMUM_VERSION
= 1,
46 // We reserve up to 8 bits for the version number.
47 RESPONSE_INFO_VERSION_MASK
= 0xFF,
49 // This bit is set if the response info has a cert at the end.
50 // Version 1 serialized only the end-entity certificate, while subsequent
51 // versions include the available certificate chain.
52 RESPONSE_INFO_HAS_CERT
= 1 << 8,
54 // This bit is set if the response info has a security-bits field (security
55 // strength, in bits, of the SSL connection) at the end.
56 RESPONSE_INFO_HAS_SECURITY_BITS
= 1 << 9,
58 // This bit is set if the response info has a cert status at the end.
59 RESPONSE_INFO_HAS_CERT_STATUS
= 1 << 10,
61 // This bit is set if the response info has vary header data.
62 RESPONSE_INFO_HAS_VARY_DATA
= 1 << 11,
64 // This bit is set if the request was cancelled before completion.
65 RESPONSE_INFO_TRUNCATED
= 1 << 12,
67 // This bit is set if the response was received via SPDY.
68 RESPONSE_INFO_WAS_SPDY
= 1 << 13,
70 // This bit is set if the request has NPN negotiated.
71 RESPONSE_INFO_WAS_NPN
= 1 << 14,
73 // This bit is set if the request was fetched via an explicit proxy.
74 RESPONSE_INFO_WAS_PROXY
= 1 << 15,
76 // This bit is set if the response info has an SSL connection status field.
77 // This contains the ciphersuite used to fetch the resource as well as the
78 // protocol version, compression method and whether SSLv3 fallback was used.
79 RESPONSE_INFO_HAS_SSL_CONNECTION_STATUS
= 1 << 16,
81 // This bit is set if the response info has protocol version.
82 RESPONSE_INFO_HAS_NPN_NEGOTIATED_PROTOCOL
= 1 << 17,
84 // This bit is set if the response info has connection info.
85 RESPONSE_INFO_HAS_CONNECTION_INFO
= 1 << 18,
87 // This bit is set if the request has http authentication.
88 RESPONSE_INFO_USE_HTTP_AUTHENTICATION
= 1 << 19,
90 // TODO(darin): Add other bits to indicate alternate request methods.
91 // For now, we don't support storing those.
94 HttpResponseInfo::HttpResponseInfo()
96 server_data_unavailable(false),
97 network_accessed(false),
98 was_fetched_via_spdy(false),
99 was_npn_negotiated(false),
100 was_fetched_via_proxy(false),
101 did_use_http_auth(false),
102 connection_info(CONNECTION_INFO_UNKNOWN
) {
105 HttpResponseInfo::HttpResponseInfo(const HttpResponseInfo
& rhs
)
106 : was_cached(rhs
.was_cached
),
107 server_data_unavailable(rhs
.server_data_unavailable
),
108 network_accessed(rhs
.network_accessed
),
109 was_fetched_via_spdy(rhs
.was_fetched_via_spdy
),
110 was_npn_negotiated(rhs
.was_npn_negotiated
),
111 was_fetched_via_proxy(rhs
.was_fetched_via_proxy
),
112 did_use_http_auth(rhs
.did_use_http_auth
),
113 socket_address(rhs
.socket_address
),
114 npn_negotiated_protocol(rhs
.npn_negotiated_protocol
),
115 connection_info(rhs
.connection_info
),
116 request_time(rhs
.request_time
),
117 response_time(rhs
.response_time
),
118 auth_challenge(rhs
.auth_challenge
),
119 cert_request_info(rhs
.cert_request_info
),
120 ssl_info(rhs
.ssl_info
),
121 headers(rhs
.headers
),
122 vary_data(rhs
.vary_data
),
123 metadata(rhs
.metadata
) {
126 HttpResponseInfo::~HttpResponseInfo() {
129 HttpResponseInfo
& HttpResponseInfo::operator=(const HttpResponseInfo
& rhs
) {
130 was_cached
= rhs
.was_cached
;
131 server_data_unavailable
= rhs
.server_data_unavailable
;
132 network_accessed
= rhs
.network_accessed
;
133 was_fetched_via_spdy
= rhs
.was_fetched_via_spdy
;
134 was_npn_negotiated
= rhs
.was_npn_negotiated
;
135 was_fetched_via_proxy
= rhs
.was_fetched_via_proxy
;
136 did_use_http_auth
= rhs
.did_use_http_auth
;
137 socket_address
= rhs
.socket_address
;
138 npn_negotiated_protocol
= rhs
.npn_negotiated_protocol
;
139 connection_info
= rhs
.connection_info
;
140 request_time
= rhs
.request_time
;
141 response_time
= rhs
.response_time
;
142 auth_challenge
= rhs
.auth_challenge
;
143 cert_request_info
= rhs
.cert_request_info
;
144 ssl_info
= rhs
.ssl_info
;
145 headers
= rhs
.headers
;
146 vary_data
= rhs
.vary_data
;
147 metadata
= rhs
.metadata
;
151 bool HttpResponseInfo::InitFromPickle(const Pickle
& pickle
,
152 bool* response_truncated
) {
153 PickleIterator
iter(pickle
);
155 // Read flags and verify version
157 if (!pickle
.ReadInt(&iter
, &flags
))
159 int version
= flags
& RESPONSE_INFO_VERSION_MASK
;
160 if (version
< RESPONSE_INFO_MINIMUM_VERSION
||
161 version
> RESPONSE_INFO_VERSION
) {
162 DLOG(ERROR
) << "unexpected response info version: " << version
;
168 if (!pickle
.ReadInt64(&iter
, &time_val
))
170 request_time
= Time::FromInternalValue(time_val
);
171 was_cached
= true; // Set status to show cache resurrection.
173 // Read response-time
174 if (!pickle
.ReadInt64(&iter
, &time_val
))
176 response_time
= Time::FromInternalValue(time_val
);
178 // Read response-headers
179 headers
= new HttpResponseHeaders(pickle
, &iter
);
180 if (headers
->response_code() == -1)
184 if (flags
& RESPONSE_INFO_HAS_CERT
) {
185 X509Certificate::PickleType type
= GetPickleTypeForVersion(version
);
186 ssl_info
.cert
= X509Certificate::CreateFromPickle(pickle
, &iter
, type
);
187 if (!ssl_info
.cert
.get())
190 if (flags
& RESPONSE_INFO_HAS_CERT_STATUS
) {
191 CertStatus cert_status
;
192 if (!pickle
.ReadUInt32(&iter
, &cert_status
))
194 ssl_info
.cert_status
= cert_status
;
196 if (flags
& RESPONSE_INFO_HAS_SECURITY_BITS
) {
198 if (!pickle
.ReadInt(&iter
, &security_bits
))
200 ssl_info
.security_bits
= security_bits
;
203 if (flags
& RESPONSE_INFO_HAS_SSL_CONNECTION_STATUS
) {
204 int connection_status
;
205 if (!pickle
.ReadInt(&iter
, &connection_status
))
207 ssl_info
.connection_status
= connection_status
;
211 if (flags
& RESPONSE_INFO_HAS_VARY_DATA
) {
212 if (!vary_data
.InitFromPickle(pickle
, &iter
))
216 // Read socket_address.
217 std::string socket_address_host
;
218 if (pickle
.ReadString(&iter
, &socket_address_host
)) {
219 // If the host was written, we always expect the port to follow.
220 uint16 socket_address_port
;
221 if (!pickle
.ReadUInt16(&iter
, &socket_address_port
))
223 socket_address
= HostPortPair(socket_address_host
, socket_address_port
);
224 } else if (version
> 1) {
225 // socket_address was not always present in version 1 of the response
226 // info, so we don't fail if it can't be read.
230 // Read protocol-version.
231 if (flags
& RESPONSE_INFO_HAS_NPN_NEGOTIATED_PROTOCOL
) {
232 if (!pickle
.ReadString(&iter
, &npn_negotiated_protocol
))
236 // Read connection info.
237 if (flags
& RESPONSE_INFO_HAS_CONNECTION_INFO
) {
239 if (!pickle
.ReadInt(&iter
, &value
))
242 if (value
> static_cast<int>(CONNECTION_INFO_UNKNOWN
) &&
243 value
< static_cast<int>(NUM_OF_CONNECTION_INFOS
)) {
244 connection_info
= static_cast<ConnectionInfo
>(value
);
248 was_fetched_via_spdy
= (flags
& RESPONSE_INFO_WAS_SPDY
) != 0;
250 was_npn_negotiated
= (flags
& RESPONSE_INFO_WAS_NPN
) != 0;
252 was_fetched_via_proxy
= (flags
& RESPONSE_INFO_WAS_PROXY
) != 0;
254 *response_truncated
= (flags
& RESPONSE_INFO_TRUNCATED
) != 0;
256 did_use_http_auth
= (flags
& RESPONSE_INFO_USE_HTTP_AUTHENTICATION
) != 0;
261 void HttpResponseInfo::Persist(Pickle
* pickle
,
262 bool skip_transient_headers
,
263 bool response_truncated
) const {
264 int flags
= RESPONSE_INFO_VERSION
;
265 if (ssl_info
.is_valid()) {
266 flags
|= RESPONSE_INFO_HAS_CERT
;
267 flags
|= RESPONSE_INFO_HAS_CERT_STATUS
;
268 if (ssl_info
.security_bits
!= -1)
269 flags
|= RESPONSE_INFO_HAS_SECURITY_BITS
;
270 if (ssl_info
.connection_status
!= 0)
271 flags
|= RESPONSE_INFO_HAS_SSL_CONNECTION_STATUS
;
273 if (vary_data
.is_valid())
274 flags
|= RESPONSE_INFO_HAS_VARY_DATA
;
275 if (response_truncated
)
276 flags
|= RESPONSE_INFO_TRUNCATED
;
277 if (was_fetched_via_spdy
)
278 flags
|= RESPONSE_INFO_WAS_SPDY
;
279 if (was_npn_negotiated
) {
280 flags
|= RESPONSE_INFO_WAS_NPN
;
281 flags
|= RESPONSE_INFO_HAS_NPN_NEGOTIATED_PROTOCOL
;
283 if (was_fetched_via_proxy
)
284 flags
|= RESPONSE_INFO_WAS_PROXY
;
285 if (connection_info
!= CONNECTION_INFO_UNKNOWN
)
286 flags
|= RESPONSE_INFO_HAS_CONNECTION_INFO
;
287 if (did_use_http_auth
)
288 flags
|= RESPONSE_INFO_USE_HTTP_AUTHENTICATION
;
290 pickle
->WriteInt(flags
);
291 pickle
->WriteInt64(request_time
.ToInternalValue());
292 pickle
->WriteInt64(response_time
.ToInternalValue());
294 net::HttpResponseHeaders::PersistOptions persist_options
=
295 net::HttpResponseHeaders::PERSIST_RAW
;
297 if (skip_transient_headers
) {
299 net::HttpResponseHeaders::PERSIST_SANS_COOKIES
|
300 net::HttpResponseHeaders::PERSIST_SANS_CHALLENGES
|
301 net::HttpResponseHeaders::PERSIST_SANS_HOP_BY_HOP
|
302 net::HttpResponseHeaders::PERSIST_SANS_NON_CACHEABLE
|
303 net::HttpResponseHeaders::PERSIST_SANS_RANGES
|
304 net::HttpResponseHeaders::PERSIST_SANS_SECURITY_STATE
;
307 headers
->Persist(pickle
, persist_options
);
309 if (ssl_info
.is_valid()) {
310 ssl_info
.cert
->Persist(pickle
);
311 pickle
->WriteUInt32(ssl_info
.cert_status
);
312 if (ssl_info
.security_bits
!= -1)
313 pickle
->WriteInt(ssl_info
.security_bits
);
314 if (ssl_info
.connection_status
!= 0)
315 pickle
->WriteInt(ssl_info
.connection_status
);
318 if (vary_data
.is_valid())
319 vary_data
.Persist(pickle
);
321 pickle
->WriteString(socket_address
.host());
322 pickle
->WriteUInt16(socket_address
.port());
324 if (was_npn_negotiated
)
325 pickle
->WriteString(npn_negotiated_protocol
);
327 if (connection_info
!= CONNECTION_INFO_UNKNOWN
)
328 pickle
->WriteInt(static_cast<int>(connection_info
));
331 HttpResponseInfo::ConnectionInfo
HttpResponseInfo::ConnectionInfoFromNextProto(
332 NextProto next_proto
) {
333 switch (next_proto
) {
335 return CONNECTION_INFO_SPDY2
;
338 return CONNECTION_INFO_SPDY3
;
340 return CONNECTION_INFO_SPDY4A2
;
341 case kProtoHTTP2Draft04
:
342 return CONNECTION_INFO_HTTP2_DRAFT_04
;
343 case kProtoQUIC1SPDY3
:
344 return CONNECTION_INFO_QUIC1_SPDY3
;
354 return CONNECTION_INFO_UNKNOWN
;
358 std::string
HttpResponseInfo::ConnectionInfoToString(
359 ConnectionInfo connection_info
) {
360 switch (connection_info
) {
361 case CONNECTION_INFO_UNKNOWN
:
363 case CONNECTION_INFO_HTTP1
:
365 case CONNECTION_INFO_SPDY2
:
367 case CONNECTION_INFO_SPDY3
:
369 case CONNECTION_INFO_SPDY4A2
:
371 case CONNECTION_INFO_HTTP2_DRAFT_04
:
372 return "HTTP-draft-04/2.0";
373 case CONNECTION_INFO_QUIC1_SPDY3
:
374 return "quic/1+spdy/3";
375 case NUM_OF_CONNECTION_INFOS
: