Home | History | Annotate | Download | only in http
      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/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/cert/signed_certificate_timestamp.h"
     14 #include "net/cert/x509_certificate.h"
     15 #include "net/http/http_response_headers.h"
     16 #include "net/ssl/ssl_cert_request_info.h"
     17 
     18 using base::Time;
     19 
     20 namespace net {
     21 
     22 namespace {
     23 
     24 X509Certificate::PickleType GetPickleTypeForVersion(int version) {
     25   switch (version) {
     26     case 1:
     27       return X509Certificate::PICKLETYPE_SINGLE_CERTIFICATE;
     28     case 2:
     29       return X509Certificate::PICKLETYPE_CERTIFICATE_CHAIN_V2;
     30     case 3:
     31     default:
     32       return X509Certificate::PICKLETYPE_CERTIFICATE_CHAIN_V3;
     33   }
     34 }
     35 
     36 }  // namespace
     37 
     38 // These values can be bit-wise combined to form the flags field of the
     39 // serialized HttpResponseInfo.
     40 enum {
     41   // The version of the response info used when persisting response info.
     42   RESPONSE_INFO_VERSION = 3,
     43 
     44   // The minimum version supported for deserializing response info.
     45   RESPONSE_INFO_MINIMUM_VERSION = 1,
     46 
     47   // We reserve up to 8 bits for the version number.
     48   RESPONSE_INFO_VERSION_MASK = 0xFF,
     49 
     50   // This bit is set if the response info has a cert at the end.
     51   // Version 1 serialized only the end-entity certificate, while subsequent
     52   // versions include the available certificate chain.
     53   RESPONSE_INFO_HAS_CERT = 1 << 8,
     54 
     55   // This bit is set if the response info has a security-bits field (security
     56   // strength, in bits, of the SSL connection) at the end.
     57   RESPONSE_INFO_HAS_SECURITY_BITS = 1 << 9,
     58 
     59   // This bit is set if the response info has a cert status at the end.
     60   RESPONSE_INFO_HAS_CERT_STATUS = 1 << 10,
     61 
     62   // This bit is set if the response info has vary header data.
     63   RESPONSE_INFO_HAS_VARY_DATA = 1 << 11,
     64 
     65   // This bit is set if the request was cancelled before completion.
     66   RESPONSE_INFO_TRUNCATED = 1 << 12,
     67 
     68   // This bit is set if the response was received via SPDY.
     69   RESPONSE_INFO_WAS_SPDY = 1 << 13,
     70 
     71   // This bit is set if the request has NPN negotiated.
     72   RESPONSE_INFO_WAS_NPN = 1 << 14,
     73 
     74   // This bit is set if the request was fetched via an explicit proxy.
     75   RESPONSE_INFO_WAS_PROXY = 1 << 15,
     76 
     77   // This bit is set if the response info has an SSL connection status field.
     78   // This contains the ciphersuite used to fetch the resource as well as the
     79   // protocol version, compression method and whether SSLv3 fallback was used.
     80   RESPONSE_INFO_HAS_SSL_CONNECTION_STATUS = 1 << 16,
     81 
     82   // This bit is set if the response info has protocol version.
     83   RESPONSE_INFO_HAS_NPN_NEGOTIATED_PROTOCOL = 1 << 17,
     84 
     85   // This bit is set if the response info has connection info.
     86   RESPONSE_INFO_HAS_CONNECTION_INFO = 1 << 18,
     87 
     88   // This bit is set if the request has http authentication.
     89   RESPONSE_INFO_USE_HTTP_AUTHENTICATION = 1 << 19,
     90 
     91   // This bit is set if ssl_info has SCTs.
     92   RESPONSE_INFO_HAS_SIGNED_CERTIFICATE_TIMESTAMPS = 1 << 20,
     93 
     94   // TODO(darin): Add other bits to indicate alternate request methods.
     95   // For now, we don't support storing those.
     96 };
     97 
     98 HttpResponseInfo::HttpResponseInfo()
     99     : was_cached(false),
    100       server_data_unavailable(false),
    101       network_accessed(false),
    102       was_fetched_via_spdy(false),
    103       was_npn_negotiated(false),
    104       was_fetched_via_proxy(false),
    105       did_use_http_auth(false),
    106       connection_info(CONNECTION_INFO_UNKNOWN) {
    107 }
    108 
    109 HttpResponseInfo::HttpResponseInfo(const HttpResponseInfo& rhs)
    110     : was_cached(rhs.was_cached),
    111       server_data_unavailable(rhs.server_data_unavailable),
    112       network_accessed(rhs.network_accessed),
    113       was_fetched_via_spdy(rhs.was_fetched_via_spdy),
    114       was_npn_negotiated(rhs.was_npn_negotiated),
    115       was_fetched_via_proxy(rhs.was_fetched_via_proxy),
    116       did_use_http_auth(rhs.did_use_http_auth),
    117       socket_address(rhs.socket_address),
    118       npn_negotiated_protocol(rhs.npn_negotiated_protocol),
    119       connection_info(rhs.connection_info),
    120       request_time(rhs.request_time),
    121       response_time(rhs.response_time),
    122       auth_challenge(rhs.auth_challenge),
    123       cert_request_info(rhs.cert_request_info),
    124       ssl_info(rhs.ssl_info),
    125       headers(rhs.headers),
    126       vary_data(rhs.vary_data),
    127       metadata(rhs.metadata) {
    128 }
    129 
    130 HttpResponseInfo::~HttpResponseInfo() {
    131 }
    132 
    133 HttpResponseInfo& HttpResponseInfo::operator=(const HttpResponseInfo& rhs) {
    134   was_cached = rhs.was_cached;
    135   server_data_unavailable = rhs.server_data_unavailable;
    136   network_accessed = rhs.network_accessed;
    137   was_fetched_via_spdy = rhs.was_fetched_via_spdy;
    138   was_npn_negotiated = rhs.was_npn_negotiated;
    139   was_fetched_via_proxy = rhs.was_fetched_via_proxy;
    140   did_use_http_auth = rhs.did_use_http_auth;
    141   socket_address = rhs.socket_address;
    142   npn_negotiated_protocol = rhs.npn_negotiated_protocol;
    143   connection_info = rhs.connection_info;
    144   request_time = rhs.request_time;
    145   response_time = rhs.response_time;
    146   auth_challenge = rhs.auth_challenge;
    147   cert_request_info = rhs.cert_request_info;
    148   ssl_info = rhs.ssl_info;
    149   headers = rhs.headers;
    150   vary_data = rhs.vary_data;
    151   metadata = rhs.metadata;
    152   return *this;
    153 }
    154 
    155 bool HttpResponseInfo::InitFromPickle(const Pickle& pickle,
    156                                       bool* response_truncated) {
    157   PickleIterator iter(pickle);
    158 
    159   // Read flags and verify version
    160   int flags;
    161   if (!pickle.ReadInt(&iter, &flags))
    162     return false;
    163   int version = flags & RESPONSE_INFO_VERSION_MASK;
    164   if (version < RESPONSE_INFO_MINIMUM_VERSION ||
    165       version > RESPONSE_INFO_VERSION) {
    166     DLOG(ERROR) << "unexpected response info version: " << version;
    167     return false;
    168   }
    169 
    170   // Read request-time
    171   int64 time_val;
    172   if (!pickle.ReadInt64(&iter, &time_val))
    173     return false;
    174   request_time = Time::FromInternalValue(time_val);
    175   was_cached = true;  // Set status to show cache resurrection.
    176 
    177   // Read response-time
    178   if (!pickle.ReadInt64(&iter, &time_val))
    179     return false;
    180   response_time = Time::FromInternalValue(time_val);
    181 
    182   // Read response-headers
    183   headers = new HttpResponseHeaders(pickle, &iter);
    184   if (headers->response_code() == -1)
    185     return false;
    186 
    187   // Read ssl-info
    188   if (flags & RESPONSE_INFO_HAS_CERT) {
    189     X509Certificate::PickleType type = GetPickleTypeForVersion(version);
    190     ssl_info.cert = X509Certificate::CreateFromPickle(pickle, &iter, type);
    191     if (!ssl_info.cert.get())
    192       return false;
    193   }
    194   if (flags & RESPONSE_INFO_HAS_CERT_STATUS) {
    195     CertStatus cert_status;
    196     if (!pickle.ReadUInt32(&iter, &cert_status))
    197       return false;
    198     ssl_info.cert_status = cert_status;
    199   }
    200   if (flags & RESPONSE_INFO_HAS_SECURITY_BITS) {
    201     int security_bits;
    202     if (!pickle.ReadInt(&iter, &security_bits))
    203       return false;
    204     ssl_info.security_bits = security_bits;
    205   }
    206 
    207   if (flags & RESPONSE_INFO_HAS_SSL_CONNECTION_STATUS) {
    208     int connection_status;
    209     if (!pickle.ReadInt(&iter, &connection_status))
    210       return false;
    211     ssl_info.connection_status = connection_status;
    212   }
    213 
    214   if (flags & RESPONSE_INFO_HAS_SIGNED_CERTIFICATE_TIMESTAMPS) {
    215     int num_scts;
    216     if (!pickle.ReadInt(&iter, &num_scts))
    217       return false;
    218     for (int i = 0; i < num_scts; ++i) {
    219       scoped_refptr<ct::SignedCertificateTimestamp> sct(
    220           ct::SignedCertificateTimestamp::CreateFromPickle(&iter));
    221       uint16 status;
    222       if (!sct.get() || !pickle.ReadUInt16(&iter, &status))
    223         return false;
    224       ssl_info.signed_certificate_timestamps.push_back(
    225           SignedCertificateTimestampAndStatus(
    226               sct, static_cast<ct::SCTVerifyStatus>(status)));
    227     }
    228   }
    229 
    230   // Read vary-data
    231   if (flags & RESPONSE_INFO_HAS_VARY_DATA) {
    232     if (!vary_data.InitFromPickle(pickle, &iter))
    233       return false;
    234   }
    235 
    236   // Read socket_address.
    237   std::string socket_address_host;
    238   if (pickle.ReadString(&iter, &socket_address_host)) {
    239     // If the host was written, we always expect the port to follow.
    240     uint16 socket_address_port;
    241     if (!pickle.ReadUInt16(&iter, &socket_address_port))
    242       return false;
    243     socket_address = HostPortPair(socket_address_host, socket_address_port);
    244   } else if (version > 1) {
    245     // socket_address was not always present in version 1 of the response
    246     // info, so we don't fail if it can't be read.
    247     return false;
    248   }
    249 
    250   // Read protocol-version.
    251   if (flags & RESPONSE_INFO_HAS_NPN_NEGOTIATED_PROTOCOL) {
    252     if (!pickle.ReadString(&iter, &npn_negotiated_protocol))
    253       return false;
    254   }
    255 
    256   // Read connection info.
    257   if (flags & RESPONSE_INFO_HAS_CONNECTION_INFO) {
    258     int value;
    259     if (!pickle.ReadInt(&iter, &value))
    260       return false;
    261 
    262     if (value > static_cast<int>(CONNECTION_INFO_UNKNOWN) &&
    263         value < static_cast<int>(NUM_OF_CONNECTION_INFOS)) {
    264       connection_info = static_cast<ConnectionInfo>(value);
    265     }
    266   }
    267 
    268   was_fetched_via_spdy = (flags & RESPONSE_INFO_WAS_SPDY) != 0;
    269 
    270   was_npn_negotiated = (flags & RESPONSE_INFO_WAS_NPN) != 0;
    271 
    272   was_fetched_via_proxy = (flags & RESPONSE_INFO_WAS_PROXY) != 0;
    273 
    274   *response_truncated = (flags & RESPONSE_INFO_TRUNCATED) != 0;
    275 
    276   did_use_http_auth = (flags & RESPONSE_INFO_USE_HTTP_AUTHENTICATION) != 0;
    277 
    278   return true;
    279 }
    280 
    281 void HttpResponseInfo::Persist(Pickle* pickle,
    282                                bool skip_transient_headers,
    283                                bool response_truncated) const {
    284   int flags = RESPONSE_INFO_VERSION;
    285   if (ssl_info.is_valid()) {
    286     flags |= RESPONSE_INFO_HAS_CERT;
    287     flags |= RESPONSE_INFO_HAS_CERT_STATUS;
    288     if (ssl_info.security_bits != -1)
    289       flags |= RESPONSE_INFO_HAS_SECURITY_BITS;
    290     if (ssl_info.connection_status != 0)
    291       flags |= RESPONSE_INFO_HAS_SSL_CONNECTION_STATUS;
    292   }
    293   if (vary_data.is_valid())
    294     flags |= RESPONSE_INFO_HAS_VARY_DATA;
    295   if (response_truncated)
    296     flags |= RESPONSE_INFO_TRUNCATED;
    297   if (was_fetched_via_spdy)
    298     flags |= RESPONSE_INFO_WAS_SPDY;
    299   if (was_npn_negotiated) {
    300     flags |= RESPONSE_INFO_WAS_NPN;
    301     flags |= RESPONSE_INFO_HAS_NPN_NEGOTIATED_PROTOCOL;
    302   }
    303   if (was_fetched_via_proxy)
    304     flags |= RESPONSE_INFO_WAS_PROXY;
    305   if (connection_info != CONNECTION_INFO_UNKNOWN)
    306     flags |= RESPONSE_INFO_HAS_CONNECTION_INFO;
    307   if (did_use_http_auth)
    308     flags |= RESPONSE_INFO_USE_HTTP_AUTHENTICATION;
    309   if (!ssl_info.signed_certificate_timestamps.empty())
    310     flags |= RESPONSE_INFO_HAS_SIGNED_CERTIFICATE_TIMESTAMPS;
    311 
    312   pickle->WriteInt(flags);
    313   pickle->WriteInt64(request_time.ToInternalValue());
    314   pickle->WriteInt64(response_time.ToInternalValue());
    315 
    316   net::HttpResponseHeaders::PersistOptions persist_options =
    317       net::HttpResponseHeaders::PERSIST_RAW;
    318 
    319   if (skip_transient_headers) {
    320     persist_options =
    321         net::HttpResponseHeaders::PERSIST_SANS_COOKIES |
    322         net::HttpResponseHeaders::PERSIST_SANS_CHALLENGES |
    323         net::HttpResponseHeaders::PERSIST_SANS_HOP_BY_HOP |
    324         net::HttpResponseHeaders::PERSIST_SANS_NON_CACHEABLE |
    325         net::HttpResponseHeaders::PERSIST_SANS_RANGES |
    326         net::HttpResponseHeaders::PERSIST_SANS_SECURITY_STATE;
    327   }
    328 
    329   headers->Persist(pickle, persist_options);
    330 
    331   if (ssl_info.is_valid()) {
    332     ssl_info.cert->Persist(pickle);
    333     pickle->WriteUInt32(ssl_info.cert_status);
    334     if (ssl_info.security_bits != -1)
    335       pickle->WriteInt(ssl_info.security_bits);
    336     if (ssl_info.connection_status != 0)
    337       pickle->WriteInt(ssl_info.connection_status);
    338     if (!ssl_info.signed_certificate_timestamps.empty()) {
    339       pickle->WriteInt(ssl_info.signed_certificate_timestamps.size());
    340       for (SignedCertificateTimestampAndStatusList::const_iterator it =
    341            ssl_info.signed_certificate_timestamps.begin(); it !=
    342            ssl_info.signed_certificate_timestamps.end(); ++it) {
    343         it->sct_->Persist(pickle);
    344         pickle->WriteUInt16(it->status_);
    345       }
    346     }
    347   }
    348 
    349   if (vary_data.is_valid())
    350     vary_data.Persist(pickle);
    351 
    352   pickle->WriteString(socket_address.host());
    353   pickle->WriteUInt16(socket_address.port());
    354 
    355   if (was_npn_negotiated)
    356     pickle->WriteString(npn_negotiated_protocol);
    357 
    358   if (connection_info != CONNECTION_INFO_UNKNOWN)
    359     pickle->WriteInt(static_cast<int>(connection_info));
    360 }
    361 
    362 HttpResponseInfo::ConnectionInfo HttpResponseInfo::ConnectionInfoFromNextProto(
    363     NextProto next_proto) {
    364   switch (next_proto) {
    365     case kProtoDeprecatedSPDY2:
    366       return CONNECTION_INFO_DEPRECATED_SPDY2;
    367     case kProtoSPDY3:
    368     case kProtoSPDY31:
    369       return CONNECTION_INFO_SPDY3;
    370     case kProtoSPDY4a2:
    371       return CONNECTION_INFO_SPDY4A2;
    372     case kProtoHTTP2Draft04:
    373       return CONNECTION_INFO_HTTP2_DRAFT_04;
    374     case kProtoQUIC1SPDY3:
    375       return CONNECTION_INFO_QUIC1_SPDY3;
    376 
    377     case kProtoUnknown:
    378     case kProtoHTTP11:
    379       break;
    380   }
    381 
    382   NOTREACHED();
    383   return CONNECTION_INFO_UNKNOWN;
    384 }
    385 
    386 // static
    387 std::string HttpResponseInfo::ConnectionInfoToString(
    388     ConnectionInfo connection_info) {
    389   switch (connection_info) {
    390     case CONNECTION_INFO_UNKNOWN:
    391       return "unknown";
    392     case CONNECTION_INFO_HTTP1:
    393       return "http/1";
    394     case CONNECTION_INFO_DEPRECATED_SPDY2:
    395       return "spdy/2";
    396     case CONNECTION_INFO_SPDY3:
    397       return "spdy/3";
    398     case CONNECTION_INFO_SPDY4A2:
    399       return "spdy/4a2";
    400     case CONNECTION_INFO_HTTP2_DRAFT_04:
    401       return "HTTP-draft-04/2.0";
    402     case CONNECTION_INFO_QUIC1_SPDY3:
    403       return "quic/1+spdy/3";
    404     case NUM_OF_CONNECTION_INFOS:
    405       break;
    406   }
    407   NOTREACHED();
    408   return "";
    409 }
    410 
    411 }  // namespace net
    412