Home | History | Annotate | Download | only in http
      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 
     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 
     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 
     85 HttpResponseInfo::~HttpResponseInfo() {
     86 }
     87 
     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 
    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 
    187 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