Expose OpenSSL's key_exchange_info in the content API
[chromium-blink-merge.git] / net / http / http_response_info.cc
blobfa9d63cccb401acc2c2153a61b6102f4627585ce
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"
18 using base::Time;
20 namespace net {
22 namespace {
24 X509Certificate::PickleType GetPickleTypeForVersion(int version) {
25 switch (version) {
26 case 1:
27 return X509Certificate::PICKLETYPE_SINGLE_CERTIFICATE;
28 case 2:
29 return X509Certificate::PICKLETYPE_CERTIFICATE_CHAIN_V2;
30 case 3:
31 default:
32 return X509Certificate::PICKLETYPE_CERTIFICATE_CHAIN_V3;
36 } // namespace
38 // These values can be bit-wise combined to form the flags field of the
39 // serialized HttpResponseInfo.
40 enum {
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()
104 : was_cached(false),
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;
163 return *this;
166 bool HttpResponseInfo::InitFromPickle(const base::Pickle& pickle,
167 bool* response_truncated) {
168 base::PickleIterator iter(pickle);
170 // Read flags and verify version
171 int flags;
172 if (!iter.ReadInt(&flags))
173 return false;
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;
178 return false;
181 // Read request-time
182 int64 time_val;
183 if (!iter.ReadInt64(&time_val))
184 return false;
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))
190 return false;
191 response_time = Time::FromInternalValue(time_val);
193 // Read response-headers
194 headers = new HttpResponseHeaders(&iter);
195 if (headers->response_code() == -1)
196 return false;
198 // Read ssl-info
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())
203 return false;
205 if (flags & RESPONSE_INFO_HAS_CERT_STATUS) {
206 CertStatus cert_status;
207 if (!iter.ReadUInt32(&cert_status))
208 return false;
209 ssl_info.cert_status = cert_status;
211 if (flags & RESPONSE_INFO_HAS_SECURITY_BITS) {
212 int security_bits;
213 if (!iter.ReadInt(&security_bits))
214 return false;
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))
221 return false;
222 ssl_info.connection_status = connection_status;
225 if (flags & RESPONSE_INFO_HAS_SIGNED_CERTIFICATE_TIMESTAMPS) {
226 int num_scts;
227 if (!iter.ReadInt(&num_scts))
228 return false;
229 for (int i = 0; i < num_scts; ++i) {
230 scoped_refptr<ct::SignedCertificateTimestamp> sct(
231 ct::SignedCertificateTimestamp::CreateFromPickle(&iter));
232 uint16 status;
233 if (!sct.get() || !iter.ReadUInt16(&status))
234 return false;
235 ssl_info.signed_certificate_timestamps.push_back(
236 SignedCertificateTimestampAndStatus(
237 sct, static_cast<ct::SCTVerifyStatus>(status)));
241 // Read vary-data
242 if (flags & RESPONSE_INFO_HAS_VARY_DATA) {
243 if (!vary_data.InitFromPickle(&iter))
244 return false;
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))
253 return false;
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.
258 return false;
261 // Read protocol-version.
262 if (flags & RESPONSE_INFO_HAS_NPN_NEGOTIATED_PROTOCOL) {
263 if (!iter.ReadString(&npn_negotiated_protocol))
264 return false;
267 // Read connection info.
268 if (flags & RESPONSE_INFO_HAS_CONNECTION_INFO) {
269 int value;
270 if (!iter.ReadInt(&value))
271 return false;
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))
283 return false;
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;
299 return true;
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;
394 case kProtoSPDY3:
395 case kProtoSPDY31:
396 return CONNECTION_INFO_SPDY3;
397 case kProtoHTTP2:
398 return CONNECTION_INFO_HTTP2;
399 case kProtoQUIC1SPDY3:
400 return CONNECTION_INFO_QUIC1_SPDY3;
402 case kProtoUnknown:
403 case kProtoHTTP11:
404 break;
407 NOTREACHED();
408 return CONNECTION_INFO_UNKNOWN;
411 // static
412 std::string HttpResponseInfo::ConnectionInfoToString(
413 ConnectionInfo connection_info) {
414 switch (connection_info) {
415 case CONNECTION_INFO_UNKNOWN:
416 return "unknown";
417 case CONNECTION_INFO_HTTP1:
418 return "http/1";
419 case CONNECTION_INFO_DEPRECATED_SPDY2:
420 return "spdy/2";
421 case CONNECTION_INFO_SPDY3:
422 return "spdy/3";
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
425 // h2.
426 // Intentional fallthrough.
427 case CONNECTION_INFO_HTTP2_14:
428 case CONNECTION_INFO_HTTP2_15:
429 case CONNECTION_INFO_HTTP2:
430 return "h2";
431 case CONNECTION_INFO_QUIC1_SPDY3:
432 return "quic/1+spdy/3";
433 case NUM_OF_CONNECTION_INFOS:
434 break;
436 NOTREACHED();
437 return "";
440 } // namespace net