http_response_info.cc revision dc0f95d653279beabeb9817299e2902918ba123e
1// Copyright (c) 2010 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/ssl_cert_request_info.h"
14#include "net/base/x509_certificate.h"
15#include "net/http/http_response_headers.h"
16
17using base::Time;
18
19namespace net {
20
21// These values can be bit-wise combined to form the flags field of the
22// serialized HttpResponseInfo.
23enum {
24  // The version of the response info used when persisting response info.
25  RESPONSE_INFO_VERSION = 1,
26
27  // We reserve up to 8 bits for the version number.
28  RESPONSE_INFO_VERSION_MASK = 0xFF,
29
30  // This bit is set if the response info has a cert at the end.
31  RESPONSE_INFO_HAS_CERT = 1 << 8,
32
33  // This bit is set if the response info has a security-bits field (security
34  // strength, in bits, of the SSL connection) at the end.
35  RESPONSE_INFO_HAS_SECURITY_BITS = 1 << 9,
36
37  // This bit is set if the response info has a cert status at the end.
38  RESPONSE_INFO_HAS_CERT_STATUS = 1 << 10,
39
40  // This bit is set if the response info has vary header data.
41  RESPONSE_INFO_HAS_VARY_DATA = 1 << 11,
42
43  // This bit is set if the request was cancelled before completion.
44  RESPONSE_INFO_TRUNCATED = 1 << 12,
45
46  // This bit is set if the response was received via SPDY.
47  RESPONSE_INFO_WAS_SPDY = 1 << 13,
48
49  // This bit is set if the request has NPN negotiated.
50  RESPONSE_INFO_WAS_NPN = 1 << 14,
51
52  // This bit is set if the request was fetched via an explicit proxy.
53  RESPONSE_INFO_WAS_PROXY = 1 << 15,
54
55  // This bit is set if response could use alternate protocol. However, browser
56  // will ingore the alternate protocol if spdy is not enabled.
57  RESPONSE_INFO_WAS_ALTERNATE_PROTOCOL_AVAILABLE = 1 << 16,
58
59  // TODO(darin): Add other bits to indicate alternate request methods.
60  // For now, we don't support storing those.
61};
62
63HttpResponseInfo::HttpResponseInfo()
64    : was_cached(false),
65      was_fetched_via_spdy(false),
66      was_npn_negotiated(false),
67      was_alternate_protocol_available(false),
68      was_fetched_via_proxy(false) {
69}
70
71HttpResponseInfo::HttpResponseInfo(const HttpResponseInfo& rhs)
72    : was_cached(rhs.was_cached),
73      was_fetched_via_spdy(rhs.was_fetched_via_spdy),
74      was_npn_negotiated(rhs.was_npn_negotiated),
75      was_alternate_protocol_available(rhs.was_alternate_protocol_available),
76      was_fetched_via_proxy(rhs.was_fetched_via_proxy),
77      socket_address(rhs.socket_address),
78      request_time(rhs.request_time),
79      response_time(rhs.response_time),
80      auth_challenge(rhs.auth_challenge),
81      cert_request_info(rhs.cert_request_info),
82      ssl_info(rhs.ssl_info),
83      headers(rhs.headers),
84      vary_data(rhs.vary_data),
85      metadata(rhs.metadata) {
86}
87
88HttpResponseInfo::~HttpResponseInfo() {
89}
90
91HttpResponseInfo& HttpResponseInfo::operator=(const HttpResponseInfo& rhs) {
92  was_cached = rhs.was_cached;
93  was_fetched_via_spdy = rhs.was_fetched_via_spdy;
94  was_npn_negotiated = rhs.was_npn_negotiated;
95  was_alternate_protocol_available = rhs.was_alternate_protocol_available;
96  was_fetched_via_proxy = rhs.was_fetched_via_proxy;
97  socket_address = rhs.socket_address;
98  request_time = rhs.request_time;
99  response_time = rhs.response_time;
100  auth_challenge = rhs.auth_challenge;
101  cert_request_info = rhs.cert_request_info;
102  ssl_info = rhs.ssl_info;
103  headers = rhs.headers;
104  vary_data = rhs.vary_data;
105  metadata = rhs.metadata;
106  return *this;
107}
108
109bool HttpResponseInfo::InitFromPickle(const Pickle& pickle,
110                                      bool* response_truncated) {
111  void* iter = NULL;
112
113  // read flags and verify version
114  int flags;
115  if (!pickle.ReadInt(&iter, &flags))
116    return false;
117  int version = flags & RESPONSE_INFO_VERSION_MASK;
118  if (version != RESPONSE_INFO_VERSION) {
119    DLOG(ERROR) << "unexpected response info version: " << version;
120    return false;
121  }
122
123  // read request-time
124  int64 time_val;
125  if (!pickle.ReadInt64(&iter, &time_val))
126    return false;
127  request_time = Time::FromInternalValue(time_val);
128  was_cached = true;  // Set status to show cache resurrection.
129
130  // read response-time
131  if (!pickle.ReadInt64(&iter, &time_val))
132    return false;
133  response_time = Time::FromInternalValue(time_val);
134
135  // read response-headers
136  headers = new HttpResponseHeaders(pickle, &iter);
137  DCHECK_NE(headers->response_code(), -1);
138
139  // read ssl-info
140  if (flags & RESPONSE_INFO_HAS_CERT) {
141    ssl_info.cert =
142        X509Certificate::CreateFromPickle(pickle, &iter);
143  }
144  if (flags & RESPONSE_INFO_HAS_CERT_STATUS) {
145    int cert_status;
146    if (!pickle.ReadInt(&iter, &cert_status))
147      return false;
148    ssl_info.cert_status = cert_status;
149  }
150  if (flags & RESPONSE_INFO_HAS_SECURITY_BITS) {
151    int security_bits;
152    if (!pickle.ReadInt(&iter, &security_bits))
153      return false;
154    ssl_info.security_bits = security_bits;
155  }
156
157  // read vary-data
158  if (flags & RESPONSE_INFO_HAS_VARY_DATA) {
159    if (!vary_data.InitFromPickle(pickle, &iter))
160      return false;
161  }
162
163  // Read socket_address.  This was not always present in the response info,
164  // so we don't fail if it can't be read.  If additional fields are added in
165  // a future version, then they must only be read if this operation succeeds.
166  std::string socket_address_host;
167  if (pickle.ReadString(&iter, &socket_address_host)) {
168    // If the host was written, we always expect the port to follow.
169    uint16 socket_address_port;
170    if (!pickle.ReadUInt16(&iter, &socket_address_port))
171      return false;
172    socket_address = HostPortPair(socket_address_host, socket_address_port);
173  }
174
175  was_fetched_via_spdy = (flags & RESPONSE_INFO_WAS_SPDY) != 0;
176
177  was_npn_negotiated = (flags & RESPONSE_INFO_WAS_NPN) != 0;
178
179  was_alternate_protocol_available =
180      (flags & RESPONSE_INFO_WAS_ALTERNATE_PROTOCOL_AVAILABLE) != 0;
181
182  was_fetched_via_proxy = (flags & RESPONSE_INFO_WAS_PROXY) != 0;
183
184  *response_truncated = (flags & RESPONSE_INFO_TRUNCATED) ? true : false;
185
186  return true;
187}
188
189void HttpResponseInfo::Persist(Pickle* pickle,
190                               bool skip_transient_headers,
191                               bool response_truncated) const {
192  int flags = RESPONSE_INFO_VERSION;
193  if (ssl_info.is_valid()) {
194    flags |= RESPONSE_INFO_HAS_CERT;
195    flags |= RESPONSE_INFO_HAS_CERT_STATUS;
196    if (ssl_info.security_bits != -1)
197      flags |= RESPONSE_INFO_HAS_SECURITY_BITS;
198    // TODO(wtc): we should persist ssl_info.connection_status.
199  }
200  if (vary_data.is_valid())
201    flags |= RESPONSE_INFO_HAS_VARY_DATA;
202  if (response_truncated)
203    flags |= RESPONSE_INFO_TRUNCATED;
204  if (was_fetched_via_spdy)
205    flags |= RESPONSE_INFO_WAS_SPDY;
206  if (was_npn_negotiated)
207    flags |= RESPONSE_INFO_WAS_NPN;
208  if (was_alternate_protocol_available)
209    flags |= RESPONSE_INFO_WAS_ALTERNATE_PROTOCOL_AVAILABLE;
210  if (was_fetched_via_proxy)
211    flags |= RESPONSE_INFO_WAS_PROXY;
212
213  pickle->WriteInt(flags);
214  pickle->WriteInt64(request_time.ToInternalValue());
215  pickle->WriteInt64(response_time.ToInternalValue());
216
217  net::HttpResponseHeaders::PersistOptions persist_options =
218      net::HttpResponseHeaders::PERSIST_RAW;
219
220  if (skip_transient_headers) {
221    persist_options =
222        net::HttpResponseHeaders::PERSIST_SANS_COOKIES |
223        net::HttpResponseHeaders::PERSIST_SANS_CHALLENGES |
224        net::HttpResponseHeaders::PERSIST_SANS_HOP_BY_HOP |
225        net::HttpResponseHeaders::PERSIST_SANS_NON_CACHEABLE |
226        net::HttpResponseHeaders::PERSIST_SANS_RANGES;
227  }
228
229  headers->Persist(pickle, persist_options);
230
231  if (ssl_info.is_valid()) {
232    ssl_info.cert->Persist(pickle);
233    pickle->WriteInt(ssl_info.cert_status);
234    if (ssl_info.security_bits != -1)
235      pickle->WriteInt(ssl_info.security_bits);
236  }
237
238  if (vary_data.is_valid())
239    vary_data.Persist(pickle);
240
241  pickle->WriteString(socket_address.host());
242  pickle->WriteUInt16(socket_address.port());
243}
244
245}  // namespace net
246