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