• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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