1ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Use of this source code is governed by a BSD-style license that can be
3c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// found in the LICENSE file.
4c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
5c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/http/http_network_layer.h"
6c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
7c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "base/logging.h"
83f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#include "base/string_number_conversions.h"
93345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/string_split.h"
10c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "base/string_util.h"
11c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/http/http_network_session.h"
12c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/http/http_network_transaction.h"
13c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/spdy/spdy_framer.h"
14c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/spdy/spdy_session.h"
15dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "net/spdy/spdy_session_pool.h"
16c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
17c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottnamespace net {
18c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
19c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott//-----------------------------------------------------------------------------
20c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottHttpNetworkLayer::HttpNetworkLayer(HttpNetworkSession* session)
2172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    : session_(session),
22c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      suspended_(false) {
23c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK(session_.get());
24c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
25c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
26c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottHttpNetworkLayer::~HttpNetworkLayer() {
27c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
28c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
2972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen//-----------------------------------------------------------------------------
30c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
3172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// static
3272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian MonsenHttpTransactionFactory* HttpNetworkLayer::CreateFactory(
3372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    HttpNetworkSession* session) {
3472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  DCHECK(session);
35c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
3672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  return new HttpNetworkLayer(session);
37c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
38c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
39c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// static
40c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid HttpNetworkLayer::EnableSpdy(const std::string& mode) {
41731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  static const char kOff[] = "off";
423345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  static const char kSSL[] = "ssl";
43c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  static const char kDisableSSL[] = "no-ssl";
442c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  static const char kDisablePing[] = "no-ping";
453f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen  static const char kExclude[] = "exclude";  // Hosts to exclude
46c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  static const char kDisableCompression[] = "no-compress";
47c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  static const char kDisableAltProtocols[] = "no-alt-protocols";
483345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  static const char kEnableVersionOne[] = "v1";
493345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  static const char kForceAltProtocols[] = "force-alt-protocols";
50dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  static const char kSingleDomain[] = "single-domain";
513345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
523345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // If flow-control is enabled, received WINDOW_UPDATE and SETTINGS
533345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // messages are processed and outstanding window size is actually obeyed
543345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // when sending data frames, and WINDOW_UPDATE messages are generated
553345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // when data is consumed.
563345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  static const char kEnableFlowControl[] = "flow-control";
57c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
58c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // We want an A/B experiment between SPDY enabled and SPDY disabled,
59c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // but only for pages where SPDY *could have been* negotiated.  To do
60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // this, we use NPN, but prevent it from negotiating SPDY.  If the
61c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // server negotiates HTTP, rather than SPDY, today that will only happen
62c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // on servers that installed NPN (and could have done SPDY).  But this is
63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // a bit of a hack, as this correlation between NPN and SPDY is not
64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // really guaranteed.
65c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  static const char kEnableNPN[] = "npn";
66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  static const char kEnableNpnHttpOnly[] = "npn-http";
67c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
68c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Except for the first element, the order is irrelevant.  First element
69c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // specifies the fallback in case nothing matches
70c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // (SSLClientSocket::kNextProtoNoOverlap).  Otherwise, the SSL library
71c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // will choose the first overlapping protocol in the server's list, since
72c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // it presumedly has a better understanding of which protocol we should
73c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // use, therefore the rest of the ordering here is not important.
743345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  static const char kNpnProtosFull[] = "\x08http/1.1\x06spdy/2";
753345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // This is a temporary hack to pretend we support version 1.
763345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  static const char kNpnProtosFullV1[] = "\x08http/1.1\x06spdy/1";
77c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // No spdy specified.
78c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  static const char kNpnProtosHttpOnly[] = "\x08http/1.1\x07http1.1";
79c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
80c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::vector<std::string> spdy_options;
81731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  base::SplitString(mode, ',', &spdy_options);
82c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
83c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bool use_alt_protocols = true;
84c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
85c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (std::vector<std::string>::iterator it = spdy_options.begin();
86c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch       it != spdy_options.end(); ++it) {
873f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen    const std::string& element = *it;
883f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen    std::vector<std::string> name_value;
893f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen    base::SplitString(element, '=', &name_value);
903f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen    const std::string& option = name_value[0];
913f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen    const std::string value = name_value.size() > 1 ? name_value[1] : "";
923f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen
93731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    if (option == kOff) {
94731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      HttpStreamFactory::set_spdy_enabled(false);
95731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    } else if (option == kDisableSSL) {
96c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      SpdySession::SetSSLMode(false);  // Disable SSL
973345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      HttpStreamFactory::set_force_spdy_over_ssl(false);
983345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      HttpStreamFactory::set_force_spdy_always(true);
993345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    } else if (option == kSSL) {
1003345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      HttpStreamFactory::set_force_spdy_over_ssl(true);
1013345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      HttpStreamFactory::set_force_spdy_always(true);
1022c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    } else if (option == kDisablePing) {
1032c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun      SpdySession::set_enable_ping_based_connection_checking(false);
1043f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen    } else if (option == kExclude) {
1053f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen      HttpStreamFactory::add_forced_spdy_exclusion(value);
106c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    } else if (option == kDisableCompression) {
107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      spdy::SpdyFramer::set_enable_compression_default(false);
108c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    } else if (option == kEnableNPN) {
1093345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      HttpStreamFactory::set_use_alternate_protocols(use_alt_protocols);
1103345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      HttpStreamFactory::set_next_protos(kNpnProtosFull);
111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    } else if (option == kEnableNpnHttpOnly) {
112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // Avoid alternate protocol in this case. Otherwise, browser will try SSL
113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // and then fallback to http. This introduces extra load.
1143345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      HttpStreamFactory::set_use_alternate_protocols(false);
1153345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      HttpStreamFactory::set_next_protos(kNpnProtosHttpOnly);
1163345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    } else if (option == kEnableVersionOne) {
1173345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      spdy::SpdyFramer::set_protocol_version(1);
1183345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      HttpStreamFactory::set_next_protos(kNpnProtosFullV1);
119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    } else if (option == kDisableAltProtocols) {
120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      use_alt_protocols = false;
1213345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      HttpStreamFactory::set_use_alternate_protocols(false);
1223345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    } else if (option == kEnableFlowControl) {
1233345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      SpdySession::set_flow_control(true);
1243345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    } else if (option == kForceAltProtocols) {
1253345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      HttpAlternateProtocols::PortProtocolPair pair;
1263345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      pair.port = 443;
1273345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      pair.protocol = HttpAlternateProtocols::NPN_SPDY_2;
1283345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      HttpAlternateProtocols::ForceAlternateProtocol(pair);
129dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    } else if (option == kSingleDomain) {
130dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      SpdySessionPool::ForceSingleDomain();
131dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      LOG(ERROR) << "FORCING SINGLE DOMAIN";
132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    } else if (option.empty() && it == spdy_options.begin()) {
133c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      continue;
134c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    } else {
135c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      LOG(DFATAL) << "Unrecognized spdy option: " << option;
136c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    }
137c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
138c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
13972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
14072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen//-----------------------------------------------------------------------------
14172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
14272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenint HttpNetworkLayer::CreateTransaction(scoped_ptr<HttpTransaction>* trans) {
14372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (suspended_)
14472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    return ERR_NETWORK_IO_SUSPENDED;
14572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
14672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  trans->reset(new HttpNetworkTransaction(GetSession()));
14772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  return OK;
14872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
14972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
15072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian MonsenHttpCache* HttpNetworkLayer::GetCache() {
15172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  return NULL;
15272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
15372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
15472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian MonsenHttpNetworkSession* HttpNetworkLayer::GetSession() {
15572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  return session_;
15672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
15772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
15872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenvoid HttpNetworkLayer::Suspend(bool suspend) {
15972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  suspended_ = suspend;
16072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
16172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (suspend && session_)
162dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    session_->CloseIdleConnections();
16372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
16472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
165c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}  // namespace net
166