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 // TODO(darin): Add other bits to indicate alternate request methods.
95 // For now, we don't support storing those.
98 HttpResponseInfo::HttpResponseInfo()
100 server_data_unavailable(false),
101 network_accessed(false),
102 was_fetched_via_spdy(false),
103 was_npn_negotiated(false),
104 was_fetched_via_proxy(false),
105 did_use_http_auth(false),
106 connection_info(CONNECTION_INFO_UNKNOWN) {
109 HttpResponseInfo::HttpResponseInfo(const HttpResponseInfo& rhs)
110 : was_cached(rhs.was_cached),
111 server_data_unavailable(rhs.server_data_unavailable),
112 network_accessed(rhs.network_accessed),
113 was_fetched_via_spdy(rhs.was_fetched_via_spdy),
114 was_npn_negotiated(rhs.was_npn_negotiated),
115 was_fetched_via_proxy(rhs.was_fetched_via_proxy),
116 did_use_http_auth(rhs.did_use_http_auth),
117 socket_address(rhs.socket_address),
118 npn_negotiated_protocol(rhs.npn_negotiated_protocol),
119 connection_info(rhs.connection_info),
120 request_time(rhs.request_time),
121 response_time(rhs.response_time),
122 auth_challenge(rhs.auth_challenge),
123 cert_request_info(rhs.cert_request_info),
124 ssl_info(rhs.ssl_info),
125 headers(rhs.headers),
126 vary_data(rhs.vary_data),
127 metadata(rhs.metadata) {
130 HttpResponseInfo::~HttpResponseInfo() {
133 HttpResponseInfo& HttpResponseInfo::operator=(const HttpResponseInfo& rhs) {
134 was_cached = rhs.was_cached;
135 server_data_unavailable = rhs.server_data_unavailable;
136 network_accessed = rhs.network_accessed;
137 was_fetched_via_spdy = rhs.was_fetched_via_spdy;
138 was_npn_negotiated = rhs.was_npn_negotiated;
139 was_fetched_via_proxy = rhs.was_fetched_via_proxy;
140 did_use_http_auth = rhs.did_use_http_auth;
141 socket_address = rhs.socket_address;
142 npn_negotiated_protocol = rhs.npn_negotiated_protocol;
143 connection_info = rhs.connection_info;
144 request_time = rhs.request_time;
145 response_time = rhs.response_time;
146 auth_challenge = rhs.auth_challenge;
147 cert_request_info = rhs.cert_request_info;
148 ssl_info = rhs.ssl_info;
149 headers = rhs.headers;
150 vary_data = rhs.vary_data;
151 metadata = rhs.metadata;
155 bool HttpResponseInfo::InitFromPickle(const Pickle& pickle,
156 bool* response_truncated) {
157 PickleIterator iter(pickle);
159 // Read flags and verify version
161 if (!pickle.ReadInt(&iter, &flags))
163 int version = flags & RESPONSE_INFO_VERSION_MASK;
164 if (version < RESPONSE_INFO_MINIMUM_VERSION ||
165 version > RESPONSE_INFO_VERSION) {
166 DLOG(ERROR) << "unexpected response info version: " << version;
172 if (!pickle.ReadInt64(&iter, &time_val))
174 request_time = Time::FromInternalValue(time_val);
175 was_cached = true; // Set status to show cache resurrection.
177 // Read response-time
178 if (!pickle.ReadInt64(&iter, &time_val))
180 response_time = Time::FromInternalValue(time_val);
182 // Read response-headers
183 headers = new HttpResponseHeaders(pickle, &iter);
184 if (headers->response_code() == -1)
188 if (flags & RESPONSE_INFO_HAS_CERT) {
189 X509Certificate::PickleType type = GetPickleTypeForVersion(version);
190 ssl_info.cert = X509Certificate::CreateFromPickle(pickle, &iter, type);
191 if (!ssl_info.cert.get())
194 if (flags & RESPONSE_INFO_HAS_CERT_STATUS) {
195 CertStatus cert_status;
196 if (!pickle.ReadUInt32(&iter, &cert_status))
198 ssl_info.cert_status = cert_status;
200 if (flags & RESPONSE_INFO_HAS_SECURITY_BITS) {
202 if (!pickle.ReadInt(&iter, &security_bits))
204 ssl_info.security_bits = security_bits;
207 if (flags & RESPONSE_INFO_HAS_SSL_CONNECTION_STATUS) {
208 int connection_status;
209 if (!pickle.ReadInt(&iter, &connection_status))
211 ssl_info.connection_status = connection_status;
214 if (flags & RESPONSE_INFO_HAS_SIGNED_CERTIFICATE_TIMESTAMPS) {
216 if (!pickle.ReadInt(&iter, &num_scts))
218 for (int i = 0; i < num_scts; ++i) {
219 scoped_refptr<ct::SignedCertificateTimestamp> sct(
220 ct::SignedCertificateTimestamp::CreateFromPickle(&iter));
222 if (!sct.get() || !pickle.ReadUInt16(&iter, &status))
224 ssl_info.signed_certificate_timestamps.push_back(
225 SignedCertificateTimestampAndStatus(
226 sct, static_cast<ct::SCTVerifyStatus>(status)));
231 if (flags & RESPONSE_INFO_HAS_VARY_DATA) {
232 if (!vary_data.InitFromPickle(pickle, &iter))
236 // Read socket_address.
237 std::string socket_address_host;
238 if (pickle.ReadString(&iter, &socket_address_host)) {
239 // If the host was written, we always expect the port to follow.
240 uint16 socket_address_port;
241 if (!pickle.ReadUInt16(&iter, &socket_address_port))
243 socket_address = HostPortPair(socket_address_host, socket_address_port);
244 } else if (version > 1) {
245 // socket_address was not always present in version 1 of the response
246 // info, so we don't fail if it can't be read.
250 // Read protocol-version.
251 if (flags & RESPONSE_INFO_HAS_NPN_NEGOTIATED_PROTOCOL) {
252 if (!pickle.ReadString(&iter, &npn_negotiated_protocol))
256 // Read connection info.
257 if (flags & RESPONSE_INFO_HAS_CONNECTION_INFO) {
259 if (!pickle.ReadInt(&iter, &value))
262 if (value > static_cast<int>(CONNECTION_INFO_UNKNOWN) &&
263 value < static_cast<int>(NUM_OF_CONNECTION_INFOS)) {
264 connection_info = static_cast<ConnectionInfo>(value);
268 was_fetched_via_spdy = (flags & RESPONSE_INFO_WAS_SPDY) != 0;
270 was_npn_negotiated = (flags & RESPONSE_INFO_WAS_NPN) != 0;
272 was_fetched_via_proxy = (flags & RESPONSE_INFO_WAS_PROXY) != 0;
274 *response_truncated = (flags & RESPONSE_INFO_TRUNCATED) != 0;
276 did_use_http_auth = (flags & RESPONSE_INFO_USE_HTTP_AUTHENTICATION) != 0;
281 void HttpResponseInfo::Persist(Pickle* pickle,
282 bool skip_transient_headers,
283 bool response_truncated) const {
284 int flags = RESPONSE_INFO_VERSION;
285 if (ssl_info.is_valid()) {
286 flags |= RESPONSE_INFO_HAS_CERT;
287 flags |= RESPONSE_INFO_HAS_CERT_STATUS;
288 if (ssl_info.security_bits != -1)
289 flags |= RESPONSE_INFO_HAS_SECURITY_BITS;
290 if (ssl_info.connection_status != 0)
291 flags |= RESPONSE_INFO_HAS_SSL_CONNECTION_STATUS;
293 if (vary_data.is_valid())
294 flags |= RESPONSE_INFO_HAS_VARY_DATA;
295 if (response_truncated)
296 flags |= RESPONSE_INFO_TRUNCATED;
297 if (was_fetched_via_spdy)
298 flags |= RESPONSE_INFO_WAS_SPDY;
299 if (was_npn_negotiated) {
300 flags |= RESPONSE_INFO_WAS_NPN;
301 flags |= RESPONSE_INFO_HAS_NPN_NEGOTIATED_PROTOCOL;
303 if (was_fetched_via_proxy)
304 flags |= RESPONSE_INFO_WAS_PROXY;
305 if (connection_info != CONNECTION_INFO_UNKNOWN)
306 flags |= RESPONSE_INFO_HAS_CONNECTION_INFO;
307 if (did_use_http_auth)
308 flags |= RESPONSE_INFO_USE_HTTP_AUTHENTICATION;
309 if (!ssl_info.signed_certificate_timestamps.empty())
310 flags |= RESPONSE_INFO_HAS_SIGNED_CERTIFICATE_TIMESTAMPS;
312 pickle->WriteInt(flags);
313 pickle->WriteInt64(request_time.ToInternalValue());
314 pickle->WriteInt64(response_time.ToInternalValue());
316 net::HttpResponseHeaders::PersistOptions persist_options =
317 net::HttpResponseHeaders::PERSIST_RAW;
319 if (skip_transient_headers) {
321 net::HttpResponseHeaders::PERSIST_SANS_COOKIES |
322 net::HttpResponseHeaders::PERSIST_SANS_CHALLENGES |
323 net::HttpResponseHeaders::PERSIST_SANS_HOP_BY_HOP |
324 net::HttpResponseHeaders::PERSIST_SANS_NON_CACHEABLE |
325 net::HttpResponseHeaders::PERSIST_SANS_RANGES |
326 net::HttpResponseHeaders::PERSIST_SANS_SECURITY_STATE;
329 headers->Persist(pickle, persist_options);
331 if (ssl_info.is_valid()) {
332 ssl_info.cert->Persist(pickle);
333 pickle->WriteUInt32(ssl_info.cert_status);
334 if (ssl_info.security_bits != -1)
335 pickle->WriteInt(ssl_info.security_bits);
336 if (ssl_info.connection_status != 0)
337 pickle->WriteInt(ssl_info.connection_status);
338 if (!ssl_info.signed_certificate_timestamps.empty()) {
339 pickle->WriteInt(ssl_info.signed_certificate_timestamps.size());
340 for (SignedCertificateTimestampAndStatusList::const_iterator it =
341 ssl_info.signed_certificate_timestamps.begin(); it !=
342 ssl_info.signed_certificate_timestamps.end(); ++it) {
343 it->sct->Persist(pickle);
344 pickle->WriteUInt16(it->status);
349 if (vary_data.is_valid())
350 vary_data.Persist(pickle);
352 pickle->WriteString(socket_address.host());
353 pickle->WriteUInt16(socket_address.port());
355 if (was_npn_negotiated)
356 pickle->WriteString(npn_negotiated_protocol);
358 if (connection_info != CONNECTION_INFO_UNKNOWN)
359 pickle->WriteInt(static_cast<int>(connection_info));
362 HttpResponseInfo::ConnectionInfo HttpResponseInfo::ConnectionInfoFromNextProto(
363 NextProto next_proto) {
364 switch (next_proto) {
365 case kProtoDeprecatedSPDY2:
366 return CONNECTION_INFO_DEPRECATED_SPDY2;
369 return CONNECTION_INFO_SPDY3;
371 return CONNECTION_INFO_SPDY4;
372 case kProtoQUIC1SPDY3:
373 return CONNECTION_INFO_QUIC1_SPDY3;
381 return CONNECTION_INFO_UNKNOWN;
385 std::string HttpResponseInfo::ConnectionInfoToString(
386 ConnectionInfo connection_info) {
387 switch (connection_info) {
388 case CONNECTION_INFO_UNKNOWN:
390 case CONNECTION_INFO_HTTP1:
392 case CONNECTION_INFO_DEPRECATED_SPDY2:
394 case CONNECTION_INFO_SPDY3:
396 case CONNECTION_INFO_SPDY4:
397 // This is the HTTP/2 draft 11 identifier. For internal
398 // consistency, HTTP/2 is named SPDY4 within Chromium.
400 case CONNECTION_INFO_QUIC1_SPDY3:
401 return "quic/1+spdy/3";
402 case NUM_OF_CONNECTION_INFOS: