http_response_info.cc revision 2a99a7e74a7f215066514fe81d2bfa6639d9eddd
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.
4
5#include "net/http/http_response_info.h"
6
7#include "base/logging.h"
8#include "base/pickle.h"
9#include "base/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/base/x509_certificate.h"
14#include "net/http/http_response_headers.h"
15#include "net/ssl/ssl_cert_request_info.h"
16
17using base::Time;
18
19namespace net {
20
21namespace {
22
23X509Certificate::PickleType GetPickleTypeForVersion(int version) {
24  switch (version) {
25    case 1:
26      return X509Certificate::PICKLETYPE_SINGLE_CERTIFICATE;
27    case 2:
28      return X509Certificate::PICKLETYPE_CERTIFICATE_CHAIN_V2;
29    case 3:
30    default:
31      return X509Certificate::PICKLETYPE_CERTIFICATE_CHAIN_V3;
32  }
33}
34
35}  // namespace
36
37// These values can be bit-wise combined to form the flags field of the
38// serialized HttpResponseInfo.
39enum {
40  // The version of the response info used when persisting response info.
41  RESPONSE_INFO_VERSION = 3,
42
43  // The minimum version supported for deserializing response info.
44  RESPONSE_INFO_MINIMUM_VERSION = 1,
45
46  // We reserve up to 8 bits for the version number.
47  RESPONSE_INFO_VERSION_MASK = 0xFF,
48
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,
53
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,
57
58  // This bit is set if the response info has a cert status at the end.
59  RESPONSE_INFO_HAS_CERT_STATUS = 1 << 10,
60
61  // This bit is set if the response info has vary header data.
62  RESPONSE_INFO_HAS_VARY_DATA = 1 << 11,
63
64  // This bit is set if the request was cancelled before completion.
65  RESPONSE_INFO_TRUNCATED = 1 << 12,
66
67  // This bit is set if the response was received via SPDY.
68  RESPONSE_INFO_WAS_SPDY = 1 << 13,
69
70  // This bit is set if the request has NPN negotiated.
71  RESPONSE_INFO_WAS_NPN = 1 << 14,
72
73  // This bit is set if the request was fetched via an explicit proxy.
74  RESPONSE_INFO_WAS_PROXY = 1 << 15,
75
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,
80
81  // This bit is set if the response info has protocol version.
82  RESPONSE_INFO_HAS_NPN_NEGOTIATED_PROTOCOL = 1 << 17,
83
84  // This bit is set if the response info has connection info.
85  RESPONSE_INFO_HAS_CONNECTION_INFO = 1 << 18,
86
87  // TODO(darin): Add other bits to indicate alternate request methods.
88  // For now, we don't support storing those.
89};
90
91HttpResponseInfo::HttpResponseInfo()
92    : was_cached(false),
93      server_data_unavailable(false),
94      was_fetched_via_spdy(false),
95      was_npn_negotiated(false),
96      was_fetched_via_proxy(false),
97      connection_info(CONNECTION_INFO_UNKNOWN) {
98}
99
100HttpResponseInfo::HttpResponseInfo(const HttpResponseInfo& rhs)
101    : was_cached(rhs.was_cached),
102      server_data_unavailable(rhs.server_data_unavailable),
103      was_fetched_via_spdy(rhs.was_fetched_via_spdy),
104      was_npn_negotiated(rhs.was_npn_negotiated),
105      was_fetched_via_proxy(rhs.was_fetched_via_proxy),
106      socket_address(rhs.socket_address),
107      npn_negotiated_protocol(rhs.npn_negotiated_protocol),
108      connection_info(rhs.connection_info),
109      request_time(rhs.request_time),
110      response_time(rhs.response_time),
111      auth_challenge(rhs.auth_challenge),
112      cert_request_info(rhs.cert_request_info),
113      ssl_info(rhs.ssl_info),
114      headers(rhs.headers),
115      vary_data(rhs.vary_data),
116      metadata(rhs.metadata) {
117}
118
119HttpResponseInfo::~HttpResponseInfo() {
120}
121
122HttpResponseInfo& HttpResponseInfo::operator=(const HttpResponseInfo& rhs) {
123  was_cached = rhs.was_cached;
124  server_data_unavailable = rhs.server_data_unavailable;
125  was_fetched_via_spdy = rhs.was_fetched_via_spdy;
126  was_npn_negotiated = rhs.was_npn_negotiated;
127  was_fetched_via_proxy = rhs.was_fetched_via_proxy;
128  socket_address = rhs.socket_address;
129  npn_negotiated_protocol = rhs.npn_negotiated_protocol;
130  request_time = rhs.request_time;
131  response_time = rhs.response_time;
132  auth_challenge = rhs.auth_challenge;
133  cert_request_info = rhs.cert_request_info;
134  ssl_info = rhs.ssl_info;
135  headers = rhs.headers;
136  vary_data = rhs.vary_data;
137  metadata = rhs.metadata;
138  return *this;
139}
140
141bool HttpResponseInfo::InitFromPickle(const Pickle& pickle,
142                                      bool* response_truncated) {
143  PickleIterator iter(pickle);
144
145  // Read flags and verify version
146  int flags;
147  if (!pickle.ReadInt(&iter, &flags))
148    return false;
149  int version = flags & RESPONSE_INFO_VERSION_MASK;
150  if (version < RESPONSE_INFO_MINIMUM_VERSION ||
151      version > RESPONSE_INFO_VERSION) {
152    DLOG(ERROR) << "unexpected response info version: " << version;
153    return false;
154  }
155
156  // Read request-time
157  int64 time_val;
158  if (!pickle.ReadInt64(&iter, &time_val))
159    return false;
160  request_time = Time::FromInternalValue(time_val);
161  was_cached = true;  // Set status to show cache resurrection.
162
163  // Read response-time
164  if (!pickle.ReadInt64(&iter, &time_val))
165    return false;
166  response_time = Time::FromInternalValue(time_val);
167
168  // Read response-headers
169  headers = new HttpResponseHeaders(pickle, &iter);
170  if (headers->response_code() == -1)
171    return false;
172
173  // Read ssl-info
174  if (flags & RESPONSE_INFO_HAS_CERT) {
175    X509Certificate::PickleType type = GetPickleTypeForVersion(version);
176    ssl_info.cert = X509Certificate::CreateFromPickle(pickle, &iter, type);
177    if (!ssl_info.cert)
178      return false;
179  }
180  if (flags & RESPONSE_INFO_HAS_CERT_STATUS) {
181    CertStatus cert_status;
182    if (!pickle.ReadUInt32(&iter, &cert_status))
183      return false;
184    ssl_info.cert_status = cert_status;
185  }
186  if (flags & RESPONSE_INFO_HAS_SECURITY_BITS) {
187    int security_bits;
188    if (!pickle.ReadInt(&iter, &security_bits))
189      return false;
190    ssl_info.security_bits = security_bits;
191  }
192
193  if (flags & RESPONSE_INFO_HAS_SSL_CONNECTION_STATUS) {
194    int connection_status;
195    if (!pickle.ReadInt(&iter, &connection_status))
196      return false;
197    ssl_info.connection_status = connection_status;
198  }
199
200  // Read vary-data
201  if (flags & RESPONSE_INFO_HAS_VARY_DATA) {
202    if (!vary_data.InitFromPickle(pickle, &iter))
203      return false;
204  }
205
206  // Read socket_address.
207  std::string socket_address_host;
208  if (pickle.ReadString(&iter, &socket_address_host)) {
209    // If the host was written, we always expect the port to follow.
210    uint16 socket_address_port;
211    if (!pickle.ReadUInt16(&iter, &socket_address_port))
212      return false;
213    socket_address = HostPortPair(socket_address_host, socket_address_port);
214  } else if (version > 1) {
215    // socket_address was not always present in version 1 of the response
216    // info, so we don't fail if it can't be read.
217    return false;
218  }
219
220  // Read protocol-version.
221  if (flags & RESPONSE_INFO_HAS_NPN_NEGOTIATED_PROTOCOL) {
222    if (!pickle.ReadString(&iter, &npn_negotiated_protocol))
223      return false;
224  }
225
226  // Read connection info.
227  if (flags & RESPONSE_INFO_HAS_CONNECTION_INFO) {
228    int value;
229    if (!pickle.ReadInt(&iter, &value))
230      return false;
231
232    if (value > static_cast<int>(CONNECTION_INFO_UNKNOWN) &&
233        value < static_cast<int>(NUM_OF_CONNECTION_INFOS)) {
234      connection_info = static_cast<ConnectionInfo>(value);
235    }
236  }
237
238  was_fetched_via_spdy = (flags & RESPONSE_INFO_WAS_SPDY) != 0;
239
240  was_npn_negotiated = (flags & RESPONSE_INFO_WAS_NPN) != 0;
241
242  was_fetched_via_proxy = (flags & RESPONSE_INFO_WAS_PROXY) != 0;
243
244  *response_truncated = (flags & RESPONSE_INFO_TRUNCATED) != 0;
245
246  return true;
247}
248
249void HttpResponseInfo::Persist(Pickle* pickle,
250                               bool skip_transient_headers,
251                               bool response_truncated) const {
252  int flags = RESPONSE_INFO_VERSION;
253  if (ssl_info.is_valid()) {
254    flags |= RESPONSE_INFO_HAS_CERT;
255    flags |= RESPONSE_INFO_HAS_CERT_STATUS;
256    if (ssl_info.security_bits != -1)
257      flags |= RESPONSE_INFO_HAS_SECURITY_BITS;
258    if (ssl_info.connection_status != 0)
259      flags |= RESPONSE_INFO_HAS_SSL_CONNECTION_STATUS;
260  }
261  if (vary_data.is_valid())
262    flags |= RESPONSE_INFO_HAS_VARY_DATA;
263  if (response_truncated)
264    flags |= RESPONSE_INFO_TRUNCATED;
265  if (was_fetched_via_spdy)
266    flags |= RESPONSE_INFO_WAS_SPDY;
267  if (was_npn_negotiated) {
268    flags |= RESPONSE_INFO_WAS_NPN;
269    flags |= RESPONSE_INFO_HAS_NPN_NEGOTIATED_PROTOCOL;
270  }
271  if (was_fetched_via_proxy)
272    flags |= RESPONSE_INFO_WAS_PROXY;
273  if (connection_info != CONNECTION_INFO_UNKNOWN)
274    flags |= RESPONSE_INFO_HAS_CONNECTION_INFO;
275
276  pickle->WriteInt(flags);
277  pickle->WriteInt64(request_time.ToInternalValue());
278  pickle->WriteInt64(response_time.ToInternalValue());
279
280  net::HttpResponseHeaders::PersistOptions persist_options =
281      net::HttpResponseHeaders::PERSIST_RAW;
282
283  if (skip_transient_headers) {
284    persist_options =
285        net::HttpResponseHeaders::PERSIST_SANS_COOKIES |
286        net::HttpResponseHeaders::PERSIST_SANS_CHALLENGES |
287        net::HttpResponseHeaders::PERSIST_SANS_HOP_BY_HOP |
288        net::HttpResponseHeaders::PERSIST_SANS_NON_CACHEABLE |
289        net::HttpResponseHeaders::PERSIST_SANS_RANGES |
290        net::HttpResponseHeaders::PERSIST_SANS_SECURITY_STATE;
291  }
292
293  headers->Persist(pickle, persist_options);
294
295  if (ssl_info.is_valid()) {
296    ssl_info.cert->Persist(pickle);
297    pickle->WriteUInt32(ssl_info.cert_status);
298    if (ssl_info.security_bits != -1)
299      pickle->WriteInt(ssl_info.security_bits);
300    if (ssl_info.connection_status != 0)
301      pickle->WriteInt(ssl_info.connection_status);
302  }
303
304  if (vary_data.is_valid())
305    vary_data.Persist(pickle);
306
307  pickle->WriteString(socket_address.host());
308  pickle->WriteUInt16(socket_address.port());
309
310  if (was_npn_negotiated)
311    pickle->WriteString(npn_negotiated_protocol);
312
313  if (connection_info != CONNECTION_INFO_UNKNOWN)
314    pickle->WriteInt(static_cast<int>(connection_info));
315}
316
317}  // namespace net
318