Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / net / http / http_network_transaction.cc
index ba27cb7..20ffdd1 100644 (file)
@@ -15,6 +15,7 @@
 #include "base/metrics/field_trial.h"
 #include "base/metrics/histogram.h"
 #include "base/metrics/stats_counters.h"
+#include "base/profiler/scoped_tracker.h"
 #include "base/stl_util.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
@@ -44,7 +45,7 @@
 #include "net/http/http_response_info.h"
 #include "net/http/http_server_properties.h"
 #include "net/http/http_status_code.h"
-#include "net/http/http_stream_base.h"
+#include "net/http/http_stream.h"
 #include "net/http/http_stream_factory.h"
 #include "net/http/http_util.h"
 #include "net/http/transport_security_state.h"
 #include "net/socket/ssl_client_socket.h"
 #include "net/socket/ssl_client_socket_pool.h"
 #include "net/socket/transport_client_socket_pool.h"
+#include "net/spdy/hpack_huffman_aggregator.h"
 #include "net/spdy/spdy_http_stream.h"
 #include "net/spdy/spdy_session.h"
 #include "net/spdy/spdy_session_pool.h"
 #include "net/ssl/ssl_cert_request_info.h"
 #include "net/ssl/ssl_connection_status_flags.h"
 #include "url/gurl.h"
-
-#if defined(SPDY_PROXY_AUTH_ORIGIN)
-#include <algorithm>
-#include "net/proxy/proxy_server.h"
-#endif
-
-
-using base::Time;
-using base::TimeDelta;
+#include "url/url_canon.h"
 
 namespace net {
 
 namespace {
 
 void ProcessAlternateProtocol(
-    HttpStreamFactory* factory,
-    const base::WeakPtr<HttpServerProperties>& http_server_properties,
+    HttpNetworkSession* session,
     const HttpResponseHeaders& headers,
     const HostPortPair& http_host_port_pair) {
-  std::string alternate_protocol_str;
-
-  if (!headers.EnumerateHeader(NULL, kAlternateProtocolHeader,
-                               &alternate_protocol_str)) {
-    // Header is not present.
+  if (!headers.HasHeader(kAlternateProtocolHeader))
     return;
-  }
-
-  factory->ProcessAlternateProtocol(http_server_properties,
-                                    alternate_protocol_str,
-                                    http_host_port_pair);
-}
 
-// Returns true if |error| is a client certificate authentication error.
-bool IsClientCertificateError(int error) {
-  switch (error) {
-    case ERR_BAD_SSL_CLIENT_AUTH_CERT:
-    case ERR_SSL_CLIENT_AUTH_PRIVATE_KEY_ACCESS_DENIED:
-    case ERR_SSL_CLIENT_AUTH_CERT_NO_PRIVATE_KEY:
-    case ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED:
-      return true;
-    default:
-      return false;
+  std::vector<std::string> alternate_protocol_values;
+  void* iter = NULL;
+  std::string alternate_protocol_str;
+  while (headers.EnumerateHeader(&iter, kAlternateProtocolHeader,
+                                 &alternate_protocol_str)) {
+    alternate_protocol_values.push_back(alternate_protocol_str);
   }
+
+  session->http_stream_factory()->ProcessAlternateProtocol(
+      session->http_server_properties(),
+      alternate_protocol_values,
+      http_host_port_pair,
+      *session);
 }
 
 base::Value* NetLogSSLVersionFallbackCallback(
@@ -132,7 +117,6 @@ HttpNetworkTransaction::HttpNetworkTransaction(RequestPriority priority,
       request_(NULL),
       priority_(priority),
       headers_valid_(false),
-      logged_response_time_(false),
       fallback_error_code_(ERR_SSL_INAPPROPRIATE_FALLBACK),
       request_headers_(),
       read_buf_len_(0),
@@ -141,10 +125,7 @@ HttpNetworkTransaction::HttpNetworkTransaction(RequestPriority priority,
       establishing_tunnel_(false),
       websocket_handshake_stream_base_create_helper_(NULL) {
   session->ssl_config_service()->GetSSLConfig(&server_ssl_config_);
-  if (session->http_stream_factory()->has_next_protos()) {
-    server_ssl_config_.next_protos =
-        session->http_stream_factory()->next_protos();
-  }
+  session->GetNextProtos(&server_ssl_config_.next_protos);
   proxy_ssl_config_ = server_ssl_config_;
 }
 
@@ -169,7 +150,7 @@ HttpNetworkTransaction::~HttpNetworkTransaction() {
         stream_->Close(true /* not reusable */);
       } else {
         // Otherwise, we try to drain the response body.
-        HttpStreamBase* stream = stream_.release();
+        HttpStream* stream = stream_.release();
         stream->Drain(session_);
       }
     }
@@ -186,18 +167,15 @@ int HttpNetworkTransaction::Start(const HttpRequestInfo* request_info,
 
   net_log_ = net_log;
   request_ = request_info;
-  start_time_ = base::Time::Now();
 
   if (request_->load_flags & LOAD_DISABLE_CERT_REVOCATION_CHECKING) {
     server_ssl_config_.rev_checking_enabled = false;
     proxy_ssl_config_.rev_checking_enabled = false;
   }
 
-  // Channel ID is enabled unless --disable-tls-channel-id flag is set,
-  // or if privacy mode is enabled.
-  bool channel_id_enabled = server_ssl_config_.channel_id_enabled &&
-      (request_->privacy_mode == kPrivacyModeDisabled);
-  server_ssl_config_.channel_id_enabled = channel_id_enabled;
+  // Channel ID is disabled if privacy mode is enabled for this request.
+  if (request_->privacy_mode == PRIVACY_MODE_ENABLED)
+    server_ssl_config_.channel_id_enabled = false;
 
   next_state_ = STATE_NOTIFY_BEFORE_CREATE_STREAM;
   int rv = DoLoop(OK);
@@ -314,8 +292,7 @@ void HttpNetworkTransaction::DidDrainBodyForAuthRestart(bool keep_alive) {
       // We should call connection_->set_idle_time(), but this doesn't occur
       // often enough to be worth the trouble.
       stream_->SetConnectionReused();
-      new_stream =
-          static_cast<HttpStream*>(stream_.get())->RenewStreamForAuth();
+      new_stream = stream_->RenewStreamForAuth();
     }
 
     if (!new_stream) {
@@ -430,8 +407,7 @@ UploadProgress HttpNetworkTransaction::GetUploadProgress() const {
   if (!stream_.get())
     return UploadProgress();
 
-  // TODO(bashi): This cast is temporary. Remove later.
-  return static_cast<HttpStream*>(stream_.get())->GetUploadProgress();
+  return stream_->GetUploadProgress();
 }
 
 void HttpNetworkTransaction::SetQuicServerInfo(
@@ -468,6 +444,11 @@ void HttpNetworkTransaction::SetBeforeNetworkStartCallback(
   before_network_start_callback_ = callback;
 }
 
+void HttpNetworkTransaction::SetBeforeProxyHeadersSentCallback(
+    const BeforeProxyHeadersSentCallback& callback) {
+  before_proxy_headers_sent_callback_ = callback;
+}
+
 int HttpNetworkTransaction::ResumeNetworkStart() {
   DCHECK_EQ(next_state_, STATE_CREATE_STREAM);
   return DoLoop(OK);
@@ -475,7 +456,7 @@ int HttpNetworkTransaction::ResumeNetworkStart() {
 
 void HttpNetworkTransaction::OnStreamReady(const SSLConfig& used_ssl_config,
                                            const ProxyInfo& used_proxy_info,
-                                           HttpStreamBase* stream) {
+                                           HttpStream* stream) {
   DCHECK_EQ(STATE_CREATE_STREAM_COMPLETE, next_state_);
   DCHECK(stream_request_.get());
 
@@ -489,7 +470,8 @@ void HttpNetworkTransaction::OnStreamReady(const SSLConfig& used_ssl_config,
       stream_request_->protocol_negotiated());
   response_.was_fetched_via_spdy = stream_request_->using_spdy();
   response_.was_fetched_via_proxy = !proxy_info_.is_direct();
-
+  if (response_.was_fetched_via_proxy && !proxy_info_.is_empty())
+    response_.proxy_server = proxy_info_.proxy_server().host_port_pair();
   OnIOComplete(OK);
 }
 
@@ -567,7 +549,7 @@ void HttpNetworkTransaction::OnHttpsProxyTunnelResponse(
     const HttpResponseInfo& response_info,
     const SSLConfig& used_ssl_config,
     const ProxyInfo& used_proxy_info,
-    HttpStreamBase* stream) {
+    HttpStream* stream) {
   DCHECK_EQ(STATE_CREATE_STREAM_COMPLETE, next_state_);
 
   headers_valid_ = true;
@@ -596,7 +578,18 @@ void HttpNetworkTransaction::DoCallback(int rv) {
 }
 
 void HttpNetworkTransaction::OnIOComplete(int result) {
+  // TODO(vadimt): Remove ScopedTracker below once crbug.com/424359 is fixed.
+  tracked_objects::ScopedTracker tracking_profile1(
+      FROM_HERE_WITH_EXPLICIT_FUNCTION(
+          "424359 HttpNetworkTransaction::OnIOComplete 1"));
+
   int rv = DoLoop(result);
+
+  // TODO(vadimt): Remove ScopedTracker below once crbug.com/424359 is fixed.
+  tracked_objects::ScopedTracker tracking_profile2(
+      FROM_HERE_WITH_EXPLICIT_FUNCTION(
+          "424359 HttpNetworkTransaction::OnIOComplete 2"));
+
   if (rv != ERR_IO_PENDING)
     DoCallback(rv);
 }
@@ -882,6 +875,10 @@ void HttpNetworkTransaction::BuildRequestHeaders(bool using_proxy) {
         &request_headers_);
 
   request_headers_.MergeFrom(request_->extra_headers);
+
+  if (using_proxy && !before_proxy_headers_sent_callback_.is_null())
+    before_proxy_headers_sent_callback_.Run(proxy_info_, &request_headers_);
+
   response_.did_use_http_auth =
       request_headers_.HasHeader(HttpRequestHeaders::kAuthorization) ||
       request_headers_.HasHeader(HttpRequestHeaders::kProxyAuthorization);
@@ -969,12 +966,6 @@ int HttpNetworkTransaction::DoReadHeadersComplete(int result) {
     return OK;
   }
 
-  // After we call RestartWithAuth a new response_time will be recorded, and
-  // we need to be cautious about incorrectly logging the duration across the
-  // authentication activity.
-  if (result == OK)
-    LogTransactionConnectedMetrics();
-
   // ERR_CONNECTION_CLOSED is treated differently at this point; if partial
   // response headers were received, we do the best we can to make sense of it
   // and send it back up the stack.
@@ -990,86 +981,19 @@ int HttpNetworkTransaction::DoReadHeadersComplete(int result) {
 
   DCHECK(response_.headers.get());
 
-#if defined(SPDY_PROXY_AUTH_ORIGIN)
-  // Server-induced fallback; see: http://crbug.com/143712
-  if (response_.was_fetched_via_proxy) {
-    ProxyService::DataReductionProxyBypassEventType proxy_bypass_event =
-        ProxyService::BYPASS_EVENT_TYPE_MAX;
-    net::HttpResponseHeaders::ChromeProxyInfo chrome_proxy_info;
-    bool chrome_proxy_used =
-        proxy_info_.proxy_server().isDataReductionProxy();
-    bool chrome_fallback_proxy_used = false;
-#if defined(DATA_REDUCTION_FALLBACK_HOST)
-    if (!chrome_proxy_used) {
-      chrome_fallback_proxy_used =
-          proxy_info_.proxy_server().isDataReductionProxyFallback();
-    }
-#endif
-
-    if (chrome_proxy_used || chrome_fallback_proxy_used) {
-      // A Via header might not be present in a 304. Since the goal of a 304
-      // response is to minimize information transfer, a sender in general
-      // should not generate representation metadata other than Cache-Control,
-      // Content-Location, Date, ETag, Expires, and Vary.
-      if (!response_.headers->IsChromeProxyResponse() &&
-          (response_.headers->response_code() != HTTP_NOT_MODIFIED)) {
-        proxy_bypass_event = ProxyService::MISSING_VIA_HEADER;
-      } else if (response_.headers->GetChromeProxyInfo(&chrome_proxy_info)) {
-        if (chrome_proxy_info.bypass_duration < TimeDelta::FromMinutes(30))
-          proxy_bypass_event = ProxyService::SHORT_BYPASS;
-        else
-          proxy_bypass_event = ProxyService::LONG_BYPASS;
-      } else {
-        // Additionally, fallback if a 500, 502 or 503 is returned via the data
-        // reduction proxy. This is conservative, as the 500, 502 or 503 might
-        // have been generated by the origin, and not the proxy.
-        if (response_.headers->response_code() == HTTP_INTERNAL_SERVER_ERROR ||
-            response_.headers->response_code() == HTTP_BAD_GATEWAY ||
-            response_.headers->response_code() == HTTP_SERVICE_UNAVAILABLE) {
-          proxy_bypass_event = ProxyService::INTERNAL_SERVER_ERROR_BYPASS;
-        }
-      }
-
-      if (proxy_bypass_event < ProxyService::BYPASS_EVENT_TYPE_MAX) {
-        ProxyService* proxy_service = session_->proxy_service();
-
-        proxy_service->RecordDataReductionProxyBypassInfo(
-            chrome_proxy_used, proxy_info_.proxy_server(), proxy_bypass_event);
-
-        ProxyServer proxy_server;
-#if defined(DATA_REDUCTION_FALLBACK_HOST)
-        if (chrome_proxy_used && chrome_proxy_info.bypass_all) {
-          // TODO(bengr): Rename as DATA_REDUCTION_FALLBACK_ORIGIN.
-          GURL proxy_url(DATA_REDUCTION_FALLBACK_HOST);
-          if (proxy_url.SchemeIsHTTPOrHTTPS()) {
-            proxy_server = ProxyServer(proxy_url.SchemeIs("http") ?
-                                           ProxyServer::SCHEME_HTTP :
-                                           ProxyServer::SCHEME_HTTPS,
-                                       HostPortPair::FromURL(proxy_url));
-            }
-        }
-#endif
-        if (proxy_service->MarkProxiesAsBadUntil(
-                proxy_info_,
-                chrome_proxy_info.bypass_duration,
-                proxy_server,
-                net_log_)) {
-          // Only retry idempotent methods. We don't want to resubmit a POST
-          // if the proxy took some action.
-          if (request_->method == "GET" ||
-              request_->method == "OPTIONS" ||
-              request_->method == "HEAD" ||
-              request_->method == "PUT" ||
-              request_->method == "DELETE" ||
-              request_->method == "TRACE") {
-            ResetConnectionAndRequestForResend();
-            return OK;
-          }
-        }
-      }
-    }
+  // On a 408 response from the server ("Request Timeout") on a stale socket,
+  // retry the request.
+  // Headers can be NULL because of http://crbug.com/384554.
+  if (response_.headers.get() && response_.headers->response_code() == 408 &&
+      stream_->IsConnectionReused()) {
+    net_log_.AddEventWithNetErrorCode(
+        NetLog::TYPE_HTTP_TRANSACTION_RESTART_AFTER_ERROR,
+        response_.headers->response_code());
+    // This will close the socket - it would be weird to try and reuse it, even
+    // if the server doesn't actually close it.
+    ResetConnectionAndRequestForResend();
+    return OK;
   }
-#endif  // defined(SPDY_PROXY_AUTH_ORIGIN)
 
   // Like Net.HttpResponseCode, but only for MAIN_FRAME loads.
   if (request_->load_flags & LOAD_MAIN_FRAME) {
@@ -1105,8 +1029,7 @@ int HttpNetworkTransaction::DoReadHeadersComplete(int result) {
 
   HostPortPair endpoint = HostPortPair(request_->url.HostNoBrackets(),
                                        request_->url.EffectiveIntPort());
-  ProcessAlternateProtocol(session_->http_stream_factory(),
-                           session_->http_server_properties(),
+  ProcessAlternateProtocol(session_,
                            *response_.headers.get(),
                            endpoint);
 
@@ -1118,6 +1041,14 @@ int HttpNetworkTransaction::DoReadHeadersComplete(int result) {
     stream_->GetSSLInfo(&response_.ssl_info);
 
   headers_valid_ = true;
+
+  if (session_->huffman_aggregator()) {
+    session_->huffman_aggregator()->AggregateTransactionCharacterCounts(
+        *request_,
+        request_headers_,
+        proxy_info_.proxy_server(),
+        *response_.headers.get());
+  }
   return OK;
 }
 
@@ -1159,7 +1090,6 @@ int HttpNetworkTransaction::DoReadBodyComplete(int result) {
 
   // Clean up connection if we are done.
   if (done) {
-    LogTransactionMetrics();
     stream_->Close(!keep_alive);
     // Note: we don't reset the stream here.  We've closed it, but we still
     // need it around so that callers can call methods such as
@@ -1211,72 +1141,6 @@ int HttpNetworkTransaction::DoDrainBodyForAuthRestartComplete(int result) {
   return OK;
 }
 
-void HttpNetworkTransaction::LogTransactionConnectedMetrics() {
-  if (logged_response_time_)
-    return;
-
-  logged_response_time_ = true;
-
-  base::TimeDelta total_duration = response_.response_time - start_time_;
-
-  UMA_HISTOGRAM_CUSTOM_TIMES(
-      "Net.Transaction_Connected",
-      total_duration,
-      base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(10),
-      100);
-
-  bool reused_socket = stream_->IsConnectionReused();
-  if (!reused_socket) {
-    UMA_HISTOGRAM_CUSTOM_TIMES(
-        "Net.Transaction_Connected_New_b",
-        total_duration,
-        base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(10),
-        100);
-  }
-
-  // Currently, non-HIGHEST priority requests are frame or sub-frame resource
-  // types.  This will change when we also prioritize certain subresources like
-  // css, js, etc.
-  if (priority_ != HIGHEST) {
-    UMA_HISTOGRAM_CUSTOM_TIMES(
-        "Net.Priority_High_Latency_b",
-        total_duration,
-        base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(10),
-        100);
-  } else {
-    UMA_HISTOGRAM_CUSTOM_TIMES(
-        "Net.Priority_Low_Latency_b",
-        total_duration,
-        base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(10),
-        100);
-  }
-}
-
-void HttpNetworkTransaction::LogTransactionMetrics() const {
-  base::TimeDelta duration = base::Time::Now() -
-                             response_.request_time;
-  if (60 < duration.InMinutes())
-    return;
-
-  base::TimeDelta total_duration = base::Time::Now() - start_time_;
-
-  UMA_HISTOGRAM_CUSTOM_TIMES("Net.Transaction_Latency_b", duration,
-                             base::TimeDelta::FromMilliseconds(1),
-                             base::TimeDelta::FromMinutes(10),
-                             100);
-  UMA_HISTOGRAM_CUSTOM_TIMES("Net.Transaction_Latency_Total",
-                             total_duration,
-                             base::TimeDelta::FromMilliseconds(1),
-                             base::TimeDelta::FromMinutes(10), 100);
-
-  if (!stream_->IsConnectionReused()) {
-    UMA_HISTOGRAM_CUSTOM_TIMES(
-        "Net.Transaction_Latency_Total_New_Connection",
-        total_duration, base::TimeDelta::FromMilliseconds(1),
-        base::TimeDelta::FromMinutes(10), 100);
-  }
-}
-
 int HttpNetworkTransaction::HandleCertificateRequest(int error) {
   // There are two paths through which the server can request a certificate
   // from us.  The first is during the initial handshake, the second is
@@ -1359,6 +1223,7 @@ int HttpNetworkTransaction::HandleSSLHandshakeError(int error) {
   uint16 version_max = server_ssl_config_.version_max;
 
   switch (error) {
+    case ERR_CONNECTION_CLOSED:
     case ERR_SSL_PROTOCOL_ERROR:
     case ERR_SSL_VERSION_OR_CIPHER_MISMATCH:
       if (version_max >= SSL_PROTOCOL_VERSION_TLS1 &&
@@ -1382,6 +1247,26 @@ int HttpNetworkTransaction::HandleSSLHandshakeError(int error) {
         should_fallback = true;
       }
       break;
+    case ERR_CONNECTION_RESET:
+      if (version_max >= SSL_PROTOCOL_VERSION_TLS1_1 &&
+          version_max > server_ssl_config_.version_min) {
+        // Some network devices that inspect application-layer packets seem to
+        // inject TCP reset packets to break the connections when they see TLS
+        // 1.1 in ClientHello or ServerHello. See http://crbug.com/130293.
+        //
+        // Only allow ERR_CONNECTION_RESET to trigger a fallback from TLS 1.1 or
+        // 1.2. We don't lose much in this fallback because the explicit IV for
+        // CBC mode in TLS 1.1 is approximated by record splitting in TLS
+        // 1.0. The fallback will be more painful for TLS 1.2 when we have GCM
+        // support.
+        //
+        // ERR_CONNECTION_RESET is a common network error, so we don't want it
+        // to trigger a version fallback in general, especially the TLS 1.0 ->
+        // SSL 3.0 fallback, which would drop TLS extensions.
+        version_max--;
+        should_fallback = true;
+      }
+      break;
     case ERR_SSL_BAD_RECORD_MAC_ALERT:
       if (version_max >= SSL_PROTOCOL_VERSION_TLS1_1 &&
           version_max > server_ssl_config_.version_min) {
@@ -1454,14 +1339,6 @@ int HttpNetworkTransaction::HandleIOError(int error) {
         error = OK;
       }
       break;
-    case ERR_PIPELINE_EVICTION:
-      if (!session_->force_http_pipelining()) {
-        net_log_.AddEventWithNetErrorCode(
-            NetLog::TYPE_HTTP_TRANSACTION_RESTART_AFTER_ERROR, error);
-        ResetConnectionAndRequestForResend();
-        error = OK;
-      }
-      break;
     case ERR_SPDY_PING_FAILED:
     case ERR_SPDY_SERVER_REFUSED_STREAM:
     case ERR_QUIC_HANDSHAKE_FAILED:
@@ -1582,6 +1459,17 @@ GURL HttpNetworkTransaction::AuthURL(HttpAuth::Target target) const {
                   proxy_info_.proxy_server().host_port_pair().ToString());
     }
     case HttpAuth::AUTH_SERVER:
+      if (ForWebSocketHandshake()) {
+        const GURL& url = request_->url;
+        url::Replacements<char> ws_to_http;
+        if (url.SchemeIs("ws")) {
+          ws_to_http.SetScheme("http", url::Component(0, 4));
+        } else {
+          DCHECK(url.SchemeIs("wss"));
+          ws_to_http.SetScheme("https", url::Component(0, 5));
+        }
+        return url.ReplaceComponents(ws_to_http);
+      }
       return request_->url;
     default:
      return GURL();