Update from chromium https://crrev.com/304586
Review URL: https://codereview.chromium.org/732423002
diff --git a/net/BUILD.gn b/net/BUILD.gn
index 3bd06bc..be0ac53 100644
--- a/net/BUILD.gn
+++ b/net/BUILD.gn
@@ -473,6 +473,8 @@
# doesn't set USE_NSS but needs some of the files.
set_sources_assignment_filter([])
sources += [
+ "base/net_util_mac.cc",
+ "base/net_util_mac.h",
"base/network_change_notifier_mac.cc",
"base/network_config_watcher_mac.cc",
"base/platform_mime_util_mac.mm",
@@ -506,6 +508,8 @@
"base/platform_mime_util_linux.cc",
"base/address_tracker_linux.cc",
"base/address_tracker_linux.h",
+ "base/net_util_linux.cc",
+ "base/net_util_linux.h"
]
set_sources_assignment_filter(sources_assignment_filter)
diff --git a/net/base/host_port_pair.cc b/net/base/host_port_pair.cc
index 6675692..18cf9f5 100644
--- a/net/base/host_port_pair.cc
+++ b/net/base/host_port_pair.cc
@@ -10,6 +10,7 @@
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "net/base/ip_endpoint.h"
+#include "net/base/net_util.h"
#include "url/gurl.h"
namespace net {
@@ -36,7 +37,8 @@
int port;
if (!base::StringToInt(key_port[1], &port))
return HostPortPair();
- DCHECK_LT(port, 1 << 16);
+ if (!IsPortValid(port))
+ return HostPortPair();
HostPortPair host_port_pair;
host_port_pair.set_host(key_port[0]);
host_port_pair.set_port(port);
diff --git a/net/base/host_port_pair_unittest.cc b/net/base/host_port_pair_unittest.cc
index 5b15db9..2c97e94 100644
--- a/net/base/host_port_pair_unittest.cc
+++ b/net/base/host_port_pair_unittest.cc
@@ -37,13 +37,19 @@
}
TEST(HostPortPairTest, BadString) {
- HostPortPair foo = HostPortPair::FromString("foo.com:2:3");
- EXPECT_TRUE(foo.host().empty());
- EXPECT_EQ(0, foo.port());
+ const char* kBadStrings[] = {
+ "foo.com:2:3",
+ "bar.com:two",
+ "www.google.com:-1",
+ "127.0.0.1:65536",
+ "[2001:db8::42]:65536",
+ };
- HostPortPair bar = HostPortPair::FromString("bar.com:two");
- EXPECT_TRUE(bar.host().empty());
- EXPECT_EQ(0, bar.port());
+ for (size_t index = 0; index < arraysize(kBadStrings); ++index) {
+ HostPortPair foo = HostPortPair::FromString(kBadStrings[index]);
+ EXPECT_TRUE(foo.host().empty());
+ EXPECT_EQ(0, foo.port());
+ }
}
TEST(HostPortPairTest, Emptiness) {
diff --git a/net/base/load_flags_list.h b/net/base/load_flags_list.h
index 6e49bbb..2754326 100644
--- a/net/base/load_flags_list.h
+++ b/net/base/load_flags_list.h
@@ -34,94 +34,90 @@
// impact the HTTP request headers.
LOAD_FLAG(DISABLE_CACHE, 1 << 5)
-// This is a navigation that will not be intercepted by any registered
-// URLRequest::Interceptors.
-LOAD_FLAG(DISABLE_INTERCEPT, 1 << 6)
-
// If present, ignores certificate mismatches with the domain name.
// (The default behavior is to trigger an OnSSLCertificateError callback.)
-LOAD_FLAG(IGNORE_CERT_COMMON_NAME_INVALID, 1 << 7)
+LOAD_FLAG(IGNORE_CERT_COMMON_NAME_INVALID, 1 << 6)
// If present, ignores certificate expiration dates
// (The default behavior is to trigger an OnSSLCertificateError callback).
-LOAD_FLAG(IGNORE_CERT_DATE_INVALID, 1 << 8)
+LOAD_FLAG(IGNORE_CERT_DATE_INVALID, 1 << 7)
// If present, trusts all certificate authorities
// (The default behavior is to trigger an OnSSLCertificateError callback).
-LOAD_FLAG(IGNORE_CERT_AUTHORITY_INVALID, 1 << 9)
+LOAD_FLAG(IGNORE_CERT_AUTHORITY_INVALID, 1 << 8)
// If present, causes certificate revocation checks to be skipped on secure
// connections.
-LOAD_FLAG(DISABLE_CERT_REVOCATION_CHECKING, 1 << 10)
+LOAD_FLAG(DISABLE_CERT_REVOCATION_CHECKING, 1 << 9)
// If present, ignores wrong key usage of the certificate
// (The default behavior is to trigger an OnSSLCertificateError callback).
-LOAD_FLAG(IGNORE_CERT_WRONG_USAGE, 1 << 11)
+LOAD_FLAG(IGNORE_CERT_WRONG_USAGE, 1 << 10)
// This load will not make any changes to cookies, including storing new
// cookies or updating existing ones.
-LOAD_FLAG(DO_NOT_SAVE_COOKIES, 1 << 12)
+LOAD_FLAG(DO_NOT_SAVE_COOKIES, 1 << 11)
// Do not resolve proxies. This override is used when downloading PAC files
// to avoid having a circular dependency.
-LOAD_FLAG(BYPASS_PROXY, 1 << 13)
+LOAD_FLAG(BYPASS_PROXY, 1 << 12)
// Indicate this request is for a download, as opposed to viewing.
-LOAD_FLAG(IS_DOWNLOAD, 1 << 14)
+LOAD_FLAG(IS_DOWNLOAD, 1 << 13)
// Requires EV certificate verification.
-LOAD_FLAG(VERIFY_EV_CERT, 1 << 15)
+LOAD_FLAG(VERIFY_EV_CERT, 1 << 14)
// This load will not send any cookies.
-LOAD_FLAG(DO_NOT_SEND_COOKIES, 1 << 16)
+LOAD_FLAG(DO_NOT_SEND_COOKIES, 1 << 15)
// This load will not send authentication data (user name/password)
// to the server (as opposed to the proxy).
-LOAD_FLAG(DO_NOT_SEND_AUTH_DATA, 1 << 17)
+LOAD_FLAG(DO_NOT_SEND_AUTH_DATA, 1 << 16)
// This should only be used for testing (set by HttpNetworkTransaction).
-LOAD_FLAG(IGNORE_ALL_CERT_ERRORS, 1 << 18)
+LOAD_FLAG(IGNORE_ALL_CERT_ERRORS, 1 << 17)
// Indicate that this is a top level frame, so that we don't assume it is a
// subresource and speculatively pre-connect or pre-resolve when a referring
// page is loaded.
-LOAD_FLAG(MAIN_FRAME, 1 << 19)
+LOAD_FLAG(MAIN_FRAME, 1 << 18)
// Indicate that this is a sub frame, and hence it might have subresources that
// should be speculatively resolved, or even speculatively preconnected.
-LOAD_FLAG(SUB_FRAME, 1 << 20)
+LOAD_FLAG(SUB_FRAME, 1 << 19)
// If present, intercept actual request/response headers from network stack
// and report them to renderer. This includes cookies, so the flag is only
// respected if renderer has CanReadRawCookies capability in the security
// policy.
-LOAD_FLAG(REPORT_RAW_HEADERS, 1 << 21)
+LOAD_FLAG(REPORT_RAW_HEADERS, 1 << 20)
// Indicates that this load was motivated by the rel=prefetch feature,
// and is (in theory) not intended for the current frame.
-LOAD_FLAG(PREFETCH, 1 << 22)
+LOAD_FLAG(PREFETCH, 1 << 21)
// Indicates that this is a load that ignores limits and should complete
// immediately.
-LOAD_FLAG(IGNORE_LIMITS, 1 << 23)
+LOAD_FLAG(IGNORE_LIMITS, 1 << 22)
// Suppress login prompts for this request. Cached credentials or
// default credentials may still be used for authentication.
-LOAD_FLAG(DO_NOT_PROMPT_FOR_LOGIN, 1 << 24)
+LOAD_FLAG(DO_NOT_PROMPT_FOR_LOGIN, 1 << 23)
// Indicates that the operation is somewhat likely to be due to an
// explicit user action. This can be used as a hint to treat the
// request with higher priority.
-LOAD_FLAG(MAYBE_USER_GESTURE, 1 << 25)
+LOAD_FLAG(MAYBE_USER_GESTURE, 1 << 24)
// Indicates that the username:password portion of the URL should not
// be honored, but that other forms of authority may be used.
-LOAD_FLAG(DO_NOT_USE_EMBEDDED_IDENTITY, 1 << 26)
+LOAD_FLAG(DO_NOT_USE_EMBEDDED_IDENTITY, 1 << 25)
// Send request directly to the origin if the effective proxy is the data
// reduction proxy.
// TODO(rcs): Remove this flag as soon as http://crbug.com/339237 is resolved.
-LOAD_FLAG(BYPASS_DATA_REDUCTION_PROXY, 1 << 27)
+LOAD_FLAG(BYPASS_DATA_REDUCTION_PROXY, 1 << 26)
// Indicates the the request is an asynchronous revalidation.
-LOAD_FLAG(ASYNC_REVALIDATION, 1 << 28)
+LOAD_FLAG(ASYNC_REVALIDATION, 1 << 27)
diff --git a/net/base/net_info_source_list.h b/net/base/net_info_source_list.h
index be3019e..107840b 100644
--- a/net/base/net_info_source_list.h
+++ b/net/base/net_info_source_list.h
@@ -20,3 +20,4 @@
NET_INFO_SOURCE(SPDY_ALT_PROTO_MAPPINGS, "spdyAlternateProtocolMappings",
1 << 7)
NET_INFO_SOURCE(HTTP_CACHE, "httpCacheInfo", 1 << 8)
+NET_INFO_SOURCE(SDCH, "sdchInfo", 1 << 9)
diff --git a/net/base/net_log_event_type_list.h b/net/base/net_log_event_type_list.h
index 6dfe8c6..af7c290 100644
--- a/net/base/net_log_event_type_list.h
+++ b/net/base/net_log_event_type_list.h
@@ -2363,3 +2363,38 @@
// This event is created (in a source of the same name) when the internal DNS
// resolver creates a UDP socket to check for global IPv6 connectivity.
EVENT_TYPE(IPV6_REACHABILITY_CHECK)
+
+// ------------------------------------------------------------------------
+// SDCH
+// ------------------------------------------------------------------------
+
+// This event is created when some problem occurs during sdch-encoded resource
+// handling. It contains the following parameters:
+// {
+// "sdch_problem_code": <SDCH problem code>,
+// "net_error": <Always ERR_FAILED, present just to indicate this is a
+// failure>,
+// }
+EVENT_TYPE(SDCH_DECODING_ERROR)
+
+// This event is created when SdchFilter initialization fails due to the
+// response corruption. It contains the following parameters:
+// {
+// "cause": <Response corruption detection cause>,
+// "cached": <True if response was read from cache>,
+// }
+EVENT_TYPE(SDCH_RESPONSE_CORRUPTION_DETECTION)
+
+// This event is created when some problem occurs during sdch dictionary fetch.
+// It contains the following parameters:
+// {
+// "dictionary_url": <Dictionary url>,
+// "sdch_problem_code": <SDCH problem code>,
+// "net_error": <Only present on unexpected errors. Always ERR_FAILED when
+// present. Used to indicate this is a real failure>,
+// }
+EVENT_TYPE(SDCH_DICTIONARY_ERROR)
+
+// This event is created when SdchDictionaryFetcher starts fetch. It contains
+// no parameters.
+EVENT_TYPE(SDCH_DICTIONARY_FETCH)
diff --git a/net/base/net_log_util.cc b/net/base/net_log_util.cc
index b8816ba..a15e899 100644
--- a/net/base/net_log_util.cc
+++ b/net/base/net_log_util.cc
@@ -15,6 +15,7 @@
#include "net/base/load_states.h"
#include "net/base/net_errors.h"
#include "net/base/net_log.h"
+#include "net/base/sdch_manager.h"
#include "net/disk_cache/disk_cache.h"
#include "net/dns/host_cache.h"
#include "net/dns/host_resolver.h"
@@ -66,6 +67,14 @@
#undef NET_ERROR
};
+const StringToConstant kSdchProblems[] = {
+#define SDCH_PROBLEM_CODE(label, value) \
+ { #label, value } \
+ ,
+#include "net/base/sdch_problem_code_list.h"
+#undef SDCH_PROBLEM_CODE
+};
+
const char* NetInfoSourceToString(NetInfoSource source) {
switch (source) {
#define NET_INFO_SOURCE(label, string, value) \
@@ -187,6 +196,17 @@
constants_dict->Set("quicRstStreamError", dict);
}
+ // Add information on the relationship between SDCH problem codes and their
+ // symbolic names.
+ {
+ base::DictionaryValue* dict = new base::DictionaryValue();
+
+ for (size_t i = 0; i < arraysize(kSdchProblems); i++)
+ dict->SetInteger(kSdchProblems[i].name, kSdchProblems[i].constant);
+
+ constants_dict->Set("sdchProblemCode", dict);
+ }
+
// Information about the relationship between event phase enums and their
// symbolic names.
{
@@ -455,6 +475,17 @@
info_dict);
}
+ if (info_sources & NET_INFO_SDCH) {
+ base::Value* info_dict;
+ SdchManager* sdch_manager = context->sdch_manager();
+ if (sdch_manager) {
+ info_dict = sdch_manager->SdchInfoToValue();
+ } else {
+ info_dict = new base::DictionaryValue();
+ }
+ net_info_dict->Set(NetInfoSourceToString(NET_INFO_SDCH), info_dict);
+ }
+
return net_info_dict.Pass();
}
diff --git a/net/base/net_util.cc b/net/base/net_util.cc
index b9cf59f..9dcf9df 100644
--- a/net/base/net_util.cc
+++ b/net/base/net_util.cc
@@ -9,6 +9,7 @@
#include <algorithm>
#include <iterator>
+#include <limits>
#include <set>
#include "build/build_config.h"
@@ -294,6 +295,10 @@
return StripWWW(base::ASCIIToUTF16(url.host()));
}
+bool IsPortValid(int port) {
+ return port >= 0 && port <= std::numeric_limits<uint16>::max();
+}
+
bool IsPortAllowedByDefault(int port) {
int array_size = arraysize(kRestrictedPorts);
for (int i = 0; i < array_size; i++) {
diff --git a/net/base/net_util.h b/net/base/net_util.h
index 72ac169..44b913a 100644
--- a/net/base/net_util.h
+++ b/net/base/net_util.h
@@ -248,6 +248,10 @@
// Runs |url|'s host through StripWWW(). |url| must be valid.
NET_EXPORT base::string16 StripWWWFromHost(const GURL& url);
+// Checks if |port| is in the valid range (0 to 65535, though 0 is technically
+// reserved). Should be used before casting a port to a uint16.
+NET_EXPORT bool IsPortValid(int port);
+
// Checks |port| against a list of ports which are restricted by default.
// Returns true if |port| is allowed, false if it is restricted.
NET_EXPORT bool IsPortAllowedByDefault(int port);
diff --git a/net/base/net_util_linux.cc b/net/base/net_util_linux.cc
new file mode 100644
index 0000000..e4e0f7f
--- /dev/null
+++ b/net/base/net_util_linux.cc
@@ -0,0 +1,154 @@
+// Copyright (c) 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/base/net_util_linux.h"
+
+#include <net/if.h>
+#include <netinet/in.h>
+#include <set>
+#include <sys/types.h>
+
+#include "base/files/file_path.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_tokenizer.h"
+#include "base/strings/string_util.h"
+#include "base/threading/thread_restrictions.h"
+#include "net/base/address_tracker_linux.h"
+#include "net/base/escape.h"
+#include "net/base/ip_endpoint.h"
+#include "net/base/net_errors.h"
+#include "net/base/net_util_posix.h"
+#include "url/gurl.h"
+
+namespace net {
+
+namespace {
+
+// When returning true, the platform native IPv6 address attributes were
+// successfully converted to net IP address attributes. Otherwise, returning
+// false and the caller should drop the IP address which can't be used by the
+// application layer.
+bool TryConvertNativeToNetIPAttributes(int native_attributes,
+ int* net_attributes) {
+ // For Linux/ChromeOS/Android, we disallow addresses with attributes
+ // IFA_F_OPTIMISTIC, IFA_F_DADFAILED, and IFA_F_TENTATIVE as these
+ // are still progressing through duplicated address detection (DAD)
+ // and shouldn't be used by the application layer until DAD process
+ // is completed.
+ if (native_attributes & (
+#if !defined(OS_ANDROID)
+ IFA_F_OPTIMISTIC | IFA_F_DADFAILED |
+#endif // !OS_ANDROID
+ IFA_F_TENTATIVE)) {
+ return false;
+ }
+
+ if (native_attributes & IFA_F_TEMPORARY) {
+ *net_attributes |= IP_ADDRESS_ATTRIBUTE_TEMPORARY;
+ }
+
+ if (native_attributes & IFA_F_DEPRECATED) {
+ *net_attributes |= IP_ADDRESS_ATTRIBUTE_DEPRECATED;
+ }
+
+ return true;
+}
+
+} // namespace
+
+namespace internal {
+
+inline const unsigned char* GetIPAddressData(const IPAddressNumber& ip) {
+#if defined(OS_ANDROID)
+ return ip.begin();
+#else
+ return ip.data();
+#endif
+}
+
+bool GetNetworkListImpl(
+ NetworkInterfaceList* networks,
+ int policy,
+ const base::hash_set<int>& online_links,
+ const internal::AddressTrackerLinux::AddressMap& address_map,
+ GetInterfaceNameFunction get_interface_name) {
+ std::map<int, std::string> ifnames;
+
+ for (internal::AddressTrackerLinux::AddressMap::const_iterator it =
+ address_map.begin();
+ it != address_map.end(); ++it) {
+ // Ignore addresses whose links are not online.
+ if (online_links.find(it->second.ifa_index) == online_links.end())
+ continue;
+
+ sockaddr_storage sock_addr;
+ socklen_t sock_len = sizeof(sockaddr_storage);
+
+ // Convert to sockaddr for next check.
+ if (!IPEndPoint(it->first, 0)
+ .ToSockAddr(reinterpret_cast<sockaddr*>(&sock_addr), &sock_len)) {
+ continue;
+ }
+
+ // Skip unspecified addresses (i.e. made of zeroes) and loopback addresses
+ if (IsLoopbackOrUnspecifiedAddress(reinterpret_cast<sockaddr*>(&sock_addr)))
+ continue;
+
+ int ip_attributes = IP_ADDRESS_ATTRIBUTE_NONE;
+
+ if (it->second.ifa_family == AF_INET6) {
+ // Ignore addresses whose attributes are not actionable by
+ // the application layer.
+ if (!TryConvertNativeToNetIPAttributes(it->second.ifa_flags,
+ &ip_attributes))
+ continue;
+ }
+
+ // Find the name of this link.
+ std::map<int, std::string>::const_iterator itname =
+ ifnames.find(it->second.ifa_index);
+ std::string ifname;
+ if (itname == ifnames.end()) {
+ char buffer[IF_NAMESIZE] = {0};
+ if (get_interface_name(it->second.ifa_index, buffer)) {
+ ifname = ifnames[it->second.ifa_index] = buffer;
+ } else {
+ // Ignore addresses whose interface name can't be retrieved.
+ continue;
+ }
+ } else {
+ ifname = itname->second;
+ }
+
+ // Based on the interface name and policy, determine whether we
+ // should ignore it.
+ if (ShouldIgnoreInterface(ifname, policy))
+ continue;
+
+ networks->push_back(
+ NetworkInterface(ifname, ifname, it->second.ifa_index,
+ NetworkChangeNotifier::CONNECTION_UNKNOWN, it->first,
+ it->second.ifa_prefixlen, ip_attributes));
+ }
+
+ return true;
+}
+
+} // namespace internal
+
+bool GetNetworkList(NetworkInterfaceList* networks, int policy) {
+ if (networks == NULL)
+ return false;
+
+ internal::AddressTrackerLinux tracker;
+ tracker.Init();
+
+ return internal::GetNetworkListImpl(networks, policy,
+ tracker.GetOnlineLinks(),
+ tracker.GetAddressMap(), &if_indextoname);
+}
+
+} // namespace net
diff --git a/net/base/net_util_linux.h b/net/base/net_util_linux.h
new file mode 100644
index 0000000..340c380
--- /dev/null
+++ b/net/base/net_util_linux.h
@@ -0,0 +1,31 @@
+// Copyright (c) 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_BASE_NET_UTIL_LINUX_H_
+#define NET_BASE_NET_UTIL_LINUX_H_
+
+// This file is only used to expose some of the internals
+// of net_util_linux.cc to tests.
+
+#include "base/containers/hash_tables.h"
+#include "net/base/address_tracker_linux.h"
+#include "net/base/net_util.h"
+
+namespace net {
+namespace internal {
+
+typedef char* (*GetInterfaceNameFunction)(unsigned int interface_index,
+ char* ifname);
+
+NET_EXPORT bool GetNetworkListImpl(
+ NetworkInterfaceList* networks,
+ int policy,
+ const base::hash_set<int>& online_links,
+ const internal::AddressTrackerLinux::AddressMap& address_map,
+ GetInterfaceNameFunction get_interface_name);
+
+} // namespace internal
+} // namespace net
+
+#endif // NET_BASE_NET_UTIL_LINUX_H_
diff --git a/net/base/net_util_mac.cc b/net/base/net_util_mac.cc
new file mode 100644
index 0000000..5dd4630
--- /dev/null
+++ b/net/base/net_util_mac.cc
@@ -0,0 +1,246 @@
+// Copyright (c) 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/base/net_util_mac.h"
+
+#include <ifaddrs.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <set>
+#include <sys/types.h>
+
+#include "base/files/file_path.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_tokenizer.h"
+#include "base/strings/string_util.h"
+#include "base/threading/thread_restrictions.h"
+#include "net/base/escape.h"
+#include "net/base/ip_endpoint.h"
+#include "net/base/net_errors.h"
+#include "net/base/net_util_posix.h"
+#include "url/gurl.h"
+
+#if !defined(OS_IOS)
+#include <net/if_media.h>
+#include <netinet/in_var.h>
+#include <sys/ioctl.h>
+#endif // !OS_IOS
+
+namespace net {
+
+namespace {
+
+#if !defined(OS_IOS)
+
+// MacOSX implementation of IPAttributesGetterMac which calls ioctl on socket to
+// retrieve IP attributes.
+class IPAttributesGetterMacImpl : public internal::IPAttributesGetterMac {
+ public:
+ IPAttributesGetterMacImpl();
+ ~IPAttributesGetterMacImpl() override;
+ bool IsInitialized() const override;
+ bool GetIPAttributes(const char* ifname,
+ const sockaddr* sock_addr,
+ int* native_attributes) override;
+
+ private:
+ int ioctl_socket_;
+};
+
+IPAttributesGetterMacImpl::IPAttributesGetterMacImpl()
+ : ioctl_socket_(socket(AF_INET6, SOCK_DGRAM, 0)) {
+ DCHECK_GE(ioctl_socket_, 0);
+}
+
+bool IPAttributesGetterMacImpl::IsInitialized() const {
+ return ioctl_socket_ >= 0;
+}
+
+IPAttributesGetterMacImpl::~IPAttributesGetterMacImpl() {
+ if (ioctl_socket_ >= 0) {
+ close(ioctl_socket_);
+ }
+}
+
+bool IPAttributesGetterMacImpl::GetIPAttributes(const char* ifname,
+ const sockaddr* sock_addr,
+ int* native_attributes) {
+ struct in6_ifreq ifr = {};
+ strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name) - 1);
+ memcpy(&ifr.ifr_ifru.ifru_addr, sock_addr, sock_addr->sa_len);
+ int rv = ioctl(ioctl_socket_, SIOCGIFAFLAG_IN6, &ifr);
+ if (rv >= 0) {
+ *native_attributes = ifr.ifr_ifru.ifru_flags;
+ }
+ return (rv >= 0);
+}
+
+// When returning true, the platform native IPv6 address attributes were
+// successfully converted to net IP address attributes. Otherwise, returning
+// false and the caller should drop the IP address which can't be used by the
+// application layer.
+bool TryConvertNativeToNetIPAttributes(int native_attributes,
+ int* net_attributes) {
+ // For MacOSX, we disallow addresses with attributes IN6_IFF_ANYCASE,
+ // IN6_IFF_DUPLICATED, IN6_IFF_TENTATIVE, and IN6_IFF_DETACHED as these are
+ // still progressing through duplicated address detection (DAD) or are not
+ // suitable to be used in an one-to-one communication and shouldn't be used
+ // by the application layer.
+ if (native_attributes & (IN6_IFF_ANYCAST | IN6_IFF_DUPLICATED |
+ IN6_IFF_TENTATIVE | IN6_IFF_DETACHED)) {
+ return false;
+ }
+
+ if (native_attributes & IN6_IFF_TEMPORARY) {
+ *net_attributes |= IP_ADDRESS_ATTRIBUTE_TEMPORARY;
+ }
+
+ if (native_attributes & IN6_IFF_DEPRECATED) {
+ *net_attributes |= IP_ADDRESS_ATTRIBUTE_DEPRECATED;
+ }
+
+ return true;
+}
+
+NetworkChangeNotifier::ConnectionType GetNetworkInterfaceType(
+ int addr_family,
+ const std::string& interface_name) {
+ NetworkChangeNotifier::ConnectionType type =
+ NetworkChangeNotifier::CONNECTION_UNKNOWN;
+
+ struct ifmediareq ifmr = {};
+ strncpy(ifmr.ifm_name, interface_name.c_str(), sizeof(ifmr.ifm_name) - 1);
+
+ int s = socket(addr_family, SOCK_DGRAM, 0);
+ if (s == -1) {
+ return type;
+ }
+
+ if (ioctl(s, SIOCGIFMEDIA, &ifmr) != -1) {
+ if (ifmr.ifm_current & IFM_IEEE80211) {
+ type = NetworkChangeNotifier::CONNECTION_WIFI;
+ } else if (ifmr.ifm_current & IFM_ETHER) {
+ type = NetworkChangeNotifier::CONNECTION_ETHERNET;
+ }
+ }
+ close(s);
+ return type;
+}
+
+#endif // !OS_IOS
+} // namespace
+
+namespace internal {
+
+bool GetNetworkListImpl(NetworkInterfaceList* networks,
+ int policy,
+ const ifaddrs* interfaces,
+ IPAttributesGetterMac* ip_attributes_getter) {
+ // Enumerate the addresses assigned to network interfaces which are up.
+ for (const ifaddrs* interface = interfaces; interface != NULL;
+ interface = interface->ifa_next) {
+ // Skip loopback interfaces, and ones which are down.
+ if (!(IFF_RUNNING & interface->ifa_flags))
+ continue;
+ if (IFF_LOOPBACK & interface->ifa_flags)
+ continue;
+ // Skip interfaces with no address configured.
+ struct sockaddr* addr = interface->ifa_addr;
+ if (!addr)
+ continue;
+
+ // Skip unspecified addresses (i.e. made of zeroes) and loopback addresses
+ // configured on non-loopback interfaces.
+ if (IsLoopbackOrUnspecifiedAddress(addr))
+ continue;
+
+ const std::string& name = interface->ifa_name;
+ // Filter out VMware interfaces, typically named vmnet1 and vmnet8.
+ if (ShouldIgnoreInterface(name, policy)) {
+ continue;
+ }
+
+ NetworkChangeNotifier::ConnectionType connection_type =
+ NetworkChangeNotifier::CONNECTION_UNKNOWN;
+
+ int ip_attributes = IP_ADDRESS_ATTRIBUTE_NONE;
+
+#if !defined(OS_IOS)
+ // Retrieve native ip attributes and convert to net version if a getter is
+ // given.
+ if (ip_attributes_getter && ip_attributes_getter->IsInitialized()) {
+ int native_attributes = 0;
+ if (addr->sa_family == AF_INET6 &&
+ ip_attributes_getter->GetIPAttributes(
+ interface->ifa_name, interface->ifa_addr, &native_attributes)) {
+ if (!TryConvertNativeToNetIPAttributes(native_attributes,
+ &ip_attributes)) {
+ continue;
+ }
+ }
+ }
+
+ connection_type = GetNetworkInterfaceType(addr->sa_family, name);
+#endif // !OS_IOS
+
+ IPEndPoint address;
+
+ int addr_size = 0;
+ if (addr->sa_family == AF_INET6) {
+ addr_size = sizeof(sockaddr_in6);
+ } else if (addr->sa_family == AF_INET) {
+ addr_size = sizeof(sockaddr_in);
+ }
+
+ if (address.FromSockAddr(addr, addr_size)) {
+ uint8 prefix_length = 0;
+ if (interface->ifa_netmask) {
+ // If not otherwise set, assume the same sa_family as ifa_addr.
+ if (interface->ifa_netmask->sa_family == 0) {
+ interface->ifa_netmask->sa_family = addr->sa_family;
+ }
+ IPEndPoint netmask;
+ if (netmask.FromSockAddr(interface->ifa_netmask, addr_size)) {
+ prefix_length = MaskPrefixLength(netmask.address());
+ }
+ }
+ networks->push_back(NetworkInterface(
+ name, name, if_nametoindex(name.c_str()), connection_type,
+ address.address(), prefix_length, ip_attributes));
+ }
+ }
+
+ return true;
+}
+
+} // namespace internal
+
+bool GetNetworkList(NetworkInterfaceList* networks, int policy) {
+ if (networks == NULL)
+ return false;
+
+ // getifaddrs() may require IO operations.
+ base::ThreadRestrictions::AssertIOAllowed();
+
+ ifaddrs* interfaces;
+ if (getifaddrs(&interfaces) < 0) {
+ PLOG(ERROR) << "getifaddrs";
+ return false;
+ }
+
+ scoped_ptr<internal::IPAttributesGetterMac> ip_attributes_getter;
+
+#if !defined(OS_IOS)
+ ip_attributes_getter.reset(new IPAttributesGetterMacImpl());
+#endif
+
+ bool result = internal::GetNetworkListImpl(networks, policy, interfaces,
+ ip_attributes_getter.get());
+ freeifaddrs(interfaces);
+ return result;
+}
+
+} // namespace net
diff --git a/net/base/net_util_mac.h b/net/base/net_util_mac.h
new file mode 100644
index 0000000..178facc
--- /dev/null
+++ b/net/base/net_util_mac.h
@@ -0,0 +1,42 @@
+// Copyright (c) 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_BASE_NET_UTIL_MAC_H_
+#define NET_BASE_NET_UTIL_MAC_H_
+
+// This file is only used to expose some of the internals
+// of net_util_mac.cc to tests.
+
+#include "base/macros.h"
+#include "net/base/net_export.h"
+#include "net/base/net_util.h"
+
+struct ifaddrs;
+struct sockaddr;
+
+namespace net {
+namespace internal {
+
+class NET_EXPORT IPAttributesGetterMac {
+ public:
+ IPAttributesGetterMac() {}
+ virtual ~IPAttributesGetterMac() {}
+ virtual bool IsInitialized() const = 0;
+ virtual bool GetIPAttributes(const char* ifname,
+ const sockaddr* sock_addr,
+ int* native_attributes) = 0;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(IPAttributesGetterMac);
+};
+
+NET_EXPORT bool GetNetworkListImpl(NetworkInterfaceList* networks,
+ int policy,
+ const ifaddrs* interfaces,
+ IPAttributesGetterMac* ip_attributes_getter);
+
+} // namespace internal
+} // namespace net
+
+#endif // NET_BASE_NET_UTIL_MAC_H_
diff --git a/net/base/net_util_posix.cc b/net/base/net_util_posix.cc
index a2fa6cd..b8e7195 100644
--- a/net/base/net_util_posix.cc
+++ b/net/base/net_util_posix.cc
@@ -7,38 +7,18 @@
#include <set>
#include <sys/types.h>
-#include "base/files/file_path.h"
-#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/string_tokenizer.h"
-#include "base/strings/string_util.h"
-#include "base/threading/thread_restrictions.h"
-#include "net/base/escape.h"
-#include "net/base/ip_endpoint.h"
-#include "net/base/net_errors.h"
-#include "url/gurl.h"
#if !defined(OS_NACL)
-#if defined(OS_MACOSX)
-#include <ifaddrs.h>
-#else
-#include "net/base/address_tracker_linux.h"
#include "net/base/net_util_posix.h"
-#endif // OS_MACOSX
#include <net/if.h>
#include <netinet/in.h>
#endif // !defined(OS_NACL)
-#if defined(OS_MACOSX) && !defined(OS_IOS)
-#include <net/if_media.h>
-#include <netinet/in_var.h>
-#include <sys/ioctl.h>
-#endif
-
namespace net {
-namespace {
+#if !defined(OS_NACL)
+namespace internal {
// The application layer can pass |policy| defined in net_util.h to
// request filtering out certain type of interfaces.
@@ -77,330 +57,13 @@
return false;
}
-#if defined(OS_MACOSX)
-
-struct NetworkInterfaceInfo {
- NetworkInterfaceInfo() : permanent(true) { }
-
- bool permanent; // IPv6 has notion of temporary address. If the address is
- // IPv6 and it's temporary this field will be false.
- NetworkInterface interface;
-};
-
-// This method will remove permanent IPv6 addresses if a temporary address
-// is available for same network interface.
-void RemovePermanentIPv6AddressesWhereTemporaryExists(
- std::vector<NetworkInterfaceInfo>* infos) {
- if (!infos || infos->empty())
- return;
-
- // Build a set containing the names of interfaces with a temp IPv6 address
- std::set<std::string> ifaces_with_temp_addrs;
- std::vector<NetworkInterfaceInfo>::iterator i;
- for (i = infos->begin(); i != infos->end(); ++i) {
- if (!i->permanent && i->interface.address.size() == kIPv6AddressSize) {
- ifaces_with_temp_addrs.insert(i->interface.name);
- }
- }
-
- // If there are no such interfaces then there's no further work.
- if (ifaces_with_temp_addrs.empty())
- return;
-
- // Search for permenent addresses belonging to same network interface.
- for (i = infos->begin(); i != infos->end(); ) {
- // If the address is IPv6 and it's permanent and there is temporary
- // address for it, then we can remove this address.
- if ((i->interface.address.size() == kIPv6AddressSize) && i->permanent &&
- (ifaces_with_temp_addrs.find(i->interface.name) !=
- ifaces_with_temp_addrs.end())) {
- i = infos->erase(i);
- } else {
- ++i;
- }
- }
-}
-
-#if !defined(OS_IOS)
-NetworkChangeNotifier::ConnectionType GetNetworkInterfaceType(
- int addr_family, const std::string& interface_name) {
- NetworkChangeNotifier::ConnectionType type =
- NetworkChangeNotifier::CONNECTION_UNKNOWN;
-
- struct ifmediareq ifmr = {};
- strncpy(ifmr.ifm_name, interface_name.c_str(), sizeof(ifmr.ifm_name) - 1);
-
- int s = socket(addr_family, SOCK_DGRAM, 0);
- if (s == -1) {
- return type;
- }
-
- if (ioctl(s, SIOCGIFMEDIA, &ifmr) != -1) {
- if (ifmr.ifm_current & IFM_IEEE80211) {
- type = NetworkChangeNotifier::CONNECTION_WIFI;
- } else if (ifmr.ifm_current & IFM_ETHER) {
- type = NetworkChangeNotifier::CONNECTION_ETHERNET;
- }
- }
- close(s);
- return type;
-}
-
-#endif // !defined(OS_IOS)
-#elif !defined(OS_NACL) // OS_MACOSX
-
-// Convert platform native IPv6 address attributes to net IP address
-// attributes and drop ones that can't be used by the application
-// layer.
-bool TryConvertNativeToNetIPAttributes(int native_attributes,
- int* net_attributes) {
- // For Linux/ChromeOS/Android, we disallow addresses with attributes
- // IFA_F_OPTIMISTIC, IFA_F_DADFAILED, and IFA_F_TENTATIVE as these
- // are still progressing through duplicated address detection (DAD)
- // and shouldn't be used by the application layer until DAD process
- // is completed.
- if (native_attributes & (
-#if !defined(OS_ANDROID)
- IFA_F_OPTIMISTIC | IFA_F_DADFAILED |
-#endif // !OS_ANDROID
- IFA_F_TENTATIVE)) {
- return false;
- }
-
- if (native_attributes & IFA_F_TEMPORARY) {
- *net_attributes |= IP_ADDRESS_ATTRIBUTE_TEMPORARY;
- }
-
- if (native_attributes & IFA_F_DEPRECATED) {
- *net_attributes |= IP_ADDRESS_ATTRIBUTE_DEPRECATED;
- }
-
- return true;
-}
-#endif // OS_MACOSX
-} // namespace
-
-namespace internal {
-
-#if !defined(OS_MACOSX) && !defined(OS_NACL)
-
-inline const unsigned char* GetIPAddressData(const IPAddressNumber& ip) {
-#if defined(OS_ANDROID)
- return ip.begin();
-#else
- return ip.data();
-#endif
-}
-
-bool GetNetworkListImpl(
- NetworkInterfaceList* networks,
- int policy,
- const base::hash_set<int>& online_links,
- const internal::AddressTrackerLinux::AddressMap& address_map,
- GetInterfaceNameFunction get_interface_name) {
- std::map<int, std::string> ifnames;
-
- for (internal::AddressTrackerLinux::AddressMap::const_iterator it =
- address_map.begin();
- it != address_map.end();
- ++it) {
- // Ignore addresses whose links are not online.
- if (online_links.find(it->second.ifa_index) == online_links.end())
- continue;
-
- sockaddr_storage sock_addr;
- socklen_t sock_len = sizeof(sockaddr_storage);
-
- // Convert to sockaddr for next check.
- if (!IPEndPoint(it->first, 0)
- .ToSockAddr(reinterpret_cast<sockaddr*>(&sock_addr), &sock_len)) {
- continue;
- }
-
- // Skip unspecified addresses (i.e. made of zeroes) and loopback addresses
- if (IsLoopbackOrUnspecifiedAddress(reinterpret_cast<sockaddr*>(&sock_addr)))
- continue;
-
- int ip_attributes = IP_ADDRESS_ATTRIBUTE_NONE;
-
- if (it->second.ifa_family == AF_INET6) {
- // Ignore addresses whose attributes are not actionable by
- // the application layer.
- if (!TryConvertNativeToNetIPAttributes(it->second.ifa_flags,
- &ip_attributes))
- continue;
- }
-
- // Find the name of this link.
- std::map<int, std::string>::const_iterator itname =
- ifnames.find(it->second.ifa_index);
- std::string ifname;
- if (itname == ifnames.end()) {
- char buffer[IF_NAMESIZE] = {0};
- if (get_interface_name(it->second.ifa_index, buffer)) {
- ifname = ifnames[it->second.ifa_index] = buffer;
- } else {
- // Ignore addresses whose interface name can't be retrieved.
- continue;
- }
- } else {
- ifname = itname->second;
- }
-
- // Based on the interface name and policy, determine whether we
- // should ignore it.
- if (ShouldIgnoreInterface(ifname, policy))
- continue;
-
- networks->push_back(
- NetworkInterface(ifname,
- ifname,
- it->second.ifa_index,
- NetworkChangeNotifier::CONNECTION_UNKNOWN,
- it->first,
- it->second.ifa_prefixlen,
- ip_attributes));
- }
-
- return true;
-}
-#endif
-
} // namespace internal
-
+#else // OS_NACL
bool GetNetworkList(NetworkInterfaceList* networks, int policy) {
- if (networks == NULL)
- return false;
-#if defined(OS_NACL)
NOTIMPLEMENTED();
return false;
-#elif !defined(OS_MACOSX)
-
- internal::AddressTrackerLinux tracker;
- tracker.Init();
-
- return internal::GetNetworkListImpl(networks,
- policy,
- tracker.GetOnlineLinks(),
- tracker.GetAddressMap(),
- &if_indextoname);
-
-#else // Only OS_MACOSX and OS_IOS will run the code below
-
- // getifaddrs() may require IO operations.
- base::ThreadRestrictions::AssertIOAllowed();
-
-#if !defined(OS_IOS)
- int ioctl_socket = -1;
- if (policy & INCLUDE_ONLY_TEMP_IPV6_ADDRESS_IF_POSSIBLE) {
- // we need a socket to query information about temporary address.
- ioctl_socket = socket(AF_INET6, SOCK_DGRAM, 0);
- DCHECK_GT(ioctl_socket, 0);
- }
-#endif
-
- ifaddrs* interfaces;
- if (getifaddrs(&interfaces) < 0) {
- PLOG(ERROR) << "getifaddrs";
- return false;
- }
-
- std::vector<NetworkInterfaceInfo> network_infos;
-
- // Enumerate the addresses assigned to network interfaces which are up.
- for (ifaddrs *interface = interfaces;
- interface != NULL;
- interface = interface->ifa_next) {
- // Skip loopback interfaces, and ones which are down.
- if (!(IFF_UP & interface->ifa_flags))
- continue;
- if (IFF_LOOPBACK & interface->ifa_flags)
- continue;
- // Skip interfaces with no address configured.
- struct sockaddr* addr = interface->ifa_addr;
- if (!addr)
- continue;
-
- // Skip unspecified addresses (i.e. made of zeroes) and loopback addresses
- // configured on non-loopback interfaces.
- if (IsLoopbackOrUnspecifiedAddress(addr))
- continue;
-
- int addr_size = 0;
- if (addr->sa_family == AF_INET6) {
- addr_size = sizeof(sockaddr_in6);
- } else if (addr->sa_family == AF_INET) {
- addr_size = sizeof(sockaddr_in);
- }
-
- const std::string& name = interface->ifa_name;
- // Filter out VMware interfaces, typically named vmnet1 and vmnet8.
- if (ShouldIgnoreInterface(name, policy)) {
- continue;
- }
-
- NetworkInterfaceInfo network_info;
- NetworkChangeNotifier::ConnectionType connection_type =
- NetworkChangeNotifier::CONNECTION_UNKNOWN;
-#if !defined(OS_IOS)
- // Check if this is a temporary address. Currently this is only supported
- // on Mac.
- if ((policy & INCLUDE_ONLY_TEMP_IPV6_ADDRESS_IF_POSSIBLE) &&
- ioctl_socket >= 0 && addr->sa_family == AF_INET6) {
- struct in6_ifreq ifr = {};
- strncpy(ifr.ifr_name, interface->ifa_name, sizeof(ifr.ifr_name) - 1);
- memcpy(&ifr.ifr_ifru.ifru_addr, interface->ifa_addr,
- interface->ifa_addr->sa_len);
- int rv = ioctl(ioctl_socket, SIOCGIFAFLAG_IN6, &ifr);
- if (rv >= 0) {
- network_info.permanent = !(ifr.ifr_ifru.ifru_flags & IN6_IFF_TEMPORARY);
- }
- }
-
- connection_type = GetNetworkInterfaceType(addr->sa_family, name);
-#endif
-
- IPEndPoint address;
- if (address.FromSockAddr(addr, addr_size)) {
- uint8 net_mask = 0;
- if (interface->ifa_netmask) {
- // If not otherwise set, assume the same sa_family as ifa_addr.
- if (interface->ifa_netmask->sa_family == 0) {
- interface->ifa_netmask->sa_family = addr->sa_family;
- }
- IPEndPoint netmask;
- if (netmask.FromSockAddr(interface->ifa_netmask, addr_size)) {
- net_mask = MaskPrefixLength(netmask.address());
- }
- }
- network_info.interface = NetworkInterface(name,
- name,
- if_nametoindex(name.c_str()),
- connection_type,
- address.address(),
- net_mask,
- IP_ADDRESS_ATTRIBUTE_NONE);
-
- network_infos.push_back(NetworkInterfaceInfo(network_info));
- }
- }
- freeifaddrs(interfaces);
-#if !defined(OS_IOS)
- if (ioctl_socket >= 0) {
- close(ioctl_socket);
- }
-#endif
-
- if (policy & INCLUDE_ONLY_TEMP_IPV6_ADDRESS_IF_POSSIBLE) {
- RemovePermanentIPv6AddressesWhereTemporaryExists(&network_infos);
- }
-
- for (size_t i = 0; i < network_infos.size(); ++i) {
- networks->push_back(network_infos[i].interface);
- }
- return true;
-#endif
}
+#endif // OS_NACL
WifiPHYLayerProtocol GetWifiPHYLayerProtocol() {
return WIFI_PHY_LAYER_PROTOCOL_UNKNOWN;
diff --git a/net/base/net_util_posix.h b/net/base/net_util_posix.h
index b553d1c..93089c2 100644
--- a/net/base/net_util_posix.h
+++ b/net/base/net_util_posix.h
@@ -5,27 +5,21 @@
#ifndef NET_BASE_NET_UTIL_POSIX_H_
#define NET_BASE_NET_UTIL_POSIX_H_
-// This file is only used to expose some of the internals
-// of net_util_posix.cc to tests.
+// This file is only used to expose some of the internals of
+// net_util_posix.cc to net_util_linux.cc and net_util_mac.cc.
+
+#include <string>
+
+struct sockaddr;
namespace net {
namespace internal {
-
-#if !defined(OS_MACOSX) && !defined(OS_NACL)
-typedef char* (*GetInterfaceNameFunction)(unsigned int interface_index,
- char* ifname);
-
-NET_EXPORT bool GetNetworkListImpl(
- NetworkInterfaceList* networks,
- int policy,
- const base::hash_set<int>& online_links,
- const internal::AddressTrackerLinux::AddressMap& address_map,
- GetInterfaceNameFunction get_interface_name);
-
-#endif // !OS_MACOSX && !OS_NACL
+#if !defined(OS_NACL)
+bool ShouldIgnoreInterface(const std::string& name, int policy);
+bool IsLoopbackOrUnspecifiedAddress(const sockaddr* addr);
+#endif // !OS_NACL
} // namespace internal
-
} // namespace net
#endif // NET_BASE_NET_UTIL_POSIX_H_
diff --git a/net/base/net_util_unittest.cc b/net/base/net_util_unittest.cc
index 45f0857..a25903a 100644
--- a/net/base/net_util_unittest.cc
+++ b/net/base/net_util_unittest.cc
@@ -17,10 +17,17 @@
#include "base/strings/utf_string_conversions.h"
#include "base/sys_byteorder.h"
#include "base/time/time.h"
+#include "net/base/ip_endpoint.h"
#if !defined(OS_NACL) && !defined(OS_WIN)
#include <net/if.h>
#include <netinet/in.h>
+#if defined(OS_MACOSX)
+#include <ifaddrs.h>
+#if !defined(OS_IOS)
+#include <netinet/in_var.h>
+#endif // !OS_IOS
+#endif // OS_MACOSX
#endif // !OS_NACL && !OS_WIN
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
@@ -38,6 +45,11 @@
#if !defined(OS_WIN)
#include "net/base/net_util_posix.h"
+#if defined(OS_MACOSX)
+#include "net/base/net_util_mac.h"
+#else // OS_MACOSX
+#include "net/base/net_util_linux.h"
+#endif
#endif // !OS_WIN
using base::ASCIIToUTF16;
@@ -85,6 +97,58 @@
return out;
}
+#if defined(OS_MACOSX)
+class IPAttributesGetterTest : public internal::IPAttributesGetterMac {
+ public:
+ IPAttributesGetterTest() : native_attributes_(0) {}
+ bool IsInitialized() const override { return true; }
+ bool GetIPAttributes(const char* ifname,
+ const sockaddr* sock_addr,
+ int* native_attributes) override {
+ *native_attributes = native_attributes_;
+ return true;
+ }
+ void set_native_attributes(int native_attributes) {
+ native_attributes_ = native_attributes;
+ }
+
+ private:
+ int native_attributes_;
+};
+
+// Helper function to create a single valid ifaddrs
+bool FillIfaddrs(ifaddrs* interfaces,
+ const char* ifname,
+ uint flags,
+ const IPAddressNumber& ip_address,
+ const IPAddressNumber& ip_netmask,
+ sockaddr_storage sock_addrs[2]) {
+ interfaces->ifa_next = NULL;
+ interfaces->ifa_name = const_cast<char*>(ifname);
+ interfaces->ifa_flags = flags;
+
+ socklen_t sock_len = sizeof(sockaddr_storage);
+
+ // Convert to sockaddr for next check.
+ if (!IPEndPoint(ip_address, 0)
+ .ToSockAddr(reinterpret_cast<sockaddr*>(&sock_addrs[0]),
+ &sock_len)) {
+ return false;
+ }
+ interfaces->ifa_addr = reinterpret_cast<sockaddr*>(&sock_addrs[0]);
+
+ sock_len = sizeof(sockaddr_storage);
+ if (!IPEndPoint(ip_netmask, 0)
+ .ToSockAddr(reinterpret_cast<sockaddr*>(&sock_addrs[1]),
+ &sock_len)) {
+ return false;
+ }
+ interfaces->ifa_netmask = reinterpret_cast<sockaddr*>(&sock_addrs[1]);
+
+ return true;
+}
+#endif // OS_MACOSX
+
} // anonymous namespace
TEST(NetUtilTest, GetIdentityFromURL) {
@@ -812,6 +876,18 @@
}
}
+static const char ifname_em1[] = "em1";
+static const char ifname_vm[] = "vmnet";
+
+static const unsigned char kIPv6LocalAddr[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1};
+static const unsigned char kIPv6Addr[] =
+ {0x24, 0x01, 0xfa, 0x00, 0x00, 0x04, 0x10, 0x00, 0xbe, 0x30, 0x5b, 0xff,
+ 0xfe, 0xe5, 0x00, 0xc3};
+static const unsigned char kIPv6Netmask[] =
+ {0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00};
+
#if !defined(OS_MACOSX) && !defined(OS_WIN) && !defined(OS_NACL)
char* CopyInterfaceName(const char* ifname, int ifname_size, char* output) {
@@ -820,30 +896,24 @@
return output;
}
-static const char ifname_em1[] = "em1";
char* GetInterfaceName(unsigned int interface_index, char* ifname) {
return CopyInterfaceName(ifname_em1, arraysize(ifname_em1), ifname);
}
-static const char ifname_vm[] = "vmnet";
char* GetInterfaceNameVM(unsigned int interface_index, char* ifname) {
return CopyInterfaceName(ifname_vm, arraysize(ifname_vm), ifname);
}
TEST(NetUtilTest, GetNetworkListTrimming) {
- NetworkInterfaceList results;
- ::base::hash_set<int> online_links;
- net::internal::AddressTrackerLinux::AddressMap address_map;
-
- const unsigned char kIPv6LocalAddr[] = {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1};
- const unsigned char kIPv6Addr[] =
- {0x24, 0x01, 0xfa, 0x00, 0x00, 0x04, 0x10, 0x00, 0xbe, 0x30, 0x5b, 0xff,
- 0xfe, 0xe5, 0x00, 0xc3};
-
IPAddressNumber ipv6_local_address(
kIPv6LocalAddr, kIPv6LocalAddr + arraysize(kIPv6LocalAddr));
IPAddressNumber ipv6_address(kIPv6Addr, kIPv6Addr + arraysize(kIPv6Addr));
+ IPAddressNumber ipv6_netmask(kIPv6Netmask,
+ kIPv6Netmask + arraysize(kIPv6Netmask));
+
+ NetworkInterfaceList results;
+ ::base::hash_set<int> online_links;
+ net::internal::AddressTrackerLinux::AddressMap address_map;
// Interface 1 is offline.
struct ifaddrmsg msg = {
@@ -956,7 +1026,101 @@
results.clear();
}
-#endif
+#elif defined(OS_MACOSX)
+
+TEST(NetUtilTest, GetNetworkListTrimming) {
+ IPAddressNumber ipv6_local_address(
+ kIPv6LocalAddr, kIPv6LocalAddr + arraysize(kIPv6LocalAddr));
+ IPAddressNumber ipv6_address(kIPv6Addr, kIPv6Addr + arraysize(kIPv6Addr));
+ IPAddressNumber ipv6_netmask(kIPv6Netmask,
+ kIPv6Netmask + arraysize(kIPv6Netmask));
+
+ NetworkInterfaceList results;
+ IPAttributesGetterTest ip_attributes_getter;
+ sockaddr_storage addresses[2];
+ ifaddrs interface;
+
+ // Address of offline links should be ignored.
+ ASSERT_TRUE(FillIfaddrs(&interface, ifname_em1, IFF_UP, ipv6_address,
+ ipv6_netmask, addresses));
+ EXPECT_TRUE(net::internal::GetNetworkListImpl(
+ &results, INCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES, &interface,
+ &ip_attributes_getter));
+ EXPECT_EQ(results.size(), 0ul);
+
+ // Local address should be trimmed out.
+ ASSERT_TRUE(FillIfaddrs(&interface, ifname_em1, IFF_RUNNING,
+ ipv6_local_address, ipv6_netmask, addresses));
+ EXPECT_TRUE(net::internal::GetNetworkListImpl(
+ &results, INCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES, &interface,
+ &ip_attributes_getter));
+ EXPECT_EQ(results.size(), 0ul);
+
+ // vmware address should return by default.
+ ASSERT_TRUE(FillIfaddrs(&interface, ifname_vm, IFF_RUNNING, ipv6_address,
+ ipv6_netmask, addresses));
+ EXPECT_TRUE(net::internal::GetNetworkListImpl(
+ &results, INCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES, &interface,
+ &ip_attributes_getter));
+ EXPECT_EQ(results.size(), 1ul);
+ EXPECT_EQ(results[0].name, ifname_vm);
+ EXPECT_EQ(results[0].network_prefix, 1ul);
+ EXPECT_EQ(results[0].address, ipv6_address);
+ results.clear();
+
+ // vmware address should be trimmed out if policy specified so.
+ ASSERT_TRUE(FillIfaddrs(&interface, ifname_vm, IFF_RUNNING, ipv6_address,
+ ipv6_netmask, addresses));
+ EXPECT_TRUE(net::internal::GetNetworkListImpl(
+ &results, EXCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES, &interface,
+ &ip_attributes_getter));
+ EXPECT_EQ(results.size(), 0ul);
+ results.clear();
+
+#if !defined(OS_IOS)
+ // Addresses with banned attributes should be ignored.
+ ip_attributes_getter.set_native_attributes(IN6_IFF_ANYCAST);
+ ASSERT_TRUE(FillIfaddrs(&interface, ifname_em1, IFF_RUNNING, ipv6_address,
+ ipv6_netmask, addresses));
+ EXPECT_TRUE(net::internal::GetNetworkListImpl(
+ &results, INCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES, &interface,
+ &ip_attributes_getter));
+ EXPECT_EQ(results.size(), 0ul);
+ results.clear();
+
+ // Addresses with allowed attribute IFA_F_TEMPORARY should be returned and
+ // attributes should be translated correctly.
+ ip_attributes_getter.set_native_attributes(IN6_IFF_TEMPORARY);
+ ASSERT_TRUE(FillIfaddrs(&interface, ifname_em1, IFF_RUNNING, ipv6_address,
+ ipv6_netmask, addresses));
+ EXPECT_TRUE(net::internal::GetNetworkListImpl(
+ &results, INCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES, &interface,
+ &ip_attributes_getter));
+ EXPECT_EQ(results.size(), 1ul);
+ EXPECT_EQ(results[0].name, ifname_em1);
+ EXPECT_EQ(results[0].network_prefix, 1ul);
+ EXPECT_EQ(results[0].address, ipv6_address);
+ EXPECT_EQ(results[0].ip_address_attributes, IP_ADDRESS_ATTRIBUTE_TEMPORARY);
+ results.clear();
+
+ // Addresses with allowed attribute IFA_F_DEPRECATED should be returned and
+ // attributes should be translated correctly.
+ ip_attributes_getter.set_native_attributes(IN6_IFF_DEPRECATED);
+ ASSERT_TRUE(FillIfaddrs(&interface, ifname_em1, IFF_RUNNING, ipv6_address,
+ ipv6_netmask, addresses));
+ EXPECT_TRUE(net::internal::GetNetworkListImpl(
+ &results, INCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES, &interface,
+ &ip_attributes_getter));
+ EXPECT_EQ(results.size(), 1ul);
+ EXPECT_EQ(results[0].name, ifname_em1);
+ EXPECT_EQ(results[0].network_prefix, 1ul);
+ EXPECT_EQ(results[0].address, ipv6_address);
+ EXPECT_EQ(results[0].ip_address_attributes, IP_ADDRESS_ATTRIBUTE_DEPRECATED);
+ results.clear();
+#endif // !OS_IOS
+}
+
+#endif // !OS_MACOSX && !OS_WIN && !OS_NACL
namespace {
diff --git a/net/base/network_activity_monitor.cc b/net/base/network_activity_monitor.cc
new file mode 100644
index 0000000..78da8c8
--- /dev/null
+++ b/net/base/network_activity_monitor.cc
@@ -0,0 +1,64 @@
+// Copyright (c) 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/base/network_activity_monitor.h"
+
+namespace net {
+
+namespace {
+
+base::LazyInstance<NetworkActivityMonitor>::Leaky g_network_activity_monitor =
+ LAZY_INSTANCE_INITIALIZER;
+
+} // namespace
+
+NetworkActivityMonitor::NetworkActivityMonitor()
+ : bytes_received_(0), bytes_sent_(0) {
+}
+
+NetworkActivityMonitor::~NetworkActivityMonitor() {
+}
+
+// static
+NetworkActivityMonitor* NetworkActivityMonitor::GetInstance() {
+ return g_network_activity_monitor.Pointer();
+}
+
+void NetworkActivityMonitor::IncrementBytesReceived(uint64_t bytes_received) {
+ base::TimeTicks now = base::TimeTicks::Now();
+ base::AutoLock lock(lock_);
+ bytes_received_ += bytes_received;
+ last_received_ticks_ = now;
+}
+
+void NetworkActivityMonitor::IncrementBytesSent(uint64_t bytes_sent) {
+ base::TimeTicks now = base::TimeTicks::Now();
+ base::AutoLock lock(lock_);
+ bytes_sent_ += bytes_sent;
+ last_sent_ticks_ = now;
+}
+
+uint64_t NetworkActivityMonitor::GetBytesReceived() const {
+ base::AutoLock lock(lock_);
+ return bytes_received_;
+}
+
+uint64_t NetworkActivityMonitor::GetBytesSent() const {
+ base::AutoLock lock(lock_);
+ return bytes_sent_;
+}
+
+base::TimeDelta NetworkActivityMonitor::GetTimeSinceLastReceived() const {
+ base::TimeTicks now = base::TimeTicks::Now();
+ base::AutoLock lock(lock_);
+ return now - last_received_ticks_;
+}
+
+base::TimeDelta NetworkActivityMonitor::GetTimeSinceLastSent() const {
+ base::TimeTicks now = base::TimeTicks::Now();
+ base::AutoLock lock(lock_);
+ return now - last_sent_ticks_;
+}
+
+} // namespace net
diff --git a/net/base/network_activity_monitor.h b/net/base/network_activity_monitor.h
new file mode 100644
index 0000000..5319477
--- /dev/null
+++ b/net/base/network_activity_monitor.h
@@ -0,0 +1,68 @@
+// Copyright (c) 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_BASE_NETWORK_ACTIVITY_MONITOR_H_
+#define NET_BASE_NETWORK_ACTIVITY_MONITOR_H_
+
+#include "base/basictypes.h"
+#include "base/lazy_instance.h"
+#include "base/synchronization/lock.h"
+#include "base/time/time.h"
+#include "net/base/net_export.h"
+
+namespace net {
+
+namespace test {
+
+class NetworkActivityMonitorPeer;
+
+} // namespace test
+
+// NetworkActivityMonitor tracks network activity across all sockets and
+// provides cumulative statistics about bytes sent to and received from
+// the network. It uses a lock to ensure thread-safety.
+//
+// There are a few caveats:
+// * Bytes "sent" includes all send attempts and may include
+// some bytes which were actually never sent over the network.
+// * Bytes received includes only bytes actually received from the network,
+// and does not include any bytes read from the the cache.
+// * Network activity not initiated directly using chromium sockets won't
+// be reflected here (for instance DNS queries issued by getaddrinfo()).
+class NET_EXPORT_PRIVATE NetworkActivityMonitor {
+ public:
+ // Returns the singleton instance of the monitor.
+ static NetworkActivityMonitor* GetInstance();
+
+ void IncrementBytesReceived(uint64_t bytes_received);
+ void IncrementBytesSent(uint64_t bytes_sent);
+
+ uint64_t GetBytesReceived() const;
+ uint64_t GetBytesSent() const;
+
+ base::TimeDelta GetTimeSinceLastReceived() const;
+ base::TimeDelta GetTimeSinceLastSent() const;
+
+ private:
+ friend class test::NetworkActivityMonitorPeer;
+
+ NetworkActivityMonitor();
+ ~NetworkActivityMonitor();
+ friend struct base::DefaultLazyInstanceTraits<NetworkActivityMonitor>;
+
+ // Protects all the following members.
+ mutable base::Lock lock_;
+
+ uint64_t bytes_received_;
+ uint64_t bytes_sent_;
+
+ base::TimeTicks last_received_ticks_;
+ base::TimeTicks last_sent_ticks_;
+
+ DISALLOW_COPY_AND_ASSIGN(NetworkActivityMonitor);
+};
+
+} // namespace net
+
+#endif // NET_BASE_NETWORK_ACTIVITY_MONITOR_H_
diff --git a/net/base/network_activity_monitor_unittest.cc b/net/base/network_activity_monitor_unittest.cc
new file mode 100644
index 0000000..e625c55
--- /dev/null
+++ b/net/base/network_activity_monitor_unittest.cc
@@ -0,0 +1,131 @@
+// Copyright (c) 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/base/network_activity_monitor.h"
+
+#include <vector>
+
+#include "base/bind.h"
+#include "base/port.h"
+#include "base/stl_util.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/synchronization/lock.h"
+#include "base/threading/thread.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+
+namespace test {
+
+class NetworkActivityMonitorPeer {
+ public:
+ static void ResetMonitor() {
+ NetworkActivityMonitor* monitor = NetworkActivityMonitor::GetInstance();
+ base::AutoLock lock(monitor->lock_);
+ monitor->bytes_sent_ = 0;
+ monitor->bytes_received_ = 0;
+ monitor->last_received_ticks_ = base::TimeTicks();
+ monitor->last_sent_ticks_ = base::TimeTicks();
+ }
+};
+
+
+class NetworkActivityMontiorTest : public testing::Test {
+ public:
+ NetworkActivityMontiorTest() {
+ NetworkActivityMonitorPeer::ResetMonitor();
+ }
+};
+
+TEST_F(NetworkActivityMontiorTest, GetInstance) {
+ NetworkActivityMonitor* monitor = NetworkActivityMonitor::GetInstance();
+ EXPECT_TRUE(monitor != NULL);
+ EXPECT_TRUE(monitor == NetworkActivityMonitor::GetInstance());
+}
+
+TEST_F(NetworkActivityMontiorTest, BytesReceived) {
+ NetworkActivityMonitor* monitor = NetworkActivityMonitor::GetInstance();
+
+ EXPECT_EQ(0u, monitor->GetBytesReceived());
+
+ base::TimeTicks start = base::TimeTicks::Now();
+ uint64_t bytes = 12345;
+ monitor->IncrementBytesReceived(bytes);
+ EXPECT_EQ(bytes, monitor->GetBytesReceived());
+ base::TimeDelta delta = monitor->GetTimeSinceLastReceived();
+ EXPECT_LE(base::TimeDelta(), delta);
+ EXPECT_GE(base::TimeTicks::Now() - start, delta);
+}
+
+TEST_F(NetworkActivityMontiorTest, BytesSent) {
+ NetworkActivityMonitor* monitor = NetworkActivityMonitor::GetInstance();
+
+ EXPECT_EQ(0u, monitor->GetBytesSent());
+
+ base::TimeTicks start = base::TimeTicks::Now();
+ uint64_t bytes = 12345;
+ monitor->IncrementBytesSent(bytes);
+ EXPECT_EQ(bytes, monitor->GetBytesSent());
+ base::TimeDelta delta = monitor->GetTimeSinceLastSent();
+ EXPECT_LE(base::TimeDelta(), delta);
+ EXPECT_GE(base::TimeTicks::Now() - start, delta);
+}
+
+namespace {
+
+void VerifyBytesReceivedIsMultipleOf(uint64_t bytes) {
+ EXPECT_EQ(0u,
+ NetworkActivityMonitor::GetInstance()->GetBytesReceived() % bytes);
+}
+
+void VerifyBytesSentIsMultipleOf(uint64_t bytes) {
+ EXPECT_EQ(0u, NetworkActivityMonitor::GetInstance()->GetBytesSent() % bytes);
+}
+
+void IncrementBytesReceived(uint64_t bytes) {
+ NetworkActivityMonitor::GetInstance()->IncrementBytesReceived(bytes);
+}
+
+void IncrementBytesSent(uint64_t bytes) {
+ NetworkActivityMonitor::GetInstance()->IncrementBytesSent(bytes);
+}
+
+} // namespace
+
+TEST_F(NetworkActivityMontiorTest, Threading) {
+ std::vector<base::Thread*> threads;
+ for (size_t i = 0; i < 3; ++i) {
+ threads.push_back(new base::Thread(base::UintToString(i)));
+ ASSERT_TRUE(threads.back()->Start());
+ }
+
+ size_t num_increments = 157;
+ uint64_t bytes_received = GG_UINT64_C(7294954321);
+ uint64_t bytes_sent = GG_UINT64_C(91294998765);
+ for (size_t i = 0; i < num_increments; ++i) {
+ size_t thread_num = i % threads.size();
+ threads[thread_num]->task_runner()->PostTask(
+ FROM_HERE,
+ base::Bind(&IncrementBytesReceived, bytes_received));
+ threads[thread_num]->task_runner()->PostTask(
+ FROM_HERE,
+ base::Bind(&IncrementBytesSent, bytes_sent));
+ threads[thread_num]->task_runner()->PostTask(
+ FROM_HERE,
+ base::Bind(&VerifyBytesSentIsMultipleOf, bytes_sent));
+ threads[thread_num]->task_runner()->PostTask(
+ FROM_HERE,
+ base::Bind(&VerifyBytesReceivedIsMultipleOf, bytes_received));
+ }
+
+ STLDeleteElements(&threads);
+
+ NetworkActivityMonitor* monitor = NetworkActivityMonitor::GetInstance();
+ EXPECT_EQ(num_increments * bytes_received, monitor->GetBytesReceived());
+ EXPECT_EQ(num_increments * bytes_sent, monitor->GetBytesSent());
+}
+
+} // namespace test
+
+} // namespace net
diff --git a/net/base/sdch_manager.cc b/net/base/sdch_manager.cc
index 1285ad9..af5e6ee 100644
--- a/net/base/sdch_manager.cc
+++ b/net/base/sdch_manager.cc
@@ -9,6 +9,7 @@
#include "base/metrics/histogram.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
+#include "base/values.h"
#include "crypto/sha2.h"
#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
#include "net/base/sdch_observer.h"
@@ -78,7 +79,8 @@
SdchManager::Dictionary::~Dictionary() {
}
-bool SdchManager::Dictionary::CanAdvertise(const GURL& target_url) {
+SdchProblemCode SdchManager::Dictionary::CanAdvertise(
+ const GURL& target_url) const {
/* The specific rules of when a dictionary should be advertised in an
Avail-Dictionary header are modeled after the rules for cookie scoping. The
terms "domain-match" and "pathmatch" are defined in RFC 2965 [6]. A
@@ -95,28 +97,28 @@
url scheme.
*/
if (!DomainMatch(target_url, domain_))
- return false;
+ return SDCH_DICTIONARY_FOUND_HAS_WRONG_DOMAIN;
if (!ports_.empty() && 0 == ports_.count(target_url.EffectiveIntPort()))
- return false;
+ return SDCH_DICTIONARY_FOUND_HAS_WRONG_PORT_LIST;
if (path_.size() && !PathMatch(target_url.path(), path_))
- return false;
+ return SDCH_DICTIONARY_FOUND_HAS_WRONG_PATH;
if (!SdchManager::secure_scheme_supported() && target_url.SchemeIsSecure())
- return false;
+ return SDCH_DICTIONARY_FOUND_HAS_WRONG_SCHEME;
if (target_url.SchemeIsSecure() != url_.SchemeIsSecure())
- return false;
+ return SDCH_DICTIONARY_FOUND_HAS_WRONG_SCHEME;
if (base::Time::Now() > expiration_)
- return false;
- return true;
+ return SDCH_DICTIONARY_FOUND_EXPIRED;
+ return SDCH_OK;
}
//------------------------------------------------------------------------------
// Security functions restricting loads and use of dictionaries.
// static
-bool SdchManager::Dictionary::CanSet(const std::string& domain,
- const std::string& path,
- const std::set<int>& ports,
- const GURL& dictionary_url) {
+SdchProblemCode SdchManager::Dictionary::CanSet(const std::string& domain,
+ const std::string& path,
+ const std::set<int>& ports,
+ const GURL& dictionary_url) {
/*
A dictionary is invalid and must not be stored if any of the following are
true:
@@ -135,20 +137,17 @@
// and hence the conservative approach is to not allow any redirects (if there
// were any... then don't allow the dictionary to be set).
- if (domain.empty()) {
- SdchErrorRecovery(DICTIONARY_MISSING_DOMAIN_SPECIFIER);
- return false; // Domain is required.
- }
+ if (domain.empty())
+ return SDCH_DICTIONARY_MISSING_DOMAIN_SPECIFIER; // Domain is required.
+
if (registry_controlled_domains::GetDomainAndRegistry(
- domain,
- registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES).empty()) {
- SdchErrorRecovery(DICTIONARY_SPECIFIES_TOP_LEVEL_DOMAIN);
- return false; // domain was a TLD.
+ domain, registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES)
+ .empty()) {
+ return SDCH_DICTIONARY_SPECIFIES_TOP_LEVEL_DOMAIN; // domain was a TLD.
}
- if (!Dictionary::DomainMatch(dictionary_url, domain)) {
- SdchErrorRecovery(DICTIONARY_DOMAIN_NOT_MATCHING_SOURCE_URL);
- return false;
- }
+
+ if (!Dictionary::DomainMatch(dictionary_url, domain))
+ return SDCH_DICTIONARY_DOMAIN_NOT_MATCHING_SOURCE_URL;
std::string referrer_url_host = dictionary_url.host();
size_t postfix_domain_index = referrer_url_host.rfind(domain);
@@ -156,23 +155,20 @@
if (referrer_url_host.size() == postfix_domain_index + domain.size()) {
// It is a postfix... so check to see if there's a dot in the prefix.
size_t end_of_host_index = referrer_url_host.find_first_of('.');
- if (referrer_url_host.npos != end_of_host_index &&
+ if (referrer_url_host.npos != end_of_host_index &&
end_of_host_index < postfix_domain_index) {
- SdchErrorRecovery(DICTIONARY_REFERER_URL_HAS_DOT_IN_PREFIX);
- return false;
+ return SDCH_DICTIONARY_REFERER_URL_HAS_DOT_IN_PREFIX;
}
}
- if (!ports.empty()
- && 0 == ports.count(dictionary_url.EffectiveIntPort())) {
- SdchErrorRecovery(DICTIONARY_PORT_NOT_MATCHING_SOURCE_URL);
- return false;
- }
- return true;
+ if (!ports.empty() && 0 == ports.count(dictionary_url.EffectiveIntPort()))
+ return SDCH_DICTIONARY_PORT_NOT_MATCHING_SOURCE_URL;
+
+ return SDCH_OK;
}
-// static
-bool SdchManager::Dictionary::CanUse(const GURL& referring_url) {
+SdchProblemCode SdchManager::Dictionary::CanUse(
+ const GURL& referring_url) const {
/*
1. The request URL's host name domain-matches the Domain attribute of the
dictionary.
@@ -184,39 +180,30 @@
HTTPS support AND the dictionary acquisition scheme matches the target
url scheme.
*/
- if (!DomainMatch(referring_url, domain_)) {
- SdchErrorRecovery(DICTIONARY_FOUND_HAS_WRONG_DOMAIN);
- return false;
- }
- if (!ports_.empty()
- && 0 == ports_.count(referring_url.EffectiveIntPort())) {
- SdchErrorRecovery(DICTIONARY_FOUND_HAS_WRONG_PORT_LIST);
- return false;
- }
- if (path_.size() && !PathMatch(referring_url.path(), path_)) {
- SdchErrorRecovery(DICTIONARY_FOUND_HAS_WRONG_PATH);
- return false;
- }
- if (!SdchManager::secure_scheme_supported() &&
- referring_url.SchemeIsSecure()) {
- SdchErrorRecovery(DICTIONARY_FOUND_HAS_WRONG_SCHEME);
- return false;
- }
- if (referring_url.SchemeIsSecure() != url_.SchemeIsSecure()) {
- SdchErrorRecovery(DICTIONARY_FOUND_HAS_WRONG_SCHEME);
- return false;
- }
+ if (!DomainMatch(referring_url, domain_))
+ return SDCH_DICTIONARY_FOUND_HAS_WRONG_DOMAIN;
+
+ if (!ports_.empty() && 0 == ports_.count(referring_url.EffectiveIntPort()))
+ return SDCH_DICTIONARY_FOUND_HAS_WRONG_PORT_LIST;
+
+ if (path_.size() && !PathMatch(referring_url.path(), path_))
+ return SDCH_DICTIONARY_FOUND_HAS_WRONG_PATH;
+
+ if (!SdchManager::secure_scheme_supported() && referring_url.SchemeIsSecure())
+ return SDCH_DICTIONARY_FOUND_HAS_WRONG_SCHEME;
+
+ if (referring_url.SchemeIsSecure() != url_.SchemeIsSecure())
+ return SDCH_DICTIONARY_FOUND_HAS_WRONG_SCHEME;
// TODO(jar): Remove overly restrictive failsafe test (added per security
// review) when we have a need to be more general.
- if (!referring_url.SchemeIsHTTPOrHTTPS()) {
- SdchErrorRecovery(ATTEMPT_TO_DECODE_NON_HTTP_DATA);
- return false;
- }
+ if (!referring_url.SchemeIsHTTPOrHTTPS())
+ return SDCH_ATTEMPT_TO_DECODE_NON_HTTP_DATA;
- return true;
+ return SDCH_OK;
}
+// static
bool SdchManager::Dictionary::PathMatch(const std::string& path,
const std::string& restriction) {
/* Must be either:
@@ -268,8 +255,9 @@
}
// static
-void SdchManager::SdchErrorRecovery(ProblemCodes problem) {
- UMA_HISTOGRAM_ENUMERATION("Sdch3.ProblemCodes_4", problem, MAX_PROBLEM_CODE);
+void SdchManager::SdchErrorRecovery(SdchProblemCode problem) {
+ UMA_HISTOGRAM_ENUMERATION("Sdch3.ProblemCodes_5", problem,
+ SDCH_MAX_PROBLEM_CODE);
}
// static
@@ -283,7 +271,7 @@
}
void SdchManager::BlacklistDomain(const GURL& url,
- ProblemCodes blacklist_reason) {
+ SdchProblemCode blacklist_reason) {
SetAllowLatencyExperiment(url, false);
BlacklistInfo* blacklist_info =
@@ -304,7 +292,7 @@
}
void SdchManager::BlacklistDomainForever(const GURL& url,
- ProblemCodes blacklist_reason) {
+ SdchProblemCode blacklist_reason) {
SetAllowLatencyExperiment(url, false);
BlacklistInfo* blacklist_info =
@@ -322,7 +310,7 @@
BlacklistInfo* blacklist_info = &blacklisted_domains_[
base::StringToLowerASCII(domain)];
blacklist_info->count = 0;
- blacklist_info->reason = MIN_PROBLEM_CODE;
+ blacklist_info->reason = SDCH_OK;
}
int SdchManager::BlackListDomainCount(const std::string& domain) {
@@ -341,49 +329,53 @@
return blacklisted_domains_[domain_lower].exponential_count;
}
-bool SdchManager::IsInSupportedDomain(const GURL& url) {
+SdchProblemCode SdchManager::IsInSupportedDomain(const GURL& url) {
DCHECK(thread_checker_.CalledOnValidThread());
if (!g_sdch_enabled_ )
- return false;
+ return SDCH_DISABLED;
if (!secure_scheme_supported() && url.SchemeIsSecure())
- return false;
+ return SDCH_SECURE_SCHEME_NOT_SUPPORTED;
if (blacklisted_domains_.empty())
- return true;
+ return SDCH_OK;
DomainBlacklistInfo::iterator it =
blacklisted_domains_.find(base::StringToLowerASCII(url.host()));
if (blacklisted_domains_.end() == it || it->second.count == 0)
- return true;
+ return SDCH_OK;
UMA_HISTOGRAM_ENUMERATION("Sdch3.BlacklistReason", it->second.reason,
- MAX_PROBLEM_CODE);
- SdchErrorRecovery(DOMAIN_BLACKLIST_INCLUDES_TARGET);
+ SDCH_MAX_PROBLEM_CODE);
int count = it->second.count - 1;
if (count > 0) {
it->second.count = count;
} else {
it->second.count = 0;
- it->second.reason = MIN_PROBLEM_CODE;
+ it->second.reason = SDCH_OK;
}
- return false;
+ return SDCH_DOMAIN_BLACKLIST_INCLUDES_TARGET;
}
-void SdchManager::OnGetDictionary(const GURL& request_url,
- const GURL& dictionary_url) {
- if (!CanFetchDictionary(request_url, dictionary_url))
- return;
+SdchProblemCode SdchManager::OnGetDictionary(const GURL& request_url,
+ const GURL& dictionary_url) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ SdchProblemCode rv = CanFetchDictionary(request_url, dictionary_url);
+ if (rv != SDCH_OK)
+ return rv;
FOR_EACH_OBSERVER(SdchObserver,
observers_,
OnGetDictionary(this, request_url, dictionary_url));
+
+ return SDCH_OK;
}
-bool SdchManager::CanFetchDictionary(const GURL& referring_url,
- const GURL& dictionary_url) const {
+SdchProblemCode SdchManager::CanFetchDictionary(
+ const GURL& referring_url,
+ const GURL& dictionary_url) const {
DCHECK(thread_checker_.CalledOnValidThread());
/* The user agent may retrieve a dictionary from the dictionary URL if all of
the following are true:
@@ -397,41 +389,40 @@
// Item (1) above implies item (2). Spec should be updated.
// I take "host name match" to be "is identical to"
if (referring_url.host() != dictionary_url.host() ||
- referring_url.scheme() != dictionary_url.scheme()) {
- SdchErrorRecovery(DICTIONARY_LOAD_ATTEMPT_FROM_DIFFERENT_HOST);
- return false;
- }
- if (!secure_scheme_supported() && referring_url.SchemeIsSecure()) {
- SdchErrorRecovery(DICTIONARY_SELECTED_FOR_SSL);
- return false;
- }
+ referring_url.scheme() != dictionary_url.scheme())
+ return SDCH_DICTIONARY_LOAD_ATTEMPT_FROM_DIFFERENT_HOST;
+
+ if (!secure_scheme_supported() && referring_url.SchemeIsSecure())
+ return SDCH_DICTIONARY_SELECTED_FOR_SSL;
// TODO(jar): Remove this failsafe conservative hack which is more restrictive
// than current SDCH spec when needed, and justified by security audit.
- if (!referring_url.SchemeIsHTTPOrHTTPS()) {
- SdchErrorRecovery(DICTIONARY_SELECTED_FROM_NON_HTTP);
- return false;
- }
+ if (!referring_url.SchemeIsHTTPOrHTTPS())
+ return SDCH_DICTIONARY_SELECTED_FROM_NON_HTTP;
- return true;
+ return SDCH_OK;
}
-void SdchManager::GetVcdiffDictionary(
+SdchProblemCode SdchManager::GetVcdiffDictionary(
const std::string& server_hash,
const GURL& referring_url,
scoped_refptr<Dictionary>* dictionary) {
DCHECK(thread_checker_.CalledOnValidThread());
*dictionary = NULL;
DictionaryMap::iterator it = dictionaries_.find(server_hash);
- if (it == dictionaries_.end()) {
- return;
- }
+ if (it == dictionaries_.end())
+ return SDCH_DICTIONARY_HASH_NOT_FOUND;
+
scoped_refptr<Dictionary> matching_dictionary = it->second;
- if (!IsInSupportedDomain(referring_url))
- return;
- if (!matching_dictionary->CanUse(referring_url))
- return;
- *dictionary = matching_dictionary;
+
+ SdchProblemCode rv = IsInSupportedDomain(referring_url);
+ if (rv != SDCH_OK)
+ return rv;
+
+ rv = matching_dictionary->CanUse(referring_url);
+ if (rv == SDCH_OK)
+ *dictionary = matching_dictionary;
+ return rv;
}
// TODO(jar): If we have evictions from the dictionaries_, then we need to
@@ -443,9 +434,11 @@
int count = 0;
for (DictionaryMap::iterator it = dictionaries_.begin();
it != dictionaries_.end(); ++it) {
- if (!IsInSupportedDomain(target_url))
+ SdchProblemCode rv = IsInSupportedDomain(target_url);
+ if (rv != SDCH_OK)
continue;
- if (!it->second->CanAdvertise(target_url))
+
+ if (it->second->CanAdvertise(target_url) != SDCH_OK)
continue;
++count;
if (!list->empty())
@@ -490,7 +483,7 @@
ExperimentSet::iterator it = allow_latency_experiment_.find(url.host());
if (allow_latency_experiment_.end() == it)
return; // It was already erased, or never allowed.
- SdchErrorRecovery(LATENCY_TEST_DISALLOWED);
+ SdchErrorRecovery(SDCH_LATENCY_TEST_DISALLOWED);
allow_latency_experiment_.erase(it);
}
@@ -502,31 +495,27 @@
observers_.RemoveObserver(observer);
}
-void SdchManager::AddSdchDictionary(const std::string& dictionary_text,
+SdchProblemCode SdchManager::AddSdchDictionary(
+ const std::string& dictionary_text,
const GURL& dictionary_url) {
DCHECK(thread_checker_.CalledOnValidThread());
std::string client_hash;
std::string server_hash;
GenerateHash(dictionary_text, &client_hash, &server_hash);
- if (dictionaries_.find(server_hash) != dictionaries_.end()) {
- SdchErrorRecovery(DICTIONARY_ALREADY_LOADED);
- return; // Already loaded.
- }
+ if (dictionaries_.find(server_hash) != dictionaries_.end())
+ return SDCH_DICTIONARY_ALREADY_LOADED; // Already loaded.
std::string domain, path;
std::set<int> ports;
base::Time expiration(base::Time::Now() + base::TimeDelta::FromDays(30));
- if (dictionary_text.empty()) {
- SdchErrorRecovery(DICTIONARY_HAS_NO_TEXT);
- return; // Missing header.
- }
+ if (dictionary_text.empty())
+ return SDCH_DICTIONARY_HAS_NO_TEXT; // Missing header.
size_t header_end = dictionary_text.find("\n\n");
- if (std::string::npos == header_end) {
- SdchErrorRecovery(DICTIONARY_HAS_NO_HEADER);
- return; // Missing header.
- }
+ if (std::string::npos == header_end)
+ return SDCH_DICTIONARY_HAS_NO_HEADER; // Missing header.
+
size_t line_start = 0; // Start of line being parsed.
while (1) {
size_t line_end = dictionary_text.find('\n', line_start);
@@ -534,10 +523,9 @@
DCHECK_LE(line_end, header_end);
size_t colon_index = dictionary_text.find(':', line_start);
- if (std::string::npos == colon_index) {
- SdchErrorRecovery(DICTIONARY_HEADER_LINE_MISSING_COLON);
- return; // Illegal line missing a colon.
- }
+ if (std::string::npos == colon_index)
+ return SDCH_DICTIONARY_HEADER_LINE_MISSING_COLON; // Illegal line missing
+ // a colon.
if (colon_index > line_end)
break;
@@ -556,7 +544,7 @@
path = value;
} else if (name == "format-version") {
if (value != "1.0")
- return;
+ return SDCH_DICTIONARY_UNSUPPORTED_VERSION;
} else if (name == "max-age") {
int64 seconds;
base::StringToInt64(value, &seconds);
@@ -578,24 +566,23 @@
GURL dictionary_url_normalized(dictionary_url);
StripTrailingDot(&dictionary_url_normalized);
- if (!IsInSupportedDomain(dictionary_url_normalized))
- return;
+ SdchProblemCode rv = IsInSupportedDomain(dictionary_url_normalized);
+ if (rv != SDCH_OK)
+ return rv;
- if (!Dictionary::CanSet(domain, path, ports, dictionary_url_normalized))
- return;
+ rv = Dictionary::CanSet(domain, path, ports, dictionary_url_normalized);
+ if (rv != SDCH_OK)
+ return rv;
// TODO(jar): Remove these hacks to preclude a DOS attack involving piles of
// useless dictionaries. We should probably have a cache eviction plan,
// instead of just blocking additions. For now, with the spec in flux, it
// is probably not worth doing eviction handling.
- if (kMaxDictionarySize < dictionary_text.size()) {
- SdchErrorRecovery(DICTIONARY_IS_TOO_LARGE);
- return;
- }
- if (kMaxDictionaryCount <= dictionaries_.size()) {
- SdchErrorRecovery(DICTIONARY_COUNT_EXCEEDED);
- return;
- }
+ if (kMaxDictionarySize < dictionary_text.size())
+ return SDCH_DICTIONARY_IS_TOO_LARGE;
+
+ if (kMaxDictionaryCount <= dictionaries_.size())
+ return SDCH_DICTIONARY_COUNT_EXCEEDED;
UMA_HISTOGRAM_COUNTS("Sdch3.Dictionary size loaded", dictionary_text.size());
DVLOG(1) << "Loaded dictionary with client hash " << client_hash
@@ -605,7 +592,7 @@
dictionary_url_normalized, domain,
path, expiration, ports);
dictionaries_[server_hash] = dictionary;
- return;
+ return SDCH_OK;
}
// static
@@ -618,4 +605,46 @@
std::replace(output->begin(), output->end(), '/', '_');
}
+base::Value* SdchManager::SdchInfoToValue() const {
+ base::DictionaryValue* value = new base::DictionaryValue();
+
+ value->SetBoolean("sdch_enabled", sdch_enabled());
+ value->SetBoolean("secure_scheme_support", secure_scheme_supported());
+
+ base::ListValue* entry_list = new base::ListValue();
+ for (DictionaryMap::const_iterator it = dictionaries_.begin();
+ it != dictionaries_.end(); ++it) {
+ base::DictionaryValue* entry_dict = new base::DictionaryValue();
+ entry_dict->SetString("url", it->second->url().spec());
+ entry_dict->SetString("client_hash", it->second->client_hash());
+ entry_dict->SetString("domain", it->second->domain());
+ entry_dict->SetString("path", it->second->path());
+ base::ListValue* port_list = new base::ListValue();
+ for (std::set<int>::const_iterator port_it = it->second->ports().begin();
+ port_it != it->second->ports().end(); ++port_it) {
+ port_list->AppendInteger(*port_it);
+ }
+ entry_dict->Set("ports", port_list);
+ entry_dict->SetString("server_hash", it->first);
+ entry_list->Append(entry_dict);
+ }
+ value->Set("dictionaries", entry_list);
+
+ entry_list = new base::ListValue();
+ for (DomainBlacklistInfo::const_iterator it = blacklisted_domains_.begin();
+ it != blacklisted_domains_.end(); ++it) {
+ if (it->second.count == 0)
+ continue;
+ base::DictionaryValue* entry_dict = new base::DictionaryValue();
+ entry_dict->SetString("domain", it->first);
+ if (it->second.count != INT_MAX)
+ entry_dict->SetInteger("tries", it->second.count);
+ entry_dict->SetInteger("reason", it->second.reason);
+ entry_list->Append(entry_dict);
+ }
+ value->Set("blacklisted", entry_list);
+
+ return value;
+}
+
} // namespace net
diff --git a/net/base/sdch_manager.h b/net/base/sdch_manager.h
index ff157e5..016978a 100644
--- a/net/base/sdch_manager.h
+++ b/net/base/sdch_manager.h
@@ -16,8 +16,13 @@
#include "base/threading/thread_checker.h"
#include "base/time/time.h"
#include "net/base/net_export.h"
+#include "net/base/sdch_problem_codes.h"
#include "url/gurl.h"
+namespace base {
+class Value;
+}
+
namespace net {
class SdchObserver;
@@ -35,106 +40,6 @@
// module) to decompress data.
class NET_EXPORT SdchManager {
public:
- // A list of errors that appeared and were either resolved, or used to turn
- // off sdch encoding.
- enum ProblemCodes {
- MIN_PROBLEM_CODE,
-
- // Content-encoding correction problems.
- ADDED_CONTENT_ENCODING = 1,
- FIXED_CONTENT_ENCODING = 2,
- FIXED_CONTENT_ENCODINGS = 3,
-
- // Content decoding errors.
- DECODE_HEADER_ERROR = 4,
- DECODE_BODY_ERROR = 5,
-
- // More content-encoding correction problems.
- OPTIONAL_GUNZIP_ENCODING_ADDED = 6,
-
- // Content encoding correction when we're not even tagged as HTML!?!
- BINARY_ADDED_CONTENT_ENCODING = 7,
- BINARY_FIXED_CONTENT_ENCODING = 8,
- BINARY_FIXED_CONTENT_ENCODINGS = 9,
-
- // Dictionary selection for use problems.
- DICTIONARY_FOUND_HAS_WRONG_DOMAIN = 10,
- DICTIONARY_FOUND_HAS_WRONG_PORT_LIST = 11,
- DICTIONARY_FOUND_HAS_WRONG_PATH = 12,
- DICTIONARY_FOUND_HAS_WRONG_SCHEME = 13,
- DICTIONARY_HASH_NOT_FOUND = 14,
- DICTIONARY_HASH_MALFORMED = 15,
-
- // Dictionary saving problems.
- DICTIONARY_HAS_NO_HEADER = 20,
- DICTIONARY_HEADER_LINE_MISSING_COLON = 21,
- DICTIONARY_MISSING_DOMAIN_SPECIFIER = 22,
- DICTIONARY_SPECIFIES_TOP_LEVEL_DOMAIN = 23,
- DICTIONARY_DOMAIN_NOT_MATCHING_SOURCE_URL = 24,
- DICTIONARY_PORT_NOT_MATCHING_SOURCE_URL = 25,
- DICTIONARY_HAS_NO_TEXT = 26,
- DICTIONARY_REFERER_URL_HAS_DOT_IN_PREFIX = 27,
-
- // Dictionary loading problems.
- DICTIONARY_LOAD_ATTEMPT_FROM_DIFFERENT_HOST = 30,
- DICTIONARY_SELECTED_FOR_SSL = 31,
- DICTIONARY_ALREADY_LOADED = 32,
- DICTIONARY_SELECTED_FROM_NON_HTTP = 33,
- DICTIONARY_IS_TOO_LARGE= 34,
- DICTIONARY_COUNT_EXCEEDED = 35,
- DICTIONARY_ALREADY_SCHEDULED_TO_DOWNLOAD = 36,
- DICTIONARY_ALREADY_TRIED_TO_DOWNLOAD = 37,
- DICTIONARY_FETCH_READ_FAILED = 38,
-
- // Failsafe hack.
- ATTEMPT_TO_DECODE_NON_HTTP_DATA = 40,
-
-
- // Content-Encoding problems detected, with no action taken.
- MULTIENCODING_FOR_NON_SDCH_REQUEST = 50,
- SDCH_CONTENT_ENCODE_FOR_NON_SDCH_REQUEST = 51,
-
- // Dictionary manager issues.
- DOMAIN_BLACKLIST_INCLUDES_TARGET = 61,
-
- // Problematic decode recovery methods.
- META_REFRESH_RECOVERY = 70, // Dictionary not found.
- // defunct = 71, // Almost the same as META_REFRESH_UNSUPPORTED.
- // defunct = 72, // Almost the same as CACHED_META_REFRESH_UNSUPPORTED.
- // defunct = 73, // PASSING_THROUGH_NON_SDCH plus
- // RESPONSE_TENTATIVE_SDCH in ../filter/sdch_filter.cc.
- META_REFRESH_UNSUPPORTED = 74, // Unrecoverable error.
- CACHED_META_REFRESH_UNSUPPORTED = 75, // As above, but pulled from cache.
- PASSING_THROUGH_NON_SDCH = 76, // Tagged sdch but missing dictionary-hash.
- INCOMPLETE_SDCH_CONTENT = 77, // Last window was not completely decoded.
- PASS_THROUGH_404_CODE = 78, // URL not found message passing through.
-
- // This next report is very common, and not really an error scenario, but
- // it exercises the error recovery logic.
- PASS_THROUGH_OLD_CACHED = 79, // Back button got pre-SDCH cached content.
-
- // Common decoded recovery methods.
- META_REFRESH_CACHED_RECOVERY = 80, // Probably startup tab loading.
- // defunct = 81, // Now tracked by ResponseCorruptionDetectionCause histo.
-
- // Non SDCH problems, only accounted for to make stat counting complete
- // (i.e., be able to be sure all dictionary advertisements are accounted
- // for).
-
- UNFLUSHED_CONTENT = 90, // Possible error in filter chaining.
- // defunct = 91, // MISSING_TIME_STATS (Should never happen.)
- CACHE_DECODED = 92, // No timing stats recorded.
- // defunct = 93, // OVER_10_MINUTES (No timing stats recorded.)
- UNINITIALIZED = 94, // Filter never even got initialized.
- PRIOR_TO_DICTIONARY = 95, // We hadn't even parsed a dictionary selector.
- DECODE_ERROR = 96, // Something went wrong during decode.
-
- // Problem during the latency test.
- LATENCY_TEST_DISALLOWED = 100, // SDCH now failing, but it worked before!
-
- MAX_PROBLEM_CODE // Used to bound histogram.
- };
-
// Use the following static limits to block DOS attacks until we implement
// a cached dictionary evicition strategy.
static const size_t kMaxDictionarySize;
@@ -167,19 +72,25 @@
const GURL& url() const { return url_; }
const std::string& client_hash() const { return client_hash_; }
+ const std::string& domain() const { return domain_; }
+ const std::string& path() const { return path_; }
+ const base::Time& expiration() const { return expiration_; }
+ const std::set<int>& ports() const { return ports_; }
// Security method to check if we can advertise this dictionary for use
// if the |target_url| returns SDCH compressed data.
- bool CanAdvertise(const GURL& target_url);
+ SdchProblemCode CanAdvertise(const GURL& target_url) const;
// Security methods to check if we can establish a new dictionary with the
// given data, that arrived in response to get of dictionary_url.
- static bool CanSet(const std::string& domain, const std::string& path,
- const std::set<int>& ports, const GURL& dictionary_url);
+ static SdchProblemCode CanSet(const std::string& domain,
+ const std::string& path,
+ const std::set<int>& ports,
+ const GURL& dictionary_url);
// Security method to check if we can use a dictionary to decompress a
// target that arrived with a reference to this dictionary.
- bool CanUse(const GURL& referring_url);
+ SdchProblemCode CanUse(const GURL& referring_url) const;
// Compare paths to see if they "match" for dictionary use.
static bool PathMatch(const std::string& path,
@@ -188,7 +99,6 @@
// Compare domains to see if the "match" for dictionary use.
static bool DomainMatch(const GURL& url, const std::string& restriction);
-
// The actual text of the dictionary.
std::string text_;
@@ -218,7 +128,7 @@
void ClearData();
// Record stats on various errors.
- static void SdchErrorRecovery(ProblemCodes problem);
+ static void SdchErrorRecovery(SdchProblemCode problem);
// Enables or disables SDCH compression.
static void EnableSdchSupport(bool enabled);
@@ -237,11 +147,12 @@
// Used when filter errors are found from a given domain, but it is plausible
// that the cause is temporary (such as application startup, where cached
// entries are used, but a dictionary is not yet loaded).
- void BlacklistDomain(const GURL& url, ProblemCodes blacklist_reason);
+ void BlacklistDomain(const GURL& url, SdchProblemCode blacklist_reason);
// Used when SEVERE filter errors are found from a given domain, to prevent
// further use of SDCH on that domain.
- void BlacklistDomainForever(const GURL& url, ProblemCodes blacklist_reason);
+ void BlacklistDomainForever(const GURL& url,
+ SdchProblemCode blacklist_reason);
// Unit test only, this function resets enabling of sdch, and clears the
// blacklist.
@@ -260,11 +171,12 @@
// supported domain (i.e., not blacklisted, and either the specific supported
// domain, or all domains were assumed supported). If it is blacklist, reduce
// by 1 the number of times it will be reported as blacklisted.
- bool IsInSupportedDomain(const GURL& url);
+ SdchProblemCode IsInSupportedDomain(const GURL& url);
// Send out appropriate events notifying observers that a Get-Dictionary
// header has been seen.
- void OnGetDictionary(const GURL& request_url, const GURL& dictionary_url);
+ SdchProblemCode OnGetDictionary(const GURL& request_url,
+ const GURL& dictionary_url);
// Find the vcdiff dictionary (the body of the sdch dictionary that appears
// after the meta-data headers like Domain:...) with the given |server_hash|
@@ -272,9 +184,12 @@
// be sure the returned |dictionary| can be used for decoding content supplied
// in response to a request for |referring_url|.
// Return null in |dictionary| if there is no matching legal dictionary.
- void GetVcdiffDictionary(const std::string& server_hash,
- const GURL& referring_url,
- scoped_refptr<Dictionary>* dictionary);
+ // Returns SDCH_OK if dictionary is not found, SDCH(-over-https) is disabled,
+ // or if matching legal dictionary exists. Otherwise returns the
+ // corresponding problem code.
+ SdchProblemCode GetVcdiffDictionary(const std::string& server_hash,
+ const GURL& referring_url,
+ scoped_refptr<Dictionary>* dictionary);
// Get list of available (pre-cached) dictionaries that we have already loaded
// into memory. The list is a comma separated list of (client) hashes per
@@ -295,12 +210,16 @@
void SetAllowLatencyExperiment(const GURL& url, bool enable);
+ base::Value* SdchInfoToValue() const;
+
// Add an SDCH dictionary to our list of availible
// dictionaries. This addition will fail if addition is illegal
// (data in the dictionary is not acceptable from the
// dictionary_url; dictionary already added, etc.).
- void AddSdchDictionary(const std::string& dictionary_text,
- const GURL& dictionary_url);
+ // Returns SDCH_OK if the addition was successfull, and corresponding error
+ // code otherwise.
+ SdchProblemCode AddSdchDictionary(const std::string& dictionary_text,
+ const GURL& dictionary_url);
// Registration for events generated by the SDCH subsystem.
void AddObserver(SdchObserver* observer);
@@ -308,24 +227,20 @@
private:
struct BlacklistInfo {
- BlacklistInfo()
- : count(0),
- exponential_count(0),
- reason(MIN_PROBLEM_CODE) {}
+ BlacklistInfo() : count(0), exponential_count(0), reason(SDCH_OK) {}
- int count; // # of times to refuse SDCH advertisement.
- int exponential_count; // Current exponential backoff ratchet.
- ProblemCodes reason; // Why domain was blacklisted.
-
+ int count; // # of times to refuse SDCH advertisement.
+ int exponential_count; // Current exponential backoff ratchet.
+ SdchProblemCode reason; // Why domain was blacklisted.
};
typedef std::map<std::string, BlacklistInfo> DomainBlacklistInfo;
typedef std::set<std::string> ExperimentSet;
// Determines whether a "Get-Dictionary" header is legal (dictionary
// url has appropriate relationship to referrer url) in the SDCH
- // protocol. Return true if fetch is legal.
- bool CanFetchDictionary(const GURL& referring_url,
- const GURL& dictionary_url) const;
+ // protocol. Return SDCH_OK if fetch is legal.
+ SdchProblemCode CanFetchDictionary(const GURL& referring_url,
+ const GURL& dictionary_url) const;
// A map of dictionaries info indexed by the hash that the server provides.
typedef std::map<std::string, scoped_refptr<Dictionary> > DictionaryMap;
@@ -340,6 +255,7 @@
// A simple implementation of a RFC 3548 "URL safe" base64 encoder.
static void UrlSafeBase64Encode(const std::string& input,
std::string* output);
+
DictionaryMap dictionaries_;
// List domains where decode failures have required disabling sdch.
diff --git a/net/base/sdch_manager_unittest.cc b/net/base/sdch_manager_unittest.cc
index d986879..c20be58 100644
--- a/net/base/sdch_manager_unittest.cc
+++ b/net/base/sdch_manager_unittest.cc
@@ -8,6 +8,7 @@
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
+#include "net/base/net_log.h"
#include "net/base/sdch_manager.h"
#include "net/base/sdch_observer.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -73,14 +74,7 @@
// failure.
bool AddSdchDictionary(const std::string& dictionary_text,
const GURL& gurl) {
- std::string list;
- sdch_manager_->GetAvailDictionaryList(gurl, &list);
- sdch_manager_->AddSdchDictionary(dictionary_text, gurl);
- std::string list2;
- sdch_manager_->GetAvailDictionaryList(gurl, &list2);
-
- // The list of hashes should change iff the addition succeeds.
- return (list != list2);
+ return sdch_manager_->AddSdchDictionary(dictionary_text, gurl) == SDCH_OK;
}
private:
@@ -105,31 +99,34 @@
GURL google_url("http://www.google.com");
SdchManager::EnableSdchSupport(false);
- EXPECT_FALSE(sdch_manager()->IsInSupportedDomain(google_url));
+ EXPECT_EQ(SDCH_DISABLED, sdch_manager()->IsInSupportedDomain(google_url));
SdchManager::EnableSdchSupport(true);
- EXPECT_TRUE(sdch_manager()->IsInSupportedDomain(google_url));
+ EXPECT_EQ(SDCH_OK, sdch_manager()->IsInSupportedDomain(google_url));
}
TEST_F(SdchManagerTest, DomainBlacklisting) {
GURL test_url("http://www.test.com");
GURL google_url("http://www.google.com");
- sdch_manager()->BlacklistDomain(test_url, SdchManager::MIN_PROBLEM_CODE);
- EXPECT_FALSE(sdch_manager()->IsInSupportedDomain(test_url));
- EXPECT_TRUE(sdch_manager()->IsInSupportedDomain(google_url));
+ sdch_manager()->BlacklistDomain(test_url, SDCH_OK);
+ EXPECT_EQ(SDCH_DOMAIN_BLACKLIST_INCLUDES_TARGET,
+ sdch_manager()->IsInSupportedDomain(test_url));
+ EXPECT_EQ(SDCH_OK, sdch_manager()->IsInSupportedDomain(google_url));
- sdch_manager()->BlacklistDomain(google_url, SdchManager::MIN_PROBLEM_CODE);
- EXPECT_FALSE(sdch_manager()->IsInSupportedDomain(google_url));
+ sdch_manager()->BlacklistDomain(google_url, SDCH_OK);
+ EXPECT_EQ(SDCH_DOMAIN_BLACKLIST_INCLUDES_TARGET,
+ sdch_manager()->IsInSupportedDomain(google_url));
}
TEST_F(SdchManagerTest, DomainBlacklistingCaseSensitivity) {
GURL test_url("http://www.TesT.com");
GURL test2_url("http://www.tEst.com");
- EXPECT_TRUE(sdch_manager()->IsInSupportedDomain(test_url));
- EXPECT_TRUE(sdch_manager()->IsInSupportedDomain(test2_url));
- sdch_manager()->BlacklistDomain(test_url, SdchManager::MIN_PROBLEM_CODE);
- EXPECT_FALSE(sdch_manager()->IsInSupportedDomain(test2_url));
+ EXPECT_EQ(SDCH_OK, sdch_manager()->IsInSupportedDomain(test_url));
+ EXPECT_EQ(SDCH_OK, sdch_manager()->IsInSupportedDomain(test2_url));
+ sdch_manager()->BlacklistDomain(test_url, SDCH_OK);
+ EXPECT_EQ(SDCH_DOMAIN_BLACKLIST_INCLUDES_TARGET,
+ sdch_manager()->IsInSupportedDomain(test2_url));
}
TEST_F(SdchManagerTest, BlacklistingReset) {
@@ -139,7 +136,7 @@
sdch_manager()->ClearBlacklistings();
EXPECT_EQ(sdch_manager()->BlackListDomainCount(domain), 0);
EXPECT_EQ(sdch_manager()->BlacklistDomainExponential(domain), 0);
- EXPECT_TRUE(sdch_manager()->IsInSupportedDomain(gurl));
+ EXPECT_EQ(SDCH_OK, sdch_manager()->IsInSupportedDomain(gurl));
}
TEST_F(SdchManagerTest, BlacklistingSingleBlacklist) {
@@ -147,14 +144,15 @@
std::string domain(gurl.host());
sdch_manager()->ClearBlacklistings();
- sdch_manager()->BlacklistDomain(gurl, SdchManager::MIN_PROBLEM_CODE);
+ sdch_manager()->BlacklistDomain(gurl, SDCH_OK);
EXPECT_EQ(sdch_manager()->BlackListDomainCount(domain), 1);
EXPECT_EQ(sdch_manager()->BlacklistDomainExponential(domain), 1);
// Check that any domain lookup reduces the blacklist counter.
- EXPECT_FALSE(sdch_manager()->IsInSupportedDomain(gurl));
+ EXPECT_EQ(SDCH_DOMAIN_BLACKLIST_INCLUDES_TARGET,
+ sdch_manager()->IsInSupportedDomain(gurl));
EXPECT_EQ(sdch_manager()->BlackListDomainCount(domain), 0);
- EXPECT_TRUE(sdch_manager()->IsInSupportedDomain(gurl));
+ EXPECT_EQ(SDCH_OK, sdch_manager()->IsInSupportedDomain(gurl));
}
TEST_F(SdchManagerTest, BlacklistingExponential) {
@@ -164,18 +162,19 @@
int exponential = 1;
for (int i = 1; i < 100; ++i) {
- sdch_manager()->BlacklistDomain(gurl, SdchManager::MIN_PROBLEM_CODE);
+ sdch_manager()->BlacklistDomain(gurl, SDCH_OK);
EXPECT_EQ(sdch_manager()->BlacklistDomainExponential(domain), exponential);
EXPECT_EQ(sdch_manager()->BlackListDomainCount(domain), exponential);
- EXPECT_FALSE(sdch_manager()->IsInSupportedDomain(gurl));
+ EXPECT_EQ(SDCH_DOMAIN_BLACKLIST_INCLUDES_TARGET,
+ sdch_manager()->IsInSupportedDomain(gurl));
EXPECT_EQ(sdch_manager()->BlackListDomainCount(domain), exponential - 1);
// Simulate a large number of domain checks (which eventually remove the
// blacklisting).
sdch_manager()->ClearDomainBlacklisting(domain);
EXPECT_EQ(sdch_manager()->BlackListDomainCount(domain), 0);
- EXPECT_TRUE(sdch_manager()->IsInSupportedDomain(gurl));
+ EXPECT_EQ(SDCH_OK, sdch_manager()->IsInSupportedDomain(gurl));
// Predict what exponential backoff will be.
exponential = 1 + 2 * exponential;
@@ -246,7 +245,8 @@
std::string client_hash;
std::string server_hash;
sdch_manager()->GenerateHash(dictionary_text, &client_hash, &server_hash);
- sdch_manager()->GetVcdiffDictionary(server_hash, target_url, &dictionary);
+ EXPECT_EQ(SDCH_OK, sdch_manager()->GetVcdiffDictionary(
+ server_hash, target_url, &dictionary));
EXPECT_TRUE(dictionary.get() != NULL);
}
@@ -269,7 +269,9 @@
std::string client_hash;
std::string server_hash;
sdch_manager()->GenerateHash(dictionary_text, &client_hash, &server_hash);
- sdch_manager()->GetVcdiffDictionary(server_hash, target_url, &dictionary);
+ EXPECT_EQ(SDCH_DICTIONARY_FOUND_HAS_WRONG_SCHEME,
+ sdch_manager()->GetVcdiffDictionary(server_hash, target_url,
+ &dictionary));
EXPECT_TRUE(dictionary.get() == NULL);
}
@@ -292,7 +294,9 @@
std::string client_hash;
std::string server_hash;
sdch_manager()->GenerateHash(dictionary_text, &client_hash, &server_hash);
- sdch_manager()->GetVcdiffDictionary(server_hash, target_url, &dictionary);
+ EXPECT_EQ(SDCH_DICTIONARY_FOUND_HAS_WRONG_SCHEME,
+ sdch_manager()->GetVcdiffDictionary(server_hash, target_url,
+ &dictionary));
EXPECT_TRUE(dictionary.get() == NULL);
}
@@ -516,10 +520,10 @@
EXPECT_TRUE(AddSdchDictionary(dictionary_text_1,
GURL("http://" + dictionary_domain_1)));
scoped_refptr<SdchManager::Dictionary> dictionary;
- sdch_manager()->GetVcdiffDictionary(
- server_hash_1,
- GURL("http://" + dictionary_domain_1 + "/random_url"),
- &dictionary);
+ EXPECT_EQ(SDCH_OK, sdch_manager()->GetVcdiffDictionary(
+ server_hash_1,
+ GURL("http://" + dictionary_domain_1 + "/random_url"),
+ &dictionary));
EXPECT_TRUE(dictionary.get());
second_manager.AddSdchDictionary(
@@ -530,16 +534,18 @@
&dictionary);
EXPECT_TRUE(dictionary.get());
- sdch_manager()->GetVcdiffDictionary(
- server_hash_2,
- GURL("http://" + dictionary_domain_2 + "/random_url"),
- &dictionary);
+ EXPECT_EQ(
+ SDCH_DICTIONARY_HASH_NOT_FOUND,
+ sdch_manager()->GetVcdiffDictionary(
+ server_hash_2, GURL("http://" + dictionary_domain_2 + "/random_url"),
+ &dictionary));
EXPECT_FALSE(dictionary.get());
- second_manager.GetVcdiffDictionary(
- server_hash_1,
- GURL("http://" + dictionary_domain_1 + "/random_url"),
- &dictionary);
+ EXPECT_EQ(
+ SDCH_DICTIONARY_HASH_NOT_FOUND,
+ second_manager.GetVcdiffDictionary(
+ server_hash_1, GURL("http://" + dictionary_domain_1 + "/random_url"),
+ &dictionary));
EXPECT_FALSE(dictionary.get());
}
@@ -549,14 +555,15 @@
bool expect_https_support = true;
- EXPECT_TRUE(sdch_manager()->IsInSupportedDomain(url));
- EXPECT_EQ(expect_https_support,
- sdch_manager()->IsInSupportedDomain(secure_url));
+ SdchProblemCode expected_code =
+ expect_https_support ? SDCH_OK : SDCH_SECURE_SCHEME_NOT_SUPPORTED;
+
+ EXPECT_EQ(SDCH_OK, sdch_manager()->IsInSupportedDomain(url));
+ EXPECT_EQ(expected_code, sdch_manager()->IsInSupportedDomain(secure_url));
SdchManager::EnableSecureSchemeSupport(!expect_https_support);
- EXPECT_TRUE(sdch_manager()->IsInSupportedDomain(url));
- EXPECT_NE(expect_https_support,
- sdch_manager()->IsInSupportedDomain(secure_url));
+ EXPECT_EQ(SDCH_OK, sdch_manager()->IsInSupportedDomain(url));
+ EXPECT_NE(expected_code, sdch_manager()->IsInSupportedDomain(secure_url));
}
TEST_F(SdchManagerTest, ClearDictionaryData) {
@@ -572,25 +579,26 @@
EXPECT_TRUE(AddSdchDictionary(dictionary_text,
GURL("http://" + dictionary_domain)));
scoped_refptr<SdchManager::Dictionary> dictionary;
- sdch_manager()->GetVcdiffDictionary(
- server_hash,
- GURL("http://" + dictionary_domain + "/random_url"),
- &dictionary);
+ EXPECT_EQ(SDCH_OK, sdch_manager()->GetVcdiffDictionary(
+ server_hash,
+ GURL("http://" + dictionary_domain + "/random_url"),
+ &dictionary));
EXPECT_TRUE(dictionary.get());
- sdch_manager()->BlacklistDomain(GURL(blacklist_url),
- SdchManager::MIN_PROBLEM_CODE);
- EXPECT_FALSE(sdch_manager()->IsInSupportedDomain(blacklist_url));
+ sdch_manager()->BlacklistDomain(GURL(blacklist_url), SDCH_OK);
+ EXPECT_EQ(SDCH_DOMAIN_BLACKLIST_INCLUDES_TARGET,
+ sdch_manager()->IsInSupportedDomain(blacklist_url));
sdch_manager()->ClearData();
dictionary = NULL;
- sdch_manager()->GetVcdiffDictionary(
- server_hash,
- GURL("http://" + dictionary_domain + "/random_url"),
- &dictionary);
+ EXPECT_EQ(
+ SDCH_DICTIONARY_HASH_NOT_FOUND,
+ sdch_manager()->GetVcdiffDictionary(
+ server_hash, GURL("http://" + dictionary_domain + "/random_url"),
+ &dictionary));
EXPECT_FALSE(dictionary.get());
- EXPECT_TRUE(sdch_manager()->IsInSupportedDomain(blacklist_url));
+ EXPECT_EQ(SDCH_OK, sdch_manager()->IsInSupportedDomain(blacklist_url));
}
TEST_F(SdchManagerTest, GetDictionaryNotification) {
diff --git a/net/base/sdch_net_log_params.cc b/net/base/sdch_net_log_params.cc
new file mode 100644
index 0000000..02e0ad7
--- /dev/null
+++ b/net/base/sdch_net_log_params.cc
@@ -0,0 +1,34 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/base/sdch_net_log_params.h"
+
+#include "base/values.h"
+#include "net/base/net_errors.h"
+#include "url/gurl.h"
+
+namespace net {
+
+base::Value* NetLogSdchResourceProblemCallback(SdchProblemCode problem,
+ NetLog::LogLevel log_level) {
+ base::DictionaryValue* dict = new base::DictionaryValue();
+ dict->SetInteger("sdch_problem_code", problem);
+ dict->SetInteger("net_error", ERR_FAILED);
+ return dict;
+}
+
+base::Value* NetLogSdchDictionaryFetchProblemCallback(
+ SdchProblemCode problem,
+ const GURL& url,
+ bool is_error,
+ NetLog::LogLevel log_level) {
+ base::DictionaryValue* dict = new base::DictionaryValue();
+ dict->SetInteger("sdch_problem_code", problem);
+ dict->SetString("dictionary_url", url.spec());
+ if (is_error)
+ dict->SetInteger("net_error", ERR_FAILED);
+ return dict;
+}
+
+} // namespace net
diff --git a/net/base/sdch_net_log_params.h b/net/base/sdch_net_log_params.h
new file mode 100644
index 0000000..7421a0a
--- /dev/null
+++ b/net/base/sdch_net_log_params.h
@@ -0,0 +1,32 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_BASE_SDCH_NET_LOG_PARAMS_H_
+#define NET_BASE_SDCH_NET_LOG_PARAMS_H_
+
+#include <string>
+
+#include "net/base/net_export.h"
+#include "net/base/net_log.h"
+#include "net/base/sdch_problem_codes.h"
+
+class GURL;
+
+namespace net {
+
+NET_EXPORT base::Value* NetLogSdchResourceProblemCallback(
+ SdchProblemCode problem,
+ NetLog::LogLevel log_level);
+
+// If |is_error| is false, "net_error" field won't be added to the JSON and the
+// event won't be painted red in the netlog.
+NET_EXPORT base::Value* NetLogSdchDictionaryFetchProblemCallback(
+ SdchProblemCode problem,
+ const GURL& url,
+ bool is_error,
+ NetLog::LogLevel log_level);
+
+} // namespace net
+
+#endif // NET_BASE_SDCH_NET_LOG_PARAMS_H_
diff --git a/net/base/sdch_problem_code_list.h b/net/base/sdch_problem_code_list.h
new file mode 100644
index 0000000..4efc17c
--- /dev/null
+++ b/net/base/sdch_problem_code_list.h
@@ -0,0 +1,127 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file intentionally does not have header guards, it's included
+// inside a macro to generate enum values.
+
+// This file contains list of sdch-related problem codes.
+// No error.
+SDCH_PROBLEM_CODE(OK, 0)
+
+// Content-encoding correction problems.
+SDCH_PROBLEM_CODE(ADDED_CONTENT_ENCODING, 1)
+SDCH_PROBLEM_CODE(FIXED_CONTENT_ENCODING, 2)
+SDCH_PROBLEM_CODE(FIXED_CONTENT_ENCODINGS, 3)
+
+// Content decoding errors.
+SDCH_PROBLEM_CODE(DECODE_HEADER_ERROR, 4)
+SDCH_PROBLEM_CODE(DECODE_BODY_ERROR, 5)
+
+// More content-encoding correction problems.
+SDCH_PROBLEM_CODE(OPTIONAL_GUNZIP_ENCODING_ADDED, 6)
+
+// Content encoding correction when we're not even tagged as HTML!?!
+SDCH_PROBLEM_CODE(BINARY_ADDED_CONTENT_ENCODING, 7)
+SDCH_PROBLEM_CODE(BINARY_FIXED_CONTENT_ENCODING, 8)
+SDCH_PROBLEM_CODE(BINARY_FIXED_CONTENT_ENCODINGS, 9)
+
+// Dictionary selection for use problems.
+SDCH_PROBLEM_CODE(DICTIONARY_FOUND_HAS_WRONG_DOMAIN, 10)
+SDCH_PROBLEM_CODE(DICTIONARY_FOUND_HAS_WRONG_PORT_LIST, 11)
+SDCH_PROBLEM_CODE(DICTIONARY_FOUND_HAS_WRONG_PATH, 12)
+SDCH_PROBLEM_CODE(DICTIONARY_FOUND_HAS_WRONG_SCHEME, 13)
+SDCH_PROBLEM_CODE(DICTIONARY_HASH_NOT_FOUND, 14)
+SDCH_PROBLEM_CODE(DICTIONARY_HASH_MALFORMED, 15)
+SDCH_PROBLEM_CODE(DICTIONARY_FOUND_EXPIRED, 16)
+
+// Dictionary saving problems.
+SDCH_PROBLEM_CODE(DICTIONARY_HAS_NO_HEADER, 20)
+SDCH_PROBLEM_CODE(DICTIONARY_HEADER_LINE_MISSING_COLON, 21)
+SDCH_PROBLEM_CODE(DICTIONARY_MISSING_DOMAIN_SPECIFIER, 22)
+SDCH_PROBLEM_CODE(DICTIONARY_SPECIFIES_TOP_LEVEL_DOMAIN, 23)
+SDCH_PROBLEM_CODE(DICTIONARY_DOMAIN_NOT_MATCHING_SOURCE_URL, 24)
+SDCH_PROBLEM_CODE(DICTIONARY_PORT_NOT_MATCHING_SOURCE_URL, 25)
+SDCH_PROBLEM_CODE(DICTIONARY_HAS_NO_TEXT, 26)
+SDCH_PROBLEM_CODE(DICTIONARY_REFERER_URL_HAS_DOT_IN_PREFIX, 27)
+SDCH_PROBLEM_CODE(DICTIONARY_UNSUPPORTED_VERSION, 28)
+
+// Dictionary loading problems.
+SDCH_PROBLEM_CODE(DICTIONARY_LOAD_ATTEMPT_FROM_DIFFERENT_HOST, 30)
+SDCH_PROBLEM_CODE(DICTIONARY_SELECTED_FOR_SSL, 31)
+SDCH_PROBLEM_CODE(DICTIONARY_ALREADY_LOADED, 32)
+SDCH_PROBLEM_CODE(DICTIONARY_SELECTED_FROM_NON_HTTP, 33)
+SDCH_PROBLEM_CODE(DICTIONARY_IS_TOO_LARGE, 34)
+SDCH_PROBLEM_CODE(DICTIONARY_COUNT_EXCEEDED, 35)
+// defunct = 36, // DICTIONARY_PREVIOUSLY_SCHEDULED_TO_DOWNLOAD used instead.
+// defunct = 37, // DICTIONARY_PREVIOUSLY_SCHEDULED_TO_DOWNLOAD used instead.
+SDCH_PROBLEM_CODE(DICTIONARY_FETCH_READ_FAILED, 38)
+SDCH_PROBLEM_CODE(DICTIONARY_PREVIOUSLY_SCHEDULED_TO_DOWNLOAD, 39)
+
+// Failsafe hack.
+SDCH_PROBLEM_CODE(ATTEMPT_TO_DECODE_NON_HTTP_DATA, 40)
+
+// Content-Encoding problems detected, with no action taken.
+SDCH_PROBLEM_CODE(MULTIENCODING_FOR_NON_SDCH_REQUEST, 50)
+SDCH_PROBLEM_CODE(SDCH_CONTENT_ENCODE_FOR_NON_SDCH_REQUEST, 51)
+
+// Dictionary manager issues.
+SDCH_PROBLEM_CODE(DOMAIN_BLACKLIST_INCLUDES_TARGET, 61)
+
+// Problematic decode recovery methods.
+// Dictionary not found.
+SDCH_PROBLEM_CODE(META_REFRESH_RECOVERY, 70)
+// defunct = 71, // Almost the same as META_REFRESH_UNSUPPORTED.
+// defunct = 72, // Almost the same as CACHED_META_REFRESH_UNSUPPORTED.
+// defunct = 73, // PASSING_THROUGH_NON_SDCH plus DISCARD_TENTATIVE_SDCH.
+// Unrecoverable error.
+SDCH_PROBLEM_CODE(META_REFRESH_UNSUPPORTED, 74)
+// As above, but pulled from cache.
+SDCH_PROBLEM_CODE(CACHED_META_REFRESH_UNSUPPORTED, 75)
+// Tagged sdch but missing dictionary-hash.
+SDCH_PROBLEM_CODE(PASSING_THROUGH_NON_SDCH, 76)
+// Last window was not completely decoded.
+SDCH_PROBLEM_CODE(INCOMPLETE_SDCH_CONTENT, 77)
+// URL not found message passing through.
+SDCH_PROBLEM_CODE(PASS_THROUGH_404_CODE, 78)
+
+// This next report is very common, and not really an error scenario, but
+// it exercises the error recovery logic.
+// Back button got pre-SDCH cached content.
+SDCH_PROBLEM_CODE(PASS_THROUGH_OLD_CACHED, 79)
+
+// Common decoded recovery methods.
+// Probably startup tab loading.
+SDCH_PROBLEM_CODE(META_REFRESH_CACHED_RECOVERY, 80)
+// defunct = 81, // Now tracked by ResponseCorruptionDetectionCause histo.
+
+// Non SDCH problems, only accounted for to make stat counting complete
+// (i.e., be able to be sure all dictionary advertisements are accounted
+// for).
+// Possible error in filter chaining.
+SDCH_PROBLEM_CODE(UNFLUSHED_CONTENT, 90)
+// defunct = 91, // MISSING_TIME_STATS (Should never happen.)
+// No timing stats recorded.
+SDCH_PROBLEM_CODE(CACHE_DECODED, 92)
+// defunct = 93, // OVER_10_MINUTES (No timing stats recorded.)
+// Filter never even got initialized.
+SDCH_PROBLEM_CODE(UNINITIALIZED, 94)
+// We hadn't even parsed a dictionary selector.
+SDCH_PROBLEM_CODE(PRIOR_TO_DICTIONARY, 95)
+// Something went wrong during decode.
+SDCH_PROBLEM_CODE(DECODE_ERROR, 96)
+
+// Problem during the latency test.
+// SDCH now failing, but it worked before!
+SDCH_PROBLEM_CODE(LATENCY_TEST_DISALLOWED, 100)
+
+// General SDCH problems.
+// SDCH is disabled.
+SDCH_PROBLEM_CODE(DISABLED, 105)
+// SDCH over https is disabled.
+SDCH_PROBLEM_CODE(SECURE_SCHEME_NOT_SUPPORTED, 106)
+
+// Used to bound histogram.
+SDCH_PROBLEM_CODE(MAX_PROBLEM_CODE, 110)
+
+// These values are not used in histograms.
diff --git a/net/base/sdch_problem_codes.h b/net/base/sdch_problem_codes.h
new file mode 100644
index 0000000..da979fc
--- /dev/null
+++ b/net/base/sdch_problem_codes.h
@@ -0,0 +1,20 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_BASE_SDCH_PROBLEM_CODES_H_
+#define NET_BASE_SDCH_PROBLEM_CODES_H_
+
+namespace net {
+
+// A list of errors that appeared and were either resolved, or used to turn
+// off sdch encoding.
+enum SdchProblemCode {
+#define SDCH_PROBLEM_CODE(label, value) SDCH_##label = value,
+#include "net/base/sdch_problem_code_list.h"
+#undef SDCH_PROBLEM_CODE
+};
+
+} // namespace net
+
+#endif // NET_BASE_SDCH_PROBLEM_CODES_H_
diff --git a/net/filter/filter.cc b/net/filter/filter.cc
index c8a4740..c9a56bd 100644
--- a/net/filter/filter.cc
+++ b/net/filter/filter.cc
@@ -28,11 +28,14 @@
#include "net/base/filename_util_unsafe.h"
#include "net/base/io_buffer.h"
#include "net/base/mime_util.h"
+#include "net/base/sdch_net_log_params.h"
#include "net/filter/gzip_filter.h"
#include "net/filter/sdch_filter.h"
#include "net/url_request/url_request_context.h"
#include "url/gurl.h"
+namespace net {
+
namespace {
// Filter types (using canonical lower case only):
@@ -53,9 +56,15 @@
// Buffer size allocated when de-compressing data.
const int kFilterBufSize = 32 * 1024;
-} // namespace
+void LogSdchProblem(const FilterContext& filter_context,
+ SdchProblemCode problem) {
+ SdchManager::SdchErrorRecovery(problem);
+ filter_context.GetNetLog().AddEvent(
+ NetLog::TYPE_SDCH_DECODING_ERROR,
+ base::Bind(&NetLogSdchResourceProblemCallback, problem));
+}
-namespace net {
+} // namespace
FilterContext::~FilterContext() {
}
@@ -233,13 +242,12 @@
// It was not an SDCH request, so we'll just record stats.
if (1 < encoding_types->size()) {
// Multiple filters were intended to only be used for SDCH (thus far!)
- SdchManager::SdchErrorRecovery(
- SdchManager::MULTIENCODING_FOR_NON_SDCH_REQUEST);
+ LogSdchProblem(filter_context, SDCH_MULTIENCODING_FOR_NON_SDCH_REQUEST);
}
if ((1 == encoding_types->size()) &&
(FILTER_TYPE_SDCH == encoding_types->front())) {
- SdchManager::SdchErrorRecovery(
- SdchManager::SDCH_CONTENT_ENCODE_FOR_NON_SDCH_REQUEST);
+ LogSdchProblem(filter_context,
+ SDCH_SDCH_CONTENT_ENCODE_FOR_NON_SDCH_REQUEST);
}
return;
}
@@ -259,8 +267,7 @@
// no-op pass through filter if it doesn't get gzip headers where expected.
if (1 == encoding_types->size()) {
encoding_types->push_back(FILTER_TYPE_GZIP_HELPING_SDCH);
- SdchManager::SdchErrorRecovery(
- SdchManager::OPTIONAL_GUNZIP_ENCODING_ADDED);
+ LogSdchProblem(filter_context, SDCH_OPTIONAL_GUNZIP_ENCODING_ADDED);
}
return;
}
@@ -294,14 +301,11 @@
// Suspicious case: Advertised dictionary, but server didn't use sdch, and
// we're HTML tagged.
if (encoding_types->empty()) {
- SdchManager::SdchErrorRecovery(
- SdchManager::ADDED_CONTENT_ENCODING);
+ LogSdchProblem(filter_context, SDCH_ADDED_CONTENT_ENCODING);
} else if (1 == encoding_types->size()) {
- SdchManager::SdchErrorRecovery(
- SdchManager::FIXED_CONTENT_ENCODING);
+ LogSdchProblem(filter_context, SDCH_FIXED_CONTENT_ENCODING);
} else {
- SdchManager::SdchErrorRecovery(
- SdchManager::FIXED_CONTENT_ENCODINGS);
+ LogSdchProblem(filter_context, SDCH_FIXED_CONTENT_ENCODINGS);
}
} else {
// Remarkable case!?! We advertised an SDCH dictionary, content-encoding
@@ -313,14 +317,11 @@
// start with "text/html" for some other reason?? We'll report this as a
// fixup to a binary file, but it probably really is text/html (some how).
if (encoding_types->empty()) {
- SdchManager::SdchErrorRecovery(
- SdchManager::BINARY_ADDED_CONTENT_ENCODING);
+ LogSdchProblem(filter_context, SDCH_BINARY_ADDED_CONTENT_ENCODING);
} else if (1 == encoding_types->size()) {
- SdchManager::SdchErrorRecovery(
- SdchManager::BINARY_FIXED_CONTENT_ENCODING);
+ LogSdchProblem(filter_context, SDCH_BINARY_FIXED_CONTENT_ENCODING);
} else {
- SdchManager::SdchErrorRecovery(
- SdchManager::BINARY_FIXED_CONTENT_ENCODINGS);
+ LogSdchProblem(filter_context, SDCH_BINARY_FIXED_CONTENT_ENCODINGS);
}
}
diff --git a/net/filter/filter.h b/net/filter/filter.h
index 37f55e2..13489ef 100644
--- a/net/filter/filter.h
+++ b/net/filter/filter.h
@@ -60,8 +60,9 @@
namespace net {
-class URLRequestContext;
+class BoundNetLog;
class IOBuffer;
+class URLRequestContext;
//------------------------------------------------------------------------------
// Define an interface class that allows access to contextual information
@@ -122,6 +123,9 @@
// The following method forces the context to emit a specific set of
// statistics as selected by the argument.
virtual void RecordPacketStats(StatisticSelector statistic) const = 0;
+
+ // The BoundNetLog of the associated request.
+ virtual const BoundNetLog& GetNetLog() const = 0;
};
//------------------------------------------------------------------------------
diff --git a/net/filter/mock_filter_context.cc b/net/filter/mock_filter_context.cc
index e1e4793..35ab9ee 100644
--- a/net/filter/mock_filter_context.cc
+++ b/net/filter/mock_filter_context.cc
@@ -66,4 +66,8 @@
return context_.get();
}
+const BoundNetLog& MockFilterContext::GetNetLog() const {
+ return net_log_;
+}
+
} // namespace net
diff --git a/net/filter/mock_filter_context.h b/net/filter/mock_filter_context.h
index 8150e8b..41c9e9e 100644
--- a/net/filter/mock_filter_context.h
+++ b/net/filter/mock_filter_context.h
@@ -8,6 +8,7 @@
#include <string>
#include "base/memory/scoped_ptr.h"
+#include "net/base/net_log.h"
#include "net/filter/filter.h"
#include "url/gurl.h"
@@ -73,6 +74,8 @@
void RecordPacketStats(StatisticSelector statistic) const override {}
+ const BoundNetLog& GetNetLog() const override;
+
private:
int buffer_size_;
std::string mime_type_;
@@ -85,6 +88,7 @@
bool ok_to_call_get_url_;
int response_code_;
scoped_ptr<URLRequestContext> context_;
+ BoundNetLog net_log_;
DISALLOW_COPY_AND_ASSIGN(MockFilterContext);
};
diff --git a/net/filter/sdch_filter.cc b/net/filter/sdch_filter.cc
index df72367..d03ff7f 100644
--- a/net/filter/sdch_filter.cc
+++ b/net/filter/sdch_filter.cc
@@ -11,7 +11,9 @@
#include "base/logging.h"
#include "base/metrics/histogram.h"
+#include "base/values.h"
#include "net/base/sdch_manager.h"
+#include "net/base/sdch_net_log_params.h"
#include "net/url_request/url_request_context.h"
#include "sdch/open-vcdiff/src/google/vcdecoder.h"
@@ -50,6 +52,51 @@
RESPONSE_MAX,
};
+const char* ResponseCorruptionDetectionCauseToString(
+ ResponseCorruptionDetectionCause cause) {
+ const char* cause_string = "<unknown>";
+ switch (cause) {
+ case RESPONSE_NONE:
+ cause_string = "NONE";
+ break;
+ case RESPONSE_404:
+ cause_string = "404";
+ break;
+ case RESPONSE_NOT_200:
+ cause_string = "NOT_200";
+ break;
+ case RESPONSE_OLD_UNENCODED:
+ cause_string = "OLD_UNENCODED";
+ break;
+ case RESPONSE_TENTATIVE_SDCH:
+ cause_string = "TENTATIVE_SDCH";
+ break;
+ case RESPONSE_NO_DICTIONARY:
+ cause_string = "NO_DICTIONARY";
+ break;
+ case RESPONSE_CORRUPT_SDCH:
+ cause_string = "CORRUPT_SDCH";
+ break;
+ case RESPONSE_ENCODING_LIE:
+ cause_string = "ENCODING_LIE";
+ break;
+ case RESPONSE_MAX:
+ cause_string = "<Error: max enum value>";
+ break;
+ }
+ return cause_string;
+}
+
+base::Value* NetLogSdchResponseCorruptionDetectionCallback(
+ ResponseCorruptionDetectionCause cause,
+ bool cached,
+ NetLog::LogLevel log_level) {
+ base::DictionaryValue* dict = new base::DictionaryValue();
+ dict->SetString("cause", ResponseCorruptionDetectionCauseToString(cause));
+ dict->SetBoolean("cached", cached);
+ return dict;
+}
+
} // namespace
SdchFilter::SdchFilter(const FilterContext& filter_context)
@@ -84,12 +131,12 @@
if (vcdiff_streaming_decoder_.get()) {
if (!vcdiff_streaming_decoder_->FinishDecoding()) {
decoding_status_ = DECODING_ERROR;
- SdchManager::SdchErrorRecovery(SdchManager::INCOMPLETE_SDCH_CONTENT);
+ LogSdchProblem(SDCH_INCOMPLETE_SDCH_CONTENT);
// Make it possible for the user to hit reload, and get non-sdch content.
// Note this will "wear off" quickly enough, and is just meant to assure
// in some rare case that the user is not stuck.
url_request_context_->sdch_manager()->BlacklistDomain(
- url_, SdchManager::INCOMPLETE_SDCH_CONTENT);
+ url_, SDCH_INCOMPLETE_SDCH_CONTENT);
UMA_HISTOGRAM_COUNTS("Sdch3.PartialBytesIn",
static_cast<int>(filter_context_.GetByteReadCount()));
UMA_HISTOGRAM_COUNTS("Sdch3.PartialVcdiffIn", source_bytes_);
@@ -99,7 +146,7 @@
if (!dest_buffer_excess_.empty()) {
// Filter chaining error, or premature teardown.
- SdchManager::SdchErrorRecovery(SdchManager::UNFLUSHED_CONTENT);
+ LogSdchProblem(SDCH_UNFLUSHED_CONTENT);
UMA_HISTOGRAM_COUNTS("Sdch3.UnflushedBytesIn",
static_cast<int>(filter_context_.GetByteReadCount()));
UMA_HISTOGRAM_COUNTS("Sdch3.UnflushedBufferSize",
@@ -111,7 +158,7 @@
if (filter_context_.IsCachedContent()) {
// Not a real error, but it is useful to have this tally.
// TODO(jar): Remove this stat after SDCH stability is validated.
- SdchManager::SdchErrorRecovery(SdchManager::CACHE_DECODED);
+ LogSdchProblem(SDCH_CACHE_DECODED);
return; // We don't need timing stats, and we aready got ratios.
}
@@ -135,15 +182,15 @@
return;
}
case DECODING_UNINITIALIZED: {
- SdchManager::SdchErrorRecovery(SdchManager::UNINITIALIZED);
+ LogSdchProblem(SDCH_UNINITIALIZED);
return;
}
case WAITING_FOR_DICTIONARY_SELECTION: {
- SdchManager::SdchErrorRecovery(SdchManager::PRIOR_TO_DICTIONARY);
+ LogSdchProblem(SDCH_PRIOR_TO_DICTIONARY);
return;
}
case DECODING_ERROR: {
- SdchManager::SdchErrorRecovery(SdchManager::DECODE_ERROR);
+ LogSdchProblem(SDCH_DECODE_ERROR);
return;
}
case META_REFRESH_RECOVERY: {
@@ -210,7 +257,7 @@
// We could be more generous, but for now, only a "NOT FOUND" code will
// cause a pass through. All other bad codes will fall into a
// meta-refresh.
- SdchManager::SdchErrorRecovery(SdchManager::PASS_THROUGH_404_CODE);
+ LogSdchProblem(SDCH_PASS_THROUGH_404_CODE);
cause = RESPONSE_404;
decoding_status_ = PASS_THROUGH;
} else if (filter_context_.GetResponseCode() != 200) {
@@ -220,7 +267,7 @@
&& !dictionary_hash_is_plausible_) {
// We must have hit the back button, and gotten content that was fetched
// before we *really* advertised SDCH and a dictionary.
- SdchManager::SdchErrorRecovery(SdchManager::PASS_THROUGH_OLD_CACHED);
+ LogSdchProblem(SDCH_PASS_THROUGH_OLD_CACHED);
decoding_status_ = PASS_THROUGH;
cause = RESPONSE_OLD_UNENCODED;
} else if (possible_pass_through_) {
@@ -256,11 +303,11 @@
// though it is not!
// Meta-refresh won't help, as we didn't advertise an SDCH dictionary!!
// Worse yet, meta-refresh could lead to an infinite refresh loop.
- SdchManager::SdchErrorRecovery(SdchManager::PASSING_THROUGH_NON_SDCH);
+ LogSdchProblem(SDCH_PASSING_THROUGH_NON_SDCH);
decoding_status_ = PASS_THROUGH;
// ... but further back-off on advertising SDCH support.
url_request_context_->sdch_manager()->BlacklistDomain(
- url_, SdchManager::PASSING_THROUGH_NON_SDCH);
+ url_, SDCH_PASSING_THROUGH_NON_SDCH);
cause = RESPONSE_ENCODING_LIE;
}
DCHECK_NE(RESPONSE_NONE, cause);
@@ -274,6 +321,10 @@
UMA_HISTOGRAM_ENUMERATION(
"Sdch3.ResponseCorruptionDetection.Uncached", cause, RESPONSE_MAX);
}
+ filter_context_.GetNetLog().AddEvent(
+ NetLog::TYPE_SDCH_RESPONSE_CORRUPTION_DETECTION,
+ base::Bind(&NetLogSdchResponseCorruptionDetectionCallback, cause,
+ filter_context_.IsCachedContent()));
if (decoding_status_ == PASS_THROUGH) {
dest_buffer_excess_ = dictionary_hash_; // Send what we scanned.
@@ -282,13 +333,12 @@
if (std::string::npos == mime_type_.find("text/html")) {
// Since we can't do a meta-refresh (along with an exponential
// backoff), we'll just make sure this NEVER happens again.
- SdchManager::ProblemCodes problem =
- (filter_context_.IsCachedContent() ?
- SdchManager::CACHED_META_REFRESH_UNSUPPORTED :
- SdchManager::META_REFRESH_UNSUPPORTED);
+ SdchProblemCode problem = (filter_context_.IsCachedContent()
+ ? SDCH_CACHED_META_REFRESH_UNSUPPORTED
+ : SDCH_META_REFRESH_UNSUPPORTED);
url_request_context_->sdch_manager()->BlacklistDomainForever(
url_, problem);
- SdchManager::SdchErrorRecovery(problem);
+ LogSdchProblem(problem);
return FILTER_ERROR;
}
// HTML content means we can issue a meta-refresh, and get the content
@@ -296,14 +346,13 @@
if (filter_context_.IsCachedContent()) {
// Cached content is probably a startup tab, so we'll just get fresh
// content and try again, without disabling sdch.
- SdchManager::SdchErrorRecovery(
- SdchManager::META_REFRESH_CACHED_RECOVERY);
+ LogSdchProblem(SDCH_META_REFRESH_CACHED_RECOVERY);
} else {
// Since it wasn't in the cache, we definately need at least some
// period of blacklisting to get the correct content.
url_request_context_->sdch_manager()->BlacklistDomain(
- url_, SdchManager::META_REFRESH_RECOVERY);
- SdchManager::SdchErrorRecovery(SdchManager::META_REFRESH_RECOVERY);
+ url_, SDCH_META_REFRESH_RECOVERY);
+ LogSdchProblem(SDCH_META_REFRESH_RECOVERY);
}
decoding_status_ = META_REFRESH_RECOVERY;
// Issue a meta redirect with SDCH disabled.
@@ -357,7 +406,7 @@
if (!ret) {
vcdiff_streaming_decoder_.reset(NULL); // Don't call it again.
decoding_status_ = DECODING_ERROR;
- SdchManager::SdchErrorRecovery(SdchManager::DECODE_BODY_ERROR);
+ LogSdchProblem(SDCH_DECODE_BODY_ERROR);
return FILTER_ERROR;
}
@@ -394,32 +443,35 @@
DCHECK(!dictionary_.get());
dictionary_hash_is_plausible_ = true; // Assume plausible, but check.
+ SdchProblemCode rv = SDCH_OK;
if ('\0' == dictionary_hash_[kServerIdLength - 1]) {
SdchManager* manager(url_request_context_->sdch_manager());
- manager->GetVcdiffDictionary(
- std::string(dictionary_hash_, 0, kServerIdLength - 1),
- url_, &dictionary_);
- } else {
- dictionary_hash_is_plausible_ = false;
- }
-
- if (!dictionary_.get()) {
- DCHECK(dictionary_hash_.size() == kServerIdLength);
- // Since dictionary was not found, check to see if hash was even plausible.
- for (size_t i = 0; i < kServerIdLength - 1; ++i) {
- char base64_char = dictionary_hash_[i];
- if (!isalnum(base64_char) && '-' != base64_char && '_' != base64_char) {
- dictionary_hash_is_plausible_ = false;
- break;
+ rv = manager->GetVcdiffDictionary(
+ std::string(dictionary_hash_, 0, kServerIdLength - 1), url_,
+ &dictionary_);
+ if (rv == SDCH_DICTIONARY_HASH_NOT_FOUND) {
+ DCHECK(dictionary_hash_.size() == kServerIdLength);
+ // Since dictionary was not found, check to see if hash was even
+ // plausible.
+ for (size_t i = 0; i < kServerIdLength - 1; ++i) {
+ char base64_char = dictionary_hash_[i];
+ if (!isalnum(base64_char) && '-' != base64_char && '_' != base64_char) {
+ rv = SDCH_DICTIONARY_HASH_MALFORMED;
+ dictionary_hash_is_plausible_ = false;
+ break;
+ }
}
}
- if (dictionary_hash_is_plausible_)
- SdchManager::SdchErrorRecovery(SdchManager::DICTIONARY_HASH_NOT_FOUND);
- else
- SdchManager::SdchErrorRecovery(SdchManager::DICTIONARY_HASH_MALFORMED);
+ } else {
+ dictionary_hash_is_plausible_ = false;
+ rv = SDCH_DICTIONARY_HASH_MALFORMED;
+ }
+ if (rv != SDCH_OK) {
+ LogSdchProblem(rv);
decoding_status_ = DECODING_ERROR;
return FILTER_ERROR;
}
+ DCHECK(dictionary_.get());
vcdiff_streaming_decoder_.reset(new open_vcdiff::VCDiffStreamingDecoder);
vcdiff_streaming_decoder_->SetAllowVcdTarget(false);
vcdiff_streaming_decoder_->StartDecoding(dictionary_->text().data(),
@@ -446,4 +498,11 @@
return amount;
}
+void SdchFilter::LogSdchProblem(SdchProblemCode problem) {
+ SdchManager::SdchErrorRecovery(problem);
+ filter_context_.GetNetLog().AddEvent(
+ NetLog::TYPE_SDCH_DECODING_ERROR,
+ base::Bind(&NetLogSdchResourceProblemCallback, problem));
+}
+
} // namespace net
diff --git a/net/filter/sdch_filter.h b/net/filter/sdch_filter.h
index e9648b1..a1a6607 100644
--- a/net/filter/sdch_filter.h
+++ b/net/filter/sdch_filter.h
@@ -64,6 +64,9 @@
// specified dest_buffer.
int OutputBufferExcess(char* const dest_buffer, size_t available_space);
+ // Add SDCH Problem to net-log and record histogram.
+ void LogSdchProblem(SdchProblemCode problem);
+
// Context data from the owner of this filter.
const FilterContext& filter_context_;
diff --git a/net/filter/sdch_filter_unittest.cc b/net/filter/sdch_filter_unittest.cc
index 2263001..79b5673 100644
--- a/net/filter/sdch_filter_unittest.cc
+++ b/net/filter/sdch_filter_unittest.cc
@@ -67,14 +67,7 @@
// the attempt succeeded.
bool AddSdchDictionary(const std::string& dictionary_text,
const GURL& gurl) {
- std::string list;
- sdch_manager_->GetAvailDictionaryList(gurl, &list);
- sdch_manager_->AddSdchDictionary(dictionary_text, gurl);
- std::string list2;
- sdch_manager_->GetAvailDictionaryList(gurl, &list2);
-
- // The list of hashes should change iff the addition succeeds.
- return (list != list2);
+ return sdch_manager_->AddSdchDictionary(dictionary_text, gurl) == SDCH_OK;
}
MockFilterContext* filter_context() { return filter_context_.get(); }
@@ -412,9 +405,10 @@
EXPECT_EQ(0, output_bytes_or_buffer_size);
EXPECT_EQ(Filter::FILTER_ERROR, status);
- EXPECT_FALSE(sdch_manager_->IsInSupportedDomain(GURL(url_string)));
+ EXPECT_EQ(SDCH_DOMAIN_BLACKLIST_INCLUDES_TARGET,
+ sdch_manager_->IsInSupportedDomain(GURL(url_string)));
sdch_manager_->ClearBlacklistings();
- EXPECT_TRUE(sdch_manager_->IsInSupportedDomain(GURL(url_string)));
+ EXPECT_EQ(SDCH_OK, sdch_manager_->IsInSupportedDomain(GURL(url_string)));
}
TEST_F(SdchFilterTest, DictionaryAddOnce) {
@@ -667,10 +661,11 @@
filter.get(), &output));
EXPECT_EQ(output.size(), 0u); // No output written.
- EXPECT_TRUE(sdch_manager_->IsInSupportedDomain(GURL(url_string)));
- EXPECT_FALSE(sdch_manager_->IsInSupportedDomain(wrong_domain_url));
+ EXPECT_EQ(SDCH_OK, sdch_manager_->IsInSupportedDomain(GURL(url_string)));
+ EXPECT_EQ(SDCH_DOMAIN_BLACKLIST_INCLUDES_TARGET,
+ sdch_manager_->IsInSupportedDomain(wrong_domain_url));
sdch_manager_->ClearBlacklistings();
- EXPECT_TRUE(sdch_manager_->IsInSupportedDomain(wrong_domain_url));
+ EXPECT_EQ(SDCH_OK, sdch_manager_->IsInSupportedDomain(wrong_domain_url));
}
TEST_F(SdchFilterTest, DictionaryPathValidation) {
@@ -723,9 +718,10 @@
output_block_size, filter.get(), &output));
EXPECT_EQ(output.size(), 0u); // No output written.
- EXPECT_FALSE(sdch_manager_->IsInSupportedDomain(GURL(url_string)));
+ EXPECT_EQ(SDCH_DOMAIN_BLACKLIST_INCLUDES_TARGET,
+ sdch_manager_->IsInSupportedDomain(GURL(url_string)));
sdch_manager_->ClearBlacklistings();
- EXPECT_TRUE(sdch_manager_->IsInSupportedDomain(GURL(url_string)));
+ EXPECT_EQ(SDCH_OK, sdch_manager_->IsInSupportedDomain(GURL(url_string)));
}
TEST_F(SdchFilterTest, DictionaryPortValidation) {
@@ -789,9 +785,10 @@
output_block_size, filter.get(), &output));
EXPECT_EQ(output.size(), 0u); // No output written.
- EXPECT_FALSE(sdch_manager_->IsInSupportedDomain(GURL(url_string)));
+ EXPECT_EQ(SDCH_DOMAIN_BLACKLIST_INCLUDES_TARGET,
+ sdch_manager_->IsInSupportedDomain(GURL(url_string)));
sdch_manager_->ClearBlacklistings();
- EXPECT_TRUE(sdch_manager_->IsInSupportedDomain(GURL(url_string)));
+ EXPECT_EQ(SDCH_OK, sdch_manager_->IsInSupportedDomain(GURL(url_string)));
}
//------------------------------------------------------------------------------
diff --git a/net/http/transport_security_state_static.certs b/net/http/transport_security_state_static.certs
index 525d05b..04f4ae4 100644
--- a/net/http/transport_security_state_static.certs
+++ b/net/http/transport_security_state_static.certs
@@ -1507,3 +1507,9 @@
FacebookBackup
sha1/1ww8E0AYsR2oX5lndk2hwp2Uosk=
+
+SpiderOak1
+sha1/UPrvFUSrp9aal5v6Rn0Jv3YJ/wU=
+
+SpiderOak2
+sha1/D0fS/hquA6QprluciyO1hlFUAxg=
diff --git a/net/http/transport_security_state_static.h b/net/http/transport_security_state_static.h
index 867cafd..1774a24 100644
--- a/net/http/transport_security_state_static.h
+++ b/net/http/transport_security_state_static.h
@@ -263,6 +263,7 @@
DOMAIN_YOUTUBE_NOCOOKIE_COM,
DOMAIN_2MDN_NET,
DOMAIN_FACEBOOK_COM,
+ DOMAIN_SPIDEROAK_COM,
// Boundary value for UMA_HISTOGRAM_ENUMERATION.
DOMAIN_NUM_EVENTS,
};
@@ -530,6 +531,14 @@
"\xd7\x0c\x3c\x13\x40\x18\xb1\x1d\xa8\x5f"
"\x99\x67\x76\x4d\xa1\xc2\x9d\x94\xa2\xc9";
+static const char kSPKIHash_SpiderOak1[] =
+ "\x50\xfa\xef\x15\x44\xab\xa7\xd6\x9a\x97"
+ "\x9b\xfa\x46\x7d\x09\xbf\x76\x09\xff\x05";
+
+static const char kSPKIHash_SpiderOak2[] =
+ "\x0f\x47\xd2\xfe\x1a\xae\x03\xa4\x29\xae"
+ "\x5b\x9c\x8b\x23\xb5\x86\x51\x54\x03\x18";
+
// The following is static data describing the hosts that are hardcoded with
// certificate pins or HSTS information.
@@ -668,6 +677,12 @@
kSPKIHash_FacebookBackup,
NULL,
};
+static const char* const kSpideroakAcceptableCerts[] = {
+ kSPKIHash_RapidSSL,
+ kSPKIHash_SpiderOak1,
+ kSPKIHash_SpiderOak2,
+ NULL,
+};
struct Pinset {
const char *const *const accepted_pins;
@@ -685,6 +700,7 @@
{kLavabitAcceptableCerts, kNoRejectedPublicKeys},
{kDropboxAcceptableCerts, kNoRejectedPublicKeys},
{kFacebookAcceptableCerts, kNoRejectedPublicKeys},
+ {kSpideroakAcceptableCerts, kNoRejectedPublicKeys},
};
// kHSTSHuffmanTree describes a Huffman tree. The nodes of the tree are pairs
@@ -1441,805 +1457,805 @@
0x04, 0x27, 0x45, 0x4d, 0xc0, 0x48, 0xa7, 0xea,
0xfa, 0xdd, 0x96, 0x29, 0xc6, 0x86, 0x70, 0x42,
0x12, 0xa7, 0x9f, 0x7c, 0x42, 0x9c, 0x5e, 0x4f,
- 0xb3, 0x6f, 0x02, 0xa7, 0x4b, 0x84, 0xf5, 0xfe,
- 0x5f, 0x3f, 0x7e, 0x9a, 0xb5, 0x97, 0x3a, 0x7f,
- 0xfb, 0xf7, 0x6b, 0x07, 0x39, 0x8b, 0x6f, 0x6c,
- 0x74, 0xfa, 0x8d, 0xdf, 0xb2, 0x93, 0xa7, 0xde,
- 0xaa, 0xd0, 0xc3, 0xe5, 0xfb, 0x3e, 0x5e, 0x10,
- 0x6a, 0x7c, 0xbf, 0x66, 0xe7, 0x9f, 0x2f, 0xd9,
- 0xed, 0x5f, 0x95, 0x3e, 0x5f, 0xb1, 0xb1, 0xe8,
- 0xfc, 0x8a, 0x7c, 0xb9, 0x5c, 0xf9, 0xf2, 0xfd,
- 0x83, 0xe5, 0xfb, 0x37, 0x5c, 0xf9, 0x7e, 0xb0,
- 0xb7, 0x93, 0xfe, 0x7f, 0x5a, 0xa4, 0xcf, 0x66,
- 0xe7, 0x80, 0x7c, 0xbf, 0x60, 0xf9, 0x7e, 0xcc,
- 0x05, 0x3e, 0x5f, 0xb3, 0xfd, 0x80, 0xe1, 0xc6,
- 0xd9, 0xb1, 0xf2, 0xfd, 0x9f, 0xb2, 0xde, 0xae,
- 0xb4, 0x1f, 0x2f, 0xd8, 0x02, 0x28, 0xfe, 0x45,
- 0x54, 0x59, 0xe1, 0xa1, 0x6e, 0x7c, 0xbf, 0x60,
- 0xf9, 0x7e, 0xe1, 0xae, 0x98, 0x21, 0x3e, 0x5f,
- 0xb0, 0xf5, 0x62, 0x3b, 0x1a, 0xe4, 0x21, 0x29,
- 0x84, 0xe8, 0x94, 0xb0, 0xc6, 0xb0, 0xba, 0xba,
- 0xf0, 0x49, 0xa7, 0xb1, 0xeb, 0xa4, 0xb9, 0x7e,
- 0xdc, 0x88, 0xf9, 0xff, 0x62, 0x6d, 0x82, 0x1e,
- 0xb3, 0x47, 0x4c, 0xfa, 0x0a, 0x8a, 0x11, 0x2d,
- 0x4a, 0x17, 0xcf, 0x60, 0x57, 0x25, 0x7a, 0x71,
- 0x8e, 0x7f, 0xfe, 0xa5, 0xe2, 0xad, 0xb9, 0xa5,
- 0xda, 0xca, 0xce, 0x68, 0xe8, 0x55, 0xdc, 0x3c,
- 0x26, 0xf1, 0x7f, 0x4e, 0x72, 0x6a, 0x59, 0x3f,
- 0xed, 0x2b, 0x4f, 0xd6, 0xd6, 0xd5, 0x0e, 0x9f,
- 0xbf, 0xda, 0x6d, 0xcf, 0x3a, 0x70, 0x42, 0x12,
- 0xa7, 0x6f, 0x50, 0x14, 0xe2, 0xf2, 0x7f, 0xdf,
- 0xe7, 0xef, 0x1c, 0x6d, 0xc2, 0x74, 0xff, 0x7f,
- 0x81, 0xa1, 0xea, 0x0a, 0x4e, 0x8d, 0x93, 0x31,
- 0x62, 0x08, 0x12, 0xbe, 0x59, 0x73, 0xf9, 0xff,
- 0x7f, 0xfe, 0xd5, 0xbb, 0xae, 0xe2, 0xdc, 0xe9,
- 0xc1, 0x08, 0x4b, 0x10, 0x82, 0x7c, 0x29, 0xdc,
- 0x85, 0x88, 0x40, 0xe3, 0x55, 0x38, 0x21, 0x09,
- 0x62, 0x0f, 0x41, 0x62, 0x0f, 0x38, 0xd5, 0x4c,
- 0xac, 0xc4, 0x49, 0xa3, 0x5c, 0xfa, 0xeb, 0x75,
- 0x61, 0xd3, 0xdf, 0xf2, 0xe9, 0x3a, 0x76, 0xf5,
- 0x01, 0xd1, 0x41, 0xe0, 0x30, 0x8e, 0x7c, 0x8b,
- 0x65, 0x61, 0x53, 0xef, 0xf7, 0xff, 0x85, 0x4d,
- 0x88, 0x54, 0xc1, 0x09, 0x51, 0x87, 0xeb, 0x52,
- 0x5b, 0x93, 0x04, 0x52, 0x7f, 0x7f, 0x7a, 0x82,
- 0xd8, 0xde, 0x53, 0x8d, 0xdc, 0x2a, 0x70, 0x1e,
- 0x66, 0xe8, 0x69, 0xcf, 0xfe, 0xb2, 0x82, 0xb9,
- 0x9b, 0x77, 0xfb, 0x49, 0xd3, 0xfa, 0xbb, 0xd9,
- 0x50, 0xf5, 0x27, 0x42, 0xab, 0xb1, 0xc4, 0xcf,
- 0x46, 0x0a, 0x31, 0xd6, 0x71, 0xa5, 0x52, 0xa7,
- 0x04, 0x21, 0x2a, 0x7c, 0xf0, 0x77, 0xf6, 0x29,
- 0xc5, 0xe4, 0xff, 0xf7, 0xe9, 0xd1, 0x48, 0x17,
- 0xe9, 0xd4, 0x7f, 0x8e, 0x9f, 0xfe, 0xc5, 0x76,
- 0xdf, 0x5d, 0x53, 0x34, 0xf8, 0x4e, 0x9e, 0x6f,
- 0xb0, 0x1b, 0x1d, 0x0f, 0x3f, 0x7e, 0x50, 0x9f,
- 0xfc, 0xfc, 0x10, 0x33, 0xd5, 0xdf, 0x55, 0xc3,
- 0xa7, 0xbd, 0xb6, 0x30, 0xe8, 0x54, 0xe3, 0x9e,
- 0x6f, 0xd0, 0xca, 0xf9, 0x0e, 0xa9, 0x53, 0xf6,
- 0xee, 0xbe, 0xfd, 0x2f, 0x3a, 0x7f, 0xdc, 0x3b,
- 0x9e, 0xb6, 0x75, 0x20, 0x3a, 0x7f, 0xd5, 0xaa,
- 0x8d, 0xd5, 0xdb, 0x78, 0xe9, 0xff, 0x7f, 0x9a,
- 0xb7, 0x08, 0xfb, 0x63, 0xa3, 0x11, 0xde, 0x86,
- 0x7e, 0x40, 0x61, 0xf4, 0xf3, 0xf7, 0xe3, 0x47,
- 0x4f, 0x87, 0x6c, 0xcf, 0x9d, 0x3f, 0xf6, 0xef,
- 0xd9, 0x65, 0x6d, 0x5b, 0x2d, 0x27, 0x47, 0x1f,
- 0x85, 0x49, 0xa7, 0xff, 0xb2, 0xf5, 0xc6, 0xac,
- 0xad, 0xb2, 0xd6, 0x53, 0xa7, 0xf5, 0xdb, 0xab,
- 0x5f, 0x6e, 0x94, 0x6a, 0x74, 0x6c, 0x8b, 0x4f,
- 0x90, 0xdd, 0x42, 0x7f, 0xfb, 0xd5, 0xcd, 0xaf,
- 0x5f, 0x69, 0xb7, 0x7f, 0xc7, 0x4f, 0xff, 0xef,
- 0xdf, 0x2d, 0xe5, 0xbf, 0x80, 0xaf, 0x70, 0x42,
- 0x12, 0xa7, 0xb6, 0xcc, 0xd2, 0x54, 0xe7, 0xff,
- 0x53, 0x44, 0x33, 0x38, 0x21, 0x09, 0x53, 0xb3,
- 0xe8, 0x53, 0x8b, 0xc9, 0xff, 0x65, 0x19, 0xb7,
- 0x3f, 0xeb, 0x41, 0xd0, 0x03, 0xe8, 0xf9, 0x4c,
- 0xfe, 0x7f, 0xf2, 0xf7, 0xd6, 0x83, 0xa1, 0x53,
- 0x89, 0xa1, 0x86, 0x92, 0x31, 0x85, 0x77, 0x11,
- 0x4f, 0x7a, 0xfe, 0x53, 0xa7, 0xf6, 0xb8, 0x20,
- 0x07, 0xbe, 0x74, 0xff, 0xf9, 0x5f, 0xed, 0xad,
- 0xbe, 0xb8, 0x29, 0xdc, 0x86, 0x88, 0x32, 0x2c,
- 0x89, 0x4b, 0x99, 0xcf, 0xaa, 0x3e, 0x0e, 0xec,
- 0xe9, 0xfd, 0xb9, 0x95, 0xdc, 0xc1, 0x53, 0xa1,
- 0xe9, 0x9c, 0xfa, 0x16, 0xb5, 0x23, 0xb9, 0x5c,
- 0xff, 0xf2, 0xfe, 0x8d, 0x0d, 0x7b, 0xf9, 0xb6,
- 0x7f, 0x49, 0xd3, 0x94, 0x5a, 0x3a, 0x15, 0x77,
- 0x33, 0x63, 0xbc, 0x8d, 0x21, 0x0c, 0x7d, 0x1e,
- 0xe7, 0x47, 0x11, 0xaa, 0x1e, 0xe2, 0xb4, 0xff,
- 0xf2, 0x2d, 0x6a, 0xac, 0xcb, 0xfa, 0xb6, 0xe3,
- 0xa7, 0xf7, 0xfe, 0xaf, 0x62, 0xf8, 0xe9, 0xfd,
- 0x7f, 0x36, 0xf5, 0xde, 0xa5, 0x49, 0x87, 0x4f,
- 0xd9, 0xfd, 0x22, 0xae, 0xf1, 0xe2, 0xef, 0x35,
- 0x8c, 0x4c, 0x2f, 0xc9, 0xb5, 0x77, 0x9e, 0x1d,
- 0x69, 0x79, 0xd3, 0xfb, 0xef, 0xfe, 0x31, 0x50,
- 0xe9, 0xcc, 0xdb, 0x0e, 0x85, 0x3f, 0x0c, 0x23,
- 0xe3, 0x19, 0xd7, 0xf5, 0x07, 0x4f, 0xfb, 0x5b,
- 0xd7, 0x78, 0x81, 0x9e, 0xa9, 0xd3, 0xff, 0x2f,
- 0xfa, 0xca, 0x07, 0x0d, 0x6a, 0x54, 0x6c, 0x88,
- 0x46, 0x21, 0x4f, 0xad, 0xef, 0x53, 0x53, 0xa0,
- 0xa9, 0xfa, 0xbb, 0xd4, 0x55, 0x85, 0x41, 0x50,
- 0x54, 0x15, 0x05, 0x43, 0xcf, 0x7f, 0xc1, 0x40,
- 0x2d, 0xd4, 0x2b, 0x70, 0x29, 0xbc, 0x2a, 0x6b,
- 0x61, 0x53, 0xf7, 0x75, 0xda, 0x56, 0x15, 0xa0,
- 0xb5, 0x93, 0x76, 0x54, 0x15, 0x05, 0x43, 0xcb,
- 0x4f, 0x05, 0x41, 0x50, 0x54, 0x15, 0x05, 0x41,
- 0x50, 0x54, 0x50, 0x6f, 0x36, 0x0a, 0xf0, 0x50,
- 0x02, 0xaa, 0x14, 0xd8, 0x2a, 0x0a, 0x82, 0xa1,
- 0xe5, 0xa5, 0x42, 0xa0, 0xa8, 0x2a, 0x0a, 0x82,
- 0xa1, 0xe6, 0xa0, 0x01, 0x57, 0x0a, 0x6f, 0x0a,
- 0x82, 0xa0, 0xa8, 0x2a, 0x0a, 0x8a, 0x0d, 0x46,
- 0x90, 0xa1, 0x0a, 0xb0, 0x54, 0xb4, 0x95, 0x05,
- 0x41, 0x50, 0x54, 0x15, 0x1b, 0x1a, 0x8a, 0x42,
- 0x80, 0x15, 0xa8, 0x54, 0x15, 0x05, 0x41, 0x53,
- 0xeb, 0x28, 0x2b, 0x85, 0x41, 0x50, 0xf3, 0xce,
- 0x40, 0xab, 0x05, 0x70, 0x50, 0x09, 0xa4, 0x85,
- 0x41, 0x50, 0x54, 0x15, 0x05, 0x43, 0xcd, 0x45,
- 0x21, 0x5e, 0x0a, 0x6c, 0x15, 0x05, 0x41, 0x50,
- 0x54, 0x15, 0x0f, 0x35, 0x1b, 0x05, 0x58, 0x2b,
- 0xe1, 0x52, 0xb1, 0x50, 0x54, 0x15, 0x27, 0x95,
- 0x05, 0x52, 0x58, 0x41, 0x50, 0x54, 0x15, 0x05,
- 0x45, 0x07, 0xcc, 0xf0, 0xad, 0x23, 0x48, 0x34,
- 0xd0, 0x50, 0x02, 0xae, 0x15, 0x2c, 0x2a, 0x0a,
- 0x82, 0xa4, 0xf2, 0xa0, 0xaa, 0x4b, 0x08, 0x2a,
- 0x0a, 0x85, 0x3d, 0x27, 0x85, 0x78, 0x68, 0x46,
- 0x98, 0x15, 0x05, 0x41, 0x50, 0x54, 0x15, 0x05,
- 0x42, 0x9b, 0x2a, 0x42, 0x84, 0x29, 0x81, 0x5f,
- 0x0a, 0x82, 0xa0, 0xa8, 0x2a, 0x04, 0xbe, 0xa8,
- 0x55, 0xc2, 0xa0, 0xa8, 0x2a, 0x0a, 0x86, 0x17,
- 0xdf, 0x0a, 0xb8, 0x54, 0x98, 0x54, 0x15, 0x05,
- 0x40, 0x0b, 0x4d, 0x42, 0xa0, 0xa8, 0x2a, 0x0a,
- 0x82, 0xa1, 0x4d, 0x43, 0x41, 0x56, 0x0a, 0xd4,
- 0x2a, 0x15, 0x7e, 0xb6, 0x87, 0x27, 0x9e, 0xec,
- 0x53, 0x8b, 0x88, 0xdb, 0x4a, 0x47, 0x99, 0xb7,
- 0x67, 0xad, 0x1d, 0x0c, 0x23, 0x18, 0x8f, 0x63,
- 0x7e, 0x66, 0x01, 0xe7, 0xdd, 0xaa, 0xcd, 0x76,
- 0x1d, 0x5e, 0x5b, 0x32, 0x85, 0x2b, 0x70, 0xb7,
- 0x79, 0x23, 0x7a, 0x4c, 0xf9, 0xff, 0x5c, 0xa9,
- 0x4e, 0x4d, 0x5e, 0x77, 0x95, 0x85, 0x4f, 0x79,
- 0x38, 0x4e, 0x9d, 0xed, 0xb0, 0xe9, 0xcb, 0xbd,
- 0xd4, 0xa2, 0x3c, 0x4e, 0x6c, 0x37, 0x71, 0xf9,
- 0xfd, 0x6f, 0x07, 0x61, 0x5a, 0x0e, 0x8a, 0x51,
- 0x08, 0xd2, 0x84, 0xc0, 0x53, 0xa7, 0xe1, 0xef,
- 0xef, 0x50, 0x1d, 0x37, 0x09, 0xd2, 0xf1, 0xc8,
- 0x5a, 0x49, 0x0e, 0x93, 0x0e, 0x9d, 0x9b, 0x8e,
- 0xf2, 0x24, 0xc4, 0x56, 0xc8, 0x3c, 0x3d, 0xbc,
- 0x3e, 0x7f, 0xfd, 0xaa, 0xe8, 0xe1, 0x1e, 0x02,
- 0xb8, 0x21, 0x09, 0xd0, 0xf6, 0x6c, 0xde, 0xd0,
- 0xa0, 0x42, 0xcf, 0x42, 0x85, 0xa2, 0x4e, 0xa5,
- 0x4f, 0xfe, 0x17, 0x17, 0x5e, 0x9f, 0xcb, 0xfb,
- 0xf7, 0xf5, 0xc3, 0xa7, 0xe7, 0xff, 0xcf, 0xb6,
- 0x1d, 0x3e, 0xa3, 0xc2, 0xaf, 0x3a, 0x04, 0xf5,
- 0x3e, 0x5b, 0x3f, 0xeb, 0x28, 0x83, 0xf8, 0x1e,
- 0x01, 0xd3, 0xb3, 0x1a, 0x3a, 0x59, 0x63, 0xd7,
- 0x01, 0xe4, 0xf3, 0x17, 0x28, 0x3a, 0x7d, 0x8d,
- 0xbe, 0xb4, 0x9d, 0x1e, 0x3c, 0xaa, 0x90, 0xcf,
- 0x2f, 0xee, 0x87, 0x49, 0x71, 0x32, 0xbf, 0xbc,
- 0x5d, 0xc7, 0x70, 0x8a, 0x7b, 0x5e, 0x17, 0x9d,
- 0x3c, 0xba, 0xb7, 0x75, 0x2a, 0x7c, 0xf7, 0x04,
- 0x21, 0x3a, 0x3e, 0x79, 0xfa, 0x93, 0xc6, 0xc8,
- 0x93, 0xc7, 0x08, 0x62, 0xaa, 0xc0, 0x47, 0x63,
- 0xac, 0x36, 0x27, 0xe1, 0xd4, 0x19, 0xf4, 0x3a,
- 0x7f, 0xa8, 0xfe, 0x3e, 0xd8, 0x0a, 0x9d, 0x3d,
- 0xb6, 0xca, 0xd8, 0xe9, 0xff, 0xf2, 0xd9, 0x58,
- 0x8b, 0x7c, 0x14, 0xee, 0x43, 0x45, 0xf1, 0x3f,
- 0x83, 0xd7, 0xaa, 0xe5, 0x07, 0x4f, 0xff, 0xd9,
- 0x7d, 0xef, 0x56, 0xde, 0xf8, 0x07, 0xca, 0xcc,
- 0x2a, 0x6b, 0xe1, 0xd3, 0xe1, 0xf5, 0x1c, 0xc3,
- 0x4c, 0x27, 0x3d, 0x7d, 0x57, 0x8d, 0x30, 0x9c,
- 0xc0, 0x53, 0x50, 0x27, 0x3f, 0xbf, 0xda, 0x6e,
- 0xa2, 0x03, 0x50, 0x27, 0x3f, 0xab, 0x96, 0xf5,
- 0x75, 0xa0, 0xd3, 0x09, 0xcd, 0x9b, 0x1a, 0x61,
- 0x39, 0x82, 0x13, 0xcc, 0x27, 0x18, 0x9a, 0x65,
- 0x26, 0x9e, 0x2e, 0x61, 0x15, 0x50, 0x1b, 0x21,
- 0x04, 0x8e, 0x57, 0x2c, 0xc2, 0x67, 0x1f, 0x3c,
- 0xbd, 0x4a, 0x7e, 0xe1, 0x8f, 0x22, 0x2a, 0xaa,
- 0x16, 0xf2, 0x95, 0x21, 0x55, 0xce, 0x6c, 0x72,
- 0x84, 0xb6, 0x5b, 0xbc, 0xab, 0x79, 0xf6, 0xd8,
- 0x3e, 0xd2, 0x74, 0xfb, 0xf9, 0xbf, 0x1a, 0x3a,
- 0x7f, 0xad, 0xcc, 0xb7, 0x96, 0x97, 0x9d, 0x3f,
- 0x6f, 0xfb, 0xf7, 0x3a, 0x83, 0xa3, 0xc7, 0xd8,
- 0x03, 0x98, 0xfa, 0x2d, 0xef, 0x09, 0x58, 0x55,
- 0xd2, 0x2c, 0x97, 0x91, 0xe5, 0x2e, 0x87, 0x04,
- 0xff, 0xe6, 0x5e, 0xbe, 0xfd, 0x2f, 0xbf, 0xab,
- 0xe3, 0xa7, 0xff, 0xf7, 0xf2, 0x9c, 0xaf, 0x7e,
- 0xde, 0x5b, 0xdb, 0x5e, 0x61, 0xd3, 0xf7, 0xf5,
- 0x67, 0xac, 0xa7, 0x4f, 0xff, 0xbb, 0xf7, 0xee,
- 0xb7, 0xd6, 0xf5, 0x0e, 0x58, 0xe9, 0xc3, 0x5a,
- 0x9e, 0x20, 0x39, 0xff, 0xed, 0xe2, 0xb6, 0x5d,
- 0x18, 0x29, 0xdc, 0x86, 0x88, 0x0d, 0xc6, 0xa2,
- 0x00, 0x8e, 0x5b, 0xbd, 0xc6, 0x26, 0x6d, 0xe8,
- 0xc4, 0xe7, 0xff, 0xf7, 0x3f, 0x2b, 0xe1, 0x1f,
- 0x33, 0x7d, 0xed, 0x81, 0xb9, 0xd3, 0xff, 0xfd,
- 0xcf, 0xcf, 0xb4, 0xfc, 0xa5, 0xfb, 0xd4, 0x0e,
- 0x08, 0x42, 0x54, 0x59, 0x19, 0x7f, 0x61, 0x9f,
- 0xcb, 0x82, 0x9d, 0xc8, 0x68, 0x82, 0x67, 0xf9,
- 0x6f, 0x82, 0x9d, 0xc8, 0x68, 0xbe, 0x67, 0xde,
- 0x6d, 0xfc, 0xae, 0xc7, 0xf4, 0x87, 0x53, 0xfe,
- 0xa3, 0xa9, 0xdc, 0xcb, 0xff, 0x9b, 0x1d, 0x38,
- 0x21, 0x09, 0x53, 0xf5, 0xed, 0x89, 0xc2, 0x53,
- 0x8b, 0xc8, 0xa1, 0x13, 0x3f, 0x60, 0x9f, 0xfa,
- 0x86, 0x2d, 0x35, 0xfe, 0x51, 0xbd, 0xe7, 0x4f,
- 0xff, 0x6f, 0xa7, 0xfa, 0x12, 0xde, 0x00, 0x14,
- 0x5e, 0x74, 0xe0, 0x84, 0x25, 0x4f, 0xed, 0xe0,
- 0x5f, 0xe5, 0x37, 0x29, 0xc5, 0xe4, 0xff, 0xfc,
- 0xdd, 0xe8, 0x4b, 0x7b, 0x6d, 0xb0, 0x3a, 0x2f,
- 0x5c, 0xa0, 0xe9, 0x75, 0x91, 0x57, 0xaa, 0x24,
- 0x3d, 0x54, 0x5f, 0xa1, 0xb4, 0x24, 0x8c, 0x49,
- 0xbc, 0x63, 0x73, 0xeb, 0x65, 0xda, 0x79, 0xd3,
- 0xfe, 0xcb, 0xa8, 0xd6, 0xcb, 0xfb, 0x9e, 0x20,
- 0x89, 0xfc, 0xb8, 0x29, 0xdc, 0x86, 0x88, 0x21,
- 0xc7, 0x93, 0x3f, 0x75, 0x84, 0x7c, 0x13, 0xa7,
- 0xed, 0xde, 0xc1, 0xef, 0xbc, 0xe8, 0xf9, 0xee,
- 0xea, 0x57, 0x16, 0x4c, 0xf0, 0x0e, 0x3f, 0x85,
- 0x44, 0xff, 0x2f, 0xef, 0xbf, 0x2d, 0xd4, 0x9d,
- 0x3f, 0xfd, 0xc1, 0xbe, 0x59, 0x7d, 0x7f, 0xe5,
- 0xbc, 0x74, 0x3d, 0x11, 0x1f, 0x3a, 0x9f, 0xd7,
- 0xde, 0xca, 0x87, 0xa9, 0x3a, 0x7b, 0xcd, 0x78,
- 0x27, 0x4f, 0xff, 0xb5, 0xa3, 0xeb, 0x96, 0x72,
- 0xdf, 0x2d, 0xa8, 0x9d, 0x3e, 0xcb, 0xd7, 0x7d,
- 0x76, 0x3f, 0x9d, 0xe4, 0x73, 0xf2, 0x5b, 0xdb,
- 0x9e, 0xd2, 0x74, 0xfc, 0xc5, 0xdd, 0xdb, 0x28,
- 0x3a, 0x7f, 0xff, 0xfb, 0xd7, 0xe6, 0x77, 0xc0,
- 0xff, 0x57, 0x56, 0x5b, 0xcb, 0x7b, 0x6b, 0xcc,
- 0x3a, 0x36, 0x47, 0x1f, 0x8c, 0xb8, 0xc6, 0x70,
- 0xef, 0xa9, 0xd3, 0xfe, 0xef, 0xa6, 0x0a, 0x77,
- 0x21, 0xa2, 0x11, 0x85, 0x3e, 0x2d, 0x47, 0x67,
- 0xff, 0x2e, 0x53, 0xbe, 0xfe, 0xfe, 0xaf, 0xca,
- 0x9d, 0x3f, 0xfd, 0xdd, 0x46, 0xfc, 0xb7, 0x31,
- 0xc1, 0x08, 0x4e, 0x96, 0x6c, 0x89, 0xe6, 0x93,
- 0x67, 0x04, 0x21, 0x2a, 0x7f, 0xb0, 0x1c, 0x38,
- 0xdb, 0x36, 0x29, 0xc5, 0xe4, 0xc1, 0x09, 0x53,
- 0x82, 0x10, 0x95, 0x3f, 0x75, 0x1b, 0x59, 0x6a,
- 0x53, 0x8b, 0xc8, 0xfa, 0x2d, 0x82, 0x8f, 0xb8,
- 0x65, 0x3e, 0x4f, 0x6d, 0xbd, 0x85, 0x38, 0xd9,
- 0xce, 0x08, 0x42, 0x54, 0xea, 0xa8, 0x94, 0xe2,
- 0xf2, 0x40, 0xf1, 0xff, 0xdd, 0x5a, 0x7e, 0xdb,
- 0xea, 0xfe, 0x43, 0xa7, 0xf6, 0xf1, 0xdb, 0xcd,
- 0x97, 0x63, 0xa7, 0xf5, 0xed, 0x8d, 0xb2, 0xf5,
- 0x3a, 0x05, 0x13, 0x16, 0x2c, 0xf9, 0xc4, 0x2a,
- 0x3b, 0xf2, 0x18, 0x13, 0xa9, 0xdd, 0x73, 0x75,
- 0x3a, 0x7f, 0xf6, 0x6e, 0xfb, 0xe0, 0xc4, 0x5b,
- 0x2b, 0x0e, 0x9f, 0x93, 0xd5, 0xb7, 0x9a, 0x2a,
- 0x7f, 0x7f, 0x29, 0x7d, 0x7d, 0xa4, 0xe9, 0xee,
- 0xe1, 0xd2, 0x74, 0x68, 0x3d, 0x7a, 0x0d, 0xa7,
- 0x97, 0x98, 0xd8, 0xa9, 0xc1, 0x08, 0x4a, 0x9f,
- 0xfe, 0xde, 0xa0, 0xcc, 0xfd, 0xed, 0xe5, 0xfd,
- 0x05, 0x38, 0xbc, 0x96, 0x22, 0x27, 0x98, 0x7d,
- 0x0a, 0x9f, 0x23, 0xca, 0xe9, 0x4a, 0xf4, 0x21,
- 0x6d, 0x0c, 0x39, 0xff, 0xf3, 0x31, 0x17, 0xfd,
- 0x7a, 0xed, 0xaf, 0x0b, 0xce, 0x9f, 0x2d, 0xea,
- 0xdb, 0x0e, 0x85, 0x3f, 0xcb, 0xaa, 0x4f, 0xff,
- 0x79, 0xb6, 0x7f, 0x6f, 0xf0, 0x73, 0xfd, 0xa4,
- 0xe9, 0xff, 0xfe, 0xda, 0xde, 0x0e, 0x37, 0xf9,
- 0x9d, 0x7a, 0xea, 0xfc, 0xa6, 0xe7, 0x46, 0x23,
- 0x03, 0x94, 0xe1, 0x5b, 0x21, 0x5a, 0x13, 0x5f,
- 0x1c, 0xbe, 0xd0, 0xf4, 0xc9, 0x65, 0x1e, 0x8e,
- 0x49, 0xa8, 0x5f, 0x09, 0x1b, 0x21, 0x5f, 0x68,
- 0xc9, 0xc1, 0x09, 0x2f, 0xc3, 0x02, 0xb2, 0xa7,
- 0x6f, 0x28, 0x2b, 0x58, 0x68, 0x86, 0x1c, 0x33,
- 0x9b, 0x2f, 0xce, 0x9f, 0xfe, 0xcf, 0xba, 0xfa,
- 0x7d, 0x4d, 0x6d, 0x80, 0xe3, 0xa5, 0x4b, 0xcf,
- 0xbf, 0x61, 0xd9, 0xfa, 0xcd, 0x7a, 0xde, 0x61,
- 0xd3, 0xfe, 0xfa, 0xde, 0xdc, 0x0e, 0xa6, 0xa7,
- 0x4e, 0x6b, 0x51, 0x3a, 0x7f, 0xdd, 0xe1, 0xca,
- 0x5c, 0x10, 0x84, 0xe8, 0xe3, 0xdb, 0xa8, 0xec,
- 0xff, 0xf7, 0xd5, 0xfa, 0x37, 0xdf, 0xdf, 0xd5,
- 0xf9, 0x53, 0xa3, 0x13, 0x3e, 0x42, 0xfb, 0x42,
- 0x64, 0x04, 0x33, 0xf9, 0x7e, 0xff, 0xe6, 0x00,
- 0xe9, 0xfc, 0xfc, 0x1a, 0xfd, 0x68, 0x3a, 0x7f,
- 0xf9, 0x5b, 0x28, 0xbb, 0x7d, 0xff, 0x94, 0x78,
- 0x4f, 0x77, 0xbc, 0xff, 0xf6, 0x5d, 0x7e, 0x99,
- 0x7b, 0x78, 0x40, 0x87, 0x4f, 0xba, 0xb9, 0xfb,
- 0x9d, 0x3a, 0xfd, 0xbb, 0x3a, 0x7f, 0x5e, 0xde,
- 0x70, 0x3b, 0xc7, 0x45, 0x09, 0x91, 0xec, 0xbf,
- 0xf4, 0xcb, 0x93, 0x6a, 0x3f, 0x3f, 0xb5, 0x02,
- 0xdb, 0xdc, 0xf3, 0xa7, 0xff, 0xef, 0xe5, 0x75,
- 0xd1, 0x96, 0xef, 0xe3, 0x4f, 0x5a, 0x4e, 0x9f,
- 0xf6, 0x57, 0x5c, 0x14, 0xee, 0x43, 0x44, 0x0d,
- 0x3e, 0xcb, 0xdb, 0x9f, 0xa1, 0x14, 0xbf, 0x5e,
- 0x9f, 0xff, 0xff, 0xb2, 0xf6, 0xef, 0xe9, 0xd1,
- 0x51, 0xee, 0xbb, 0x6c, 0xdb, 0x46, 0x33, 0xbf,
- 0x4b, 0xcf, 0x10, 0x5c, 0xff, 0xbb, 0xb4, 0xa7,
- 0x6d, 0xa3, 0x48, 0x4f, 0x10, 0x5c, 0xff, 0xd6,
- 0xf5, 0xbc, 0xbf, 0xbe, 0x8d, 0x21, 0x3c, 0x41,
- 0x73, 0xf9, 0x7d, 0xfb, 0xe8, 0xd2, 0x13, 0xc4,
- 0x17, 0x3f, 0x33, 0x36, 0xd1, 0xa4, 0x27, 0x88,
- 0x2e, 0x7f, 0xff, 0xbb, 0xff, 0xf3, 0x34, 0x55,
- 0x2d, 0xe1, 0xf6, 0x9a, 0x30, 0x27, 0x88, 0x2e,
- 0x6a, 0x74, 0x6c, 0x9d, 0x0a, 0x28, 0x0a, 0xb7,
- 0x22, 0x7c, 0xfe, 0x2c, 0xaa, 0x5b, 0xf2, 0x8f,
- 0xa7, 0xb8, 0x41, 0xc7, 0x4f, 0xfd, 0x6f, 0x5b,
- 0xcb, 0xfb, 0xe8, 0xd2, 0x13, 0xc4, 0x17, 0x3f,
- 0xcd, 0x55, 0x3d, 0x46, 0x8d, 0x21, 0x3c, 0x41,
- 0x73, 0xeb, 0xd5, 0x59, 0xa1, 0x11, 0x45, 0xbd,
- 0x5a, 0x7f, 0xf6, 0x84, 0xb7, 0x91, 0x6f, 0x5d,
- 0x1a, 0x42, 0x78, 0x82, 0xe7, 0xff, 0xfe, 0xff,
- 0xfc, 0xcd, 0x1a, 0xe6, 0x8a, 0xa5, 0xbc, 0x3e,
- 0xd3, 0x46, 0x04, 0xf1, 0x05, 0xc6, 0x26, 0x4d,
- 0x4a, 0x1f, 0x2e, 0x4f, 0xf5, 0xbc, 0x3e, 0xd3,
- 0x46, 0x04, 0xf1, 0x05, 0xcf, 0xff, 0x77, 0x52,
- 0xfa, 0xdb, 0xdb, 0x6c, 0xa2, 0xa5, 0x4f, 0xfb,
- 0x1e, 0xfd, 0x6a, 0x3f, 0xa3, 0x70, 0xf1, 0x05,
- 0xc2, 0x23, 0xa0, 0x52, 0x2a, 0xa1, 0x3f, 0xe4,
- 0xf0, 0xdf, 0x81, 0x5d, 0x01, 0x3c, 0x41, 0x73,
- 0xf5, 0xbd, 0x6b, 0x78, 0x06, 0x80, 0x2e, 0x7d,
- 0x80, 0xd1, 0xa4, 0x27, 0x88, 0x2e, 0x6c, 0xba,
- 0x1f, 0x9d, 0x8e, 0xe2, 0x94, 0x75, 0xd6, 0x17,
- 0xf3, 0xf3, 0x33, 0x6d, 0x1a, 0x42, 0x78, 0x82,
- 0xe7, 0xfc, 0x96, 0xf0, 0xfb, 0x4d, 0x18, 0x13,
- 0xc4, 0x17, 0x36, 0x68, 0xe4, 0x46, 0x54, 0xfe,
- 0x7f, 0x6b, 0xe6, 0x77, 0xe9, 0x79, 0xe2, 0x0b,
- 0x9f, 0xf6, 0x79, 0xb6, 0x7f, 0x36, 0xe7, 0x9e,
- 0x20, 0xb6, 0x1e, 0x14, 0x6c, 0xbb, 0x8e, 0x02,
- 0xcf, 0xc7, 0xcf, 0x58, 0xc6, 0x2f, 0x18, 0xce,
- 0xb0, 0xb5, 0x0b, 0x8c, 0xf8, 0x15, 0x00, 0x14,
- 0xd1, 0x05, 0xb9, 0x10, 0x13, 0xfe, 0xc7, 0xdb,
- 0x9e, 0xde, 0xdf, 0xad, 0x07, 0x4f, 0xe1, 0xfe,
- 0x6d, 0x6d, 0x42, 0x74, 0xfa, 0x9b, 0xf0, 0x80,
- 0xe9, 0xfb, 0x28, 0xeb, 0x2e, 0xec, 0xe8, 0xf2,
- 0x22, 0xf8, 0xd3, 0xe4, 0xf3, 0xb8, 0x68, 0x3a,
- 0x60, 0x29, 0xd3, 0xde, 0x56, 0x61, 0xd0, 0x74,
- 0xfd, 0xda, 0x6e, 0xa2, 0x03, 0xa3, 0x63, 0x6f,
- 0xf0, 0xa9, 0xff, 0xfc, 0xbe, 0xdb, 0xeb, 0xaa,
- 0x5f, 0x13, 0x65, 0x4d, 0xec, 0x3a, 0x60, 0x29,
- 0xd3, 0x2e, 0x93, 0xa7, 0xfb, 0x2f, 0x55, 0x66,
- 0xfc, 0x68, 0xe9, 0xfd, 0x5c, 0xb7, 0xab, 0xad,
- 0x07, 0x4c, 0x10, 0x95, 0x3f, 0xdf, 0xc6, 0xdc,
- 0xfa, 0xfb, 0x63, 0xa1, 0x13, 0xf7, 0xf0, 0xd8,
- 0x8a, 0xb1, 0x5e, 0xc4, 0x40, 0x62, 0x6e, 0xc5,
- 0x7e, 0x2f, 0x53, 0xa0, 0x9a, 0xef, 0x16, 0x9c,
- 0x10, 0x84, 0xa9, 0x30, 0xa7, 0x17, 0x93, 0xee,
- 0x6b, 0xb8, 0x4a, 0x72, 0x36, 0x77, 0xc2, 0xea,
- 0x7f, 0x53, 0x75, 0xcb, 0x65, 0x07, 0x42, 0xb6,
- 0x40, 0xf9, 0x1b, 0x46, 0x94, 0x1a, 0x4c, 0x7d,
- 0x1a, 0xa8, 0xa7, 0x5a, 0x1b, 0x1d, 0x49, 0x1e,
- 0xfa, 0x35, 0x61, 0xa3, 0xac, 0xaf, 0xf6, 0xc9,
- 0x73, 0xd8, 0x8b, 0x73, 0xa7, 0xb1, 0x99, 0x73,
- 0xa7, 0xba, 0x8d, 0xef, 0x3a, 0x14, 0xf8, 0xe9,
- 0x1f, 0x6f, 0x20, 0x9f, 0xbf, 0xae, 0xcc, 0xe7,
- 0x9d, 0x3f, 0xfd, 0x4b, 0xfe, 0xba, 0x19, 0xf5,
- 0xd3, 0x7f, 0x50, 0x74, 0xfe, 0xad, 0xdb, 0x67,
- 0xf3, 0x63, 0xa1, 0x51, 0x75, 0xe2, 0xfe, 0x56,
- 0x9d, 0xda, 0x37, 0x9d, 0x3f, 0xfd, 0xf7, 0xe8,
- 0xcd, 0xbd, 0x5a, 0x6f, 0xaf, 0x54, 0xe8, 0xd0,
- 0x7e, 0x98, 0x3f, 0x3f, 0x50, 0xd3, 0xdb, 0x83,
- 0x41, 0xd3, 0x3e, 0x83, 0xa7, 0xd6, 0xcf, 0x3e,
- 0xa7, 0x4f, 0xff, 0x59, 0x77, 0xba, 0xff, 0xe0,
- 0x56, 0xaa, 0x02, 0xa7, 0xf0, 0x30, 0x53, 0xb9,
- 0x0f, 0x10, 0x24, 0x3d, 0x16, 0x7b, 0x13, 0x8a,
- 0x8c, 0xcd, 0xef, 0x3a, 0x7a, 0xf4, 0x77, 0xce,
- 0x9e, 0xa6, 0xbd, 0x73, 0xa2, 0x83, 0xdd, 0xc1,
- 0x9b, 0x11, 0x4f, 0xef, 0xf0, 0x6b, 0x55, 0x01,
- 0xd3, 0x82, 0x10, 0x9f, 0x0f, 0xa9, 0xdd, 0xfd,
- 0x8b, 0x87, 0xd1, 0xc6, 0xa6, 0x36, 0x44, 0xa8,
- 0x16, 0xe7, 0xff, 0xd9, 0xff, 0x69, 0x75, 0x6f,
- 0x6d, 0x79, 0xef, 0x53, 0xa2, 0x83, 0xfc, 0xd2,
- 0x49, 0x1b, 0xa9, 0x57, 0x83, 0xcd, 0x32, 0x19,
- 0x5e, 0x84, 0x6f, 0x46, 0x81, 0x3e, 0xf5, 0xd6,
- 0xf5, 0x2a, 0x79, 0x16, 0xf5, 0x2a, 0x60, 0x84,
- 0xa8, 0x79, 0xee, 0xe1, 0x38, 0x48, 0x26, 0xc0,
- 0x94, 0xe3, 0x5d, 0x3f, 0xfe, 0xcb, 0xaa, 0x66,
- 0x7e, 0xf6, 0xf2, 0xfe, 0x83, 0xa0, 0x07, 0xf0,
- 0x12, 0x59, 0xff, 0xfc, 0xad, 0xbd, 0xf0, 0x68,
- 0xbd, 0x71, 0x2d, 0xdf, 0xbd, 0x4e, 0x9f, 0xcd,
- 0x52, 0xfb, 0x6a, 0xa2, 0x74, 0xe7, 0xf0, 0x9d,
- 0x3e, 0x7e, 0x5f, 0x36, 0x2a, 0x5e, 0x68, 0xf0,
- 0x6e, 0x35, 0x30, 0x14, 0xe9, 0x80, 0xa7, 0x4f,
- 0xdf, 0xd5, 0xf9, 0xf7, 0x78, 0xd5, 0x00, 0x56,
- 0x7f, 0xeb, 0xdb, 0x19, 0xbd, 0x41, 0x94, 0xdc,
- 0xe9, 0xfd, 0x4a, 0x78, 0x77, 0xae, 0xc7, 0x4f,
- 0x01, 0x9c, 0xfa, 0x9f, 0xdd, 0xd1, 0xa7, 0x6e,
- 0x65, 0x27, 0x42, 0x9e, 0xc7, 0x1c, 0xcf, 0x57,
- 0x5a, 0x6e, 0x74, 0xe0, 0x84, 0x25, 0x4f, 0xb3,
- 0x4f, 0xf5, 0xa9, 0x4e, 0x2f, 0x27, 0xd8, 0xe0,
- 0x84, 0x27, 0x42, 0x9f, 0x05, 0xce, 0x67, 0x83,
- 0xdf, 0x79, 0xd3, 0x25, 0x8e, 0x9c, 0x10, 0x84,
- 0xa9, 0xfb, 0xdd, 0xa6, 0xde, 0xb9, 0x4e, 0x2f,
- 0x27, 0xd8, 0x0c, 0xc6, 0x8e, 0x95, 0x74, 0x22,
- 0x54, 0x4c, 0x7e, 0x7d, 0x3d, 0xef, 0xea, 0xfd,
- 0x91, 0xdb, 0x90, 0xb6, 0x85, 0x5c, 0x76, 0x79,
- 0x16, 0x32, 0x69, 0x76, 0x15, 0x3b, 0x46, 0x31,
- 0xc4, 0x15, 0x85, 0x05, 0xe3, 0x0e, 0x9f, 0x95,
- 0x82, 0x3d, 0x73, 0xa7, 0xff, 0xbc, 0xca, 0x5f,
- 0x5d, 0x19, 0xff, 0xe7, 0x80, 0x74, 0x58, 0xff,
- 0x6e, 0x55, 0x27, 0x37, 0x48, 0x43, 0x36, 0x2c,
- 0xae, 0xda, 0x23, 0x23, 0x7c, 0xa4, 0xdd, 0xa5,
- 0x80, 0xe5, 0x6e, 0x95, 0xa6, 0x37, 0x14, 0x8e,
- 0xca, 0x99, 0x54, 0xfe, 0x84, 0xeb, 0x53, 0xce,
- 0x43, 0x3a, 0x6a, 0xc9, 0x41, 0x76, 0x9f, 0x0a,
- 0xea, 0x79, 0x68, 0x25, 0x9c, 0xfe, 0x75, 0x82,
- 0xb5, 0x92, 0xf5, 0xeb, 0x39, 0xfd, 0x63, 0x35,
- 0x6d, 0x0e, 0xc0, 0xc2, 0x8b, 0x72, 0x58, 0x9e,
- 0xf9, 0xdd, 0x96, 0xf8, 0xc3, 0x61, 0xd0, 0x88,
- 0xd3, 0x7e, 0x21, 0xae, 0x27, 0xf3, 0xb0, 0x53,
- 0xb9, 0x0d, 0x17, 0x1c, 0xfe, 0x76, 0x0a, 0x77,
- 0x21, 0xa2, 0xeb, 0x9f, 0xf9, 0xdc, 0xf7, 0x60,
- 0xa7, 0x72, 0x1a, 0x25, 0x18, 0x58, 0x46, 0x14,
- 0x3c, 0xa3, 0x63, 0xbd, 0x27, 0x68, 0x77, 0xe8,
- 0x78, 0x6e, 0xd0, 0x3b, 0x11, 0x24, 0xb5, 0x38,
- 0xb9, 0xdb, 0x79, 0xdc, 0xff, 0xe7, 0x33, 0x9e,
- 0xec, 0x14, 0xee, 0x43, 0x44, 0xb5, 0x3e, 0x14,
- 0xee, 0x43, 0x44, 0x6f, 0x3f, 0xee, 0x7b, 0xb0,
- 0x53, 0xb9, 0x0d, 0x12, 0xfc, 0x9d, 0x87, 0xec,
- 0xc3, 0x09, 0xfc, 0xec, 0x14, 0xee, 0x43, 0x45,
- 0x57, 0x3f, 0xda, 0x73, 0xf9, 0x4d, 0xf9, 0x87,
- 0x4d, 0xb7, 0x8e, 0x9f, 0xb0, 0x53, 0xb9, 0x0d,
- 0x12, 0x04, 0x68, 0x3c, 0xc7, 0x0b, 0xcf, 0xab,
- 0xdf, 0xea, 0x4e, 0x87, 0x9e, 0x5d, 0x24, 0x91,
- 0xa5, 0x1e, 0x9d, 0x0d, 0x19, 0xff, 0xbf, 0x94,
- 0x3b, 0x71, 0x7f, 0xfc, 0xb9, 0xd0, 0xe3, 0xf0,
- 0x12, 0x99, 0xfc, 0xec, 0x14, 0xee, 0x43, 0x45,
- 0x91, 0x3f, 0x9d, 0x82, 0x9d, 0xc8, 0x68, 0xb5,
- 0xe7, 0xf3, 0xb0, 0x53, 0xb9, 0x0d, 0x17, 0x24,
- 0xf8, 0x53, 0xb9, 0x0d, 0x17, 0x64, 0xff, 0xb9,
- 0xee, 0xc1, 0x4e, 0xe4, 0x34, 0x51, 0xd2, 0x76,
- 0x1f, 0xb3, 0x0c, 0x27, 0xc2, 0x9d, 0xc8, 0x68,
- 0xa5, 0x67, 0xff, 0xff, 0xac, 0xb4, 0x2d, 0xbc,
- 0xdb, 0xb6, 0xb7, 0x9c, 0x96, 0xf3, 0x56, 0x5a,
- 0x30, 0xe9, 0xf3, 0x99, 0xcf, 0x76, 0x22, 0xc9,
- 0xa3, 0x08, 0xa1, 0x73, 0xbd, 0xf0, 0xc8, 0xa4,
- 0x9f, 0xd1, 0xcf, 0xb0, 0x84, 0x07, 0x75, 0x3b,
- 0xbc, 0x2c, 0x5b, 0x43, 0x66, 0x7f, 0x9e, 0xec,
- 0x14, 0xee, 0x43, 0x44, 0x71, 0x3f, 0xde, 0x76,
- 0x0a, 0x77, 0x21, 0xa2, 0xb5, 0x93, 0xb9, 0x10,
- 0x57, 0x41, 0x9f, 0xfc, 0xe6, 0x73, 0xdd, 0x82,
- 0x9d, 0xc8, 0x68, 0x96, 0xe6, 0xca, 0x4e, 0x9f,
- 0xdb, 0x63, 0x18, 0xbe, 0xa9, 0xd1, 0x49, 0xe4,
- 0xf8, 0x5a, 0x75, 0xb6, 0x79, 0xd3, 0x9e, 0xc4,
- 0x3a, 0x7f, 0xfe, 0xb7, 0x52, 0x0d, 0xad, 0xcf,
- 0xca, 0xff, 0x5e, 0xde, 0x74, 0x1a, 0x21, 0xb9,
- 0xff, 0x73, 0xdd, 0x82, 0x9d, 0xc8, 0x68, 0x98,
- 0x27, 0x0e, 0xa0, 0x2a, 0x7f, 0x7f, 0x2f, 0x75,
- 0x1a, 0x9d, 0x27, 0x2a, 0x6c, 0x94, 0x11, 0xec,
- 0x3b, 0x83, 0x68, 0xbe, 0xc1, 0x7b, 0xa3, 0x6f,
- 0x1c, 0x9c, 0xcd, 0x44, 0xa9, 0xff, 0x73, 0xdd,
- 0x82, 0x9d, 0xc8, 0x68, 0x98, 0xe4, 0xef, 0x1f,
- 0x13, 0x07, 0x27, 0xe5, 0xae, 0x8b, 0xe5, 0x8e,
- 0x9f, 0xff, 0xfe, 0x7d, 0x6d, 0x9a, 0x86, 0xb6,
- 0xc4, 0xca, 0xe8, 0xca, 0x5f, 0x5f, 0x7f, 0xc7,
- 0x4f, 0x27, 0x72, 0x1a, 0x2b, 0x19, 0xff, 0x6e,
- 0x65, 0xff, 0x9a, 0xaf, 0xee, 0x74, 0x69, 0x4c,
- 0x6e, 0x92, 0xe1, 0x84, 0x0d, 0xca, 0xe7, 0xff,
- 0x2f, 0xef, 0xa7, 0x55, 0xfe, 0x22, 0x89, 0xd3,
- 0xfe, 0xcd, 0xad, 0x95, 0xa5, 0xeb, 0x63, 0xa7,
- 0xfd, 0x9b, 0x0f, 0xb5, 0xa0, 0x15, 0x79, 0xd3,
- 0xff, 0xff, 0x7f, 0x5a, 0x31, 0x34, 0x7f, 0x56,
- 0xfd, 0x19, 0x4b, 0xf3, 0x5f, 0x82, 0xa7, 0x4f,
- 0xed, 0xd5, 0x43, 0x4f, 0x6e, 0x0d, 0x07, 0x4e,
- 0xb7, 0x9d, 0x89, 0xe6, 0x22, 0x2d, 0x92, 0x7e,
- 0x7f, 0x74, 0x1d, 0xc7, 0xe9, 0xb5, 0x68, 0xe9,
- 0xf7, 0x7e, 0x8d, 0x6a, 0x74, 0x7c, 0xf0, 0x6a,
- 0x31, 0x3c, 0xa3, 0xdf, 0x3a, 0x7a, 0xb5, 0x50,
- 0x1d, 0x16, 0x3c, 0x00, 0x8f, 0xcf, 0x95, 0xe0,
- 0xd5, 0xe7, 0x4e, 0x5f, 0xbc, 0xe8, 0x68, 0xf0,
- 0xee, 0x51, 0x3f, 0x2b, 0x33, 0xfe, 0xd2, 0x74,
- 0xaa, 0x74, 0x78, 0xdf, 0x71, 0x74, 0xc0, 0x52,
- 0xa6, 0x08, 0x4a, 0x8f, 0x1a, 0xb0, 0x8a, 0xcf,
- 0xee, 0x7f, 0xf2, 0xf6, 0xf1, 0x4e, 0x34, 0x33,
- 0xdb, 0x75, 0x35, 0x3a, 0x72, 0xfd, 0xa3, 0xa6,
- 0xfa, 0x9d, 0x0d, 0x1b, 0x11, 0x1c, 0x9e, 0x10,
- 0x63, 0x79, 0xd3, 0xb7, 0x8e, 0x93, 0xa1, 0x51,
- 0x6f, 0x8a, 0x9e, 0x21, 0xb1, 0x1c, 0xd6, 0xb9,
- 0xd3, 0x82, 0x10, 0x95, 0x3f, 0xf6, 0x26, 0xcb,
- 0x46, 0xfc, 0xb7, 0x52, 0x53, 0x8b, 0xc9, 0xef,
- 0x0b, 0x7e, 0xc7, 0x48, 0x4e, 0x9f, 0x33, 0xd7,
- 0x07, 0x1d, 0x14, 0x1e, 0xde, 0xec, 0x97, 0x50,
- 0xf9, 0xfc, 0x9e, 0xaf, 0xf1, 0xb7, 0x1d, 0x36,
- 0x5c, 0xe8, 0xa4, 0xf2, 0x2c, 0x67, 0x3d, 0x7f,
- 0xe3, 0xce, 0x9f, 0xfd, 0xea, 0xdb, 0x36, 0xfe,
- 0x36, 0xfe, 0x54, 0xe8, 0x13, 0xed, 0xb9, 0x0c,
- 0x9c, 0xab, 0x9b, 0x1b, 0x31, 0x63, 0x28, 0xb0,
- 0xb1, 0xb2, 0xd0, 0xf9, 0xe3, 0xbf, 0x99, 0x56,
- 0x16, 0x17, 0x7d, 0xdf, 0x09, 0x09, 0xf0, 0xa7,
- 0x72, 0x1a, 0x2b, 0x79, 0xff, 0x73, 0xdd, 0x82,
- 0x9d, 0xc8, 0x68, 0x9c, 0x24, 0xec, 0x3f, 0x66,
- 0x18, 0x4f, 0x85, 0x3b, 0x90, 0xd1, 0x68, 0xcf,
- 0x63, 0x5e, 0xd2, 0x74, 0x9d, 0x87, 0xa9, 0x63,
- 0x09, 0xe4, 0xee, 0x43, 0x45, 0xb5, 0x3f, 0x59,
- 0x58, 0xbe, 0xd8, 0xe9, 0x9d, 0x82, 0x7b, 0x17,
- 0x2b, 0x9f, 0xce, 0xc1, 0x4e, 0xe4, 0x34, 0x5c,
- 0xb3, 0xf9, 0xd8, 0x29, 0xdc, 0x86, 0x8b, 0xb6,
- 0x15, 0x9c, 0xad, 0x41, 0x43, 0xe3, 0xff, 0xda,
- 0x1b, 0x7a, 0x65, 0x87, 0xfa, 0x76, 0x13, 0x77,
- 0x19, 0x2d, 0x9e, 0xfe, 0xff, 0x52, 0xcb, 0x9d,
- 0xcf, 0xe7, 0x60, 0xa7, 0x72, 0x1a, 0x2a, 0x79,
- 0xe4, 0xee, 0x43, 0x45, 0x73, 0x3f, 0x9d, 0x82,
- 0x9d, 0xc8, 0x68, 0xb3, 0xa0, 0x4f, 0x9a, 0xc5,
- 0x73, 0xe1, 0x4e, 0xe4, 0x34, 0x48, 0x53, 0xfd,
- 0xea, 0x6b, 0x7f, 0xab, 0x2a, 0x74, 0xcf, 0x76,
- 0x1f, 0x50, 0x0c, 0x27, 0x9b, 0xa5, 0x95, 0x87,
- 0x4f, 0xec, 0xb5, 0x6b, 0x83, 0x41, 0xd2, 0x76,
- 0x26, 0x23, 0xd0, 0x8b, 0xa9, 0x6d, 0xc9, 0xe7,
- 0xff, 0x39, 0x9c, 0xf7, 0x60, 0xa7, 0x72, 0x1a,
- 0x27, 0xc8, 0x45, 0x49, 0x7b, 0xb8, 0xec, 0xac,
- 0x8f, 0x3e, 0x14, 0xee, 0x43, 0x45, 0x65, 0x3f,
- 0xee, 0x7b, 0xb0, 0x53, 0xb9, 0x0d, 0x13, 0x74,
- 0xde, 0x76, 0x1f, 0xb3, 0x0c, 0x27, 0xc2, 0x9d,
- 0xc8, 0x68, 0x95, 0xa7, 0xfb, 0x4d, 0xbd, 0xa3,
- 0x54, 0xca, 0x9d, 0x3e, 0x73, 0x39, 0xee, 0xc3,
- 0xed, 0xe3, 0x09, 0xf0, 0xa7, 0x72, 0x1a, 0x25,
- 0xc9, 0xfe, 0xf7, 0x3e, 0xff, 0x56, 0x54, 0xe9,
- 0xe6, 0xde, 0xfa, 0x9d, 0x3e, 0x73, 0x39, 0xee,
- 0xc4, 0x45, 0xd8, 0xc3, 0x8e, 0x27, 0xfe, 0x77,
- 0x3d, 0xd8, 0x29, 0xdc, 0x86, 0x88, 0xee, 0x7f,
- 0xaf, 0x6c, 0x7b, 0xbb, 0xf5, 0x3a, 0x7e, 0x6e,
- 0x7d, 0x53, 0x3e, 0x74, 0xfd, 0xba, 0x7f, 0x2d,
- 0xd7, 0x3a, 0x7c, 0x29, 0xdc, 0x86, 0x8a, 0x86,
- 0x7d, 0x96, 0xbe, 0x50, 0x74, 0xff, 0xff, 0x6b,
- 0xdb, 0xbf, 0x51, 0x6e, 0xf5, 0xd6, 0xde, 0xbd,
- 0x73, 0x63, 0xa4, 0xed, 0xd1, 0x32, 0x46, 0xe1,
- 0x7e, 0x18, 0xdc, 0xc3, 0x70, 0x9e, 0x7c, 0x29,
- 0xdc, 0x86, 0x8a, 0xa2, 0x7f, 0xdc, 0xf7, 0x60,
- 0xa7, 0x72, 0x1a, 0x26, 0xb9, 0x3b, 0x0f, 0xd9,
- 0x86, 0x13, 0xf9, 0xd8, 0x29, 0xdc, 0x86, 0x8a,
- 0xb2, 0x7f, 0xe7, 0x73, 0xdd, 0x82, 0x9d, 0xc8,
- 0x68, 0x91, 0x27, 0xc2, 0x9d, 0xc8, 0x68, 0xb4,
- 0xa7, 0xfd, 0xcf, 0x76, 0x0a, 0x77, 0x21, 0xa2,
- 0x7d, 0x93, 0xb0, 0xfd, 0x98, 0x61, 0x3f, 0xf9,
- 0xcc, 0xe7, 0xbb, 0x05, 0x3b, 0x90, 0xd1, 0x42,
- 0x4f, 0xad, 0xea, 0x14, 0x4e, 0x9f, 0x0a, 0x77,
- 0x21, 0xa2, 0x8f, 0x9f, 0xff, 0xb3, 0x6b, 0x2e,
- 0xf7, 0x5f, 0xfc, 0x0a, 0xd5, 0x40, 0x54, 0xf9,
- 0xcc, 0xe7, 0xb9, 0x51, 0x69, 0x84, 0xfb, 0x86,
- 0x10, 0xab, 0xc5, 0x94, 0x43, 0x21, 0xe9, 0x78,
- 0x99, 0xa6, 0x35, 0xc4, 0x86, 0x95, 0x24, 0xed,
- 0x1d, 0xda, 0x18, 0x40, 0x27, 0xbc, 0x60, 0xd3,
- 0xf9, 0xd8, 0x29, 0xdc, 0x86, 0x88, 0x8a, 0x7e,
- 0xc1, 0x4e, 0xe4, 0x34, 0x45, 0x73, 0xfd, 0xbb,
- 0x76, 0x0a, 0x77, 0x21, 0xa2, 0xb8, 0x87, 0x1f,
- 0xd7, 0x1a, 0xcf, 0x65, 0xba, 0xe7, 0x4f, 0xec,
- 0xf0, 0x80, 0x1a, 0xd4, 0xe9, 0x6e, 0x9f, 0x3d,
- 0x3a, 0x90, 0x4f, 0xfd, 0xde, 0x7f, 0xbf, 0x7d,
- 0x6c, 0x38, 0x74, 0xfb, 0x3d, 0xb0, 0xe1, 0xd3,
- 0xaf, 0x5f, 0x58, 0xfa, 0xae, 0x89, 0x3e, 0x14,
- 0xee, 0x43, 0x45, 0x3d, 0x0d, 0xc4, 0x7d, 0xac,
- 0x25, 0xf0, 0xd2, 0x7f, 0xf7, 0x3d, 0xdb, 0x7f,
- 0x83, 0x5a, 0xa8, 0x0e, 0x87, 0x22, 0x07, 0x63,
- 0x79, 0xce, 0xdb, 0x0e, 0x9f, 0x2b, 0xc1, 0xab,
- 0xce, 0x9e, 0x4e, 0xe4, 0x34, 0x56, 0x70, 0xd1,
- 0xe9, 0x89, 0x44, 0xfd, 0x43, 0x17, 0xef, 0xa9,
- 0xd3, 0x96, 0x8f, 0x1d, 0x3e, 0xb8, 0x37, 0xfd,
- 0xe7, 0x4e, 0xd7, 0xaa, 0x74, 0xfb, 0x1a, 0xa3,
- 0x50, 0x1d, 0x27, 0x62, 0x37, 0x04, 0x8a, 0xc5,
- 0xdc, 0x39, 0xf2, 0xad, 0xe3, 0x93, 0xff, 0x3b,
- 0x9e, 0xec, 0x14, 0xee, 0x43, 0x44, 0x8b, 0x3f,
- 0x9d, 0x82, 0x9d, 0xc8, 0x68, 0xb2, 0x67, 0xf3,
- 0xb0, 0x53, 0xb9, 0x0d, 0x16, 0xc4, 0xec, 0xae,
- 0x1d, 0x3e, 0x14, 0xee, 0x43, 0x45, 0xb7, 0x27,
- 0x3c, 0xf2, 0xb0, 0x6a, 0x7f, 0xcd, 0xc6, 0xe6,
- 0xeb, 0x5e, 0xd9, 0xf5, 0x01, 0xd3, 0xf2, 0xfd,
- 0xfb, 0x6a, 0xc3, 0xa7, 0xc2, 0x9d, 0xc8, 0x68,
- 0xbc, 0x27, 0xaf, 0xb9, 0x96, 0x3a, 0x7f, 0xe5,
- 0xde, 0xca, 0x5f, 0x7c, 0xfd, 0xea, 0x74, 0xfb,
- 0x3e, 0x06, 0xf5, 0x3a, 0x7c, 0xbb, 0xf5, 0xea,
- 0x9d, 0x3a, 0xea, 0x03, 0xa4, 0xed, 0xd7, 0x93,
- 0x84, 0xa1, 0x37, 0x0b, 0xe9, 0x30, 0xb1, 0x20,
- 0x11, 0xfe, 0x53, 0x72, 0x99, 0xde, 0xca, 0x4e,
- 0x9f, 0x0a, 0x77, 0x21, 0xa2, 0xf4, 0x9f, 0xf7,
- 0xfa, 0xef, 0x5d, 0x37, 0xf5, 0x07, 0x4f, 0xb1,
- 0x96, 0xed, 0x8e, 0x93, 0xb6, 0x45, 0xa6, 0x0e,
- 0x6f, 0x30, 0x6f, 0x41, 0x85, 0x64, 0x52, 0xd1,
- 0x0b, 0x5c, 0x8f, 0xc1, 0x09, 0x3d, 0x1a, 0x58,
- 0xae, 0x31, 0x30, 0x07, 0x7f, 0x84, 0x2e, 0xb1,
- 0xd5, 0x86, 0x33, 0x69, 0xec, 0xb7, 0x5c, 0xe9,
- 0xfd, 0x9e, 0x10, 0x03, 0x5a, 0x9d, 0x2d, 0xd3,
- 0xe7, 0xa7, 0x52, 0x09, 0xf0, 0xa7, 0x72, 0x1a,
- 0x22, 0x39, 0xff, 0xeb, 0x6b, 0x5a, 0xe3, 0x3f,
- 0x8d, 0xb4, 0x2b, 0x75, 0x3a, 0x7f, 0xcf, 0x5a,
- 0x07, 0x2f, 0x7f, 0x5c, 0xe9, 0xff, 0xfe, 0x5b,
- 0x77, 0xae, 0xb6, 0xfe, 0x5e, 0xde, 0xb6, 0x78,
- 0x27, 0x4d, 0x43, 0x0a, 0x98, 0x21, 0x2a, 0x7f,
- 0xe7, 0xb9, 0x2d, 0xe6, 0xac, 0xb4, 0x38, 0x06,
- 0xb4, 0x22, 0xf3, 0xfb, 0x37, 0x7f, 0xcb, 0x75,
- 0xce, 0x9f, 0xff, 0x91, 0xc3, 0xdf, 0xf5, 0xdc,
- 0x2b, 0x7f, 0xf0, 0x0e, 0x86, 0xe2, 0xa7, 0x1c,
- 0x2d, 0x43, 0x0a, 0x56, 0x84, 0xfb, 0xa1, 0x25,
- 0x75, 0xd6, 0xc6, 0xb3, 0xe1, 0x4e, 0xe4, 0x34,
- 0x45, 0xd3, 0xeb, 0x83, 0x7f, 0xde, 0x5b, 0x3d,
- 0x92, 0x76, 0x1f, 0x47, 0x18, 0x43, 0x93, 0x09,
- 0x7c, 0x38, 0xe7, 0xfe, 0x67, 0x3d, 0xd8, 0x29,
- 0xdc, 0x86, 0x89, 0x9a, 0x75, 0x2b, 0x53, 0xa7,
- 0x27, 0x98, 0x74, 0xed, 0xd5, 0xb9, 0xba, 0x8e,
- 0x9f, 0x27, 0x5b, 0xcd, 0x1d, 0x3f, 0xf3, 0x7f,
- 0xaf, 0xe4, 0xf6, 0xd7, 0xc4, 0x3a, 0x7f, 0xff,
- 0xb5, 0xef, 0xa7, 0xf3, 0x6b, 0x6b, 0xa2, 0xca,
- 0xf1, 0x5a, 0x0e, 0x8c, 0x45, 0x8d, 0x91, 0xe7,
- 0xff, 0xdb, 0x7b, 0xf4, 0x65, 0x7d, 0xd6, 0x70,
- 0x42, 0x12, 0xa7, 0x93, 0xb9, 0x0d, 0x16, 0x7c,
- 0xff, 0xbd, 0x65, 0x7f, 0xae, 0xb7, 0xa9, 0xd3,
- 0xff, 0xde, 0x1b, 0x76, 0x8c, 0x6d, 0xfc, 0xae,
- 0x7c, 0xe9, 0xc1, 0x08, 0x4a, 0x9f, 0xf7, 0x3e,
- 0xbf, 0xc4, 0xdb, 0x04, 0xa7, 0x17, 0x93, 0xfc,
- 0xb6, 0xf6, 0xdf, 0xee, 0x68, 0xe9, 0xfe, 0xf7,
- 0xf6, 0xdf, 0xb6, 0xb7, 0xa9, 0xd0, 0x89, 0xf8,
- 0x8a, 0xc3, 0x0a, 0xec, 0x7c, 0x06, 0xdb, 0xa5,
- 0xb6, 0x39, 0x9f, 0xff, 0xff, 0xb3, 0x01, 0x5c,
- 0xcf, 0xe9, 0xde, 0x3f, 0x5c, 0xb3, 0xab, 0xfc,
- 0xa1, 0x98, 0xc3, 0xa7, 0x55, 0x68, 0x3a, 0x76,
- 0xe6, 0x58, 0xe8, 0x7a, 0x31, 0x2b, 0x08, 0xab,
- 0x8e, 0x4f, 0x52, 0x0d, 0x50, 0xe9, 0xf5, 0xbe,
- 0xb8, 0x26, 0x4f, 0xfb, 0xc2, 0xfc, 0x1a, 0x35,
- 0xed, 0x8d, 0x10, 0x6b, 0x8d, 0x2c, 0xfb, 0x93,
- 0xcc, 0x53, 0xa7, 0xe7, 0xdb, 0xfd, 0x4d, 0xce,
- 0x96, 0x21, 0xe9, 0xfc, 0x96, 0x7f, 0xff, 0xdc,
- 0x1b, 0xe5, 0xae, 0xb9, 0xfa, 0x6f, 0x83, 0xea,
- 0x39, 0x87, 0x43, 0xd3, 0x40, 0xc8, 0x57, 0xfc,
- 0x9a, 0x7e, 0x1c, 0xda, 0xb6, 0x53, 0xa7, 0xff,
- 0xf6, 0xbf, 0xed, 0x3a, 0x37, 0xff, 0xaf, 0x5f,
- 0x53, 0x6f, 0x04, 0xe9, 0xff, 0xfe, 0xad, 0x54,
- 0x6e, 0xae, 0x66, 0x5e, 0xbb, 0xeb, 0xcf, 0xc3,
- 0xa7, 0xad, 0x9e, 0x6c, 0x74, 0x79, 0x11, 0x36,
- 0x66, 0x99, 0x9b, 0xa1, 0xa2, 0xfc, 0x9f, 0xf9,
- 0xf7, 0xd5, 0xef, 0x65, 0xee, 0xac, 0x3a, 0x7f,
- 0xef, 0x67, 0xf3, 0x2b, 0xa1, 0xf5, 0x61, 0xd1,
- 0x4a, 0x22, 0xea, 0x8d, 0x3d, 0xff, 0xaa, 0x1d,
- 0x0a, 0x98, 0xd6, 0xc4, 0x79, 0x0b, 0x3e, 0x24,
- 0x9f, 0xff, 0xf9, 0xbd, 0x6d, 0xe6, 0x39, 0xa7,
- 0xf0, 0xef, 0xb7, 0xa9, 0xaa, 0x7a, 0x83, 0xa7,
- 0xfd, 0xcf, 0x67, 0x3e, 0xf5, 0x5d, 0x27, 0x4f,
- 0x65, 0x7d, 0xf3, 0xa3, 0xe7, 0xc1, 0xa9, 0xfc,
- 0xf6, 0xfd, 0x7a, 0xa7, 0x4f, 0xfa, 0xf5, 0x07,
- 0xa9, 0xa5, 0xf9, 0x73, 0xa1, 0x4f, 0x97, 0x09,
- 0x26, 0x6b, 0x53, 0xa4, 0xc3, 0xa2, 0x93, 0x50,
- 0xdd, 0x8c, 0x4f, 0xff, 0xfa, 0xde, 0xa6, 0xf9,
- 0x4d, 0xc4, 0x56, 0xe0, 0xdf, 0xf7, 0xdb, 0x0e,
- 0x9c, 0x10, 0x84, 0xa9, 0xed, 0xb6, 0xef, 0x94,
- 0xe2, 0xf2, 0x7f, 0xdd, 0x64, 0xf7, 0x68, 0xaf,
- 0x58, 0xe8, 0x54, 0xc8, 0x90, 0x9f, 0xd0, 0x8b,
- 0xb1, 0x94, 0xff, 0xd9, 0xfa, 0x6f, 0x83, 0xea,
- 0x39, 0x87, 0x4f, 0xb2, 0xef, 0x65, 0x8e, 0x85,
- 0x3e, 0xba, 0xa2, 0x4c, 0x0b, 0x1d, 0x3f, 0x50,
- 0xd3, 0xdb, 0x83, 0x41, 0xd3, 0xfb, 0x4d, 0xb2,
- 0xf6, 0xf5, 0xce, 0x9b, 0xc2, 0x74, 0x6e, 0xa3,
- 0xfe, 0xf1, 0xa5, 0x8d, 0x67, 0xfe, 0xd9, 0x76,
- 0x15, 0xbf, 0x93, 0xdb, 0x1d, 0x3f, 0x5b, 0x5a,
- 0x1a, 0xb7, 0x8e, 0x8d, 0x8f, 0xda, 0xc8, 0xb2,
- 0x73, 0x74, 0x66, 0xee, 0xee, 0xb0, 0xe2, 0x8d,
- 0xd0, 0x57, 0xb4, 0x36, 0x32, 0x50, 0x9d, 0x31,
- 0x94, 0xf8, 0xd5, 0xa8, 0xe2, 0x04, 0xd5, 0x85,
- 0x96, 0x94, 0x1b, 0xc8, 0x20, 0x86, 0xd7, 0xe1,
- 0x11, 0x58, 0xda, 0xaf, 0x0a, 0xc0, 0x90, 0xee,
- 0x42, 0x53, 0x7c, 0x2a, 0xe1, 0xcc, 0xf9, 0x0b,
- 0x53, 0x8a, 0x67, 0xff, 0x39, 0x9c, 0xf7, 0x60,
- 0xa7, 0x72, 0x1a, 0x26, 0xc9, 0xfc, 0xec, 0x14,
- 0xee, 0x43, 0x45, 0x5b, 0x3f, 0x9e, 0xfd, 0x6f,
- 0xf5, 0x79, 0xd3, 0xd9, 0x6e, 0xb9, 0xd2, 0xdd,
- 0x30, 0xf5, 0x3e, 0x69, 0x3e, 0x14, 0xee, 0x43,
- 0x45, 0x69, 0x3f, 0xfc, 0x8a, 0x38, 0x0e, 0x67,
- 0x3d, 0x7c, 0x87, 0x4f, 0xff, 0x3e, 0xb9, 0xf5,
- 0x67, 0x65, 0xee, 0xac, 0x3a, 0x6b, 0xdd, 0x51,
- 0x2f, 0xc9, 0x53, 0xf9, 0x5b, 0x6f, 0xbf, 0xd4,
- 0x07, 0x4f, 0xd4, 0x65, 0xbd, 0x8c, 0x3a, 0x7f,
- 0xb1, 0xbf, 0xea, 0x1a, 0x5f, 0x53, 0xa7, 0xf3,
- 0xf2, 0xfd, 0xf0, 0x6a, 0x74, 0x9c, 0xdc, 0x4f,
- 0xcb, 0x0b, 0x3d, 0x0c, 0x7b, 0x16, 0xf1, 0xb7,
- 0xcb, 0x6e, 0x79, 0x3f, 0x9d, 0x82, 0x9d, 0xc8,
- 0x68, 0xb0, 0x27, 0xc2, 0x9d, 0xc8, 0x68, 0x9d,
- 0x67, 0xff, 0xf5, 0x96, 0x8d, 0xb1, 0x8e, 0xad,
- 0x72, 0xde, 0xae, 0xb4, 0x1d, 0x3e, 0x73, 0x39,
- 0xee, 0xc4, 0x4a, 0xb4, 0x61, 0x3e, 0x14, 0xee,
- 0x43, 0x45, 0xb3, 0x3f, 0xe0, 0x2d, 0x5d, 0x6f,
- 0x27, 0x09, 0xd2, 0x76, 0x1f, 0x67, 0x18, 0x4f,
- 0x27, 0x72, 0x1a, 0x2e, 0x69, 0x30, 0xe9, 0x9d,
- 0x82, 0x6e, 0xc2, 0x57, 0x3f, 0x9d, 0x82, 0x9d,
- 0xc8, 0x68, 0xbb, 0xe7, 0x9d, 0xa7, 0x60, 0x1d,
- 0x0a, 0xda, 0xcb, 0x65, 0x3e, 0xe5, 0x0c, 0x29,
- 0x52, 0xf4, 0xa8, 0x11, 0x72, 0x64, 0x34, 0x01,
- 0x0a, 0xca, 0xb0, 0xdc, 0xaf, 0x79, 0xdc, 0xff,
- 0xbf, 0xce, 0x5a, 0xd5, 0x9c, 0xf3, 0xa7, 0xf7,
- 0xe8, 0xc6, 0xfb, 0xae, 0x93, 0xa7, 0xc2, 0x9d,
- 0xc8, 0x68, 0x95, 0xe7, 0xfd, 0xfe, 0x0e, 0xd6,
- 0x5a, 0x30, 0x27, 0x4f, 0x6b, 0xc2, 0xf3, 0xa7,
- 0xff, 0xf7, 0xaf, 0xcc, 0xef, 0x82, 0xc1, 0xef,
- 0xd0, 0x9e, 0xa0, 0xe8, 0xd9, 0x10, 0x7c, 0x43,
- 0x1b, 0x23, 0x96, 0xd0, 0xc2, 0x9d, 0xcf, 0x72,
- 0xa6, 0xed, 0x87, 0x15, 0x8c, 0x56, 0x75, 0xd7,
- 0x62, 0xa7, 0xff, 0x5b, 0xbd, 0x75, 0x7f, 0x86,
- 0x8d, 0x40, 0x54, 0xfe, 0xe4, 0x76, 0xc2, 0xdd,
- 0xb9, 0x4f, 0x9e, 0xa3, 0x92, 0x72, 0x2a, 0xae,
- 0x64, 0x76, 0x6d, 0xa1, 0x5b, 0x3f, 0xf9, 0xcc,
- 0xe7, 0xbb, 0x05, 0x3b, 0x90, 0xd1, 0x30, 0xcf,
- 0xff, 0xd8, 0xed, 0xe3, 0xc0, 0x76, 0x9b, 0xbc,
- 0x2b, 0x57, 0x9d, 0x3f, 0xf6, 0xe9, 0x94, 0xbf,
- 0x5e, 0xbf, 0xd5, 0xe7, 0x4f, 0xe5, 0xea, 0x2f,
- 0xa7, 0x84, 0xe9, 0xf7, 0x0b, 0xf9, 0x87, 0x47,
- 0xcf, 0x63, 0x53, 0x39, 0xf9, 0x8b, 0x9f, 0xbe,
- 0xe1, 0xd3, 0xe5, 0xcf, 0xdf, 0x70, 0xe9, 0xfa,
- 0xde, 0xbd, 0x7a, 0x9d, 0x07, 0xb0, 0xc2, 0xf9,
- 0xff, 0xff, 0x7f, 0x02, 0xdf, 0x7c, 0xb6, 0x8f,
- 0xe5, 0x1e, 0xcf, 0xd2, 0xfa, 0x9d, 0x3f, 0x36,
- 0xdf, 0x7f, 0xa8, 0x0e, 0x9f, 0xfc, 0xb7, 0x02,
- 0xbf, 0x29, 0xbd, 0x1a, 0x84, 0xe8, 0x53, 0xfd,
- 0xf1, 0x8c, 0xfd, 0x5f, 0x69, 0x67, 0x5c, 0xe9,
- 0xff, 0xff, 0x0e, 0x36, 0x5f, 0xdf, 0x46, 0xff,
- 0xad, 0xbb, 0xd7, 0x5b, 0xd4, 0xe9, 0x65, 0x28,
- 0x9f, 0x12, 0xf9, 0xef, 0xa8, 0x37, 0x9d, 0x3d,
- 0xdb, 0xf6, 0xc3, 0xa4, 0xe6, 0xe2, 0xb8, 0x3d,
- 0xa1, 0x44, 0x8f, 0x6d, 0x24, 0x5a, 0x1e, 0x1f,
- 0x86, 0x05, 0xca, 0x35, 0x23, 0x9f, 0x0a, 0x77,
- 0x21, 0xa2, 0xae, 0x9f, 0xe7, 0xbb, 0x05, 0x3b,
- 0x90, 0xd1, 0x1e, 0x49, 0xd8, 0x7e, 0x3c, 0x61,
- 0x3f, 0x9d, 0x82, 0x9d, 0xc8, 0x68, 0xb0, 0x67,
- 0xf3, 0xb0, 0x53, 0xb9, 0x0d, 0x16, 0x54, 0xfe,
- 0x76, 0x0a, 0x77, 0x21, 0xa2, 0xd3, 0x9e, 0x4e,
- 0xe4, 0x34, 0x5b, 0x93, 0xff, 0x2e, 0x0e, 0x7f,
- 0x45, 0xb2, 0x90, 0x9d, 0x02, 0x7d, 0xf5, 0x2b,
- 0x9f, 0xe5, 0xfe, 0xac, 0x5a, 0xdf, 0xc7, 0x4f,
- 0xfb, 0x9e, 0xec, 0x14, 0xee, 0x43, 0x45, 0x0f,
- 0x3f, 0x57, 0xa9, 0xad, 0xfc, 0x74, 0xfd, 0xf6,
- 0xe6, 0x0a, 0xd4, 0xe9, 0xff, 0xfb, 0x36, 0xb2,
- 0xef, 0x75, 0xff, 0xc0, 0xad, 0x54, 0x05, 0x49,
- 0xd8, 0x9a, 0xd7, 0x88, 0x58, 0x73, 0x74, 0x6d,
- 0x4b, 0xb7, 0x0b, 0xe7, 0xf3, 0xb0, 0x53, 0xb9,
- 0x0d, 0x17, 0x9c, 0x2b, 0x22, 0xc9, 0xe8, 0x9b,
- 0x29, 0x64, 0xbe, 0x1a, 0x61, 0xfe, 0x24, 0xcc,
- 0x3b, 0xb1, 0xdf, 0xe5, 0x02, 0x36, 0x61, 0x9f,
- 0xce, 0xc1, 0x4e, 0xe4, 0x34, 0x52, 0xd3, 0xf9,
- 0xd8, 0x29, 0xdc, 0x86, 0x8b, 0x0a, 0x7f, 0x3b,
- 0x05, 0x3b, 0x90, 0xd1, 0x65, 0xcf, 0x3b, 0x4e,
- 0xeb, 0xe6, 0xea, 0x74, 0xe7, 0x6f, 0x61, 0xd3,
- 0xc8, 0xe5, 0xaa, 0x1e, 0x96, 0xa6, 0x93, 0xff,
- 0x9c, 0xce, 0x7b, 0xb0, 0x53, 0xb9, 0x0d, 0x14,
- 0x64, 0xfe, 0x72, 0xb6, 0x51, 0x50, 0x1d, 0x0f,
- 0x4e, 0xfc, 0x4e, 0xd8, 0x77, 0xd0, 0x8d, 0xa9,
- 0xc5, 0xd4, 0xa7, 0xfe, 0x77, 0x3d, 0xd8, 0x29,
- 0xdc, 0x86, 0x88, 0xe6, 0x7f, 0xf3, 0x99, 0xcf,
- 0x76, 0x0a, 0x77, 0x21, 0xa2, 0x72, 0x9f, 0xce,
- 0xc1, 0x4e, 0xe4, 0x34, 0x59, 0x93, 0xff, 0x39,
- 0x40, 0x2b, 0x7b, 0x75, 0x2f, 0x3a, 0x7f, 0x3b,
- 0x05, 0x3b, 0x90, 0xd1, 0x6e, 0xcf, 0xfe, 0x73,
- 0x39, 0xee, 0xc1, 0x4e, 0xe4, 0x34, 0x52, 0x13,
- 0xff, 0x3b, 0x9e, 0xec, 0x14, 0xee, 0x43, 0x44,
- 0xa5, 0x14, 0x27, 0xea, 0xd2, 0x63, 0x14, 0x80,
- 0x77, 0xf4, 0x3b, 0x9d, 0xb7, 0xa9, 0x4f, 0xfb,
- 0x9e, 0xec, 0x14, 0xee, 0x43, 0x44, 0xed, 0x3f,
- 0xfe, 0xf6, 0xda, 0xb1, 0x5b, 0xfb, 0x6f, 0xaf,
- 0xf1, 0x0e, 0x93, 0x98, 0x89, 0xfe, 0x46, 0x9f,
- 0xfb, 0x99, 0x6c, 0x4e, 0xb2, 0xef, 0x79, 0xd3,
- 0xff, 0x7f, 0x2d, 0xd4, 0x65, 0x7f, 0xd4, 0x9d,
- 0x36, 0xe3, 0xb6, 0x44, 0x3d, 0x50, 0xe1, 0x88,
- 0xe2, 0xdc, 0x85, 0x7c, 0xf8, 0x53, 0xb9, 0x0d,
- 0x11, 0x64, 0xff, 0xb9, 0xee, 0xc1, 0x4e, 0xe4,
- 0x34, 0x4b, 0xb3, 0xff, 0xf6, 0x6d, 0x65, 0xde,
- 0xeb, 0xff, 0x81, 0x5a, 0xa8, 0x0a, 0x93, 0xb1,
- 0x1a, 0x6c, 0x30, 0xdc, 0x46, 0x9f, 0xfc, 0xe6,
- 0x73, 0xdd, 0x82, 0x9d, 0xc8, 0x68, 0x98, 0xa7,
- 0xec, 0x14, 0xee, 0x43, 0x45, 0x53, 0x3f, 0xff,
- 0xf8, 0x7a, 0xd4, 0xbf, 0x2e, 0xeb, 0x75, 0x47,
- 0xc1, 0xbd, 0xbc, 0x2f, 0x3a, 0x1c, 0x8a, 0xce,
- 0x35, 0x9f, 0xfc, 0xe6, 0x73, 0xdd, 0x82, 0x9d,
- 0xc8, 0x68, 0x9d, 0x27, 0xf7, 0xb8, 0x55, 0xfc,
- 0xd8, 0xe9, 0xf3, 0x4a, 0xd2, 0xd4, 0xe9, 0xf8,
- 0x39, 0xe6, 0xd9, 0xf3, 0xa7, 0xbd, 0x65, 0x77,
- 0x8f, 0x5a, 0xa5, 0x13, 0xff, 0x6b, 0x5b, 0xad,
- 0x2e, 0xd5, 0xaf, 0x30, 0xe8, 0x62, 0x20, 0xac,
- 0x73, 0x3f, 0xee, 0x7b, 0xb0, 0x53, 0xb9, 0x0d,
- 0x13, 0xbc, 0xfa, 0xfa, 0xf3, 0x3c, 0x54, 0x9d,
- 0xb2, 0x73, 0x79, 0x18, 0x53, 0x08, 0xf9, 0x1a,
- 0x7f, 0xf3, 0x99, 0xcf, 0x76, 0x0a, 0x77, 0x21,
- 0xa2, 0x85, 0x9f, 0xfc, 0xe6, 0x73, 0xdd, 0x82,
- 0x9d, 0xc8, 0x68, 0xa4, 0xa7, 0xff, 0xf6, 0x55,
- 0xdb, 0xf1, 0xab, 0x73, 0x2f, 0x65, 0xbe, 0xac,
- 0x3a, 0x28, 0x5c, 0x96, 0x79, 0xc2, 0x43, 0xf8,
- 0x48, 0x99, 0x1f, 0x68, 0x12, 0x75, 0x52, 0xdc,
- 0x52, 0x9f, 0xce, 0xc1, 0x4e, 0xe4, 0x34, 0x44,
- 0x93, 0xff, 0x9c, 0xce, 0x7b, 0xb0, 0x53, 0xb9,
- 0x0d, 0x12, 0xf4, 0xf8, 0x53, 0xb9, 0x0d, 0x14,
- 0xbc, 0xff, 0xec, 0x7a, 0x82, 0xa2, 0xb4, 0xbf,
- 0xcc, 0x3a, 0x7c, 0xdf, 0xe6, 0x2d, 0x4e, 0x9f,
- 0x73, 0x6c, 0x1a, 0x9d, 0x25, 0xd8, 0xf4, 0x58,
- 0x55, 0x27, 0x62, 0x3c, 0x9a, 0x30, 0xbc, 0x26,
- 0xa7, 0xf3, 0xb0, 0x53, 0xb9, 0x0d, 0x14, 0xe4,
- 0xff, 0xbc, 0x3d, 0x5b, 0x66, 0x7d, 0x0e, 0x9f,
- 0xf6, 0x59, 0x47, 0x1c, 0x10, 0x84, 0xa9, 0xbc,
- 0x13, 0xa6, 0xa1, 0xdb, 0x22, 0x37, 0x70, 0xed,
- 0xbc, 0xf2, 0x7c, 0x29, 0xdc, 0x86, 0x8a, 0xf2,
- 0x7f, 0xfe, 0xcd, 0xac, 0xbb, 0xdd, 0x7f, 0xf0,
- 0x2b, 0x55, 0x01, 0x52, 0x76, 0x22, 0x37, 0x70,
- 0xc2, 0x7f, 0xe7, 0x73, 0xdd, 0x82, 0x9d, 0xc8,
- 0x68, 0x91, 0xe7, 0x78, 0x0a, 0x74, 0xe4, 0xc6,
- 0x14, 0xe2, 0xee, 0x7c, 0x29, 0xdc, 0x86, 0x89,
- 0x22, 0x79, 0xdc, 0xf7, 0x29, 0xec, 0xe1, 0x4c,
- 0xff, 0xce, 0xe7, 0xbb, 0x05, 0x3b, 0x90, 0xd1,
- 0x25, 0x4f, 0x85, 0x3b, 0x90, 0xd1, 0x78, 0xcf,
- 0xda, 0xfe, 0x9e, 0xa6, 0xa7, 0x4f, 0xab, 0x5b,
- 0xe2, 0x1d, 0x3f, 0xcf, 0x76, 0x0a, 0x77, 0x21,
- 0xa2, 0x4d, 0x93, 0xb1, 0x18, 0xf4, 0x98, 0x09,
- 0x87, 0x13, 0x42, 0xae, 0xe4, 0xd0, 0x76, 0xf8,
- 0xd1, 0x36, 0x3b, 0xf4, 0x32, 0x1a, 0x86, 0x8b,
- 0x0a, 0xed, 0x0c, 0x0b, 0x9b, 0xeb, 0x18, 0x9c,
- 0x2c, 0x6e, 0xd9, 0x14, 0x47, 0x5c, 0xf8, 0xf2,
- 0x76, 0x94, 0x35, 0x96, 0xeb, 0x5b, 0x4c, 0xa5,
- 0x84, 0xaf, 0xf7, 0xa9, 0x9e, 0x7b, 0xf4, 0xe7,
- 0xa6, 0xee, 0x3b, 0x06, 0xa9, 0xd8, 0x63, 0x48,
- 0xf5, 0x66, 0x23, 0x3e, 0xed, 0x3b, 0x51, 0xd4,
- 0xf7, 0x20, 0x4b, 0x0e, 0x6e, 0xe1, 0x63, 0xf9,
- 0xec, 0x6a, 0xd2, 0x57, 0x6f, 0x5d, 0x0f, 0xeb,
- 0x4c, 0x16, 0x6d, 0x29, 0x88, 0x32, 0x94, 0x37,
- 0x23, 0xeb, 0xdf, 0x3b, 0x28, 0xdf, 0x3c, 0x97,
- 0x00,
+ 0xb3, 0x6f, 0x02, 0xa7, 0xd3, 0xfa, 0x5c, 0x27,
+ 0xc9, 0xf2, 0xf9, 0xfb, 0xf4, 0xd5, 0xac, 0xb9,
+ 0xd3, 0xff, 0xdf, 0xbb, 0x58, 0x39, 0xcc, 0x5b,
+ 0x7b, 0x63, 0xa7, 0xd4, 0x6e, 0xfd, 0x94, 0x9d,
+ 0x3e, 0xf5, 0x56, 0x86, 0x1f, 0x2f, 0xd9, 0xf2,
+ 0xf0, 0x83, 0x53, 0xe5, 0xfb, 0x37, 0x3c, 0xf9,
+ 0x7e, 0xcf, 0x6a, 0xfc, 0xa9, 0xf2, 0xfd, 0x8d,
+ 0x8f, 0x47, 0xe4, 0x53, 0xe5, 0xca, 0xe7, 0xcf,
+ 0x97, 0xec, 0x1f, 0x2f, 0xd9, 0xba, 0xe7, 0xcb,
+ 0xf5, 0x85, 0xbc, 0x9f, 0xf3, 0xfa, 0xd5, 0x26,
+ 0x7b, 0x37, 0x3c, 0x03, 0xe5, 0xfb, 0x07, 0xcb,
+ 0xf6, 0x60, 0x29, 0xf2, 0xfd, 0x9f, 0xec, 0x07,
+ 0x0e, 0x36, 0xcd, 0x8f, 0x97, 0xec, 0xfd, 0x96,
+ 0xf5, 0x75, 0xa0, 0xf9, 0x7e, 0xc0, 0x11, 0x47,
+ 0xf2, 0x2a, 0xa2, 0xcf, 0x0d, 0x0b, 0x73, 0xe5,
+ 0xfb, 0x07, 0xcb, 0xf7, 0x0d, 0x74, 0xc1, 0x09,
+ 0xf2, 0xfd, 0x87, 0xab, 0x11, 0xd8, 0xd7, 0x21,
+ 0x09, 0x4c, 0x27, 0x44, 0xa5, 0x86, 0x35, 0x85,
+ 0xd5, 0xd7, 0x82, 0x4d, 0x3d, 0x8f, 0x5d, 0x25,
+ 0xcb, 0xf4, 0xe4, 0x47, 0xcf, 0xfb, 0x13, 0x6c,
+ 0x10, 0xf5, 0x9a, 0x3a, 0x67, 0xd0, 0x54, 0x50,
+ 0x89, 0x6a, 0x50, 0xbe, 0x7b, 0x02, 0xb9, 0x2b,
+ 0xd3, 0x8c, 0x73, 0xff, 0xf5, 0x2f, 0x15, 0x6d,
+ 0xcd, 0x2e, 0xd6, 0x56, 0x73, 0x47, 0x42, 0xae,
+ 0xe1, 0xe1, 0x37, 0x8b, 0xfa, 0x73, 0x93, 0x52,
+ 0xc9, 0xff, 0x69, 0x5a, 0x7e, 0xb6, 0xb6, 0xa8,
+ 0x74, 0xfd, 0xfe, 0xd3, 0x6e, 0x79, 0xd3, 0x82,
+ 0x10, 0x95, 0x3b, 0x7a, 0x80, 0xa7, 0x17, 0x93,
+ 0xfe, 0xff, 0x3f, 0x78, 0xe3, 0x6e, 0x13, 0xa7,
+ 0xfb, 0xfc, 0x0d, 0x0f, 0x50, 0x52, 0x74, 0x6c,
+ 0x99, 0x8b, 0x10, 0x40, 0x95, 0xf2, 0xcb, 0x9f,
+ 0xcf, 0xfb, 0xff, 0xf6, 0xad, 0xdd, 0x77, 0x16,
+ 0xe7, 0x4e, 0x08, 0x42, 0x58, 0x84, 0x13, 0xe1,
+ 0x4e, 0xe4, 0x2c, 0x42, 0x07, 0x1a, 0xa9, 0xc1,
+ 0x08, 0x4b, 0x10, 0x7a, 0x0b, 0x10, 0x79, 0xc6,
+ 0xaa, 0x65, 0x66, 0x22, 0x4d, 0x1a, 0xe7, 0xd7,
+ 0x5b, 0xab, 0x0e, 0x9e, 0xff, 0x97, 0x49, 0xd3,
+ 0xb7, 0xa8, 0x0e, 0x8a, 0x0f, 0x01, 0x84, 0x73,
+ 0xe4, 0x5b, 0x2b, 0x0a, 0x9f, 0x7f, 0xbf, 0xfc,
+ 0x2a, 0x6c, 0x42, 0xa6, 0x08, 0x4a, 0x8c, 0x3f,
+ 0x5a, 0x92, 0xdc, 0x98, 0x22, 0x93, 0xfb, 0xfb,
+ 0xd4, 0x16, 0xc6, 0xf2, 0x9c, 0x6e, 0xe1, 0x53,
+ 0x80, 0xf3, 0x37, 0x43, 0x4e, 0x7f, 0xf5, 0x94,
+ 0x15, 0xcc, 0xdb, 0xbf, 0xda, 0x4e, 0x9f, 0xd5,
+ 0xde, 0xca, 0x87, 0xa9, 0x3a, 0x15, 0x5d, 0x8e,
+ 0x26, 0x7a, 0x30, 0x51, 0x8e, 0xb3, 0x8d, 0x2a,
+ 0x95, 0x38, 0x21, 0x09, 0x53, 0xe7, 0x83, 0xbf,
+ 0xb1, 0x4e, 0x2f, 0x27, 0xff, 0xbf, 0x4e, 0x8a,
+ 0x40, 0xbf, 0x4e, 0xa3, 0xfc, 0x74, 0xff, 0xf6,
+ 0x2b, 0xb6, 0xfa, 0xea, 0x99, 0xa7, 0xc2, 0x74,
+ 0xf3, 0x7d, 0x80, 0xd8, 0xe8, 0x79, 0xfb, 0xf2,
+ 0x84, 0xff, 0xe7, 0xe0, 0x81, 0x9e, 0xae, 0xfa,
+ 0xae, 0x1d, 0x3d, 0xed, 0xb1, 0x87, 0x42, 0xa7,
+ 0x1c, 0xf3, 0x7e, 0x86, 0x57, 0xc8, 0x75, 0x4a,
+ 0x9f, 0xb7, 0x75, 0xf7, 0xe9, 0x79, 0xd3, 0xfe,
+ 0xe1, 0xdc, 0xf5, 0xb3, 0xa9, 0x01, 0xd3, 0xfe,
+ 0xad, 0x54, 0x6e, 0xae, 0xdb, 0xc7, 0x4f, 0xfb,
+ 0xfc, 0xd5, 0xb8, 0x47, 0xdb, 0x1d, 0x18, 0x8e,
+ 0xf4, 0x33, 0xf2, 0x03, 0x0f, 0xa7, 0x9f, 0xbf,
+ 0x1a, 0x3a, 0x7c, 0x3b, 0x66, 0x7c, 0xe9, 0xff,
+ 0xb7, 0x7e, 0xcb, 0x2b, 0x6a, 0xd9, 0x69, 0x3a,
+ 0x38, 0xfc, 0x2a, 0x4d, 0x3f, 0xfd, 0x97, 0xae,
+ 0x35, 0x65, 0x6d, 0x96, 0xb2, 0x9d, 0x3f, 0xae,
+ 0xdd, 0x5a, 0xfb, 0x74, 0xa3, 0x53, 0xa3, 0x64,
+ 0x5a, 0x7c, 0x86, 0xea, 0x13, 0xff, 0xde, 0xae,
+ 0x6d, 0x7a, 0xfb, 0x4d, 0xbb, 0xfe, 0x3a, 0x7f,
+ 0xff, 0x7e, 0xf9, 0x6f, 0x2d, 0xfc, 0x05, 0x7b,
+ 0x82, 0x10, 0x95, 0x3d, 0xb6, 0x66, 0x92, 0xa7,
+ 0x3f, 0xfa, 0x9a, 0x21, 0x99, 0xc1, 0x08, 0x4a,
+ 0x9d, 0x9f, 0x42, 0x9c, 0x5e, 0x4f, 0xfb, 0x28,
+ 0xcd, 0xb9, 0xff, 0x5a, 0x0e, 0x80, 0x1f, 0x47,
+ 0xca, 0x67, 0xf3, 0xff, 0x97, 0xbe, 0xb4, 0x1d,
+ 0x0a, 0x9c, 0x4d, 0x0c, 0x34, 0x91, 0x8c, 0x2b,
+ 0xb8, 0x8a, 0x7b, 0xd7, 0xf2, 0x9d, 0x3f, 0xb5,
+ 0xc1, 0x00, 0x3d, 0xf3, 0xa7, 0xff, 0xca, 0xff,
+ 0x6d, 0x6d, 0xf5, 0xc1, 0x4e, 0xe4, 0x34, 0x41,
+ 0x91, 0x64, 0x4a, 0x5c, 0xce, 0x7d, 0x51, 0xf0,
+ 0x77, 0x67, 0x4f, 0xed, 0xcc, 0xae, 0xe6, 0x0a,
+ 0x9d, 0x0f, 0x4c, 0xe7, 0xd0, 0xb5, 0xa9, 0x1d,
+ 0xca, 0xe7, 0xff, 0x97, 0xf4, 0x68, 0x6b, 0xdf,
+ 0xcd, 0xb3, 0xfa, 0x4e, 0x9c, 0xa2, 0xd1, 0xd0,
+ 0xab, 0xb9, 0x9b, 0x1d, 0xe4, 0x69, 0x08, 0x63,
+ 0xe8, 0xf7, 0x3a, 0x38, 0x8d, 0x50, 0xf7, 0x15,
+ 0xa7, 0xff, 0x91, 0x6b, 0x55, 0x66, 0x5f, 0xd5,
+ 0xb7, 0x1d, 0x3f, 0xbf, 0xf5, 0x7b, 0x17, 0xc7,
+ 0x4f, 0xeb, 0xf9, 0xb7, 0xae, 0xf5, 0x2a, 0x4c,
+ 0x3a, 0x7e, 0xcf, 0xe9, 0x15, 0x77, 0x8f, 0x17,
+ 0x79, 0xac, 0x62, 0x61, 0x7e, 0x4d, 0xab, 0xbc,
+ 0xf0, 0xeb, 0x4b, 0xce, 0x9f, 0xdf, 0x7f, 0xf1,
+ 0x8a, 0x87, 0x4e, 0x66, 0xd8, 0x74, 0x29, 0xf8,
+ 0x61, 0x1f, 0x18, 0xce, 0xbf, 0xa8, 0x3a, 0x7f,
+ 0xda, 0xde, 0xbb, 0xc4, 0x0c, 0xf5, 0x4e, 0x9f,
+ 0xf9, 0x7f, 0xd6, 0x50, 0x38, 0x6b, 0x52, 0xa3,
+ 0x64, 0x42, 0x31, 0x0a, 0x7d, 0x6f, 0x7a, 0x9a,
+ 0x9d, 0x05, 0x4f, 0xd5, 0xde, 0xa2, 0xac, 0x2a,
+ 0x0a, 0x82, 0xa0, 0xa8, 0x2a, 0x1e, 0x7b, 0xfe,
+ 0x0a, 0x01, 0x6e, 0xa1, 0x5b, 0x81, 0x4d, 0xe1,
+ 0x53, 0x5b, 0x0a, 0x9f, 0xbb, 0xae, 0xd2, 0xb0,
+ 0xad, 0x05, 0xac, 0x9b, 0xb2, 0xa0, 0xa8, 0x2a,
+ 0x1e, 0x5a, 0x78, 0x2a, 0x0a, 0x82, 0xa0, 0xa8,
+ 0x2a, 0x0a, 0x82, 0xa2, 0x83, 0x79, 0xb0, 0x57,
+ 0x82, 0x80, 0x15, 0x50, 0xa6, 0xc1, 0x50, 0x54,
+ 0x15, 0x0f, 0x2d, 0x2a, 0x15, 0x05, 0x41, 0x50,
+ 0x54, 0x15, 0x0f, 0x35, 0x00, 0x0a, 0xb8, 0x53,
+ 0x78, 0x54, 0x15, 0x05, 0x41, 0x50, 0x54, 0x50,
+ 0x6a, 0x34, 0x85, 0x08, 0x55, 0x82, 0xa5, 0xa4,
+ 0xa8, 0x2a, 0x0a, 0x82, 0xa0, 0xa8, 0xd8, 0xd4,
+ 0x52, 0x14, 0x00, 0xad, 0x42, 0xa0, 0xa8, 0x2a,
+ 0x0a, 0x9f, 0x59, 0x41, 0x5c, 0x2a, 0x0a, 0x87,
+ 0x9e, 0x72, 0x05, 0x58, 0x2b, 0x82, 0x80, 0x4d,
+ 0x24, 0x2a, 0x0a, 0x82, 0xa0, 0xa8, 0x2a, 0x1e,
+ 0x6a, 0x29, 0x0a, 0xf0, 0x53, 0x60, 0xa8, 0x2a,
+ 0x0a, 0x82, 0xa0, 0xa8, 0x79, 0xa8, 0xd8, 0x2a,
+ 0xc1, 0x5f, 0x0a, 0x95, 0x8a, 0x82, 0xa0, 0xa9,
+ 0x3c, 0xa8, 0x2a, 0x92, 0xc2, 0x0a, 0x82, 0xa0,
+ 0xa8, 0x2a, 0x28, 0x3e, 0x67, 0x85, 0x69, 0x1a,
+ 0x41, 0xa6, 0x82, 0x80, 0x15, 0x70, 0xa9, 0x61,
+ 0x50, 0x54, 0x15, 0x27, 0x95, 0x05, 0x52, 0x58,
+ 0x41, 0x50, 0x54, 0x29, 0xe9, 0x3c, 0x2b, 0xc3,
+ 0x42, 0x34, 0xc0, 0xa8, 0x2a, 0x0a, 0x82, 0xa0,
+ 0xa8, 0x2a, 0x14, 0xd9, 0x52, 0x14, 0x21, 0x4c,
+ 0x0a, 0xf8, 0x54, 0x15, 0x05, 0x41, 0x50, 0x25,
+ 0xf5, 0x42, 0xae, 0x15, 0x05, 0x41, 0x50, 0x54,
+ 0x30, 0xbe, 0xf8, 0x55, 0xc2, 0xa4, 0xc2, 0xa0,
+ 0xa8, 0x2a, 0x00, 0x5a, 0x6a, 0x15, 0x05, 0x41,
+ 0x50, 0x54, 0x15, 0x0a, 0x6a, 0x1a, 0x0a, 0xb0,
+ 0x56, 0xa1, 0x50, 0xab, 0xf5, 0xb4, 0x39, 0x3c,
+ 0xf7, 0x62, 0x9c, 0x5c, 0x46, 0xda, 0x52, 0x3c,
+ 0xcd, 0xbb, 0x3d, 0x68, 0xe8, 0x61, 0x18, 0xc4,
+ 0x7b, 0x1b, 0xf3, 0x30, 0x0f, 0x3e, 0xed, 0x56,
+ 0x6b, 0xb0, 0xea, 0xf2, 0xd9, 0x94, 0x29, 0x5b,
+ 0x85, 0xbb, 0xc9, 0x1b, 0xd2, 0x67, 0xcf, 0xfa,
+ 0xe5, 0x4a, 0x72, 0x6a, 0xf3, 0xbc, 0xac, 0x2a,
+ 0x7b, 0xc9, 0xc2, 0x74, 0xef, 0x6d, 0x87, 0x4e,
+ 0x5d, 0xee, 0xa5, 0x11, 0xe2, 0x73, 0x61, 0xbb,
+ 0x8f, 0xcf, 0xeb, 0x78, 0x3b, 0x0a, 0xd0, 0x74,
+ 0x52, 0x88, 0x46, 0x94, 0x26, 0x02, 0x9d, 0x3f,
+ 0x0f, 0x7f, 0x7a, 0x80, 0xe9, 0xb8, 0x4e, 0x97,
+ 0x8e, 0x42, 0xd2, 0x48, 0x74, 0x98, 0x74, 0xec,
+ 0xdc, 0x77, 0x91, 0x26, 0x22, 0xb6, 0x41, 0xe1,
+ 0xed, 0xe1, 0xf3, 0xff, 0xed, 0x57, 0x47, 0x08,
+ 0xf0, 0x15, 0xc1, 0x08, 0x4e, 0x87, 0xb3, 0x66,
+ 0xf6, 0x85, 0x02, 0x16, 0x7a, 0x14, 0x2d, 0x12,
+ 0x75, 0x2a, 0x7f, 0xf0, 0xb8, 0xba, 0xf4, 0xfe,
+ 0x5f, 0xdf, 0xbf, 0xae, 0x1d, 0x3f, 0x3f, 0xfe,
+ 0x7d, 0xb0, 0xe9, 0xf5, 0x1e, 0x15, 0x79, 0xd0,
+ 0x27, 0xa9, 0xf2, 0xd9, 0xff, 0x59, 0x44, 0x1f,
+ 0xc0, 0xf0, 0x0e, 0x9d, 0x98, 0xd1, 0xd2, 0xcb,
+ 0x1e, 0xb8, 0x0f, 0x27, 0x98, 0xb9, 0x41, 0xd3,
+ 0xec, 0x6d, 0xf5, 0xa4, 0xe8, 0xf1, 0xe5, 0x54,
+ 0x86, 0x79, 0x7f, 0x74, 0x3a, 0x4b, 0x89, 0x95,
+ 0xfd, 0xe2, 0xee, 0x3b, 0x84, 0x53, 0xda, 0xf0,
+ 0xbc, 0xe9, 0xe5, 0xd5, 0xbb, 0xa9, 0x53, 0xe7,
+ 0xb8, 0x21, 0x09, 0xd1, 0xf3, 0xcf, 0xd4, 0x9e,
+ 0x36, 0x44, 0x9e, 0x38, 0x43, 0x15, 0x56, 0x02,
+ 0x3b, 0x1d, 0x61, 0xb1, 0x3f, 0x0e, 0xa0, 0xcf,
+ 0xa1, 0xd3, 0xfd, 0x47, 0xf1, 0xf6, 0xc0, 0x54,
+ 0xe9, 0xed, 0xb6, 0x56, 0xc7, 0x4f, 0xff, 0x96,
+ 0xca, 0xc4, 0x5b, 0xe0, 0xa7, 0x72, 0x1a, 0x2f,
+ 0x89, 0xfc, 0x1e, 0xbd, 0x57, 0x28, 0x3a, 0x7f,
+ 0xfe, 0xcb, 0xef, 0x7a, 0xb6, 0xf7, 0xc0, 0x3e,
+ 0x56, 0x61, 0x53, 0x5f, 0x0e, 0x9f, 0x0f, 0xa8,
+ 0xe6, 0x1a, 0x61, 0x39, 0xeb, 0xea, 0xbc, 0x69,
+ 0x84, 0xe6, 0x02, 0x9a, 0x81, 0x39, 0xfd, 0xfe,
+ 0xd3, 0x75, 0x10, 0x1a, 0x81, 0x39, 0xfd, 0x5c,
+ 0xb7, 0xab, 0xad, 0x06, 0x98, 0x4e, 0x6c, 0xd8,
+ 0xd3, 0x09, 0xcc, 0x10, 0x9e, 0x61, 0x38, 0xc4,
+ 0xd3, 0x29, 0x34, 0xf1, 0x73, 0x08, 0xaa, 0x80,
+ 0xd9, 0x08, 0x24, 0x72, 0xb9, 0x66, 0x13, 0x38,
+ 0xf9, 0xe5, 0xea, 0x53, 0xf7, 0x0c, 0x79, 0x11,
+ 0x55, 0x50, 0xb7, 0x94, 0xa9, 0x0a, 0xae, 0x73,
+ 0x63, 0x94, 0x25, 0xb2, 0xdd, 0xe5, 0x5b, 0xcf,
+ 0xb6, 0xc1, 0xf6, 0x93, 0xa7, 0xdf, 0xcd, 0xf8,
+ 0xd1, 0xd3, 0xfd, 0x6e, 0x65, 0xbc, 0xb4, 0xbc,
+ 0xe9, 0xfb, 0x7f, 0xdf, 0xb9, 0xd4, 0x1d, 0x1e,
+ 0x3e, 0xc0, 0x1c, 0xc7, 0xd1, 0x6f, 0x78, 0x4a,
+ 0xc2, 0xae, 0x91, 0x64, 0xbc, 0x8f, 0x29, 0x74,
+ 0x38, 0x27, 0xff, 0x32, 0xf5, 0xf7, 0xe9, 0x7d,
+ 0xfd, 0x5f, 0x1d, 0x3f, 0xff, 0xbf, 0x94, 0xe5,
+ 0x7b, 0xf6, 0xf2, 0xde, 0xda, 0xf3, 0x0e, 0x9f,
+ 0xbf, 0xab, 0x3d, 0x65, 0x3a, 0x7f, 0xfd, 0xdf,
+ 0xbf, 0x75, 0xbe, 0xb7, 0xa8, 0x72, 0xc7, 0x4e,
+ 0x1a, 0xd4, 0xf1, 0x01, 0xcf, 0xff, 0x6f, 0x15,
+ 0xb2, 0xe8, 0xc1, 0x4e, 0xe4, 0x34, 0x40, 0x6e,
+ 0x35, 0x10, 0x04, 0x72, 0xdd, 0xee, 0x31, 0x33,
+ 0x6f, 0x46, 0x27, 0x3f, 0xff, 0xb9, 0xf9, 0x5f,
+ 0x08, 0xf9, 0x9b, 0xef, 0x6c, 0x0d, 0xce, 0x9f,
+ 0xff, 0xee, 0x7e, 0x7d, 0xa7, 0xe5, 0x2f, 0xde,
+ 0xa0, 0x70, 0x42, 0x12, 0xa2, 0xc8, 0xcb, 0xfb,
+ 0x0c, 0xfe, 0x5c, 0x14, 0xee, 0x43, 0x44, 0x13,
+ 0x3f, 0xcb, 0x7c, 0x14, 0xee, 0x43, 0x45, 0xf3,
+ 0x3e, 0xf3, 0x6f, 0xe5, 0x76, 0x3f, 0xa4, 0x3a,
+ 0x9f, 0xf5, 0x1d, 0x4e, 0xe6, 0x5f, 0xfc, 0xd8,
+ 0xe9, 0xc1, 0x08, 0x4a, 0x9f, 0xaf, 0x6c, 0x4e,
+ 0x12, 0x9c, 0x5e, 0x45, 0x08, 0x99, 0xfb, 0x04,
+ 0xff, 0xd4, 0x31, 0x69, 0xaf, 0xf2, 0x8d, 0xef,
+ 0x3a, 0x7f, 0xfb, 0x7d, 0x3f, 0xd0, 0x96, 0xf0,
+ 0x00, 0xa2, 0xf3, 0xa7, 0x04, 0x21, 0x2a, 0x7f,
+ 0x6f, 0x02, 0xff, 0x29, 0xb9, 0x4e, 0x2f, 0x27,
+ 0xff, 0xe6, 0xef, 0x42, 0x5b, 0xdb, 0x6d, 0x81,
+ 0xd1, 0x7a, 0xe5, 0x07, 0x4b, 0xac, 0x8a, 0xbd,
+ 0x51, 0x21, 0xea, 0xa2, 0xfd, 0x0d, 0xa1, 0x24,
+ 0x62, 0x4d, 0xe3, 0x1b, 0x9f, 0x5b, 0x2e, 0xd3,
+ 0xce, 0x9f, 0xf6, 0x5d, 0x46, 0xb6, 0x5f, 0xdc,
+ 0xf1, 0x04, 0x4f, 0xe5, 0xc1, 0x4e, 0xe4, 0x34,
+ 0x41, 0x0e, 0x3c, 0x99, 0xfb, 0xac, 0x23, 0xe0,
+ 0x9d, 0x3f, 0x6e, 0xf6, 0x0f, 0x7d, 0xe7, 0x47,
+ 0xcf, 0x77, 0x52, 0xb8, 0xb2, 0x67, 0x80, 0x71,
+ 0xfc, 0x2a, 0x27, 0xf9, 0x7f, 0x7d, 0xf9, 0x6e,
+ 0xa4, 0xe9, 0xff, 0xee, 0x0d, 0xf2, 0xcb, 0xeb,
+ 0xff, 0x2d, 0xe3, 0xa1, 0xe8, 0x88, 0xf9, 0xd4,
+ 0xfe, 0xbe, 0xf6, 0x54, 0x3d, 0x49, 0xd3, 0xde,
+ 0x6b, 0xc1, 0x3a, 0x7f, 0xfd, 0xad, 0x1f, 0x5c,
+ 0xb3, 0x96, 0xf9, 0x6d, 0x44, 0xe9, 0xf6, 0x5e,
+ 0xbb, 0xeb, 0xb1, 0xfc, 0xef, 0x23, 0x9f, 0x92,
+ 0xde, 0xdc, 0xf6, 0x93, 0xa7, 0xe6, 0x2e, 0xee,
+ 0xd9, 0x41, 0xd3, 0xff, 0xff, 0xde, 0xbf, 0x33,
+ 0xbe, 0x07, 0xfa, 0xba, 0xb2, 0xde, 0x5b, 0xdb,
+ 0x5e, 0x61, 0xd1, 0xb2, 0x38, 0xfc, 0x65, 0xc6,
+ 0x33, 0x87, 0x7d, 0x4e, 0x9f, 0xf7, 0x7d, 0x30,
+ 0x53, 0xb9, 0x0d, 0x10, 0x8c, 0x29, 0xf1, 0x6a,
+ 0x3b, 0x3f, 0xf9, 0x72, 0x9d, 0xf7, 0xf7, 0xf5,
+ 0x7e, 0x54, 0xe9, 0xff, 0xee, 0xea, 0x37, 0xe5,
+ 0xb9, 0x8e, 0x08, 0x42, 0x74, 0xb3, 0x64, 0x4f,
+ 0x34, 0x9b, 0x38, 0x21, 0x09, 0x53, 0xfd, 0x80,
+ 0xe1, 0xc6, 0xd9, 0xb1, 0x4e, 0x2f, 0x26, 0x08,
+ 0x4a, 0x9c, 0x10, 0x84, 0xa9, 0xfb, 0xa8, 0xda,
+ 0xcb, 0x52, 0x9c, 0x5e, 0x47, 0xd1, 0x6c, 0x14,
+ 0x7d, 0xc3, 0x29, 0xf2, 0x7b, 0x6d, 0xec, 0x29,
+ 0xc6, 0xce, 0x70, 0x42, 0x12, 0xa7, 0x55, 0x44,
+ 0xa7, 0x17, 0x92, 0x07, 0x8f, 0xfe, 0xea, 0xd3,
+ 0xf6, 0xdf, 0x57, 0xf2, 0x1d, 0x3f, 0xb7, 0x8e,
+ 0xde, 0x6c, 0xbb, 0x1d, 0x3f, 0xaf, 0x6c, 0x6d,
+ 0x97, 0xa9, 0xd0, 0x28, 0x98, 0xb1, 0x67, 0xce,
+ 0x21, 0x51, 0xdf, 0x90, 0xc0, 0x9d, 0x4e, 0xeb,
+ 0x9b, 0xa9, 0xd3, 0xff, 0xb3, 0x77, 0xdf, 0x06,
+ 0x22, 0xd9, 0x58, 0x74, 0xfc, 0x9e, 0xad, 0xbc,
+ 0xd1, 0x53, 0xfb, 0xf9, 0x4b, 0xeb, 0xed, 0x27,
+ 0x4f, 0x77, 0x0e, 0x93, 0xa3, 0x41, 0xeb, 0xd0,
+ 0x6d, 0x3c, 0xbc, 0xc6, 0xc5, 0x4e, 0x08, 0x42,
+ 0x54, 0xff, 0xf6, 0xf5, 0x06, 0x67, 0xef, 0x6f,
+ 0x2f, 0xe8, 0x29, 0xc5, 0xe4, 0xb1, 0x11, 0x3c,
+ 0xc3, 0xe8, 0x54, 0xf9, 0x1e, 0x57, 0x4a, 0x57,
+ 0xa1, 0x0b, 0x68, 0x61, 0xcf, 0xff, 0x99, 0x88,
+ 0xbf, 0xeb, 0xd7, 0x6d, 0x78, 0x5e, 0x74, 0xf9,
+ 0x6f, 0x56, 0xd8, 0x74, 0x29, 0xfe, 0x5d, 0x52,
+ 0x7f, 0xfb, 0xcd, 0xb3, 0xfb, 0x7f, 0x83, 0x9f,
+ 0xed, 0x27, 0x4f, 0xff, 0xf6, 0xd6, 0xf0, 0x71,
+ 0xbf, 0xcc, 0xeb, 0xd7, 0x57, 0xe5, 0x37, 0x3a,
+ 0x31, 0x18, 0x1c, 0xa7, 0x0a, 0xd9, 0x0a, 0xd0,
+ 0x9a, 0xf8, 0xe5, 0xf6, 0x87, 0xa6, 0x4b, 0x28,
+ 0xf4, 0x72, 0x4d, 0x42, 0xf8, 0x48, 0xd9, 0x0a,
+ 0xfb, 0x46, 0x4e, 0x08, 0x49, 0x7e, 0x18, 0x15,
+ 0x95, 0x3b, 0x79, 0x41, 0x5a, 0xc3, 0x44, 0x30,
+ 0xe1, 0x9c, 0xd9, 0x7e, 0x74, 0xff, 0xf6, 0x7d,
+ 0xd7, 0xd3, 0xea, 0x6b, 0x6c, 0x07, 0x1d, 0x2a,
+ 0x5e, 0x7d, 0xfb, 0x0e, 0xcf, 0xd6, 0x6b, 0xd6,
+ 0xf3, 0x0e, 0x9f, 0xf7, 0xd6, 0xf6, 0xe0, 0x75,
+ 0x35, 0x3a, 0x73, 0x5a, 0x89, 0xd3, 0xfe, 0xef,
+ 0x0e, 0x52, 0xe0, 0x84, 0x27, 0x47, 0x1e, 0xdd,
+ 0x47, 0x67, 0xff, 0xbe, 0xaf, 0xd1, 0xbe, 0xfe,
+ 0xfe, 0xaf, 0xca, 0x9d, 0x18, 0x99, 0xf2, 0x17,
+ 0xda, 0x13, 0x20, 0x21, 0x9f, 0xcb, 0xf7, 0xff,
+ 0x30, 0x07, 0x4f, 0xe7, 0xe0, 0xd7, 0xeb, 0x41,
+ 0xd3, 0xff, 0xca, 0xd9, 0x45, 0xdb, 0xef, 0xfc,
+ 0xa3, 0xc2, 0x7b, 0xbd, 0xe7, 0xff, 0xb2, 0xeb,
+ 0xf4, 0xcb, 0xdb, 0xc2, 0x04, 0x3a, 0x7d, 0xd5,
+ 0xcf, 0xdc, 0xe9, 0xd7, 0xed, 0xd9, 0xd3, 0xfa,
+ 0xf6, 0xf3, 0x81, 0xde, 0x3a, 0x28, 0x4c, 0x8f,
+ 0x65, 0xff, 0xa6, 0x5c, 0x9b, 0x51, 0xf9, 0xfd,
+ 0xa8, 0x16, 0xde, 0xe7, 0x9d, 0x3f, 0xff, 0x7f,
+ 0x2b, 0xae, 0x8c, 0xb7, 0x7f, 0x1a, 0x7a, 0xd2,
+ 0x74, 0xff, 0xb2, 0xba, 0xe0, 0xa7, 0x72, 0x1a,
+ 0x20, 0x69, 0xf6, 0x5e, 0xdc, 0xfd, 0x08, 0xa5,
+ 0xfa, 0xf4, 0xff, 0xff, 0xfd, 0x97, 0xb7, 0x7f,
+ 0x4e, 0x8a, 0x8f, 0x75, 0xdb, 0x66, 0xda, 0x31,
+ 0x9d, 0xfa, 0x5e, 0x78, 0x82, 0xe7, 0xfd, 0xdd,
+ 0xa5, 0x3b, 0x6d, 0x1a, 0x42, 0x78, 0x82, 0xe7,
+ 0xfe, 0xb7, 0xad, 0xe5, 0xfd, 0xf4, 0x69, 0x09,
+ 0xe2, 0x0b, 0x9f, 0xcb, 0xef, 0xdf, 0x46, 0x90,
+ 0x9e, 0x20, 0xb9, 0xf9, 0x99, 0xb6, 0x8d, 0x21,
+ 0x3c, 0x41, 0x73, 0xff, 0xfd, 0xdf, 0xff, 0x99,
+ 0xa2, 0xa9, 0x6f, 0x0f, 0xb4, 0xd1, 0x81, 0x3c,
+ 0x41, 0x73, 0x53, 0xa3, 0x64, 0xe8, 0x51, 0x40,
+ 0x55, 0xb9, 0x13, 0xe7, 0xf1, 0x65, 0x52, 0xdf,
+ 0x94, 0x7d, 0x3d, 0xc2, 0x0e, 0x3a, 0x7f, 0xeb,
+ 0x7a, 0xde, 0x5f, 0xdf, 0x46, 0x90, 0x9e, 0x20,
+ 0xb9, 0xfe, 0x6a, 0xa9, 0xea, 0x34, 0x69, 0x09,
+ 0xe2, 0x0b, 0x9f, 0x5e, 0xaa, 0xcd, 0x08, 0x8a,
+ 0x2d, 0xea, 0xd3, 0xff, 0xb4, 0x25, 0xbc, 0x8b,
+ 0x7a, 0xe8, 0xd2, 0x13, 0xc4, 0x17, 0x3f, 0xff,
+ 0xf7, 0xff, 0xe6, 0x68, 0xd7, 0x34, 0x55, 0x2d,
+ 0xe1, 0xf6, 0x9a, 0x30, 0x27, 0x88, 0x2e, 0x31,
+ 0x32, 0x6a, 0x50, 0xf9, 0x72, 0x7f, 0xad, 0xe1,
+ 0xf6, 0x9a, 0x30, 0x27, 0x88, 0x2e, 0x7f, 0xfb,
+ 0xba, 0x97, 0xd6, 0xde, 0xdb, 0x65, 0x15, 0x2a,
+ 0x7f, 0xd8, 0xf7, 0xeb, 0x51, 0xfd, 0x1b, 0x87,
+ 0x88, 0x2e, 0x11, 0x1d, 0x02, 0x91, 0x55, 0x09,
+ 0xff, 0x27, 0x86, 0xfc, 0x0a, 0xe8, 0x09, 0xe2,
+ 0x0b, 0x9f, 0xad, 0xeb, 0x5b, 0xc0, 0x34, 0x01,
+ 0x73, 0xec, 0x06, 0x8d, 0x21, 0x3c, 0x41, 0x73,
+ 0x65, 0xd0, 0xfc, 0xec, 0x77, 0x14, 0xa3, 0xae,
+ 0xb0, 0xbf, 0x9f, 0x99, 0x9b, 0x68, 0xd2, 0x13,
+ 0xc4, 0x17, 0x3f, 0xe4, 0xb7, 0x87, 0xda, 0x68,
+ 0xc0, 0x9e, 0x20, 0xb9, 0xb3, 0x47, 0x22, 0x32,
+ 0xa7, 0xf3, 0xfb, 0x5f, 0x33, 0xbf, 0x4b, 0xcf,
+ 0x10, 0x5c, 0xff, 0xb3, 0xcd, 0xb3, 0xf9, 0xb7,
+ 0x3c, 0xf1, 0x05, 0xb0, 0xf0, 0xa3, 0x65, 0xdc,
+ 0x70, 0x16, 0x7e, 0x3e, 0x7a, 0xc6, 0x31, 0x78,
+ 0xc6, 0x75, 0x85, 0xa8, 0x5c, 0x67, 0xc0, 0xa8,
+ 0x00, 0xa6, 0x88, 0x2d, 0xc8, 0x80, 0x9f, 0xf6,
+ 0x3e, 0xdc, 0xf6, 0xf6, 0xfd, 0x68, 0x3a, 0x7f,
+ 0x0f, 0xf3, 0x6b, 0x6a, 0x13, 0xa7, 0xd4, 0xdf,
+ 0x84, 0x07, 0x4f, 0xd9, 0x47, 0x59, 0x77, 0x67,
+ 0x47, 0x91, 0x17, 0xc6, 0x9f, 0x27, 0x9d, 0xc3,
+ 0x41, 0xd3, 0x01, 0x4e, 0x9e, 0xf2, 0xb3, 0x0e,
+ 0x83, 0xa7, 0xee, 0xd3, 0x75, 0x10, 0x1d, 0x1b,
+ 0x1b, 0x7f, 0x85, 0x4f, 0xff, 0xe5, 0xf6, 0xdf,
+ 0x5d, 0x52, 0xf8, 0x9b, 0x2a, 0x6f, 0x61, 0xd3,
+ 0x01, 0x4e, 0x99, 0x74, 0x9d, 0x3f, 0xd9, 0x7a,
+ 0xab, 0x37, 0xe3, 0x47, 0x4f, 0xea, 0xe5, 0xbd,
+ 0x5d, 0x68, 0x3a, 0x60, 0x84, 0xa9, 0xfe, 0xfe,
+ 0x36, 0xe7, 0xd7, 0xdb, 0x1d, 0x08, 0x9f, 0xbf,
+ 0x86, 0xc4, 0x55, 0x8a, 0xf6, 0x22, 0x03, 0x13,
+ 0x76, 0x2b, 0xf1, 0x7a, 0x9d, 0x04, 0xd7, 0x78,
+ 0xb4, 0xe0, 0x84, 0x25, 0x49, 0x85, 0x38, 0xbc,
+ 0x9f, 0x73, 0x5d, 0xc2, 0x53, 0x91, 0xb3, 0xbe,
+ 0x17, 0x53, 0xfa, 0x9b, 0xae, 0x5b, 0x28, 0x3a,
+ 0x15, 0xb2, 0x07, 0xc8, 0xda, 0x34, 0xa0, 0xd2,
+ 0x63, 0xe8, 0xd5, 0x45, 0x3a, 0xd0, 0xd8, 0xea,
+ 0x48, 0xf7, 0xd1, 0xab, 0x0d, 0x1d, 0x65, 0x7f,
+ 0xb6, 0x4b, 0x9e, 0xc4, 0x5b, 0x9d, 0x3d, 0x8c,
+ 0xcb, 0x9d, 0x3d, 0xd4, 0x6f, 0x79, 0xd0, 0xa7,
+ 0xc7, 0x48, 0xfb, 0x79, 0x04, 0xfd, 0xfd, 0x76,
+ 0x67, 0x3c, 0xe9, 0xff, 0xea, 0x5f, 0xf5, 0xd0,
+ 0xcf, 0xae, 0x9b, 0xfa, 0x83, 0xa7, 0xf5, 0x6e,
+ 0xdb, 0x3f, 0x9b, 0x1d, 0x0a, 0x8b, 0xaf, 0x17,
+ 0xf2, 0xb4, 0xee, 0xd1, 0xbc, 0xe9, 0xff, 0xef,
+ 0xbf, 0x46, 0x6d, 0xea, 0xd3, 0x7d, 0x7a, 0xa7,
+ 0x46, 0x83, 0xf4, 0xc1, 0xf9, 0xfa, 0x86, 0x9e,
+ 0xdc, 0x1a, 0x0e, 0x99, 0xf4, 0x1d, 0x3e, 0xb6,
+ 0x79, 0xf5, 0x3a, 0x7f, 0xfa, 0xcb, 0xbd, 0xd7,
+ 0xff, 0x02, 0xb5, 0x50, 0x15, 0x3f, 0x81, 0x82,
+ 0x9d, 0xc8, 0x78, 0x81, 0x21, 0xe8, 0xb3, 0xd8,
+ 0x9c, 0x54, 0x66, 0x6f, 0x79, 0xd3, 0xd7, 0xa3,
+ 0xbe, 0x74, 0xf5, 0x35, 0xeb, 0x9d, 0x14, 0x1e,
+ 0xee, 0x0c, 0xd8, 0x8a, 0x7f, 0x7f, 0x83, 0x5a,
+ 0xa8, 0x0e, 0x9c, 0x10, 0x84, 0xf8, 0x7d, 0x4e,
+ 0xef, 0xec, 0x5c, 0x3e, 0x8e, 0x35, 0x31, 0xb2,
+ 0x25, 0x40, 0xb7, 0x3f, 0xfe, 0xcf, 0xfb, 0x4b,
+ 0xab, 0x7b, 0x6b, 0xcf, 0x7a, 0x9d, 0x14, 0x1f,
+ 0xe6, 0x92, 0x48, 0xdd, 0x4a, 0xbc, 0x1e, 0x69,
+ 0x90, 0xca, 0xf4, 0x23, 0x7a, 0x34, 0x09, 0xf7,
+ 0xae, 0xb7, 0xa9, 0x53, 0xc8, 0xb7, 0xa9, 0x53,
+ 0x04, 0x25, 0x43, 0xcf, 0x77, 0x09, 0xc2, 0x41,
+ 0x36, 0x04, 0xa7, 0x1a, 0xe9, 0xff, 0xf6, 0x5d,
+ 0x53, 0x33, 0xf7, 0xb7, 0x97, 0xf4, 0x1d, 0x00,
+ 0x3f, 0x80, 0x92, 0xcf, 0xff, 0xe5, 0x6d, 0xef,
+ 0x83, 0x45, 0xeb, 0x89, 0x6e, 0xfd, 0xea, 0x74,
+ 0xfe, 0x6a, 0x97, 0xdb, 0x55, 0x13, 0xa7, 0x3f,
+ 0x84, 0xe9, 0xf3, 0xf2, 0xf9, 0xb1, 0x52, 0xf3,
+ 0x47, 0x83, 0x71, 0xa9, 0x80, 0xa7, 0x4c, 0x05,
+ 0x3a, 0x7e, 0xfe, 0xaf, 0xcf, 0xbb, 0xc6, 0xa8,
+ 0x02, 0xb3, 0xff, 0x5e, 0xd8, 0xcd, 0xea, 0x0c,
+ 0xa6, 0xe7, 0x4f, 0xea, 0x53, 0xc3, 0xbd, 0x76,
+ 0x3a, 0x78, 0x0c, 0xe7, 0xd4, 0xfe, 0xee, 0x8d,
+ 0x3b, 0x73, 0x29, 0x3a, 0x14, 0xf6, 0x38, 0xe6,
+ 0x7a, 0xba, 0xd3, 0x73, 0xa7, 0x04, 0x21, 0x2a,
+ 0x7d, 0x9a, 0x7f, 0xad, 0x4a, 0x71, 0x79, 0x3e,
+ 0xc7, 0x04, 0x21, 0x3a, 0x14, 0xf8, 0x2e, 0x73,
+ 0x3c, 0x1e, 0xfb, 0xce, 0x99, 0x2c, 0x74, 0xe0,
+ 0x84, 0x25, 0x4f, 0xde, 0xed, 0x36, 0xf5, 0xca,
+ 0x71, 0x79, 0x3e, 0xc0, 0x66, 0x34, 0x74, 0xab,
+ 0xa1, 0x12, 0xa2, 0x63, 0xf3, 0xe9, 0xef, 0x7f,
+ 0x57, 0xec, 0x8e, 0xdc, 0x85, 0xb4, 0x2a, 0xe3,
+ 0xb3, 0xc8, 0xb1, 0x93, 0x4b, 0xb0, 0xa9, 0xda,
+ 0x31, 0x8e, 0x20, 0xac, 0x28, 0x2f, 0x18, 0x74,
+ 0xfc, 0xac, 0x11, 0xeb, 0x9d, 0x3f, 0xfd, 0xe6,
+ 0x52, 0xfa, 0xe8, 0xcf, 0xff, 0x3c, 0x03, 0xa2,
+ 0xc7, 0xfb, 0x72, 0xa9, 0x39, 0xba, 0x42, 0x19,
+ 0xe5, 0x65, 0x76, 0xd1, 0x19, 0x1b, 0xe5, 0x26,
+ 0xed, 0x2c, 0x07, 0x2b, 0x74, 0xad, 0x31, 0xb8,
+ 0xa4, 0x76, 0x54, 0xca, 0xa7, 0xf4, 0x27, 0x5a,
+ 0x9e, 0x7f, 0x19, 0xd3, 0x56, 0x4a, 0x0b, 0xb4,
+ 0xf8, 0x57, 0x53, 0xcb, 0x41, 0x2c, 0xe7, 0xf3,
+ 0xac, 0x15, 0xac, 0x97, 0xaf, 0x59, 0xcf, 0xeb,
+ 0x19, 0xab, 0x68, 0x76, 0x06, 0x14, 0x5b, 0x92,
+ 0xc4, 0xf7, 0xce, 0xec, 0xb7, 0xc6, 0x1b, 0x0e,
+ 0x84, 0x47, 0x03, 0xf1, 0x0d, 0x8b, 0x3f, 0x9d,
+ 0x82, 0x9d, 0xc8, 0x68, 0xb8, 0xe7, 0xf3, 0xb0,
+ 0x53, 0xb9, 0x0d, 0x17, 0x5c, 0xff, 0xce, 0xe7,
+ 0xbb, 0x05, 0x3b, 0x90, 0xd1, 0x28, 0xc2, 0xc2,
+ 0x30, 0xd5, 0xe5, 0x1b, 0x1d, 0xe9, 0x3b, 0x43,
+ 0xbf, 0x43, 0xc3, 0x76, 0x81, 0xd8, 0x89, 0x32,
+ 0xa9, 0xc5, 0xce, 0xdb, 0xce, 0xe7, 0xff, 0x39,
+ 0x9c, 0xf7, 0x60, 0xa7, 0x72, 0x1a, 0x25, 0xa9,
+ 0xf0, 0xa7, 0x72, 0x1a, 0x23, 0x79, 0xff, 0x73,
+ 0xdd, 0x82, 0x9d, 0xc8, 0x68, 0x97, 0xe4, 0xec,
+ 0x3f, 0x66, 0x18, 0x4f, 0xe7, 0x60, 0xa7, 0x72,
+ 0x1a, 0x2a, 0xb9, 0xfe, 0xd3, 0x9f, 0xca, 0x6f,
+ 0xcc, 0x3a, 0x6d, 0xbc, 0x74, 0xfd, 0x82, 0x9d,
+ 0xc8, 0x68, 0x90, 0x23, 0x41, 0xe6, 0x38, 0x5e,
+ 0x7d, 0x5e, 0xff, 0x52, 0x74, 0x3c, 0xf2, 0xe9,
+ 0x24, 0x8d, 0x28, 0xf4, 0xe8, 0x68, 0xcf, 0xfd,
+ 0xfc, 0xa1, 0xdb, 0x8b, 0xff, 0xe5, 0xce, 0x87,
+ 0x1f, 0x80, 0x94, 0xcf, 0xe7, 0x60, 0xa7, 0x72,
+ 0x1a, 0x2c, 0x89, 0xfc, 0xec, 0x14, 0xee, 0x43,
+ 0x45, 0xaf, 0x3f, 0x9d, 0x82, 0x9d, 0xc8, 0x68,
+ 0xb9, 0x27, 0xc2, 0x9d, 0xc8, 0x68, 0xbb, 0x27,
+ 0xfd, 0xcf, 0x76, 0x0a, 0x77, 0x21, 0xa2, 0x8e,
+ 0x93, 0xb0, 0xfd, 0x98, 0x61, 0x3e, 0x14, 0xee,
+ 0x43, 0x45, 0x2b, 0x3f, 0xff, 0xfd, 0x65, 0xa1,
+ 0x6d, 0xe6, 0xdd, 0xb5, 0xbc, 0xe4, 0xb7, 0x9a,
+ 0xb2, 0xd1, 0x87, 0x4f, 0x9c, 0xce, 0x7b, 0xb1,
+ 0x16, 0x4d, 0x18, 0x45, 0x0b, 0x9d, 0xef, 0x86,
+ 0x45, 0x24, 0xfe, 0x8e, 0x7d, 0x84, 0x20, 0x3b,
+ 0xa9, 0xdd, 0xe1, 0x62, 0xda, 0x1b, 0x33, 0xfc,
+ 0xf7, 0x60, 0xa7, 0x72, 0x1a, 0x23, 0x89, 0xfe,
+ 0xf3, 0xb0, 0x53, 0xb9, 0x0d, 0x15, 0xac, 0x9d,
+ 0xc8, 0x82, 0xba, 0x0c, 0xff, 0xe7, 0x33, 0x9e,
+ 0xec, 0x14, 0xee, 0x43, 0x44, 0xb7, 0x36, 0x52,
+ 0x74, 0xfe, 0xdb, 0x18, 0xc5, 0xf5, 0x4e, 0x8a,
+ 0x4f, 0x27, 0xc2, 0xd3, 0xad, 0xb3, 0xce, 0x9c,
+ 0xf6, 0x21, 0xd3, 0xff, 0xf5, 0xba, 0x90, 0x6d,
+ 0x6e, 0x7e, 0x57, 0xfa, 0xf6, 0xf3, 0xa0, 0xd1,
+ 0x0d, 0xcf, 0xfb, 0x9e, 0xec, 0x14, 0xee, 0x43,
+ 0x44, 0xc1, 0x38, 0x75, 0x01, 0x53, 0xfb, 0xf9,
+ 0x7b, 0xa8, 0xd4, 0xe9, 0x39, 0x53, 0x64, 0xa0,
+ 0x8f, 0x61, 0xdc, 0x1b, 0x45, 0xf6, 0x0b, 0xdd,
+ 0x1b, 0x78, 0xe4, 0xe6, 0x6a, 0x25, 0x4f, 0xfb,
+ 0x9e, 0xec, 0x14, 0xee, 0x43, 0x44, 0xc7, 0x27,
+ 0x78, 0xf8, 0x98, 0x39, 0x3f, 0x2d, 0x74, 0x5f,
+ 0x2c, 0x74, 0xff, 0xff, 0xf3, 0xeb, 0x6c, 0xd4,
+ 0x35, 0xb6, 0x26, 0x57, 0x46, 0x52, 0xfa, 0xfb,
+ 0xfe, 0x3a, 0x79, 0x3b, 0x90, 0xd1, 0x58, 0xcf,
+ 0xfb, 0x73, 0x2f, 0xfc, 0xd5, 0x7f, 0x73, 0xa3,
+ 0x4a, 0x63, 0x74, 0x97, 0x0c, 0x20, 0x6e, 0x57,
+ 0x3f, 0xf9, 0x7f, 0x7d, 0x3a, 0xaf, 0xf1, 0x14,
+ 0x4e, 0x9f, 0xf6, 0x6d, 0x6c, 0xad, 0x2f, 0x5b,
+ 0x1d, 0x3f, 0xec, 0xd8, 0x7d, 0xad, 0x00, 0xab,
+ 0xce, 0x9f, 0xff, 0xfb, 0xfa, 0xd1, 0x89, 0xa3,
+ 0xfa, 0xb7, 0xe8, 0xca, 0x5f, 0x9a, 0xfc, 0x15,
+ 0x3a, 0x7f, 0x6e, 0xaa, 0x1a, 0x7b, 0x70, 0x68,
+ 0x3a, 0x75, 0xbc, 0xec, 0x4f, 0x31, 0x11, 0x6c,
+ 0x93, 0xf3, 0xfb, 0xa0, 0xee, 0x3f, 0x4d, 0xab,
+ 0x47, 0x4f, 0xbb, 0xf4, 0x6b, 0x53, 0xa3, 0xe7,
+ 0x83, 0x51, 0x89, 0xe5, 0x1e, 0xf9, 0xd3, 0xd5,
+ 0xaa, 0x80, 0xe8, 0xb1, 0xe0, 0x04, 0x7e, 0x7c,
+ 0xaf, 0x06, 0xaf, 0x3a, 0x72, 0xfd, 0xe7, 0x43,
+ 0x47, 0x87, 0x72, 0x89, 0xf9, 0x59, 0x9f, 0xf6,
+ 0x93, 0xa5, 0x53, 0xa3, 0xc6, 0xfb, 0x8b, 0xa6,
+ 0x02, 0x95, 0x30, 0x42, 0x54, 0x78, 0xd5, 0x84,
+ 0x56, 0x7f, 0x73, 0xff, 0x97, 0xb7, 0x8a, 0x71,
+ 0xa1, 0x9e, 0xdb, 0xa9, 0xa9, 0xd3, 0x97, 0xed,
+ 0x1d, 0x37, 0xd4, 0xe8, 0x68, 0xd8, 0x88, 0xe4,
+ 0xf0, 0x83, 0x1b, 0xce, 0x9d, 0xbc, 0x74, 0x9d,
+ 0x0a, 0x8b, 0x7c, 0x54, 0xf1, 0x0d, 0x88, 0xe6,
+ 0xb5, 0xce, 0x9c, 0x10, 0x84, 0xa9, 0xff, 0xb1,
+ 0x36, 0x5a, 0x37, 0xe5, 0xba, 0x92, 0x9c, 0x5e,
+ 0x4f, 0x78, 0x5b, 0xf6, 0x3a, 0x42, 0x74, 0xf9,
+ 0x9e, 0xb8, 0x38, 0xe8, 0xa0, 0xf6, 0xf7, 0x64,
+ 0xba, 0x87, 0xcf, 0xe4, 0xf5, 0x7f, 0x8d, 0xb8,
+ 0xe9, 0xb2, 0xe7, 0x45, 0x27, 0x91, 0x63, 0x39,
+ 0xeb, 0xff, 0x1e, 0x74, 0xff, 0xef, 0x56, 0xd9,
+ 0xb7, 0xf1, 0xb7, 0xf2, 0xa7, 0x40, 0x9f, 0x6d,
+ 0xc8, 0x64, 0xe5, 0x5c, 0xd8, 0xd9, 0x8b, 0x19,
+ 0x45, 0x85, 0x8d, 0x96, 0x87, 0xcf, 0x1d, 0xfc,
+ 0xca, 0xb0, 0xb0, 0xbb, 0xee, 0xf8, 0x48, 0x4f,
+ 0x85, 0x3b, 0x90, 0xd1, 0x5b, 0xcf, 0xfb, 0x9e,
+ 0xec, 0x14, 0xee, 0x43, 0x44, 0xe1, 0x27, 0x61,
+ 0xfb, 0x30, 0xc2, 0x7c, 0x29, 0xdc, 0x86, 0x8b,
+ 0x46, 0x7b, 0x1a, 0xf6, 0x93, 0xa4, 0xec, 0x3d,
+ 0x4b, 0x18, 0x4f, 0x27, 0x72, 0x1a, 0x2d, 0xa9,
+ 0xfa, 0xca, 0xc5, 0xf6, 0xc7, 0x4c, 0xec, 0x13,
+ 0xd8, 0xb9, 0x5c, 0xfe, 0x76, 0x0a, 0x77, 0x21,
+ 0xa2, 0xe5, 0x9f, 0xce, 0xc1, 0x4e, 0xe4, 0x34,
+ 0x5d, 0xb0, 0xac, 0xe5, 0x6a, 0x0a, 0x1f, 0x1f,
+ 0xfe, 0xd0, 0xdb, 0xd3, 0x2c, 0x3f, 0xd3, 0xb0,
+ 0x9b, 0xb8, 0xc9, 0x6c, 0xf7, 0xf7, 0xfa, 0x96,
+ 0x5c, 0xee, 0x7f, 0x3b, 0x05, 0x3b, 0x90, 0xd1,
+ 0x53, 0xcf, 0x27, 0x72, 0x1a, 0x2b, 0x99, 0xfc,
+ 0xec, 0x14, 0xee, 0x43, 0x45, 0x9d, 0x02, 0x7c,
+ 0xd6, 0x2b, 0x9f, 0x0a, 0x77, 0x21, 0xa2, 0x42,
+ 0x9f, 0xef, 0x53, 0x5b, 0xfd, 0x59, 0x53, 0xa6,
+ 0x7b, 0xb0, 0xfa, 0x80, 0x61, 0x3c, 0xdd, 0x2c,
+ 0xac, 0x3a, 0x7f, 0x65, 0xab, 0x5c, 0x1a, 0x0e,
+ 0x93, 0xb1, 0x31, 0x1e, 0x84, 0x5d, 0x4b, 0x6e,
+ 0x4f, 0x3f, 0xf9, 0xcc, 0xe7, 0xbb, 0x05, 0x3b,
+ 0x90, 0xd1, 0x3e, 0x42, 0x2a, 0x4b, 0xdd, 0xc7,
+ 0x65, 0x64, 0x79, 0xf0, 0xa7, 0x72, 0x1a, 0x2b,
+ 0x29, 0xff, 0x73, 0xdd, 0x82, 0x9d, 0xc8, 0x68,
+ 0x9b, 0xa6, 0xf3, 0xb0, 0xfd, 0x98, 0x61, 0x3e,
+ 0x14, 0xee, 0x43, 0x44, 0xad, 0x3f, 0xda, 0x6d,
+ 0xed, 0x1a, 0xa6, 0x54, 0xe9, 0xf3, 0x99, 0xcf,
+ 0x76, 0x1f, 0x6f, 0x18, 0x4f, 0x85, 0x3b, 0x90,
+ 0xd1, 0x2e, 0x4f, 0xf7, 0xb9, 0xf7, 0xfa, 0xb2,
+ 0xa7, 0x4f, 0x36, 0xf7, 0xd4, 0xe9, 0xf3, 0x99,
+ 0xcf, 0x76, 0x22, 0x2e, 0xc6, 0x1c, 0x71, 0x3f,
+ 0xf3, 0xb9, 0xee, 0xc1, 0x4e, 0xe4, 0x34, 0x47,
+ 0x73, 0xfd, 0x7b, 0x63, 0xdd, 0xdf, 0xa9, 0xd3,
+ 0xf3, 0x73, 0xea, 0x99, 0xf3, 0xa7, 0xed, 0xd3,
+ 0xf9, 0x6e, 0xb9, 0xd3, 0xe1, 0x4e, 0xe4, 0x34,
+ 0x54, 0x33, 0xec, 0xb5, 0xf2, 0x83, 0xa7, 0xff,
+ 0xfb, 0x5e, 0xdd, 0xfa, 0x8b, 0x77, 0xae, 0xb6,
+ 0xf5, 0xeb, 0x9b, 0x1d, 0x27, 0x6e, 0x89, 0x92,
+ 0x37, 0x0b, 0xf0, 0xc6, 0xe6, 0x1b, 0x84, 0xf3,
+ 0xe1, 0x4e, 0xe4, 0x34, 0x55, 0x13, 0xfe, 0xe7,
+ 0xbb, 0x05, 0x3b, 0x90, 0xd1, 0x35, 0xc9, 0xd8,
+ 0x7e, 0xcc, 0x30, 0x9f, 0xce, 0xc1, 0x4e, 0xe4,
+ 0x34, 0x55, 0x93, 0xff, 0x3b, 0x9e, 0xec, 0x14,
+ 0xee, 0x43, 0x44, 0x89, 0x3e, 0x14, 0xee, 0x43,
+ 0x45, 0xa5, 0x3f, 0xee, 0x7b, 0xb0, 0x53, 0xb9,
+ 0x0d, 0x13, 0xec, 0x9d, 0x87, 0xec, 0xc3, 0x09,
+ 0xff, 0xce, 0x67, 0x3d, 0xd8, 0x29, 0xdc, 0x86,
+ 0x8a, 0x12, 0x7d, 0x6f, 0x50, 0xa2, 0x74, 0xf8,
+ 0x53, 0xb9, 0x0d, 0x14, 0x7c, 0xff, 0xfd, 0x9b,
+ 0x59, 0x77, 0xba, 0xff, 0xe0, 0x56, 0xaa, 0x02,
+ 0xa7, 0xce, 0x67, 0x3d, 0xca, 0x8b, 0x4c, 0x27,
+ 0xdc, 0x30, 0x85, 0x5e, 0x2c, 0xa2, 0x19, 0x0f,
+ 0x4b, 0xc4, 0xcd, 0x31, 0xae, 0x24, 0x34, 0xa9,
+ 0x27, 0x68, 0xee, 0xd0, 0xc2, 0x01, 0x3d, 0xe3,
+ 0x06, 0x9f, 0xce, 0xc1, 0x4e, 0xe4, 0x34, 0x44,
+ 0x53, 0xf6, 0x0a, 0x77, 0x21, 0xa2, 0x2b, 0x9f,
+ 0xed, 0xdb, 0xb0, 0x53, 0xb9, 0x0d, 0x15, 0xc4,
+ 0x38, 0xfe, 0xb8, 0xd6, 0x7b, 0x2d, 0xd7, 0x3a,
+ 0x7f, 0x67, 0x84, 0x00, 0xd6, 0xa7, 0x4b, 0x74,
+ 0xf9, 0xe9, 0xd4, 0x82, 0x7f, 0xee, 0xf3, 0xfd,
+ 0xfb, 0xeb, 0x61, 0xc3, 0xa7, 0xd9, 0xed, 0x87,
+ 0x0e, 0x9d, 0x7a, 0xfa, 0xc7, 0xd5, 0x74, 0x49,
+ 0xf0, 0xa7, 0x72, 0x1a, 0x29, 0xe8, 0x6e, 0x23,
+ 0xed, 0x61, 0x2f, 0x86, 0x93, 0xff, 0xb9, 0xee,
+ 0xdb, 0xfc, 0x1a, 0xd5, 0x40, 0x74, 0x39, 0x10,
+ 0x3b, 0x1b, 0xce, 0x76, 0xd8, 0x74, 0xf9, 0x5e,
+ 0x0d, 0x5e, 0x74, 0xf2, 0x77, 0x21, 0xa2, 0xb3,
+ 0x86, 0x8f, 0x4c, 0x4a, 0x27, 0xea, 0x18, 0xbf,
+ 0x7d, 0x4e, 0x9c, 0xb4, 0x78, 0xe9, 0xf5, 0xc1,
+ 0xbf, 0xef, 0x3a, 0x76, 0xbd, 0x53, 0xa7, 0xd8,
+ 0xd5, 0x1a, 0x80, 0xe9, 0x3b, 0x11, 0xb8, 0x24,
+ 0x56, 0x2e, 0xe1, 0xcf, 0x95, 0x6f, 0x1c, 0x9f,
+ 0xf9, 0xdc, 0xf7, 0x60, 0xa7, 0x72, 0x1a, 0x24,
+ 0x59, 0xfc, 0xec, 0x14, 0xee, 0x43, 0x45, 0x93,
+ 0x3f, 0x9d, 0x82, 0x9d, 0xc8, 0x68, 0xb6, 0x27,
+ 0x65, 0x70, 0xe9, 0xf0, 0xa7, 0x72, 0x1a, 0x2d,
+ 0xb9, 0x39, 0xe7, 0x95, 0x83, 0x53, 0xfe, 0x6e,
+ 0x37, 0x37, 0x5a, 0xf6, 0xcf, 0xa8, 0x0e, 0x9f,
+ 0x97, 0xef, 0xdb, 0x56, 0x1d, 0x3e, 0x14, 0xee,
+ 0x43, 0x45, 0xe1, 0x3d, 0x7d, 0xcc, 0xb1, 0xd3,
+ 0xff, 0x2e, 0xf6, 0x52, 0xfb, 0xe7, 0xef, 0x53,
+ 0xa7, 0xd9, 0xf0, 0x37, 0xa9, 0xd3, 0xe5, 0xdf,
+ 0xaf, 0x54, 0xe9, 0xd7, 0x50, 0x1d, 0x27, 0x6e,
+ 0xbc, 0x9c, 0x25, 0x09, 0xb8, 0x5f, 0x49, 0x85,
+ 0x89, 0x00, 0x8f, 0xf2, 0x9b, 0x94, 0xce, 0xf6,
+ 0x52, 0x74, 0xf8, 0x53, 0xb9, 0x0d, 0x17, 0xa4,
+ 0xff, 0xbf, 0xd7, 0x7a, 0xe9, 0xbf, 0xa8, 0x3a,
+ 0x7d, 0x8c, 0xb7, 0x6c, 0x74, 0x9d, 0xb2, 0x2d,
+ 0x30, 0x73, 0x79, 0x83, 0x7a, 0x0c, 0x2b, 0x22,
+ 0x96, 0x88, 0x5a, 0xe4, 0x7e, 0x08, 0x49, 0xe8,
+ 0xd2, 0xc5, 0x71, 0x89, 0x80, 0x3b, 0xfc, 0x21,
+ 0x75, 0x8e, 0xac, 0x31, 0x9b, 0x4f, 0x65, 0xba,
+ 0xe7, 0x4f, 0xec, 0xf0, 0x80, 0x1a, 0xd4, 0xe9,
+ 0x6e, 0x9f, 0x3d, 0x3a, 0x90, 0x4f, 0x85, 0x3b,
+ 0x90, 0xd1, 0x11, 0xcf, 0xff, 0x5b, 0x5a, 0xd7,
+ 0x19, 0xfc, 0x6d, 0xa1, 0x5b, 0xa9, 0xd3, 0xfe,
+ 0x7a, 0xd0, 0x39, 0x7b, 0xfa, 0xe7, 0x4f, 0xff,
+ 0xf2, 0xdb, 0xbd, 0x75, 0xb7, 0xf2, 0xf6, 0xf5,
+ 0xb3, 0xc1, 0x3a, 0x6a, 0x18, 0x54, 0xc1, 0x09,
+ 0x53, 0xff, 0x3d, 0xc9, 0x6f, 0x35, 0x65, 0xa1,
+ 0xc0, 0x35, 0xa1, 0x17, 0x9f, 0xd9, 0xbb, 0xfe,
+ 0x5b, 0xae, 0x74, 0xff, 0xfc, 0x8e, 0x1e, 0xff,
+ 0xae, 0xe1, 0x5b, 0xff, 0x80, 0x74, 0x37, 0x15,
+ 0x38, 0xe1, 0x6a, 0x18, 0x52, 0xb4, 0x27, 0xdd,
+ 0x09, 0x2b, 0xae, 0xb6, 0x35, 0x9f, 0x0a, 0x77,
+ 0x21, 0xa2, 0x2e, 0x9f, 0x5c, 0x1b, 0xfe, 0xf2,
+ 0xd9, 0xec, 0x93, 0xb0, 0xfa, 0x38, 0xc2, 0x1c,
+ 0x98, 0x4b, 0xe1, 0xc7, 0x3f, 0xf3, 0x39, 0xee,
+ 0xc1, 0x4e, 0xe4, 0x34, 0x4c, 0xd3, 0xa9, 0x5a,
+ 0x9d, 0x39, 0x3c, 0xc3, 0xa7, 0x6e, 0xad, 0xcd,
+ 0xd4, 0x74, 0xf9, 0x3a, 0xde, 0x68, 0xe9, 0xff,
+ 0x9b, 0xfd, 0x7f, 0x27, 0xb6, 0xbe, 0x21, 0xd3,
+ 0xff, 0xfd, 0xaf, 0x7d, 0x3f, 0x9b, 0x5b, 0x5d,
+ 0x16, 0x57, 0x8a, 0xd0, 0x74, 0x62, 0x2c, 0x6c,
+ 0x8f, 0x3f, 0xfe, 0xdb, 0xdf, 0xa3, 0x2b, 0xee,
+ 0xb3, 0x82, 0x10, 0x95, 0x3c, 0x9d, 0xc8, 0x68,
+ 0xb3, 0xe7, 0xfd, 0xeb, 0x2b, 0xfd, 0x75, 0xbd,
+ 0x4e, 0x9f, 0xfe, 0xf0, 0xdb, 0xb4, 0x63, 0x6f,
+ 0xe5, 0x73, 0xe7, 0x4e, 0x08, 0x42, 0x54, 0xff,
+ 0xb9, 0xf5, 0xfe, 0x26, 0xd8, 0x25, 0x38, 0xbc,
+ 0x9f, 0xe5, 0xb7, 0xb6, 0xff, 0x73, 0x47, 0x4f,
+ 0xf7, 0xbf, 0xb6, 0xfd, 0xb5, 0xbd, 0x4e, 0x84,
+ 0x4f, 0xc4, 0x56, 0x18, 0x57, 0x63, 0xe0, 0x36,
+ 0xdd, 0x2d, 0xb1, 0xcc, 0xff, 0xff, 0xfd, 0x98,
+ 0x0a, 0xe6, 0x7f, 0x4e, 0xf1, 0xfa, 0xe5, 0x9d,
+ 0x5f, 0xe5, 0x0c, 0xc6, 0x1d, 0x3a, 0xab, 0x41,
+ 0xd3, 0xb7, 0x32, 0xc7, 0x43, 0xd1, 0x89, 0x58,
+ 0x45, 0x5c, 0x72, 0x7a, 0x90, 0x6a, 0x87, 0x4f,
+ 0xad, 0xf5, 0xc1, 0x32, 0x7f, 0xde, 0x17, 0xe0,
+ 0xd1, 0xaf, 0x6c, 0x68, 0x83, 0x5c, 0x69, 0x67,
+ 0xdc, 0x9e, 0x62, 0x9d, 0x3f, 0x3e, 0xdf, 0xea,
+ 0x6e, 0x74, 0xb1, 0x0f, 0x4f, 0xe4, 0xb3, 0xff,
+ 0xfe, 0xe0, 0xdf, 0x2d, 0x75, 0xcf, 0xd3, 0x7c,
+ 0x1f, 0x51, 0xcc, 0x3a, 0x1e, 0x9a, 0x06, 0x42,
+ 0xbf, 0xe4, 0xd3, 0xf0, 0xe6, 0xd5, 0xb2, 0x9d,
+ 0x3f, 0xff, 0xb5, 0xff, 0x69, 0xd1, 0xbf, 0xfd,
+ 0x7a, 0xfa, 0x9b, 0x78, 0x27, 0x4f, 0xff, 0xf5,
+ 0x6a, 0xa3, 0x75, 0x73, 0x32, 0xf5, 0xdf, 0x5e,
+ 0x7e, 0x1d, 0x3d, 0x6c, 0xf3, 0x63, 0xa3, 0xc8,
+ 0x89, 0xb3, 0x34, 0xcc, 0xdd, 0x0d, 0x17, 0xe4,
+ 0xff, 0xcf, 0xbe, 0xaf, 0x7b, 0x2f, 0x75, 0x61,
+ 0xd3, 0xff, 0x7b, 0x3f, 0x99, 0x5d, 0x0f, 0xab,
+ 0x0e, 0x8a, 0x51, 0x17, 0x54, 0x69, 0xef, 0xfd,
+ 0x50, 0xe8, 0x54, 0xc6, 0xb6, 0x23, 0xc8, 0x59,
+ 0xf1, 0x24, 0xff, 0xff, 0xcd, 0xeb, 0x6f, 0x31,
+ 0xcd, 0x3f, 0x87, 0x7d, 0xbd, 0x4d, 0x53, 0xd4,
+ 0x1d, 0x3f, 0xee, 0x7b, 0x39, 0xf7, 0xaa, 0xe9,
+ 0x3a, 0x7b, 0x2b, 0xef, 0x9d, 0x1f, 0x3e, 0x0d,
+ 0x4f, 0xe7, 0xb7, 0xeb, 0xd5, 0x3a, 0x7f, 0xd7,
+ 0xa8, 0x3d, 0x4d, 0x2f, 0xcb, 0x9d, 0x0a, 0x7c,
+ 0xb8, 0x49, 0x33, 0x5a, 0x9d, 0x26, 0x1d, 0x14,
+ 0x9a, 0x86, 0xec, 0x62, 0x7f, 0xff, 0xd6, 0xf5,
+ 0x37, 0xca, 0x6e, 0x22, 0xb7, 0x06, 0xff, 0xbe,
+ 0xd8, 0x74, 0xe0, 0x84, 0x25, 0x4f, 0x6d, 0xb7,
+ 0x7c, 0xa7, 0x17, 0x93, 0xfe, 0xeb, 0x27, 0xbb,
+ 0x45, 0x7a, 0xc7, 0x42, 0xa6, 0x44, 0x84, 0xfe,
+ 0x84, 0x5d, 0x8c, 0xa7, 0xfe, 0xcf, 0xd3, 0x7c,
+ 0x1f, 0x51, 0xcc, 0x3a, 0x7d, 0x97, 0x7b, 0x2c,
+ 0x74, 0x29, 0xf5, 0xd5, 0x12, 0x60, 0x58, 0xe9,
+ 0xfa, 0x86, 0x9e, 0xdc, 0x1a, 0x0e, 0x9f, 0xda,
+ 0x6d, 0x97, 0xb7, 0xae, 0x74, 0xde, 0x13, 0xa3,
+ 0x75, 0x1f, 0xf7, 0x8d, 0x2c, 0x6b, 0x3f, 0xf6,
+ 0xcb, 0xb0, 0xad, 0xfc, 0x9e, 0xd8, 0xe9, 0xfa,
+ 0xda, 0xd0, 0xd5, 0xbc, 0x74, 0x6c, 0x7e, 0xd6,
+ 0x45, 0x93, 0x9b, 0xa3, 0x37, 0x77, 0x75, 0x87,
+ 0x14, 0x6e, 0x82, 0xbd, 0xa1, 0xb1, 0x92, 0x84,
+ 0xe9, 0x8c, 0xa7, 0xc6, 0xad, 0x47, 0x10, 0x26,
+ 0xac, 0x2c, 0xb4, 0xa0, 0xde, 0x41, 0x04, 0x36,
+ 0xbf, 0x08, 0x8a, 0xc6, 0xd5, 0x78, 0x56, 0x04,
+ 0x87, 0x72, 0x12, 0x9b, 0xe1, 0x57, 0x0e, 0x67,
+ 0xc8, 0x5a, 0x9c, 0x53, 0x3f, 0xf9, 0xcc, 0xe7,
+ 0xbb, 0x05, 0x3b, 0x90, 0xd1, 0x36, 0x4f, 0xe7,
+ 0x60, 0xa7, 0x72, 0x1a, 0x2a, 0xd9, 0xfc, 0xf7,
+ 0xeb, 0x7f, 0xab, 0xce, 0x9e, 0xcb, 0x75, 0xce,
+ 0x96, 0xe9, 0x87, 0xa9, 0xf3, 0x49, 0xf0, 0xa7,
+ 0x72, 0x1a, 0x2b, 0x49, 0xff, 0xe4, 0x51, 0xc0,
+ 0x73, 0x39, 0xeb, 0xe4, 0x3a, 0x7f, 0xf9, 0xf5,
+ 0xcf, 0xab, 0x3b, 0x2f, 0x75, 0x61, 0xd3, 0x5e,
+ 0xea, 0x89, 0x7e, 0x4a, 0x9f, 0xca, 0xdb, 0x7d,
+ 0xfe, 0xa0, 0x3a, 0x7e, 0xa3, 0x2d, 0xec, 0x61,
+ 0xd3, 0xfd, 0x8d, 0xff, 0x50, 0xd2, 0xfa, 0x9d,
+ 0x3f, 0x9f, 0x97, 0xef, 0x83, 0x53, 0xa4, 0xe6,
+ 0xe2, 0x7e, 0x58, 0x59, 0xe8, 0x63, 0xd8, 0xb7,
+ 0x8d, 0xbe, 0x5b, 0x73, 0xc9, 0xfc, 0xec, 0x14,
+ 0xee, 0x43, 0x45, 0x81, 0x3e, 0x14, 0xee, 0x43,
+ 0x44, 0xeb, 0x3f, 0xff, 0xac, 0xb4, 0x6d, 0x8c,
+ 0x75, 0x6b, 0x96, 0xf5, 0x75, 0xa0, 0xe9, 0xf3,
+ 0x99, 0xcf, 0x76, 0x22, 0x55, 0xa3, 0x09, 0xf0,
+ 0xa7, 0x72, 0x1a, 0x2d, 0x99, 0xff, 0x01, 0x6a,
+ 0xeb, 0x79, 0x38, 0x4e, 0x93, 0xb0, 0xfb, 0x38,
+ 0xc2, 0x79, 0x3b, 0x90, 0xd1, 0x73, 0x49, 0x87,
+ 0x4c, 0xec, 0x13, 0x76, 0x12, 0xb9, 0xfc, 0xec,
+ 0x14, 0xee, 0x43, 0x45, 0xdf, 0x3c, 0xed, 0x3b,
+ 0x00, 0xe8, 0x56, 0xd6, 0x5b, 0x29, 0xf7, 0x28,
+ 0x61, 0x4a, 0x97, 0xa5, 0x40, 0x8b, 0x93, 0x21,
+ 0xa0, 0x08, 0x56, 0x55, 0x86, 0xe5, 0x7b, 0xce,
+ 0xe7, 0xfd, 0xfe, 0x72, 0xd6, 0xac, 0xe7, 0x9d,
+ 0x3f, 0xbf, 0x46, 0x37, 0xdd, 0x74, 0x9d, 0x3e,
+ 0x14, 0xee, 0x43, 0x44, 0xaf, 0x3f, 0xef, 0xf0,
+ 0x76, 0xb2, 0xd1, 0x81, 0x3a, 0x7b, 0x5e, 0x17,
+ 0x9d, 0x3f, 0xff, 0xbd, 0x7e, 0x67, 0x7c, 0x16,
+ 0x0f, 0x7e, 0x84, 0xf5, 0x07, 0x46, 0xc8, 0x83,
+ 0xe2, 0x18, 0xd9, 0x1c, 0xb6, 0x86, 0x14, 0xee,
+ 0x7b, 0x95, 0x37, 0x6c, 0x38, 0xac, 0x62, 0xb3,
+ 0xae, 0xbb, 0x15, 0x3f, 0xfa, 0xdd, 0xeb, 0xab,
+ 0xfc, 0x34, 0x6a, 0x02, 0xa7, 0xf7, 0x23, 0xb6,
+ 0x16, 0xed, 0xca, 0x7c, 0xf5, 0x1c, 0x93, 0x91,
+ 0x55, 0x73, 0x23, 0xb3, 0x6d, 0x0a, 0xd9, 0xff,
+ 0xce, 0x67, 0x3d, 0xd8, 0x29, 0xdc, 0x86, 0x89,
+ 0x86, 0x7f, 0xfe, 0xc7, 0x6f, 0x1e, 0x03, 0xb4,
+ 0xdd, 0xe1, 0x5a, 0xbc, 0xe9, 0xff, 0xb7, 0x4c,
+ 0xa5, 0xfa, 0xf5, 0xfe, 0xaf, 0x3a, 0x7f, 0x2f,
+ 0x51, 0x7d, 0x3c, 0x27, 0x4f, 0xb8, 0x5f, 0xcc,
+ 0x3a, 0x3e, 0x7b, 0x1a, 0x99, 0xcf, 0xcc, 0x5c,
+ 0xfd, 0xf7, 0x0e, 0x9f, 0x2e, 0x7e, 0xfb, 0x87,
+ 0x4f, 0xd6, 0xf5, 0xeb, 0xd4, 0xe8, 0x3d, 0x86,
+ 0x17, 0xcf, 0xff, 0xfb, 0xf8, 0x16, 0xfb, 0xe5,
+ 0xb4, 0x7f, 0x28, 0xf6, 0x7e, 0x97, 0xd4, 0xe9,
+ 0xf9, 0xb6, 0xfb, 0xfd, 0x40, 0x74, 0xff, 0xe5,
+ 0xb8, 0x15, 0xf9, 0x4d, 0xe8, 0xd4, 0x27, 0x42,
+ 0x9f, 0xef, 0x8c, 0x67, 0xea, 0xfb, 0x4b, 0x3a,
+ 0xe7, 0x4f, 0xff, 0xf8, 0x71, 0xb2, 0xfe, 0xfa,
+ 0x37, 0xfd, 0x6d, 0xde, 0xba, 0xde, 0xa7, 0x4b,
+ 0x29, 0x44, 0xf8, 0x97, 0xcf, 0x7d, 0x41, 0xbc,
+ 0xe9, 0xee, 0xdf, 0xb6, 0x1d, 0x27, 0x37, 0x15,
+ 0xc1, 0xed, 0x0a, 0x24, 0x7b, 0x69, 0x22, 0xd0,
+ 0xf0, 0xfc, 0x30, 0x2e, 0x51, 0xa9, 0x1c, 0xf8,
+ 0x53, 0xb9, 0x0d, 0x15, 0x74, 0xff, 0x3d, 0xd8,
+ 0x29, 0xdc, 0x86, 0x88, 0xf2, 0x4e, 0xc3, 0xf1,
+ 0xe3, 0x09, 0xfc, 0xec, 0x14, 0xee, 0x43, 0x45,
+ 0x83, 0x3f, 0x9d, 0x82, 0x9d, 0xc8, 0x68, 0xb2,
+ 0xa7, 0xf3, 0xb0, 0x53, 0xb9, 0x0d, 0x16, 0x9c,
+ 0xf2, 0x77, 0x21, 0xa2, 0xdc, 0x9f, 0xf9, 0x70,
+ 0x73, 0xfa, 0x2d, 0x94, 0x84, 0xe8, 0x13, 0xef,
+ 0xa9, 0x5c, 0xff, 0x2f, 0xf5, 0x62, 0xd6, 0xfe,
+ 0x3a, 0x7f, 0xdc, 0xf7, 0x60, 0xa7, 0x72, 0x1a,
+ 0x28, 0x79, 0xfa, 0xbd, 0x4d, 0x6f, 0xe3, 0xa7,
+ 0xef, 0xb7, 0x30, 0x56, 0xa7, 0x4f, 0xff, 0xd9,
+ 0xb5, 0x97, 0x7b, 0xaf, 0xfe, 0x05, 0x6a, 0xa0,
+ 0x2a, 0x4e, 0xc4, 0xd6, 0xbc, 0x42, 0xc3, 0x9b,
+ 0xa3, 0x6a, 0x5d, 0xb8, 0x5f, 0x3f, 0x9d, 0x82,
+ 0x9d, 0xc8, 0x68, 0xbc, 0xe1, 0x59, 0x16, 0x4f,
+ 0x44, 0xd9, 0x4b, 0x25, 0xf0, 0xd3, 0x0f, 0xf1,
+ 0x26, 0x61, 0xdd, 0x8e, 0xff, 0x28, 0x11, 0xb3,
+ 0x0c, 0xfe, 0x76, 0x0a, 0x77, 0x21, 0xa2, 0x96,
+ 0x9f, 0xce, 0xc1, 0x4e, 0xe4, 0x34, 0x58, 0x53,
+ 0xf9, 0xd8, 0x29, 0xdc, 0x86, 0x8b, 0x2e, 0x79,
+ 0xda, 0x77, 0x5f, 0x37, 0x53, 0xa7, 0x3b, 0x7b,
+ 0x0e, 0x9e, 0x47, 0x2d, 0x50, 0xf4, 0xb5, 0x34,
+ 0x9f, 0xfc, 0xe6, 0x73, 0xdd, 0x82, 0x9d, 0xc8,
+ 0x68, 0xa3, 0x27, 0xf3, 0x95, 0xb2, 0x8a, 0x80,
+ 0xe8, 0x7a, 0x77, 0xe2, 0x76, 0xc3, 0xbe, 0x84,
+ 0x6d, 0x4e, 0x2e, 0xa5, 0x3f, 0xf3, 0xb9, 0xee,
+ 0xc1, 0x4e, 0xe4, 0x34, 0x47, 0x33, 0xff, 0x9c,
+ 0xce, 0x7b, 0xb0, 0x53, 0xb9, 0x0d, 0x13, 0x94,
+ 0xfe, 0x76, 0x0a, 0x77, 0x21, 0xa2, 0xcc, 0x9f,
+ 0xf9, 0xca, 0x01, 0x5b, 0xdb, 0xa9, 0x79, 0xd3,
+ 0xf9, 0xd8, 0x29, 0xdc, 0x86, 0x8b, 0x76, 0x7f,
+ 0xf3, 0x99, 0xcf, 0x76, 0x0a, 0x77, 0x21, 0xa2,
+ 0x90, 0x9f, 0xf9, 0xdc, 0xf7, 0x60, 0xa7, 0x72,
+ 0x1a, 0x25, 0x28, 0xa1, 0x3f, 0x56, 0x93, 0x18,
+ 0xa4, 0x03, 0xbf, 0xa1, 0xdc, 0xed, 0xbd, 0x4a,
+ 0x7f, 0xdc, 0xf7, 0x60, 0xa7, 0x72, 0x1a, 0x27,
+ 0x69, 0xff, 0xf7, 0xb6, 0xd5, 0x8a, 0xdf, 0xdb,
+ 0x7d, 0x7f, 0x88, 0x74, 0x9c, 0xc4, 0x4f, 0xf2,
+ 0x34, 0xff, 0xdc, 0xcb, 0x62, 0x75, 0x97, 0x7b,
+ 0xce, 0x9f, 0xfb, 0xf9, 0x6e, 0xa3, 0x2b, 0xfe,
+ 0xa4, 0xe9, 0xb7, 0x1d, 0xb2, 0x21, 0xea, 0x87,
+ 0x0c, 0x47, 0x16, 0xe4, 0x2b, 0xe7, 0xc2, 0x9d,
+ 0xc8, 0x68, 0x8b, 0x27, 0xfd, 0xcf, 0x76, 0x0a,
+ 0x77, 0x21, 0xa2, 0x5d, 0x9f, 0xff, 0xb3, 0x6b,
+ 0x2e, 0xf7, 0x5f, 0xfc, 0x0a, 0xd5, 0x40, 0x54,
+ 0x9d, 0x88, 0xd3, 0x61, 0x86, 0xe2, 0x34, 0xff,
+ 0xe7, 0x33, 0x9e, 0xec, 0x14, 0xee, 0x43, 0x44,
+ 0xc5, 0x3f, 0x60, 0xa7, 0x72, 0x1a, 0x2a, 0x99,
+ 0xff, 0xff, 0xc3, 0xd6, 0xa5, 0xf9, 0x77, 0x5b,
+ 0xaa, 0x3e, 0x0d, 0xed, 0xe1, 0x79, 0xd0, 0xe4,
+ 0x56, 0x71, 0xac, 0xff, 0xe7, 0x33, 0x9e, 0xec,
+ 0x14, 0xee, 0x43, 0x44, 0xe9, 0x3f, 0xbd, 0xc2,
+ 0xaf, 0xe6, 0xc7, 0x4f, 0x9a, 0x56, 0x96, 0xa7,
+ 0x4f, 0xc1, 0xcf, 0x36, 0xcf, 0x9d, 0x3d, 0xeb,
+ 0x2b, 0xbc, 0x7a, 0xd5, 0x28, 0x9f, 0xfb, 0x5a,
+ 0xdd, 0x69, 0x76, 0xad, 0x79, 0x87, 0x43, 0x11,
+ 0x05, 0x63, 0x99, 0xff, 0x73, 0xdd, 0x82, 0x9d,
+ 0xc8, 0x68, 0x9d, 0xe7, 0xd7, 0xd7, 0x99, 0xe2,
+ 0xa4, 0xed, 0x93, 0x9b, 0xc8, 0xc2, 0x98, 0x47,
+ 0xc8, 0xd3, 0xff, 0x9c, 0xce, 0x7b, 0xb0, 0x53,
+ 0xb9, 0x0d, 0x14, 0x2c, 0xff, 0xe7, 0x33, 0x9e,
+ 0xec, 0x14, 0xee, 0x43, 0x45, 0x25, 0x3f, 0xff,
+ 0xb2, 0xae, 0xdf, 0x8d, 0x5b, 0x99, 0x7b, 0x2d,
+ 0xf5, 0x61, 0xd1, 0x42, 0xe4, 0xb3, 0xce, 0x12,
+ 0x1f, 0xc2, 0x44, 0xc8, 0xfb, 0x40, 0x93, 0xaa,
+ 0x96, 0xe2, 0x94, 0xfe, 0x76, 0x0a, 0x77, 0x21,
+ 0xa2, 0x24, 0x9f, 0xfc, 0xe6, 0x73, 0xdd, 0x82,
+ 0x9d, 0xc8, 0x68, 0x97, 0xa7, 0xc2, 0x9d, 0xc8,
+ 0x68, 0xa5, 0xe7, 0xff, 0x63, 0xd4, 0x15, 0x15,
+ 0xa5, 0xfe, 0x61, 0xd3, 0xe6, 0xff, 0x31, 0x6a,
+ 0x74, 0xfb, 0x9b, 0x60, 0xd4, 0xe9, 0x2e, 0xc7,
+ 0xa2, 0xc2, 0xa9, 0x3b, 0x11, 0xe4, 0xd1, 0x85,
+ 0xe1, 0x35, 0x3f, 0x9d, 0x82, 0x9d, 0xc8, 0x68,
+ 0xa7, 0x27, 0xfd, 0xe1, 0xea, 0xdb, 0x33, 0xe8,
+ 0x74, 0xff, 0xb2, 0xca, 0x38, 0xe0, 0x84, 0x25,
+ 0x4d, 0xe0, 0x9d, 0x35, 0x0e, 0xd9, 0x11, 0xbb,
+ 0x87, 0x6d, 0xe7, 0x93, 0xe1, 0x4e, 0xe4, 0x34,
+ 0x57, 0x93, 0xff, 0xf6, 0x6d, 0x65, 0xde, 0xeb,
+ 0xff, 0x81, 0x5a, 0xa8, 0x0a, 0x93, 0xb1, 0x11,
+ 0xbb, 0x86, 0x13, 0xff, 0x3b, 0x9e, 0xec, 0x14,
+ 0xee, 0x43, 0x44, 0x8f, 0x3b, 0xc0, 0x53, 0xa7,
+ 0x26, 0x30, 0xa7, 0x17, 0x73, 0xe1, 0x4e, 0xe4,
+ 0x34, 0x49, 0x13, 0xce, 0xe7, 0xb9, 0x4f, 0x67,
+ 0x0a, 0x67, 0xfe, 0x77, 0x3d, 0xd8, 0x29, 0xdc,
+ 0x86, 0x89, 0x2a, 0x7c, 0x29, 0xdc, 0x86, 0x8b,
+ 0xc6, 0x7e, 0xd7, 0xf4, 0xf5, 0x35, 0x3a, 0x7d,
+ 0x5a, 0xdf, 0x10, 0xe9, 0xfe, 0x7b, 0xb0, 0x53,
+ 0xb9, 0x0d, 0x12, 0x6c, 0x9d, 0x88, 0xc7, 0xa4,
+ 0xc0, 0x4c, 0x38, 0x9a, 0x15, 0x77, 0x26, 0x83,
+ 0xb7, 0xc6, 0x89, 0xb1, 0xdf, 0xa1, 0x90, 0xd4,
+ 0x34, 0x58, 0x57, 0x68, 0x60, 0x5c, 0xdf, 0x58,
+ 0xc4, 0xe1, 0x63, 0x76, 0xd5, 0xa2, 0x3a, 0xe7,
+ 0xc7, 0x93, 0xb4, 0xa1, 0xac, 0xb7, 0x5a, 0xda,
+ 0x65, 0x2c, 0x25, 0x7f, 0xbd, 0x4c, 0xf3, 0xdf,
+ 0xa7, 0x3d, 0x37, 0x71, 0xd8, 0x35, 0x4e, 0xc3,
+ 0x1a, 0x47, 0xab, 0x31, 0x1a, 0x11, 0x69, 0xda,
+ 0x8e, 0xa7, 0xb9, 0x02, 0x58, 0x73, 0x77, 0x0b,
+ 0x1f, 0xcf, 0x63, 0x56, 0x92, 0xbb, 0x7a, 0xe8,
+ 0x7f, 0x5a, 0x60, 0xb3, 0x69, 0x4c, 0x41, 0x94,
+ 0xa1, 0xb9, 0x1f, 0x5e, 0xf9, 0xd9, 0x46, 0xf9,
+ 0xe4, 0xb8,
};
-static const unsigned kPreloadedHSTSBits = 97858;
+static const unsigned kPreloadedHSTSBits = 97871;
-static const unsigned kHSTSRootPosition = 97280;
+static const unsigned kHSTSRootPosition = 97293;
#endif // NET_HTTP_TRANSPORT_SECURITY_STATE_STATIC_H_
diff --git a/net/http/transport_security_state_static.json b/net/http/transport_security_state_static.json
index 39ca582..59eb9f7 100644
--- a/net/http/transport_security_state_static.json
+++ b/net/http/transport_security_state_static.json
@@ -186,6 +186,14 @@
"DigiCertEVRoot",
"FacebookBackup"
]
+ },
+ {
+ "name": "spideroak",
+ "static_spki_hashes": [
+ "RapidSSL",
+ "SpiderOak1",
+ "SpiderOak2"
+ ]
}
],
@@ -1266,7 +1274,7 @@
{ "name": "ravchat.com", "include_subdomains": true, "mode": "force-https" },
{ "name": "sciencex.com", "include_subdomains": true, "mode": "force-https" },
{ "name": "shiinko.com", "include_subdomains": true, "mode": "force-https" },
- { "name": "spideroak.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "spideroak.com", "include_subdomains": true, "mode": "force-https", "pins": "spideroak" },
{ "name": "thorncreek.net", "include_subdomains": true, "mode": "force-https" },
{ "name": "tno.io", "include_subdomains": true, "mode": "force-https" },
{ "name": "translatoruk.co.uk", "include_subdomains": true, "mode": "force-https" },
@@ -1393,9 +1401,10 @@
{ "name": "fleximus.org", "include_subdomains": true, "mode": "force-https" },
// Facebook would like to have pinning enforced on (*.)facebook.com and
- // HSTS enforced on specific names. We can't (yet) represent that in JSON
- // So we're currently only applying pinning on the specific names.
- { "name": "facebook.com", "mode": "force-https", "pins": "facebook", "include_subdomains_for_pinning": true },
+ // HSTS enforced on specific names. We have the
+ // "include_subdomains_for_pinning" flag that can do that, but it triggered a
+ // wave of pinning failures and so isn't used until that can be investigated.
+ { "name": "facebook.com", "mode": "force-https", "pins": "facebook" },
{ "name": "www.facebook.com", "include_subdomains": true, "mode": "force-https", "pins": "facebook" },
{ "name": "m.facebook.com", "include_subdomains": true, "mode": "force-https", "pins": "facebook" },
{ "name": "tablet.facebook.com", "include_subdomains": true, "mode": "force-https", "pins": "facebook" },
@@ -1777,6 +1786,7 @@
"DROPBOX_COM",
"YOUTUBE_NOCOOKIE_COM",
"2MDN_NET",
- "FACEBOOK_COM"
+ "FACEBOOK_COM",
+ "SPIDEROAK_COM"
]
}
diff --git a/net/http/transport_security_state_unittest.cc b/net/http/transport_security_state_unittest.cc
index cf5f243..1872e72 100644
--- a/net/http/transport_security_state_unittest.cc
+++ b/net/http/transport_security_state_unittest.cc
@@ -540,9 +540,7 @@
EXPECT_FALSE(domain_state.pkp.spki_hashes.empty());
EXPECT_TRUE(StaticShouldRedirect("facebook.com"));
- EXPECT_TRUE(state.GetStaticDomainState("foo.facebook.com", &domain_state));
- EXPECT_FALSE(domain_state.pkp.spki_hashes.empty());
- EXPECT_FALSE(StaticShouldRedirect("foo.facebook.com"));
+ EXPECT_FALSE(state.GetStaticDomainState("foo.facebook.com", &domain_state));
EXPECT_TRUE(state.GetStaticDomainState("www.facebook.com", &domain_state));
EXPECT_FALSE(domain_state.pkp.spki_hashes.empty());
diff --git a/net/net.gyp b/net/net.gyp
index e9379e0..3c9a520 100644
--- a/net/net.gyp
+++ b/net/net.gyp
@@ -487,10 +487,14 @@
['include', '^base/platform_mime_util_linux\\.cc$'],
['include', '^base/address_tracker_linux\\.cc$'],
['include', '^base/address_tracker_linux\\.h$'],
+ ['include', '^base/net_util_linux\\.cc$'],
+ ['include', '^base/net_util_linux\\.h$'],
],
}],
['OS == "ios"', {
'sources/': [
+ ['include', '^base/net_util_mac\\.cc$'],
+ ['include', '^base/net_util_mac\\.h$'],
['include', '^base/network_change_notifier_mac\\.cc$'],
['include', '^base/network_config_watcher_mac\\.cc$'],
['include', '^base/platform_mime_util_mac\\.mm$'],
diff --git a/net/net.gypi b/net/net.gypi
index fef6136..337f016 100644
--- a/net/net.gypi
+++ b/net/net.gypi
@@ -246,7 +246,11 @@
'base/net_log_logger.h',
'base/net_log_util.cc',
'base/net_log_util.h',
+ 'base/net_util_linux.cc',
+ 'base/net_util_mac.cc',
'base/net_util_win.cc',
+ 'base/network_activity_monitor.cc',
+ 'base/network_activity_monitor.h',
'base/network_change_notifier.cc',
'base/network_change_notifier.h',
'base/network_change_notifier_factory.h',
@@ -275,8 +279,12 @@
'base/request_priority.h',
'base/sdch_manager.cc',
'base/sdch_manager.h',
+ 'base/sdch_net_log_params.cc',
+ 'base/sdch_net_log_params.h',
'base/sdch_observer.cc',
'base/sdch_observer.h',
+ 'base/sdch_problem_code_list.h',
+ 'base/sdch_problem_codes.h',
'base/static_cookie_policy.cc',
'base/static_cookie_policy.h',
'base/test_data_stream.cc',
@@ -751,8 +759,6 @@
'quic/congestion_control/cubic.h',
'quic/congestion_control/hybrid_slow_start.cc',
'quic/congestion_control/hybrid_slow_start.h',
- 'quic/congestion_control/leaky_bucket.cc',
- 'quic/congestion_control/leaky_bucket.h',
'quic/congestion_control/loss_detection_interface.cc',
'quic/congestion_control/loss_detection_interface.h',
'quic/congestion_control/pacing_sender.cc',
@@ -785,6 +791,8 @@
'quic/crypto/aes_128_gcm_12_encrypter.h',
'quic/crypto/aes_128_gcm_12_encrypter_nss.cc',
'quic/crypto/aes_128_gcm_12_encrypter_openssl.cc',
+ 'quic/crypto/cached_network_parameters.cc',
+ 'quic/crypto/cached_network_parameters.h',
'quic/crypto/cert_compressor.cc',
'quic/crypto/cert_compressor.h',
'quic/crypto/chacha20_poly1305_decrypter.h',
@@ -1276,6 +1284,7 @@
'base/net_log_util_unittest.cc',
'base/net_util_unittest.cc',
'base/net_util_icu_unittest.cc',
+ 'base/network_activity_monitor_unittest.cc',
'base/network_change_notifier_unittest.cc',
'base/network_change_notifier_win_unittest.cc',
'base/prioritized_dispatcher_unittest.cc',
@@ -1440,7 +1449,6 @@
'quic/congestion_control/cube_root_test.cc',
'quic/congestion_control/cubic_test.cc',
'quic/congestion_control/hybrid_slow_start_test.cc',
- 'quic/congestion_control/leaky_bucket_test.cc',
'quic/congestion_control/pacing_sender_test.cc',
'quic/congestion_control/prr_sender_test.cc',
'quic/congestion_control/rtt_stats_test.cc',
diff --git a/net/quic/congestion_control/hybrid_slow_start.cc b/net/quic/congestion_control/hybrid_slow_start.cc
index 4b1e842..e3789b4 100644
--- a/net/quic/congestion_control/hybrid_slow_start.cc
+++ b/net/quic/congestion_control/hybrid_slow_start.cc
@@ -23,6 +23,7 @@
HybridSlowStart::HybridSlowStart(const QuicClock* clock)
: clock_(clock),
+ ack_train_detection_(true),
started_(false),
hystart_found_(NOT_FOUND),
last_sent_sequence_number_(0),
@@ -84,12 +85,8 @@
// more than the capacity.
// This first trigger will not come into play until we hit roughly 9.6 Mbps
// with delayed acks (or 4.8Mbps without delayed acks)
- // TODO(ianswett): QUIC always uses delayed acks, even at the beginning, so
- // this should likely be at least 4ms.
- // TODO(pwestin): we need to make sure our pacing don't trigger this detector.
- // TODO(ianswett): Pacing or other cases could be handled by checking the send
- // time of the first acked packet in a receive round.
- if (current_time.Subtract(last_close_ack_pair_time_).ToMicroseconds() <=
+ if (ack_train_detection_ &&
+ current_time.Subtract(last_close_ack_pair_time_).ToMicroseconds() <=
kHybridStartDelayMinThresholdUs) {
last_close_ack_pair_time_ = current_time;
if (current_time.Subtract(round_start_).ToMicroseconds() >=
diff --git a/net/quic/congestion_control/hybrid_slow_start.h b/net/quic/congestion_control/hybrid_slow_start.h
index 5d36c53..cee9a60 100644
--- a/net/quic/congestion_control/hybrid_slow_start.h
+++ b/net/quic/congestion_control/hybrid_slow_start.h
@@ -53,6 +53,14 @@
// Call for the start of each receive round (burst) in the slow start phase.
void StartReceiveRound(QuicPacketSequenceNumber last_sent);
+ void set_ack_train_detection(bool ack_train_detection) {
+ ack_train_detection_ = ack_train_detection;
+ }
+
+ bool ack_train_detection() const {
+ return ack_train_detection_;
+ }
+
// Whether slow start has started.
bool started() const {
return started_;
@@ -67,6 +75,7 @@
};
const QuicClock* clock_;
+ bool ack_train_detection_;
// Whether the hybrid slow start has been started.
bool started_;
HystartState hystart_found_;
diff --git a/net/quic/congestion_control/hybrid_slow_start_test.cc b/net/quic/congestion_control/hybrid_slow_start_test.cc
index dd74933..bcdf8d9 100644
--- a/net/quic/congestion_control/hybrid_slow_start_test.cc
+++ b/net/quic/congestion_control/hybrid_slow_start_test.cc
@@ -54,26 +54,33 @@
// At a typical RTT 60 ms, assuming that the inter arrival timestamp is 1 ms,
// we expect to be able to send a burst of 30 packet before we trigger the
// ack train detection.
- const int kMaxLoopCount = 5;
- QuicPacketSequenceNumber sequence_number = 2;
- QuicPacketSequenceNumber end_sequence_number = 2;
- for (int burst = 0; burst < kMaxLoopCount; ++burst) {
+ // Run this test for both enabled and disabled ack train detection.
+ for (int i = 0; i < 2; ++i) {
+ const bool ack_train_detection = (i == 1);
+ slow_start_->set_ack_train_detection(ack_train_detection);
+
+ const int kMaxLoopCount = 5;
+ QuicPacketSequenceNumber sequence_number = 2;
+ QuicPacketSequenceNumber end_sequence_number = 2;
+ for (int burst = 0; burst < kMaxLoopCount; ++burst) {
+ slow_start_->StartReceiveRound(end_sequence_number);
+ do {
+ clock_.AdvanceTime(one_ms_);
+ EXPECT_FALSE(slow_start_->ShouldExitSlowStart(rtt_, rtt_, 100));
+ } while (!slow_start_->IsEndOfRound(sequence_number++));
+ end_sequence_number *= 2; // Exponential growth.
+ }
slow_start_->StartReceiveRound(end_sequence_number);
- do {
+
+ for (int n = 0;
+ n < 29 && !slow_start_->IsEndOfRound(sequence_number++); ++n) {
clock_.AdvanceTime(one_ms_);
EXPECT_FALSE(slow_start_->ShouldExitSlowStart(rtt_, rtt_, 100));
- } while (!slow_start_->IsEndOfRound(sequence_number++));
- end_sequence_number *= 2; // Exponential growth.
- }
- slow_start_->StartReceiveRound(end_sequence_number);
-
- for (int n = 0;
- n < 29 && !slow_start_->IsEndOfRound(sequence_number++); ++n) {
+ }
clock_.AdvanceTime(one_ms_);
- EXPECT_FALSE(slow_start_->ShouldExitSlowStart(rtt_, rtt_, 100));
+ EXPECT_EQ(ack_train_detection,
+ slow_start_->ShouldExitSlowStart(rtt_, rtt_, 100));
}
- clock_.AdvanceTime(one_ms_);
- EXPECT_TRUE(slow_start_->ShouldExitSlowStart(rtt_, rtt_, 100));
}
TEST_F(HybridSlowStartTest, Delay) {
diff --git a/net/quic/congestion_control/leaky_bucket.cc b/net/quic/congestion_control/leaky_bucket.cc
deleted file mode 100644
index f3972f6..0000000
--- a/net/quic/congestion_control/leaky_bucket.cc
+++ /dev/null
@@ -1,54 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/quic/congestion_control/leaky_bucket.h"
-
-#include "base/time/time.h"
-
-namespace net {
-
-LeakyBucket::LeakyBucket(QuicBandwidth draining_rate)
- : bytes_(0),
- time_last_updated_(QuicTime::Zero()),
- draining_rate_(draining_rate) {
-}
-
-void LeakyBucket::SetDrainingRate(QuicTime now, QuicBandwidth draining_rate) {
- Update(now);
- draining_rate_ = draining_rate;
-}
-
-void LeakyBucket::Add(QuicTime now, QuicByteCount bytes) {
- Update(now);
- bytes_ += bytes;
-}
-
-QuicTime::Delta LeakyBucket::TimeRemaining(QuicTime now) const {
- QuicTime::Delta time_since_last_update = now.Subtract(time_last_updated_);
- QuicTime::Delta send_delay = QuicTime::Delta::FromMicroseconds(
- (bytes_ * base::Time::kMicrosecondsPerSecond) /
- draining_rate_.ToBytesPerSecond());
- if (send_delay < time_since_last_update) {
- return QuicTime::Delta::Zero();
- }
- return send_delay.Subtract(time_since_last_update);
-}
-
-QuicByteCount LeakyBucket::BytesPending(QuicTime now) {
- Update(now);
- return bytes_;
-}
-
-void LeakyBucket::Update(QuicTime now) {
- QuicTime::Delta elapsed_time = now.Subtract(time_last_updated_);
- QuicByteCount bytes_cleared = draining_rate_.ToBytesPerPeriod(elapsed_time);
- if (bytes_cleared >= bytes_) {
- bytes_ = 0;
- } else {
- bytes_ -= bytes_cleared;
- }
- time_last_updated_ = now;
-}
-
-} // namespace net
diff --git a/net/quic/congestion_control/leaky_bucket.h b/net/quic/congestion_control/leaky_bucket.h
deleted file mode 100644
index eb4cdb0..0000000
--- a/net/quic/congestion_control/leaky_bucket.h
+++ /dev/null
@@ -1,49 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-//
-// Helper class to track the rate data can leave the buffer for pacing.
-// A leaky bucket drains the data at a constant rate regardless of fullness of
-// the buffer.
-// See http://en.wikipedia.org/wiki/Leaky_bucket for more details.
-
-#ifndef NET_QUIC_CONGESTION_CONTROL_LEAKY_BUCKET_H_
-#define NET_QUIC_CONGESTION_CONTROL_LEAKY_BUCKET_H_
-
-#include "base/basictypes.h"
-#include "net/base/net_export.h"
-#include "net/quic/quic_bandwidth.h"
-#include "net/quic/quic_protocol.h"
-#include "net/quic/quic_time.h"
-
-namespace net {
-
-class NET_EXPORT_PRIVATE LeakyBucket {
- public:
- explicit LeakyBucket(QuicBandwidth draining_rate);
-
- // Set the rate at which the bytes leave the buffer.
- void SetDrainingRate(QuicTime now, QuicBandwidth draining_rate);
-
- // Add data to the buffer.
- void Add(QuicTime now, QuicByteCount bytes);
-
- // Time until the buffer is empty.
- QuicTime::Delta TimeRemaining(QuicTime now) const;
-
- // Number of bytes in the buffer.
- QuicByteCount BytesPending(QuicTime now);
-
- private:
- void Update(QuicTime now);
-
- QuicByteCount bytes_;
- QuicTime time_last_updated_;
- QuicBandwidth draining_rate_;
-
- DISALLOW_COPY_AND_ASSIGN(LeakyBucket);
-};
-
-} // namespace net
-
-#endif // NET_QUIC_CONGESTION_CONTROL_LEAKY_BUCKET_H_
diff --git a/net/quic/congestion_control/leaky_bucket_test.cc b/net/quic/congestion_control/leaky_bucket_test.cc
deleted file mode 100644
index 8387ada..0000000
--- a/net/quic/congestion_control/leaky_bucket_test.cc
+++ /dev/null
@@ -1,75 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/logging.h"
-#include "base/memory/scoped_ptr.h"
-#include "net/quic/congestion_control/leaky_bucket.h"
-#include "net/quic/test_tools/mock_clock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace net {
-namespace test {
-
-class LeakyBucketTest : public ::testing::Test {
- protected:
- void SetUp() override {
- leaky_bucket_.reset(new LeakyBucket(QuicBandwidth::Zero()));
- }
- MockClock clock_;
- scoped_ptr<LeakyBucket> leaky_bucket_;
-};
-
-TEST_F(LeakyBucketTest, Basic) {
- QuicBandwidth draining_rate = QuicBandwidth::FromBytesPerSecond(200000);
- leaky_bucket_->SetDrainingRate(clock_.Now(), draining_rate);
- leaky_bucket_->Add(clock_.Now(), 2000);
- EXPECT_EQ(2000u, leaky_bucket_->BytesPending(clock_.Now()));
- EXPECT_EQ(QuicTime::Delta::FromMilliseconds(10),
- leaky_bucket_->TimeRemaining(clock_.Now()));
- clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
- EXPECT_EQ(1000u, leaky_bucket_->BytesPending(clock_.Now()));
- EXPECT_EQ(QuicTime::Delta::FromMilliseconds(5),
- leaky_bucket_->TimeRemaining(clock_.Now()));
- clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
- EXPECT_EQ(0u, leaky_bucket_->BytesPending(clock_.Now()));
- EXPECT_TRUE(leaky_bucket_->TimeRemaining(clock_.Now()).IsZero());
- clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
- EXPECT_EQ(0u, leaky_bucket_->BytesPending(clock_.Now()));
- EXPECT_TRUE(leaky_bucket_->TimeRemaining(clock_.Now()).IsZero());
- leaky_bucket_->Add(clock_.Now(), 2000);
- clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(11));
- EXPECT_EQ(0u, leaky_bucket_->BytesPending(clock_.Now()));
- EXPECT_TRUE(leaky_bucket_->TimeRemaining(clock_.Now()).IsZero());
- leaky_bucket_->Add(clock_.Now(), 2000);
- clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
- leaky_bucket_->Add(clock_.Now(), 2000);
- clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
- EXPECT_EQ(2000u, leaky_bucket_->BytesPending(clock_.Now()));
- EXPECT_EQ(QuicTime::Delta::FromMilliseconds(10),
- leaky_bucket_->TimeRemaining(clock_.Now()));
- clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(10));
- EXPECT_EQ(0u, leaky_bucket_->BytesPending(clock_.Now()));
- EXPECT_TRUE(leaky_bucket_->TimeRemaining(clock_.Now()).IsZero());
-}
-
-TEST_F(LeakyBucketTest, ChangeDrainRate) {
- QuicBandwidth draining_rate = QuicBandwidth::FromBytesPerSecond(200000);
- leaky_bucket_->SetDrainingRate(clock_.Now(), draining_rate);
- leaky_bucket_->Add(clock_.Now(), 2000);
- EXPECT_EQ(2000u, leaky_bucket_->BytesPending(clock_.Now()));
- EXPECT_EQ(QuicTime::Delta::FromMilliseconds(10),
- leaky_bucket_->TimeRemaining(clock_.Now()));
- clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
- EXPECT_EQ(1000u, leaky_bucket_->BytesPending(clock_.Now()));
- EXPECT_EQ(QuicTime::Delta::FromMilliseconds(5),
- leaky_bucket_->TimeRemaining(clock_.Now()));
- draining_rate = draining_rate.Scale(0.5f); // Cut drain rate in half.
- leaky_bucket_->SetDrainingRate(clock_.Now(), draining_rate);
- EXPECT_EQ(1000u, leaky_bucket_->BytesPending(clock_.Now()));
- EXPECT_EQ(QuicTime::Delta::FromMilliseconds(10),
- leaky_bucket_->TimeRemaining(clock_.Now()));
-}
-
-} // namespace test
-} // namespace net
diff --git a/net/quic/congestion_control/pacing_sender.cc b/net/quic/congestion_control/pacing_sender.cc
index 061f6ec..8073c5b 100644
--- a/net/quic/congestion_control/pacing_sender.cc
+++ b/net/quic/congestion_control/pacing_sender.cc
@@ -20,8 +20,11 @@
PacingSender::~PacingSender() {}
-void PacingSender::SetFromConfig(const QuicConfig& config, bool is_server) {
- sender_->SetFromConfig(config, is_server);
+void PacingSender::SetFromConfig(const QuicConfig& config,
+ bool is_server,
+ bool using_pacing) {
+ DCHECK(using_pacing);
+ sender_->SetFromConfig(config, is_server, using_pacing);
}
void PacingSender::SetNumEmulatedConnections(int num_connections) {
diff --git a/net/quic/congestion_control/pacing_sender.h b/net/quic/congestion_control/pacing_sender.h
index f16172a..4eb3dab 100644
--- a/net/quic/congestion_control/pacing_sender.h
+++ b/net/quic/congestion_control/pacing_sender.h
@@ -35,7 +35,9 @@
~PacingSender() override;
// SendAlgorithmInterface methods.
- void SetFromConfig(const QuicConfig& config, bool is_server) override;
+ void SetFromConfig(const QuicConfig& config,
+ bool is_server,
+ bool using_pacing) override;
void SetNumEmulatedConnections(int num_connections) override;
void OnCongestionEvent(bool rtt_updated,
QuicByteCount bytes_in_flight,
diff --git a/net/quic/congestion_control/rtt_stats.cc b/net/quic/congestion_control/rtt_stats.cc
index dfb50ef..32e3b58 100644
--- a/net/quic/congestion_control/rtt_stats.cc
+++ b/net/quic/congestion_control/rtt_stats.cc
@@ -28,7 +28,7 @@
min_rtt_(QuicTime::Delta::Zero()),
smoothed_rtt_(QuicTime::Delta::Zero()),
mean_deviation_(QuicTime::Delta::Zero()),
- initial_rtt_us_(kInitialRttMs * base::Time::kMicrosecondsPerMillisecond),
+ initial_rtt_us_(kInitialRttMs * kNumMicrosPerMilli),
num_min_rtt_samples_remaining_(0),
recent_min_rtt_window_(QuicTime::Delta::Infinite()) {}
diff --git a/net/quic/congestion_control/send_algorithm_interface.cc b/net/quic/congestion_control/send_algorithm_interface.cc
index 7245e33..82f1135 100644
--- a/net/quic/congestion_control/send_algorithm_interface.cc
+++ b/net/quic/congestion_control/send_algorithm_interface.cc
@@ -16,17 +16,23 @@
const QuicClock* clock,
const RttStats* rtt_stats,
CongestionControlType congestion_control_type,
- QuicConnectionStats* stats) {
+ QuicConnectionStats* stats,
+ QuicPacketCount initial_congestion_window) {
switch (congestion_control_type) {
case kCubic:
- return new TcpCubicSender(clock, rtt_stats,
- false /* don't use Reno */,
+ return new TcpCubicSender(clock, rtt_stats, false /* don't use Reno */,
+ initial_congestion_window,
kMaxTcpCongestionWindow, stats);
case kReno:
- return new TcpCubicSender(clock, rtt_stats,
- true /* use Reno */,
+ return new TcpCubicSender(clock, rtt_stats, true /* use Reno */,
+ initial_congestion_window,
kMaxTcpCongestionWindow, stats);
case kBBR:
+ // TODO(rtenneti): Enable BbrTcpSender.
+#if 0
+ return new BbrTcpSender(clock, rtt_stats, initial_congestion_window,
+ kMaxTcpCongestionWindow, stats);
+#endif
LOG(DFATAL) << "BbrTcpSender is not supported.";
return nullptr;
}
diff --git a/net/quic/congestion_control/send_algorithm_interface.h b/net/quic/congestion_control/send_algorithm_interface.h
index 4f74628..7195f81 100644
--- a/net/quic/congestion_control/send_algorithm_interface.h
+++ b/net/quic/congestion_control/send_algorithm_interface.h
@@ -29,14 +29,17 @@
typedef std::vector<std::pair<QuicPacketSequenceNumber, TransmissionInfo>>
CongestionVector;
- static SendAlgorithmInterface* Create(const QuicClock* clock,
- const RttStats* rtt_stats,
- CongestionControlType type,
- QuicConnectionStats* stats);
+ static SendAlgorithmInterface* Create(
+ const QuicClock* clock,
+ const RttStats* rtt_stats,
+ CongestionControlType type,
+ QuicConnectionStats* stats,
+ QuicPacketCount initial_congestion_window);
virtual ~SendAlgorithmInterface() {}
- virtual void SetFromConfig(const QuicConfig& config, bool is_server) = 0;
+ virtual void SetFromConfig(
+ const QuicConfig& config, bool is_server, bool using_pacing) = 0;
// Sets the number of connections to emulate when doing congestion control,
// particularly for congestion avoidance. Can be set any time.
diff --git a/net/quic/congestion_control/tcp_cubic_sender.cc b/net/quic/congestion_control/tcp_cubic_sender.cc
index 5f20597..2d0efd7 100644
--- a/net/quic/congestion_control/tcp_cubic_sender.cc
+++ b/net/quic/congestion_control/tcp_cubic_sender.cc
@@ -31,6 +31,7 @@
const QuicClock* clock,
const RttStats* rtt_stats,
bool reno,
+ QuicPacketCount initial_tcp_congestion_window,
QuicPacketCount max_tcp_congestion_window,
QuicConnectionStats* stats)
: hybrid_slow_start_(clock),
@@ -43,7 +44,7 @@
largest_sent_sequence_number_(0),
largest_acked_sequence_number_(0),
largest_sent_at_last_cutback_(0),
- congestion_window_(kDefaultInitialWindow),
+ congestion_window_(initial_tcp_congestion_window),
previous_congestion_window_(0),
slowstart_threshold_(max_tcp_congestion_window),
previous_slowstart_threshold_(0),
@@ -55,20 +56,19 @@
UMA_HISTOGRAM_COUNTS("Net.QuicSession.FinalTcpCwnd", congestion_window_);
}
-void TcpCubicSender::SetFromConfig(const QuicConfig& config, bool is_server) {
+void TcpCubicSender::SetFromConfig(const QuicConfig& config,
+ bool is_server,
+ bool using_pacing) {
if (is_server) {
if (config.HasReceivedConnectionOptions() &&
ContainsQuicTag(config.ReceivedConnectionOptions(), kIW10)) {
- // Initial window experiment. Ignore the initial congestion
- // window suggested by the client and use the default ICWND of
- // 10 instead.
- congestion_window_ = kDefaultInitialWindow;
- } else if (config.HasReceivedInitialCongestionWindow()) {
- // Set the initial window size.
- congestion_window_ = max(kMinimumCongestionWindow,
- min(kMaxInitialWindow,
- static_cast<QuicPacketCount>(
- config.ReceivedInitialCongestionWindow())));
+ // Initial window experiment.
+ congestion_window_ = 10;
+ }
+ if (using_pacing) {
+ // Disable the ack train mode in hystart when pacing is enabled, since it
+ // may be falsely triggered.
+ hybrid_slow_start_.set_ack_train_detection(false);
}
}
}
diff --git a/net/quic/congestion_control/tcp_cubic_sender.h b/net/quic/congestion_control/tcp_cubic_sender.h
index 7491565..a7507a2 100644
--- a/net/quic/congestion_control/tcp_cubic_sender.h
+++ b/net/quic/congestion_control/tcp_cubic_sender.h
@@ -34,12 +34,15 @@
TcpCubicSender(const QuicClock* clock,
const RttStats* rtt_stats,
bool reno,
+ QuicPacketCount initial_tcp_congestion_window,
QuicPacketCount max_tcp_congestion_window,
QuicConnectionStats* stats);
~TcpCubicSender() override;
// Start implementation of SendAlgorithmInterface.
- void SetFromConfig(const QuicConfig& config, bool is_server) override;
+ void SetFromConfig(const QuicConfig& config,
+ bool is_server,
+ bool using_pacing) override;
void SetNumEmulatedConnections(int num_connections) override;
void OnCongestionEvent(bool rtt_updated,
QuicByteCount bytes_in_flight,
diff --git a/net/quic/congestion_control/tcp_cubic_sender_test.cc b/net/quic/congestion_control/tcp_cubic_sender_test.cc
index 48a1300..427dd8c 100644
--- a/net/quic/congestion_control/tcp_cubic_sender_test.cc
+++ b/net/quic/congestion_control/tcp_cubic_sender_test.cc
@@ -21,19 +21,22 @@
namespace net {
namespace test {
-const uint32 kDefaultWindowTCP = kDefaultInitialWindow * kDefaultTCPMSS;
+// TODO(ianswett): A number of theses tests were written with the assumption of
+// an initial CWND of 10. They have carefully calculated values which should be
+// updated to be based on kInitialCongestionWindowInsecure.
+const uint32 kInitialCongestionWindowPackets = 10;
+const uint32 kDefaultWindowTCP =
+ kInitialCongestionWindowPackets * kDefaultTCPMSS;
const float kRenoBeta = 0.7f; // Reno backoff factor.
-// TODO(ianswett): Remove 10000 once b/10075719 is fixed.
-const QuicPacketCount kDefaultMaxCongestionWindowTCP = 10000;
-
class TcpCubicSenderPeer : public TcpCubicSender {
public:
TcpCubicSenderPeer(const QuicClock* clock,
bool reno,
QuicPacketCount max_tcp_congestion_window)
: TcpCubicSender(
- clock, &rtt_stats_, reno, max_tcp_congestion_window, &stats_) {
+ clock, &rtt_stats_, reno, kInitialCongestionWindowPackets,
+ max_tcp_congestion_window, &stats_) {
}
QuicPacketCount congestion_window() {
@@ -61,7 +64,7 @@
TcpCubicSenderTest()
: one_ms_(QuicTime::Delta::FromMilliseconds(1)),
sender_(new TcpCubicSenderPeer(&clock_, true,
- kDefaultMaxCongestionWindowTCP)),
+ kMaxTcpCongestionWindow)),
receiver_(new TcpReceiver()),
sequence_number_(1),
acked_sequence_number_(0),
@@ -209,7 +212,7 @@
TEST_F(TcpCubicSenderTest, SlowStartAckTrain) {
sender_->SetNumEmulatedConnections(1);
- EXPECT_EQ(kDefaultMaxCongestionWindowTCP * kDefaultTCPMSS,
+ EXPECT_EQ(kMaxTcpCongestionWindow * kDefaultTCPMSS,
sender_->GetSlowStartThreshold());
// Make sure that we fall out of slow start when we send ACK train longer
@@ -305,7 +308,7 @@
TEST_F(TcpCubicSenderTest, NoPRRWhenLessThanOnePacketInFlight) {
SendAvailableSendWindow();
- LoseNPackets(kDefaultInitialWindow - 1);
+ LoseNPackets(kInitialCongestionWindowPackets - 1);
AckNPackets(1);
// PRR will allow 2 packets for every ack during recovery.
EXPECT_EQ(2, SendAvailableSendWindow());
@@ -424,7 +427,7 @@
TEST_F(TcpCubicSenderTest, RTOCongestionWindowAndRevert) {
EXPECT_EQ(kDefaultWindowTCP, sender_->GetCongestionWindow());
- EXPECT_EQ(10000u, sender_->slowstart_threshold());
+ EXPECT_EQ(kMaxTcpCongestionWindow, sender_->slowstart_threshold());
// Expect the window to decrease to the minimum once the RTO fires
// and slow start threshold to be set to 1/2 of the CWND.
@@ -435,7 +438,7 @@
// Now repair the RTO and ensure the slowstart threshold reverts.
sender_->RevertRetransmissionTimeout();
EXPECT_EQ(kDefaultWindowTCP, sender_->GetCongestionWindow());
- EXPECT_EQ(10000u, sender_->slowstart_threshold());
+ EXPECT_EQ(kMaxTcpCongestionWindow, sender_->slowstart_threshold());
}
TEST_F(TcpCubicSenderTest, RTOCongestionWindowNoRetransmission) {
@@ -574,20 +577,26 @@
}
TEST_F(TcpCubicSenderTest, ConfigureMaxInitialWindow) {
- QuicPacketCount congestion_window = sender_->congestion_window();
QuicConfig config;
- QuicConfigPeer::SetReceivedInitialWindow(&config, 2 * congestion_window);
- sender_->SetFromConfig(config, true);
- EXPECT_EQ(2 * congestion_window, sender_->congestion_window());
-
- // Verify that kCOPT: kIW10 forces the congestion window to the
- // default of 10 regardless of ReceivedInitialWindow.
+ // Verify that kCOPT: kIW10 forces the congestion window to the default of 10.
QuicTagVector options;
options.push_back(kIW10);
QuicConfigPeer::SetReceivedConnectionOptions(&config, options);
- sender_->SetFromConfig(config, true);
- EXPECT_EQ(congestion_window, sender_->congestion_window());
+ sender_->SetFromConfig(config,
+ /* is_server= */ true,
+ /* using_pacing= */ false);
+ EXPECT_EQ(10u, sender_->congestion_window());
+}
+
+TEST_F(TcpCubicSenderTest, DisableAckTrainDetectionWithPacing) {
+ EXPECT_TRUE(sender_->hybrid_slow_start().ack_train_detection());
+
+ QuicConfig config;
+ sender_->SetFromConfig(config,
+ /* is_server= */ true,
+ /* using_pacing= */ true);
+ EXPECT_FALSE(sender_->hybrid_slow_start().ack_train_detection());
}
TEST_F(TcpCubicSenderTest, 2ConnectionCongestionAvoidanceAtEndOfRecovery) {
diff --git a/net/quic/crypto/cached_network_parameters.cc b/net/quic/crypto/cached_network_parameters.cc
new file mode 100644
index 0000000..20a438b
--- /dev/null
+++ b/net/quic/crypto/cached_network_parameters.cc
@@ -0,0 +1,40 @@
+// Copyright (c) 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/quic/crypto/cached_network_parameters.h"
+
+namespace net {
+
+CachedNetworkParameters::CachedNetworkParameters()
+ : bandwidth_estimate_bytes_per_second_(0),
+ max_bandwidth_estimate_bytes_per_second_(0),
+ max_bandwidth_timestamp_seconds_(0),
+ min_rtt_ms_(0),
+ previous_connection_state_(0),
+ timestamp_(0) {
+}
+
+CachedNetworkParameters::~CachedNetworkParameters() {
+}
+
+bool CachedNetworkParameters::operator==(
+ const CachedNetworkParameters& other) const {
+ return serving_region_ == other.serving_region_ &&
+ bandwidth_estimate_bytes_per_second_ ==
+ other.bandwidth_estimate_bytes_per_second_ &&
+ max_bandwidth_estimate_bytes_per_second_ ==
+ other.max_bandwidth_estimate_bytes_per_second_ &&
+ max_bandwidth_timestamp_seconds_ ==
+ other.max_bandwidth_timestamp_seconds_ &&
+ min_rtt_ms_ == other.min_rtt_ms_ &&
+ previous_connection_state_ == other.previous_connection_state_ &&
+ timestamp_ == other.timestamp_;
+}
+
+bool CachedNetworkParameters::operator!=(
+ const CachedNetworkParameters& other) const {
+ return !(*this == other);
+}
+
+} // namespace net
diff --git a/net/quic/crypto/cached_network_parameters.h b/net/quic/crypto/cached_network_parameters.h
new file mode 100644
index 0000000..5f22070
--- /dev/null
+++ b/net/quic/crypto/cached_network_parameters.h
@@ -0,0 +1,109 @@
+// Copyright (c) 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_QUIC_CRYPTO_CACHED_NETWORK_PARAMETERS_H_
+#define NET_QUIC_CRYPTO_CACHED_NETWORK_PARAMETERS_H_
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/strings/string_piece.h"
+#include "net/base/net_export.h"
+
+namespace net {
+
+// TODO(rtenneti): sync with server more rationally.
+// CachedNetworkParameters contains data that can be used to choose appropriate
+// connection parameters (initial RTT, initial CWND, etc.) in new connections.
+class NET_EXPORT_PRIVATE CachedNetworkParameters {
+ public:
+ // Describes the state of the connection during which the supplied network
+ // parameters were calculated.
+ enum PreviousConnectionState {
+ SLOW_START = 0,
+ CONGESTION_AVOIDANCE = 1,
+ };
+
+ CachedNetworkParameters();
+ ~CachedNetworkParameters();
+
+ bool operator==(const CachedNetworkParameters& other) const;
+ bool operator!=(const CachedNetworkParameters& other) const;
+
+ std::string serving_region() const {
+ return serving_region_;
+ }
+ void set_serving_region(base::StringPiece serving_region) {
+ serving_region_ = serving_region.as_string();
+ }
+
+ int32 bandwidth_estimate_bytes_per_second() const {
+ return bandwidth_estimate_bytes_per_second_;
+ }
+ void set_bandwidth_estimate_bytes_per_second(
+ int32 bandwidth_estimate_bytes_per_second) {
+ bandwidth_estimate_bytes_per_second_ = bandwidth_estimate_bytes_per_second;
+ }
+
+ int32 max_bandwidth_estimate_bytes_per_second() const {
+ return max_bandwidth_estimate_bytes_per_second_;
+ }
+ void set_max_bandwidth_estimate_bytes_per_second(
+ int32 max_bandwidth_estimate_bytes_per_second) {
+ max_bandwidth_estimate_bytes_per_second_ =
+ max_bandwidth_estimate_bytes_per_second;
+ }
+
+ int64 max_bandwidth_timestamp_seconds() const {
+ return max_bandwidth_timestamp_seconds_;
+ }
+ void set_max_bandwidth_timestamp_seconds(
+ int64 max_bandwidth_timestamp_seconds) {
+ max_bandwidth_timestamp_seconds_ = max_bandwidth_timestamp_seconds;
+ }
+
+ int32 min_rtt_ms() const {
+ return min_rtt_ms_;
+ }
+ void set_min_rtt_ms(int32 min_rtt_ms) {
+ min_rtt_ms_ = min_rtt_ms;
+ }
+
+ int32 previous_connection_state() const {
+ return previous_connection_state_;
+ }
+ void set_previous_connection_state(int32 previous_connection_state) {
+ previous_connection_state_ = previous_connection_state;
+ }
+
+ int64 timestamp() const { return timestamp_; }
+ void set_timestamp(int64 timestamp) { timestamp_ = timestamp; }
+
+ private:
+ // serving_region_ is used to decide whether or not the bandwidth estimate and
+ // min RTT are reasonable and if they should be used.
+ // For example a group of geographically close servers may share the same
+ // serving_region_ string if they are expected to have similar network
+ // performance.
+ std::string serving_region_;
+ // The server can supply a bandwidth estimate (in bytes/s) which it may re-use
+ // on receipt of a source-address token with this field set.
+ int32 bandwidth_estimate_bytes_per_second_;
+ // The maximum bandwidth seen by the client, not necessarily the latest.
+ int32 max_bandwidth_estimate_bytes_per_second_;
+ // Timestamp (seconds since UNIX epoch) that indicates when the max bandwidth
+ // was seen by the server.
+ int64 max_bandwidth_timestamp_seconds_;
+ // The min RTT seen on a previous connection can be used by the server to
+ // inform initial connection parameters for new connections.
+ int32 min_rtt_ms_;
+ // Encodes the PreviousConnectionState enum.
+ int32 previous_connection_state_;
+ // UNIX timestamp when this bandwidth estimate was created.
+ int64 timestamp_;
+};
+
+} // namespace net
+
+#endif // NET_QUIC_CRYPTO_CACHED_NETWORK_PARAMETERS_H_
diff --git a/net/quic/crypto/quic_crypto_client_config.cc b/net/quic/crypto/quic_crypto_client_config.cc
index 4828c3a..268c8ee 100644
--- a/net/quic/crypto/quic_crypto_client_config.cc
+++ b/net/quic/crypto/quic_crypto_client_config.cc
@@ -847,8 +847,9 @@
break;
}
}
- if (i == canonical_suffixes_.size())
+ if (i == canonical_suffixes_.size()) {
return false;
+ }
QuicServerId suffix_server_id(canonical_suffixes_[i], server_id.port(),
server_id.is_https(),
diff --git a/net/quic/crypto/quic_crypto_server_config.h b/net/quic/crypto/quic_crypto_server_config.h
index dbbff1a..8a58aea 100644
--- a/net/quic/crypto/quic_crypto_server_config.h
+++ b/net/quic/crypto/quic_crypto_server_config.h
@@ -15,11 +15,11 @@
#include "base/synchronization/lock.h"
#include "net/base/ip_endpoint.h"
#include "net/base/net_export.h"
+#include "net/quic/crypto/cached_network_parameters.h"
#include "net/quic/crypto/crypto_handshake.h"
#include "net/quic/crypto/crypto_handshake_message.h"
#include "net/quic/crypto/crypto_protocol.h"
#include "net/quic/crypto/crypto_secret_boxer.h"
-#include "net/quic/crypto/source_address_token.h"
#include "net/quic/quic_time.h"
namespace net {
diff --git a/net/quic/crypto/source_address_token.cc b/net/quic/crypto/source_address_token.cc
index 0b514fe..5faedaa 100644
--- a/net/quic/crypto/source_address_token.cc
+++ b/net/quic/crypto/source_address_token.cc
@@ -11,37 +11,6 @@
namespace net {
-CachedNetworkParameters::CachedNetworkParameters()
- : bandwidth_estimate_bytes_per_second_(0),
- max_bandwidth_estimate_bytes_per_second_(0),
- max_bandwidth_timestamp_seconds_(0),
- min_rtt_ms_(0),
- previous_connection_state_(0),
- timestamp_(0) {
-}
-
-CachedNetworkParameters::~CachedNetworkParameters() {
-}
-
-bool CachedNetworkParameters::operator==(
- const CachedNetworkParameters& other) const {
- return serving_region_ == other.serving_region_ &&
- bandwidth_estimate_bytes_per_second_ ==
- other.bandwidth_estimate_bytes_per_second_ &&
- max_bandwidth_estimate_bytes_per_second_ ==
- other.max_bandwidth_estimate_bytes_per_second_ &&
- max_bandwidth_timestamp_seconds_ ==
- other.max_bandwidth_timestamp_seconds_ &&
- min_rtt_ms_ == other.min_rtt_ms_ &&
- previous_connection_state_ == other.previous_connection_state_ &&
- timestamp_ == other.timestamp_;
-}
-
-bool CachedNetworkParameters::operator!=(
- const CachedNetworkParameters& other) const {
- return !(*this == other);
-}
-
SourceAddressToken::SourceAddressToken()
: has_cached_network_parameters_(false) {
}
diff --git a/net/quic/crypto/source_address_token.h b/net/quic/crypto/source_address_token.h
index 76c3454..f9a5098 100644
--- a/net/quic/crypto/source_address_token.h
+++ b/net/quic/crypto/source_address_token.h
@@ -10,101 +10,11 @@
#include "base/basictypes.h"
#include "base/strings/string_piece.h"
#include "net/base/net_export.h"
+#include "net/quic/crypto/cached_network_parameters.h"
namespace net {
// TODO(rtenneti): sync with server more rationally.
-// CachedNetworkParameters contains data that can be used to choose appropriate
-// connection parameters (initial RTT, initial CWND, etc.) in new connections.
-class NET_EXPORT_PRIVATE CachedNetworkParameters {
- public:
- // Describes the state of the connection during which the supplied network
- // parameters were calculated.
- enum PreviousConnectionState {
- SLOW_START = 0,
- CONGESTION_AVOIDANCE = 1,
- };
-
- CachedNetworkParameters();
- ~CachedNetworkParameters();
-
- bool operator==(const CachedNetworkParameters& other) const;
- bool operator!=(const CachedNetworkParameters& other) const;
-
- std::string serving_region() const {
- return serving_region_;
- }
- void set_serving_region(base::StringPiece serving_region) {
- serving_region_ = serving_region.as_string();
- }
-
- int32 bandwidth_estimate_bytes_per_second() const {
- return bandwidth_estimate_bytes_per_second_;
- }
- void set_bandwidth_estimate_bytes_per_second(
- int32 bandwidth_estimate_bytes_per_second) {
- bandwidth_estimate_bytes_per_second_ = bandwidth_estimate_bytes_per_second;
- }
-
- int32 max_bandwidth_estimate_bytes_per_second() const {
- return max_bandwidth_estimate_bytes_per_second_;
- }
- void set_max_bandwidth_estimate_bytes_per_second(
- int32 max_bandwidth_estimate_bytes_per_second) {
- max_bandwidth_estimate_bytes_per_second_ =
- max_bandwidth_estimate_bytes_per_second;
- }
-
- int64 max_bandwidth_timestamp_seconds() const {
- return max_bandwidth_timestamp_seconds_;
- }
- void set_max_bandwidth_timestamp_seconds(
- int64 max_bandwidth_timestamp_seconds) {
- max_bandwidth_timestamp_seconds_ = max_bandwidth_timestamp_seconds;
- }
-
- int32 min_rtt_ms() const {
- return min_rtt_ms_;
- }
- void set_min_rtt_ms(int32 min_rtt_ms) {
- min_rtt_ms_ = min_rtt_ms;
- }
-
- int32 previous_connection_state() const {
- return previous_connection_state_;
- }
- void set_previous_connection_state(int32 previous_connection_state) {
- previous_connection_state_ = previous_connection_state;
- }
-
- int64 timestamp() const { return timestamp_; }
- void set_timestamp(int64 timestamp) { timestamp_ = timestamp; }
-
- private:
- // serving_region_ is used to decide whether or not the bandwidth estimate and
- // min RTT are reasonable and if they should be used.
- // For example a group of geographically close servers may share the same
- // serving_region_ string if they are expected to have similar network
- // performance.
- std::string serving_region_;
- // The server can supply a bandwidth estimate (in bytes/s) which it may re-use
- // on receipt of a source-address token with this field set.
- int32 bandwidth_estimate_bytes_per_second_;
- // The maximum bandwidth seen by the client, not necessarily the latest.
- int32 max_bandwidth_estimate_bytes_per_second_;
- // Timestamp (seconds since UNIX epoch) that indicates when the max bandwidth
- // was seen by the server.
- int64 max_bandwidth_timestamp_seconds_;
- // The min RTT seen on a previous connection can be used by the server to
- // inform initial connection parameters for new connections.
- int32 min_rtt_ms_;
- // Encodes the PreviousConnectionState enum.
- int32 previous_connection_state_;
- // UNIX timestamp when this bandwidth estimate was created.
- int64 timestamp_;
-};
-
-// TODO(rtenneti): sync with server more rationally.
// A SourceAddressToken is serialised, encrypted and sent to clients so that
// they can prove ownership of an IP address.
class NET_EXPORT_PRIVATE SourceAddressToken {
diff --git a/net/quic/quic_client_session.cc b/net/quic/quic_client_session.cc
index 73a5aec..274099c 100644
--- a/net/quic/quic_client_session.cc
+++ b/net/quic/quic_client_session.cc
@@ -155,10 +155,9 @@
TransportSecurityState* transport_security_state,
scoped_ptr<QuicServerInfo> server_info,
const QuicConfig& config,
- bool is_secure,
base::TaskRunner* task_runner,
NetLog* net_log)
- : QuicClientSessionBase(connection, config, is_secure),
+ : QuicClientSessionBase(connection, config),
require_confirmation_(false),
stream_factory_(stream_factory),
socket_(socket.Pass()),
diff --git a/net/quic/quic_client_session.h b/net/quic/quic_client_session.h
index 6c33eb5..b1a35d9 100644
--- a/net/quic/quic_client_session.h
+++ b/net/quic/quic_client_session.h
@@ -96,7 +96,6 @@
TransportSecurityState* transport_security_state,
scoped_ptr<QuicServerInfo> server_info,
const QuicConfig& config,
- bool is_secure,
base::TaskRunner* task_runner,
NetLog* net_log);
~QuicClientSession() override;
diff --git a/net/quic/quic_client_session_base.cc b/net/quic/quic_client_session_base.cc
index 5b5902b..40d4b86 100644
--- a/net/quic/quic_client_session_base.cc
+++ b/net/quic/quic_client_session_base.cc
@@ -10,9 +10,8 @@
QuicClientSessionBase::QuicClientSessionBase(
QuicConnection* connection,
- const QuicConfig& config,
- bool is_secure)
- : QuicSession(connection, config, is_secure) {}
+ const QuicConfig& config)
+ : QuicSession(connection, config) {}
QuicClientSessionBase::~QuicClientSessionBase() {}
diff --git a/net/quic/quic_client_session_base.h b/net/quic/quic_client_session_base.h
index a7f64fb..d72996c 100644
--- a/net/quic/quic_client_session_base.h
+++ b/net/quic/quic_client_session_base.h
@@ -14,8 +14,7 @@
class NET_EXPORT_PRIVATE QuicClientSessionBase : public QuicSession {
public:
QuicClientSessionBase(QuicConnection* connection,
- const QuicConfig& config,
- bool is_secure);
+ const QuicConfig& config);
~QuicClientSessionBase() override;
diff --git a/net/quic/quic_client_session_test.cc b/net/quic/quic_client_session_test.cc
index 8860f2e..66583b8 100644
--- a/net/quic/quic_client_session_test.cc
+++ b/net/quic/quic_client_session_test.cc
@@ -46,7 +46,6 @@
session_(connection_, GetSocket().Pass(), nullptr,
&transport_security_state_,
make_scoped_ptr((QuicServerInfo*)nullptr), DefaultQuicConfig(),
- /*is_secure=*/false,
base::MessageLoop::current()->message_loop_proxy().get(),
&net_log_) {
session_.InitializeSession(QuicServerId(kServerHostname, kServerPort,
diff --git a/net/quic/quic_config.cc b/net/quic/quic_config.cc
index b1b7343..622cf3f 100644
--- a/net/quic/quic_config.cc
+++ b/net/quic/quic_config.cc
@@ -434,7 +434,6 @@
keepalive_timeout_seconds_(kKATO, PRESENCE_OPTIONAL),
max_streams_per_connection_(kMSPC, PRESENCE_REQUIRED),
bytes_for_connection_id_(kTCID, PRESENCE_OPTIONAL),
- initial_congestion_window_(kSWND, PRESENCE_OPTIONAL),
initial_round_trip_time_us_(kIRTT, PRESENCE_OPTIONAL),
// TODO(rjshade): Remove this when retiring QUIC_VERSION_19.
initial_flow_control_window_bytes_(kIFCW, PRESENCE_OPTIONAL),
@@ -524,18 +523,6 @@
return bytes_for_connection_id_.GetReceivedValue();
}
-void QuicConfig::SetInitialCongestionWindowToSend(size_t initial_window) {
- initial_congestion_window_.SetSendValue(initial_window);
-}
-
-bool QuicConfig::HasReceivedInitialCongestionWindow() const {
- return initial_congestion_window_.HasReceivedValue();
-}
-
-uint32 QuicConfig::ReceivedInitialCongestionWindow() const {
- return initial_congestion_window_.GetReceivedValue();
-}
-
void QuicConfig::SetInitialRoundTripTimeUsToSend(size_t rtt) {
initial_round_trip_time_us_.SetSendValue(rtt);
}
@@ -675,7 +662,6 @@
keepalive_timeout_seconds_.ToHandshakeMessage(out);
max_streams_per_connection_.ToHandshakeMessage(out);
bytes_for_connection_id_.ToHandshakeMessage(out);
- initial_congestion_window_.ToHandshakeMessage(out);
initial_round_trip_time_us_.ToHandshakeMessage(out);
initial_flow_control_window_bytes_.ToHandshakeMessage(out);
initial_stream_flow_control_window_bytes_.ToHandshakeMessage(out);
@@ -712,10 +698,6 @@
peer_hello, hello_type, error_details);
}
if (error == QUIC_NO_ERROR) {
- error = initial_congestion_window_.ProcessPeerHello(
- peer_hello, hello_type, error_details);
- }
- if (error == QUIC_NO_ERROR) {
error = initial_round_trip_time_us_.ProcessPeerHello(
peer_hello, hello_type, error_details);
}
diff --git a/net/quic/quic_config.h b/net/quic/quic_config.h
index a4d6129..cf3775c 100644
--- a/net/quic/quic_config.h
+++ b/net/quic/quic_config.h
@@ -319,13 +319,6 @@
uint32 ReceivedBytesForConnectionId() const;
- // Sets the peer's default initial congestion window in packets.
- void SetInitialCongestionWindowToSend(size_t initial_window);
-
- bool HasReceivedInitialCongestionWindow() const;
-
- uint32 ReceivedInitialCongestionWindow() const;
-
// Sets an estimated initial round trip time in us.
void SetInitialRoundTripTimeUsToSend(size_t rtt_us);
@@ -413,8 +406,6 @@
QuicNegotiableUint32 max_streams_per_connection_;
// The number of bytes required for the connection ID.
QuicFixedUint32 bytes_for_connection_id_;
- // Initial congestion window in packets.
- QuicFixedUint32 initial_congestion_window_;
// Initial round trip time estimate in microseconds.
QuicFixedUint32 initial_round_trip_time_us_;
diff --git a/net/quic/quic_config_test.cc b/net/quic/quic_config_test.cc
index 914b137..413d7fb 100644
--- a/net/quic/quic_config_test.cc
+++ b/net/quic/quic_config_test.cc
@@ -81,8 +81,7 @@
QuicTime::Delta::FromSeconds(kMaximumIdleTimeoutSecs));
client_config.SetMaxStreamsPerConnection(
2 * kDefaultMaxStreamsPerConnection, kDefaultMaxStreamsPerConnection);
- client_config.SetInitialRoundTripTimeUsToSend(
- 10 * base::Time::kMicrosecondsPerMillisecond);
+ client_config.SetInitialRoundTripTimeUsToSend(10 * kNumMicrosPerMilli);
client_config.SetInitialFlowControlWindowToSend(
2 * kInitialSessionFlowControlWindowForTest);
client_config.SetInitialStreamFlowControlWindowToSend(
@@ -107,8 +106,7 @@
EXPECT_EQ(kDefaultMaxStreamsPerConnection,
config_.MaxStreamsPerConnection());
EXPECT_EQ(QuicTime::Delta::FromSeconds(0), config_.KeepaliveTimeout());
- EXPECT_EQ(10 * base::Time::kMicrosecondsPerMillisecond,
- config_.ReceivedInitialRoundTripTimeUs());
+ EXPECT_EQ(10 * kNumMicrosPerMilli, config_.ReceivedInitialRoundTripTimeUs());
EXPECT_TRUE(config_.HasReceivedConnectionOptions());
EXPECT_EQ(2u, config_.ReceivedConnectionOptions().size());
EXPECT_EQ(config_.ReceivedConnectionOptions()[0], kTBBR);
@@ -134,9 +132,7 @@
server_config.SetMaxStreamsPerConnection(
kDefaultMaxStreamsPerConnection / 2,
kDefaultMaxStreamsPerConnection / 2);
- server_config.SetInitialCongestionWindowToSend(kDefaultInitialWindow / 2);
- server_config.SetInitialRoundTripTimeUsToSend(
- 10 * base::Time::kMicrosecondsPerMillisecond);
+ server_config.SetInitialRoundTripTimeUsToSend(10 * kNumMicrosPerMilli);
server_config.SetInitialFlowControlWindowToSend(
2 * kInitialSessionFlowControlWindowForTest);
server_config.SetInitialStreamFlowControlWindowToSend(
@@ -156,11 +152,8 @@
config_.IdleConnectionStateLifetime());
EXPECT_EQ(kDefaultMaxStreamsPerConnection / 2,
config_.MaxStreamsPerConnection());
- EXPECT_EQ(kDefaultInitialWindow / 2,
- config_.ReceivedInitialCongestionWindow());
EXPECT_EQ(QuicTime::Delta::FromSeconds(0), config_.KeepaliveTimeout());
- EXPECT_EQ(10 * base::Time::kMicrosecondsPerMillisecond,
- config_.ReceivedInitialRoundTripTimeUs());
+ EXPECT_EQ(10 * kNumMicrosPerMilli, config_.ReceivedInitialRoundTripTimeUs());
EXPECT_EQ(config_.ReceivedInitialFlowControlWindowBytes(),
2 * kInitialSessionFlowControlWindowForTest);
EXPECT_EQ(config_.ReceivedInitialStreamFlowControlWindowBytes(),
diff --git a/net/quic/quic_connection.cc b/net/quic/quic_connection.cc
index 6308d88..fd9ec5f 100644
--- a/net/quic/quic_connection.cc
+++ b/net/quic/quic_connection.cc
@@ -189,6 +189,7 @@
const PacketWriterFactory& writer_factory,
bool owns_writer,
bool is_server,
+ bool is_secure,
const QuicVersionVector& supported_versions)
: framer_(supported_versions, helper->GetClock()->ApproximateNow(),
is_server),
@@ -222,9 +223,7 @@
timeout_alarm_(helper->CreateAlarm(new TimeoutAlarm(this))),
ping_alarm_(helper->CreateAlarm(new PingAlarm(this))),
packet_generator_(connection_id_, &framer_, random_generator_, this),
- idle_network_timeout_(FLAGS_quic_unified_timeouts ?
- QuicTime::Delta::Infinite() :
- QuicTime::Delta::FromSeconds(kDefaultIdleTimeoutSecs)),
+ idle_network_timeout_(QuicTime::Delta::Infinite()),
overall_connection_timeout_(QuicTime::Delta::Infinite()),
time_of_last_received_packet_(clock_->ApproximateNow()),
time_of_last_sent_new_packet_(clock_->ApproximateNow()),
@@ -232,7 +231,8 @@
sent_packet_manager_(
is_server, clock_, &stats_,
FLAGS_quic_use_bbr_congestion_control ? kBBR : kCubic,
- FLAGS_quic_use_time_loss_detection ? kTime : kNack),
+ FLAGS_quic_use_time_loss_detection ? kTime : kNack,
+ is_secure),
version_negotiation_state_(START_NEGOTIATION),
is_server_(is_server),
connected_(true),
@@ -240,12 +240,10 @@
peer_port_changed_(false),
self_ip_changed_(false),
self_port_changed_(false),
- can_truncate_connection_ids_(true) {
+ can_truncate_connection_ids_(true),
+ is_secure_(is_secure) {
DVLOG(1) << ENDPOINT << "Created connection with connection_id: "
<< connection_id;
- if (!FLAGS_quic_unified_timeouts) {
- timeout_alarm_->Set(clock_->ApproximateNow().Add(idle_network_timeout_));
- }
framer_.set_visitor(this);
framer_.set_received_entropy_calculator(&received_packet_manager_);
stats_.connection_creation_time = clock_->ApproximateNow();
@@ -266,17 +264,14 @@
}
void QuicConnection::SetFromConfig(const QuicConfig& config) {
- if (FLAGS_quic_unified_timeouts) {
- if (config.negotiated()) {
- SetNetworkTimeouts(QuicTime::Delta::Infinite(),
- config.IdleConnectionStateLifetime());
- } else {
- SetNetworkTimeouts(config.max_time_before_crypto_handshake(),
- config.max_idle_time_before_crypto_handshake());
- }
+ if (config.negotiated()) {
+ SetNetworkTimeouts(QuicTime::Delta::Infinite(),
+ config.IdleConnectionStateLifetime());
} else {
- SetIdleNetworkTimeout(config.IdleConnectionStateLifetime());
+ SetNetworkTimeouts(config.max_time_before_crypto_handshake(),
+ config.max_idle_time_before_crypto_handshake());
}
+
sent_packet_manager_.SetFromConfig(config);
if (FLAGS_allow_truncated_connection_ids_for_quic &&
config.HasReceivedBytesForConnectionId() &&
@@ -1898,11 +1893,11 @@
}
}
-size_t QuicConnection::max_packet_length() const {
+QuicByteCount QuicConnection::max_packet_length() const {
return packet_generator_.max_packet_length();
}
-void QuicConnection::set_max_packet_length(size_t length) {
+void QuicConnection::set_max_packet_length(QuicByteCount length) {
return packet_generator_.set_max_packet_length(length);
}
@@ -1928,32 +1923,6 @@
pending_handshake);
}
-void QuicConnection::SetIdleNetworkTimeout(QuicTime::Delta timeout) {
- // Adjust the idle timeout on client and server to prevent clients from
- // sending requests to servers which have already closed the connection.
- if (is_server_) {
- timeout = timeout.Add(QuicTime::Delta::FromSeconds(3));
- } else if (timeout > QuicTime::Delta::FromSeconds(1)) {
- timeout = timeout.Subtract(QuicTime::Delta::FromSeconds(1));
- }
-
- if (timeout < idle_network_timeout_) {
- idle_network_timeout_ = timeout;
- SetTimeoutAlarm();
- } else {
- idle_network_timeout_ = timeout;
- }
-}
-
-void QuicConnection::SetOverallConnectionTimeout(QuicTime::Delta timeout) {
- if (timeout < overall_connection_timeout_) {
- overall_connection_timeout_ = timeout;
- SetTimeoutAlarm();
- } else {
- overall_connection_timeout_ = timeout;
- }
-}
-
void QuicConnection::SetNetworkTimeouts(QuicTime::Delta overall_timeout,
QuicTime::Delta idle_timeout) {
LOG_IF(DFATAL, idle_timeout > overall_timeout)
diff --git a/net/quic/quic_connection.h b/net/quic/quic_connection.h
index f9f8733..96f5cbc 100644
--- a/net/quic/quic_connection.h
+++ b/net/quic/quic_connection.h
@@ -251,6 +251,7 @@
const PacketWriterFactory& writer_factory,
bool owns_writer,
bool is_server,
+ bool is_secure,
const QuicVersionVector& supported_versions);
~QuicConnection() override;
@@ -397,8 +398,8 @@
QuicConnectionId connection_id() const { return connection_id_; }
const QuicClock* clock() const { return clock_; }
QuicRandom* random_generator() const { return random_generator_; }
- size_t max_packet_length() const;
- void set_max_packet_length(size_t length);
+ QuicByteCount max_packet_length() const;
+ void set_max_packet_length(QuicByteCount length);
bool connected() const { return connected_; }
@@ -425,16 +426,6 @@
// Returns true if the connection has queued packets or frames.
bool HasQueuedData() const;
- // TODO(ianswett): Remove when quic_unified_timeouts is removed.
- // Sets (or resets) the idle state connection timeout. Also, checks and times
- // out the connection if network timer has expired for |timeout|.
- void SetIdleNetworkTimeout(QuicTime::Delta timeout);
-
- // Sets (or resets) the total time delta the connection can be alive for.
- // Used to limit the time a connection can be alive before crypto handshake
- // finishes.
- void SetOverallConnectionTimeout(QuicTime::Delta timeout);
-
// Sets the overall and idle state connection timeouts.
void SetNetworkTimeouts(QuicTime::Delta overall_timeout,
QuicTime::Delta idle_timeout);
@@ -530,6 +521,9 @@
QuicPacketSequenceNumber sequence_number_of_last_sent_packet() const {
return sequence_number_of_last_sent_packet_;
}
+ const QuicPacketWriter* writer() const { return writer_; }
+
+ bool is_secure() const { return is_secure_; }
protected:
// Packets which have not been written to the wire.
@@ -567,7 +561,6 @@
bool SelectMutualVersion(const QuicVersionVector& available_versions);
QuicPacketWriter* writer() { return writer_; }
- const QuicPacketWriter* writer() const { return writer_; }
bool peer_port_changed() const { return peer_port_changed_; }
@@ -702,7 +695,7 @@
// decrypted.
bool last_packet_decrypted_;
bool last_packet_revived_; // True if the last packet was revived from FEC.
- size_t last_size_; // Size of the last received packet.
+ QuicByteCount last_size_; // Size of the last received packet.
EncryptionLevel last_decrypted_packet_level_;
QuicPacketHeader last_header_;
std::vector<QuicStreamFrame> last_stream_frames_;
@@ -837,6 +830,9 @@
// version negotiation packet.
QuicVersionVector server_supported_versions_;
+ // True if this is a secure QUIC connection.
+ bool is_secure_;
+
DISALLOW_COPY_AND_ASSIGN(QuicConnection);
};
diff --git a/net/quic/quic_connection_test.cc b/net/quic/quic_connection_test.cc
index 66cb89c..4e58dfd 100644
--- a/net/quic/quic_connection_test.cc
+++ b/net/quic/quic_connection_test.cc
@@ -408,6 +408,7 @@
factory,
/* owns_writer= */ false,
is_server,
+ /* is_secure= */ false,
SupportedVersions(version)) {
// Disable tail loss probes for most tests.
QuicSentPacketManagerPeer::SetMaxTailLossProbes(
@@ -2506,7 +2507,7 @@
TEST_P(QuicConnectionTest, BufferNonDecryptablePackets) {
// SetFromConfig is always called after construction from InitializeSession.
- EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+ EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _, _));
QuicConfig config;
connection_.SetFromConfig(config);
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
@@ -2536,7 +2537,7 @@
TEST_P(QuicConnectionTest, Buffer100NonDecryptablePackets) {
// SetFromConfig is always called after construction from InitializeSession.
- EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+ EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _, _));
QuicConfig config;
config.set_max_undecryptable_packets(100);
connection_.SetFromConfig(config);
@@ -2775,36 +2776,12 @@
}
TEST_P(QuicConnectionTest, InitialTimeout) {
- if (!FLAGS_quic_unified_timeouts) {
- EXPECT_TRUE(connection_.connected());
- EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_CONNECTION_TIMED_OUT, false));
- EXPECT_CALL(*send_algorithm_,
- OnPacketSent(_, _, _, _, _)).Times(AnyNumber());
-
- QuicTime default_timeout = clock_.ApproximateNow().Add(
- QuicTime::Delta::FromSeconds(kDefaultIdleTimeoutSecs));
- EXPECT_EQ(default_timeout, connection_.GetTimeoutAlarm()->deadline());
-
- // Simulate the timeout alarm firing.
- clock_.AdvanceTime(QuicTime::Delta::FromSeconds(kDefaultIdleTimeoutSecs));
- connection_.GetTimeoutAlarm()->Fire();
-
- EXPECT_FALSE(connection_.GetTimeoutAlarm()->IsSet());
- EXPECT_FALSE(connection_.connected());
-
- EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
- EXPECT_FALSE(connection_.GetPingAlarm()->IsSet());
- EXPECT_FALSE(connection_.GetResumeWritesAlarm()->IsSet());
- EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet());
- EXPECT_FALSE(connection_.GetSendAlarm()->IsSet());
- return;
- }
EXPECT_TRUE(connection_.connected());
EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(AnyNumber());
EXPECT_FALSE(connection_.GetTimeoutAlarm()->IsSet());
// SetFromConfig sets the initial timeouts before negotiation.
- EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+ EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _, _));
QuicConfig config;
connection_.SetFromConfig(config);
// Subtract a second from the idle timeout on the client side.
@@ -2913,44 +2890,8 @@
}
TEST_P(QuicConnectionTest, TimeoutAfterSend) {
- if (!FLAGS_quic_unified_timeouts) {
- EXPECT_TRUE(connection_.connected());
-
- QuicTime default_timeout = clock_.ApproximateNow().Add(
- QuicTime::Delta::FromSeconds(kDefaultIdleTimeoutSecs));
-
- // When we send a packet, the timeout will change to 5000 +
- // kDefaultInitialTimeoutSecs.
- clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
-
- // Send an ack so we don't set the retransmission alarm.
- SendAckPacketToPeer();
- EXPECT_EQ(default_timeout, connection_.GetTimeoutAlarm()->deadline());
-
- // The original alarm will fire. We should not time out because we had a
- // network event at t=5000. The alarm will reregister.
- clock_.AdvanceTime(QuicTime::Delta::FromMicroseconds(
- kDefaultIdleTimeoutSecs * 1000000 - 5000));
- EXPECT_EQ(default_timeout, clock_.ApproximateNow());
- connection_.GetTimeoutAlarm()->Fire();
- EXPECT_TRUE(connection_.GetTimeoutAlarm()->IsSet());
- EXPECT_TRUE(connection_.connected());
- EXPECT_EQ(default_timeout.Add(QuicTime::Delta::FromMilliseconds(5)),
- connection_.GetTimeoutAlarm()->deadline());
-
- // This time, we should time out.
- EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_CONNECTION_TIMED_OUT, false));
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _));
- clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
- EXPECT_EQ(default_timeout.Add(QuicTime::Delta::FromMilliseconds(5)),
- clock_.ApproximateNow());
- connection_.GetTimeoutAlarm()->Fire();
- EXPECT_FALSE(connection_.GetTimeoutAlarm()->IsSet());
- EXPECT_FALSE(connection_.connected());
- return;
- }
EXPECT_TRUE(connection_.connected());
- EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+ EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _, _));
QuicConfig config;
connection_.SetFromConfig(config);
@@ -3055,7 +2996,7 @@
// Set up a larger payload than will fit in one packet.
const string payload(connection_.max_packet_length(), 'a');
- EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _)).Times(AnyNumber());
+ EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _, _)).Times(AnyNumber());
// Now send some packets with no truncation.
EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(2);
diff --git a/net/quic/quic_crypto_server_stream.cc b/net/quic/quic_crypto_server_stream.cc
index dac2087..1d62376 100644
--- a/net/quic/quic_crypto_server_stream.cc
+++ b/net/quic/quic_crypto_server_stream.cc
@@ -6,10 +6,10 @@
#include "base/base64.h"
#include "crypto/secure_hash.h"
+#include "net/quic/crypto/cached_network_parameters.h"
#include "net/quic/crypto/crypto_protocol.h"
#include "net/quic/crypto/crypto_utils.h"
#include "net/quic/crypto/quic_crypto_server_config.h"
-#include "net/quic/crypto/source_address_token.h"
#include "net/quic/quic_config.h"
#include "net/quic/quic_flags.h"
#include "net/quic/quic_protocol.h"
diff --git a/net/quic/quic_dispatcher.cc b/net/quic/quic_dispatcher.cc
index aede7c2..d27b454 100644
--- a/net/quic/quic_dispatcher.cc
+++ b/net/quic/quic_dispatcher.cc
@@ -352,8 +352,7 @@
QuicServerSession* session = new QuicServerSession(
config_,
CreateQuicConnection(connection_id, server_address, client_address),
- this,
- crypto_config_.HasProofSource());
+ this);
session->InitializeSession(crypto_config_);
return session;
}
@@ -368,6 +367,7 @@
connection_writer_factory_,
/* owns_writer= */ true,
/* is_server= */ true,
+ crypto_config_.HasProofSource(),
supported_versions_);
}
diff --git a/net/quic/quic_flags.cc b/net/quic/quic_flags.cc
index 8d6dd86..47d58ce 100644
--- a/net/quic/quic_flags.cc
+++ b/net/quic/quic_flags.cc
@@ -36,10 +36,6 @@
// limit.
bool FLAGS_quic_allow_more_open_streams = false;
-// If true, then QUIC connections will set both idle and overall timeouts in a
-// single method.
-bool FLAGS_quic_unified_timeouts = true;
-
// If true, QUIC will be more resilliant to junk packets with valid connection
// IDs.
bool FLAGS_quic_drop_junk_packets = true;
diff --git a/net/quic/quic_flags.h b/net/quic/quic_flags.h
index d49f47a..a75f79b 100644
--- a/net/quic/quic_flags.h
+++ b/net/quic/quic_flags.h
@@ -15,7 +15,6 @@
NET_EXPORT_PRIVATE extern bool FLAGS_enable_quic_fec;
NET_EXPORT_PRIVATE extern bool FLAGS_quic_use_bbr_congestion_control;
NET_EXPORT_PRIVATE extern bool FLAGS_quic_allow_more_open_streams;
-NET_EXPORT_PRIVATE extern bool FLAGS_quic_unified_timeouts;
NET_EXPORT_PRIVATE extern bool FLAGS_quic_drop_junk_packets;
NET_EXPORT_PRIVATE extern bool FLAGS_quic_allow_bbr;
NET_EXPORT_PRIVATE extern bool FLAGS_allow_truncated_connection_ids_for_quic;
diff --git a/net/quic/quic_framer.cc b/net/quic/quic_framer.cc
index e2487b4..d2a7694 100644
--- a/net/quic/quic_framer.cc
+++ b/net/quic/quic_framer.cc
@@ -978,30 +978,30 @@
QuicFramer::AckFrameInfo QuicFramer::GetAckFrameInfo(
const QuicAckFrame& frame) {
AckFrameInfo ack_info;
- if (!frame.missing_packets.empty()) {
- DCHECK_GE(frame.largest_observed, *frame.missing_packets.rbegin());
- size_t cur_range_length = 0;
- SequenceNumberSet::const_iterator iter = frame.missing_packets.begin();
- QuicPacketSequenceNumber last_missing = *iter;
- ++iter;
- for (; iter != frame.missing_packets.end(); ++iter) {
- if (cur_range_length != numeric_limits<uint8>::max() &&
- *iter == (last_missing + 1)) {
- ++cur_range_length;
- } else {
- ack_info.nack_ranges[last_missing - cur_range_length] =
- cur_range_length;
- cur_range_length = 0;
- }
- ack_info.max_delta = max(ack_info.max_delta, *iter - last_missing);
- last_missing = *iter;
- }
- // Include the last nack range.
- ack_info.nack_ranges[last_missing - cur_range_length] = cur_range_length;
- // Include the range to the largest observed.
- ack_info.max_delta = max(ack_info.max_delta,
- frame.largest_observed - last_missing);
+ if (frame.missing_packets.empty()) {
+ return ack_info;
}
+ DCHECK_GE(frame.largest_observed, *frame.missing_packets.rbegin());
+ size_t cur_range_length = 0;
+ SequenceNumberSet::const_iterator iter = frame.missing_packets.begin();
+ QuicPacketSequenceNumber last_missing = *iter;
+ ++iter;
+ for (; iter != frame.missing_packets.end(); ++iter) {
+ if (cur_range_length != numeric_limits<uint8>::max() &&
+ *iter == (last_missing + 1)) {
+ ++cur_range_length;
+ } else {
+ ack_info.nack_ranges[last_missing - cur_range_length] = cur_range_length;
+ cur_range_length = 0;
+ }
+ ack_info.max_delta = max(ack_info.max_delta, *iter - last_missing);
+ last_missing = *iter;
+ }
+ // Include the last nack range.
+ ack_info.nack_ranges[last_missing - cur_range_length] = cur_range_length;
+ // Include the range to the largest observed.
+ ack_info.max_delta =
+ max(ack_info.max_delta, frame.largest_observed - last_missing);
return ack_info;
}
diff --git a/net/quic/quic_http_stream_test.cc b/net/quic/quic_http_stream_test.cc
index db97aac..a172c24 100644
--- a/net/quic/quic_http_stream_test.cc
+++ b/net/quic/quic_http_stream_test.cc
@@ -65,8 +65,9 @@
address,
helper,
writer_factory,
- true /* owns_writer */,
+ true /* owns_writer */,
false /* is_server */,
+ false /* is_secure */,
versions) {
}
@@ -215,7 +216,7 @@
WillRepeatedly(Return(QuicTime::Delta::Zero()));
EXPECT_CALL(*send_algorithm_, BandwidthEstimate()).WillRepeatedly(
Return(QuicBandwidth::Zero()));
- EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _)).Times(AnyNumber());
+ EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _, _)).Times(AnyNumber());
helper_.reset(new QuicConnectionHelper(runner_.get(), &clock_,
&random_generator_));
TestPacketWriterFactory writer_factory(socket);
@@ -232,7 +233,6 @@
&transport_security_state_,
make_scoped_ptr((QuicServerInfo*)nullptr),
DefaultQuicConfig(),
- /*is_secure=*/false,
base::MessageLoop::current()->
message_loop_proxy().get(),
nullptr));
diff --git a/net/quic/quic_packet_creator.h b/net/quic/quic_packet_creator.h
index 287cde1..bada2c3 100644
--- a/net/quic/quic_packet_creator.h
+++ b/net/quic/quic_packet_creator.h
@@ -212,11 +212,11 @@
next_sequence_number_length_ = length;
}
- size_t max_packet_length() const {
+ QuicByteCount max_packet_length() const {
return max_packet_length_;
}
- void set_max_packet_length(size_t length) {
+ void set_max_packet_length(QuicByteCount length) {
// |max_packet_length_| should not be changed mid-packet or mid-FEC group.
DCHECK(fec_group_.get() == nullptr && queued_frames_.empty());
max_packet_length_ = length;
@@ -272,7 +272,7 @@
// packet.
bool send_version_in_packet_;
// Maximum length including headers and encryption (UDP payload length.)
- size_t max_packet_length_;
+ QuicByteCount max_packet_length_;
// 0 indicates FEC is disabled.
size_t max_packets_per_fec_group_;
// Length of connection_id to send over the wire.
diff --git a/net/quic/quic_packet_generator.cc b/net/quic/quic_packet_generator.cc
index 2481ddc..21ab10c 100644
--- a/net/quic/quic_packet_generator.cc
+++ b/net/quic/quic_packet_generator.cc
@@ -357,11 +357,11 @@
return packet_creator_.sequence_number();
}
-size_t QuicPacketGenerator::max_packet_length() const {
+QuicByteCount QuicPacketGenerator::max_packet_length() const {
return packet_creator_.max_packet_length();
}
-void QuicPacketGenerator::set_max_packet_length(size_t length) {
+void QuicPacketGenerator::set_max_packet_length(QuicByteCount length) {
packet_creator_.set_max_packet_length(length);
}
diff --git a/net/quic/quic_packet_generator.h b/net/quic/quic_packet_generator.h
index 3fec02a..2882aab 100644
--- a/net/quic/quic_packet_generator.h
+++ b/net/quic/quic_packet_generator.h
@@ -177,9 +177,9 @@
// created.
QuicPacketSequenceNumber sequence_number() const;
- size_t max_packet_length() const;
+ QuicByteCount max_packet_length() const;
- void set_max_packet_length(size_t length);
+ void set_max_packet_length(QuicByteCount length);
void set_debug_delegate(DebugDelegate* debug_delegate) {
debug_delegate_ = debug_delegate;
diff --git a/net/quic/quic_protocol.h b/net/quic/quic_protocol.h
index ad920d0..00064ff 100644
--- a/net/quic/quic_protocol.h
+++ b/net/quic/quic_protocol.h
@@ -60,8 +60,11 @@
const QuicByteCount kDefaultTCPMSS = 1460;
// Maximum size of the initial congestion window in packets.
-const QuicPacketCount kDefaultInitialWindow = 10;
const QuicPacketCount kMaxInitialWindow = 100;
+// We match SPDY's use of 32 when secure (since we'd compete with SPDY).
+const QuicPacketCount kInitialCongestionWindowSecure = 32;
+// Be conservative, and just use double a typical TCP ICWND for HTTP.
+const QuicPacketCount kInitialCongestionWindowInsecure = 20;
// Default size of initial flow control window, for both stream and session.
const uint32 kDefaultFlowControlSendWindow = 16 * 1024; // 16 KB
diff --git a/net/quic/quic_reliable_client_stream.cc b/net/quic/quic_reliable_client_stream.cc
index e186b03..68651cb 100644
--- a/net/quic/quic_reliable_client_stream.cc
+++ b/net/quic/quic_reliable_client_stream.cc
@@ -83,7 +83,7 @@
void QuicReliableClientStream::SetDelegate(
QuicReliableClientStream::Delegate* delegate) {
- DCHECK((!delegate_ && delegate) || (delegate_ && !delegate));
+ DCHECK(!(delegate_ && delegate));
delegate_ = delegate;
}
diff --git a/net/quic/quic_sent_packet_manager.cc b/net/quic/quic_sent_packet_manager.cc
index 9e2d04f..7978fed 100644
--- a/net/quic/quic_sent_packet_manager.cc
+++ b/net/quic/quic_sent_packet_manager.cc
@@ -34,8 +34,8 @@
static const int64 kMaxRetransmissionTimeMs = 60000;
static const size_t kMaxRetransmissions = 10;
-// Only exponentially back off the handshake timer 5 times due to a timeout.
-static const size_t kMaxHandshakeRetransmissionBackoffs = 5;
+// Ensure the handshake timer isnt't faster than 10ms.
+// This limits the tenth retransmitted packet to 10s after the initial CHLO.
static const int64 kMinHandshakeTimeoutMs = 10;
// Sends up to two tail loss probes before firing an RTO,
@@ -49,6 +49,10 @@
// Number of unpaced packets to send after quiescence.
static const size_t kInitialUnpacedBurst = 10;
+// Fraction of the receive buffer that can be used for encrypted bytes.
+// Allows a 5% overhead for IP and UDP framing, as well as ack only packets.
+static const float kUsableRecieveBufferFraction = 0.95f;
+
bool HasCryptoHandshake(const TransmissionInfo& transmission_info) {
if (transmission_info.retransmittable_frames == nullptr) {
return false;
@@ -66,17 +70,22 @@
const QuicClock* clock,
QuicConnectionStats* stats,
CongestionControlType congestion_control_type,
- LossDetectionType loss_type)
+ LossDetectionType loss_type,
+ bool is_secure)
: unacked_packets_(),
is_server_(is_server),
clock_(clock),
stats_(stats),
debug_delegate_(nullptr),
network_change_visitor_(nullptr),
- send_algorithm_(SendAlgorithmInterface::Create(clock,
- &rtt_stats_,
- congestion_control_type,
- stats)),
+ initial_congestion_window_(is_secure ? kInitialCongestionWindowSecure
+ : kInitialCongestionWindowInsecure),
+ send_algorithm_(
+ SendAlgorithmInterface::Create(clock,
+ &rtt_stats_,
+ congestion_control_type,
+ stats,
+ initial_congestion_window_)),
loss_algorithm_(LossDetectionInterface::Create(loss_type)),
n_connection_simulation_(false),
receive_buffer_bytes_(kDefaultSocketReceiveBuffer),
@@ -116,15 +125,17 @@
rtt_stats_.set_recent_min_rtt_window(
QuicTime::Delta::FromSeconds(FLAGS_quic_recent_min_rtt_window_s));
}
- send_algorithm_.reset(
- SendAlgorithmInterface::Create(clock_, &rtt_stats_, kBBR, stats_));
+ send_algorithm_.reset(SendAlgorithmInterface::Create(
+ clock_, &rtt_stats_, kBBR, stats_, initial_congestion_window_));
}
if (config.HasReceivedConnectionOptions() &&
ContainsQuicTag(config.ReceivedConnectionOptions(), kRENO)) {
- send_algorithm_.reset(
- SendAlgorithmInterface::Create(clock_, &rtt_stats_, kReno, stats_));
+ send_algorithm_.reset(SendAlgorithmInterface::Create(
+ clock_, &rtt_stats_, kReno, stats_, initial_congestion_window_));
}
- if (HasClientSentConnectionOption(config, kPACE)) {
+ if (HasClientSentConnectionOption(config, kPACE) ||
+ (FLAGS_quic_allow_bbr &&
+ HasClientSentConnectionOption(config, kTBBR))) {
EnablePacing();
}
if (HasClientSentConnectionOption(config, k1CON)) {
@@ -145,7 +156,7 @@
max(kMinSocketReceiveBuffer,
static_cast<QuicByteCount>(config.ReceivedSocketReceiveBuffer()));
}
- send_algorithm_->SetFromConfig(config, is_server_);
+ send_algorithm_->SetFromConfig(config, is_server_, using_pacing_);
if (network_change_visitor_ != nullptr) {
network_change_visitor_->OnCongestionWindowChange();
@@ -595,10 +606,7 @@
void QuicSentPacketManager::RetransmitCryptoPackets() {
DCHECK_EQ(HANDSHAKE_MODE, GetRetransmissionMode());
- // TODO(ianswett): Typical TCP implementations only retransmit 5 times.
- consecutive_crypto_retransmission_count_ =
- min(kMaxHandshakeRetransmissionBackoffs,
- consecutive_crypto_retransmission_count_ + 1);
+ ++consecutive_crypto_retransmission_count_;
bool packet_retransmitted = false;
QuicPacketSequenceNumber sequence_number = unacked_packets_.GetLeastUnacked();
for (QuicUnackedPacketMap::const_iterator it = unacked_packets_.begin();
@@ -757,7 +765,8 @@
if (pending_timer_transmission_count_ > 0) {
return QuicTime::Delta::Zero();
}
- if (unacked_packets_.bytes_in_flight() >= receive_buffer_bytes_) {
+ if (unacked_packets_.bytes_in_flight() >=
+ kUsableRecieveBufferFraction * receive_buffer_bytes_) {
return QuicTime::Delta::Infinite();
}
return send_algorithm_->TimeUntilSend(
diff --git a/net/quic/quic_sent_packet_manager.h b/net/quic/quic_sent_packet_manager.h
index f82e34b..2a3ea64 100644
--- a/net/quic/quic_sent_packet_manager.h
+++ b/net/quic/quic_sent_packet_manager.h
@@ -93,7 +93,8 @@
const QuicClock* clock,
QuicConnectionStats* stats,
CongestionControlType congestion_control_type,
- LossDetectionType loss_type);
+ LossDetectionType loss_type,
+ bool is_secure);
virtual ~QuicSentPacketManager();
virtual void SetFromConfig(const QuicConfig& config);
@@ -351,6 +352,7 @@
QuicConnectionStats* stats_;
DebugDelegate* debug_delegate_;
NetworkChangeVisitor* network_change_visitor_;
+ const QuicPacketCount initial_congestion_window_;
RttStats rtt_stats_;
scoped_ptr<SendAlgorithmInterface> send_algorithm_;
scoped_ptr<LossDetectionInterface> loss_algorithm_;
diff --git a/net/quic/quic_sent_packet_manager_test.cc b/net/quic/quic_sent_packet_manager_test.cc
index d7a846a..d710120 100644
--- a/net/quic/quic_sent_packet_manager_test.cc
+++ b/net/quic/quic_sent_packet_manager_test.cc
@@ -45,7 +45,7 @@
class QuicSentPacketManagerTest : public ::testing::TestWithParam<bool> {
protected:
QuicSentPacketManagerTest()
- : manager_(true, &clock_, &stats_, kCubic, kNack),
+ : manager_(true, &clock_, &stats_, kCubic, kNack, false),
send_algorithm_(new StrictMock<MockSendAlgorithm>),
network_change_visitor_(new StrictMock<MockNetworkChangeVisitor>) {
QuicSentPacketManagerPeer::SetSendAlgorithm(&manager_, send_algorithm_);
@@ -1080,12 +1080,12 @@
// Check the min.
RttStats* rtt_stats = QuicSentPacketManagerPeer::GetRttStats(&manager_);
- rtt_stats->set_initial_rtt_us(1 * base::Time::kMicrosecondsPerMillisecond);
+ rtt_stats->set_initial_rtt_us(1 * kNumMicrosPerMilli);
EXPECT_EQ(clock_.Now().Add(QuicTime::Delta::FromMilliseconds(10)),
manager_.GetRetransmissionTime());
// Test with a standard smoothed RTT.
- rtt_stats->set_initial_rtt_us(100 * base::Time::kMicrosecondsPerMillisecond);
+ rtt_stats->set_initial_rtt_us(100 * kNumMicrosPerMilli);
QuicTime::Delta srtt =
QuicTime::Delta::FromMicroseconds(rtt_stats->initial_rtt_us());
@@ -1109,12 +1109,12 @@
// Check the min.
RttStats* rtt_stats = QuicSentPacketManagerPeer::GetRttStats(&manager_);
- rtt_stats->set_initial_rtt_us(1 * base::Time::kMicrosecondsPerMillisecond);
+ rtt_stats->set_initial_rtt_us(1 * kNumMicrosPerMilli);
EXPECT_EQ(clock_.Now().Add(QuicTime::Delta::FromMilliseconds(10)),
manager_.GetRetransmissionTime());
// Test with a standard smoothed RTT.
- rtt_stats->set_initial_rtt_us(100 * base::Time::kMicrosecondsPerMillisecond);
+ rtt_stats->set_initial_rtt_us(100 * kNumMicrosPerMilli);
QuicTime::Delta srtt =
QuicTime::Delta::FromMicroseconds(rtt_stats->initial_rtt_us());
QuicTime::Delta expected_tlp_delay = srtt.Multiply(2);
@@ -1277,7 +1277,7 @@
QuicTagVector options;
options.push_back(kTIME);
QuicConfigPeer::SetReceivedConnectionOptions(&config, options);
- EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+ EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _, _));
EXPECT_CALL(*network_change_visitor_, OnCongestionWindowChange());
manager_.SetFromConfig(config);
@@ -1318,7 +1318,7 @@
QuicConfigPeer::SetReceivedConnectionOptions(&config, options);
EXPECT_CALL(*network_change_visitor_, OnCongestionWindowChange());
EXPECT_CALL(*send_algorithm_, SetNumEmulatedConnections(1));
- EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+ EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _, _));
manager_.SetFromConfig(config);
QuicSentPacketManagerPeer::SetIsServer(&manager_, false);
@@ -1326,7 +1326,7 @@
client_config.SetConnectionOptionsToSend(options);
EXPECT_CALL(*network_change_visitor_, OnCongestionWindowChange());
EXPECT_CALL(*send_algorithm_, SetNumEmulatedConnections(1));
- EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+ EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _, _));
manager_.SetFromConfig(client_config);
}
@@ -1340,7 +1340,7 @@
options.push_back(kNCON);
QuicConfigPeer::SetReceivedConnectionOptions(&config, options);
EXPECT_CALL(*network_change_visitor_, OnCongestionWindowChange());
- EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+ EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _, _));
manager_.SetFromConfig(config);
EXPECT_CALL(*send_algorithm_, SetNumEmulatedConnections(5));
@@ -1354,7 +1354,7 @@
options.push_back(kNTLP);
QuicConfigPeer::SetReceivedConnectionOptions(&config, options);
EXPECT_CALL(*network_change_visitor_, OnCongestionWindowChange());
- EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+ EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _, _));
manager_.SetFromConfig(config);
EXPECT_EQ(0u, QuicSentPacketManagerPeer::GetMaxTailLossProbes(&manager_));
}
@@ -1367,7 +1367,7 @@
QuicSentPacketManagerPeer::SetIsServer(&manager_, false);
client_config.SetConnectionOptionsToSend(options);
EXPECT_CALL(*network_change_visitor_, OnCongestionWindowChange());
- EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+ EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _, _));
manager_.SetFromConfig(client_config);
EXPECT_EQ(0u, QuicSentPacketManagerPeer::GetMaxTailLossProbes(&manager_));
}
@@ -1380,7 +1380,7 @@
options.push_back(kPACE);
QuicConfigPeer::SetReceivedConnectionOptions(&config, options);
EXPECT_CALL(*network_change_visitor_, OnCongestionWindowChange());
- EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+ EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _, /* using_pacing= */ true));
manager_.SetFromConfig(config);
EXPECT_TRUE(manager_.using_pacing());
@@ -1393,7 +1393,7 @@
// Try to set a size below the minimum and ensure it gets set to the min.
QuicConfig client_config;
QuicConfigPeer::SetReceivedSocketReceiveBuffer(&client_config, 1024);
- EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+ EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _, _));
EXPECT_CALL(*network_change_visitor_, OnCongestionWindowChange());
manager_.SetFromConfig(client_config);
@@ -1417,6 +1417,27 @@
manager_.TimeUntilSend(clock_.Now(), HAS_RETRANSMITTABLE_DATA));
}
+TEST_F(QuicSentPacketManagerTest, ReceiveWindowLimited) {
+ EXPECT_EQ(kDefaultSocketReceiveBuffer,
+ QuicSentPacketManagerPeer::GetReceiveWindow(&manager_));
+
+ // Ensure the smaller send window only allows 256 * 0.95 packets to be sent.
+ for (QuicPacketSequenceNumber i = 1; i <= 244; ++i) {
+ EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, _, _)).WillOnce(Return(
+ QuicTime::Delta::Zero()));
+ EXPECT_EQ(QuicTime::Delta::Zero(),
+ manager_.TimeUntilSend(clock_.Now(), HAS_RETRANSMITTABLE_DATA));
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, BytesInFlight(), i,
+ 1024, HAS_RETRANSMITTABLE_DATA))
+ .WillOnce(Return(true));
+ SerializedPacket packet(CreatePacket(i, true));
+ manager_.OnPacketSent(&packet, 0, clock_.Now(), 1024,
+ NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA);
+ }
+ EXPECT_EQ(QuicTime::Delta::Infinite(),
+ manager_.TimeUntilSend(clock_.Now(), HAS_RETRANSMITTABLE_DATA));
+}
+
TEST_F(QuicSentPacketManagerTest, UseInitialRoundTripTimeToSend) {
uint32 initial_rtt_us = 325000;
EXPECT_NE(initial_rtt_us,
@@ -1424,7 +1445,7 @@
QuicConfig config;
config.SetInitialRoundTripTimeUsToSend(initial_rtt_us);
- EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+ EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _, _));
EXPECT_CALL(*network_change_visitor_, OnCongestionWindowChange());
manager_.SetFromConfig(config);
diff --git a/net/quic/quic_server_session.cc b/net/quic/quic_server_session.cc
index 7fab509..1d48182 100644
--- a/net/quic/quic_server_session.cc
+++ b/net/quic/quic_server_session.cc
@@ -5,7 +5,7 @@
#include "net/quic/quic_server_session.h"
#include "base/logging.h"
-#include "net/quic/crypto/source_address_token.h"
+#include "net/quic/crypto/cached_network_parameters.h"
#include "net/quic/quic_connection.h"
#include "net/quic/quic_flags.h"
#include "net/quic/quic_spdy_server_stream.h"
@@ -15,9 +15,8 @@
QuicServerSession::QuicServerSession(const QuicConfig& config,
QuicConnection* connection,
- QuicServerSessionVisitor* visitor,
- bool is_secure)
- : QuicSession(connection, config, is_secure),
+ QuicServerSessionVisitor* visitor)
+ : QuicSession(connection, config),
visitor_(visitor),
bandwidth_estimate_sent_to_client_(QuicBandwidth::Zero()),
last_scup_time_(QuicTime::Zero()),
diff --git a/net/quic/quic_server_session.h b/net/quic/quic_server_session.h
index a402005..43107a0 100644
--- a/net/quic/quic_server_session.h
+++ b/net/quic/quic_server_session.h
@@ -46,8 +46,7 @@
public:
QuicServerSession(const QuicConfig& config,
QuicConnection* connection,
- QuicServerSessionVisitor* visitor,
- bool is_secure);
+ QuicServerSessionVisitor* visitor);
// Override the base class to notify the owner of the connection close.
void OnConnectionClosed(QuicErrorCode error, bool from_peer) override;
diff --git a/net/quic/quic_session.cc b/net/quic/quic_session.cc
index 34a668d..2318ab4 100644
--- a/net/quic/quic_session.cc
+++ b/net/quic/quic_session.cc
@@ -95,8 +95,7 @@
QuicSession* session_;
};
-QuicSession::QuicSession(QuicConnection* connection, const QuicConfig& config,
- bool is_secure)
+QuicSession::QuicSession(QuicConnection* connection, const QuicConfig& config)
: connection_(connection),
visitor_shim_(new VisitorShim(this)),
config_(config),
@@ -106,8 +105,7 @@
error_(QUIC_NO_ERROR),
goaway_received_(false),
goaway_sent_(false),
- has_pending_handshake_(false),
- is_secure_(is_secure) {
+ has_pending_handshake_(false) {
if (connection_->version() == QUIC_VERSION_19) {
flow_controller_.reset(new QuicFlowController(
connection_.get(), 0, is_server(), kDefaultFlowControlSendWindow,
@@ -124,10 +122,6 @@
void QuicSession::InitializeSession() {
connection_->set_visitor(visitor_shim_.get());
connection_->SetFromConfig(config_);
- if (!FLAGS_quic_unified_timeouts && connection_->connected()) {
- connection_->SetOverallConnectionTimeout(
- config_.max_time_before_crypto_handshake());
- }
headers_stream_.reset(new QuicHeadersStream(this));
}
@@ -569,9 +563,6 @@
// Discard originally encrypted packets, since they can't be decrypted by
// the peer.
connection_->NeuterUnencryptedPackets();
- if (!FLAGS_quic_unified_timeouts) {
- connection_->SetOverallConnectionTimeout(QuicTime::Delta::Infinite());
- }
if (!FLAGS_quic_allow_more_open_streams) {
max_open_streams_ = config_.MaxStreamsPerConnection();
}
diff --git a/net/quic/quic_session.h b/net/quic/quic_session.h
index 6ca9ce0..43f4042 100644
--- a/net/quic/quic_session.h
+++ b/net/quic/quic_session.h
@@ -52,9 +52,7 @@
HANDSHAKE_CONFIRMED,
};
- QuicSession(QuicConnection* connection,
- const QuicConfig& config,
- bool is_secure);
+ QuicSession(QuicConnection* connection, const QuicConfig& config);
void InitializeSession();
~QuicSession() override;
@@ -212,8 +210,8 @@
bool IsStreamFlowControlBlocked();
// Returns true if this is a secure QUIC session.
- bool is_secure() const {
- return is_secure_;
+ bool IsSecure() const {
+ return connection()->is_secure();
}
size_t get_max_open_streams() const { return max_open_streams_; }
diff --git a/net/quic/quic_session_test.cc b/net/quic/quic_session_test.cc
index edbfbee..d14d875 100644
--- a/net/quic/quic_session_test.cc
+++ b/net/quic/quic_session_test.cc
@@ -125,9 +125,7 @@
class TestSession : public QuicSession {
public:
explicit TestSession(QuicConnection* connection)
- : QuicSession(connection,
- DefaultQuicConfig(),
- false),
+ : QuicSession(connection, DefaultQuicConfig()),
crypto_stream_(this),
writev_consumes_all_data_(false) {
InitializeSession();
@@ -580,8 +578,7 @@
}
TEST_P(QuicSessionTest, IncreasedTimeoutAfterCryptoHandshake) {
- EXPECT_EQ((FLAGS_quic_unified_timeouts ?
- kInitialIdleTimeoutSecs : kDefaultIdleTimeoutSecs) + 3,
+ EXPECT_EQ(kInitialIdleTimeoutSecs + 3,
QuicConnectionPeer::GetNetworkTimeout(connection_).ToSeconds());
CryptoHandshakeMessage msg;
session_.GetCryptoStream()->OnHandshakeMessage(msg);
diff --git a/net/quic/quic_stream_factory.cc b/net/quic/quic_stream_factory.cc
index 076797a..32adeda 100644
--- a/net/quic/quic_stream_factory.cc
+++ b/net/quic/quic_stream_factory.cc
@@ -60,16 +60,6 @@
// The initial receive window size for both streams and sessions.
const int32 kInitialReceiveWindowSize = 10 * 1024 * 1024; // 10MB
-// The suggested initial congestion windows for a server to use.
-// TODO: This should be tested and optimized, and even better, suggest a window
-// that corresponds to historical bandwidth and min-RTT.
-// Larger initial congestion windows can, if we don't overshoot, reduce latency
-// by avoiding the RTT needed for slow start to double (and re-double) from a
-// default of 10.
-// We match SPDY's use of 32 when secure (since we'd compete with SPDY).
-const int32 kServerSecureInitialCongestionWindow = 32;
-// Be conservative, and just use double a typical TCP ICWND for HTTP.
-const int32 kServerInecureInitialCongestionWindow = 20;
// Set the maximum number of undecryptable packets the connection will store.
const int32 kMaxUndecryptablePackets = 100;
@@ -922,15 +912,13 @@
packet_writer_factory,
true /* owns_writer */,
false /* is_server */,
+ server_id.is_https(),
supported_versions_);
connection->set_max_packet_length(max_packet_length_);
InitializeCachedStateInCryptoConfig(server_id, server_info);
QuicConfig config = config_;
- config.SetInitialCongestionWindowToSend(
- server_id.is_https() ? kServerSecureInitialCongestionWindow
- : kServerInecureInitialCongestionWindow);
config.set_max_undecryptable_packets(kMaxUndecryptablePackets);
config.SetInitialFlowControlWindowToSend(kInitialReceiveWindowSize);
config.SetInitialStreamFlowControlWindowToSend(kInitialReceiveWindowSize);
@@ -954,7 +942,7 @@
*session = new QuicClientSession(
connection, socket.Pass(), this, transport_security_state_,
- server_info.Pass(), config, server_id.is_https(),
+ server_info.Pass(), config,
base::MessageLoop::current()->message_loop_proxy().get(),
net_log.net_log());
all_sessions_[*session] = server_id; // owning pointer
diff --git a/net/quic/quic_time_wait_list_manager.cc b/net/quic/quic_time_wait_list_manager.cc
index d59cbc4..67d347f 100644
--- a/net/quic/quic_time_wait_list_manager.cc
+++ b/net/quic/quic_time_wait_list_manager.cc
@@ -27,9 +27,8 @@
namespace {
-// Time period for which a given connection_id should live in the time-wait
-// state.
-int64 FLAGS_quic_time_wait_list_seconds = 5;
+// Time period for which the connection_id should live in time wait state.
+const int kTimeWaitSeconds = 5;
} // namespace
@@ -40,7 +39,8 @@
public:
explicit ConnectionIdCleanUpAlarm(
QuicTimeWaitListManager* time_wait_list_manager)
- : time_wait_list_manager_(time_wait_list_manager) {}
+ : time_wait_list_manager_(time_wait_list_manager) {
+ }
QuicTime OnAlarm() override {
time_wait_list_manager_->CleanUpOldConnectionIds();
@@ -67,7 +67,8 @@
QuicEncryptedPacket* packet)
: server_address_(server_address),
client_address_(client_address),
- packet_(packet) {}
+ packet_(packet) {
+ }
const IPEndPoint& server_address() const { return server_address_; }
const IPEndPoint& client_address() const { return client_address_; }
@@ -87,8 +88,7 @@
QuicConnectionHelperInterface* helper,
const QuicVersionVector& supported_versions)
: helper_(helper),
- kTimeWaitPeriod_(
- QuicTime::Delta::FromSeconds(FLAGS_quic_time_wait_list_seconds)),
+ kTimeWaitPeriod_(QuicTime::Delta::FromSeconds(kTimeWaitSeconds)),
connection_id_clean_up_alarm_(
helper_->CreateAlarm(new ConnectionIdCleanUpAlarm(this))),
writer_(writer),
@@ -276,7 +276,6 @@
break;
}
// This connection_id has lived its age, retire it now.
- DVLOG(1) << "Retiring " << it->first << " from the time-wait state.";
delete it->second.close_packet;
connection_id_map_.erase(it);
}
diff --git a/net/quic/test_tools/quic_config_peer.cc b/net/quic/test_tools/quic_config_peer.cc
index 7c84001..d0f5bfd 100644
--- a/net/quic/test_tools/quic_config_peer.cc
+++ b/net/quic/test_tools/quic_config_peer.cc
@@ -10,12 +10,6 @@
namespace test {
// static
-void QuicConfigPeer::SetReceivedInitialWindow(QuicConfig* config,
- size_t initial_window) {
- config->initial_congestion_window_.SetReceivedValue(initial_window);
-}
-
-// static
void QuicConfigPeer::SetReceivedSocketReceiveBuffer(
QuicConfig* config,
uint32 receive_buffer_bytes) {
diff --git a/net/quic/test_tools/quic_config_peer.h b/net/quic/test_tools/quic_config_peer.h
index 6c5e237..32e6bff 100644
--- a/net/quic/test_tools/quic_config_peer.h
+++ b/net/quic/test_tools/quic_config_peer.h
@@ -15,9 +15,6 @@
class QuicConfigPeer {
public:
- static void SetReceivedInitialWindow(QuicConfig* config,
- size_t initial_window);
-
static void SetReceivedSocketReceiveBuffer(QuicConfig* config,
uint32 receive_buffer_bytes);
diff --git a/net/quic/test_tools/quic_test_utils.cc b/net/quic/test_tools/quic_test_utils.cc
index ae3abfe..13e5eb1 100644
--- a/net/quic/test_tools/quic_test_utils.cc
+++ b/net/quic/test_tools/quic_test_utils.cc
@@ -221,21 +221,10 @@
clock_.AdvanceTime(delta);
}
-namespace {
-class NiceMockPacketWriterFactory
- : public QuicConnection::PacketWriterFactory {
- public:
- NiceMockPacketWriterFactory() {}
- ~NiceMockPacketWriterFactory() override {}
-
- QuicPacketWriter* Create(QuicConnection* /*connection*/) const override {
- return new testing::NiceMock<MockPacketWriter>();
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(NiceMockPacketWriterFactory);
-};
-} // namespace
+QuicPacketWriter* NiceMockPacketWriterFactory::Create(
+ QuicConnection* /*connection*/) const {
+ return new testing::NiceMock<MockPacketWriter>();
+}
MockConnection::MockConnection(bool is_server)
: QuicConnection(kTestConnectionId,
@@ -243,7 +232,21 @@
new testing::NiceMock<MockHelper>(),
NiceMockPacketWriterFactory(),
/* owns_writer= */ true,
- is_server, QuicSupportedVersions()),
+ is_server,
+ /* is_secure= */ false,
+ QuicSupportedVersions()),
+ helper_(helper()) {
+}
+
+MockConnection::MockConnection(bool is_server, bool is_secure)
+ : QuicConnection(kTestConnectionId,
+ IPEndPoint(TestPeerIPAddress(), kTestPort),
+ new testing::NiceMock<MockHelper>(),
+ NiceMockPacketWriterFactory(),
+ /* owns_writer= */ true,
+ is_server,
+ is_secure,
+ QuicSupportedVersions()),
helper_(helper()) {
}
@@ -253,7 +256,9 @@
new testing::NiceMock<MockHelper>(),
NiceMockPacketWriterFactory(),
/* owns_writer= */ true,
- is_server, QuicSupportedVersions()),
+ is_server,
+ /* is_secure= */ false,
+ QuicSupportedVersions()),
helper_(helper()) {
}
@@ -264,7 +269,9 @@
new testing::NiceMock<MockHelper>(),
NiceMockPacketWriterFactory(),
/* owns_writer= */ true,
- is_server, QuicSupportedVersions()),
+ is_server,
+ /* is_secure= */ false,
+ QuicSupportedVersions()),
helper_(helper()) {
}
@@ -275,7 +282,9 @@
new testing::NiceMock<MockHelper>(),
NiceMockPacketWriterFactory(),
/* owns_writer= */ true,
- is_server, supported_versions),
+ is_server,
+ /* is_secure= */ false,
+ supported_versions),
helper_(helper()) {
}
@@ -316,7 +325,7 @@
}
MockSession::MockSession(QuicConnection* connection)
- : QuicSession(connection, DefaultQuicConfig(), /*is_secure=*/false) {
+ : QuicSession(connection, DefaultQuicConfig()) {
InitializeSession();
ON_CALL(*this, WritevData(_, _, _, _, _, _))
.WillByDefault(testing::Return(QuicConsumedData(0, false)));
@@ -326,7 +335,7 @@
}
TestSession::TestSession(QuicConnection* connection, const QuicConfig& config)
- : QuicSession(connection, config, /*is_secure=*/false),
+ : QuicSession(connection, config),
crypto_stream_(nullptr) {
InitializeSession();
}
@@ -343,7 +352,7 @@
TestClientSession::TestClientSession(QuicConnection* connection,
const QuicConfig& config)
- : QuicClientSessionBase(connection, config, /*is_secure=*/false),
+ : QuicClientSessionBase(connection, config),
crypto_stream_(nullptr) {
EXPECT_CALL(*this, OnProofValid(_)).Times(AnyNumber());
InitializeSession();
diff --git a/net/quic/test_tools/quic_test_utils.h b/net/quic/test_tools/quic_test_utils.h
index ea5e5ef..fa987de 100644
--- a/net/quic/test_tools/quic_test_utils.h
+++ b/net/quic/test_tools/quic_test_utils.h
@@ -265,11 +265,25 @@
DISALLOW_COPY_AND_ASSIGN(MockHelper);
};
+class NiceMockPacketWriterFactory : public QuicConnection::PacketWriterFactory {
+ public:
+ NiceMockPacketWriterFactory() {}
+ ~NiceMockPacketWriterFactory() override {}
+
+ QuicPacketWriter* Create(QuicConnection* /*connection*/) const override;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(NiceMockPacketWriterFactory);
+};
+
class MockConnection : public QuicConnection {
public:
// Uses a MockHelper, ConnectionId of 42, and 127.0.0.1:123.
explicit MockConnection(bool is_server);
+ // Uses a MockHelper, ConnectionId of 42, and 127.0.0.1:123.
+ MockConnection(bool is_server, bool is_secure);
+
// Uses a MockHelper, ConnectionId of 42.
MockConnection(IPEndPoint address, bool is_server);
@@ -437,7 +451,9 @@
MockSendAlgorithm();
virtual ~MockSendAlgorithm();
- MOCK_METHOD2(SetFromConfig, void(const QuicConfig& config, bool is_server));
+ MOCK_METHOD3(SetFromConfig, void(const QuicConfig& config,
+ bool is_server,
+ bool using_pacing));
MOCK_METHOD1(SetNumEmulatedConnections, void(int num_connections));
MOCK_METHOD1(SetMaxPacketSize, void(QuicByteCount max_packet_size));
MOCK_METHOD2(OnIncomingQuicCongestionFeedbackFrame,
diff --git a/net/socket/tcp_socket_libevent.cc b/net/socket/tcp_socket_libevent.cc
index cc23765..d7fa9fa 100644
--- a/net/socket/tcp_socket_libevent.cc
+++ b/net/socket/tcp_socket_libevent.cc
@@ -21,6 +21,7 @@
#include "net/base/ip_endpoint.h"
#include "net/base/net_errors.h"
#include "net/base/net_util.h"
+#include "net/base/network_activity_monitor.h"
#include "net/base/network_change_notifier.h"
#include "net/socket/socket_libevent.h"
#include "net/socket/socket_net_log_params.h"
@@ -601,6 +602,8 @@
read_bytes.Add(rv);
net_log_.AddByteTransferEvent(NetLog::TYPE_SOCKET_BYTES_RECEIVED, rv,
buf->data());
+ NetworkActivityMonitor::GetInstance()->IncrementBytesReceived(rv);
+
return rv;
}
@@ -633,6 +636,7 @@
write_bytes.Add(rv);
net_log_.AddByteTransferEvent(NetLog::TYPE_SOCKET_BYTES_SENT, rv,
buf->data());
+ NetworkActivityMonitor::GetInstance()->IncrementBytesSent(rv);
return rv;
}
diff --git a/net/socket/tcp_socket_win.cc b/net/socket/tcp_socket_win.cc
index fd3c8b7..0c3d26f 100644
--- a/net/socket/tcp_socket_win.cc
+++ b/net/socket/tcp_socket_win.cc
@@ -18,6 +18,7 @@
#include "net/base/ip_endpoint.h"
#include "net/base/net_errors.h"
#include "net/base/net_util.h"
+#include "net/base/network_activity_monitor.h"
#include "net/base/network_change_notifier.h"
#include "net/base/winsock_init.h"
#include "net/base/winsock_util.h"
@@ -545,6 +546,7 @@
write_bytes.Add(rv);
net_log_.AddByteTransferEvent(NetLog::TYPE_SOCKET_BYTES_SENT, rv,
buf->data());
+ NetworkActivityMonitor::GetInstance()->IncrementBytesSent(rv);
return rv;
}
} else {
@@ -913,6 +915,7 @@
read_bytes.Add(rv);
net_log_.AddByteTransferEvent(NetLog::TYPE_SOCKET_BYTES_RECEIVED, rv,
buf->data());
+ NetworkActivityMonitor::GetInstance()->IncrementBytesReceived(rv);
return rv;
}
@@ -982,6 +985,7 @@
write_bytes.Add(num_bytes);
net_log_.AddByteTransferEvent(NetLog::TYPE_SOCKET_BYTES_SENT, num_bytes,
core_->write_iobuffer_->data());
+ NetworkActivityMonitor::GetInstance()->IncrementBytesSent(num_bytes);
}
}
diff --git a/net/tools/quic/end_to_end_test.cc b/net/tools/quic/end_to_end_test.cc
index 1fb3e79..33f30fc 100644
--- a/net/tools/quic/end_to_end_test.cc
+++ b/net/tools/quic/end_to_end_test.cc
@@ -920,11 +920,10 @@
EXPECT_EQ(2u, client_negotiated_config->MaxStreamsPerConnection());
}
-TEST_P(EndToEndTest, LimitCongestionWindowAndRTT) {
- // Client tries to request twice the server's max initial window, and the
- // server limits it to the max.
- client_config_.SetInitialCongestionWindowToSend(2 * kMaxInitialWindow);
- client_config_.SetInitialRoundTripTimeUsToSend(20000);
+TEST_P(EndToEndTest, ClientSuggestsRTT) {
+ // Client suggests initial RTT, verify it is used.
+ const uint32 kInitialRTT = 20000;
+ client_config_.SetInitialRoundTripTimeUsToSend(kInitialRTT);
ASSERT_TRUE(Initialize());
client_->client()->WaitForCryptoHandshakeConfirmed();
@@ -940,33 +939,21 @@
const QuicSentPacketManager& server_sent_packet_manager =
*GetSentPacketManagerFromFirstServerSession();
- // The client shouldn't set its initial window based on the negotiated value.
- EXPECT_EQ(kDefaultInitialWindow,
- client_sent_packet_manager.GetCongestionWindowInTcpMss());
- EXPECT_EQ(kMaxInitialWindow,
- server_sent_packet_manager.GetCongestionWindowInTcpMss());
+ // BBR automatically enables pacing.
+ EXPECT_EQ(GetParam().use_pacing ||
+ (FLAGS_quic_allow_bbr &&
+ GetParam().congestion_control_tag == kTBBR),
+ server_sent_packet_manager.using_pacing());
+ EXPECT_EQ(GetParam().use_pacing ||
+ (FLAGS_quic_allow_bbr &&
+ GetParam().congestion_control_tag == kTBBR),
+ client_sent_packet_manager.using_pacing());
- EXPECT_EQ(GetParam().use_pacing, server_sent_packet_manager.using_pacing());
- EXPECT_EQ(GetParam().use_pacing, client_sent_packet_manager.using_pacing());
-
- // The client *should* set the intitial RTT, but it's increased to 10ms.
- EXPECT_EQ(20000u, client_sent_packet_manager.GetRttStats()->initial_rtt_us());
- EXPECT_EQ(20000u, server_sent_packet_manager.GetRttStats()->initial_rtt_us());
-
- // Now use the negotiated limits with packet loss.
- SetPacketLossPercentage(30);
-
- // 10 KB body.
- string body;
- GenerateBody(&body, 1024 * 10);
-
- HTTPMessage request(HttpConstants::HTTP_1_1,
- HttpConstants::POST, "/foo");
- request.AddBody(body, true);
-
+ EXPECT_EQ(kInitialRTT,
+ client_sent_packet_manager.GetRttStats()->initial_rtt_us());
+ EXPECT_EQ(kInitialRTT,
+ server_sent_packet_manager.GetRttStats()->initial_rtt_us());
server_thread_->Resume();
-
- EXPECT_EQ(kFooResponseBody, client_->SendCustomSynchronousRequest(request));
}
TEST_P(EndToEndTest, MaxInitialRTT) {
@@ -1025,7 +1012,7 @@
EXPECT_FALSE(
client_sent_packet_manager.GetRttStats()->smoothed_rtt().IsInfinite());
// Expect the default rtt of 100ms.
- EXPECT_EQ(static_cast<int64>(100 * base::Time::kMicrosecondsPerMillisecond),
+ EXPECT_EQ(static_cast<int64>(100 * kNumMicrosPerMilli),
server_sent_packet_manager.GetRttStats()->initial_rtt_us());
// Ensure the bandwidth is valid.
client_sent_packet_manager.BandwidthEstimate();
diff --git a/net/tools/quic/quic_client.cc b/net/tools/quic/quic_client.cc
index b28ec2b..74874d7 100644
--- a/net/tools/quic/quic_client.cc
+++ b/net/tools/quic/quic_client.cc
@@ -199,8 +199,8 @@
factory,
/* owns_writer= */ false,
/* is_server= */ false,
- supported_versions_),
- server_id_.is_https()));
+ server_id_.is_https(),
+ supported_versions_)));
// Reset |writer_| after |session_| so that the old writer outlives the old
// session.
diff --git a/net/tools/quic/quic_client_session.cc b/net/tools/quic/quic_client_session.cc
index 87ca0ce..235eeb0 100644
--- a/net/tools/quic/quic_client_session.cc
+++ b/net/tools/quic/quic_client_session.cc
@@ -15,9 +15,8 @@
namespace tools {
QuicClientSession::QuicClientSession(const QuicConfig& config,
- QuicConnection* connection,
- bool is_secure)
- : QuicClientSessionBase(connection, config, is_secure) {
+ QuicConnection* connection)
+ : QuicClientSessionBase(connection, config) {
}
QuicClientSession::~QuicClientSession() {
@@ -26,18 +25,16 @@
void QuicClientSession::InitializeSession(
const QuicServerId& server_id,
QuicCryptoClientConfig* crypto_config) {
- QuicClientSessionBase::InitializeSession();
crypto_stream_.reset(
new QuicCryptoClientStream(server_id, this, nullptr, crypto_config));
+ QuicClientSessionBase::InitializeSession();
}
void QuicClientSession::OnProofValid(
- const QuicCryptoClientConfig::CachedState& /*cached*/) {
-}
+ const QuicCryptoClientConfig::CachedState& /*cached*/) {}
void QuicClientSession::OnProofVerifyDetailsAvailable(
- const ProofVerifyDetails& /*verify_details*/) {
-}
+ const ProofVerifyDetails& /*verify_details*/) {}
QuicSpdyClientStream* QuicClientSession::CreateOutgoingDataStream() {
if (!crypto_stream_->encryption_established()) {
diff --git a/net/tools/quic/quic_client_session.h b/net/tools/quic/quic_client_session.h
index d1cd38c..3c92efa 100644
--- a/net/tools/quic/quic_client_session.h
+++ b/net/tools/quic/quic_client_session.h
@@ -25,9 +25,7 @@
class QuicClientSession : public QuicClientSessionBase {
public:
- QuicClientSession(const QuicConfig& config,
- QuicConnection* connection,
- bool is_secure);
+ QuicClientSession(const QuicConfig& config, QuicConnection* connection);
~QuicClientSession() override;
void InitializeSession(const QuicServerId& server_id,
diff --git a/net/tools/quic/quic_client_session_test.cc b/net/tools/quic/quic_client_session_test.cc
index 61422e1..5b5c415 100644
--- a/net/tools/quic/quic_client_session_test.cc
+++ b/net/tools/quic/quic_client_session_test.cc
@@ -42,8 +42,7 @@
ToolsQuicClientSessionTest()
: connection_(
new PacketSavingConnection(false, SupportedVersions(GetParam()))) {
- session_.reset(new QuicClientSession(DefaultQuicConfig(), connection_,
- /*is_secure=*/false));
+ session_.reset(new QuicClientSession(DefaultQuicConfig(), connection_));
session_->InitializeSession(
QuicServerId(kServerHostname, kPort, false, PRIVACY_MODE_DISABLED),
&crypto_config_);
diff --git a/net/tools/quic/quic_dispatcher.cc b/net/tools/quic/quic_dispatcher.cc
index 16cee2b..4ea48e9 100644
--- a/net/tools/quic/quic_dispatcher.cc
+++ b/net/tools/quic/quic_dispatcher.cc
@@ -364,8 +364,7 @@
QuicServerSession* session = new QuicServerSession(
config_,
CreateQuicConnection(connection_id, server_address, client_address),
- this,
- crypto_config_.HasProofSource());
+ this);
session->InitializeSession(crypto_config_);
return session;
}
@@ -380,6 +379,7 @@
connection_writer_factory_,
/* owns_writer= */ true,
/* is_server= */ true,
+ crypto_config_.HasProofSource(),
supported_versions_);
}
diff --git a/net/tools/quic/quic_server_session.cc b/net/tools/quic/quic_server_session.cc
index 1dd5748..45c1379 100644
--- a/net/tools/quic/quic_server_session.cc
+++ b/net/tools/quic/quic_server_session.cc
@@ -5,7 +5,7 @@
#include "net/tools/quic/quic_server_session.h"
#include "base/logging.h"
-#include "net/quic/crypto/source_address_token.h"
+#include "net/quic/crypto/cached_network_parameters.h"
#include "net/quic/quic_connection.h"
#include "net/quic/quic_flags.h"
#include "net/quic/reliable_quic_stream.h"
@@ -16,9 +16,8 @@
QuicServerSession::QuicServerSession(const QuicConfig& config,
QuicConnection* connection,
- QuicServerSessionVisitor* visitor,
- bool is_secure)
- : QuicSession(connection, config, is_secure),
+ QuicServerSessionVisitor* visitor)
+ : QuicSession(connection, config),
visitor_(visitor),
bandwidth_estimate_sent_to_client_(QuicBandwidth::Zero()),
last_scup_time_(QuicTime::Zero()),
diff --git a/net/tools/quic/quic_server_session.h b/net/tools/quic/quic_server_session.h
index cdc2bf3..603ad35 100644
--- a/net/tools/quic/quic_server_session.h
+++ b/net/tools/quic/quic_server_session.h
@@ -47,8 +47,7 @@
public:
QuicServerSession(const QuicConfig& config,
QuicConnection* connection,
- QuicServerSessionVisitor* visitor,
- bool is_secure);
+ QuicServerSessionVisitor* visitor);
// Override the base class to notify the owner of the connection close.
void OnConnectionClosed(QuicErrorCode error, bool from_peer) override;
diff --git a/net/tools/quic/quic_server_session_test.cc b/net/tools/quic/quic_server_session_test.cc
index 202022f..6a17f53 100644
--- a/net/tools/quic/quic_server_session_test.cc
+++ b/net/tools/quic/quic_server_session_test.cc
@@ -4,9 +4,9 @@
#include "net/tools/quic/quic_server_session.h"
+#include "net/quic/crypto/cached_network_parameters.h"
#include "net/quic/crypto/quic_crypto_server_config.h"
#include "net/quic/crypto/quic_random.h"
-#include "net/quic/crypto/source_address_token.h"
#include "net/quic/quic_connection.h"
#include "net/quic/quic_crypto_server_stream.h"
#include "net/quic/quic_flags.h"
@@ -79,8 +79,7 @@
connection_ =
new StrictMock<MockConnection>(true, SupportedVersions(GetParam()));
- session_.reset(new QuicServerSession(config_, connection_, &owner_,
- /*is_secure=*/false));
+ session_.reset(new QuicServerSession(config_, connection_, &owner_));
MockClock clock;
handshake_message_.reset(crypto_config_.AddDefaultConfig(
QuicRandom::GetInstance(), &clock,
diff --git a/net/tools/quic/quic_spdy_client_stream_test.cc b/net/tools/quic/quic_spdy_client_stream_test.cc
index d2106d9..090e2da 100644
--- a/net/tools/quic/quic_spdy_client_stream_test.cc
+++ b/net/tools/quic/quic_spdy_client_stream_test.cc
@@ -29,7 +29,7 @@
QuicSpdyClientStreamTest()
: connection_(new StrictMock<MockConnection>(
false, SupportedVersions(GetParam()))),
- session_(DefaultQuicConfig(), connection_, /*is_secure=*/false),
+ session_(DefaultQuicConfig(), connection_),
body_("hello world") {
session_.InitializeSession(
QuicServerId("example.com", 80, false, PRIVACY_MODE_DISABLED),
diff --git a/net/tools/quic/quic_time_wait_list_manager.cc b/net/tools/quic/quic_time_wait_list_manager.cc
index 58f50fe..f54a465 100644
--- a/net/tools/quic/quic_time_wait_list_manager.cc
+++ b/net/tools/quic/quic_time_wait_list_manager.cc
@@ -28,9 +28,8 @@
namespace {
-// Time period for which a given connection_id should live in the time-wait
-// state.
-int64 FLAGS_quic_time_wait_list_seconds = 5;
+// Time period for which the connection_id should live in time wait state.
+const int kTimeWaitSeconds = 5;
} // namespace
@@ -91,8 +90,7 @@
EpollServer* epoll_server,
const QuicVersionVector& supported_versions)
: epoll_server_(epoll_server),
- kTimeWaitPeriod_(
- QuicTime::Delta::FromSeconds(FLAGS_quic_time_wait_list_seconds)),
+ kTimeWaitPeriod_(QuicTime::Delta::FromSeconds(kTimeWaitSeconds)),
connection_id_clean_up_alarm_(new ConnectionIdCleanUpAlarm(this)),
clock_(epoll_server_),
writer_(writer),
@@ -122,7 +120,9 @@
delete it->second.close_packet;
connection_id_map_.erase(it);
}
- ConnectionIdData data(num_packets, version, clock_.ApproximateNow(),
+ ConnectionIdData data(num_packets,
+ version,
+ clock_.ApproximateNow(),
close_packet);
connection_id_map_.insert(make_pair(connection_id, data));
}
@@ -168,12 +168,12 @@
return;
}
if (it->second.close_packet) {
- QueuedPacket* queued_packet =
- new QueuedPacket(server_address,
- client_address,
- it->second.close_packet->Clone());
- // Takes ownership of the packet.
- SendOrQueuePacket(queued_packet);
+ QueuedPacket* queued_packet =
+ new QueuedPacket(server_address,
+ client_address,
+ it->second.close_packet->Clone());
+ // Takes ownership of the packet.
+ SendOrQueuePacket(queued_packet);
} else {
SendPublicReset(server_address,
client_address,
@@ -282,7 +282,6 @@
break;
}
// This connection_id has lived its age, retire it now.
- DVLOG(1) << "Retiring " << it->first << " from the time-wait state.";
delete it->second.close_packet;
connection_id_map_.erase(it);
}
diff --git a/net/tools/quic/test_tools/quic_test_utils.cc b/net/tools/quic/test_tools/quic_test_utils.cc
index 40b7e88..91cd003 100644
--- a/net/tools/quic/test_tools/quic_test_utils.cc
+++ b/net/tools/quic/test_tools/quic_test_utils.cc
@@ -18,21 +18,10 @@
namespace tools {
namespace test {
-namespace {
-class NiceMockPacketWriterFactory
- : public QuicConnection::PacketWriterFactory {
- public:
- NiceMockPacketWriterFactory() {}
- ~NiceMockPacketWriterFactory() override {}
-
- QuicPacketWriter* Create(QuicConnection* /*connection*/) const override {
- return new testing::NiceMock<MockPacketWriter>();
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(NiceMockPacketWriterFactory);
-};
-} // namespace
+QuicPacketWriter* NiceMockPacketWriterFactory::Create(
+ QuicConnection* /*connection*/) const {
+ return new testing::NiceMock<MockPacketWriter>();
+}
MockConnection::MockConnection(bool is_server)
: QuicConnection(kTestConnectionId,
@@ -40,7 +29,21 @@
new testing::NiceMock<MockHelper>(),
NiceMockPacketWriterFactory(),
/* owns_writer= */ true,
- is_server, QuicSupportedVersions()),
+ is_server,
+ /* is_secure= */ false,
+ QuicSupportedVersions()),
+ helper_(helper()) {
+}
+
+MockConnection::MockConnection(bool is_server, bool is_secure)
+ : QuicConnection(kTestConnectionId,
+ IPEndPoint(net::test::Loopback4(), kTestPort),
+ new testing::NiceMock<MockHelper>(),
+ NiceMockPacketWriterFactory(),
+ /* owns_writer= */ true,
+ is_server,
+ is_secure,
+ QuicSupportedVersions()),
helper_(helper()) {
}
@@ -50,7 +53,9 @@
new testing::NiceMock<MockHelper>(),
NiceMockPacketWriterFactory(),
/* owns_writer= */ true,
- is_server, QuicSupportedVersions()),
+ is_server,
+ /* is_secure= */ false,
+ QuicSupportedVersions()),
helper_(helper()) {
}
@@ -61,7 +66,9 @@
new testing::NiceMock<MockHelper>(),
NiceMockPacketWriterFactory(),
/* owns_writer= */ true,
- is_server, QuicSupportedVersions()),
+ is_server,
+ /* is_secure= */ false,
+ QuicSupportedVersions()),
helper_(helper()) {
}
@@ -72,7 +79,9 @@
new testing::NiceMock<MockHelper>(),
NiceMockPacketWriterFactory(),
/* owns_writer= */ true,
- is_server, QuicSupportedVersions()),
+ is_server,
+ /* is_secure= */ false,
+ supported_versions),
helper_(helper()) {
}
@@ -93,9 +102,8 @@
return ack;
}
-TestSession::TestSession(QuicConnection* connection,
- const QuicConfig& config)
- : QuicSession(connection, config, /*is_secure=*/false),
+TestSession::TestSession(QuicConnection* connection, const QuicConfig& config)
+ : QuicSession(connection, config),
crypto_stream_(nullptr) {
InitializeSession();
}
diff --git a/net/tools/quic/test_tools/quic_test_utils.h b/net/tools/quic/test_tools/quic_test_utils.h
index cbd7fbe..9db9fb5 100644
--- a/net/tools/quic/test_tools/quic_test_utils.h
+++ b/net/tools/quic/test_tools/quic_test_utils.h
@@ -39,11 +39,25 @@
QuicAckFrame MakeAckFrameWithNackRanges(size_t num_nack_ranges,
QuicPacketSequenceNumber least_unacked);
+class NiceMockPacketWriterFactory : public QuicConnection::PacketWriterFactory {
+ public:
+ NiceMockPacketWriterFactory() {}
+ ~NiceMockPacketWriterFactory() override {}
+
+ QuicPacketWriter* Create(QuicConnection* /*connection*/) const override;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(NiceMockPacketWriterFactory);
+};
+
class MockConnection : public QuicConnection {
public:
// Uses a MockHelper, ConnectionId of 42, and 127.0.0.1:123.
explicit MockConnection(bool is_server);
+ // Uses a MockHelper, ConnectionId of 42, and 127.0.0.1:123.
+ MockConnection(bool is_server, bool is_secure);
+
// Uses a MockHelper, ConnectionId of 42.
MockConnection(IPEndPoint address, bool is_server);
@@ -83,10 +97,12 @@
void ReallyProcessUdpPacket(const IPEndPoint& self_address,
const IPEndPoint& peer_address,
const QuicEncryptedPacket& packet) {
- return QuicConnection::ProcessUdpPacket(self_address, peer_address, packet);
+ QuicConnection::ProcessUdpPacket(self_address, peer_address, packet);
}
- virtual bool OnProtocolVersionMismatch(QuicVersion version) { return false; }
+ virtual bool OnProtocolVersionMismatch(QuicVersion version) override {
+ return false;
+ }
private:
scoped_ptr<QuicConnectionHelperInterface> helper_;
diff --git a/net/udp/udp_socket_libevent.cc b/net/udp/udp_socket_libevent.cc
index 9b1a995..2dffff3 100644
--- a/net/udp/udp_socket_libevent.cc
+++ b/net/udp/udp_socket_libevent.cc
@@ -24,6 +24,7 @@
#include "net/base/net_errors.h"
#include "net/base/net_log.h"
#include "net/base/net_util.h"
+#include "net/base/network_activity_monitor.h"
#include "net/socket/socket_descriptor.h"
#include "net/udp/udp_net_log_parameters.h"
@@ -414,6 +415,7 @@
base::StatsCounter read_bytes("udp.read_bytes");
read_bytes.Add(result);
+ NetworkActivityMonitor::GetInstance()->IncrementBytesReceived(result);
}
int UDPSocketLibevent::CreateSocket(int addr_family) {
@@ -458,6 +460,7 @@
base::StatsCounter write_bytes("udp.write_bytes");
write_bytes.Add(result);
+ NetworkActivityMonitor::GetInstance()->IncrementBytesSent(result);
}
int UDPSocketLibevent::InternalRecvFrom(IOBuffer* buf, int buf_len,
diff --git a/net/udp/udp_socket_win.cc b/net/udp/udp_socket_win.cc
index 4c307fd..11c731f 100644
--- a/net/udp/udp_socket_win.cc
+++ b/net/udp/udp_socket_win.cc
@@ -20,6 +20,7 @@
#include "net/base/net_errors.h"
#include "net/base/net_log.h"
#include "net/base/net_util.h"
+#include "net/base/network_activity_monitor.h"
#include "net/base/winsock_init.h"
#include "net/base/winsock_util.h"
#include "net/socket/socket_descriptor.h"
@@ -595,6 +596,7 @@
base::StatsCounter read_bytes("udp.read_bytes");
read_bytes.Add(result);
+ NetworkActivityMonitor::GetInstance()->IncrementBytesReceived(result);
}
void UDPSocketWin::DidCompleteWrite() {
@@ -626,6 +628,7 @@
base::StatsCounter write_bytes("udp.write_bytes");
write_bytes.Add(result);
+ NetworkActivityMonitor::GetInstance()->IncrementBytesSent(result);
}
int UDPSocketWin::InternalRecvFrom(IOBuffer* buf, int buf_len,
diff --git a/net/url_request/sdch_dictionary_fetcher.cc b/net/url_request/sdch_dictionary_fetcher.cc
index 5806193..5ac65ef 100644
--- a/net/url_request/sdch_dictionary_fetcher.cc
+++ b/net/url_request/sdch_dictionary_fetcher.cc
@@ -11,6 +11,7 @@
#include "base/compiler_specific.h"
#include "base/thread_task_runner_handle.h"
#include "net/base/load_flags.h"
+#include "net/base/sdch_net_log_params.h"
#include "net/url_request/url_request_context.h"
#include "net/url_request/url_request_status.h"
#include "net/url_request/url_request_throttler_manager.h"
@@ -45,16 +46,15 @@
// Avoid pushing duplicate copy onto queue. We may fetch this url again later
// and get a different dictionary, but there is no reason to have it in the
// queue twice at one time.
- if (!fetch_queue_.empty() && fetch_queue_.back() == dictionary_url) {
+ if ((!fetch_queue_.empty() && fetch_queue_.back() == dictionary_url) ||
+ attempted_load_.find(dictionary_url) != attempted_load_.end()) {
+ // TODO(rdsmith): log this error to the net log of the URLRequest
+ // initiating this fetch, once URLRequest will be passed here.
SdchManager::SdchErrorRecovery(
- SdchManager::DICTIONARY_ALREADY_SCHEDULED_TO_DOWNLOAD);
+ SDCH_DICTIONARY_PREVIOUSLY_SCHEDULED_TO_DOWNLOAD);
return;
}
- if (attempted_load_.find(dictionary_url) != attempted_load_.end()) {
- SdchManager::SdchErrorRecovery(
- SdchManager::DICTIONARY_ALREADY_TRIED_TO_DOWNLOAD);
- return;
- }
+
attempted_load_.insert(dictionary_url);
fetch_queue_.push(dictionary_url);
@@ -166,6 +166,7 @@
next_state_ = STATE_REQUEST_STARTED;
current_request_->Start();
+ current_request_->net_log().AddEvent(NetLog::TYPE_SDCH_DICTIONARY_FETCH);
return OK;
}
@@ -207,7 +208,12 @@
// an infinite loop. It's not clear how to handle a read failure
// without a promise to invoke the callback at some point in the future,
// so the request is failed.
- SdchManager::SdchErrorRecovery(SdchManager::DICTIONARY_FETCH_READ_FAILED);
+ SdchManager::SdchErrorRecovery(SDCH_DICTIONARY_FETCH_READ_FAILED);
+ current_request_->net_log().AddEvent(
+ NetLog::TYPE_SDCH_DICTIONARY_ERROR,
+ base::Bind(&NetLogSdchDictionaryFetchProblemCallback,
+ SDCH_DICTIONARY_FETCH_READ_FAILED, current_request_->url(),
+ true));
DLOG(FATAL)
<< "URLRequest::Read() returned false without IO pending or error!";
return ERR_FAILED;
@@ -228,8 +234,10 @@
DCHECK(CalledOnValidThread());
// If the dictionary was successfully fetched, add it to the manager.
- if (rv == OK)
- dictionary_fetched_callback_.Run(dictionary_, current_request_->url());
+ if (rv == OK) {
+ dictionary_fetched_callback_.Run(dictionary_, current_request_->url(),
+ current_request_->net_log());
+ }
current_request_.reset();
buffer_ = NULL;
diff --git a/net/url_request/sdch_dictionary_fetcher.h b/net/url_request/sdch_dictionary_fetcher.h
index 5b6f269..79d8778 100644
--- a/net/url_request/sdch_dictionary_fetcher.h
+++ b/net/url_request/sdch_dictionary_fetcher.h
@@ -36,7 +36,8 @@
public base::NonThreadSafe {
public:
typedef base::Callback<void(const std::string& dictionary_text,
- const GURL& dictionary_url)>
+ const GURL& dictionary_url,
+ const BoundNetLog& net_log)>
OnDictionaryFetchedCallback;
// The consumer must guarantee that |*context| outlives this object.
diff --git a/net/url_request/sdch_dictionary_fetcher_unittest.cc b/net/url_request/sdch_dictionary_fetcher_unittest.cc
index 0febd7e..ae76cbc 100644
--- a/net/url_request/sdch_dictionary_fetcher_unittest.cc
+++ b/net/url_request/sdch_dictionary_fetcher_unittest.cc
@@ -99,7 +99,8 @@
}
void OnDictionaryFetched(const std::string& dictionary_text,
- const GURL& dictionary_url) {
+ const GURL& dictionary_url,
+ const BoundNetLog& net_log) {
dictionary_additions.push_back(
DictionaryAdditions(dictionary_text, dictionary_url));
}
diff --git a/net/url_request/test_url_fetcher_factory.cc b/net/url_request/test_url_fetcher_factory.cc
index af76576..357dfeb 100644
--- a/net/url_request/test_url_fetcher_factory.cc
+++ b/net/url_request/test_url_fetcher_factory.cc
@@ -48,6 +48,7 @@
fake_response_destination_(STRING),
fake_was_fetched_via_proxy_(false),
fake_max_retries_(0) {
+ CHECK(original_url_.is_valid());
}
TestURLFetcher::~TestURLFetcher() {
diff --git a/net/url_request/url_fetcher.cc b/net/url_request/url_fetcher.cc
index 96a2510..ddad12d 100644
--- a/net/url_request/url_fetcher.cc
+++ b/net/url_request/url_fetcher.cc
@@ -36,11 +36,6 @@
}
// static
-void net::URLFetcher::SetEnableInterceptionForTests(bool enabled) {
- URLFetcherImpl::SetEnableInterceptionForTests(enabled);
-}
-
-// static
void net::URLFetcher::SetIgnoreCertificateRequests(bool ignored) {
URLFetcherImpl::SetIgnoreCertificateRequests(ignored);
}
diff --git a/net/url_request/url_fetcher.h b/net/url_request/url_fetcher.h
index 1b379c4..5dcaedd 100644
--- a/net/url_request/url_fetcher.h
+++ b/net/url_request/url_fetcher.h
@@ -119,11 +119,6 @@
// thread though, even though the task won't ever run.
static void CancelAll();
- // Normally interception is disabled for URLFetcher, but you can use this
- // to enable it for tests. Also see ScopedURLFetcherFactory for another way
- // of testing code that uses an URLFetcher.
- static void SetEnableInterceptionForTests(bool enabled);
-
// Normally, URLFetcher will abort loads that request SSL client certificate
// authentication, but this method may be used to cause URLFetchers to ignore
// requests for client certificates and continue anonymously. Because such
diff --git a/net/url_request/url_fetcher_core.cc b/net/url_request/url_fetcher_core.cc
index 5ea3921..aae47d9 100644
--- a/net/url_request/url_fetcher_core.cc
+++ b/net/url_request/url_fetcher_core.cc
@@ -34,7 +34,6 @@
const int kBufferSize = 4096;
const int kUploadProgressTimerInterval = 100;
-bool g_interception_enabled = false;
bool g_ignore_certificate_requests = false;
void EmptyCompletionCallback(int result) {}
@@ -470,10 +469,6 @@
return g_registry.Get().size();
}
-void URLFetcherCore::SetEnableInterceptionForTests(bool enabled) {
- g_interception_enabled = enabled;
-}
-
void URLFetcherCore::SetIgnoreCertificateRequests(bool ignored) {
g_ignore_certificate_requests = ignored;
}
@@ -514,8 +509,6 @@
original_url_, DEFAULT_PRIORITY, this, NULL);
request_->set_stack_trace(stack_trace_);
int flags = request_->load_flags() | load_flags_;
- if (!g_interception_enabled)
- flags = flags | LOAD_DISABLE_INTERCEPT;
if (is_chunked_upload_)
request_->EnableChunkedUpload();
diff --git a/net/url_request/url_fetcher_impl.cc b/net/url_request/url_fetcher_impl.cc
index fc44551..179adfb 100644
--- a/net/url_request/url_fetcher_impl.cc
+++ b/net/url_request/url_fetcher_impl.cc
@@ -193,11 +193,6 @@
}
// static
-void URLFetcherImpl::SetEnableInterceptionForTests(bool enabled) {
- URLFetcherCore::SetEnableInterceptionForTests(enabled);
-}
-
-// static
void URLFetcherImpl::SetIgnoreCertificateRequests(bool ignored) {
URLFetcherCore::SetIgnoreCertificateRequests(ignored);
}
diff --git a/net/url_request/url_fetcher_impl.h b/net/url_request/url_fetcher_impl.h
index 29c8bd5..f0a57af 100644
--- a/net/url_request/url_fetcher_impl.h
+++ b/net/url_request/url_fetcher_impl.h
@@ -90,7 +90,6 @@
static void CancelAll();
- static void SetEnableInterceptionForTests(bool enabled);
static void SetIgnoreCertificateRequests(bool ignored);
// TODO(akalin): Make these private again once URLFetcher::Create()
diff --git a/net/url_request/url_request.cc b/net/url_request/url_request.cc
index 613d9bb..a2ce07e 100644
--- a/net/url_request/url_request.cc
+++ b/net/url_request/url_request.cc
@@ -142,31 +142,6 @@
} // namespace
-void URLRequest::Deprecated::RegisterRequestInterceptor(
- Interceptor* interceptor) {
- URLRequest::RegisterRequestInterceptor(interceptor);
-}
-
-void URLRequest::Deprecated::UnregisterRequestInterceptor(
- Interceptor* interceptor) {
- URLRequest::UnregisterRequestInterceptor(interceptor);
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// URLRequest::Interceptor
-
-URLRequestJob* URLRequest::Interceptor::MaybeInterceptRedirect(
- URLRequest* request,
- NetworkDelegate* network_delegate,
- const GURL& location) {
- return NULL;
-}
-
-URLRequestJob* URLRequest::Interceptor::MaybeInterceptResponse(
- URLRequest* request, NetworkDelegate* network_delegate) {
- return NULL;
-}
-
///////////////////////////////////////////////////////////////////////////////
// URLRequest::Delegate
@@ -624,17 +599,6 @@
net_log_.BeginEvent(NetLog::TYPE_REQUEST_ALIVE);
}
-// static
-void URLRequest::RegisterRequestInterceptor(Interceptor* interceptor) {
- URLRequestJobManager::GetInstance()->RegisterRequestInterceptor(interceptor);
-}
-
-// static
-void URLRequest::UnregisterRequestInterceptor(Interceptor* interceptor) {
- URLRequestJobManager::GetInstance()->UnregisterRequestInterceptor(
- interceptor);
-}
-
void URLRequest::BeforeRequestComplete(int error) {
DCHECK(!job_.get());
DCHECK_NE(ERR_IO_PENDING, error);
diff --git a/net/url_request/url_request.h b/net/url_request/url_request.h
index 3db6c68..6117419 100644
--- a/net/url_request/url_request.h
+++ b/net/url_request/url_request.h
@@ -40,12 +40,6 @@
} // namespace debug
} // namespace base
-// Temporary layering violation to allow existing users of a deprecated
-// interface.
-namespace content {
-class AppCacheInterceptor;
-}
-
namespace net {
class ChunkedUploadDataStream;
@@ -120,58 +114,6 @@
UPDATE_FIRST_PARTY_URL_ON_REDIRECT,
};
- // This class handles network interception. Use with
- // (Un)RegisterRequestInterceptor.
- class NET_EXPORT Interceptor {
- public:
- virtual ~Interceptor() {}
-
- // Called for every request made. Should return a new job to handle the
- // request if it should be intercepted, or NULL to allow the request to
- // be handled in the normal manner.
- virtual URLRequestJob* MaybeIntercept(
- URLRequest* request, NetworkDelegate* network_delegate) = 0;
-
- // Called after having received a redirect response, but prior to the
- // the request delegate being informed of the redirect. Can return a new
- // job to replace the existing job if it should be intercepted, or NULL
- // to allow the normal handling to continue. If a new job is provided,
- // the delegate never sees the original redirect response, instead the
- // response produced by the intercept job will be returned.
- virtual URLRequestJob* MaybeInterceptRedirect(
- URLRequest* request,
- NetworkDelegate* network_delegate,
- const GURL& location);
-
- // Called after having received a final response, but prior to the
- // the request delegate being informed of the response. This is also
- // called when there is no server response at all to allow interception
- // on dns or network errors. Can return a new job to replace the existing
- // job if it should be intercepted, or NULL to allow the normal handling to
- // continue. If a new job is provided, the delegate never sees the original
- // response, instead the response produced by the intercept job will be
- // returned.
- virtual URLRequestJob* MaybeInterceptResponse(
- URLRequest* request, NetworkDelegate* network_delegate);
- };
-
- // Deprecated interfaces in net::URLRequest. They have been moved to
- // URLRequest's private section to prevent new uses. Existing uses are
- // explicitly friended here and should be removed over time.
- class NET_EXPORT Deprecated {
- private:
- // TODO(willchan): Kill off these friend declarations.
- friend class TestInterceptor;
- friend class content::AppCacheInterceptor;
-
- // TODO(pauljensen): Remove this when AppCacheInterceptor is a
- // ProtocolHandler, see crbug.com/161547.
- static void RegisterRequestInterceptor(Interceptor* interceptor);
- static void UnregisterRequestInterceptor(Interceptor* interceptor);
-
- DISALLOW_IMPLICIT_CONSTRUCTORS(Deprecated);
- };
-
// The delegate's methods are called from the message loop of the thread
// on which the request's Start() method is called. See above for the
// ordering of callbacks.
@@ -717,10 +659,6 @@
CookieStore* cookie_store,
NetworkDelegate* network_delegate);
- // Registers or unregisters a network interception class.
- static void RegisterRequestInterceptor(Interceptor* interceptor);
- static void UnregisterRequestInterceptor(Interceptor* interceptor);
-
// Resumes or blocks a request paused by the NetworkDelegate::OnBeforeRequest
// handler. If |blocked| is true, the request is blocked and an error page is
// returned indicating so. This should only be called after Start is called
diff --git a/net/url_request/url_request_context_builder.cc b/net/url_request/url_request_context_builder.cc
index 04c190c..41420d5 100644
--- a/net/url_request/url_request_context_builder.cc
+++ b/net/url_request/url_request_context_builder.cc
@@ -214,7 +214,8 @@
ftp_enabled_(false),
#endif
http_cache_enabled_(true),
- throttling_enabled_(false) {
+ throttling_enabled_(false),
+ channel_id_enabled_(true) {
}
URLRequestContextBuilder::~URLRequestContextBuilder() {}
@@ -296,12 +297,14 @@
storage->set_http_auth_handler_factory(http_auth_handler_registry_factory);
storage->set_cookie_store(new CookieMonster(NULL, NULL));
- // TODO(mmenke): This always creates a file thread, even when it ends up
- // not being used. Consider lazily creating the thread.
- storage->set_channel_id_service(
- new ChannelIDService(
- new DefaultChannelIDStore(NULL),
- context->GetFileThread()->message_loop_proxy()));
+ if (channel_id_enabled_) {
+ // TODO(mmenke): This always creates a file thread, even when it ends up
+ // not being used. Consider lazily creating the thread.
+ storage->set_channel_id_service(
+ new ChannelIDService(
+ new DefaultChannelIDStore(NULL),
+ context->GetFileThread()->message_loop_proxy()));
+ }
storage->set_transport_security_state(new net::TransportSecurityState());
if (!transport_security_persister_path_.empty()) {
diff --git a/net/url_request/url_request_context_builder.h b/net/url_request/url_request_context_builder.h
index a7d9d7b..f26552a 100644
--- a/net/url_request/url_request_context_builder.h
+++ b/net/url_request/url_request_context_builder.h
@@ -174,6 +174,10 @@
throttling_enabled_ = throttling_enabled;
}
+ void set_channel_id_enabled(bool enable) {
+ channel_id_enabled_ = enable;
+ }
+
URLRequestContext* Build();
private:
@@ -200,6 +204,7 @@
#endif
bool http_cache_enabled_;
bool throttling_enabled_;
+ bool channel_id_enabled_;
HttpCacheParams http_cache_params_;
HttpNetworkSessionParams http_network_session_params_;
diff --git a/net/url_request/url_request_http_job.cc b/net/url_request/url_request_http_job.cc
index 4261b92..33a5088 100644
--- a/net/url_request/url_request_http_job.cc
+++ b/net/url_request/url_request_http_job.cc
@@ -24,6 +24,7 @@
#include "net/base/net_util.h"
#include "net/base/network_delegate.h"
#include "net/base/sdch_manager.h"
+#include "net/base/sdch_net_log_params.h"
#include "net/cert/cert_status_flags.h"
#include "net/cookies/cookie_store.h"
#include "net/http/http_content_disposition.h"
@@ -70,6 +71,7 @@
int GetResponseCode() const override;
const URLRequestContext* GetURLRequestContext() const override;
void RecordPacketStats(StatisticSelector statistic) const override;
+ const BoundNetLog& GetNetLog() const override;
// Method to allow us to reset filter context for a response that should have
// been SDCH encoded when there is an update due to an explicit HTTP header.
@@ -78,6 +80,10 @@
private:
URLRequestHttpJob* job_;
+ // URLRequestHttpJob may be detached from URLRequest, but we still need to
+ // return something.
+ BoundNetLog dummy_log_;
+
DISALLOW_COPY_AND_ASSIGN(HttpFilterContext);
};
@@ -147,6 +153,10 @@
job_->RecordPacketStats(statistic);
}
+const BoundNetLog& URLRequestHttpJob::HttpFilterContext::GetNetLog() const {
+ return job_->request() ? job_->request()->net_log() : dummy_log_;
+}
+
// TODO(darin): make sure the port blocking code is not lost
// static
URLRequestJob* URLRequestHttpJob::Factory(URLRequest* request,
@@ -321,21 +331,42 @@
ProcessPublicKeyPinsHeader();
SdchManager* sdch_manager(request()->context()->sdch_manager());
- if (sdch_manager && sdch_manager->IsInSupportedDomain(request_->url())) {
- const std::string name = "Get-Dictionary";
- std::string url_text;
- void* iter = NULL;
- // TODO(jar): We need to not fetch dictionaries the first time they are
- // seen, but rather wait until we can justify their usefulness.
- // For now, we will only fetch the first dictionary, which will at least
- // require multiple suggestions before we get additional ones for this site.
- // Eventually we should wait until a dictionary is requested several times
- // before we even download it (so that we don't waste memory or bandwidth).
- if (GetResponseHeaders()->EnumerateHeader(&iter, name, &url_text)) {
- // Resolve suggested URL relative to request url.
- GURL sdch_dictionary_url = request_->url().Resolve(url_text);
- if (sdch_dictionary_url.is_valid()) {
- sdch_manager->OnGetDictionary(request_->url(), sdch_dictionary_url);
+ if (sdch_manager) {
+ SdchProblemCode rv = sdch_manager->IsInSupportedDomain(request()->url());
+ if (rv != SDCH_OK) {
+ // If SDCH is just disabled, it is not a real error.
+ if (rv != SDCH_DISABLED && rv != SDCH_SECURE_SCHEME_NOT_SUPPORTED) {
+ SdchManager::SdchErrorRecovery(rv);
+ request()->net_log().AddEvent(
+ NetLog::TYPE_SDCH_DECODING_ERROR,
+ base::Bind(&NetLogSdchResourceProblemCallback, rv));
+ }
+ } else {
+ const std::string name = "Get-Dictionary";
+ std::string url_text;
+ void* iter = NULL;
+ // TODO(jar): We need to not fetch dictionaries the first time they are
+ // seen, but rather wait until we can justify their usefulness.
+ // For now, we will only fetch the first dictionary, which will at least
+ // require multiple suggestions before we get additional ones for this
+ // site. Eventually we should wait until a dictionary is requested
+ // several times
+ // before we even download it (so that we don't waste memory or
+ // bandwidth).
+ if (GetResponseHeaders()->EnumerateHeader(&iter, name, &url_text)) {
+ // Resolve suggested URL relative to request url.
+ GURL sdch_dictionary_url = request_->url().Resolve(url_text);
+ if (sdch_dictionary_url.is_valid()) {
+ rv = sdch_manager->OnGetDictionary(request_->url(),
+ sdch_dictionary_url);
+ if (rv != SDCH_OK) {
+ SdchManager::SdchErrorRecovery(rv);
+ request_->net_log().AddEvent(
+ NetLog::TYPE_SDCH_DICTIONARY_ERROR,
+ base::Bind(&NetLogSdchDictionaryFetchProblemCallback, rv,
+ sdch_dictionary_url, false));
+ }
+ }
}
}
}
@@ -483,13 +514,24 @@
// simple_data_source.
if (!request_info_.extra_headers.HasHeader(
HttpRequestHeaders::kAcceptEncoding)) {
- bool advertise_sdch = sdch_manager &&
- // We don't support SDCH responses to POST as there is a possibility
- // of having SDCH encoded responses returned (e.g. by the cache)
- // which we cannot decode, and in those situations, we will need
- // to retransmit the request without SDCH, which is illegal for a POST.
- request()->method() != "POST" &&
- sdch_manager->IsInSupportedDomain(request_->url());
+ // We don't support SDCH responses to POST as there is a possibility
+ // of having SDCH encoded responses returned (e.g. by the cache)
+ // which we cannot decode, and in those situations, we will need
+ // to retransmit the request without SDCH, which is illegal for a POST.
+ bool advertise_sdch = sdch_manager != NULL && request()->method() != "POST";
+ if (advertise_sdch) {
+ SdchProblemCode rv = sdch_manager->IsInSupportedDomain(request()->url());
+ if (rv != SDCH_OK) {
+ advertise_sdch = false;
+ // If SDCH is just disabled, it is not a real error.
+ if (rv != SDCH_DISABLED && rv != SDCH_SECURE_SCHEME_NOT_SUPPORTED) {
+ SdchManager::SdchErrorRecovery(rv);
+ request()->net_log().AddEvent(
+ NetLog::TYPE_SDCH_DECODING_ERROR,
+ base::Bind(&NetLogSdchResourceProblemCallback, rv));
+ }
+ }
+ }
std::string avail_dictionaries;
if (advertise_sdch) {
sdch_manager->GetAvailDictionaryList(request_->url(),
diff --git a/net/url_request/url_request_job_manager.cc b/net/url_request/url_request_job_manager.cc
index 6fcff22..a1540fa 100644
--- a/net/url_request/url_request_job_manager.cc
+++ b/net/url_request/url_request_job_manager.cc
@@ -68,18 +68,6 @@
// See if the request should be intercepted.
//
-
- // TODO(pauljensen): Remove this when AppCacheInterceptor is a
- // ProtocolHandler, see crbug.com/161547.
- if (!(request->load_flags() & LOAD_DISABLE_INTERCEPT)) {
- InterceptorList::const_iterator i;
- for (i = interceptors_.begin(); i != interceptors_.end(); ++i) {
- URLRequestJob* job = (*i)->MaybeIntercept(request, network_delegate);
- if (job)
- return job;
- }
- }
-
URLRequestJob* job = job_factory->MaybeCreateJobWithProtocolHandler(
scheme, request, network_delegate);
if (job)
@@ -108,7 +96,6 @@
const GURL& location) const {
DCHECK(IsAllowedThread());
if (!request->url().is_valid() ||
- request->load_flags() & LOAD_DISABLE_INTERCEPT ||
request->status().status() == URLRequestStatus::CANCELED) {
return NULL;
}
@@ -120,15 +107,6 @@
if (!job_factory->IsHandledProtocol(scheme))
return NULL;
- InterceptorList::const_iterator i;
- for (i = interceptors_.begin(); i != interceptors_.end(); ++i) {
- URLRequestJob* job = (*i)->MaybeInterceptRedirect(request,
- network_delegate,
- location);
- if (job)
- return job;
- }
-
URLRequestJob* job =
request->context()->job_factory()->MaybeInterceptRedirect(
request, network_delegate, location);
@@ -142,7 +120,6 @@
URLRequest* request, NetworkDelegate* network_delegate) const {
DCHECK(IsAllowedThread());
if (!request->url().is_valid() ||
- request->load_flags() & LOAD_DISABLE_INTERCEPT ||
request->status().status() == URLRequestStatus::CANCELED) {
return NULL;
}
@@ -154,14 +131,6 @@
if (!job_factory->IsHandledProtocol(scheme))
return NULL;
- InterceptorList::const_iterator i;
- for (i = interceptors_.begin(); i != interceptors_.end(); ++i) {
- URLRequestJob* job = (*i)->MaybeInterceptResponse(request,
- network_delegate);
- if (job)
- return job;
- }
-
URLRequestJob* job =
request->context()->job_factory()->MaybeInterceptResponse(
request, network_delegate);
@@ -181,29 +150,6 @@
return false;
}
-void URLRequestJobManager::RegisterRequestInterceptor(
- URLRequest::Interceptor* interceptor) {
- DCHECK(IsAllowedThread());
-
- base::AutoLock locked(lock_);
-
- DCHECK(std::find(interceptors_.begin(), interceptors_.end(), interceptor) ==
- interceptors_.end());
- interceptors_.push_back(interceptor);
-}
-
-void URLRequestJobManager::UnregisterRequestInterceptor(
- URLRequest::Interceptor* interceptor) {
- DCHECK(IsAllowedThread());
-
- base::AutoLock locked(lock_);
-
- InterceptorList::iterator i =
- std::find(interceptors_.begin(), interceptors_.end(), interceptor);
- DCHECK(i != interceptors_.end());
- interceptors_.erase(i);
-}
-
URLRequestJobManager::URLRequestJobManager()
: allowed_thread_(0),
allowed_thread_initialized_(false) {
diff --git a/net/url_request/url_request_job_manager.h b/net/url_request/url_request_job_manager.h
index 9877bed..ca67e56 100644
--- a/net/url_request/url_request_job_manager.h
+++ b/net/url_request/url_request_job_manager.h
@@ -51,12 +51,7 @@
// Returns true if the manager has a built-in handler for |scheme|.
static bool SupportsScheme(const std::string& scheme);
- // Register/unregister a request interceptor.
- void RegisterRequestInterceptor(URLRequest::Interceptor* interceptor);
- void UnregisterRequestInterceptor(URLRequest::Interceptor* interceptor);
-
private:
- typedef std::vector<URLRequest::Interceptor*> InterceptorList;
friend struct DefaultSingletonTraits<URLRequestJobManager>;
URLRequestJobManager();
@@ -92,7 +87,6 @@
#endif
mutable base::Lock lock_;
- InterceptorList interceptors_;
DISALLOW_COPY_AND_ASSIGN(URLRequestJobManager);
};
diff --git a/net/url_request/url_request_simple_job.cc b/net/url_request/url_request_simple_job.cc
index b855932..55a0f88 100644
--- a/net/url_request/url_request_simple_job.cc
+++ b/net/url_request/url_request_simple_job.cc
@@ -8,6 +8,7 @@
#include "base/bind.h"
#include "base/compiler_specific.h"
+#include "base/memory/ref_counted_memory.h"
#include "base/message_loop/message_loop.h"
#include "base/profiler/scoped_tracker.h"
#include "net/base/io_buffer.h"
@@ -50,12 +51,31 @@
int remaining = byte_range_.last_byte_position() - data_offset_ + 1;
if (buf_size > remaining)
buf_size = remaining;
- memcpy(buf->data(), data_.data() + data_offset_, buf_size);
+ memcpy(buf->data(), data_->front() + data_offset_, buf_size);
data_offset_ += buf_size;
*bytes_read = buf_size;
return true;
}
+int URLRequestSimpleJob::GetData(std::string* mime_type,
+ std::string* charset,
+ std::string* data,
+ const CompletionCallback& callback) const {
+ NOTREACHED();
+ return ERR_UNEXPECTED;
+}
+
+int URLRequestSimpleJob::GetRefCountedData(
+ std::string* mime_type,
+ std::string* charset,
+ scoped_refptr<base::RefCountedMemory>* data,
+ const CompletionCallback& callback) const {
+ scoped_refptr<base::RefCountedString> str_data(new base::RefCountedString());
+ int result = GetData(mime_type, charset, &str_data->data(), callback);
+ *data = str_data;
+ return result;
+}
+
void URLRequestSimpleJob::StartAsync() {
if (!request_)
return;
@@ -82,11 +102,10 @@
FROM_HERE_WITH_EXPLICIT_FUNCTION(
"422489 URLRequestSimpleJob::StartAsync 2"));
- result = GetData(&mime_type_,
- &charset_,
- &data_,
- base::Bind(&URLRequestSimpleJob::OnGetDataCompleted,
- weak_factory_.GetWeakPtr()));
+ result =
+ GetRefCountedData(&mime_type_, &charset_, &data_,
+ base::Bind(&URLRequestSimpleJob::OnGetDataCompleted,
+ weak_factory_.GetWeakPtr()));
}
if (result != ERR_IO_PENDING) {
@@ -107,7 +126,7 @@
if (result == OK) {
// Notify that the headers are complete
- if (!byte_range_.ComputeBounds(data_.size())) {
+ if (!byte_range_.ComputeBounds(data_->size())) {
NotifyDone(URLRequestStatus(URLRequestStatus::FAILED,
ERR_REQUEST_RANGE_NOT_SATISFIABLE));
return;
diff --git a/net/url_request/url_request_simple_job.h b/net/url_request/url_request_simple_job.h
index 85d8f7e..99b6cb6 100644
--- a/net/url_request/url_request_simple_job.h
+++ b/net/url_request/url_request_simple_job.h
@@ -7,11 +7,17 @@
#include <string>
+#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
+#include "base/strings/string_piece.h"
#include "net/base/completion_callback.h"
#include "net/base/net_export.h"
#include "net/url_request/url_range_request_job.h"
+namespace base {
+class RefCountedMemory;
+}
+
namespace net {
class URLRequest;
@@ -28,7 +34,8 @@
protected:
~URLRequestSimpleJob() override;
- // Subclasses must override the way response data is determined.
+ // Subclasses must override either GetData or GetRefCountedData to define the
+ // way response data is determined.
// The return value should be:
// - OK if data is obtained;
// - ERR_IO_PENDING if async processing is needed to finish obtaining data.
@@ -41,9 +48,15 @@
virtual int GetData(std::string* mime_type,
std::string* charset,
std::string* data,
- const CompletionCallback& callback) const = 0;
+ const CompletionCallback& callback) const;
- protected:
+ // Similar to GetData(), except |*data| can share ownership of the bytes
+ // instead of copying them into a std::string.
+ virtual int GetRefCountedData(std::string* mime_type,
+ std::string* charset,
+ scoped_refptr<base::RefCountedMemory>* data,
+ const CompletionCallback& callback) const;
+
void StartAsync();
private:
@@ -52,7 +65,7 @@
HttpByteRange byte_range_;
std::string mime_type_;
std::string charset_;
- std::string data_;
+ scoped_refptr<base::RefCountedMemory> data_;
int data_offset_;
base::WeakPtrFactory<URLRequestSimpleJob> weak_factory_;
};
diff --git a/net/url_request/url_request_unittest.cc b/net/url_request/url_request_unittest.cc
index 2aeecc6..1d777dc 100644
--- a/net/url_request/url_request_unittest.cc
+++ b/net/url_request/url_request_unittest.cc
@@ -1158,445 +1158,6 @@
~CancelThenRestartTestJob() override {}
};
-// An Interceptor for use with interceptor tests
-class TestInterceptor : URLRequest::Interceptor {
- public:
- TestInterceptor()
- : intercept_main_request_(false), restart_main_request_(false),
- cancel_main_request_(false), cancel_then_restart_main_request_(false),
- simulate_main_network_error_(false),
- intercept_redirect_(false), cancel_redirect_request_(false),
- intercept_final_response_(false), cancel_final_request_(false),
- did_intercept_main_(false), did_restart_main_(false),
- did_cancel_main_(false), did_cancel_then_restart_main_(false),
- did_simulate_error_main_(false),
- did_intercept_redirect_(false), did_cancel_redirect_(false),
- did_intercept_final_(false), did_cancel_final_(false) {
- URLRequest::Deprecated::RegisterRequestInterceptor(this);
- }
-
- ~TestInterceptor() override {
- URLRequest::Deprecated::UnregisterRequestInterceptor(this);
- }
-
- URLRequestJob* MaybeIntercept(URLRequest* request,
- NetworkDelegate* network_delegate) override {
- if (restart_main_request_) {
- restart_main_request_ = false;
- did_restart_main_ = true;
- return new RestartTestJob(request, network_delegate);
- }
- if (cancel_main_request_) {
- cancel_main_request_ = false;
- did_cancel_main_ = true;
- return new CancelTestJob(request, network_delegate);
- }
- if (cancel_then_restart_main_request_) {
- cancel_then_restart_main_request_ = false;
- did_cancel_then_restart_main_ = true;
- return new CancelThenRestartTestJob(request, network_delegate);
- }
- if (simulate_main_network_error_) {
- simulate_main_network_error_ = false;
- did_simulate_error_main_ = true;
- // will error since the requeted url is not one of its canned urls
- return new URLRequestTestJob(request, network_delegate, true);
- }
- if (!intercept_main_request_)
- return NULL;
- intercept_main_request_ = false;
- did_intercept_main_ = true;
- URLRequestTestJob* job = new URLRequestTestJob(request,
- network_delegate,
- main_headers_,
- main_data_,
- true);
- job->set_load_timing_info(main_request_load_timing_info_);
- return job;
- }
-
- URLRequestJob* MaybeInterceptRedirect(URLRequest* request,
- NetworkDelegate* network_delegate,
- const GURL& location) override {
- if (cancel_redirect_request_) {
- cancel_redirect_request_ = false;
- did_cancel_redirect_ = true;
- return new CancelTestJob(request, network_delegate);
- }
- if (!intercept_redirect_)
- return NULL;
- intercept_redirect_ = false;
- did_intercept_redirect_ = true;
- return new URLRequestTestJob(request,
- network_delegate,
- redirect_headers_,
- redirect_data_,
- true);
- }
-
- URLRequestJob* MaybeInterceptResponse(
- URLRequest* request,
- NetworkDelegate* network_delegate) override {
- if (cancel_final_request_) {
- cancel_final_request_ = false;
- did_cancel_final_ = true;
- return new CancelTestJob(request, network_delegate);
- }
- if (!intercept_final_response_)
- return NULL;
- intercept_final_response_ = false;
- did_intercept_final_ = true;
- return new URLRequestTestJob(request,
- network_delegate,
- final_headers_,
- final_data_,
- true);
- }
-
- // Whether to intercept the main request, and if so the response to return and
- // the LoadTimingInfo to use.
- bool intercept_main_request_;
- std::string main_headers_;
- std::string main_data_;
- LoadTimingInfo main_request_load_timing_info_;
-
- // Other actions we take at MaybeIntercept time
- bool restart_main_request_;
- bool cancel_main_request_;
- bool cancel_then_restart_main_request_;
- bool simulate_main_network_error_;
-
- // Whether to intercept redirects, and if so the response to return.
- bool intercept_redirect_;
- std::string redirect_headers_;
- std::string redirect_data_;
-
- // Other actions we can take at MaybeInterceptRedirect time
- bool cancel_redirect_request_;
-
- // Whether to intercept final response, and if so the response to return.
- bool intercept_final_response_;
- std::string final_headers_;
- std::string final_data_;
-
- // Other actions we can take at MaybeInterceptResponse time
- bool cancel_final_request_;
-
- // If we did something or not
- bool did_intercept_main_;
- bool did_restart_main_;
- bool did_cancel_main_;
- bool did_cancel_then_restart_main_;
- bool did_simulate_error_main_;
- bool did_intercept_redirect_;
- bool did_cancel_redirect_;
- bool did_intercept_final_;
- bool did_cancel_final_;
-
- // Static getters for canned response header and data strings
-
- static std::string ok_data() {
- return URLRequestTestJob::test_data_1();
- }
-
- static std::string ok_headers() {
- return URLRequestTestJob::test_headers();
- }
-
- static std::string redirect_data() {
- return std::string();
- }
-
- static std::string redirect_headers() {
- return URLRequestTestJob::test_redirect_headers();
- }
-
- static std::string error_data() {
- return std::string("ohhh nooooo mr. bill!");
- }
-
- static std::string error_headers() {
- return URLRequestTestJob::test_error_headers();
- }
-};
-
-TEST_F(URLRequestTest, Intercept) {
- TestInterceptor interceptor;
-
- // intercept the main request and respond with a simple response
- interceptor.intercept_main_request_ = true;
- interceptor.main_headers_ = TestInterceptor::ok_headers();
- interceptor.main_data_ = TestInterceptor::ok_data();
-
- TestDelegate d;
- scoped_ptr<URLRequest> req(default_context_.CreateRequest(
- GURL("http://test_intercept/foo"), DEFAULT_PRIORITY, &d, NULL));
- base::SupportsUserData::Data* user_data0 = new base::SupportsUserData::Data();
- base::SupportsUserData::Data* user_data1 = new base::SupportsUserData::Data();
- base::SupportsUserData::Data* user_data2 = new base::SupportsUserData::Data();
- req->SetUserData(NULL, user_data0);
- req->SetUserData(&user_data1, user_data1);
- req->SetUserData(&user_data2, user_data2);
- req->set_method("GET");
- req->Start();
- base::RunLoop().Run();
-
- // Make sure we can retrieve our specific user data
- EXPECT_EQ(user_data0, req->GetUserData(NULL));
- EXPECT_EQ(user_data1, req->GetUserData(&user_data1));
- EXPECT_EQ(user_data2, req->GetUserData(&user_data2));
-
- // Check the interceptor got called as expected
- EXPECT_TRUE(interceptor.did_intercept_main_);
-
- // Check we got one good response
- EXPECT_TRUE(req->status().is_success());
- EXPECT_EQ(200, req->response_headers()->response_code());
- EXPECT_EQ(TestInterceptor::ok_data(), d.data_received());
- EXPECT_EQ(1, d.response_started_count());
- EXPECT_EQ(0, d.received_redirect_count());
-}
-
-TEST_F(URLRequestTest, InterceptRedirect) {
- TestInterceptor interceptor;
-
- // intercept the main request and respond with a redirect
- interceptor.intercept_main_request_ = true;
- interceptor.main_headers_ = TestInterceptor::redirect_headers();
- interceptor.main_data_ = TestInterceptor::redirect_data();
-
- // intercept that redirect and respond a final OK response
- interceptor.intercept_redirect_ = true;
- interceptor.redirect_headers_ = TestInterceptor::ok_headers();
- interceptor.redirect_data_ = TestInterceptor::ok_data();
-
- TestDelegate d;
- scoped_ptr<URLRequest> req(default_context_.CreateRequest(
- GURL("http://test_intercept/foo"), DEFAULT_PRIORITY, &d, NULL));
- req->set_method("GET");
- req->Start();
- base::RunLoop().Run();
-
- // Check the interceptor got called as expected
- EXPECT_TRUE(interceptor.did_intercept_main_);
- EXPECT_TRUE(interceptor.did_intercept_redirect_);
-
- // Check we got one good response
- EXPECT_TRUE(req->status().is_success());
- if (req->status().is_success()) {
- EXPECT_EQ(200, req->response_headers()->response_code());
- }
- EXPECT_EQ(TestInterceptor::ok_data(), d.data_received());
- EXPECT_EQ(1, d.response_started_count());
- EXPECT_EQ(0, d.received_redirect_count());
-}
-
-TEST_F(URLRequestTest, InterceptServerError) {
- TestInterceptor interceptor;
-
- // intercept the main request to generate a server error response
- interceptor.intercept_main_request_ = true;
- interceptor.main_headers_ = TestInterceptor::error_headers();
- interceptor.main_data_ = TestInterceptor::error_data();
-
- // intercept that error and respond with an OK response
- interceptor.intercept_final_response_ = true;
- interceptor.final_headers_ = TestInterceptor::ok_headers();
- interceptor.final_data_ = TestInterceptor::ok_data();
-
- TestDelegate d;
- scoped_ptr<URLRequest> req(default_context_.CreateRequest(
- GURL("http://test_intercept/foo"), DEFAULT_PRIORITY, &d, NULL));
- req->set_method("GET");
- req->Start();
- base::RunLoop().Run();
-
- // Check the interceptor got called as expected
- EXPECT_TRUE(interceptor.did_intercept_main_);
- EXPECT_TRUE(interceptor.did_intercept_final_);
-
- // Check we got one good response
- EXPECT_TRUE(req->status().is_success());
- EXPECT_EQ(200, req->response_headers()->response_code());
- EXPECT_EQ(TestInterceptor::ok_data(), d.data_received());
- EXPECT_EQ(1, d.response_started_count());
- EXPECT_EQ(0, d.received_redirect_count());
-}
-
-TEST_F(URLRequestTest, InterceptNetworkError) {
- TestInterceptor interceptor;
-
- // intercept the main request to simulate a network error
- interceptor.simulate_main_network_error_ = true;
-
- // intercept that error and respond with an OK response
- interceptor.intercept_final_response_ = true;
- interceptor.final_headers_ = TestInterceptor::ok_headers();
- interceptor.final_data_ = TestInterceptor::ok_data();
-
- TestDelegate d;
- scoped_ptr<URLRequest> req(default_context_.CreateRequest(
- GURL("http://test_intercept/foo"), DEFAULT_PRIORITY, &d, NULL));
- req->set_method("GET");
- req->Start();
- base::RunLoop().Run();
-
- // Check the interceptor got called as expected
- EXPECT_TRUE(interceptor.did_simulate_error_main_);
- EXPECT_TRUE(interceptor.did_intercept_final_);
-
- // Check we received one good response
- EXPECT_TRUE(req->status().is_success());
- EXPECT_EQ(200, req->response_headers()->response_code());
- EXPECT_EQ(TestInterceptor::ok_data(), d.data_received());
- EXPECT_EQ(1, d.response_started_count());
- EXPECT_EQ(0, d.received_redirect_count());
-}
-
-TEST_F(URLRequestTest, InterceptRestartRequired) {
- TestInterceptor interceptor;
-
- // restart the main request
- interceptor.restart_main_request_ = true;
-
- // then intercept the new main request and respond with an OK response
- interceptor.intercept_main_request_ = true;
- interceptor.main_headers_ = TestInterceptor::ok_headers();
- interceptor.main_data_ = TestInterceptor::ok_data();
-
- TestDelegate d;
- scoped_ptr<URLRequest> req(default_context_.CreateRequest(
- GURL("http://test_intercept/foo"), DEFAULT_PRIORITY, &d, NULL));
- req->set_method("GET");
- req->Start();
- base::RunLoop().Run();
-
- // Check the interceptor got called as expected
- EXPECT_TRUE(interceptor.did_restart_main_);
- EXPECT_TRUE(interceptor.did_intercept_main_);
-
- // Check we received one good response
- EXPECT_TRUE(req->status().is_success());
- if (req->status().is_success()) {
- EXPECT_EQ(200, req->response_headers()->response_code());
- }
- EXPECT_EQ(TestInterceptor::ok_data(), d.data_received());
- EXPECT_EQ(1, d.response_started_count());
- EXPECT_EQ(0, d.received_redirect_count());
-}
-
-TEST_F(URLRequestTest, InterceptRespectsCancelMain) {
- TestInterceptor interceptor;
-
- // intercept the main request and cancel from within the restarted job
- interceptor.cancel_main_request_ = true;
-
- // setup to intercept final response and override it with an OK response
- interceptor.intercept_final_response_ = true;
- interceptor.final_headers_ = TestInterceptor::ok_headers();
- interceptor.final_data_ = TestInterceptor::ok_data();
-
- TestDelegate d;
- scoped_ptr<URLRequest> req(default_context_.CreateRequest(
- GURL("http://test_intercept/foo"), DEFAULT_PRIORITY, &d, NULL));
- req->set_method("GET");
- req->Start();
- base::RunLoop().Run();
-
- // Check the interceptor got called as expected
- EXPECT_TRUE(interceptor.did_cancel_main_);
- EXPECT_FALSE(interceptor.did_intercept_final_);
-
- // Check we see a canceled request
- EXPECT_FALSE(req->status().is_success());
- EXPECT_EQ(URLRequestStatus::CANCELED, req->status().status());
-}
-
-TEST_F(URLRequestTest, InterceptRespectsCancelRedirect) {
- TestInterceptor interceptor;
-
- // intercept the main request and respond with a redirect
- interceptor.intercept_main_request_ = true;
- interceptor.main_headers_ = TestInterceptor::redirect_headers();
- interceptor.main_data_ = TestInterceptor::redirect_data();
-
- // intercept the redirect and cancel from within that job
- interceptor.cancel_redirect_request_ = true;
-
- // setup to intercept final response and override it with an OK response
- interceptor.intercept_final_response_ = true;
- interceptor.final_headers_ = TestInterceptor::ok_headers();
- interceptor.final_data_ = TestInterceptor::ok_data();
-
- TestDelegate d;
- scoped_ptr<URLRequest> req(default_context_.CreateRequest(
- GURL("http://test_intercept/foo"), DEFAULT_PRIORITY, &d, NULL));
- req->set_method("GET");
- req->Start();
- base::RunLoop().Run();
-
- // Check the interceptor got called as expected
- EXPECT_TRUE(interceptor.did_intercept_main_);
- EXPECT_TRUE(interceptor.did_cancel_redirect_);
- EXPECT_FALSE(interceptor.did_intercept_final_);
-
- // Check we see a canceled request
- EXPECT_FALSE(req->status().is_success());
- EXPECT_EQ(URLRequestStatus::CANCELED, req->status().status());
-}
-
-TEST_F(URLRequestTest, InterceptRespectsCancelFinal) {
- TestInterceptor interceptor;
-
- // intercept the main request to simulate a network error
- interceptor.simulate_main_network_error_ = true;
-
- // setup to intercept final response and cancel from within that job
- interceptor.cancel_final_request_ = true;
-
- TestDelegate d;
- scoped_ptr<URLRequest> req(default_context_.CreateRequest(
- GURL("http://test_intercept/foo"), DEFAULT_PRIORITY, &d, NULL));
- req->set_method("GET");
- req->Start();
- base::RunLoop().Run();
-
- // Check the interceptor got called as expected
- EXPECT_TRUE(interceptor.did_simulate_error_main_);
- EXPECT_TRUE(interceptor.did_cancel_final_);
-
- // Check we see a canceled request
- EXPECT_FALSE(req->status().is_success());
- EXPECT_EQ(URLRequestStatus::CANCELED, req->status().status());
-}
-
-TEST_F(URLRequestTest, InterceptRespectsCancelInRestart) {
- TestInterceptor interceptor;
-
- // intercept the main request and cancel then restart from within that job
- interceptor.cancel_then_restart_main_request_ = true;
-
- // setup to intercept final response and override it with an OK response
- interceptor.intercept_final_response_ = true;
- interceptor.final_headers_ = TestInterceptor::ok_headers();
- interceptor.final_data_ = TestInterceptor::ok_data();
-
- TestDelegate d;
- scoped_ptr<URLRequest> req(default_context_.CreateRequest(
- GURL("http://test_intercept/foo"), DEFAULT_PRIORITY, &d, NULL));
- req->set_method("GET");
- req->Start();
- base::RunLoop().Run();
-
- // Check the interceptor got called as expected
- EXPECT_TRUE(interceptor.did_cancel_then_restart_main_);
- EXPECT_FALSE(interceptor.did_intercept_final_);
-
- // Check we see a canceled request
- EXPECT_FALSE(req->status().is_success());
- EXPECT_EQ(URLRequestStatus::CANCELED, req->status().status());
-}
-
// An Interceptor for use with interceptor tests.
class MockURLRequestInterceptor : public URLRequestInterceptor {
public:
@@ -2144,8 +1705,8 @@
// Set up to intercept the final response and override it with an OK response.
interceptor()->set_intercept_final_response(true);
- interceptor()->set_final_headers(TestInterceptor::ok_headers());
- interceptor()->set_final_data(TestInterceptor::ok_data());
+ interceptor()->set_final_headers(MockURLRequestInterceptor::ok_headers());
+ interceptor()->set_final_data(MockURLRequestInterceptor::ok_data());
TestDelegate d;
scoped_ptr<URLRequest> req(default_context().CreateRequest(