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