diff options
Diffstat (limited to 'net')
218 files changed, 10264 insertions, 2147 deletions
diff --git a/net/base/cert_database.h b/net/base/cert_database.h index 377c0a8..7915cc6 100644 --- a/net/base/cert_database.h +++ b/net/base/cert_database.h @@ -67,7 +67,7 @@ class CertDatabase { // the platform cert database, or possibly other network error codes. int AddUserCert(X509Certificate* cert); -#if defined(USE_NSS) +#if defined(USE_NSS) || defined(USE_OPENSSL) // Get a list of unique certificates in the certificate database. (One // instance of all certificates.) void ListCerts(CertificateList* certs); @@ -124,6 +124,9 @@ class CertDatabase { // Returns true on success or false on failure. // |cert| is still valid when this function returns. bool DeleteCertAndKey(const X509Certificate* cert); + + // Check whether cert is stored in a readonly slot. + bool IsReadOnly(const X509Certificate* cert) const; #endif private: diff --git a/net/base/cert_database_nss.cc b/net/base/cert_database_nss.cc index 8445d4d..a32a7a3 100644 --- a/net/base/cert_database_nss.cc +++ b/net/base/cert_database_nss.cc @@ -168,7 +168,6 @@ unsigned int CertDatabase::GetCertTrust( trust.HasTrustedCA(PR_FALSE, PR_TRUE, PR_FALSE) * TRUSTED_EMAIL + trust.HasTrustedCA(PR_FALSE, PR_FALSE, PR_TRUE) * TRUSTED_OBJ_SIGN; case SERVER_CERT: - case EMAIL_CERT: return trust.HasTrustedPeer(PR_TRUE, PR_FALSE, PR_FALSE) * TRUSTED_SSL + trust.HasTrustedPeer(PR_FALSE, PR_TRUE, PR_FALSE) * TRUSTED_EMAIL + trust.HasTrustedPeer(PR_FALSE, PR_FALSE, PR_TRUE) * TRUSTED_OBJ_SIGN; @@ -205,4 +204,9 @@ bool CertDatabase::DeleteCertAndKey(const X509Certificate* cert) { return true; } +bool CertDatabase::IsReadOnly(const X509Certificate* cert) const { + PK11SlotInfo* slot = cert->os_cert_handle()->slot; + return slot && PK11_IsReadOnly(slot); +} + } // namespace net diff --git a/net/base/cert_test_util.cc b/net/base/cert_test_util.cc index cb7f9a8..1042d50 100644 --- a/net/base/cert_test_util.cc +++ b/net/base/cert_test_util.cc @@ -26,9 +26,27 @@ namespace net { #if defined(USE_OPENSSL) -X509Certificate* LoadTemporaryRootCert(const FilePath& filename) { +X509Certificate* AddTemporaryRootCertToStore(X509* x509_cert) { OpenSSLInitSingleton* openssl_init = GetOpenSSLInitSingleton(); + if (!X509_STORE_add_cert(openssl_init->x509_store(), x509_cert)) { + unsigned long error_code = ERR_get_error(); + if (ERR_GET_LIB(error_code) != ERR_LIB_X509 || + ERR_GET_REASON(error_code) != X509_R_CERT_ALREADY_IN_HASH_TABLE) { + do { + LOG(ERROR) << "X509_STORE_add_cert error: " << error_code; + } while ((error_code = ERR_get_error()) != 0); + return NULL; + } + } + return X509Certificate::CreateFromHandle( + x509_cert, X509Certificate::SOURCE_LONE_CERT_IMPORT, + X509Certificate::OSCertHandles()); +} + +X509Certificate* LoadTemporaryRootCert(const FilePath& filename) { + EnsureOpenSSLInit(); + std::string rawcert; if (!file_util::ReadFileToString(filename, &rawcert)) { LOG(ERROR) << "Can't load certificate " << filename.value(); @@ -43,27 +61,21 @@ X509Certificate* LoadTemporaryRootCert(const FilePath& filename) { return NULL; } - ScopedSSL<X509, X509_free> x509_cert(PEM_read_bio_X509(cert_bio.get(), - NULL, NULL, NULL)); - if (!x509_cert.get()) { - LOG(ERROR) << "Can't parse certificate " << filename.value(); - return NULL; - } - - if (!X509_STORE_add_cert(openssl_init->x509_store(), x509_cert.get())) { - unsigned long error_code = ERR_get_error(); - if (ERR_GET_LIB(error_code) != ERR_LIB_X509 || - ERR_GET_REASON(error_code) != X509_R_CERT_ALREADY_IN_HASH_TABLE) { - do { - LOG(ERROR) << "X509_STORE_add_cert error: " << error_code; - } while ((error_code = ERR_get_error()) != 0); - return NULL; - } - } - - return X509Certificate::CreateFromHandle( - x509_cert.get(), X509Certificate::SOURCE_LONE_CERT_IMPORT, - X509Certificate::OSCertHandles()); + ScopedSSL<X509, X509_free> pem_cert(PEM_read_bio_X509(cert_bio.get(), + NULL, NULL, NULL)); + if (pem_cert.get()) + return AddTemporaryRootCertToStore(pem_cert.get()); + + // File does not contain PEM data, let's try DER. + const unsigned char* der_data = + reinterpret_cast<const unsigned char*>(rawcert.c_str()); + int der_length = rawcert.length(); + ScopedSSL<X509, X509_free> der_cert(d2i_X509(NULL, &der_data, der_length)); + if (der_cert.get()) + return AddTemporaryRootCertToStore(der_cert.get()); + + LOG(ERROR) << "Can't parse certificate " << filename.value(); + return NULL; } #elif defined(USE_NSS) X509Certificate* LoadTemporaryRootCert(const FilePath& filename) { diff --git a/net/base/cert_test_util.h b/net/base/cert_test_util.h index 45c8ed3..8709156 100644 --- a/net/base/cert_test_util.h +++ b/net/base/cert_test_util.h @@ -14,7 +14,7 @@ namespace net { class X509Certificate; -#if defined(USE_NSS) || defined(OS_MACOSX) +#if defined(USE_NSS) || defined(OS_MACOSX) || defined(USE_OPENSSL) // Loads and trusts a root CA certificate (stored in a file) temporarily. // TODO(wtc): Implement this function on Windows (http://crbug.com/8470). X509Certificate* LoadTemporaryRootCert(const FilePath& filename); diff --git a/net/base/cert_type.h b/net/base/cert_type.h index fbe4339..d9cb8a5 100644 --- a/net/base/cert_type.h +++ b/net/base/cert_type.h @@ -11,16 +11,14 @@ namespace net { // This is only used in the context of CertDatabase, but is defined outside to // avoid an awkwardly long type name. // The type is a combination of intrinsic properties, such as the presense of an -// email address or Certificate Authority Basic Constraint, and assigned trust -// values. For example, a cert with no email address, basic constraints, or -// trust, would be classified as UNKNOWN_CERT. If that cert is then trusted -// with SetCertTrust(cert, SERVER_CERT, TRUSTED_SSL), it would become a -// SERVER_CERT. +// Certificate Authority Basic Constraint, and assigned trust values. For +// example, a cert with no basic constraints or trust would be classified as +// UNKNOWN_CERT. If that cert is then trusted with SetCertTrust(cert, +// SERVER_CERT, TRUSTED_SSL), it would become a SERVER_CERT. enum CertType { UNKNOWN_CERT, CA_CERT, USER_CERT, - EMAIL_CERT, SERVER_CERT, NUM_CERT_TYPES }; diff --git a/net/base/connection_type_histograms.h b/net/base/connection_type_histograms.h index e6c2a59..e3e4a84 100644 --- a/net/base/connection_type_histograms.h +++ b/net/base/connection_type_histograms.h @@ -30,6 +30,11 @@ enum ConnectionType { // in the certificate chain (excluding root) CONNECTION_HTTP = 7, // An HTTP connection CONNECTION_SPDY = 8, // A SPDY connection + CONNECTION_SSL_SSL2 = 9, // An SSL connection that uses SSL 2.0 + CONNECTION_SSL_SSL3 = 10, // An SSL connection that uses SSL 3.0 + CONNECTION_SSL_TLS1 = 11, // An SSL connection that uses TLS 1.0 + CONNECTION_SSL_TLS1_1 = 12, // An SSL connection that uses TLS 1.1 + CONNECTION_SSL_TLS1_2 = 13, // An SSL connection that uses TLS 1.2 NUM_OF_CONNECTION_TYPES }; diff --git a/net/base/cookie_monster.cc b/net/base/cookie_monster.cc index de00016..2fb8d0f 100644 --- a/net/base/cookie_monster.cc +++ b/net/base/cookie_monster.cc @@ -90,6 +90,13 @@ struct OrderByCreationTimeDesc { } }; +// Constants for use in VLOG +const int kVlogPerCookieMonster = 1; +const int kVlogPeriodic = 3; +const int kVlogGarbageCollection = 5; +const int kVlogSetCookies = 7; +const int kVlogGetCookies = 9; + } // namespace // static @@ -724,7 +731,8 @@ bool CookieMonster::HasCookieableScheme(const GURL& url) { } // The scheme didn't match any in our whitelist. - DVLOG(1) << "WARNING: Unsupported cookie scheme: " << url.scheme(); + VLOG(kVlogPerCookieMonster) << "WARNING: Unsupported cookie scheme: " + << url.scheme(); return false; } @@ -747,7 +755,7 @@ bool CookieMonster::SetCookieWithCreationTimeAndOptions( const CookieOptions& options) { lock_.AssertAcquired(); - DVLOG(1) << "SetCookie() line: " << cookie_line; + VLOG(kVlogSetCookies) << "SetCookie() line: " << cookie_line; Time creation_time = creation_time_or_null; if (creation_time.is_null()) { @@ -759,12 +767,12 @@ bool CookieMonster::SetCookieWithCreationTimeAndOptions( ParsedCookie pc(cookie_line); if (!pc.IsValid()) { - DVLOG(1) << "WARNING: Couldn't parse cookie"; + VLOG(kVlogSetCookies) << "WARNING: Couldn't parse cookie"; return false; } if (options.exclude_httponly() && pc.IsHttpOnly()) { - DVLOG(1) << "SetCookie() not setting httponly cookie"; + VLOG(kVlogSetCookies) << "SetCookie() not setting httponly cookie"; return false; } @@ -785,7 +793,7 @@ bool CookieMonster::SetCookieWithCreationTimeAndOptions( !cookie_expires.is_null(), cookie_expires)); if (!cc.get()) { - DVLOG(1) << "WARNING: Failed to allocate CanonicalCookie"; + VLOG(kVlogSetCookies) << "WARNING: Failed to allocate CanonicalCookie"; return false; } return SetCanonicalCookie(&cc, creation_time, options); @@ -839,11 +847,12 @@ bool CookieMonster::SetCanonicalCookie(scoped_ptr<CanonicalCookie>* cc, const CookieOptions& options) { const std::string key(GetKey((*cc)->Domain())); if (DeleteAnyEquivalentCookie(key, **cc, options.exclude_httponly())) { - DVLOG(1) << "SetCookie() not clobbering httponly cookie"; + VLOG(kVlogSetCookies) << "SetCookie() not clobbering httponly cookie"; return false; } - DVLOG(1) << "SetCookie() key: " << key << " cc: " << (*cc)->DebugString(); + VLOG(kVlogSetCookies) << "SetCookie() key: " << key << " cc: " + << (*cc)->DebugString(); // Realize that we might be setting an expired cookie, and the only point // was to delete the cookie which we've already done. @@ -906,7 +915,7 @@ void CookieMonster::InternalDeleteCookie(CookieMap::iterator it, histogram_cookie_deletion_cause_->Add(deletion_cause); CanonicalCookie* cc = it->second; - DVLOG(1) << "InternalDeleteCookie() cc: " << cc->DebugString(); + VLOG(kVlogSetCookies) << "InternalDeleteCookie() cc: " << cc->DebugString(); if (cc->IsPersistent() && store_ && sync_to_store) store_->DeleteCookie(*cc); @@ -973,7 +982,8 @@ static bool FindLeastRecentlyAccessed( std::vector<CookieMonster::CookieMap::iterator>* cookie_its) { DCHECK_LE(num_purge, num_max); if (cookie_its->size() > num_max) { - DVLOG(1) << "FindLeastRecentlyAccessed() Deep Garbage Collect."; + VLOG(kVlogGarbageCollection) + << "FindLeastRecentlyAccessed() Deep Garbage Collect."; num_purge += cookie_its->size() - num_max; DCHECK_GT(cookie_its->size(), num_purge); @@ -1020,7 +1030,7 @@ int CookieMonster::GarbageCollect(const Time& current, // Collect garbage for this key. if (cookies_.count(key) > kDomainMaxCookies) { - DVLOG(1) << "GarbageCollect() key: " << key; + VLOG(kVlogGarbageCollection) << "GarbageCollect() key: " << key; std::vector<CookieMap::iterator> cookie_its; num_deleted += GarbageCollectExpired( @@ -1056,7 +1066,7 @@ int CookieMonster::GarbageCollect(const Time& current, (expiry_and_key_scheme_ == EKS_DISCARD_RECENT_AND_PURGE_DOMAIN || earliest_access_time_ < Time::Now() - TimeDelta::FromDays(kSafeFromGlobalPurgeDays))) { - DVLOG(1) << "GarbageCollect() everything"; + VLOG(kVlogGarbageCollection) << "GarbageCollect() everything"; std::vector<CookieMap::iterator> cookie_its; base::Time oldest_left; num_deleted += GarbageCollectExpired( @@ -1067,7 +1077,7 @@ int CookieMonster::GarbageCollect(const Time& current, Time oldest_safe_cookie( expiry_and_key_scheme_ == EKS_KEEP_RECENT_AND_PURGE_ETLDP1 ? (Time::Now() - TimeDelta::FromDays(kSafeFromGlobalPurgeDays)) : - Time::Now()); + Time()); // Null time == ignore access time. int num_evicted = GarbageCollectDeleteList( current, oldest_safe_cookie, @@ -1259,7 +1269,7 @@ std::string CookieMonster::GetCookiesWithOptions(const GURL& url, histogram_time_get_->AddTime(TimeTicks::Now() - start_time); - DVLOG(1) << "GetCookies() result: " << cookie_line; + VLOG(kVlogGetCookies) << "GetCookies() result: " << cookie_line; return cookie_line; } @@ -1497,8 +1507,9 @@ void CookieMonster::RecordPeriodicStats(const base::Time& current_time) { it_key = its_cookies.second; } - DVLOG(1) << "Time for recording cookie stats (us): " - << (TimeTicks::Now() - beginning_of_time).InMicroseconds(); + VLOG(kVlogPeriodic) + << "Time for recording cookie stats (us): " + << (TimeTicks::Now() - beginning_of_time).InMicroseconds(); last_statistic_record_time_ = current_time; } diff --git a/net/base/cookie_monster_perftest.cc b/net/base/cookie_monster_perftest.cc index c006128..8c64d9a 100644 --- a/net/base/cookie_monster_perftest.cc +++ b/net/base/cookie_monster_perftest.cc @@ -283,10 +283,10 @@ TEST(CookieMonsterTest, TestGCTimes) { }; for (int ci = 0; ci < static_cast<int>(ARRAYSIZE_UNSAFE(test_cases)); ++ci) { const TestCase& test_case(test_cases[ci]); - scoped_refptr<CookieMonster> cm = + scoped_refptr<CookieMonster> cm( CreateMonsterFromStoreForGC( test_case.num_cookies, test_case.num_old_cookies, - CookieMonster::kSafeFromGlobalPurgeDays * 2); + CookieMonster::kSafeFromGlobalPurgeDays * 2)); GURL gurl("http://google.com"); std::string cookie_line("z=3"); diff --git a/net/base/cookie_monster_unittest.cc b/net/base/cookie_monster_unittest.cc index 80d58ed..751b255 100644 --- a/net/base/cookie_monster_unittest.cc +++ b/net/base/cookie_monster_unittest.cc @@ -1852,7 +1852,7 @@ TEST(CookieMonsterTest, BackingStoreCommunication) { // Create new cookies and flush them to the store. { - scoped_refptr<net::CookieMonster> cmout = new CookieMonster(store, NULL); + scoped_refptr<net::CookieMonster> cmout(new CookieMonster(store, NULL)); for (const CookiesInputInfo* p = input_info; p < &input_info[ARRAYSIZE_UNSAFE(input_info)]; p++) { EXPECT_TRUE(cmout->SetCookieWithDetails(GURL(p->gurl), p->name, p->value, @@ -1866,7 +1866,7 @@ TEST(CookieMonsterTest, BackingStoreCommunication) { // Create a new cookie monster and make sure that everything is correct { - scoped_refptr<net::CookieMonster> cmin = new CookieMonster(store, NULL); + scoped_refptr<net::CookieMonster> cmin(new CookieMonster(store, NULL)); CookieMonster::CookieList cookies(cmin->GetAllCookies()); ASSERT_EQ(2u, cookies.size()); // Ordering is path length, then creation time. So second cookie @@ -1895,7 +1895,7 @@ TEST(CookieMonsterTest, BackingStoreCommunication) { TEST(CookieMonsterTest, CookieOrdering) { // Put a random set of cookies into a monster and make sure // they're returned in the right order. - scoped_refptr<net::CookieMonster> cm = new CookieMonster(NULL, NULL); + scoped_refptr<net::CookieMonster> cm(new CookieMonster(NULL, NULL)); EXPECT_TRUE(cm->SetCookie(GURL("http://d.c.b.a.google.com/aa/x.html"), "c=1")); EXPECT_TRUE(cm->SetCookie(GURL("http://b.a.google.com/aa/bb/cc/x.html"), @@ -1953,13 +1953,12 @@ static net::CookieMonster* CreateMonsterForGC(int num_cookies) { // get rid of cookies when we should). The perftest is probing for // whether garbage collection happens when it shouldn't. See comments // before that test for more details. -// Flaky as per http://crbug.com/60015 -TEST(CookieMonsterTest, FLAKY_GarbageCollectionTriggers) { +TEST(CookieMonsterTest, GarbageCollectionTriggers) { // First we check to make sure that a whole lot of recent cookies // doesn't get rid of anything after garbage collection is checked for. { - scoped_refptr<net::CookieMonster> cm = - CreateMonsterForGC(CookieMonster::kMaxCookies * 2); + scoped_refptr<net::CookieMonster> cm( + CreateMonsterForGC(CookieMonster::kMaxCookies * 2)); EXPECT_EQ(CookieMonster::kMaxCookies * 2, cm->GetAllCookies().size()); cm->SetCookie(GURL("http://newdomain.com"), "b=2"); EXPECT_EQ(CookieMonster::kMaxCookies * 2 + 1, cm->GetAllCookies().size()); @@ -2017,10 +2016,10 @@ TEST(CookieMonsterTest, FLAKY_GarbageCollectionTriggers) { recent_scheme < static_cast<int>(ARRAYSIZE_UNSAFE(schemes)); recent_scheme++) { const TestCase *test_case = &test_cases[ci]; - scoped_refptr<net::CookieMonster> cm = + scoped_refptr<net::CookieMonster> cm( CreateMonsterFromStoreForGC( test_case->num_cookies, test_case->num_old_cookies, - CookieMonster::kSafeFromGlobalPurgeDays * 2); + CookieMonster::kSafeFromGlobalPurgeDays * 2)); cm->SetExpiryAndKeyScheme(schemes[recent_scheme]); EXPECT_EQ(test_case->expected_initial_cookies, static_cast<int>(cm->GetAllCookies().size())) diff --git a/net/base/directory_lister_unittest.cc b/net/base/directory_lister_unittest.cc index f75d8d8..5607bc5 100644 --- a/net/base/directory_lister_unittest.cc +++ b/net/base/directory_lister_unittest.cc @@ -77,8 +77,8 @@ TEST(DirectoryListerTest, BigDirTest) { ASSERT_TRUE(PathService::Get(base::DIR_SOURCE_ROOT, &path)); ListerDelegate delegate(false); - scoped_refptr<net::DirectoryLister> lister = - new net::DirectoryLister(path, &delegate); + scoped_refptr<net::DirectoryLister> lister( + new net::DirectoryLister(path, &delegate)); lister->Start(); @@ -92,11 +92,11 @@ TEST(DirectoryListerTest, BigDirRecursiveTest) { ASSERT_TRUE(PathService::Get(base::DIR_EXE, &path)); ListerDelegate delegate(true); - scoped_refptr<net::DirectoryLister> lister = + scoped_refptr<net::DirectoryLister> lister( new net::DirectoryLister(path, true, net::DirectoryLister::FULL_PATH, - &delegate); + &delegate)); lister->Start(); @@ -110,8 +110,8 @@ TEST(DirectoryListerTest, CancelTest) { ASSERT_TRUE(PathService::Get(base::DIR_SOURCE_ROOT, &path)); ListerDelegate delegate(false); - scoped_refptr<net::DirectoryLister> lister = - new net::DirectoryLister(path, &delegate); + scoped_refptr<net::DirectoryLister> lister( + new net::DirectoryLister(path, &delegate)); lister->Start(); lister->Cancel(); diff --git a/net/base/ev_root_ca_metadata.cc b/net/base/ev_root_ca_metadata.cc index 7c1c96a..7de971b 100644 --- a/net/base/ev_root_ca_metadata.cc +++ b/net/base/ev_root_ca_metadata.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Copyright (c) 2010 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. @@ -9,6 +9,8 @@ #include <pkcs11n.h> #include <secerr.h> #include <secoid.h> +#elif defined(OS_WIN) +#include <stdlib.h> #endif #include "base/logging.h" @@ -251,6 +253,36 @@ static const EVMetadata ev_root_ca_metadata[] = { } }; +#if defined(OS_WIN) +// static +const EVRootCAMetadata::PolicyOID EVRootCAMetadata::policy_oids_[] = { + // The OIDs must be sorted in ascending order. + "1.2.392.200091.100.721.1", + "1.3.6.1.4.1.14370.1.6", + "1.3.6.1.4.1.22234.2.5.2.3.1", + "1.3.6.1.4.1.23223.1.1.1", + "1.3.6.1.4.1.34697.2.1", + "1.3.6.1.4.1.34697.2.2", + "1.3.6.1.4.1.34697.2.3", + "1.3.6.1.4.1.34697.2.4", + "1.3.6.1.4.1.4146.1.1", + "1.3.6.1.4.1.6334.1.100.1", + "1.3.6.1.4.1.6449.1.2.1.5.1", + "1.3.6.1.4.1.782.1.2.1.8.1", + "1.3.6.1.4.1.8024.0.2.100.1.2", + "2.16.528.1.1001.1.1.1.12.6.1.1.1", + "2.16.756.1.89.1.2.1.1", + "2.16.840.1.113733.1.7.23.6", + "2.16.840.1.113733.1.7.48.1", + "2.16.840.1.114028.10.1.2", + "2.16.840.1.114171.500.9", + "2.16.840.1.114404.1.1.2.4.1", + "2.16.840.1.114412.2.1", + "2.16.840.1.114413.1.7.23.3", + "2.16.840.1.114414.1.7.23.3", +}; +#endif + // static EVRootCAMetadata* EVRootCAMetadata::GetInstance() { return Singleton<EVRootCAMetadata>::get(); @@ -266,6 +298,35 @@ bool EVRootCAMetadata::GetPolicyOID( return true; } +#if defined(OS_WIN) +static int PolicyOIDCmp(const void* keyval, const void* datum) { + const char* oid1 = reinterpret_cast<const char*>(keyval); + const char* const* oid2 = reinterpret_cast<const char* const*>(datum); + return strcmp(oid1, *oid2); +} + +bool EVRootCAMetadata::IsEVPolicyOID(PolicyOID policy_oid) const { + return bsearch(policy_oid, &policy_oids_[0], num_policy_oids_, + sizeof(PolicyOID), PolicyOIDCmp) != NULL; +} +#else +bool EVRootCAMetadata::IsEVPolicyOID(PolicyOID policy_oid) const { + for (size_t i = 0; i < policy_oids_.size(); ++i) { + if (PolicyOIDsAreEqual(policy_oid, policy_oids_[i])) + return true; + } + return false; +} +#endif + +bool EVRootCAMetadata::HasEVPolicyOID(const SHA1Fingerprint& fingerprint, + PolicyOID policy_oid) const { + PolicyOID ev_policy_oid; + if (!GetPolicyOID(fingerprint, &ev_policy_oid)) + return false; + return PolicyOIDsAreEqual(ev_policy_oid, policy_oid); +} + EVRootCAMetadata::EVRootCAMetadata() { // Constructs the object from the raw metadata in ev_root_ca_metadata. #if defined(USE_NSS) @@ -293,6 +354,18 @@ EVRootCAMetadata::EVRootCAMetadata() { ev_policy_[metadata.fingerprint] = policy; policy_oids_.push_back(policy); } +#elif defined(OS_WIN) + num_policy_oids_ = arraysize(policy_oids_); + // Verify policy_oids_ is in ascending order. + for (int i = 0; i < num_policy_oids_ - 1; i++) + CHECK(strcmp(policy_oids_[i], policy_oids_[i + 1]) < 0); + + for (size_t i = 0; i < arraysize(ev_root_ca_metadata); i++) { + const EVMetadata& metadata = ev_root_ca_metadata[i]; + ev_policy_[metadata.fingerprint] = metadata.policy_oid; + // Verify policy_oids_ contains every EV policy OID. + DCHECK(IsEVPolicyOID(metadata.policy_oid)); + } #else for (size_t i = 0; i < arraysize(ev_root_ca_metadata); i++) { const EVMetadata& metadata = ev_root_ca_metadata[i]; @@ -308,4 +381,13 @@ EVRootCAMetadata::EVRootCAMetadata() { EVRootCAMetadata::~EVRootCAMetadata() { } +// static +bool EVRootCAMetadata::PolicyOIDsAreEqual(PolicyOID a, PolicyOID b) { +#if defined(USE_NSS) + return a == b; +#else + return !strcmp(a, b); +#endif +} + } // namespace net diff --git a/net/base/ev_root_ca_metadata.h b/net/base/ev_root_ca_metadata.h index e9e8130..e0961f3 100644 --- a/net/base/ev_root_ca_metadata.h +++ b/net/base/ev_root_ca_metadata.h @@ -1,4 +1,4 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Copyright (c) 2010 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. @@ -40,21 +40,40 @@ class EVRootCAMetadata { PolicyOID* policy_oid) const; const PolicyOID* GetPolicyOIDs() const { return &policy_oids_[0]; } +#if defined(OS_WIN) + int NumPolicyOIDs() const { return num_policy_oids_; } +#else int NumPolicyOIDs() const { return policy_oids_.size(); } +#endif - private: - EVRootCAMetadata(); - ~EVRootCAMetadata(); + // Returns true if policy_oid is an EV policy OID of some root CA. + bool IsEVPolicyOID(PolicyOID policy_oid) const; + + // Returns true if the root CA with the given certificate fingerprint has + // the EV policy OID policy_oid. + bool HasEVPolicyOID(const SHA1Fingerprint& fingerprint, + PolicyOID policy_oid) const; + private: friend struct DefaultSingletonTraits<EVRootCAMetadata>; typedef std::map<SHA1Fingerprint, PolicyOID, SHA1FingerprintLessThan> PolicyOidMap; + EVRootCAMetadata(); + ~EVRootCAMetadata(); + + static bool PolicyOIDsAreEqual(PolicyOID a, PolicyOID b); + // Maps an EV root CA cert's SHA-1 fingerprint to its EV policy OID. PolicyOidMap ev_policy_; +#if defined(OS_WIN) + static const PolicyOID policy_oids_[]; + int num_policy_oids_; +#else std::vector<PolicyOID> policy_oids_; +#endif DISALLOW_COPY_AND_ASSIGN(EVRootCAMetadata); }; diff --git a/net/base/host_resolver.h b/net/base/host_resolver.h index 2fb7067..471ad8a 100644 --- a/net/base/host_resolver.h +++ b/net/base/host_resolver.h @@ -20,6 +20,7 @@ namespace net { class AddressList; class BoundNetLog; class HostResolverImpl; +class HostResolverProc; class NetLog; // This class represents the task of resolving hostnames (or IP address @@ -230,13 +231,13 @@ class SingleRequestHostResolver { DISALLOW_COPY_AND_ASSIGN(SingleRequestHostResolver); }; -// Creates a HostResolver implementation that queries the underlying system. -// (Except if a unit-test has changed the global HostResolverProc using -// ScopedHostResolverProc to intercept requests to the system). -// |max_concurrent_resolves| is how many resolve requests will be allowed to -// run in parallel. Pass HostResolver::kDefaultParallelism to choose a -// default value. +// Creates a HostResolver implementation using |resolver_proc| as resolver, +// (which if NULL, will default to getaddrinfo() wrapper) that queries the +// underlying system, |max_concurrent_resolves| is how many resolve +// requests will be allowed to run in parallel. Pass +// HostResolver::kDefaultParallelism to choose a default value. HostResolver* CreateSystemHostResolver(size_t max_concurrent_resolves, + HostResolverProc* resolver_proc, NetLog* net_log); } // namespace net diff --git a/net/base/host_resolver_impl.cc b/net/base/host_resolver_impl.cc index 37063af..5812d17 100644 --- a/net/base/host_resolver_impl.cc +++ b/net/base/host_resolver_impl.cc @@ -16,7 +16,8 @@ #include "base/basictypes.h" #include "base/compiler_specific.h" -#include "base/debug_util.h" +#include "base/debug/debugger.h" +#include "base/debug/stack_trace.h" #include "base/lock.h" #include "base/message_loop.h" #include "base/metrics/field_trial.h" @@ -71,7 +72,9 @@ HostCache* CreateDefaultCache() { } // anonymous namespace HostResolver* CreateSystemHostResolver(size_t max_concurrent_resolves, + HostResolverProc* resolver_proc, NetLog* net_log) { +<<<<<<< HEAD // Maximum of 50 concurrent threads. // TODO(eroman): Adjust this, do some A/B experiments. #ifdef ANDROID @@ -80,6 +83,13 @@ HostResolver* CreateSystemHostResolver(size_t max_concurrent_resolves, #else static const size_t kDefaultMaxJobs = 50u; #endif +======= + // Maximum of 8 concurrent resolver threads. + // Some routers (or resolvers) appear to start to provide host-not-found if + // too many simultaneous resolutions are pending. This number needs to be + // further optimized, but 8 is what FF currently does. + static const size_t kDefaultMaxJobs = 8u; +>>>>>>> chromium.org at r65505 if (max_concurrent_resolves == HostResolver::kDefaultParallelism) max_concurrent_resolves = kDefaultMaxJobs; @@ -93,7 +103,7 @@ HostResolver* CreateSystemHostResolver(size_t max_concurrent_resolves, return systemResolver; #else HostResolverImpl* resolver = - new HostResolverImpl(NULL, CreateDefaultCache(), + new HostResolverImpl(resolver_proc, CreateDefaultCache(), max_concurrent_resolves, net_log); return resolver; @@ -369,9 +379,10 @@ class HostResolverImpl::Job had_non_speculative_request_(false), net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_HOST_RESOLVER_IMPL_JOB)) { - net_log_.BeginEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB, - new JobCreationParameters(key.hostname, - source_net_log.source())); + net_log_.BeginEvent( + NetLog::TYPE_HOST_RESOLVER_IMPL_JOB, + make_scoped_refptr( + new JobCreationParameters(key.hostname, source_net_log.source()))); } // Attaches a request to this job. The job takes ownership of |req| and will @@ -379,7 +390,8 @@ class HostResolverImpl::Job void AddRequest(Request* req) { req->request_net_log().BeginEvent( NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_ATTACH, - new NetLogSourceParameter("source_dependency", net_log_.source())); + make_scoped_refptr(new NetLogSourceParameter( + "source_dependency", net_log_.source()))); req->set_job(this); requests_.push_back(req); @@ -1082,7 +1094,7 @@ void HostResolverImpl::CancelRequest(RequestHandle req_handle) { // Because we destroy outstanding requests during Shutdown(), // |req_handle| is already cancelled. LOG(ERROR) << "Called HostResolverImpl::CancelRequest() after Shutdown()."; - StackTrace().PrintBacktrace(); + base::debug::StackTrace().PrintBacktrace(); return; } Request* req = reinterpret_cast<Request*>(req_handle); @@ -1251,11 +1263,13 @@ void HostResolverImpl::OnStartRequest(const BoundNetLog& source_net_log, const RequestInfo& info) { source_net_log.BeginEvent( NetLog::TYPE_HOST_RESOLVER_IMPL, - new NetLogSourceParameter("source_dependency", request_net_log.source())); + make_scoped_refptr(new NetLogSourceParameter( + "source_dependency", request_net_log.source()))); request_net_log.BeginEvent( NetLog::TYPE_HOST_RESOLVER_IMPL_REQUEST, - new RequestInfoParameters(info, source_net_log.source())); + make_scoped_refptr(new RequestInfoParameters( + info, source_net_log.source()))); // Notify the observers of the start. if (!observers_.empty()) { @@ -1384,7 +1398,7 @@ void HostResolverImpl::ProcessQueuedRequests() { if (!top_req) return; - scoped_refptr<Job> job = CreateAndStartJob(top_req); + scoped_refptr<Job> job(CreateAndStartJob(top_req)); // Search for any other pending request which can piggy-back off this job. for (size_t pool_i = 0; pool_i < POOL_COUNT; ++pool_i) { @@ -1414,8 +1428,8 @@ HostResolverImpl::Job* HostResolverImpl::CreateAndStartJob(Request* req) { req->request_net_log().AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_CREATE_JOB, NULL); - scoped_refptr<Job> job = new Job(next_job_id_++, this, key, - req->request_net_log(), net_log_); + scoped_refptr<Job> job(new Job(next_job_id_++, this, key, + req->request_net_log(), net_log_)); job->AddRequest(req); AddOutstandingJob(job); job->Start(); diff --git a/net/base/host_resolver_impl_unittest.cc b/net/base/host_resolver_impl_unittest.cc index 07e00bf..f3bdb74 100644 --- a/net/base/host_resolver_impl_unittest.cc +++ b/net/base/host_resolver_impl_unittest.cc @@ -259,8 +259,8 @@ TEST_F(HostResolverImplTest, SynchronousLookup) { AddressList addrlist; const int kPortnum = 80; - scoped_refptr<RuleBasedHostResolverProc> resolver_proc = - new RuleBasedHostResolverProc(NULL); + scoped_refptr<RuleBasedHostResolverProc> resolver_proc( + new RuleBasedHostResolverProc(NULL)); resolver_proc->AddRule("just.testing", "192.168.1.42"); scoped_ptr<HostResolver> host_resolver( @@ -291,8 +291,8 @@ TEST_F(HostResolverImplTest, AsynchronousLookup) { AddressList addrlist; const int kPortnum = 80; - scoped_refptr<RuleBasedHostResolverProc> resolver_proc = - new RuleBasedHostResolverProc(NULL); + scoped_refptr<RuleBasedHostResolverProc> resolver_proc( + new RuleBasedHostResolverProc(NULL)); resolver_proc->AddRule("just.testing", "192.168.1.42"); scoped_ptr<HostResolver> host_resolver( @@ -328,8 +328,8 @@ TEST_F(HostResolverImplTest, AsynchronousLookup) { } TEST_F(HostResolverImplTest, CanceledAsynchronousLookup) { - scoped_refptr<WaitingHostResolverProc> resolver_proc = - new WaitingHostResolverProc(NULL); + scoped_refptr<WaitingHostResolverProc> resolver_proc( + new WaitingHostResolverProc(NULL)); CapturingNetLog net_log(CapturingNetLog::kUnbounded); CapturingBoundNetLog log(CapturingNetLog::kUnbounded); @@ -390,8 +390,8 @@ TEST_F(HostResolverImplTest, CanceledAsynchronousLookup) { TEST_F(HostResolverImplTest, NumericIPv4Address) { // Stevens says dotted quads with AI_UNSPEC resolve to a single sockaddr_in. - scoped_refptr<RuleBasedHostResolverProc> resolver_proc = - new RuleBasedHostResolverProc(NULL); + scoped_refptr<RuleBasedHostResolverProc> resolver_proc( + new RuleBasedHostResolverProc(NULL)); resolver_proc->AllowDirectLookup("*"); scoped_ptr<HostResolver> host_resolver( @@ -413,8 +413,8 @@ TEST_F(HostResolverImplTest, NumericIPv4Address) { } TEST_F(HostResolverImplTest, NumericIPv6Address) { - scoped_refptr<RuleBasedHostResolverProc> resolver_proc = - new RuleBasedHostResolverProc(NULL); + scoped_refptr<RuleBasedHostResolverProc> resolver_proc( + new RuleBasedHostResolverProc(NULL)); resolver_proc->AllowDirectLookup("*"); // Resolve a plain IPv6 address. Don't worry about [brackets], because @@ -445,8 +445,8 @@ TEST_F(HostResolverImplTest, NumericIPv6Address) { } TEST_F(HostResolverImplTest, EmptyHost) { - scoped_refptr<RuleBasedHostResolverProc> resolver_proc = - new RuleBasedHostResolverProc(NULL); + scoped_refptr<RuleBasedHostResolverProc> resolver_proc( + new RuleBasedHostResolverProc(NULL)); resolver_proc->AllowDirectLookup("*"); scoped_ptr<HostResolver> host_resolver( @@ -459,8 +459,8 @@ TEST_F(HostResolverImplTest, EmptyHost) { } TEST_F(HostResolverImplTest, LongHost) { - scoped_refptr<RuleBasedHostResolverProc> resolver_proc = - new RuleBasedHostResolverProc(NULL); + scoped_refptr<RuleBasedHostResolverProc> resolver_proc( + new RuleBasedHostResolverProc(NULL)); resolver_proc->AllowDirectLookup("*"); scoped_ptr<HostResolver> host_resolver( @@ -523,8 +523,8 @@ class DeDupeRequestsVerifier : public ResolveRequest::Delegate { TEST_F(HostResolverImplTest, DeDupeRequests) { // Use a capturing resolver_proc, since the verifier needs to know what calls // reached Resolve(). Also, the capturing resolver_proc is initially blocked. - scoped_refptr<CapturingHostResolverProc> resolver_proc = - new CapturingHostResolverProc(NULL); + scoped_refptr<CapturingHostResolverProc> resolver_proc( + new CapturingHostResolverProc(NULL)); scoped_ptr<HostResolver> host_resolver( CreateHostResolverImpl(resolver_proc)); @@ -574,8 +574,8 @@ TEST_F(HostResolverImplTest, CancelMultipleRequests) { // Use a capturing resolver_proc, since the verifier needs to know what calls // reached Resolver(). Also, the capturing resolver_proc is initially // blocked. - scoped_refptr<CapturingHostResolverProc> resolver_proc = - new CapturingHostResolverProc(NULL); + scoped_refptr<CapturingHostResolverProc> resolver_proc( + new CapturingHostResolverProc(NULL)); scoped_ptr<HostResolver> host_resolver( CreateHostResolverImpl(resolver_proc)); @@ -661,8 +661,8 @@ TEST_F(HostResolverImplTest, CancelWithinCallback) { // Use a capturing resolver_proc, since the verifier needs to know what calls // reached Resolver(). Also, the capturing resolver_proc is initially // blocked. - scoped_refptr<CapturingHostResolverProc> resolver_proc = - new CapturingHostResolverProc(NULL); + scoped_refptr<CapturingHostResolverProc> resolver_proc( + new CapturingHostResolverProc(NULL)); scoped_ptr<HostResolver> host_resolver( CreateHostResolverImpl(resolver_proc)); @@ -718,8 +718,8 @@ TEST_F(HostResolverImplTest, DeleteWithinCallback) { // Use a capturing resolver_proc, since the verifier needs to know what calls // reached Resolver(). Also, the capturing resolver_proc is initially // blocked. - scoped_refptr<CapturingHostResolverProc> resolver_proc = - new CapturingHostResolverProc(NULL); + scoped_refptr<CapturingHostResolverProc> resolver_proc( + new CapturingHostResolverProc(NULL)); // The class will receive callbacks for when each resolve completes. It // checks that the right things happened. Note that the verifier holds the @@ -773,8 +773,8 @@ TEST_F(HostResolverImplTest, StartWithinCallback) { // Use a capturing resolver_proc, since the verifier needs to know what calls // reached Resolver(). Also, the capturing resolver_proc is initially // blocked. - scoped_refptr<CapturingHostResolverProc> resolver_proc = - new CapturingHostResolverProc(NULL); + scoped_refptr<CapturingHostResolverProc> resolver_proc( + new CapturingHostResolverProc(NULL)); // Turn off caching for this host resolver. scoped_ptr<HostResolver> host_resolver( @@ -1105,8 +1105,8 @@ TEST_F(HostResolverImplTest, FlushCacheOnIPAddressChange) { // Test that IP address changes send ERR_ABORTED to pending requests. TEST_F(HostResolverImplTest, AbortOnIPAddressChanged) { - scoped_refptr<WaitingHostResolverProc> resolver_proc = - new WaitingHostResolverProc(NULL); + scoped_refptr<WaitingHostResolverProc> resolver_proc( + new WaitingHostResolverProc(NULL)); HostCache* cache = CreateDefaultCache(); scoped_ptr<HostResolver> host_resolver( new HostResolverImpl(resolver_proc, cache, kMaxJobs, NULL)); @@ -1130,8 +1130,8 @@ TEST_F(HostResolverImplTest, AbortOnIPAddressChanged) { // Obey pool constraints after IP address has changed. TEST_F(HostResolverImplTest, ObeyPoolConstraintsAfterIPAddressChange) { - scoped_refptr<WaitingHostResolverProc> resolver_proc = - new WaitingHostResolverProc(NULL); + scoped_refptr<WaitingHostResolverProc> resolver_proc( + new WaitingHostResolverProc(NULL)); scoped_ptr<MockHostResolver> host_resolver(new MockHostResolver()); host_resolver->Reset(resolver_proc); @@ -1202,8 +1202,8 @@ class ResolveWithinCallback : public CallbackRunner< Tuple1<int> > { }; TEST_F(HostResolverImplTest, OnlyAbortExistingRequestsOnIPAddressChange) { - scoped_refptr<WaitingHostResolverProc> resolver_proc = - new WaitingHostResolverProc(NULL); + scoped_refptr<WaitingHostResolverProc> resolver_proc( + new WaitingHostResolverProc(NULL)); scoped_ptr<MockHostResolver> host_resolver(new MockHostResolver()); host_resolver->Reset(resolver_proc); @@ -1227,8 +1227,8 @@ TEST_F(HostResolverImplTest, OnlyAbortExistingRequestsOnIPAddressChange) { // Tests that when the maximum threads is set to 1, requests are dequeued // in order of priority. TEST_F(HostResolverImplTest, HigherPriorityRequestsStartedFirst) { - scoped_refptr<CapturingHostResolverProc> resolver_proc = - new CapturingHostResolverProc(NULL); + scoped_refptr<CapturingHostResolverProc> resolver_proc( + new CapturingHostResolverProc(NULL)); // This HostResolverImpl will only allow 1 outstanding resolve at a time. size_t kMaxJobs = 1u; @@ -1312,8 +1312,8 @@ TEST_F(HostResolverImplTest, HigherPriorityRequestsStartedFirst) { // Try cancelling a request which has not been attached to a job yet. TEST_F(HostResolverImplTest, CancelPendingRequest) { - scoped_refptr<CapturingHostResolverProc> resolver_proc = - new CapturingHostResolverProc(NULL); + scoped_refptr<CapturingHostResolverProc> resolver_proc( + new CapturingHostResolverProc(NULL)); // This HostResolverImpl will only allow 1 outstanding resolve at a time. const size_t kMaxJobs = 1u; @@ -1375,8 +1375,8 @@ TEST_F(HostResolverImplTest, CancelPendingRequest) { // Test that when too many requests are enqueued, old ones start to be aborted. TEST_F(HostResolverImplTest, QueueOverflow) { - scoped_refptr<CapturingHostResolverProc> resolver_proc = - new CapturingHostResolverProc(NULL); + scoped_refptr<CapturingHostResolverProc> resolver_proc( + new CapturingHostResolverProc(NULL)); // This HostResolverImpl will only allow 1 outstanding resolve at a time. const size_t kMaxOutstandingJobs = 1u; @@ -1453,8 +1453,8 @@ TEST_F(HostResolverImplTest, QueueOverflow) { // Tests that after changing the default AddressFamily to IPV4, requests // with UNSPECIFIED address family map to IPV4. TEST_F(HostResolverImplTest, SetDefaultAddressFamily_IPv4) { - scoped_refptr<CapturingHostResolverProc> resolver_proc = - new CapturingHostResolverProc(new EchoingHostResolverProc); + scoped_refptr<CapturingHostResolverProc> resolver_proc( + new CapturingHostResolverProc(new EchoingHostResolverProc)); // This HostResolverImpl will only allow 1 outstanding resolve at a time. const size_t kMaxOutstandingJobs = 1u; @@ -1521,8 +1521,8 @@ TEST_F(HostResolverImplTest, SetDefaultAddressFamily_IPv4) { // of requests 0 and 1 is flipped, and the default is set to IPv6 in place of // IPv4. TEST_F(HostResolverImplTest, SetDefaultAddressFamily_IPv6) { - scoped_refptr<CapturingHostResolverProc> resolver_proc = - new CapturingHostResolverProc(new EchoingHostResolverProc); + scoped_refptr<CapturingHostResolverProc> resolver_proc( + new CapturingHostResolverProc(new EchoingHostResolverProc)); // This HostResolverImpl will only allow 1 outstanding resolve at a time. const size_t kMaxOutstandingJobs = 1u; @@ -1588,8 +1588,8 @@ TEST_F(HostResolverImplTest, SetDefaultAddressFamily_IPv6) { // This tests that the default address family is respected for synchronous // resolutions. TEST_F(HostResolverImplTest, SetDefaultAddressFamily_Synchronous) { - scoped_refptr<CapturingHostResolverProc> resolver_proc = - new CapturingHostResolverProc(new EchoingHostResolverProc); + scoped_refptr<CapturingHostResolverProc> resolver_proc( + new CapturingHostResolverProc(new EchoingHostResolverProc)); const size_t kMaxOutstandingJobs = 10u; scoped_ptr<HostResolverImpl> host_resolver(new HostResolverImpl( diff --git a/net/base/listen_socket.cc b/net/base/listen_socket.cc index 0cb529d..c964ec9 100644 --- a/net/base/listen_socket.cc +++ b/net/base/listen_socket.cc @@ -121,8 +121,8 @@ SOCKET ListenSocket::Accept(SOCKET s) { void ListenSocket::Accept() { SOCKET conn = Accept(socket_); if (conn != kInvalidSocket) { - scoped_refptr<ListenSocket> sock = - new ListenSocket(conn, socket_delegate_); + scoped_refptr<ListenSocket> sock( + new ListenSocket(conn, socket_delegate_)); // it's up to the delegate to AddRef if it wants to keep it around #if defined(OS_POSIX) sock->WatchSocket(WAITING_READ); diff --git a/net/base/mime_util.cc b/net/base/mime_util.cc index a580997..ddcfc4b 100644 --- a/net/base/mime_util.cc +++ b/net/base/mime_util.cc @@ -82,6 +82,7 @@ static const MimeInfo primary_mappings[] = { { "text/xml", "xml" }, { "image/gif", "gif" }, { "image/jpeg", "jpeg,jpg" }, + { "image/webp", "webp" }, { "image/png", "png" }, { "video/mp4", "mp4,m4v" }, { "audio/x-m4a", "m4a" }, @@ -192,6 +193,7 @@ static const char* const supported_image_types[] = { "image/jpeg", "image/pjpeg", "image/jpg", + "image/webp", "image/png", "image/gif", "image/bmp", @@ -547,6 +549,7 @@ static const char* kStandardImageTypes[] = { "image/gif", "image/ief", "image/jpeg", + "image/webp", "image/pict", "image/pipeg", "image/png", @@ -660,7 +663,6 @@ void HashSetToVector(base::hash_set<T>* source, std::vector<T>* target) { target->at(old_target_size + i) = *iter; } } - } void GetImageExtensions(std::vector<FilePath::StringType>* extensions) { diff --git a/net/base/mock_host_resolver.cc b/net/base/mock_host_resolver.cc index 9c82f93..9ee5c53 100644 --- a/net/base/mock_host_resolver.cc +++ b/net/base/mock_host_resolver.cc @@ -80,8 +80,8 @@ void MockHostResolverBase::Reset(HostResolverProc* interceptor) { synchronous_mode_ = false; // At the root of the chain, map everything to localhost. - scoped_refptr<RuleBasedHostResolverProc> catchall = - new RuleBasedHostResolverProc(NULL); + scoped_refptr<RuleBasedHostResolverProc> catchall( + new RuleBasedHostResolverProc(NULL)); catchall->AddRule("*", "127.0.0.1"); // Next add a rules-based layer the use controls. diff --git a/net/base/net_error_list.h b/net/base/net_error_list.h index d7ae9d1..96b19ad 100644 --- a/net/base/net_error_list.h +++ b/net/base/net_error_list.h @@ -50,7 +50,7 @@ NET_ERROR(FILE_TOO_BIG, -8) // invalid assumption. NET_ERROR(UNEXPECTED, -9) -// Permission to access a resource was denied. +// Permission to access a resource, other than the network, was denied. NET_ERROR(ACCESS_DENIED, -10) // The operation failed because of unimplemented functionality. @@ -66,7 +66,7 @@ NET_ERROR(OUT_OF_MEMORY, -13) // from the expectation. NET_ERROR(UPLOAD_FILE_CHANGED, -14) -// The socket is not connected +// The socket is not connected. NET_ERROR(SOCKET_NOT_CONNECTED, -15) // A connection was closed (corresponding to a TCP FIN). @@ -191,10 +191,7 @@ NET_ERROR(SSL_SNAP_START_NPN_MISPREDICTION, -131) // give the user a helpful error message rather than have the connection hang. NET_ERROR(ESET_ANTI_VIRUS_SSL_INTERCEPTION, -132) -// We detected NetNanny intercepting our HTTPS connections. Since this product -// is False Start intolerant, we return this error so that we can give the user -// a helpful error message rather than have the connection hang. -NET_ERROR(NETNANNY_SSL_INTERCEPTION, -133) +// Missing -133. Feel free to reuse in the future. // The permission to use the SSL client certificate's private key was denied. NET_ERROR(SSL_CLIENT_AUTH_PRIVATE_KEY_ACCESS_DENIED, -134) @@ -208,6 +205,11 @@ NET_ERROR(PROXY_CERTIFICATE_INVALID, -136) // An error occurred when trying to do a name resolution (DNS). NET_ERROR(NAME_RESOLUTION_FAILED, -137) +// Permission to access the network was denied. This is used to distinguish +// errors that were most likely caused by a firewall from other access denied +// errors. See also ERR_ACCESS_DENIED. +NET_ERROR(NETWORK_ACCESS_DENIED, -138) + // Certificate error codes // // The values of certificate error codes must be consecutive. diff --git a/net/base/net_log_event_type_list.h b/net/base/net_log_event_type_list.h index 398f7c1..6183749 100644 --- a/net/base/net_log_event_type_list.h +++ b/net/base/net_log_event_type_list.h @@ -334,6 +334,17 @@ EVENT_TYPE(SSL_HANDSHAKE_ERROR) EVENT_TYPE(SSL_READ_ERROR) EVENT_TYPE(SSL_WRITE_ERROR) +// An SSL Snap Start was attempted +// The following parameters are attached to the event: +// { +// "type": <Integer code for the Snap Start result>, +// } +EVENT_TYPE(SSL_SNAP_START) + +// We found that our prediction of the server's certificates was correct and +// we merged the verification with the SSLHostInfo. +EVENT_TYPE(SSL_VERIFICATION_MERGED) + // An SSL error occurred while calling an NSS function not directly related to // one of the above activities. Can also be used when more information than // is provided by just an error code is needed: diff --git a/net/base/net_test_suite.h b/net/base/net_test_suite.h index eab3a53..00d9844 100644 --- a/net/base/net_test_suite.h +++ b/net/base/net_test_suite.h @@ -9,7 +9,9 @@ #include "base/message_loop.h" #include "base/ref_counted.h" #include "base/test/test_suite.h" +#include "build/build_config.h" #include "net/base/mock_host_resolver.h" +#include "net/ocsp/nss_ocsp.h" class NetTestSuite : public base::TestSuite { public: @@ -39,6 +41,10 @@ class NetTestSuite : public base::TestSuite { } virtual void Shutdown() { +#if defined(OS_LINUX) + net::ShutdownOCSP(); +#endif // defined(OS_LINUX) + // We want to destroy this here before the TestSuite continues to tear down // the environment. message_loop_.reset(); diff --git a/net/base/net_util.cc b/net/base/net_util.cc index c1f769e..5afba6f 100644 --- a/net/base/net_util.cc +++ b/net/base/net_util.cc @@ -181,7 +181,7 @@ STR GetSpecificHeaderT(const STR& headers, const STR& name) { typename STR::const_iterator begin = search(headers.begin(), headers.end(), match.begin(), match.end(), - CaseInsensitiveCompareASCII<typename STR::value_type>()); + base::CaseInsensitiveCompareASCII<typename STR::value_type>()); if (begin == headers.end()) return STR(); @@ -374,9 +374,7 @@ bool DecodeWord(const std::string& encoded_word, // it should be Ok because we're not an email client but a // web browser. - // What IE6/7 does: %-escaped UTF-8. We could extend this to - // support a rudimentary form of RFC 2231 with charset label, but - // it'd gain us little in terms of compatibility. + // What IE6/7 does: %-escaped UTF-8. tmp = UnescapeURLComponent(encoded_word, UnescapeRule::SPACES); if (IsStringUTF8(tmp)) { output->swap(tmp); @@ -425,11 +423,12 @@ bool DecodeParamValue(const std::string& input, // TODO(mpcomplete): This is a quick and dirty implementation for now. I'm // sure this doesn't properly handle all (most?) cases. template<typename STR> -STR GetHeaderParamValueT(const STR& header, const STR& param_name) { +STR GetHeaderParamValueT(const STR& header, const STR& param_name, + QuoteRule::Type quote_rule) { // This assumes args are formatted exactly like "bla; arg1=value; arg2=value". typename STR::const_iterator param_begin = search(header.begin(), header.end(), param_name.begin(), param_name.end(), - CaseInsensitiveCompareASCII<typename STR::value_type>()); + base::CaseInsensitiveCompareASCII<typename STR::value_type>()); if (param_begin == header.end()) return STR(); @@ -448,7 +447,7 @@ STR GetHeaderParamValueT(const STR& header, const STR& param_name) { return STR(); typename STR::const_iterator param_end; - if (*param_begin == '"') { + if (*param_begin == '"' && quote_rule == QuoteRule::REMOVE_OUTER_QUOTES) { param_end = find(param_begin+1, header.end(), '"'); if (param_end == header.end()) return STR(); // poorly formatted param? @@ -1096,29 +1095,86 @@ std::string GetSpecificHeader(const std::string& headers, return GetSpecificHeaderT(headers, name); } +bool DecodeCharset(const std::string& input, + std::string* decoded_charset, + std::string* value) { + StringTokenizer t(input, "'"); + t.set_options(StringTokenizer::RETURN_DELIMS); + std::string temp_charset; + std::string temp_value; + int numDelimsSeen = 0; + while (t.GetNext()) { + if (t.token_is_delim()) { + ++numDelimsSeen; + continue; + } else { + switch (numDelimsSeen) { + case 0: + temp_charset = t.token(); + break; + case 1: + // Language is ignored. + break; + case 2: + temp_value = t.token(); + break; + default: + return false; + } + } + } + if (numDelimsSeen != 2) + return false; + if (temp_charset.empty() || temp_value.empty()) + return false; + decoded_charset->swap(temp_charset); + value->swap(temp_value); + return true; +} + std::string GetFileNameFromCD(const std::string& header, const std::string& referrer_charset) { - std::string param_value = GetHeaderParamValue(header, "filename"); + std::string decoded; + std::string param_value = GetHeaderParamValue(header, "filename*", + QuoteRule::KEEP_OUTER_QUOTES); + if (!param_value.empty()) { + if (param_value.find('"') == std::string::npos) { + std::string charset; + std::string value; + if (DecodeCharset(param_value, &charset, &value)) { + // RFC 5987 value should be ASCII-only. + if (!IsStringASCII(value)) + return std::string(); + std::string tmp = UnescapeURLComponent(value, UnescapeRule::SPACES); + if (base::ConvertToUtf8AndNormalize(tmp, charset, &decoded)) + return decoded; + } + } + } + param_value = GetHeaderParamValue(header, "filename", + QuoteRule::REMOVE_OUTER_QUOTES); if (param_value.empty()) { // Some servers use 'name' parameter. - param_value = GetHeaderParamValue(header, "name"); + param_value = GetHeaderParamValue(header, "name", + QuoteRule::REMOVE_OUTER_QUOTES); } if (param_value.empty()) return std::string(); - std::string decoded; if (DecodeParamValue(param_value, referrer_charset, &decoded)) return decoded; return std::string(); } std::wstring GetHeaderParamValue(const std::wstring& field, - const std::wstring& param_name) { - return GetHeaderParamValueT(field, param_name); + const std::wstring& param_name, + QuoteRule::Type quote_rule) { + return GetHeaderParamValueT(field, param_name, quote_rule); } std::string GetHeaderParamValue(const std::string& field, - const std::string& param_name) { - return GetHeaderParamValueT(field, param_name); + const std::string& param_name, + QuoteRule::Type quote_rule) { + return GetHeaderParamValueT(field, param_name, quote_rule); } // TODO(brettw) bug 734373: check the scripts for each host component and @@ -1681,10 +1737,11 @@ void SetExplicitlyAllowedPorts(const std::string& allowed_ports) { (allowed_ports[i] != kComma)) return; if (i == size || allowed_ports[i] == kComma) { - size_t length = i - last; - if (length > 0) { + if (i > last) { int port; - base::StringToInt(allowed_ports.substr(last, length), &port); + base::StringToInt(allowed_ports.begin() + last, + allowed_ports.begin() + i, + &port); ports.insert(port); } last = i + 1; diff --git a/net/base/net_util.h b/net/base/net_util.h index f5a6151..4b87c70 100644 --- a/net/base/net_util.h +++ b/net/base/net_util.h @@ -42,6 +42,18 @@ namespace net { typedef uint32 FormatUrlType; typedef uint32 FormatUrlTypes; +// Used by GetHeaderParamValue to determine how to handle quotes in the value. +class QuoteRule { + public: + enum Type { + KEEP_OUTER_QUOTES, + REMOVE_OUTER_QUOTES, + }; + + private: + QuoteRule(); +}; + // Nothing is ommitted. extern const FormatUrlType kFormatUrlOmitNothing; @@ -124,23 +136,26 @@ std::string GetSpecificHeader(const std::string& headers, // 'param_name'. Returns the empty string if the parameter is not found or is // improperly formatted. std::wstring GetHeaderParamValue(const std::wstring& field, - const std::wstring& param_name); + const std::wstring& param_name, + QuoteRule::Type quote_rule); std::string GetHeaderParamValue(const std::string& field, - const std::string& param_name); + const std::string& param_name, + QuoteRule::Type quote_rule); // Return the filename extracted from Content-Disposition header. The following // formats are tried in order listed below: // -// 1. RFC 2047 -// 2. Raw-8bit-characters : +// 1. RFC 5987 +// 2. RFC 2047 +// 3. Raw-8bit-characters : // a. UTF-8, b. referrer_charset, c. default os codepage. -// 3. %-escaped UTF-8. +// 4. %-escaped UTF-8. // -// In step 2, if referrer_charset is empty(i.e. unknown), 2b is skipped. -// In step 3, the fallback charsets tried in step 2 are not tried. We +// In step 3, if referrer_charset is empty(i.e. unknown), 3b is skipped. +// In step 4, the fallback charsets tried in step 3 are not tried. We // can consider doing that later. // -// When a param value is ASCII, but is not in format #1 or format #3 above, +// When a param value is ASCII, but is not in format #2 or format #4 above, // it is returned as it is unless it's pretty close to two supported // formats but not well-formed. In that case, an empty string is returned. // diff --git a/net/base/net_util_unittest.cc b/net/base/net_util_unittest.cc index ad7ccad..77d3a00 100644 --- a/net/base/net_util_unittest.cc +++ b/net/base/net_util_unittest.cc @@ -711,7 +711,8 @@ TEST(NetUtilTest, GetHeaderParamValue) { std::wstring header_value = net::GetSpecificHeader(google_headers, tests[i].header_name); std::wstring result = - net::GetHeaderParamValue(header_value, tests[i].param_name); + net::GetHeaderParamValue(header_value, tests[i].param_name, + net::QuoteRule::REMOVE_OUTER_QUOTES); EXPECT_EQ(result, tests[i].expected); } @@ -719,11 +720,38 @@ TEST(NetUtilTest, GetHeaderParamValue) { std::wstring header_value = net::GetSpecificHeader(L"", tests[i].header_name); std::wstring result = - net::GetHeaderParamValue(header_value, tests[i].param_name); + net::GetHeaderParamValue(header_value, tests[i].param_name, + net::QuoteRule::REMOVE_OUTER_QUOTES); EXPECT_EQ(result, std::wstring()); } } +TEST(NetUtilTest, GetHeaderParamValueQuotes) { + struct { + const char* header; + const char* expected_with_quotes; + const char* expected_without_quotes; + } tests[] = { + {"filename=foo", "foo", "foo"}, + {"filename=\"foo\"", "\"foo\"", "foo"}, + {"filename=foo\"", "foo\"", "foo\""}, + {"filename=fo\"o", "fo\"o", "fo\"o"}, + }; + + for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) { + std::string actual_with_quotes = + net::GetHeaderParamValue(tests[i].header, "filename", + net::QuoteRule::KEEP_OUTER_QUOTES); + std::string actual_without_quotes = + net::GetHeaderParamValue(tests[i].header, "filename", + net::QuoteRule::REMOVE_OUTER_QUOTES); + EXPECT_EQ(tests[i].expected_with_quotes, actual_with_quotes) + << "Failed while processing: " << tests[i].header; + EXPECT_EQ(tests[i].expected_without_quotes, actual_without_quotes) + << "Failed while processing: " << tests[i].header; + } +} + TEST(NetUtilTest, GetFileNameFromCD) { const FileNameCDCase tests[] = { // Test various forms of C-D header fields emitted by web servers. @@ -762,7 +790,7 @@ TEST(NetUtilTest, GetFileNameFromCD) { "_3=2Epng?=", "", L"\U00010330 3.png"}, {"Content-Disposition: inline; filename=\"=?iso88591?Q?caf=e9_=2epng?=\"", "", L"caf\x00e9 .png"}, - // Space after an encode word should be removed. + // Space after an encoded word should be removed. {"Content-Disposition: inline; filename=\"=?iso88591?Q?caf=E9_?= .png\"", "", L"caf\x00e9 .png"}, // Two encoded words with different charsets (not very likely to be emitted @@ -812,11 +840,92 @@ TEST(NetUtilTest, GetFileNameFromCD) { // Two RFC 2047 encoded words in a row without a space is an error. {"Content-Disposition: attachment; filename==?windows-1252?Q?caf=E3?=" "=?iso-8859-7?b?4eIucG5nCg==?=", "", L""}, + + // RFC 5987 tests with Filename* : see http://tools.ietf.org/html/rfc5987 + {"Content-Disposition: attachment; filename*=foo.html", "", L""}, + {"Content-Disposition: attachment; filename*=foo'.html", "", L""}, + {"Content-Disposition: attachment; filename*=''foo'.html", "", L""}, + {"Content-Disposition: attachment; filename*=''foo.html'", "", L""}, + {"Content-Disposition: attachment; filename*=''f\"oo\".html'", "", L""}, + {"Content-Disposition: attachment; filename*=bogus_charset''foo.html'", + "", L""}, + {"Content-Disposition: attachment; filename*='en'foo.html'", "", L""}, + {"Content-Disposition: attachment; filename*=iso-8859-1'en'foo.html", "", + L"foo.html"}, + {"Content-Disposition: attachment; filename*=utf-8'en'foo.html", "", + L"foo.html"}, + // charset cannot be omitted. + {"Content-Disposition: attachment; filename*='es'f\xfa.html'", "", L""}, + // Non-ASCII bytes are not allowed. + {"Content-Disposition: attachment; filename*=iso-8859-1'es'f\xfa.html", "", + L""}, + {"Content-Disposition: attachment; filename*=utf-8'es'f\xce\xba.html", "", + L""}, + // TODO(jshin): Space should be %-encoded, but currently, we allow + // spaces. + {"Content-Disposition: inline; filename*=iso88591''cafe foo.png", "", + L"cafe foo.png"}, + + // Filename* tests converted from Q-encoded tests above. + {"Content-Disposition: attachment; filename*=EUC-JP''%B7%DD%BD%D13%2Epng", + "", L"\x82b8\x8853" L"3.png"}, + {"Content-Disposition: attachment; filename*=utf-8''" + "%E8%8A%B8%E8%A1%93%203%2Epng", "", L"\x82b8\x8853 3.png"}, + {"Content-Disposition: attachment; filename*=utf-8''%F0%90%8C%B0 3.png", "", + L"\U00010330 3.png"}, + {"Content-Disposition: inline; filename*=Euc-Kr'ko'%BF%B9%BC%FA%2Epng", "", + L"\xc608\xc220.png"}, + {"Content-Disposition: attachment; filename*=windows-1252''caf%E9.png", "", + L"caf\x00e9.png"}, + + // http://greenbytes.de/tech/tc2231/ filename* test cases. + // attwithisofn2231iso + {"Content-Disposition: attachment; filename*=iso-8859-1''foo-%E4.html", "", + L"foo-\xe4.html"}, + // attwithfn2231utf8 + {"Content-Disposition: attachment; filename*=" + "UTF-8''foo-%c3%a4-%e2%82%ac.html", "", L"foo-\xe4-\x20ac.html"}, + // attwithfn2231noc : no encoding specified but UTF-8 is used. + {"Content-Disposition: attachment; filename*=''foo-%c3%a4-%e2%82%ac.html", + "", L""}, + // attwithfn2231utf8comp + {"Content-Disposition: attachment; filename*=UTF-8''foo-a%cc%88.html", "", + L"foo-\xe4.html"}, +#ifdef ICU_SHOULD_FAIL_CONVERSION_ON_INVALID_CHARACTER + // This does not work because we treat ISO-8859-1 synonymous with + // Windows-1252 per HTML5. For HTTP, in theory, we're not + // supposed to. + // attwithfn2231utf8-bad + {"Content-Disposition: attachment; filename*=" + "iso-8859-1''foo-%c3%a4-%e2%82%ac.html", "", L""}, +#endif + // attwithfn2231ws1 + {"Content-Disposition: attachment; filename *=UTF-8''foo-%c3%a4.html", "", + L""}, + // attwithfn2231ws2 + {"Content-Disposition: attachment; filename*= UTF-8''foo-%c3%a4.html", "", + L"foo-\xe4.html"}, + // attwithfn2231ws3 + {"Content-Disposition: attachment; filename* =UTF-8''foo-%c3%a4.html", "", + L"foo-\xe4.html"}, + // attwithfn2231quot + {"Content-Disposition: attachment; filename*=\"UTF-8''foo-%c3%a4.html\"", + "", L""}, + // attfnboth + {"Content-Disposition: attachment; filename=\"foo-ae.html\"; " + "filename*=UTF-8''foo-%c3%a4.html", "", L"foo-\xe4.html"}, + // attfnboth2 + {"Content-Disposition: attachment; filename*=UTF-8''foo-%c3%a4.html; " + "filename=\"foo-ae.html\"", "", L"foo-\xe4.html"}, + // attnewandfn + {"Content-Disposition: attachment; foobar=x; filename=\"foo.html\"", "", + L"foo.html"}, }; for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) { EXPECT_EQ(tests[i].expected, UTF8ToWide(net::GetFileNameFromCD(tests[i].header_field, - tests[i].referrer_charset))); + tests[i].referrer_charset))) + << "Failed on input: " << tests[i].header_field; } } diff --git a/net/base/network_config_watcher_mac.cc b/net/base/network_config_watcher_mac.cc index 365859e..dd93067 100644 --- a/net/base/network_config_watcher_mac.cc +++ b/net/base/network_config_watcher_mac.cc @@ -8,12 +8,10 @@ #include <SystemConfiguration/SCSchemaDefinitions.h> #include <algorithm> +#include "base/compiler_specific.h" #include "base/thread.h" #include "base/mac/scoped_cftyperef.h" -// We only post tasks to a child thread we own, so we don't need refcounting. -DISABLE_RUNNABLE_METHOD_REFCOUNT(net::NetworkConfigWatcherMac); - namespace net { namespace { @@ -27,48 +25,59 @@ void DynamicStoreCallback(SCDynamicStoreRef /* store */, net_config_delegate->OnNetworkConfigChange(changed_keys); } -} // namespace +class NetworkConfigWatcherMacThread : public base::Thread { + public: + NetworkConfigWatcherMacThread(NetworkConfigWatcherMac::Delegate* delegate); + virtual ~NetworkConfigWatcherMacThread(); -NetworkConfigWatcherMac::NetworkConfigWatcherMac( - Delegate* delegate) - : notifier_thread_(new base::Thread("NetworkConfigWatcher")), - delegate_(delegate) { - // We create this notifier thread because the notification implementation - // needs a thread with a CFRunLoop, and there's no guarantee that - // MessageLoop::current() meets that criterion. - base::Thread::Options thread_options(MessageLoop::TYPE_UI, 0); - notifier_thread_->StartWithOptions(thread_options); + protected: + // base::Thread + virtual void Init(); + virtual void CleanUp(); + + private: + // The SystemConfiguration calls in this function can lead to contention early + // on, so we invoke this function later on in startup to keep it fast. + void InitNotifications(); + + base::mac::ScopedCFTypeRef<CFRunLoopSourceRef> run_loop_source_; + NetworkConfigWatcherMac::Delegate* const delegate_; + ScopedRunnableMethodFactory<NetworkConfigWatcherMacThread> method_factory_; + + DISALLOW_COPY_AND_ASSIGN(NetworkConfigWatcherMacThread); +}; + +NetworkConfigWatcherMacThread::NetworkConfigWatcherMacThread( + NetworkConfigWatcherMac::Delegate* delegate) + : base::Thread("NetworkConfigWatcher"), + delegate_(delegate), + ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) {} + +NetworkConfigWatcherMacThread::~NetworkConfigWatcherMacThread() { + Stop(); +} + +void NetworkConfigWatcherMacThread::Init() { // TODO(willchan): Look to see if there's a better signal for when it's ok to // initialize this, rather than just delaying it by a fixed time. - const int kNotifierThreadInitializationDelayMS = 1000; - notifier_thread_->message_loop()->PostDelayedTask( + const int kInitializationDelayMS = 1000; + message_loop()->PostDelayedTask( FROM_HERE, - NewRunnableMethod(this, &NetworkConfigWatcherMac::Init), - kNotifierThreadInitializationDelayMS); -} - -NetworkConfigWatcherMac::~NetworkConfigWatcherMac() { - // We don't need to explicitly Stop(), but doing so allows us to sanity- - // check that the notifier thread shut down properly. - notifier_thread_->Stop(); - DCHECK(run_loop_source_ == NULL); + method_factory_.NewRunnableMethod( + &NetworkConfigWatcherMacThread::InitNotifications), + kInitializationDelayMS); } -void NetworkConfigWatcherMac::WillDestroyCurrentMessageLoop() { - DCHECK(notifier_thread_ != NULL); - // We can't check the notifier_thread_'s message_loop(), as it's now 0. - // DCHECK_EQ(notifier_thread_->message_loop(), MessageLoop::current()); +void NetworkConfigWatcherMacThread::CleanUp() { + if (!run_loop_source_.get()) + return; - DCHECK(run_loop_source_ != NULL); CFRunLoopRemoveSource(CFRunLoopGetCurrent(), run_loop_source_.get(), kCFRunLoopCommonModes); run_loop_source_.reset(); } -void NetworkConfigWatcherMac::Init() { - DCHECK(notifier_thread_ != NULL); - DCHECK_EQ(notifier_thread_->message_loop(), MessageLoop::current()); - +void NetworkConfigWatcherMacThread::InitNotifications() { // Add a run loop source for a dynamic store to the current run loop. SCDynamicStoreContext context = { 0, // Version 0. @@ -86,8 +95,19 @@ void NetworkConfigWatcherMac::Init() { // Set up notifications for interface and IP address changes. delegate_->SetDynamicStoreNotificationKeys(store.get()); +} + +} // namespace - MessageLoop::current()->AddDestructionObserver(this); +NetworkConfigWatcherMac::NetworkConfigWatcherMac(Delegate* delegate) + : notifier_thread_(new NetworkConfigWatcherMacThread(delegate)) { + // We create this notifier thread because the notification implementation + // needs a thread with a CFRunLoop, and there's no guarantee that + // MessageLoop::current() meets that criterion. + base::Thread::Options thread_options(MessageLoop::TYPE_UI, 0); + notifier_thread_->StartWithOptions(thread_options); } +NetworkConfigWatcherMac::~NetworkConfigWatcherMac() {} + } // namespace net diff --git a/net/base/network_config_watcher_mac.h b/net/base/network_config_watcher_mac.h index f9f9d36..3bd55f9 100644 --- a/net/base/network_config_watcher_mac.h +++ b/net/base/network_config_watcher_mac.h @@ -19,7 +19,7 @@ class Thread; namespace net { // Base class for watching the Mac OS system network settings. -class NetworkConfigWatcherMac : public MessageLoop::DestructionObserver { +class NetworkConfigWatcherMac { public: // NOTE: The lifetime of Delegate is expected to exceed the lifetime of // NetworkConfigWatcherMac. @@ -41,24 +41,11 @@ class NetworkConfigWatcherMac : public MessageLoop::DestructionObserver { virtual ~NetworkConfigWatcherMac(); private: - // MessageLoop::DestructionObserver: - virtual void WillDestroyCurrentMessageLoop(); - - // Called on the notifier thread to initialize the notification - // implementation. The SystemConfiguration calls in this function can lead to - // contention early on, so we invoke this function later on in startup to keep - // it fast. - void Init(); - // The thread used to listen for notifications. This relays the notification // to the registered observers without posting back to the thread the object // was created on. scoped_ptr<base::Thread> notifier_thread_; - base::mac::ScopedCFTypeRef<CFRunLoopSourceRef> run_loop_source_; - - Delegate* const delegate_; - DISALLOW_COPY_AND_ASSIGN(NetworkConfigWatcherMac); }; diff --git a/net/base/openssl_util.cc b/net/base/openssl_util.cc index fcdc3a1..51797ac 100644 --- a/net/base/openssl_util.cc +++ b/net/base/openssl_util.cc @@ -59,6 +59,10 @@ OpenSSLInitSingleton* GetOpenSSLInitSingleton() { return Singleton<OpenSSLInitSingleton>::get(); } +void EnsureOpenSSLInit() { + Singleton<OpenSSLInitSingleton>::get(); +} + // static void OpenSSLInitSingleton::LockingCallback(int mode, int n, diff --git a/net/base/openssl_util.h b/net/base/openssl_util.h index 4218a89..d4603c6 100644 --- a/net/base/openssl_util.h +++ b/net/base/openssl_util.h @@ -25,7 +25,7 @@ class ScopedSSL { }; // Singleton for initializing / cleaning up OpenSSL and holding a X509 store. -// Access it via EnsureOpenSSLInit(). +// Access it via GetOpenSSLInitSingleton(). class OpenSSLInitSingleton { public: SSL_CTX* ssl_ctx() const { return ssl_ctx_.get(); } @@ -49,5 +49,11 @@ class OpenSSLInitSingleton { OpenSSLInitSingleton* GetOpenSSLInitSingleton(); +// Initialize OpenSSL if it isn't already initialized. This must be called +// before any other OpenSSL functions (except GetOpenSSLInitSingleton above). +// This function is thread-safe, and OpenSSL will only ever be initialized once. +// OpenSSL will be properly shut down on program exit. +void EnsureOpenSSLInit(); + } // namespace net diff --git a/net/base/ssl_cipher_suite_names.cc b/net/base/ssl_cipher_suite_names.cc index 2db9a4b..39efd1c 100644 --- a/net/base/ssl_cipher_suite_names.cc +++ b/net/base/ssl_cipher_suite_names.cc @@ -6,6 +6,8 @@ #include <stdlib.h> +#include "base/logging.h" +#include "net/base/ssl_connection_status_flags.h" // Rather than storing the names of all the ciphersuites we eliminate the // redundancy and break each cipher suite into a key exchange method, cipher @@ -346,4 +348,28 @@ void SSLCompressionToString(const char** name, uint8 compresssion) { } } +void SSLVersionToString(const char** name, int ssl_version) { + switch (ssl_version) { + case SSL_CONNECTION_VERSION_SSL2: + *name = "SSL 2.0"; + break; + case SSL_CONNECTION_VERSION_SSL3: + *name = "SSL 3.0"; + break; + case SSL_CONNECTION_VERSION_TLS1: + *name = "TLS 1.0"; + break; + case SSL_CONNECTION_VERSION_TLS1_1: + *name = "TLS 1.1"; + break; + case SSL_CONNECTION_VERSION_TLS1_2: + *name = "TLS 1.2"; + break; + default: + NOTREACHED(); + *name = "???"; + break; + } +} + } // namespace net diff --git a/net/base/ssl_cipher_suite_names.h b/net/base/ssl_cipher_suite_names.h index cd61471..9241c1b 100644 --- a/net/base/ssl_cipher_suite_names.h +++ b/net/base/ssl_cipher_suite_names.h @@ -25,6 +25,12 @@ void SSLCipherSuiteToStrings(const char** key_exchange_str, // If the algorithm is unknown, |name| is set to "???". void SSLCompressionToString(const char** name, uint8 compression_method); +// SSLVersionToString returns the name of the SSL protocol version +// specified by |ssl_version|, which is defined in +// net/base/ssl_connection_status_flags.h. +// If the version is unknown, |name| is set to "???". +void SSLVersionToString(const char** name, int ssl_version); + } // namespace net #endif // NET_BASE_SSL_CIPHER_SUITE_NAMES_H_ diff --git a/net/base/ssl_config_service.cc b/net/base/ssl_config_service.cc index d8ecb0b..5c38f97 100644 --- a/net/base/ssl_config_service.cc +++ b/net/base/ssl_config_service.cc @@ -99,6 +99,7 @@ static bool g_dnssec_enabled = false; static bool g_false_start_enabled = true; static bool g_mitm_proxies_allowed = false; static bool g_snap_start_enabled = false; +static bool g_dns_cert_provenance_checking = false; // static void SSLConfigService::SetSSLConfigFlags(SSLConfig* ssl_config) { @@ -106,6 +107,8 @@ void SSLConfigService::SetSSLConfigFlags(SSLConfig* ssl_config) { ssl_config->false_start_enabled = g_false_start_enabled; ssl_config->mitm_proxies_allowed = g_mitm_proxies_allowed; ssl_config->snap_start_enabled = g_snap_start_enabled; + ssl_config->dns_cert_provenance_checking_enabled = + g_dns_cert_provenance_checking; } // static @@ -148,6 +151,16 @@ bool SSLConfigService::mitm_proxies_allowed() { return g_mitm_proxies_allowed; } +// static +void SSLConfigService::EnableDNSCertProvenanceChecking() { + g_dns_cert_provenance_checking = true; +} + +// static +bool SSLConfigService::dns_cert_provenance_checking_enabled() { + return g_dns_cert_provenance_checking; +} + void SSLConfigService::AddObserver(Observer* observer) { observer_list_.AddObserver(observer); } diff --git a/net/base/ssl_config_service.h b/net/base/ssl_config_service.h index 0ab88b2..be50097 100644 --- a/net/base/ssl_config_service.h +++ b/net/base/ssl_config_service.h @@ -28,6 +28,8 @@ struct SSLConfig { bool tls1_enabled; // True if TLS 1.0 is enabled. bool dnssec_enabled; // True if we'll accept DNSSEC chains in certificates. bool snap_start_enabled; // True if we'll try Snap Start handshakes. + // True if we'll do async checks for certificate provenance using DNS. + bool dns_cert_provenance_checking_enabled; // True if we allow this connection to be MITM attacked. This sounds a little // worse than it is: large networks sometimes MITM attack all SSL connections @@ -144,6 +146,10 @@ class SSLConfigService : public base::RefCountedThreadSafe<SSLConfigService> { // True if we use False Start for SSL and TLS. static bool false_start_enabled(); + // Enables DNS side checks for certificates. + static void EnableDNSCertProvenanceChecking(); + static bool dns_cert_provenance_checking_enabled(); + // Add an observer of this service. void AddObserver(Observer* observer); diff --git a/net/base/ssl_config_service_win.cc b/net/base/ssl_config_service_win.cc index 14c4d24..debea7d 100644 --- a/net/base/ssl_config_service_win.cc +++ b/net/base/ssl_config_service_win.cc @@ -4,6 +4,7 @@ #include "net/base/ssl_config_service_win.h" +#include "base/thread_restrictions.h" #include "base/win/registry.h" using base::TimeDelta; @@ -59,6 +60,9 @@ void SSLConfigServiceWin::GetSSLConfigAt(SSLConfig* config, TimeTicks now) { // static bool SSLConfigServiceWin::GetSSLConfigNow(SSLConfig* config) { + // This registry access goes to disk and will slow down the IO thread. + // http://crbug.com/61455 + base::ThreadRestrictions::ScopedAllowIO allow_io; RegKey internet_settings; if (!internet_settings.Open(HKEY_CURRENT_USER, kInternetSettingsSubKeyName, KEY_READ)) @@ -83,6 +87,8 @@ bool SSLConfigServiceWin::GetSSLConfigNow(SSLConfig* config) { // static void SSLConfigServiceWin::SetRevCheckingEnabled(bool enabled) { + // This registry access goes to disk and will slow down the IO thread. + // http://crbug.com/61455 DWORD value = enabled; RegKey internet_settings(HKEY_CURRENT_USER, kInternetSettingsSubKeyName, KEY_WRITE); @@ -108,6 +114,8 @@ void SSLConfigServiceWin::SetTLS1Enabled(bool enabled) { // static void SSLConfigServiceWin::SetSSLVersionEnabled(int version, bool enabled) { + // This registry access goes to disk and will slow down the IO thread. + // http://crbug.com/61455 RegKey internet_settings(HKEY_CURRENT_USER, kInternetSettingsSubKeyName, KEY_READ | KEY_WRITE); DWORD value; diff --git a/net/base/ssl_connection_status_flags.h b/net/base/ssl_connection_status_flags.h index 1b7640c..9596f00 100644 --- a/net/base/ssl_connection_status_flags.h +++ b/net/base/ssl_connection_status_flags.h @@ -27,10 +27,28 @@ enum { // library that doesn't report it, like SChannel.) SSL_CONNECTION_NO_RENEGOTIATION_EXTENSION = 1 << 19, + // The next three bits are reserved for the SSL version. + SSL_CONNECTION_VERSION_SHIFT = 20, + SSL_CONNECTION_VERSION_MASK = 7, + // 1 << 31 (the sign bit) is reserved so that the SSL connection status will // never be negative. }; +// NOTE: the SSL version enum constants must be between 0 and +// SSL_CONNECTION_VERSION_MASK, inclusive. +enum { + SSL_CONNECTION_VERSION_UNKNOWN = 0, // Unknown SSL version. + SSL_CONNECTION_VERSION_SSL2 = 1, + SSL_CONNECTION_VERSION_SSL3 = 2, + SSL_CONNECTION_VERSION_TLS1 = 3, + SSL_CONNECTION_VERSION_TLS1_1 = 4, + SSL_CONNECTION_VERSION_TLS1_2 = 5, + SSL_CONNECTION_VERSION_MAX, +}; +COMPILE_ASSERT(SSL_CONNECTION_VERSION_MAX - 1 <= SSL_CONNECTION_VERSION_MASK, + SSL_CONNECTION_VERSION_MASK_too_small); + inline int SSLConnectionStatusToCipherSuite(int connection_status) { return (connection_status >> SSL_CONNECTION_CIPHERSUITE_SHIFT) & SSL_CONNECTION_CIPHERSUITE_MASK; @@ -41,6 +59,11 @@ inline int SSLConnectionStatusToCompression(int connection_status) { SSL_CONNECTION_COMPRESSION_MASK; } +inline int SSLConnectionStatusToVersion(int connection_status) { + return (connection_status >> SSL_CONNECTION_VERSION_SHIFT) & + SSL_CONNECTION_VERSION_MASK; +} + } // namespace net #endif // NET_BASE_SSL_CONNECTION_STATUS_FLAGS_H_ diff --git a/net/base/ssl_false_start_blacklist.cc b/net/base/ssl_false_start_blacklist.cc index 9e0f309..b57826b 100644 --- a/net/base/ssl_false_start_blacklist.cc +++ b/net/base/ssl_false_start_blacklist.cc @@ -12,8 +12,8 @@ bool SSLFalseStartBlacklist::IsMember(const char* host) { if (!last_two_labels) return false; const unsigned bucket = Hash(last_two_labels) & (kBuckets - 1); - const uint16 start = kHashTable[bucket]; - const uint16 end = kHashTable[bucket + 1]; + const uint32 start = kHashTable[bucket]; + const uint32 end = kHashTable[bucket + 1]; const size_t len = strlen(host); for (size_t i = start; i < end;) { diff --git a/net/base/ssl_false_start_blacklist.h b/net/base/ssl_false_start_blacklist.h index 1d44d0a..d0b10e2 100644 --- a/net/base/ssl_false_start_blacklist.h +++ b/net/base/ssl_false_start_blacklist.h @@ -81,7 +81,7 @@ class SSLFalseStartBlacklist { // kHashTable contains an offset into |kHashData| for each bucket. The // additional element at the end contains the length of |kHashData|. - static const uint16 kHashTable[kBuckets + 1]; + static const uint32 kHashTable[kBuckets + 1]; // kHashData contains the contents of the hash table. |kHashTable| indexes // into this array. Each bucket consists of zero or more, 8-bit length // prefixed strings. Each string is a DNS name in dotted form. For a given diff --git a/net/base/ssl_false_start_blacklist.txt b/net/base/ssl_false_start_blacklist.txt index c718618..d782b5b 100644 --- a/net/base/ssl_false_start_blacklist.txt +++ b/net/base/ssl_false_start_blacklist.txt @@ -8,504 +8,4896 @@ # This is included for unit tests: example.com +008880.com +1-plus.com +111112.com 123.cht.com.tw +123people.com +155551.com +233332.com +24sevenselfstorage.com +2ndc.dk +2whateverittakes.com +333332.com +333337.com +365days.jp +38shop.jp +3mfx.three.com.hk +48pickup.com 4science.net +4ward.asia +50pickupnow.com +622222.com +6ftoverhead.com +911twenty.com +a-star.edu.sg +a.eap-net.com +a.thatsping.com +aaa.grh.org +aaastationreports.com +aanmelden.bjaa.nl +aaucm.org +abacustech.co.jp abangdani.wordpress.com +abc.attendseurope.com +abcirclenow.com +abdr.blood.gov.au +abeno-tennoji.jp +ablwebmail.com +abrocket.com +abrocketpilates.com +abrocketpowertrainer.com +abtserver.com +abtwebxpress.com +ac-besancon.fr +ac-caen.fr +ac-guyane.fr +ac-lille.fr +ac-limoges.fr +ac-lyon.fr +ac-nice.fr +ac-orleans-tours.fr +ac-paris.fr +ac-poitiers.fr +ac-reims.fr +ac-strasbourg.fr +ac-versailles.fr +acad1.dlit.edu.tw +academicclub.org +acams.dhs.gov access.arkansas.gov +access.coinstar.com +access.csn.edu +access.moric.org +access.opco.com +access.sullivanandassoc.com +access.vch.ca +access1.spokesman.com accessgeneral.com accessingram.com +accesswr.bannerhealth.com accorservicesdirect.net +account.payclick.com.au +accounts.jelhi.net +accu-doc.ch +acea.de +acebenefitsplus.co.uk +acheteremerycat.ca +acheterpalmwallet.ca +achs.org.au +acidesign.com +acommit.ch +acs-inc.com +acsi.eu +actionpoint.ch +activase.com +adcenter.msn.com.sg +adcouncil.tv adfox.cz +adhbcn.net +adhdtreatmenttoday.com +admin.centerpoint.jelecos.com +admin.iot.dtag.de +admin.webcast.fi +admin2.bloosky.com +administaffservices.com +adoptionscentrum.se +adox.sk +adplacer.com.au ads.bridgetrack.com +adtran.com adult.dl.rakuten.co.jp adulthire.com advanceautoparts.com +advisorpracticeconsulting.com +advocates.org.uk +aecc.ac.uk +aecom.com +aemc.net +aerosped.org +afconsult.com +afeyewear.com +affinitycircles.com +afflelou.net +afflinkservice.com +afflinksource.com +afternic.com +afterpayroll.com +aftonxchange.com +ag.729972.com +ag.ibc88.com +agencywow.com agents.nationalsecuritygroup.com +aggis.com.br +agir-recouvrement.com +agreemanager.net +agriinfo.copa-cogeca.be +agriinfo.copa-cogeca.eu +agromercantil.com.gt +ahanw.org +ahika.com +akabis.com +akershus-fk.no +aktionsplan-allergien.de alamode.com algoritam.hr +algvpn.algonquincollege.com +alinean.com +alle-inklusive.behindertenbeauftragte.de +allianz.hr +alliedliquor.co.nz +allmyaccounts.bankofamerica.com +alltours.at +alltours.de +alltours.info +almliquor.com.au +alperton.brent.sch.uk +alpinecapitalbank.com alsformalwear.com alucmo.com +alvo.com +alwaysillinois.org +am.cmc.com amail.centrum.cz +american-summit-flood.com +americanchia.com +americanexpress.hu +americanreliefcard.com +americanreliefcard.net +amesbank.com amexweb.com.mx +amf-assurances.fr +amgusa.com +ammail.edwards.com +amo-20happy.com +amo-happy-patients.com +amo-signature.net +amo-top.net +ampecommerce.com amsi.alliedgroup.net amwaylive.com +analytics.sonymusic.com +animate-onlineshop.jp +annssl01.fticonsulting.com anntaylor.recruitmax.com +anoka.k12.mn.us +anpassung.net +anshin-access.ezweb.ne.jp +antispam.hireahit.com +apex.utpa.edu +api.gogrid.com +api.rapleaf.com +apo-vpn-02.apotex.com +app.actre.it +app.audit-navigator.nl +app.elal.co.il +applicaties.tln.nl +appliedi.net +applymarketforce.com +applyshopnchek.ca +applyshopnchek.com +appraisalzone.lendervend.com +apps.caa.qld.gov.au apps.revenuecycle.com +appsgate.com +aproposgeschenk.de aps2.toshiba-tro.de apus.edu +ara.bahamaselectricity.com +aravo.com +arc.org.uk +archivedata.com +arena.highview.org aribabuyer.us.dell.com ariston.es +arizona.edu +arkansas.gov +arkona.com +arnecommunity.thomsonreuters.com +arowanacapital.com +arts.ac.uk +arvidsvensson.net +asa-seattle-1.adobe.com +asa01.svccorp.com +asacitrix.ccgh.org asb.dk +aschc.com ashgate.com ashleymadison.com +ashleyportal.com +asiandating.com +asklepios.com +asmconnects.com +asn.advolution.de asp.fm-pc.com +aspentrack.com +aspraytshirt.com +asthmamatters.com +astral.com +asugroup.com atari.com +athenasweb.brynmawr.edu +atl-c1.goodrich.com +atlas.fd.com ats.openhire.com +att.com attask-ondemand.com attask.com +attaskbeta.com +attendsguiden.se +audittool.bdoasf.com +auone.jp +aus-vpn.amd.com +auslandsschulwesen.de +authentication.accorhotels.com +autodiscover.barron.com.pe +autodiscover.dwvsolutions.com +autodiscover.eternalnetworx.com +autodiscover.montco.com +autodiscover.net +autodiscover.nimbus.nl +autodiscover.wrinklebrain.com +autopalvelut.kuusakoski.fi +autoradiostore.be +autoradiostore.nl +avastin.com +avgrewards.com +avlk.dishmail.net +avondale.org +avs.de +awesomearmsnow.com +awvn.nl axa.co.uk +axess.telcordia.com +axiamail.phoenix.edu +aza-lite.com +azurance.com +b-tracker.com +b2b.aksel.com.tr +b2b.mammut.ch +babyfoonstore.be +babyfoonstore.nl +babylon.inverso.de +backend02.d1g.com +backup.datassur.net +backupumbrella.net +bafin.de +bag-mail.de +bahmueller.de +bam.com.gt +bamf.de +bank4u.bancapopolare.it +bank4u.volksbank.it +bankadviser.com banking.ing-diba.at +bankingon.com baptisthealth.net +barakhosting.com +barclaystravelinsurance.co.uk +barelifts.tv barkoff.tv +barkoffspecialoffer.com barracudaserver.com +barrierepoker.fr barronscatalog.com +bartletthospital.org +bartoncreek.com +basco.com +basf-farefinder.com +baua.de +baxter.com bb3.utc.edu +bboardtest.nsula.edu +bbsihq.com +bcbsal.org bcbsfl.recruitmax.com +bdmp.com +beamercenter.be +beamercenter.nl +beanfun.com +bedfordschool.org.uk +beespace.issukraine.com +behindertenbeauftragter.de +bel.com.bz +belvis.swibi.ch +ben.billing.com.au +bendarooscreativity.com +bendaroosglow.com +benderball.tv +benefitsconnect.net +benendenschool.net +bennett.kent.sch.uk bentley.edu +berg-hansen.no +berger-meditec.com +berryworld.co.uk +bestobamacoin.com +bestpossiblequotes.com +bestwhole.com +beta-lighting.com +beta.algodeal.com +beta.ekool.eu +betcloud.com +betlegion.com +bettertrades.com +bevoelkerungsschutz-portal.de +bevoelkerungsschutz.de +beztakcorp.com +bfarm.de +bfu.ch +bhinc.com +bi.com +bib-demografie.de +bid53.com +bidclay.com biddingforgood.com +bidmc.org +bidokaloosa.com biffalo.net +bigcityslider.com +biglobe.ne.jp +bigwintracking.com bilder.buecher.de +billing.ntt-east.co.jp +billonline.com +biloxiregional.net +biooncology.com +biozid-portal.de +biprod01.mfsasp.com bishops.org.za +bisp-sportpsychologie.de bitfang.com +bitlasso.com +biz.portlandgeneral.com +bizneslink.pl +bizoubazart.com +blackmarble.co.uk +ble.de +blinkbox.com +blog.mudy.info +blog.neosec.dk blogger.huffingtonpost.com +blooads.com +bluearea.net +bluefinsolutions.com +blurayspelershop.be +blurayspelershop.nl +bmelv.de +bmwi-unternehmensportal.de +boaregistret.se +bockelman.org +bodycareshop.nl +bokuvpn.boku.ac.at +bonfils.org +book.lowestairfares.com +bookeo.org +bookitnow.mirabeauparkhotel.com +boormachinestore.be +boormachinestore.nl +bopowa.elcabop.org +born.ch +borsen.klasselotteriet.dk +bos.stidelivers.com +bosch-savingsystem.com +bottletops.tv +bowldvd.com +boxmedia.bredband.net +bp-platinum.com +brabantwater.nl +bradfordcollege.ac.uk +brainforce.nl +braintumorconnections.com +branders.com +brandon.ca +brcc.edu +brcn.edu +breastcancerconnections.com +brest-metropole-oceane.fr +bridgetrack.com +brighton.ac.uk +brightonsc.vic.edu.au brinksinc.com +britishmusicexperience.com +broadoak.n-somerset.sch.uk +broker.healthcompare.com +brookfield.hants.sch.uk +brookfieldservices.com +brookshealth.org +broomwellhealthwatch.com +brotheroffers.com +bs24.jp +bsal.com.au +bsi-fuer-buerger.de bsi.de +bskytracking.com +bsnparentnet.nl +bsnstaffnet.nl +bsp.bradfieldcollege.org.uk +bsprivat.de +btlaw.com +btracker.com +buckinghamhotel.com +budget.bmas.de buecher.de +bui.co.za buildings.com bund.de +bundesfinanzministerium.de +bundesgerichtshof.de +bundesgesundheitsministerium.de +bundespolizei.de +bundesrat.de +bundesversicherungsamt.de +burtsbeesacne.com +businessassetmanager.com +businessverifications.com +businessware.com +businesszone.quester.at bux.ee +buxtonbag.com +buxtoncartera.com +buxtonmicro.com +buxtonpalmwallet.com +buxtonwallet.com +buy1948pickup.com +buy1957caddy.com +buy33caddy.com +buy41flatbed.com +buy50pickupnow.com +buy57caddy.com +buyaquaglobes.tv +buyaspray.com +buybanoodle.com +buybeautifulworshipcd.com +buybenderballca.com +buybionicwrenchonline.com +buyblueplanet.com +buybombachop.com +buybumpit.tv +buychiaseedsnow.com +buycollegesuggies.com +buycucumbervine.com +buydesignersnuggie.com +buydomains.com +buyeasyreach.com +buyemagrece.com +buyfiftydollargold.com +buyflatbedfireset.com +buyflirtygirlfit.net +buyflirtygirlfit.tv +buyforemaneverydayandmore.com +buyfountainofyouthnow.com +buyfranklinmint.com +buygetitgreen.com +buygrandpa.com +buygrillglovetv.com +buygyrobowl.com +buygyrobowlset.com +buyhandyvalet.com +buyhangingstrawberry.com +buyhdvisionreaderssite.com +buyhdvisionultra.com +buyheeltastic.tv +buyhydroheel.com +buyidooffer.com +buylastmorgans.com +buymagicjacknow.com +buymagictarptv.com +buymagnetrim.com +buymightyfixit.com +buymightyputtynow.com +buymightyshine.com +buymightysuperpack.com +buymilitaryflatbed.com +buyminimaxnow.com +buymonstersteamjet.com +buymorgansilver.com +buymushroomkit.com +buymusiccristianaespanol.com +buymyarmyset.com +buymygianttomatoes.com +buymyhairblock.com +buymysportelec.com +buyoptic1050.com +buyoptic1050tv.com +buyoverthedoor.com +buypedegg.tv +buypedipaws.ca +buypedipistol.tv +buypestfree.tv +buypetmd.com +buyphilsdvdsnow.com +buypowerjuicerpro.com +buypowershaper.com +buyprofitfromrealestatenow.net +buyptpro.com +buypumpitfresh.com +buyquicklawnseed.com +buyrainbowpeppersnow.com +buyrazordock.com +buysamowraiblade.com +buysecretsolution.com buyshakeweightformen.com +buyshakeweightforwomen.com +buyshamwownow.com +buysideshowskillettv.com +buyslimmettes.com +buysnuggie.tv +buysnuggieforkids.tv +buysoftpullleash.com +buysongs4soldiers.com +buysteamjetnow.com +buystonenow.com +buyteddyspridesite.com +buytexastail.com +buythecrazycritters.com +buythecuttermouse.com +buythekingcoin.com +buythelittleredchef.com +buythemousechaser.com +buytheoptic1050.com +buytheperfectbutton.com +buythesnuggie.com +buythesteambuddy.com +buythinspin.com +buyticklemeplant.com +buytidytable.com +buytimelifeespanol.com +buytomatofactory.com +buytomatofactorynow.com +buytoolbandit.com +buytopsytree.com +buytopsyturvy.com +buytvhatnow.com +buyultimatetable.com +buyupsydaisytv.com +buywidgetlight.com +buywindshieldwonder.tv +buywonderhanger.com +buyzipdo.com +buzzcity.com +byebye.de +bzgs.ch +bzi-interlaken.ch +bzport.net +ca.gov +cachezone.cache.org.uk +cadizretail.co.za +cadizwealth.co.za cagreatamerica.com +caisse-epargne.fr +cal-x.net +calchoice.com +calchoiceplus.com +caldicott.com +call2.nl +callbe.com +callingcards.at +calvijn.nl +cambriancollege.ca +camelvpn.conncoll.edu +campasol.com +campus.himeji-du.ac.jp +campus.norquest.ca +campusharvest.org +canadaswonderland.com +canadianbenefits.com +cancer-test.com +cancerchampionprogram.org candydirect.com +caowa.altara.com +cap.dyntek.com +capellfarmfinance.com +capeplc.com.au +capgemini.com +capitalonedealsdone.com +capvpn.capilanou.ca +carcraft.co.uk +cardlabconnect.com cardsdirect.com +career.cdtechno.com +careers.hphood.com +careers.nicta.com.au +careers1.flagstar.com +careport.carilion.com +careylink.com.au +caridianbct.com +carilionlabs.com caringbridge.org +carintreggelandgroep.nl +carisbrookehighschool.net +carlislermc.com +carrinho.casashow.com.br +cas.freud.com +cas.grey.com cash.netmarble.net +cashexpress.com +cashpoint.com +catalog.synthes.com +cathflo.com +catholic.edu.au +catie.ac.cr +cave-kit.com +cbcag.edu +cbfive.com +cbsmail.constangy.com +ccisd.us ccmail.cc.gatech.edu +ccpb-basse-normandie.fr +ccpvpn.ccpdocs.com +cdcpoint.it +cdfbooks.com +cdmwsa.com +cdp.moduspec.com +cduvpn.cdu.edu.au +ce.byu.edu +cedardoc-cm.com +cedardoc-demo.com +cedardoc-dev.com +cei253e.com celebrateyourfaith.com +celebritysweatnelly.com +celtipharm.net +cemex.com +centralmississippimedicalcenter.com centralr.com +centrum.cz +centuriondirect.com +ceramicreview.com certs.zurich.co.uk +cespmi.org +ceuherning.dk +cfai-centre.net +cfliving.com +cfw.org +cgi.mbs.jp +ch.cutler-hammer.com champions-online.com +channeladvisor.com +chapmantripp.com +charlotteregional.com +charltonschool.net +chasslvpn.ecommunity.com +checkoutblog.com +cheizoo-sp.online-documents.net +chester.ac.uk +chesterregional.com +chevrolet-leadengine.de +chiaobama.ca +chiaobama.tv +chiba.jp +chill-n-go.com +chinookhosting.com +chinooknetworks.com +chl-peq.co.uk chnla.com +chocolatefactorytv.com +choicebuilder.com +churchill.n-somerset.sch.uk chw.recruitmax.com ciaoitalia.com +cic-valencia.org.ve +cifex.ethz.ch cinema.warnermycal.com circlesofwisdom.com +cisco.com cisr-ssl-vpn2.univ-lyon1.fr citi.bridgetrack.com +citicards.com +citiforward.com +citixcard.co.jp citizensfla.com +citonline.com +citynet.net +ckbmail.me +clarity.com claritycon.com +clarksoncollege.edu +claroline.lakato.net classbauth.austin.hp.com +classicsoftrock.com +classifiedventures.com +clayko.com.au +click.showcase-tv.jp +clickanalyzer.jp +client.neftex.com +client.uniastrum.ru +clients.mdmatic.com +clineavestudy.com +cloroxspss.com +cloud-mail.co.uk +cloud.carthagecsd.org +cloud.mvctc.com +cloud.santeesd.net +cloudconnectsd.net +cloudhoist.com +cloudmail.trustcld.com +cloudonestorage.peer1.com +cloudspeaker.fm +cloudworks.com +cm.commercehub.com +cmithun.dojiggy.com +cms.whereilive.com.au +cnw.albertaequestrian.com +cnw.hcbc.ca +codarts.nl +coddy.com cofunds.co.uk +cohowa.houstontx.gov +collaborate.sandia.gov +colorectalcancerconnections.com combattesting.com +commandaware.com +commentor.dk +commissies.ser.nl +commonwealth.int +communitylakes.com +compass.emmanuelschools.net +compass.oxiana.com.au compaxtrade.com -confirmit.suw.corp.google.com +compellent.com +complete180degree.com +comporium.com +comprabuxton.com +comprariddexpulse.com +comprasnuggie.com +compratastiwave.com +compreabrocket.com +compupaypartner.com +compus.de +computerstore.be +computerstore.nl +coms.industrialcontrolrepair.com +concat.de +concur.csmc.edu +conduxio.com +config.tplpbx.de +confluence.mediaspectrum.net +connect.bangor.ac.uk +connect.clearpointe.com +connect.coventry.ac.uk +connect.dpem.tas.gov.au +connect.plan-b-gmbh.com +connect.studygroup.com +connecta.se +consoleshop.be +consoleshop.nl +construction-ec.com +contitiremanagement.com +controlpanel.ch +coolblue.nl +coop-kobe.net coopervisionrebates.com +coorscup.com +copeskoal.com corporate.bpn.pt +corpset.com +correctionalbillingservices.com +correio.fdc.org.br +correio.ina.pt +correo.entelpcs.com +correo.orizonia.com +correo.psl.com.co +correo.tec.ac.cr correo.uft.cl +cortesoft.com +costco.com.mx +couplesnuggie.com +courriel.jlp.ca +courriel.journalmtl.com +courriel.lepisc.com +covlecremote.org +covnet.covenantretirement.org +coyoteportal.wc.edu +cozi.com +cp.billing.ru +cp.it2all.eu +cpas.cz +cportal.sechan.com +cprmc.com +cpsb.org +cpse.dundee.ac.uk +cranbrook.kent.sch.uk +crci.org.uk credinamico.programapar.com.br creditcards.citicards.com +creditunionon.com +creuna.dk +crew.transavia.com +criny.com +crmpartners.crmpartners.org +crnbc.ca +croc.ru +crossgatesriveroaks.com +cryptolab.org +crystalfunds.com +crystaltools.com +csaa.com +cscinfo.com +csp.cvut.cz +csst.qc.ca +ctasanywhere.centraltas.co.nz +ctdhe.org cts.vresp.com +cu.edu +cuatrecasas.com +cubewano.com cubizone.com +customer.comcast.com +customer.dgrefining.com +customer.gbs-consult.com customer.precash.com +customer.unicaresys.com +customerconnect.scholasticbookfairs.com +cusys.edu +cv.occstrategy.com cvintranet.classifiedventures.com +cwa.astra-honda.com +cwa.avanade.com +cwa.fandr.com +cwa.telecomputing.no +cwt.no +cwtnordic.com +cybershoppersonline.com +d-ikt.no +d-starjob.com +d115.de +d15email2010.d15.us d49.org +daidalos.nl +daiwa-bs.co.jp +dalinis.net +dallasregionalmedicalcenter.com +danks.com.au +daphne.gfk.com +dasa-dortmund.de +data.eglia.com +dataformas.com +dataliberation.com +datasettlement.com +datatel.com +davidson.edu +davisregional.com +dbpn.com +dc.myflorida.com +dc110.4shared.com +dcess.dallascounty.org +dcvpn.cov.com +de-mail.de +deadliestdvd.com +decc.gov.uk +dehaagsescholen.nl +deklimboom.nl +deloitte.com +deloitteresources.com +delorentz.nl +deltek.forceprotection.net +demo.crm4destinations.at +dentalxchange.com depo.ru +deshaw.com +design.cscape.com +design.nzzdomizil.ch +designersnuggie.com destinationlighting.com +deutsche-islam-konferenz.de +developer.smartapp.tw +development-school.jp +device.fancast.com +dexia.be +dexter.ansaldo-sts.us +df.co.kr +dfc.inovestor.com +dhhnet.dhh.louisiana.gov +dhs.edu.sa +diamail.diadubai.com +dice.com +dienstleistungszentrum.de +digi.mobilethink.net +digicamshop.be +digicamshop.nl +direct.msn.com +direct2wholesale.com +directv.com +disc.co.jp +discomp.cz +discovertotal.com +discovwww.waterford.k12.mi.us +dishnetwork.com +disneydigitalshare.com +dist113.org +district205.net djmmusic.com +dl.com dl.rakuten.co.jp dmgov.org +dmz.rgcweb.org +docmesa.com docstoc.com +docufide.com docuware.com +dodgeprojects.construction.com +doe.gov dokeos.ehb.be +dolandesigns.com +domain.amta.com +dosco.com.tw +dpwn-airlinesourcing.com +dr.rachisholm.com drammen.skole.d-ikt.no +drimanagement.com +drlists.com +drm.nl +droppstv.com +drs-digital.com drsha.com +drudeans.com dskdirect.bg +dsl-art.org +dsoguild.com +dtvce.com +dualforceaccessories.com +dualsaw.com +dualsawcanada.ca +dualsawspanish.com +dunamare.nl +dupnet.org +durham.ca +durringtonhigh.w-sussex.sch.uk +duvak.nl +dvlottery.state.gov dwarest.disc.co.jp +dws.com.au +dynamicscrm.asia +dynetics.com +e-billing.econgas.it +e-cap.fr +e-denpo.net +e-healthnet.mhlw.go.jp e-lotto.be +e-mechatronics.com +e-mergedata.net +e-quilibrium.net +e-state.co.jp +e-state.ne.jp +e-trade-center.com +e-usluge.rijeka.hr +e-valuer.com +e-zoa.com +earlybird.ae +earlyedcloud.net +earnplaza.com +earthclassmail.com +eastgate1.frontiercorp.com +eastgeorgiaregional.com +easv.dk +easweb.thecdmgroup.com easybillindia.in +easyhome.com.tw +easymovewithfios.com +easyreachoffer.com +easyreachtv.com easyswitch.nl +eaton.com +eazifleet.com ebb.ubb.bg +ebencom.com ebit.com.br +ec.broadom.net +ecafe.lahey.org +ecare.proctor.org echo.com +echostar.com echotrak.com +eclipse.molagers.org +ecom.peoples-bank.com +ecommerce.colsubsidio.com econda-monitor.de +ecwid.com edaccents.com +edenbrook.co.uk +edinet.cenet.ws +edu.on.ca +education.vic.gov.au edumail.tokem.fi +edumail.vic.gov.au eduportal.pl +eduweb.vic.gov.au +edziekanat.wsf.edu.pl +efo.adplan-tg.com +ehb.be +ehs.dk +ehub.dsionline.com +eiffel.nl +einfach-teilhaben.de +eisweb.enterinfo.com +eku.edu +elibrary.asdealernet.com +elibrary.comfortsite.com +elliottdevon.com elm.mcmaster.ca elmls.mcmaster.ca +elogistic.motorola.com +elpodercd.com +elproman.biz +els.cis.fukuoka-u.ac.jp +els.streetly.walsall.sch.uk +email-internet.pekao.com.pl +email.arbora-ausonia.com +email.campus.uvt.nl +email.cosan.com.br +email.eatoncounty.org +email.energy-northwest.com +email.frostburg.edu +email.fusionsys.com.mx +email.greatershepparton.com.au +email.hermos-vhm.de +email.jyu.fi email.manutouch.com.hk +email.masku.com +email.medianewsgroup.com +email.mycontact.co.nz +email.ndm.edu +email.phillynews.com +email.piraeusbank.gr +email.sjb.com.au +email.sjbcommunity.ca +email.starair.dk +email.stpeters.qld.edu.au +email.stpeters.sa.edu.au +email.svcfs.org +email.uk.betfair.com +email.unity.net.nz +email.usiu.ac.ke +email.wallawalla.edu +email.whgardiner.com email.wsd1.org email.yorksj.ac.uk +email2010.smu.edu.sg +emanet.com +embeddedwebserver.net +emea.archive.messaging.microsoft.com +emeamail.corp.salesforce.com +emedic.jp +emergenow.com +emericalinksite.com +emersonhosp.org +emerycat.ca +emerycat.com +emerycatrefill.ca +emerycatspecialoffer.com +emi.eu +emi.hu +emploi.sitq.com +employee.coastmountainbus.com employee.translink.bc.ca +empresas.bancobcr.com +enav.it +endlager-asse.de +endlager-konrad.de +endtoendsourcing.com +enhancedservices.paetec.com +enrol.ie ent.enteduc.fr +ent95.valdoise.fr enterprise.channeladvisor.com +envisionitsolutions.net +eod.teamcolts.net +eoir.com +eom.performance.gr +epaveiro.edu.pt +epistrofi-eurobank.gr epk.tv +eplus.jp +epm.com.co +eportal.fleetwoodhs.org.uk +eportal.shelfieldcommunityacademy.co.uk +epost.ha.kommune.no +epost.luftnett.com +epost.skola.ljungby.se +epost.uddevalla.se +epost.visma.no epoti.abanka.si +epsb.ca equippers.com +equitydriver.com +ercasharepoint.com +ereaderstore.be +ereaderstore.nl +erecruit.thechildrenshospital.org +ereg.biz +ergo.ergonomidesign.com +ergonet.pl +erhgroup.com +ericom.com +erivpn.eisai.com +eroom.arvato-systems.de +esabilgisayar.com.tr +esales.master.ca +esdlife.com +eshbelhost.com +eshbelsaas.co.il +eshbelsaas.com +esher.ac.uk +eskilstuna.se +esloo.nl +espaicambrabcn.org +especificacoes.com +esportivaparana.com.br +espprofitlink.com +estore.hpfairfield.com +estrellamountain.edu +etk.fi +etrack.teletrack.com +ettu.nl eumail.nov.com eurobank.pl +europ-assistance.pt +europa.eu +europass.cz +europlan.ru +eurotax.at +events.sainc.com +evergabe-online.info +evoline.net +evoraoralcaresite.com +evpn.techteam.com +ex.uni-paderborn.de +exadmin.rcs-mail.com +excels.org +exch-hub.cancer.dk +exch.naaco.ru +exchange.berden.nl exchange.chc.be +exchange.clarkslegal.com +exchange.clearwaterpaper.com +exchange.cs-soreltracy.qc.ca +exchange.datacom.com.au +exchange.dcpud.net +exchange.gilacountyaz.gov exchange.hostnet.nl +exchange.intranet.neumanpools.com +exchange.keyhie.org +exchange.khlim.be +exchange.knpc.net +exchange.mit.ie +exchange.netbit.ch +exchange.public.eibs.co.uk +exchange.raakict.nl +exchange.roteskreuz-tirol.at exchange.selco.info +exchange.tinozplace.com +exchange.uetcl.com +exchange.uniserver.nl +exchange.unitek.com +exchange4u.cz +existenzgruender.de +exmail.businesslinksoutheast.co.uk +exmail.med.uni-magdeburg.de +expesite.com +ext01.lifesouth.org +extclt.isatech.fr +extern.balslev.dk +external.piggott.wokingham.sch.uk external1.collaboration.hp.com extra.chrysler.de +extranet.4ward.it +extranet.calvis.com +extranet.cbr.nl extranet.cchmc.org +extranet.cec.org +extranet.chaco.com.bo +extranet.dialoggroup.biz +extranet.hbj-gw.com +extranet.infoproject.fr +extranet.jbdelasalle.com +extranet.lackverband.de +extranet.metabolomicscentre.nl +extranet.ministryofsound.com +extranet.mm-software.com +extranet.pandasoftware.com +extranet.portalsolutions.net +extranet.sysmex.com +extranet.transpondertech.com +extranet.ubgonline.net +extranet.winchester.com +eyelovelytv.com +eyeonamd.com +eyeonamd2.com +f-seneca.org +faberwebshop.nl +faimai.hcri.net +falcontrading.ro +falmouth.cornwall.sch.uk +fanclub.tokyodisneyresort.co.jp +fanniemae.com +farefinder.de +farsigeotech.com +fastmvr.com +fastsearch.com faxbetter.com +fcaamd.com fdc.org.br +fe-bud.mag-news.it +fedintel.net +feitest.com +felixlive.com +fema.gov +fenwalinc.com +ffis.es +fhvasa01.flhosp.org +filexchange.accarda.com financialengines.com +finansnet.dk +finn.no +fiosfriends.com +fire.tas.gov.au +firma.pcs.cz +firmaface.com firstam.net +firstassistinsurance.co.uk +firstassistinsurance.com +fish4.co.uk +fishermenshospital.com +fit.ba +fiu.edu +fiztrade.com +fjarvinna.grund.is +fleetwoodsc.org.uk +flhsmv.gov +flirtygirlfitca.com +floodlands.com +floodonline.com +floodplus.com +floodplus.net +flowerpowercds.com +flowersbelgium.hostbasket.com flydenver.com +fmglobal.com +fmpro.cati.com +fokusanalys.se +folkestonegirls.kent.sch.uk +footnote.com +footnotelibrary.com +ford.com +form-gic.altran.net +formassist.jp +forms.lasikmd.com +forms.techdata.net forums.champions-online.com forums.startrekonline.com +fossport.com +foto.mitlejerbo.dk +foxtix.com.au +fpcu.org +fr.powerjuicerpro.ca +frankfurt-oder.de +frankfurter-bankgesellschaft.ch +franklinregionalmedicalctr.com +freebioven.com +freegrillglovetv.com +freehandycaddy.com +freerejuvenateautotv.com +freerejuvenateca.com +freerejuvenatetv.com +freo.ne.jp +fridgelockertv.com +fs-efo.jp +ftp.cambridge-design.co.uk +ftp.lim.com +ftp.maedapat.co.jp +ftsportal.forensicsandediscovery.com +fubar.com fucam.ac.be +fuchs-datentechnik.de +fueldoctorcanada.ca +fueldoctorfd47.com +fueru.jp +fuji-ie.com fullseat.com +fultonschools.org +fusdaz.org futuretrails.com +fv-group.net +fw01.monheim.de +fx.sovereignbank.com +fxedge.trader.integral.net +fxinside.net +fye.com +g4s.se +gakushuin.ac.jp +gamania.com ganymede.chester.ac.uk +garconet.garco.com +garmin.com +gate.we-learn.org.uk +gatech.edu +gatekeeper2.aspectsecurity.com gateway.madisoncity.k12.al.us +gateway.sagemontchurch.org +gbssg.ch +gcc.edu +gcportal.guycarp.com +gda-portal.de +geicocard.com +geicocreditcardapplication.com +gemini-apx.com +gene.com +genentechaccesssolutions.com +genentechmm.com +geniusreport.com genuineonlinebank.com +geomant.com +geometrik.golder.se +geonosis.itsso.gc.ca +georgefox.edu +gepartsrebates.com +germfree.org +get1931roadster.com +get1933caddy.com +get2instantcover.com +get31roadster.com +get6weekbodymakeover.com +get911twentynow.com +getair-o-sage.com +getbendaroostv.com +getbestline.com +getboomaringnow.com +getcablecapture.com +getcan-air.com +getchefandgo.com +getclassicfriarsroast.com +getclassicsforrelaxation.com +getcomfortfurnace.com +getcozycolors.com +getdigitalbiblenow.com +geteasyreach.com +getefx.com +geteggiestv.com +getesiobev.com +geteyetality.com +getflexibrite.com +getflipperremote.com +getgianttomato.com +getglowbeam.com +getgreenbags.tv +getgyrobowl.com +gethandyvalet.com +gethealthsupplies.com +gethightenz.com +geticanonlyimaginecd.com +getiknowkey.com +getionpod.com +getirenewnow.com +getjupiterjack.com +getkuddles.com +getlesko1995.com +getmatthewleskoquickstart.com +getmightyputtynow.com +getmiracleplunger.com +getmonstersteamjet.com +getmorgans.com +getmpgreennow.com +getmy.com +getmybedsidetable.com +getmydreamtable.com +getmyt4.com +getmytaxform.com +getmyw2.com +getmyyobaby.com +getnazidvds.com +getnuwaveovennow.com +getopeneyesofmyheart.com +getoprydvd.com +getpalmwallet.ca +getparkbillstv.com +getpetmdnow.com +getpopmemories.com +getpuplight.com +getrejuvenate.com +getrejuvenateautotv.com +getrejuvenateca.com +getromancingthe70scds.com +getsanistep.com +getscrubglove.com +getseatwedgy.com +getsecretsolutiontv.com +getshakeweight.com +getshakeweightnow.com +getshockitclean.com +getslimts.com getslimtsnow.com +getswirlyclip.com +gettheemerycat.com +gettheturbosnakenow.com +getthewonderhanger.com +getultimaterockballadscds.com +geturinegone.com +getvibrobelt.com +getvietnamwardvds.com +getwiperwizardnow.com +getworkout180.com +getworldatwar.com +getworldatwarespanol.com +getworldofreading.com +getyourpajamajeans.com +getzasshu.com +getzerogerm.com +getznowonline.com +gezeb.cmpd.org +gfk-repinsight.com +gfkdaphne.com +ggu.edu +ggusd.us +ggy.com +gilmorehealth.com global2.mtsallstream.com +glove.mizunoballpark.com +glowinghealth.com.au +glueckkanja.net +gmb.org.uk +gmxy.org go.enbw.net +go.post.de goamp.com +gogamer.com +golan.wisela.org +goldflux.com +golfdo.com +golfersland.net gomopa.net +goodfellowbros.com +goodyear.com +goquickstart.com goredsea.com +gorm.tauron-pe.pl +got-root.ch gotobelfast.com +gotomypc.rareeditions.com +gov.on.ca +gpsshop.be +gpsshop.nl +gpz.it +gr-espel.com +graceselah.com +gradwellintra.net +graniteschools.org +greatsankey.org greenpower24.com +grillingadget.com +gripperglovestv.com +gristedes.com +grizridge.com +grmetrieve.com +grmorc.com +groenewelle.nl +grotiuscollege.nl +gruenderpreis-nominierung.de +grupalotos.pl +gsmstore.be +gu.se +guardiant.com +guardiantauto.com +guhsdaz.org +gw.alumni.iae.edu.ar gw2.fli.bund.de +gw2.vincentz.de +gynspecialistsorlando.com +gzb.info +ha.jmpextra.net +hadar.fr +hades.tens.pl haken.mynavi.jp +hakwr-neustadt.ac.at +halton.ca +hammerofgod.com +hancockbank.hb2go.mobi +hancockfabrics.com +handelwandel.com +handydryer.com +handyvalettv.com hangikredi.com +hapimag.com +happyoz.com +harborwholesale.com +harbottleonpremise.com.au +hardandheavycds.com +hardpoint.eu +harrisdseries.com +harrisvle.org.uk +hartonmedicalcenter.com +hartslagmetercenter.be +hartslagmetercenter.nl +harvard.edu +harvestbible.org hastingsdirect.com +hastingsessential.com +hatchearlychildhood.com +hcc-tripod.hoffmancorp.com +hccanet.org +hclab.jp +hcmysteryshop.com +headsetshop.be +headsetshop.nl +healthinsurance.org.au +healthportdirect.com hearablog.com +heartofflorida.com +heartoflancaster.com heavens-above.com +heeltasticpedeggpromo.com +heelusa.com +helinium.nl helpdesk.clear2pay.com +helpdesk.sarnt.co.uk +helpdesk.v-h.nl +helpdesk.yhc.edu helwanbb.com +henleycol.ac.uk +hensongroup.com +her2genes.com +herceptin.com hercle.com +herconnection.com +herculiteondemand.com +hesse-lignal.de +hetassink.nl +hhc.acerebates.com +highlandsregional.com +hillgatetravel.com +hillsgradprogram.com +hipcomputer.de +hire.acxiominsight.com +historybeat.com hivanet.hitachi-ies.co.jp +hj2.hjemmekontor.nhn.no +hma.com +hmc.it-ernity.nl +hmc.vdx.nl +hnvpn.hostnordic.com +hoganas.se +hoken-clinic.com hoken-clinic.info +hollywoodhobobagaccessories.com +hollywoodhobobagtv.com +home.ceadvisors.com homedepotrebates.com +homespot.dk honeybakedonline.com +honeywellusersgroup.com hood.com +hoodhomedelivery.com +hoodneighborhood.com +hoofdtelefoonstore.be +hoofdtelefoonstore.nl +hopline.net hostedjobs.openhire.com +hosting.privatehost.nl +hostpoint.ch +hosttraxx.com +hotelleriesuisse.ch +householdshop.nl +housingservices.com +houstonisd.org howtowritearesume.net +hox.biz +hq.eisenhowerlaw.com +hq.nimvpn.com +hq.totalengineering.biz +hqaccess.acs.org +hro-gate.aida.de +hrwow.com +hs.ct-net.nl +hsacalifornia.com +hubpen.biz +hull.ac.uk humana.recruitmax.com +humanadental.com +hurleymc.com hurmail01.hurriyet.com.tr +huronconsultinggroup.com +huttonhotel.com +hva.nl +hwinet.org hydra.cusys.edu +hypecits.com.au hz.nl +i-95alternatives.com +i-ecnet.co.il +i-teamroom.com +i485project.com +iata.invoiceworks.net +ibank.mpbsecure.com +ibank.sabank.hr +ibank.snoras.com +ibc123.com +ibc168.com +ibc4u.com +ibc818.com +ibc888.com +ibcbet.com +ibet888.net +ibqonline.com +ibweb.alphabank.ro +icc-cpi.int +icecream-money.com +iconnect4.interiorhealth.ca +ict.gov.qa +id.telecom.pt +identity.ppdi.com +identitymine.com +idrettsmail.no +ie.com +ifa.ch +ifraudalert.org +ifs.thaeles.nl +igaseguros.com.br +igc.infragard.org +igeinfo.com +igniterealestatesite.com +igweb.meridiana.it +ihale.gov.tr +iiarc.net il.systemb2b.com il2l.com +ilsole24ore.com +im-sc.com +im.its.iastate.edu +images.bdotickets.com.au +imageworksdisplay.com +imail.healtheast.org +imakenews.com +imediador.com +img.mspub1.com +imgroup.com +imgssl.shinsegae.com +imperva.com +ims.esdcar.org +imsbackyardfightclub.com +imsbi.com +imsbuyezcombs.tv +imsbuyquicklawn.com +imsbuyshoesunder.tv +imschools.org +imscleverclips.com +imsdualforce.com +imsfiftydollargold.com +imsfridgegenie.com +imsfueldoctor.com +imslappertrays.com +imsmightybite.com +imsmightybitetv.com +imspalmwallet.com +incircle.alphaomicronpi.org +incircle.alumni.american.edu +incircle.artcenter.edu +incircle.ato.org +incircle.cmualum.com +incircle.drexel.edu +incircle.lagrange.edu +incircle.mainealumni.com +incircle.sae.net +incircle.tridelta.org +incircle.umalumni.com +incircle.usfalumni.org +incircle.westwood.edu +incircle.wiu.edu +incirclepro.com +incolink.org.au indraweb.indra.es +indstate.edu +inetportals.com ineways.com +ineways.eu +inewayscanada.com +infineon-farefinder.com +info.broadsoft.com info.enet-japan.com +info.oebv.com +infobear.bridgew.edu infonet.hz.nl +infosupport.com +inframan.nl +ing-diba.at +ing-hipotecaria.mx +ingramentertainment.com +inlogin.com +innmarinsecure.com +inos.nl +inria.fr +insattningsgarantin.se +inscodico.com +inside.cod.edu +inside.consona.net inside.nhl.com +inside.santamariaworld.com insight.smartdm.com +insite.henrich.de +instantfisherman.com +instantintelligence.com +insurancebis.com integrishealth.recruitmax.com +intellilink.visa.com +intellium.co.nz +interact2.ird.govt.nz +interconnect.be +interhosting.interfree.it interiorsandsources.com +interlaken-congress.gosecure.ch +intern.abm-energie.de +intern.abm-service.de +intern.goebel.de +intern.med-bz.de +intern.svk.no internal.imaginets.com +internal.ppww.org +internal.razimports.com +internap.com +intersourcing.com +intex.com +intra.2at.net intra.billing.ru +intra.motion10.com +intra.nordfyns-gym.dk +intra.svendborg-gym.dk +intra.unbonn.org +intranet.1-first.com +intranet.2nsb.org.au +intranet.a3is.com +intranet.abesse.hu +intranet.bexleygs.co.uk +intranet.bhtc.sandwell.sch.uk +intranet.britishscienceassociation.org +intranet.carrel.fr +intranet.ceff.ch +intranet.chilcote.bham.sch.uk +intranet.espria.nl +intranet.frederikssund.dk +intranet.grupocopisa.com +intranet.hallwilcox.com.au +intranet.ipi-gmbh.com +intranet.itsduero.es +intranet.majedie.com +intranet.mhc.cc intranet.peckham.org +intranet.scriptum-site.nl +intranet.stanville.bham.sch.uk +intranet.uck.nl intranet.ucol.ac.nz +intranet.xperta.se +intuit.com +intuitrebates.com inverhills.edu +investissementsdavenir.agencerecherche.fr +inzicht.dfa.nl +ioffer.com iol.pt +iowaworkforce.org +ip.clubcorp.com +ipayables.net +ipi-interactive.com +ippo.net +iqmetrix.com iqsystem.irrc.co.jp +iraniansinglesconnection.com +iris.colum.edu +irrc.co.jp +ish-bridge.com +ishbs.com +isi-net.com +isic.hu +isstct.cz +issuemanager.myriad-it.com +istoreit.net +isupplier.americanlafrance.com +it-consult.net +itgroovehosting.com ito.org.tr +itoncloud.com +itrackit.net itrade.fhtrust.com.tw +itsfogo.com +itsyourview.com +itunescards.co.za +iva.de +ivoo.certiris.be +iwcc.edu iweb.thebankersbank.com +iyummy.com j-union.com +jac.go.jp +jamestownregional.com +japanpost.jp jasaga.or.jp +jasmenterprises.com +jazanu.edu.sa +jeddah.zfp.com +jennisondryden.com +jerseymanagedhosting.com +jerusalem.muni.il +jetblue.com +jgh.com.sg +jhop.jp +jmlexaktsaw.com +jmlfastfit.com +jmlmagiccarpet.com +jmlscratchremover.com +jmlsmoothit.com +jmltwisteze.com +jmsapps.jmsmucker.net jnet.agsys.sompo-japan.co.jp +joagift.com job.disc.co.jp job.nikkei.co.jp jobmgr.disc.co.jp +jobs.1800contacts.com +jobs.carlsonhotelsasiapacific.com +jobs.cas.org +jobs.sourcefire.com +jockjam.nl +joeys.org +journie.net +jr.com.au +jrfh.tsacorporation.com +js.joomlaservices.ca +js.metalinq.com +jsps.go.jp +jta.jtafla.com +jtasoutheast.com +jumbomortgage.citimortgage.com +juneau.billeo.com +juronghealth.com.sg +k12.al.us +k12.ks.us +k12.mo.us +k12.mt.us +k12.nm.us +k12.pa.us +k12.sc.us +k12.wa.us +k12.wi.us +k9glowguardtv.com +kabeldeutschland.com +kabukiza-kabu.com kahosl.be +kalender.nakskov-gym.dk +kanagawa.jp +kanjam.com +kaosmos.jp +karierasro.cz +katlehotrust.co.za +kawacki.com.br +kb.mbms.com +kbacmportal.net +kcc.com +kcn.jp +kddi.ne.jp keas.com +keitaipost.jp +kemi.se +kenkou-design.com +keybankdeveloper.com +kfz-versicherung.faz.net +kgh.on.ca +kicho.shoko-shimane.or.jp +kidneycancerconnections.com kimberlyclark.myvurv.com +kindenonderwijsrotterdam.nl king-invest.net kingsdominion.com +kingsize-bottle.com +kingsmail3.kings-ely.cambs.sch.uk kingsroadmerch.com +kingston-college.ac.uk +kinsou.com +kintetsu-bs.co.jp +kintetsu-hoken.co.jp +kipp.org +kirenet.com +kit.ac.jp +kkcom.co.jp +klc-ondemand.com +klerx.biz +klikbca.com +klive.kellogg.edu +klz.org.uk +kme.ch +knox.nsw.edu.au +koffiecenter.be +koffiecenter.nl +kohlaborate.com +kontor.polytec.no +kordia.net.nz +korowa.vic.edu.au +kpchoicesolution.com +kpos.melsc.co.jp +kramesondemand.com +kredinor.no +krungsricashlink.com +krungsrifileserver.com +krungsrimobile.com +ks.gov +ktr.com +ku.dk +kuanywhere.ku.edu +kuk-networks.de +kulturgutschutz-deutschland.de kwiktrip.com +kwv.nl +kyfb.com +kymweb.tokoha-jc.ac.jp +kymweb.tokoha-u.ac.jp +labs.arubanetworks.com +ladyphoneshop.be +ladyphoneshop.nl +lakecomm.com +lambertconsulting.ch +lamda.org.uk +lancasterregional.com +lancer.webhosting.uk.com +laprevisionmallorquina.com +laptoporder.wab.edu +laptopshop.be +laptopshop.nl +larix.cevak.cz +las.perkinelmer.ca +las.perkinelmer.co.uk +las.perkinelmer.com +latax.lacity.org +lavprisfly.no +lbiclaim.com +lbschools.net +lc.leics.sch.uk +lcgs.tas.edu.au +lead.rotary.nl +leadintelligence.co.uk +leadrouter.com +leap.neustar.biz +learningseat.com +learningseat.com.au +learnsheffield.com +leben-hat-gewicht.de leerlingmail.niftarlake.nl +legacy.lcpharma.com +legacy.medietilsynet.no legalconnection.com +legalease.jmls.edu +lehighregional.com +lendingpit.com +lendingtreeautos.com +leopards-den.us +leshamwowoffre.com +level.mol.hu +lexor.lsp.at +lexsan.vestingonline.nl +lh.k12.ar.us +library.failteireland.ie +liemerscollege.nl +lifeaction.net +lifeio.com +lifenetems.org +liftmonitoring.nl +liftnfix.com lightstone.co.za +limewire.com +lincoln-obama.com +linkmanager.shalink.com +linkservicepro.com +linkzeal.com +lion.wild.net +lipa.ac.uk +lisa.lpshp.fi +listech.com +lit.edu +liu.se +livegrades.com +livingwithcll.com +livingwithlymphoma.com +ljbc.wa.edu.au +lkmc.com +lks.jackhenry.com +lmmis.com +lms.kansaigaidai.ac.jp +lnrmc.com +loanet.net +loans.citifinancial.ca +loans.citifinancial.com +loanstowomen.com +localret.cat +lodge.maishima.co.jp +logica.com +logicnet.pc-ware.org login-pos.eurobank.pl login-raty.eurobank.pl +login.aderantpm.com +login.bcferries.com +login.bild.de +login.clientaccess.net +login.danskerhverv.dk +login.dtl.eu +login.skwich.com +login.smmj.com +login.visionalist.com +logixs.com +logowanie.osemka.pl +london.edu +loro.ch +loterie.ch +loucoll.ac.uk +louisianaappliancerebate.com +lpb.dueri.net +lsu.edu +lucentis.com +lucky-pantry.net +luckybuy.com.tw +ludus.greve-gym.dk +ludus.grindsted-gym.dk +ludus.maribo-gym.dk +ludus.midtfyns-gym.dk +ludus.roskilde.dk +ludus.vuc-vsn.dk +ludusweb.akat.dk +ludusweb.frberg-gym.dk +ludusweb.fredericia-gym.dk +ludusweb.herninghfogvuc.dk +ludusweb.horsenshfogvuc.dk +ludusweb.middelfart-gym.dk +ludusweb.roende-gym.dk +ludusweb.toender-gym.dk +ludusweb.tornbjerg-gym.dk +ludusweb.vejle.dk +ludusweb.vucaarhus.dk +ludusweb.vucfyn.dk +ludusweb.vucha.dk +ludusweb.vuckolding.dk +ludusweb.vucroskilde.dk +ludusweb.vucstor.dk +ludusweb.vuctm.dk +ludusweb.vucvest.dk +lukeassoc.net +lumalamps.com +lungcancerconnections.com +lusitania-cs.pt +luxoft.com +lvmpd.com +lvs1.com lxr.com +m.aafes.com +m.stackmedia.net +maandag.nl maartenluther.calvijn.nl +maastrichtuniversity.nl +macaw.nl +macihotline.com +maconomy.com +madisonregionalmedicalcenter.com magelo.com magtek.com +mail.abz.ch +mail.accretivehealth.com +mail.achap.org +mail.acousticalspecialties.com +mail.activision.co.uk +mail.aeat.co.uk +mail.albany.k12.ny.us +mail.albil.com.tr +mail.alexdejong.com +mail.almajles.gov.ae +mail.amrita-parus.ru +mail.anbank.com +mail.aocterra.nl +mail.aps.k12.co.us +mail.arcelormittal.kz +mail.asapnet.nl +mail.asascience.com +mail.asmnet.com +mail.auscampus.net +mail.avalonhealthcare.com +mail.avanquestusa.com +mail.axemusic.com +mail.axens.net +mail.banquemisr.com +mail.baptisthealth.net +mail.bb.softbank.co.jp +mail.bbms.no +mail.bedeck.co.uk +mail.behr.ch +mail.beveric.com +mail.bfds.com +mail.bfw-mainz.de +mail.bigfishgames.com +mail.bilia.net +mail.borgmanschool.nl +mail.bornholmstrafikken.dk +mail.bpsd.mb.ca +mail.burohappold.com +mail.cafuamanagement.com +mail.cardinalhume.com +mail.cba.edu.sa +mail.ccina.ro +mail.ccsmgr.com +mail.cdh.com +mail.ceat.in mail.centrum.cz +mail.chargoon.com +mail.charlton.greenwich.sch.uk +mail.charltonschool.com +mail.chenderit.northants.sch.uk +mail.childrens.com +mail.citizensmn.com +mail.citp.nl +mail.cm-sobral.pt +mail.cmalliance.org +mail.cmpunjab.gov.pk +mail.colegiodorosario.pt +mail.collab.uni.edu +mail.comeup-soft.de +mail.compuworx.hu +mail.configura.com +mail.congreso.gob.hn +mail.connectivityit.com.au +mail.cookcountyil.gov +mail.coopdefrance.coop +mail.cpnpr.org +mail.crestron.com +mail.cssaz.org +mail.cta.org +mail.cvd.nl +mail.cws.biz +mail.datagroup.de +mail.dearborncountyhospital.org +mail.depend.se +mail.desancta.nl +mail.dioceseofgreensburg.org +mail.doe.k12.de.us +mail.dollardcollege.nl +mail.dqc-hosting.net +mail.drivetime.com +mail.du.ae +mail.e-farmcredit.com +mail.eatough.net +mail.ebsi.com +mail.edwards-ind.com +mail.emailonline.net.br +mail.energy.gov.ab.ca +mail.escrotrans.com +mail.exchpro.dk +mail.expertsystems.net mail.extranet.hp.com +mail.ezeit.co.uk +mail.fachisthers.com +mail.faf.cuni.cz +mail.federalequipment.com +mail.fhconsulting.com.br +mail.footballaustralia.com.au +mail.fozzy.ua +mail.g4s.no +mail.gallowglass.co.uk +mail.gama.com.tr +mail.geninf.com +mail.ggi-sa.com +mail.ggs.vic.edu.au +mail.globeteam.com +mail.gmrgroup.in +mail.govwentworth.k12.nh.us +mail.gpworldwide.com +mail.grafil.com +mail.groupegt.ca +mail.gruppocredem.it +mail.gruppoveritas.it mail.gtri.gatech.edu +mail.guideone.com +mail.guidewire.com +mail.guk.org.uk mail.gunnebo.com +mail.haderslev-gym.dk +mail.hallrender.com +mail.hamptoncollege.org.uk +mail.harbourmsp.com +mail.harvestnaperville.org +mail.havantacademy.co.uk +mail.hemofarm.com +mail.hgs.n-yorks.sch.uk +mail.hib.no +mail.hoegh.com mail.hoover.k12.al.us +mail.horizonsd.org +mail.houdijk.com +mail.hsd153.org +mail.hsventures.org mail.hzeeland.nl +mail.iac.com.tw +mail.icepronav.ro mail.idera.com +mail.iimc.kyoto-u.ac.jp mail.ilsole24ore.com +mail.indiska.se +mail.insanity-inc.org +mail.ipswichschool.net +mail.isnsolutions.co.uk +mail.itc.mb.ca +mail.itc.net.sa +mail.itcs.com.ge +mail.iteam.se +mail.itgsolutions.com +mail.itility.us +mail.itu.queensu.ca +mail.janaf.hr +mail.jardboranir.is +mail.jarfalla.se mail.jetblue.com +mail.jjuc.no +mail.jordanhospital.org +mail.jus.cz +mail.justinho.com +mail.kairos-it.com +mail.karlsson.se +mail.kces.de +mail.kerners.com +mail.kidneyfund.org +mail.kik.gov.tr +mail.kingscollegeguildford.com +mail.kit.ae +mail.kks.se +mail.klingenberg.com +mail.kolektor.com +mail.kubota-kma.com +mail.kvanum.com +mail.labranche.net +mail.lancercatering.com +mail.lfhi.com +mail.lochem.nl +mail.loreto.nsw.edu.au +mail.lpbs.org.uk +mail.mandersconsulting.com +mail.maristcollege.school.nz +mail.mariuspedersen.cz +mail.marnixcollege.nl +mail.mauser-cabs.at +mail.mbsds.com +mail.mbvm.org +mail.mciblues.net +mail.mcx.pl +mail.mcycd.gov.ae +mail.meau.com +mail.metito.com +mail.metrostav.cz +mail.metrotrains.com.au +mail.meyernetconsulting.com +mail.mf.dk +mail.micronav.co.uk +mail.midco.net +mail.middevon.gov.uk +mail.midental.org +mail.mihs.org +mail.milesplatts.co.uk +mail.minsterlaw.co.uk +mail.mlhslancers.com +mail.moe.gov.my +mail.momatos.com +mail.moorsidehigh.com +mail.mosa.gov.qa +mail.mrcc.aast.edu +mail.msa-oost.nl +mail.mulhouse.fr +mail.mvsd.ca +mail.mygcx.org +mail.myrtuemedical.org +mail.mysterynet.mb.ca +mail.namwater.com.na +mail.nap.gsic.titech.ac.jp +mail.navitasworld.com +mail.neway.co.il +mail.nicor.com +mail.nkadd.org +mail.nli.no +mail.normandale.edu +mail.norsar.no +mail.notionsolutions.com +mail.npaid.org +mail.nty.m86security.com +mail.oakley.kent.sch.uk +mail.ocusd.net mail.officebroker.com +mail.ofg.lv mail.oma.nl +mail.omanair.aero +mail.optimum.bm +mail.oshochem.com +mail.ouc.ac.cy +mail.paratek.com +mail.pdb.se +mail.petranso.com +mail.petrex.com.pe +mail.pewsey-vale.wilts.sch.uk +mail.pflag.org +mail.pgesco.com +mail.pinecreeksd.mb.ca +mail.plainconcepts.com +mail.plpsd.mb.ca +mail.pmc-sierra.com +mail.polycom.co.il +mail.primevision.net +mail.prsdmb.ca +mail.pukzh.ch +mail.qataridiar.com +mail.ravenstone.co.uk mail.rawlinscollege.org.uk +mail.rca.gov.om mail.rcsdk12.org +mail.red-red.ru +mail.reiv.com.au +mail.rewar.com.br +mail.rexel.nl +mail.ribblesdale.org +mail.richardhicks.com +mail.ridgian.co.uk +mail.rittal.be +mail.rkbs-de-vlinder.nl +mail.rmc.com.au +mail.ruudlighting.com +mail.sage.com +mail.saic-dc.com +mail.sarasamerica.com +mail.savininsurance.com +mail.sd206.org +mail.seekeducation.org +mail.serralves.pt +mail.sigtuna.se mail.silmu.fi mail.sinclair.edu mail.skmc.gov.ae +mail.skov.com +mail.skp.com +mail.sli.com +mail.slt.com.lk +mail.smart3group.com +mail.smiddy.co.uk +mail.softlinesolutions.com.au +mail.spotlight.co.za +mail.ssb.eu +mail.ssi.com.vn +mail.stadsmissionen.se +mail.stallionoilfield.com +mail.stccs.ca +mail.stcg.net +mail.steel-line.com.au +mail.storstockholm.brand.se +mail.stuwebportal.net +mail.styletronix.net +mail.sv-com.de +mail.svsd.ca +mail.swmed.edu +mail.tegola.ru +mail.texasent.com +mail.tgn.com mail.the-ascott.com +mail.thomassabo.com +mail.tommoz.co.nz +mail.townsquaremedia.com mail.tox-us.com +mail.transunion.com +mail.tri-center.k12.ia.us +mail.tridenttech.edu +mail.trinco.de +mail.tunisiana.com +mail.tvfr.com +mail.ufonegsm.net mail.ugs.com +mail.um.sopot.pl +mail.umfmpookies.info +mail.unitil.com mail.uottawa.ca +mail.usd450.net +mail.ustboniface.mb.ca +mail.uvh.nl +mail.vakko.com.tr +mail.valdichienti.net +mail.vasallen.se +mail.vejlehs.dk +mail.versicherungsforen.net +mail.vertigo.com +mail.vestconsult.dk +mail.vicore.se +mail.viettel.com.vn +mail.vmkfb.se +mail.wasbol.nl +mail.wasserstudios.com +mail.wbd.ru +mail.wcc.vic.edu.au +mail.wellsway.bathnes.sch.uk +mail.wienholding.at +mail.wipfli.com +mail.wsdmi.org mail.yvc.ac.il +mail.zoloto585.ru +mail01.nct.ac.uk +mail1.asfourcrystal.com +mail1.sog.ga.gov mail2.law.stetson.edu +mail2.lisluanda.com +mail2.marqnet.com +mail2.nonlinear.ca mail2.skanetrafiken.se +mail3.gibsondunn.com +mailer.kuehnel-web.org +mailfilter.bowdoin.edu mailhub1.cpsb.org mailhub2.cpsb.org +maillab.state.nm.us +mailsrv.angelantoni.it +mailsrv.artax.cz +mailstation.ch +maisoku.co.jp +mall123.com.tw +mallorca.co.uk +manabo.chukyo-u.ac.jp +manchester.ac.uk +mandat24.de +mangawebstore.com +manifest5.craig-is.com +manmail.nice.org.uk +manmaruyoyaku2.jp +manukinvest.com +mapmfc.com +marathonfoto.com +maringeneral.org +maritimetacticalsecurity.com +marketforceshopper.com +mars.micex.ru marshallsonline.com +maruetsu.net +marymount.qld.edu.au +massdor.com massport.com +matgenie.com +matmut.fr +matricis.com +matsuzakaya.co.jp +mattel.com +mayvillestate.edu +mbanking.ncrwebhost.mobi +mbdvd.com +mc0.multimap.com +mc4me.mccd.edu +mc4u-ext.mcdonalds.fr +mch.io +mchscares.org +mchvpn01.midcoasthealth.com +mcostaff.com +md-whistleblower.com +meadsd.net +meagpower.org +meathvec.ie +medewerker.jouwregardz.nl +media.filas.pl +media.martignetti.com +media.wschiro.edu +media3.ignitemedia.com mediabistro.com +mediacentershop.be +mediacentershop.nl +mediafire.com +mediamaxonline.com +mediazp.cz +medicalcannabismanager.com +medicalert.co.nz +mediclinic.co.za +meinkonto.orf-gis.at +meltitofftv.com +member.marmar.com.tw member.yong-online.com.tw +memberadviser.com +members.bsrservices.biz +memory-express.co.uk +memoryshop.be +memoryshop.nl +memphis.edu +merchantcart.net merchantonlineapp.com +mercyhousing.org +meriden.nsw.edu.au +merlin.ca merrickbank.com +messaging.macmahon.com.au metalinq.com +metrogr.org +metrostarsystems.com +mexicancupid.com +mf-web.d2c.ne.jp +mg.afimilk.co.il +mhhitws.cahwnet.gov +mhric.org +mhs1.3f.dk +mhsecure.dmcontact.com +michelsville.com +midfloridacardiology.com +midnightcharm.com +midwayautosupply.com +midwestregional.com miele.co.uk +migdataengine.cms.hhs.gov +mightyblasttv.com +mightyfixit.com +mightymendittv.com +mightythirstynow.com +mightythirstytv.com +mijnrijnijssel.nl +milkmandelivers.com +mill-hillcollege.nl +milldtrack.com miller.co.jp +milsoftssl.com +mindbusiness.org +mingorp.hr +misd.net mishlohim.co.il +misim.gov.il +mitserv.com +mizuho-int.com +mizuno.co.jp +mizuno.jp +mizunonetorder.com mizunoshop.net +mmint.org +mmrpatientview.com +mmrpersonalhealthrecords.com +mnscu.edu +mobil.alfru.net +mobile.animate-shop.jp +mobile.xjt.com +mobilebankcardservices.co.uk +mochiads.com mochibot.com mochigames.com mochimedia.com +mochimedia.net +mochipass.com +mod.yodobashi.com +moe.gov.ae +mof.go.jp +mohawkeriesharepoint.com +molinosmodernos.com +monash.edu +monbureau.sophiaconseil.fr +monreglement.fr +monserviceconciergerie.com +montebello.ridgevineyards.net +montetrader.com +montiplaza.nl +montroseaccess.org.au +mopera.net +morainevalley.edu +moralesfamily.net +moreheadstate.edu +morganschaffer.net +mosalira.nl +moshtix.com moss.esher.ac.uk +moss.ise.de +moundsparkacademy.org +mp01.canon.jp +mp3shop.be +mp3shop.nl +mrc-ws.mrceweb.com +mrclaurentides.qc.ca +mrmrshandycaddy.com +mrus.co.uk +msauth.mainstreet.fiserv.net +msbmyndigheten.se +mscw.vic.edu.au msexchange.lyon.edu +msg.gov.hu +msimmunology.com msishopper.net +msmail.mvnu.edu +msu.edu +msvpn.wusm.wustl.edu +mtimail.metal-technologies.com +mtnpeaktrail.com mtsexchange.mtsn.org.uk +mtvninvoices.com mudy.info +mule.co.kr +musc.edu +mustangps.org +mwd.incontech.co.uk +mwn.de +mws.acculynk.net +mx.ahmadiyya.de +mx.twfp.com +mxs.at +mxs.deff.ru +my-aime.net +my-hammer.at +my-hammer.de +my-office.ro my.bentley.edu my.berkeleycollege.edu +my.bluebunny.com +my.ccu.edu +my.colby-sawyer.edu +my.comprehensivesleep.com +my.cpscorp.com +my.dhlglobalmail.com my.dover.edu my.ecwid.com +my.hillsdale.edu +my.ju.edu +my.proactiv.com.ph +my.sandi.net +my.siematic.de +my.snhu.edu +my.tfl.gov.uk +my.unifiedbrands.net my.wcupa.edu +myabakus.net +myaero.org +myameda.com +myapps.skiffmed.com +mybenetech.com +mybethanyranchhome.org +mybfffishfood.com +mybffnow.com +mybigcommerce.com +mybuxtonwallet.com +mycardprinter.com +mychart.carilionclinic.org +myclinicallogic.com mycls.cls.ch +mycoldfire.com +mycollaboration.sug.com +mycundus.com +myemail.com.sg +myemail.sg +myesafedepositbox.com +myevolver.com +myexterran.com +myfauquierhealth.org +myfldocs.com +myfloodonline.com +myfluvaccine.com +mygetmighytighty.com +mygiftregistry.co.za +myhdwraparoundstv.com +myholtca.com +mymail.brueggers.com +mymail.warnerconnect.com +mymccc.mc3.edu +mymcso.com +mymdc.mo.gov +mymedicallocker.com +mymedicalrecordsmd.com +mynavi.jp +mynha.com +mynhatest.com myoffice.eu.goodyear.com myoffice.na.goodyear.com myparceldelivery.com +myparkbillstv.com +mypoint.com +myportal.vhschicago.com +myr00t.com +myriad.com +myriddexpulse.com +myservices.suffolk.ac.uk +myshakeweight.com +mysheridan.shcr.com +mystarcentral.com +mystatebillstv.com +mysteryworldnet.com +mystorage.cloudleverage.com +mystudentsquare.com +mysullystore.com +mytdriver.com +mytravelersflood.com +myvpn.mdavisinc.com +myvpn.ubc.ca +mywagnercat.com +mze.cz +n-fukushi.ac.jp na.ntrsupport.com +naehmaschinen-welt.de +nagasaki.lg.jp +namg1.ipsos.com +nan.kujalleq.gl +napster.com naramail.nara.gov +nas.gov.ua +nasadvd.com +nat.tribalddb.net +natchezcommunityhospital.com +national-preferred.com +nationalparkbillstv.com +nationalsecuritygroup.com +natlloyds-flood.com +navicast.jp +navysealsfund.org +nbch.com.ar +nbrc.org +nbst.org.uk +nccrimecontrol.org +ncm-c.org +ncmpay.com +ncmstl.com +ncst.com +ndcconsultants.co.uk +ndl.qc.ca +ndr.nu +nebraska.gov +nectarwallet.com +nelson.azdamiaan.be neospeech.com +net4.saga-ja.jp +netcafe.ft.dk +netdocuments.com +netleasing.ersteleasing.hu +netmail.nmh.org +netmailing.liderexpress.hr +netnfu.ne.jp +netorder.sogo-seibu.co.jp +netpractice.com.au +netstorm.no +nettkirken.no nettkontoret.kredinor.no +nettobank.ch +netview.nu +network.directrelief.org +networkrail.rapport-online.com +nevada.edu +never-was.com +new2u.us neways.com newaysonline.com +newcollege.ac.uk +newmarket.com +news.nzzexecutive.ch newvistalive.com +nexusos.net +nfipservices.com +ngenx.net +nhc.ac.uk +nhk-ep.com +nhs.uk +nhselearning.co.uk +nhtv.nl +nicovideo.jp +niftarlake.nl +nightingaleconant.co.uk +nihon-u.ac.jp +nikkei.co.jp +niktec.com +nimbus.peru.edu +nintex.com +njreflood.com +nmsmp.alsok.co.jp +noc.touchnoc.com nochex.com +nomade.etu.univ-nantes.fr noridian.totalonboarding.com +nortcoll.ac.uk +norwich-union.com +notebookbuffer.com +notes.parliament.qld.gov.au noticiastelemicro.com +notleyhigh.com +nousinfo.com +novabase.pt +novocorreio.ultra.com.br +nowa.ntelos.com nr.edu +nraesafe.com +nrwbank.com +ns002.toshiba-sol.co.jp +ns11mm.sept11mm.org +nsw.gov.au +nswmentors.com +ntdira.com +ntstaxonline.com +ntx.at +nubod.com +nuii.com +nuskin.com +nutropin.com +nuungolf.com nuwaveoven.com +nuwaveovennow.com +nwhc.ac.uk +nyvpn.conifersecurities.com +nzmail.deloitte.co.nz +nzz.ch +oasen.nl +oasiswebvpn.net +oasystems.co.nz +obdp.org +obsmail.com +ocean.ac-toulouse.fr +odlmarkets.com +odlsecurities.com +offertool.galenos.ch +office.mls.lib.il.us +office.occ.on.ca +office.rooscs.nl +office.tatemono.com +office.wacom.de +officemd.net +ogdenbancshares.com +oha.com +oit.ac.jp +olchs.org +ollusa.edu +olmsted.mn.us +oma.nl +omnidualsaw.ca +on-linepojisteni.cz +on-nets.com +one-info.net +onecoin.tayoreru.com +onee.se +onefmcremote.com +onesies.com.au +onestop.gsi.go.jp +oneuso.org +onforce.com +online-processingcenter.com +online.alpha-web.jp +online.alphabank.com.cy +online.americanbus.com +online.clalcredit.co.il online.eurobank.pl +online.julbo-rx.com +online.mycontoso.de +online.shamir.es +online.shamir.fr +online.shamirlens.co.uk +online.steens.dk +onlinebanking.bankofalbuquerque.com +onlinebanking.bankofarizona.com +onlinebanking.bankofarkansas.com +onlinebanking.bankofkansascity.com +onlinebanking.bankofoklahoma.com +onlinebanking.bankoftexas.com +onlinebanking.csbt.com +onlinebill.fl1.li +onlinebt.de +onlineclient.nyscorporate.com +onlinelibrary.wiley.com +onlineticket.jp +onmail.dk +onmyo.com +ontarioinsco.com +ontimeweb.itfocus.co.nz onyxinv.com +opel-leadengine.de +openhire.com +operations.nvmp.nl +oppassessment.eu.com +oppenheimerfunds.com +oppy.com +opsource.net +oralchirurgie-ehingen.de +orchardworld.co.uk +ordemenfermeiros.pt +order.fujifilm.com +order.pvpl.com +orderdiscoabs.com +ordermonster1200.com +orderoxyclinical.com +orderpacecoach.com +orderpopmemories.com +orders.airculinaireinternational.com +orders.caterlinkworldwide.com +ordina.nl +oreckvac.ca orix-sumai.jp +orixliving.jp +osaki-eweb.com +oscar.gov.au +oss.schuster-gmbh.de +osuvpn.okstate.edu osvinc.com +otodok.com otpbank.hu +otpcafeteria.hu +otppenztarak.hu +otsuka-shokai.co.jp +outdoorchristmaslighting.co.uk +outlook.belam.lv +outlook.bolthouse.com +outlook.bosleyconsulting.com +outlook.cgw.com.au +outlook.delichtenvoorde.nl +outlook.effix.be +outlook.fritzhansen.net +outlook.haarlem.nl +outlook.hfwu.de +outlook.hillcrest.vic.edu.au +outlook.it-service-schwadorf.de +outlook.kennedykrieger.org +outlook.probil.com.tr +outlook.t-online.de +outlook.wcsr.com +outlook.y-tech.co.il +outlook1.wilshire.com +outlookonline.nl +outlookpremium.com +outside.cmworks.com +outspark.com +overblick.se +overthedoor.com +ovo-zaanstad.nl +owa.aas.ru +owa.acbl.net +owa.addon.de +owa.afridata.net +owa.asp.ruf.ch +owa.belnet.de +owa.bushbros.com +owa.byui.edu +owa.cancom.de +owa.caritas.at +owa.cimt-ag.de +owa.cms-hs.com +owa.consilium-uk.com +owa.consortioservices.com +owa.dannenbaum.com +owa.db-international.de +owa.dbr.com +owa.dish.com owa.dist113.org +owa.dunnhumby.com +owa.dyrbergkern.com +owa.edipresse.ch +owa.electric-house.com +owa.eneco.eu +owa.esn.at +owa.eucnordvest.dk +owa.exe.it +owa.executrain.com +owa.fh-jena.de +owa.gfe.com +owa.gft.com +owa.gtlaw.com.au +owa.hcuge.ch +owa.helsingborg.se +owa.iadt.ie +owa.ic3.gov +owa.isl-automotive.com +owa.itsindy.com +owa.iwco.com +owa.jabirumetals.com.au +owa.jacksonkelly.com +owa.jetstar.com owa.kajak.fi owa.kan.se +owa.kromannreumert.com +owa.kwfdn.org +owa.lamy-lexel.com +owa.lfb.fr +owa.lrgs.org.uk +owa.mainroads.wa.gov.au +owa.matrix.co.il +owa.mdx.ac.uk +owa.midroc.se +owa.namfg.com +owa.narsaq.gl +owa.nd.edu.au owa.nordakademie.de +owa.orangecoastcollege.net +owa.oranim.ac.il +owa.otani.ac.jp +owa.ouc.com +owa.palama.gov.za +owa.parlement.nl +owa.peak-it.nl +owa.perceptis.com +owa.pinklotusbreastcenter.com +owa.prgparking.com +owa.prinbox.com +owa.priorsfieldschool.com +owa.qaqortoq.gl +owa.qortex.com +owa.rbs1.com +owa.rcha.net +owa.rochesterathleticclub.com +owa.roeverbroenner.de +owa.rrpub.com +owa.rtc-mailing.de +owa.rtix.com +owa.sirc.co.il +owa.sktf.se +owa.slagelse.dk +owa.smh.ca +owa.spservicing.com +owa.st-benetbiscop.org.uk owa.tecnicasreunidas.es +owa.terremark.com +owa.uni.lu +owa.uniten.edu.my +owa.vetmeduni.ac.at +owa.wdm-ia.com +owa.westoncolorado.com +owa.windmobile.ca +owa.witstor.de +owa2.earthfare.com owa2k3.bhw.de +owamail.calu.edu +owenscorning.com +oztravel.com +p2pia.com +pagos.uveritas.ac.cr +pagport.jp +painel.mtv.com.br +painel.onlinesol.com.br +pajamajeans.com +pamperedchefconsultantcardapplication.com +pandorahost.net +paperlessemployee.com parfumdreams.de +parkbillstv.com +parkcity.org +parking.bristolairport.co.uk +parrishmed.com +partille.se partner.buzzcity.com +partnerhosted.com +partners.carnegieam.dk partners.conocophillipsalaska.com +partners.org +partners.sitesense-oo.com +partners.smartname.com +pascoregionalmc.com pastel.co.za +pastelincheck.co.za +pasts.lattelecom.lv +pasts.riga.lv +pathfinder.woolworths.co.za +pathrocket.com +patsiprod.upr.edu +pay.cimbal.com +paybacktime.com +payment.soulultimatenation.com.tw +payments.abm.com +paymyassociation.com +pbhrmc.com +pc-one.net +pc-soft.info +pcpobr.nl +pct.edu +pdashop.be +pdashop.nl +pdgm.com +peacecorps.gov +peaceriverregional.com +peckham.org +pedirefills.ca +pedvd.com +peelpolice.ca +penncommons.com +pent-valley.kent.sch.uk +perfectbrownie.tv perfectmoney.com +perimeter.eiu.edu +perkinelmergenetics.com +perse.co.uk +personalausweisportal.de +perspectica.telmetrics.com +perspektive-it.de +pest.griffsoft.hu +pestfreetv.com +petfinder.com +pethairpicksytv.com +petshed.com +pfizerpro.jp +pgcwl.com +pgfl.org.uk +pgi105.pacifica.edu +ph.book.airbypleasant.com +phfewic.org +photomask.com +phwebvpn.org +phwebvpn2.org +physiciansregional.net picnik.com +pictureitpostage.com +pieseautoaccesorii.com +pim.hypoport.de pimkie.de pimkie.es pimkie.fr pimkie.it pineconeresearch.com +piratenpartei-nrw.de +pittsborotransportationplan.com +piwik.healthplan.com +pixgate.fokus.fraunhofer.de +pizzutitrac.com +pl-fax.com +pl.wikidot.com +planapps.org planet-tachyon.com +plasmacool.ca +plasmacool.com +plasmaquebec.com +platform-one.suffolkone.org +playlsi.com playneverwinter.com +playnextlevel.com +plusuk01.smartsgroup.com +pluto.fipotex.com +plweb.evenflo.com +pmat3.com +pmptech.biz +pobal.ie pocket.matsui.co.jp +pocketchair.com +pocketu.jp +pocklingtonschool.com +poczta.adamed.com +poczta.barlinek.com.pl +poczta.km-net.pl +poczta.umwm.pl +pocztam.pap.pl +pods.thinkorswim.com pokervt.com +polautomatisering.nl +pooledmoneyinvestmentboard.com poolzconnect.singaporepools.com.sg +poplarbluffregional.com popularglasses.com portaal.nh1816.nl +portaal.steenbok.com +portaal.veenendaal.nl +portail.bienetrealacarte.com +portail.croix-rouge.fr +portail.ensai.fr +portail.mairie-blagnac.fr portail.mont-notre-dame.qc.ca +portal-dynamics.com +portal.aasa.ac.jp +portal.algoe-it.nl +portal.aquon.nl +portal.asms.sa.edu.au +portal.bisd.com +portal.brescia.co.za +portal.campverde.az.gov +portal.capital-tour.ru +portal.cmocpa.com +portal.coastalrange.ca +portal.collaborative.com +portal.colonialsd.org +portal.core.gb.com +portal.covenantsolutions.org +portal.crh-corp.net +portal.crtx.com portal.eduweb.vic.gov.au portal.eiffel.nl +portal.estridge.net +portal.flaglerschools.com +portal.gov.cz +portal.gses.l-3com.com +portal.halcyonit.com +portal.hallco.org +portal.hc-vlc.nl +portal.heel.com portal.hello.ch +portal.hpisd.org +portal.hud.de +portal.human-skills.com +portal.hutto.txed.net +portal.ijsselcollege.nl +portal.klinikum-niederlausitz.de portal.klz.org.uk portal.langara.bc.ca +portal.marchesschool.net portal.mariestad.se +portal.maryhare.org.uk +portal.mez.nl +portal.mhyork.org +portal.myabc.no +portal.netcuras.com +portal.nordavia.ru +portal.orlandoheart.com +portal.pascack.k12.nj.us portal.peckham.org portal.perse.co.uk +portal.riskrighter.com +portal.s1.com +portal.sangart.com +portal.sierrasystems.com +portal.sigmax.nl +portal.skbo.nl +portal.skitsap.wednet.edu +portal.stjansdal.nl +portal.svms.net +portal.tape-llc.com +portal.telefonbuchverlag-sutter.de portal.tku.ac.jp +portal.toreboda.se +portal.usgjuristen.nl +portal.yourithost.com +portal.zeidlerpartnership.com +portal2.znb.nl +portale.ervet.it +portam.jp +porthuronstclairsharepoint.com post.norwegian.no +post.simple.ru +post.socialrdg.dk +post.stortinget.no +post.time.kommune.no +post.wastecare.co.uk +posta.copma.it posta.dsi.gov.tr +posta.kolektor.si +posta.nuk.uni-lj.si +posti.hippos.fi +posti.pirko.fi +postkodlotteriet.se +postur.borgun.is +postur.hve.is powerschool.ccsdut.net +powerschool.com powerschool.lawrence.k12.ma.us +powershiftfastcash.com +powertoolshop.be +powertoolshop.nl +pph.peres-center.org +practika.ru +pragma-group.biz +precash.com +preferredhomecare.com +preishelden.de +premierinc.com +premiodestaque.com +primehhs.com +princeportal.com +princeton.edu +printershop.be +printershop.nl +private.stelizabeth.com +pro.mothers-auction.net +procapita.gfbs.se +procoder.aviacode.com +proexam.org profil.centrum.cz +profilecenter.ru +profitbuilderenroll.com +profitweb.afasgroep.nl projectinsight.cbre.com +projectserve.disti.com +promail.ru +proposalsystem.seic.com +provident.com +providentfunding.com +provider.dchpkids.com providers.tufts-health.com +prox-c.com ps.dvusd.org ps.glenbard.org ps.liberty.k12.mo.us +ps.meridianschools.org +psiwebmail.com psyquel.com +ptcube.de +ptstaxonline.com +ptw.qp.com.qa +public.myfwc.com +pufferfish.de +pulmozyme.com +puripo.jp +puser.centrum.sk pushentertainment.com +pvhs.org q8car.com +qbranch.se +qeliz.ac.uk +qenos.com +qenterprises.com +qeportal.co.uk +qewebmail.co.uk qisweb2-verw.uni-hohenheim.de +qmgs.walsall.sch.uk +qqweb.jp +qsquirrel.com +qt.sat.gob.mx +quickreg.ci.irvine.ca.us +quintogest.com +quon.asia quotien.onlinebank.com +qvc.jp +qvcliquidation.com +qwazy.net +r1.techpuls.hr +r4.musicstationonline.com +ra.budco.com +ra.hntb.com +ra.libertymgt.com +ra.pega.com +raasnet.com +raciborz.edu.pl +rahorizons.com +raildata.orr.gov.uk rainforest-alliance.org rakuraku-market.com +rakuten.co.jp +rampvpn.tessituranetwork.com +raona.com +raptiva.com +rasowa.ramairservices.com rbc.bridgetrack.com +rbsiseast.org.uk rc.kotoha.co.jp +rcssalem.com +rcxasa.watson.ibm.com +rd.rlcdn.com +rds.ilc.gov.au +reach-clp-helpdesk.de +reaktor.no +realsuperpass1.smartsubs.net +redbullcontentpool.com +redhawk.golfcart.com +region-view.com +register.daum.net +register.lynctrial.com +registration.gov.gg +regmurcia.com +rehabcare.com +rejuvenateautocanada.com +relaxtrade.com +releaseyourpotential.net +rem.clow.net.nz +remedy.justice.gov.za +remote.4tw.dk +remote.aa.net.nz +remote.aacl.com.au +remote.ap.asm.com +remote.bdmtexas.com +remote.capita.co.uk +remote.cftc.gov +remote.clickconsult.com +remote.clovertowing.com remote.cushingco.com +remote.daugherty.com +remote.dumasmining.com +remote.fhn.org +remote.fnh.no +remote.frog.se +remote.frontier-si.com +remote.fumcallen.org +remote.gndlaw.com +remote.graduateleverage.com +remote.hbcs.org +remote.hillvue.com +remote.hrjconsulting.com +remote.hselaw.com +remote.ilergroup.com +remote.inshuckch.com +remote.ipmotion.de +remote.keyorganics.net +remote.maybourne.com +remote.neighborimpact.org +remote.nexant.com +remote.nlogic.com +remote.nmcfd.com +remote.noyes-hospital.org +remote.opensolutions.com +remote.penton.com +remote.progpl.com +remote.queens.org +remote.reefdiver.de +remote.renouf-family.com +remote.rttg.co.uk +remote.sb-groep.nl +remote.senhoc.com +remote.sgsep.com.au +remote.shetland.gov.uk +remote.slalomdemo.com +remote.slfa.com +remote.starofhope.us +remote.sticares.org +remote.thechurchofgod.org +remote.unicorr.com +remote.unitedspinal.org +remote.utsystem.edu +remoteaccess.skaggs.net +remoteaccess.starkstate.net +remotecall.jp +remoteoutlook.webjet.com.au +remoteportal.nasonhospital.com +remotingcoders.com +rencap.com +reporthawk.com +reporting.accesshma.com +reporting.accessrga.com +reportingportal.com reprofinance.com +republiconline.republictt.com +resalesmart.com +resealandsave.com +research.majesticsteel.com +researchapoptosis.com +researcharchive.wintec.ac.nz +researchherpathways.com +researchvegf.com +reservations.encorelasvegas.com +reservations.wynnlasvegas.com +resource-ctr.com +ressu.ficora.fi restaurantwedding.jp +resurskontoret.se +retailer.gfkms.com +retention.nextpage.com +retina.org +revlonrunwalk.com +revonix.com +rewardgateway.co.uk +rewardplus.co.uk +rezitech.net +rgdata.com.ua +rgiexchange.net +rgiimail.com +rhwebmail.com +ricoh-usa.com +riddexcanada.com +riddexpulse.com +riddexpulsenow.com +rightathomehomestay.com +riksgalden.se +rileyhosp.com rio.edu +risesupport.com +risk-buster.com +rismail.rafflesis.com +ristken.com +rituxan.com +riverartsfestmemphis.org +riveroakshosp.com +riverviewregional.com +rk.sjdc.co.jp rlcdn.com +rlh-gmuend.at +rma.sensus.com rmg.i-grasp.com +rms.unlv.edu +rochester.edu +rockettesdvd.com +rocmondriaan.net +rodekruis.nl +rodino.ro +rome.faber.co.uk +rosalie.ciad.ch rosevalleyindia.com +rosey.ch +ross.fs.fed.us rotaban.ru +routercenter.be +routercenter.nl rozodoniy.com rpv.fbn.ca rr.com +rreporter.nl +rs.gov.br +rsasurveys.co.uk +rsg-nc.rsgsystems.com +rsmn.reschini.com +rsmoss.rsmedical.com +rsracing.com +rsu.lv +rt.rtoaster.jp +rtstr.netbk.co.jp +rumail.rockefeller.edu run.auone.jp runnet.jp +runraceresults.com +rush.edu +ryujus-netsuper.com +s-immobilien.de s-yoyaku.city.sagamihara.kanagawa.jp s-yoyaku.city.urayasu.chiba.jp +s.ixiaa.com +s.ncp.imrworldwide.com +s1defense.com +saab-leadengine.de +saas.dynamate.eu +saas.it-telcom.nl +saas.nines.nl safelinkwireless.com +safestream.com +safetekusa.com sail.iwcc.edu +saintvincenthealth.com +saksincorporated.com +salaris.acera-online.nl +sales.skipark.com +salvador-dali.org +sam.lst.se +sam.sesameworkshop.org samba.huji.ac.il samsami2u.wordpress.com +samsclub.com samstores.com +samworthenterpriseacademy.org +sandalsuperstore.com +sandingglovestv.com +sandiskdealpal.com +sandwellschools.org.uk +sanpasqualunion.net +santa-clarita.com sap.kenexa.com saratogaschools.org +sas.com +satalyst.com +satis.tcdd.gov.tr +savpn.sysadm.suny.edu +sbdc.uga.edu +sbiapps.sitesell.com +sbobet.com +sbr.shooti.jp +sbsgroupusa.com +sby.co.il +scad.edu +scarboroughcollege.co.uk +scartreatmentnow.com +scb.flysas.com +scca.com +sch.uk +schedulemyshot.vaxamerica.com +schicktech.com +schoolwebpages.com +schulstatistik-thueringen.de +scientia.sk scottsliquidgold.com +scu-vpn.scu.edu.au +sd68.bc.ca +sdt.tntpost.nl +sdx-ag.de +seanet.sbexp.com search.boox.jp search.petfinder.com +secep.net +secondmarket.com +secservizi.it +sectorzero.pt +secure-access.cne-siar.gov.uk +secure.3creditreportsinstantly.com +secure.aceinsurance.com.au +secure.anzmoneymanager.com +secure.asce.org +secure.astepsdiv.com +secure.atriacom.com +secure.atv.com +secure.bybox.com secure.cambrianc.on.ca +secure.citizenlink.com +secure.click2callu.com secure.court.gov.il +secure.cst.org +secure.cygnusresources.com secure.discountadvances.com secure.earthclassmail.com +secure.eastbayfellowship.org +secure.elcofduval.org +secure.frenell.com +secure.globalstar.com +secure.gway.org +secure.igliving.com +secure.keuzenkamp.eu +secure.makinglifebetter.com +secure.mbsbillingsolutions.com +secure.mcpa4you.org +secure.mdrc.org +secure.mededcoventry.com secure.merchantcart.net +secure.molapo.co.za +secure.motorcycle.com +secure.mrcad.co.uk +secure.my3creditreportsinstantly.com +secure.mybybox.com secure.mycashnow.com +secure.nicoga.jp secure.nochex.com +secure.nufactor.com +secure.passport.mnginteractive.com +secure.payconnect.net secure.paydaymax.com +secure.personalwatercraft.com +secure.pompvanhetvolk.be +secure.reboot.ca +secure.rfi-walmart.com +secure.rhodesfs.com +secure.sandhillsregional.com +secure.sbmonline.com +secure.sjpharmacal.com +secure.snowmobile.com +secure.softwarepursuits.com +secure.stuartelvish.com +secure.tempus-rex.com +secure.vivemejor.com +secure.www.contracostatimes.com +secure.www.dailybreeze.com +secure.www.dailybulletin.com +secure.www.dailynews.com secure.www.denverpost.com +secure.www.la.com secure.www.mercurynews.com +secure.www.montereyherald.com +secure.www.pasadenastarnews.com +secure.www.presstelegram.com +secure.www.redlandsdailyfacts.com +secure.www.santacruzsentinel.com +secure.www.sbsun.com +secure.www.sgvtribune.com +secure.www.siliconvalley.com secure.www.twincities.com +secure.www.whittierdailynews.com +secure.wzhi.net +secure.your3creditreportsinstantly.com secure.zeelandnet.nl secure.zoominfo.com secureaccess.cacu.com +secureconnect.shawgrp.com +secureconnect.uis.edu +secured.erdbeerli.ch +securedatacollection.com securedlogons.humanadental.com +securefeed.co.uk +securepayment.newapproachmarketing.co.za +securetrack.rebatetrack.com +securevtp.com +securible.com +securities.com +sedgemoor.gov.uk +seearprewards.com +sefinenlinea.jalisco.gob.mx seha.ae +seibu.jp +seibubus-gt.jp +seisentopbin.com +seizetheday.com selfcare.rr.com +selfservice.smartree.com +selfservice.vsource.com +semanticweb.com +sen-farefinder.com +send.group.com +senvpnen.senate.gov +sercel.com +serifrebates.com +serv.webhostnr1.com +server.alsautomotive.com +serveraccess.practice-it.co.uk +service.deutschepost.de +service.hkn.de +service.itatbusiness.de +servicebund.com +servicedesk.geoeye.com +servicelinkproonline.com +servicemagic.com +serviceportal.telekom.at services.bag-mail.de +services.canadoil.com +services.esc-pau.fr +services.gyc.ac.uk +servicingconnect.com +servizi.allianzbank.it +servizi.atime.it +sesameconnection.org +setnlift.com +sf-vpn01.embark.com +sfoon.com +sfsj.se +sftsrc.com +sgw.ngxo.trinity.ebay.co.uk +sgw.ngxo.trinity.ebay.com +sgw.ngxo.trinity.ebay.it shakeweight.com +shakeweight4men.com +shakeweighttimer.com +shaklee.com +shamir.pt +shamwowca.com +share.epeerless.com +sharepoint.centurionmp.com +sharepoint.convergys.com +sharepoint.exiis.net +sharepoint.rosasconstrutores.pt +sharepoint.smartit.ch +sharepoint.xformity.com +sharepointgermany.cinram.com +sharepointgurus.net +sharepointiichiprojects.iichi.org +sharkweekdvd.com +sharpmail.sharpamericas.com +shavematetv.com +shavershop.be +shavershop.nl +sheabuild.com shiki.gr.jp +shiki.jp +shinsei.kyoukaikenpo.or.jp +shochiku-kabu.com +shop.benningtonmuseum.org +shop.fatboy.co.uk +shop.fatboy.com +shop.fatboy.de +shop.fatboy.fr +shop.fatboy.nl +shop.foxxfoe.com +shop.ftv.com.tw +shop.kgcheck.com.tw +shop.lindora.com +shop.rcn.com +shop.whatsinyourcity.net +shop123.com.tw +shop4.vcomshop.com +shopbase.finetunes.net +shopnchekshopper.ca +shopnchekshopper.com +shopoutdoornebraska.ne.gov +shoptotalpillow.com +shortinsights.com +shortside.com showcase-tv.com +shr.ro +shsmail.swedish.org shsremote.solarishs.org +shutdown.cfs.iupui.edu sierranevada.com +sigmakudos.com +signup.cloudprofile.com +sildelaget.no +silkcloudservices.microfocus.com +silkroad.com +silverjoes.com +simonizfixittv.com +simonlyshop.nl +simplewebmanagement.com +sims.tanfieldschool.co.uk +sinergiefinancial.net +singtel.com +sip.ttcg.net +siriusxmrewards.com +sis.ais-r.edu.sa sis.ggusd.us +sis.gpc.edu sisense.com +sistema.giannetti.com.br +sjomannskirken.no +sjpremote.com +sjsualumninetwork.com +skills.luovi.fi +skivehs.dk +sklep.vitapertutti.com +skmm.gov.my +skogforsk.se +skyliner.ec.keisei.co.jp +slg.schools.nottscc.gov.uk +slinkprovider.com +slowemdownbowl.com smart.otpbanka.hr +smartdrv.com +smartmoptv.com +smartphoneshop.be +smartphoneshop.nl +smes.org +smoothawaysite.com +smtp.ikic.co.jp +smtp.ngatawa.school.nz +snuggie.ca +snuggiefordogs.com +snuggieforkids.com +snuggietv.com +snuggievarsity.com sobexinvest.com socketstore.co.uk +socrambanque.fr +sodexhovpn.com +sodexovpn.com +softsupercoolertv.com +sog.nl +sogo-gogo.com +sols.org +solutionsbiz.com +solvethatdebt.com +son.stellatravel.com.au +sonicwall.com +sonymusicd2c.com +soquij.qc.ca soundvision.com +southernwine.com +southlakecarroll.edu +sp.cti-w.com +sp.edu.sg +sp.hanoverva.gov +sp.se +sp1.zvw.uni-goettingen.de spalding.edu +sparinvest.dk +sparkasse.de +sparrapid.se +speedy2k3.viglen.co.uk +speedyspark.com +spilldaddy.com +spkgroup.com +spkhome.net +spknet.com +splogin.se +sports-nakama.com +sportundshop.de +spragueenergy.com +springer-sbm.com +springhillregional.net +springisd.org +sprint.com +sprint.net sprintrebates.com +sprooms.swiss.com +spss-asp.com squareup.com +sr-owa.walter.net.au +sra.com +src.sk.ca +srigold.com +srmcfl.com ss3.e-state.co.jp +ssl-vpn.multifa.com +ssl-vpn1.aau.dk ssl.arcsoft.com +ssl.clinique-pasteur.com +ssl.coig.pl +ssl.cpmc.columbia.edu +ssl.ksd.ch +ssl.levinglobal.com +ssl.siih5962.fr +ssl.walsworth.com +ssl.weniger-verbrauch.de +ssl.whoajack.com +ssl2.americanprogressaction.org +ssl3.costar.com +sslclient.runshaw.ac.uk +sslgw.emis-electrics.de +sslvpn.accent.nl +sslvpn.bentonpud.org sslvpn.broadcom.com +sslvpn.curtin.edu.au +sslvpn.emerson.com +sslvpn.mid.org +sslvpn.nyp.org +sslvpn.roedl.pl sslvpn.savannah.chatham.k12.ga.us +sslvpn.thrivent.com +sso.agglo-royan.fr +sso.collegeboard.com +sso.utilityservice.com +st.ig.com.au +stadspoort.asp4all.nl +staff.ftc.health-partners.org +staff1.f-i-f.co.uk staffmail.brighton.ac.uk +staffmail.ja.net +staffordschools.org staffportal.bne.catholic.edu.au +stage.sparksecure.com stapleseasyrebates.com +stapleseasyway.com +start.spro.no startnextweek.com.au +startrack.gfkrt.com startrekonline.com +starwoodresidenceclub.com +starwoodvacationownership.com +state.fl.us +state.ks.us +state.wy.us +static.brandsclub.com.br +static.collegeprowler.com +static.gebrauchtwagen.de +static.limewirestore.com +statistik.msb.se +statlerhotel.cornell.edu +stc.ac.uk +stcloudregional.com ste-exch1.nhc.ac.uk +steeleye.com +steelhorsecomputers.com +stemcellskintherapytv.com +stetson.edu +stichtingwillemvanoranje.nl +stihl.de +stilltracking.com +stlawrencecollege.ca +stleonards.vic.edu.au +stlogic.com +stofzuigerstore.be +stofzuigerstore.nl +stone-ware.com +stoneware.cloverdale.k12.in.us +store.homeheartbeat.com +store.sun.com +store.toto-dream.com stores.channeladvisor.com +stories.citi.com +stormgenius.com +stpats.vic.edu.au +straitservice.com +strapperfect.com +strapperfect.tv +stratfordhigh.org.uk strideeveryday.com +strijkijzerstore.be +strijkijzerstore.nl +stringfellowmemorial.com studentdata.warwick.ac.uk +studentinfo.trinityhigh.com +studmagic.com studynet.dem.hva.nl +stylio.jp subjectivemetrics.com +sug-spirit.net +suitespot.mynextsuite.com +summitmedicalcenter.net +summitshack.com +summitstrategies.com +sundahus.se +sunriseearthdvd.com +superhub.hk +support.ataretail.com +support.bsc-ideas.com +support.cryptas.com +support.dridefault.com +support.goshen.bluestarpro.com +support.landsteinar.nl +support.mcigb.com +support.orgmanager.de +support.rosebudtech.com +supportlink.net survey5.spss-asp.com surveys.itsyourview.com suvana.com +svc.aegmis.de svelvik.skole.d-ikt.no +sw.nvusd.k12.ca.us +sw.quirinale.it +sw4men.com +sw4menespanol.com +swartdev.net +sweden.icw.se +sweettracking.com +swiss-rx-login.ch +switch2verizonfios.com +swivelwonderhanger.com +swuhealth.org +sykehuspartner.no syllabus.doshisha.ac.jp +symetra.com +synergy.nma-ict.nl +synergy.workarea.nl sys.ins-uni.co.jp +syspro.com +system.cord.osaka-geidai.ac.jp +systemb2b.com +t-mobile.nl +taerobicsdvds.com +tahomasd.us +tai.com.tr +tamiflu.com +tandenborstelstore.be +tandenborstelstore.nl taocan777.com +tapapp.com +tarceva.com +tas-japan.com +tasgroup.cl +tasmanliquor.co.nz +tasmantest.sdc-online.net +tastiwave.ca +tastiwave.com +tastiwavepan.com +tatertornadotv.com +taxport.convey.com +taxslayer.com +taxslayerbooks.com +taxslayerpro.com +taxstatusnow.com +taxtes.com +tc4men.com +tco.cfbt-inspections.com +tcspost.thomassen.com +tdj.ac.jp +teachingpersonnel.com +teambrandon.ca +tecdlr.com +technology-security-associates.com +technologyandstrategy.com +techscaler.com +tecplot.com teetimesusa.com +teetroit.com +telaris.wlu.ca +telefoonshop.nl +teleplan.no +telifhaklari.gov.tr +tellabs.com +temptationscanada.com terrabanking.romexterra.ro +testdrivereward.com testdriveunlimited2.com +tewkesburyschool.org +tge.cl tgn.co.jp tgw.com +the-house.com +the-k-factor.com +theadspot.tv +thealabamacollegesnuggie.com +thealbany.biz +thebarkoff.com +thecarletonsheetscoachnetwork.com +thecharacter-classics.com thecinema.in +thecomfortfurnace.com thediamondstore.co.uk +thedownsschool.org +theezstringer.com +thefushigi.com +theglobalfund.org +thegreenspider.com +thehandyvalet.com +thehexlightsite.com +theknowledgeexchange.info +themicrowallet.com +themightysuperstore.com +theorphan.com +thepalmwallet.com +thepancakepuff.com +therockradionetwork.secure.myhosting.net +thesecuraoven.com +theshedd.org +thesource.freemanco.com +thesuperjuicer.com +thetotalcore.com +thewire.wynnresorts.com thor.movistar.com.co +threepalms.com +threescompany.com +thueringen.de +thuis.ckxs.com +thw.de thymes.com +thymesnet.com +ticket-web-shochiku.com +ticket.fast.no +ticketfly.com +tickets.carowinds.com +tickets.dorneypark.com +tickets.spoorwegmuseum.nl +tickets.valleyfair.com +tickets.worldsoffun.com +tidytweet.com +tieup.demae-can.com +tightboards.com +tigmail.tigdistributing.com +time.staffme.net +timken.com +timtrac.ca +tirerebatestatus.com +tis.co.jp +tis.jp +tixforkids.org +tjmaxx.com +tku.ac.jp tlfw01.fhsg.ch +tmgowa.pointsharp.net +tmsanalytics.com +tmsnervecenter.com +tnkase.com +tohmatsu.co.jp +toho-u.ac.jp +tokem.fi +token.vpn.mim.dk +tokyo.jp +toltestworld.com +tomategigantetv.com +tomwatsondvdtv.com +tondeusestore.be +tondeusestore.nl tools.med.nyu.edu +topearnmoney.com topfox.co.uk +toppenishhospital.com +topsytomatotree.com +topsytree.com +topsytreetv.com +toptvstuff.com +toranoana.jp +toranomon-ichiba.com +tosti-asia.com totalcore.com +touchnbrush.tv +toutatice.fr +tpmail.transplace.com tracs.txstate.edu +tradecollege.com.au +traderssupersummit.com +trans-cosmos.co.jp +transat.com +transmontaigne.com +transportationtomorrow.on.ca +travelersflood.com +travelerssaves.com +travelindochina.co.nz +travelindochina.co.uk +travelindochina.com +travelindochina.com.au +travelmoneynow.com +trebesin.cz +trendsource.com trialpay.com +tribune.com +tricarsales.com +tritium.ch +trusted.com +tryabcircle.com +tryabrocket.com +tryabrocket.tv +tryabrocketflexmaster.com +trycrunchlessabs.com +tryeasyfeet.com +tryeasyreach.com +tryeyemagic.com +tryfastfit.com +tryfreegrillglovetv.com +tryfreerejuvenate.com +trygianttomato.com +tryhealthinitiative.com +trymybffnow.com +trymytomatofactory.com +trypetmd.com tryshakeweight.com +tryshakeweightespanol.com +trysidesleeperpro.com +tryslimmersilhouette.com +tryslimtsnow.com +trytomatofactorynow.com trytotalpillow.com +ts.cadritech.com.br +ts.k14.net +ts.transsoft.dk +tsn.dataresolution.net +tss-j.co.jp +tsubuyaki.fx.dmm.com +tsuweb.pilgrimsoftware.com +tu-chemnitz.de +tu-dortmund.de +tuev-nord.de +tufts-health.com +tui.rewardgateway.ie +tulane.wisenbaker.com +tum.de +tunnel.ltu.edu +tunnel.services.wisc.edu +tutornet.com.br +tuvakademie.it +tuwien.ac.at tvspy.com tw.event.gamania.com +twinriversregional.com +twoa.ac.nz +twyford.ealing.sch.uk +twynhamschool.com +tx.maxim-ic.com +tylerisd.org +u-tokyo.ac.jp +uab.edu +uatoa.americanexpress.com +ube-ind.co.jp +ubi.pt +ucf.edu +uci.edu +uckac.edu ucol.ac.nz +ucr.edu +ucsd.edu +udsis.com +uemail.unitedelec.com +ufl.edu +ugyfelkapu.mindigtvextra.hu +uhk.cz +uillinois.edu ukblelite01.emea.aza-lite.com ukblelite02.emea.aza-lite.com +ukwebmail.markit.com +ultrapos.net +umea.se +umons.ac.be +umpcshop.nl +umsamofund.com +umweltbundesamt.at +umweltrat.de +un.org +unc.edu +uncg.edu +undercovermags.com +uni-career.jp +uni-hamburg.de uni-hohenheim.de +unibas.ch +unifymoffice.com +unionvpn.union.edu +unisanta.br +unitron.no +univ-lyon1.fr +universalfloodpr.com +universitymedicalcenter.com +unixnotes.wordpress.com +unlimity.biz +uno.edu +unr.edu +unv.org +uottawa.ca +update.com +upenn.edu +upgradeserver.coremobility.com +upstatecarolina.net +urclickthru.com +urlinkthru.com +uruanna.com +us.connect.newegg.net +us17action.com +us36managedlanetrafficandrevenue.com +usa800.net +usacapitol.com +usc.edu +uscg.gov +user.atlas.sk user.centrum.cz +userapp.waubonsee.edu +usfinancialsource.com usuwazavpn04.americas.aza-lite.com +uta.edu +utah.gov +uws.edu +v-da-001.dp-itsolutions.de +va.gov +vaderstad.com +valenciaport.com +valtech.se +vanfcog.org +vangent.com +vasttrafik.se +vaxjo.se +vbgov.com +vci.de +vcommerce.com vcsportal.viasyscs.com +vdvexchange.com +veluwsescholengroepcvo.nl +ven.softec.sk +veniceregional.com +venners.co.uk +verifiering.se +verint.com +versicherungsvergleich.payback.de +verticalresponse.com +vervoerzcn.nl +verwaltung-innovativ.de +vestedanet.com +vestedapartners.com +vetsfirstchoice.com +vfwsturgis.org +vhspoint.lt +vi.macromill.com +viacord.com +vic33.win.kennesaw.edu +video.actadvantage.org +videocamerashop.be +videocamerashop.nl +villeesch.lu +virtualexchange.nl +virtuall.nl +visualvault.com +vitalberry.eu +vivaldi.ru +vivid-trade.com +vivus.se vle.guilsborough.northants.sch.uk +vle.marling.gloucs.sch.uk +vle.saddleworthschool.org +vocalocity.com +vodamail.hu +voicerecordershop.be +voicerecordershop.nl voogd.com +vosdemarches.saintgermainenlaye.fr +vpdn.dlr.de vpn-01.houstonisd.org vpn-03.houstonisd.org vpn-04.houstonisd.org +vpn-ap2.infor.com +vpn-gw1.unbc.ca +vpn-indy.exacttarget.com +vpn-server.rrzn.uni-hannover.de +vpn-stud-ssl.hogent.be +vpn-testbetrieb.rus.uni-stuttgart.de +vpn-us-ssl.lionbridge.com +vpn-wv.mentorg.com +vpn.4j.lane.edu +vpn.agnesirwin.org +vpn.ahss.org +vpn.anl.gov +vpn.ats.edu +vpn.ausrad.com +vpn.barry.edu +vpn.bchydro.com +vpn.bonitahealthcenter.com +vpn.caltech.edu +vpn.cclswi.com +vpn.challenger.wa.edu.au +vpn.claas.com +vpn.cmu.edu +vpn.coasolutions.com +vpn.coffey.com.au +vpn.concur.com +vpn.dearborn.pcgcampbell.com +vpn.del-valle.k12.tx.us +vpn.diebold.com +vpn.doncaster.gov.uk +vpn.douglasesd.k12.or.us +vpn.ehu.es +vpn.eurecom.fr +vpn.fhi-berlin.mpg.de +vpn.gribskov.dk +vpn.gsorad.com +vpn.hbstubbs.com +vpn.hobokenumc.com +vpn.hppartners.com +vpn.ins-lua.com +vpn.interseco.nl +vpn.iridium.com +vpn.kleinandhoffman.com +vpn.kmcnetwork.org +vpn.l3stratis.com +vpn.lafayette.edu +vpn.lan.kth.se +vpn.liberty.edu +vpn.libertyregional.org +vpn.llproducts.eu +vpn.lrdc.com +vpn.mcgrathnicol.com +vpn.memorialsb.org +vpn.mercer.edu +vpn.minecofin.gov.rw +vpn.mobilearmor.com +vpn.msmc.la.edu +vpn.nbeavers.com +vpn.netprivateer.com +vpn.newpaltz.edu +vpn.pace.edu +vpn.pasadenaisd.org +vpn.pih.net +vpn.pxi.com +vpn.redbarchetta.com +vpn.reliablesprinkler.com +vpn.reykjavik.is +vpn.rmc.ca +vpn.rz.tu-clausthal.de +vpn.sausd.us +vpn.stadsdeel-osdorp.nl +vpn.stb.eu vpn.tarumanagara.com +vpn.tesd.net +vpn.tfh-wildau.de +vpn.ud-medien.ch +vpn.uiowa.edu +vpn.uni-giessen.de +vpn.univ-lr.fr +vpn.unizar.es +vpn.uoguelph.ca +vpn.uow.edu.au +vpn.utexas.edu +vpn.uwhealth.org +vpn.virteva.com +vpn.wrij.nl +vpn01.us-support.com +vpn02.nucomm.net +vpn1.dot.state.ga.us +vpn1.prvlimburg.nl +vpn1.sandyspringbank.com +vpn1.security-finance.com +vpn2.bakbone.com +vpn2.qualys.com +vpnaccess.sales-service.com +vpngate.tu-bs.de +vpngate.uni-koeln.de +vpngw.uni-wuerzburg.de +vpnssl.nwths.biz +vpnuk.oup.com vr.is +vresp.com +vrg.se +vserver.de +vtc.edu.hk vtrade.vincomsc.com.vn +vucvejle.dk +vyvxinview.com +vzw.getyourscores.com +wa.gov +wa.infrontsports.com +waffenamt.it +wakeside.com +walbeekgroep.com +walmartfaces.com +walmarthowwedoit.com +walmartstores.com +walsallcollege.ac.uk warranty.akeryards.as +warwick.ac.uk +was.org +wastis-eu.st.com +wcupa.edu +wcvpn.wartburg.edu +wdpartnersonline.com web-opas.osakaya.co.jp +web-pl.daikin.co.jp +web-vpn.hefr.ch +web.rbc.com +web.storen.ch +web.uc.atosorigin.com +web.vpn.finanzit.net +web01.de.amadee.net webaccess.7p-group.com +webaccess.atkearney.com webaccess.pvhs.org +webapp.dpd.nl +webapp.meredith.com +webapps.hudsonisd.org +webbdaf.com +webbmail.ssg.se webbt.banque-tahiti.pf +webcenc.com +webchat.unt.edu +webcomputer.nl +webdagbog.kvuc.dk +webdirect.jp +webenroll.accesstpa.com webforensics.co.uk +webgate.no +webinfra.nl +webmail.5sqc.com +webmail.aap.com.au +webmail.accentonline.com +webmail.action-inter.com +webmail.administaff.com +webmail.aguiabranca.com.br +webmail.ahs.ae +webmail.ak-normal.school.nz +webmail.akd.nl +webmail.akl.whk.co.nz +webmail.albertadoctors.org +webmail.alere.co.uk +webmail.alexmann.com +webmail.alturkigroup.net +webmail.ampvisualtv.tv +webmail.anacom.pt +webmail.apotex.ca +webmail.arbella.com +webmail.aritzia.com +webmail.arthurterry.bham.sch.uk webmail.asb.dk +webmail.asparis.fr +webmail.assembly.ab.ca +webmail.attendshealthcare.com +webmail.audencia.com webmail.austmus.gov.au +webmail.aventus.nl +webmail.awsg.at +webmail.azmedien.ch +webmail.barnet.ac.uk +webmail.bayamonpr.org +webmail.bg.fnv.nl +webmail.bggs.qld.edu.au +webmail.bie.edu +webmail.bife.ie +webmail.bluepointsolutions.com webmail.bne.catholic.edu.au webmail.bose.com +webmail.bravilor.com +webmail.bridgercapital.com +webmail.brigantine.atlnet.org +webmail.brinkgroep.nl +webmail.bwfc.co.uk +webmail.c-e.com +webmail.capacent.is +webmail.cardonald.ac.uk +webmail.carmelcollegesalland.nl +webmail.casgen.com +webmail.cavanvec.ie +webmail.cet.ac.il +webmail.cg68.fr +webmail.chmca.org webmail.choa.org +webmail.cineplex.com +webmail.citationair.com +webmail.cityofvancouver.us +webmail.cmslegal.at +webmail.corenet.se +webmail.corptax.com +webmail.cosmopolitanlasvegas.com +webmail.crchealth.com +webmail.creuna.com +webmail.croklaan.com +webmail.crow.nl webmail.csaa.com +webmail.dabs.com +webmail.davenportdiocese.org +webmail.debaak.nl +webmail.deckers.com +webmail.dibrosi.be +webmail.dongemondcollege.nl +webmail.donlen.com +webmail.dpsg.com +webmail.dwango.co.jp +webmail.e-boticario.com.br +webmail.ea.aku.edu +webmail.ecerdc.com.my +webmail.ecosystem.ca +webmail.edinburghacademy.org.uk +webmail.edita.se +webmail.ekero.se +webmail.emmahuis.nl +webmail.energimidt.dk +webmail.energyfutureholdings.com +webmail.enex-om.com.br +webmail.engevix.com.br +webmail.escortinc.com +webmail.etch.com +webmail.euroatlantic.pt +webmail.excanto.com +webmail.fdm.dk +webmail.ferroeste.com.br +webmail.finning.co.uk webmail.firstam.net +webmail.flydubai.com +webmail.francetv.fr +webmail.frederikshavn.dk +webmail.furuboda.se +webmail.gazprom-mt.com +webmail.gebalis.pt +webmail.genphysics.com +webmail.globalcloudservices.nl +webmail.gmh.edu +webmail.gorinchem.nl +webmail.guido.nl +webmail.haaga-helia.fi +webmail.hanno.dk +webmail.henrico.k12.va.us +webmail.hostedoutlook.be +webmail.howerter.org webmail.hrblock.com +webmail.icare.nl +webmail.icr-inc.net +webmail.ikno.nl webmail.ingbank.com.tr +webmail.insight-onsite.us +webmail.integrationsfonds.at +webmail.interwetten.com +webmail.intrinsec.com +webmail.ipzs.it +webmail.iqhs.nl +webmail.irdeto.com +webmail.isolve.co.za +webmail.ithaca.edu +webmail.ivoclarvivadent.com +webmail.javelindirect.com +webmail.jbc.nl +webmail.jmp.co.uk +webmail.jungfrau.ch webmail.kapsch.net +webmail.kentalis.nl +webmail.keuda.fi +webmail.kinder-stad.nl +webmail.knauf.fr +webmail.knighttrans.com +webmail.knvb.nl +webmail.komatsuforest.com +webmail.ku.edu.tr +webmail.lancashire.bm +webmail.lappia.fi +webmail.larkinhoffman.com +webmail.lett.dk +webmail.levillage1.be webmail.levinglobal.com +webmail.loginlogistica.com.br webmail.lolland.dk +webmail.macsstores.com +webmail.mahouse.gov +webmail.malvik.kommune.no +webmail.manheim.com +webmail.manpower.ch +webmail.mansion.com +webmail.marketing-asiapac.com +webmail.mcbdds.org +webmail.mdc.wa.edu.au +webmail.meca.se +webmail.med.uni-muenchen.de +webmail.medic911.com +webmail.menai.ac.uk +webmail.metalor.com +webmail.mioc.hr +webmail.mjncomputers.co.uk +webmail.modal.com.br +webmail.moeller.org +webmail.mof.gov.ae +webmail.moh.gov.sa +webmail.mondigroup.com +webmail.mondipackaging.com +webmail.monroecounty-fl.gov +webmail.montessoricollege.nl +webmail.monumentalsports.com webmail.mopera.net +webmail.morphosys.com +webmail.mr-daten.de webmail.mt.gov +webmail.mutter.se +webmail.myeasyoffice.nl +webmail.myfloridahouse.gov +webmail.mystructured.com +webmail.netdesign.dk +webmail.nettrust.ch webmail.newlook.net +webmail.nilu.no +webmail.nobel.nl +webmail.noelgroup.com +webmail.nordoc.no +webmail.normik.dk +webmail.nyfors.dk +webmail.odin-groep.nl +webmail.oecd.org +webmail.oem.dk +webmail.oensmurer.dk +webmail.offmadisonave.com +webmail.orbitone.se webmail.ordina.nl +webmail.ormiston.qld.edu.au +webmail.parametrix.com +webmail.pdtit.be +webmail.peacehealth.org webmail.peelpolice.ca +webmail.pinellascounty.org +webmail.plenarygroup.com +webmail.proag.com +webmail.psd.pt +webmail.pu-kumamoto.ac.jp +webmail.qinvest.com +webmail.quest.com +webmail.raiffeisenevolution.com +webmail.randaberg.kommune.no +webmail.rasmussen.edu +webmail.realtors.org +webmail.rebild.dk +webmail.reesmanley.com +webmail.regentcomm.com +webmail.renn4.nl +webmail.rgomiddelharnis.nl +webmail.rietlanden.nl +webmail.rijnijssel.nl +webmail.rodenstock.com +webmail.roe.ac.uk +webmail.rollins.edu +webmail.rta.ae +webmail.rtg.at +webmail.rtl.hr +webmail.rtp.pt +webmail.saintjohn.ca +webmail.sanoma-magazines.be +webmail.sbl.ch +webmail.schuleherisau.ch +webmail.seaservers.net +webmail.seha.ae +webmail.semtribe.com +webmail.shepleybulfinch.com +webmail.sicl.co.uk +webmail.skanderborg.dk +webmail.skilled.com.au +webmail.skm.gov.my +webmail.skogu.nl +webmail.sma.de +webmail.socu.dk +webmail.sotog.nl +webmail.span.hr webmail.springer-sbm.com +webmail.sprm.gov.my webmail.srhs.com +webmail.stavanger.kommune.no +webmail.struttandparker.com +webmail.stsmd.dk +webmail.stura.uni-halle.de +webmail.swafnet.com +webmail.swietelsky.com +webmail.sysco.com +webmail.t-atrium.nl +webmail.t-systems.dk +webmail.t26.dk +webmail.taarnby.dk +webmail.teaterskolen.dk +webmail.techcampus.org +webmail.tecnalia.com +webmail.teknowlogic.com +webmail.tfmc.co.za +webmail.tisq.nl webmail.toho-u.ac.jp +webmail.torshavn.fo +webmail.touricoholidays.com webmail.transat.com webmail.tribune.com webmail.tuev-nord.de +webmail.tv1.com.br +webmail.tys.fi +webmail.uatlantica.pt +webmail.uc4.com +webmail.unifiedvalve.com +webmail.unikom.se +webmail.unilu.ch +webmail.univ-catholyon.fr +webmail.unl.pt +webmail.usek.edu.lb +webmail.users.co.uk webmail.valamar.com +webmail.varnesregion.no +webmail.veghel.nl +webmail.vennesla.kommune.no +webmail.verkinderen.com +webmail.viridisit.com +webmail.vu.nl +webmail.washsports.com webmail.waterman-group.co.uk +webmail.wc.com webmail.wcupa.edu +webmail.whitireia.ac.nz +webmail.windstream.net +webmail.witc.edu +webmail.wpod.net +webmail.wtamu.edu +webmail.wuerth-phoenix.com +webmail.wuerth.at +webmail.ymcamke.org +webmail0.gifu-net.ed.jp +webmail1.finansforbundet.dk +webmail1.gmrmarketing.com +webmail1.go2uti.com +webmail2.ems-t.com +webmail2.factset.com webmaildata.rr.com +webmaileu.elcoteq.com +webmailwg.datacom.co.nz +webnet.cscdgr.on.ca +webos.bonsallusd.com +webportal.bmw.nl +webportal.simacict.nl +webportal2.cfisd.net +webprod4.hc-sc.gc.ca +webremote.grainger.com +webservicescitoyens.com webshop.weijntjes.nl +websis.unimedcuiaba.com.br +websupport.f5.com +webvpn.aamc.org webvpn.au.aecom.com webvpn.ben.edu +webvpn.botsford.org +webvpn.brmchealthcare.com +webvpn.coe.int +webvpn.colfaxcorp.com +webvpn.dm-drogeriemarkt.com +webvpn.doherty.co.uk +webvpn.dpsk12.org +webvpn.egyptianlng.com +webvpn.eso.org webvpn.eu.aecom.com +webvpn.evraz.com +webvpn.globant.com +webvpn.greywolfcapital.com +webvpn.ieua.org +webvpn.jccc.edu +webvpn.lexmed.com +webvpn.more.net +webvpn.ned.org +webvpn.oceanspray.com +webvpn.orionhealth.com +webvpn.progress-energy.com +webvpn.promon.com.br +webvpn.purdue.edu +webvpn.roosevelt.edu +webvpn.rz.tu-harburg.de +webvpn.scf.cc +webvpn.sebh.org +webvpn.steaknshake.com +webvpn.thegoodguys.com.au +webvpn.trademe.co.nz +webvpn.uni-leipzig.de webvpn.usaa.com webvpn.usps.gov +webvpn.vcu.edu +webvpn.wesleyan.edu +wecc.biz +wein7.de +wellspan.org welltrix.com +welly.sm werecoverdata.com +wessexlearning.org.uk +west.skofirm.com +westbuckland.devon.sch.uk +westcon.no wettstar.de +wha-asa5520.wilmingtonhealth.com +whataburgerfranchisees.com +whataburgervendors.com +whataburgerventures.com +whatwouldmillionairedo.com +wheelingil.gov +whitworth.edu +wholesale.starfinancial.com +whoosh.hk +whrsd.org +widgetbox.com +wiki.ngmoco.com +wiki.tradeext.com +wikipat.com +williamsonmemorial.net +winahome4you.com +winebow.com +winxnet.com +wish.org +wizardfinance.net +wm.valley.ne.jp +wms01.wimaxforum.org +wnp.waseda.jp +womanshospitalms.com +woodiesdiy.com +woodlynde.org +wordandbrown.com workhere.jetblue.com +world-direct.at +worldatwardvds.com +worldwaronecolor.com +wortech.ac.uk +worthington-portal.org wowbeez.com +wrpinfo.org ws.licenzji-vetturi.gov.mt +wsaaudit.com +wsasr520study.com +wsbe.org.uk +wsl.ch +wsu.edu +wt.gfi-informatik.de wtc.lxr.com +wtoutlook.wellcome.ac.uk +ww3.metroymca.org +www-new.epc-business.com +www-sys2.tax.state.oh.us www.accessgeneral.com www.accessingram.com www.adfox.cz @@ -654,21 +5046,71 @@ www.zenfolio.com www.zenryonetwork.com www.zoominfo.com www1.cat365.net +www1.hop.ana.co.jp www1.ticket-web-shochiku.com www2.fakton.nl +www2.hokepon.com +www2.kenkyosai.or.jp +www2.lcmcisd.org www2.proexam.org www2.secom-techno.co.jp +www2.tagmulimta.co.il +www2.tel-aviv.gov.il www2.ticket-web-shochiku.com +www2.webfactory-world.de +www3.bs-j.co.jp +www3.inferencedata.com +www3.myfloridacounty.com +www3.tv-tokyo.co.jp www6.hsmv.state.fl.us wwws.jp-bank.japanpost.jp +wwwssl.isd109.org +wwwx.oaklandcc.edu wwy01.shiki.gr.jp wynbilling.wyndhamworldwide.com +wyndhamworldwide.com wynnmacau.recruitmax.com +wza.nl +wzanet.nl xbox.redeemer.ab.ca +xchanging.com +xchg.int.t-mobile.at +xfinityhomesecurity.com +xmlic.payfuse.com +xmlrpc4.mollom.com +xnet.woodforest.com +xolair.com +xolairhcp.com +xpansions.com +xs4all.nl +xsightrewards.com +xtiva.net +xtremecardioonline.com +yahoo-vi.co.jp +yakimaregional.com +yaskawa.co.jp +yayoi-kk.co.jp +yes123.com.tw +ymca.net yodlee.com +yourownshoppingcart.com +yourperfectweightloss.com yourwirelessrebatecenter.com yoyaku.city.funabashi.chiba.jp yoyaku.city.hachioji.tokyo.jp +yoyaku.koto-sports.net +yoyaku.nasva.go.jp +yoyaku.parksweb.net +yuyu.medicarelife.com +zain.com zenfolio.com +zenryonetwork.com +zgraggen.homeserver.com +zinio.com +zis.ch +zivildienst.de +zoomienation.usafa.org zoominfo.com +zooomeee.com +zuidwester.org zumbafitness.com diff --git a/net/base/ssl_false_start_blacklist_process.cc b/net/base/ssl_false_start_blacklist_process.cc index 46b99af..634df6a 100644 --- a/net/base/ssl_false_start_blacklist_process.cc +++ b/net/base/ssl_false_start_blacklist_process.cc @@ -19,6 +19,8 @@ using net::SSLFalseStartBlacklist; static const unsigned kBuckets = SSLFalseStartBlacklist::kBuckets; +static bool verbose = false; + static int usage(const char* argv0) { fprintf(stderr, "Usage: %s <blacklist file> <output .c file>\n", argv0); @@ -48,7 +50,8 @@ static void RemoveDuplicateEntries(std::vector<std::string>* hosts) { for (std::vector<std::string>::const_iterator i = hosts->begin(); i != hosts->end(); i++) { if (hosts_set.count(*i)) { - fprintf(stderr, "Removing duplicate entry for %s\n", i->c_str()); + if (verbose) + fprintf(stderr, "Removing duplicate entry for %s\n", i->c_str()); continue; } hosts_set.insert(*i); @@ -93,7 +96,8 @@ static void RemoveRedundantEntries(std::vector<std::string>* hosts) { if (parent.empty()) { ret.push_back(*i); } else { - fprintf(stderr, "Removing %s as redundant\n", i->c_str()); + if (verbose) + fprintf(stderr, "Removing %s as redundant\n", i->c_str()); } } @@ -124,7 +128,7 @@ int main(int argc, char** argv) { const char* input_file = argv[1]; const char* output_file = argv[2]; - FILE* input = fopen(input_file, "r"); + FILE* input = fopen(input_file, "rb"); if (!input) { perror("open"); return usage(argv[0]); @@ -143,11 +147,16 @@ int main(int argc, char** argv) { } char* buffer = static_cast<char*>(malloc(input_size)); - if (fread(buffer, input_size, 1, input) != 1) { - perror("fread"); - free(buffer); - fclose(input); - return 1; + long done = 0; + while (done < input_size) { + size_t n = fread(buffer + done, 1, input_size - done, input); + if (n == 0) { + perror("fread"); + free(buffer); + fclose(input); + return 1; + } + done += n; } fclose(input); @@ -158,8 +167,12 @@ int main(int argc, char** argv) { bool non_whitespace_seen = false; for (long i = 0; i <= input_size; i++) { if (i == input_size || buffer[i] == '\n') { - if (!is_comment && non_whitespace_seen) - hosts.push_back(std::string(&buffer[line_start], i - line_start)); + if (!is_comment && non_whitespace_seen) { + long len = i - line_start; + if (i > 0 && buffer[i-1] == '\r') + len--; + hosts.push_back(std::string(&buffer[line_start], len)); + } is_comment = false; non_whitespace_seen = false; line_start = i + 1; @@ -168,7 +181,7 @@ int main(int argc, char** argv) { if (i == line_start && buffer[i] == '#') is_comment = true; - if (buffer[i] != ' ' && buffer[i] != '\t') + if (buffer[i] != ' ' && buffer[i] != '\t' && buffer[i] != '\r') non_whitespace_seen = true; } free(buffer); @@ -185,7 +198,7 @@ int main(int argc, char** argv) { } fprintf(stderr, "Using %d entry hash table\n", kBuckets); - uint16 table[kBuckets]; + uint32 table[kBuckets]; std::vector<std::string> buckets[kBuckets]; for (std::vector<std::string>::const_iterator @@ -199,11 +212,6 @@ int main(int argc, char** argv) { std::string table_data; unsigned max_bucket_size = 0; for (unsigned i = 0; i < kBuckets; i++) { - if (table_data.size() > 65535) { - fprintf(stderr, "Hash table overflowed a uint16_t index\n"); - return 3; - } - if (buckets[i].size() > max_bucket_size) max_bucket_size = buckets[i].size(); @@ -231,31 +239,24 @@ int main(int argc, char** argv) { fprintf(out, "#include \"base/basictypes.h\"\n\n"); fprintf(out, "#include \"net/base/ssl_false_start_blacklist.h\"\n\n"); fprintf(out, "namespace net {\n\n"); - fprintf(out, "const uint16 SSLFalseStartBlacklist::kHashTable[%d + 1] = {\n", + fprintf(out, "const uint32 SSLFalseStartBlacklist::kHashTable[%d + 1] = {\n", kBuckets); for (unsigned i = 0; i < kBuckets; i++) { - fprintf(out, " %d,\n", (int) table[i]); + fprintf(out, " %u,\n", (unsigned) table[i]); } - fprintf(out, " %d,\n", (int) table_data.size()); + fprintf(out, " %u,\n", (unsigned) table_data.size()); fprintf(out, "};\n\n"); - fprintf(out, "const char SSLFalseStartBlacklist::kHashData[] = \n"); + fprintf(out, "const char SSLFalseStartBlacklist::kHashData[] = {\n"); for (unsigned i = 0, line_length = 0; i < table_data.size(); i++) { if (line_length == 0) - fprintf(out, " \""); + fprintf(out, " "); uint8 c = static_cast<uint8>(table_data[i]); - if (c < 32 || c > 127 || c == '"') { - fprintf(out, "\\%c%c%c", '0' + ((c >> 6) & 7), '0' + ((c >> 3) & 7), - '0' + (c & 7)); - line_length += 4; - } else { - fprintf(out, "%c", c); - line_length++; - } + line_length += fprintf(out, "%d, ", c); if (i == table_data.size() - 1) { - fprintf(out, "\";\n"); + fprintf(out, "\n};\n"); } else if (line_length >= 70) { - fprintf(out, "\"\n"); + fprintf(out, "\n"); line_length = 0; } } diff --git a/net/base/ssl_info.h b/net/base/ssl_info.h index 1786b58..4c68f06 100644 --- a/net/base/ssl_info.h +++ b/net/base/ssl_info.h @@ -42,9 +42,8 @@ class SSLInfo { int security_bits; // Information about the SSL connection itself. See - // ssl_connection_status_flags.h for values. The ciphersuite and compression - // in use are encoded within. - // TODO(agl): also encode the protocol version used. + // ssl_connection_status_flags.h for values. The protocol version, + // ciphersuite, and compression in use are encoded within. int connection_status; }; diff --git a/net/base/transport_security_state.cc b/net/base/transport_security_state.cc index a0d2794..3014e21 100644 --- a/net/base/transport_security_state.cc +++ b/net/base/transport_security_state.cc @@ -142,7 +142,9 @@ bool TransportSecurityState::ParseHeader(const std::string& value, case AFTER_MAX_AGE_EQUALS: if (IsAsciiWhitespace(*tokenizer.token_begin())) continue; - if (!base::StringToInt(tokenizer.token(), &max_age_candidate)) + if (!base::StringToInt(tokenizer.token_begin(), + tokenizer.token_end(), + &max_age_candidate)) return false; if (max_age_candidate < 0) return false; @@ -408,6 +410,7 @@ bool TransportSecurityState::IsPreloadedSTS( {12, true, "\006jottit\003com"}, {19, true, "\015sunshinepress\003org"}, {21, false, "\003www\013noisebridge\003net"}, + {10, false, "\004neg9\003org"}, }; static const size_t kNumPreloadedSTS = ARRAYSIZE_UNSAFE(kPreloadedSTS); diff --git a/net/base/transport_security_state_unittest.cc b/net/base/transport_security_state_unittest.cc index c4a173c..2a06501 100644 --- a/net/base/transport_security_state_unittest.cc +++ b/net/base/transport_security_state_unittest.cc @@ -342,6 +342,9 @@ TEST_F(TransportSecurityStateTest, Preloaded) { EXPECT_TRUE(state->IsEnabledForHost(&domain_state, "www.noisebridge.net")); EXPECT_FALSE(state->IsEnabledForHost(&domain_state, "noisebridge.net")); EXPECT_FALSE(state->IsEnabledForHost(&domain_state, "foo.noisebridge.net")); + + EXPECT_TRUE(state->IsEnabledForHost(&domain_state, "neg9.org")); + EXPECT_FALSE(state->IsEnabledForHost(&domain_state, "www.neg9.org")); } TEST_F(TransportSecurityStateTest, LongNames) { diff --git a/net/base/x509_certificate.cc b/net/base/x509_certificate.cc index e21a3bc..7bbce5c 100644 --- a/net/base/x509_certificate.cc +++ b/net/base/x509_certificate.cc @@ -153,6 +153,46 @@ X509Certificate* X509Certificate::CreateFromHandle( return cert; } +#if defined(OS_WIN) +static X509Certificate::OSCertHandle CreateOSCert(base::StringPiece der_cert) { + X509Certificate::OSCertHandle cert_handle = NULL; + BOOL ok = CertAddEncodedCertificateToStore( + X509Certificate::cert_store(), X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, + reinterpret_cast<const BYTE*>(der_cert.data()), der_cert.size(), + CERT_STORE_ADD_USE_EXISTING, &cert_handle); + return ok ? cert_handle : NULL; +} +#else +static X509Certificate::OSCertHandle CreateOSCert(base::StringPiece der_cert) { + return X509Certificate::CreateOSCertHandleFromBytes( + const_cast<char*>(der_cert.data()), der_cert.size()); +} +#endif + +// static +X509Certificate* X509Certificate::CreateFromDERCertChain( + const std::vector<base::StringPiece>& der_certs) { + if (der_certs.size() == 0) + return NULL; + + X509Certificate::OSCertHandles intermediate_ca_certs; + for (size_t i = 1; i < der_certs.size(); i++) { + OSCertHandle handle = CreateOSCert(der_certs[i]); + DCHECK(handle); + intermediate_ca_certs.push_back(handle); + } + + OSCertHandle handle = CreateOSCert(der_certs[0]); + DCHECK(handle); + X509Certificate* cert = + CreateFromHandle(handle, SOURCE_FROM_NETWORK, intermediate_ca_certs); + FreeOSCertHandle(handle); + for (size_t i = 0; i < intermediate_ca_certs.size(); i++) + FreeOSCertHandle(intermediate_ca_certs[i]); + + return cert; +} + // static X509Certificate* X509Certificate::CreateFromBytes(const char* data, int length) { @@ -249,11 +289,9 @@ X509Certificate::X509Certificate(OSCertHandle cert_handle, const OSCertHandles& intermediates) : cert_handle_(DupOSCertHandle(cert_handle)), source_(source) { -#if defined(OS_MACOSX) || defined(OS_WIN) || defined(USE_OPENSSL) // Copy/retain the intermediate cert handles. for (size_t i = 0; i < intermediates.size(); ++i) intermediate_ca_certs_.push_back(DupOSCertHandle(intermediates[i])); -#endif // Platform-specific initialization. Initialize(); } @@ -276,10 +314,8 @@ X509Certificate::~X509Certificate() { X509Certificate::Cache::GetInstance()->Remove(this); if (cert_handle_) FreeOSCertHandle(cert_handle_); -#if defined(OS_MACOSX) || defined(OS_WIN) for (size_t i = 0; i < intermediate_ca_certs_.size(); ++i) FreeOSCertHandle(intermediate_ca_certs_[i]); -#endif } bool X509Certificate::HasExpired() const { diff --git a/net/base/x509_certificate.h b/net/base/x509_certificate.h index 577de92..68762e4 100644 --- a/net/base/x509_certificate.h +++ b/net/base/x509_certificate.h @@ -13,6 +13,7 @@ #include "base/gtest_prod_util.h" #include "base/ref_counted.h" +#include "base/string_piece.h" #include "base/time.h" #include "net/base/x509_cert_types.h" @@ -107,12 +108,20 @@ class X509Certificate : public base::RefCountedThreadSafe<X509Certificate> { // certificate cache prefers the handle from the network because our HTTP // cache isn't caching the corresponding intermediate CA certificates yet // (http://crbug.com/7065). - // The list of intermediate certificates is ignored under NSS (i.e. Linux.) // The returned pointer must be stored in a scoped_refptr<X509Certificate>. static X509Certificate* CreateFromHandle(OSCertHandle cert_handle, Source source, const OSCertHandles& intermediates); + // Create an X509Certificate from a chain of DER encoded certificates. The + // first certificate in the chain is the end-entity certificate to which a + // handle is returned. The other certificates in the chain are intermediate + // certificates. See the comment for |CreateFromHandle| about the |source| + // argument. + // The returned pointer must be stored in a scoped_refptr<X509Certificate>. + static X509Certificate* CreateFromDERCertChain( + const std::vector<base::StringPiece>& der_certs); + // Create an X509Certificate from the DER-encoded representation. // Returns NULL on failure. // @@ -173,14 +182,12 @@ class X509Certificate : public base::RefCountedThreadSafe<X509Certificate> { // now. bool HasExpired() const; -#if defined(OS_MACOSX) || defined(OS_WIN) || defined(USE_OPENSSL) // Returns intermediate certificates added via AddIntermediateCertificate(). // Ownership follows the "get" rule: it is the caller's responsibility to // retain the elements of the result. const OSCertHandles& GetIntermediateCertificates() const { return intermediate_ca_certs_; } -#endif // Returns true if I already contain the given intermediate cert. bool HasIntermediateCertificate(OSCertHandle cert); @@ -213,6 +220,17 @@ class X509Certificate : public base::RefCountedThreadSafe<X509Certificate> { CFArrayRef CreateClientCertificateChain() const; #endif +#if defined(OS_WIN) + // Returns a handle to a global, in-memory certificate store. We use it for + // two purposes: + // 1. Import server certificates into this store so that we can verify and + // display the certificates using CryptoAPI. + // 2. Copy client certificates from the "MY" system certificate store into + // this store so that we can close the system store when we finish + // searching for client certificates. + static HCERTSTORE cert_store(); +#endif + // Verifies the certificate against the given hostname. Returns OK if // successful or an error code upon failure. // @@ -268,6 +286,10 @@ class X509Certificate : public base::RefCountedThreadSafe<X509Certificate> { // Common object initialization code. Called by the constructors only. void Initialize(); +#if defined(OS_WIN) + bool CheckEV(PCCERT_CHAIN_CONTEXT chain_context, + const char* policy_oid) const; +#endif bool VerifyEV() const; // Calculates the SHA-1 fingerprint of the certificate. Returns an empty @@ -292,11 +314,9 @@ class X509Certificate : public base::RefCountedThreadSafe<X509Certificate> { // A handle to the certificate object in the underlying crypto library. OSCertHandle cert_handle_; -#if defined(OS_MACOSX) || defined(OS_WIN) || defined(USE_OPENSSL) // Untrusted intermediate certificates associated with this certificate - // that may be needed for chain building. (NSS impl does not need these.) + // that may be needed for chain building. OSCertHandles intermediate_ca_certs_; -#endif #if defined(OS_MACOSX) // Blocks multiple threads from verifying the cert simultaneously. diff --git a/net/base/x509_certificate_mac.cc b/net/base/x509_certificate_mac.cc index 05fbe63..a2a0eea 100644 --- a/net/base/x509_certificate_mac.cc +++ b/net/base/x509_certificate_mac.cc @@ -694,6 +694,7 @@ int X509Certificate::Verify(const std::string& hostname, int flags, // Determine the certificate's EV status using SecTrustCopyExtendedResult(), // which we need to look up because the function wasn't added until // Mac OS X 10.5.7. + // Note: "ExtendedResult" means extended validation results. CFBundleRef bundle = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.security")); if (bundle) { @@ -872,10 +873,10 @@ bool X509Certificate::IsIssuedBy( for (int i = 0; i < n; ++i) { SecCertificateRef cert_handle = reinterpret_cast<SecCertificateRef>( const_cast<void*>(CFArrayGetValueAtIndex(cert_chain, i))); - scoped_refptr<X509Certificate> cert = X509Certificate::CreateFromHandle( + scoped_refptr<X509Certificate> cert(X509Certificate::CreateFromHandle( cert_handle, X509Certificate::SOURCE_LONE_CERT_IMPORT, - X509Certificate::OSCertHandles()); + X509Certificate::OSCertHandles())); for (unsigned j = 0; j < valid_issuers.size(); j++) { if (cert->issuer().Matches(valid_issuers[j])) return true; diff --git a/net/base/x509_certificate_openssl.cc b/net/base/x509_certificate_openssl.cc index 668fd5f..a9ad39c 100644 --- a/net/base/x509_certificate_openssl.cc +++ b/net/base/x509_certificate_openssl.cc @@ -20,9 +20,12 @@ #include "net/base/cert_verify_result.h" #include "net/base/net_errors.h" #include "net/base/openssl_util.h" +#include "net/base/x509_openssl_util.h" namespace net { +namespace nxou = net::x509_openssl_util; + namespace { void CreateOSCertHandlesFromPKCS7Bytes( @@ -51,39 +54,13 @@ void CreateOSCertHandlesFromPKCS7Bytes( } } -bool ParsePrincipalFieldInternal(X509_NAME* name, - int index, - std::string* field) { - ASN1_STRING* data = - X509_NAME_ENTRY_get_data(X509_NAME_get_entry(name, index)); - if (!data) - return false; - - unsigned char* buf = NULL; - int len = ASN1_STRING_to_UTF8(&buf, data); - if (len <= 0) - return false; - - field->assign(reinterpret_cast<const char*>(buf), len); - OPENSSL_free(buf); - return true; -} - -void ParsePrincipalField(X509_NAME* name, int nid, std::string* field) { - int index = X509_NAME_get_index_by_NID(name, nid, -1); - if (index < 0) - return; - - ParsePrincipalFieldInternal(name, index, field); -} - -void ParsePrincipalFields(X509_NAME* name, +void ParsePrincipalValues(X509_NAME* name, int nid, std::vector<std::string>* fields) { for (int index = -1; (index = X509_NAME_get_index_by_NID(name, nid, index)) != -1;) { std::string field; - if (!ParsePrincipalFieldInternal(name, index, &field)) + if (!nxou::ParsePrincipalValueByIndex(name, index, &field)) break; fields->push_back(field); } @@ -95,58 +72,23 @@ void ParsePrincipal(X509Certificate::OSCertHandle cert, if (!x509_name) return; - ParsePrincipalFields(x509_name, NID_streetAddress, + ParsePrincipalValues(x509_name, NID_streetAddress, &principal->street_addresses); - ParsePrincipalFields(x509_name, NID_organizationName, + ParsePrincipalValues(x509_name, NID_organizationName, &principal->organization_names); - ParsePrincipalFields(x509_name, NID_organizationalUnitName, + ParsePrincipalValues(x509_name, NID_organizationalUnitName, &principal->organization_unit_names); - ParsePrincipalFields(x509_name, NID_domainComponent, + ParsePrincipalValues(x509_name, NID_domainComponent, &principal->domain_components); - ParsePrincipalField(x509_name, NID_commonName, &principal->common_name); - ParsePrincipalField(x509_name, NID_localityName, &principal->locality_name); - ParsePrincipalField(x509_name, NID_stateOrProvinceName, - &principal->state_or_province_name); - ParsePrincipalField(x509_name, NID_countryName, &principal->country_name); -} - -void ParseDate(ASN1_TIME* x509_time, base::Time* time) { - if (!x509_time || - (x509_time->type != V_ASN1_UTCTIME && - x509_time->type != V_ASN1_GENERALIZEDTIME)) - return; - - std::string str_date(reinterpret_cast<char*>(x509_time->data), - x509_time->length); - // UTCTime: YYMMDDHHMMSSZ - // GeneralizedTime: YYYYMMDDHHMMSSZ - size_t year_length = x509_time->type == V_ASN1_UTCTIME ? 2 : 4; - size_t fields_offset = x509_time->type == V_ASN1_UTCTIME ? 0 : 2; - - if (str_date.length() < 11 + year_length) - return; - - base::Time::Exploded exploded = {0}; - bool valid = base::StringToInt(str_date.substr(0, year_length), - &exploded.year); - if (valid && year_length == 2) - exploded.year += exploded.year < 50 ? 2000 : 1900; - - valid &= base::StringToInt(str_date.substr(2 + fields_offset, 2), - &exploded.month); - valid &= base::StringToInt(str_date.substr(4 + fields_offset, 2), - &exploded.day_of_month); - valid &= base::StringToInt(str_date.substr(6 + fields_offset, 2), - &exploded.hour); - valid &= base::StringToInt(str_date.substr(8 + fields_offset, 2), - &exploded.minute); - valid &= base::StringToInt(str_date.substr(10 + fields_offset, 2), - &exploded.second); - - DCHECK(valid); - - *time = base::Time::FromUTCExploded(exploded); + nxou::ParsePrincipalValueByNID(x509_name, NID_commonName, + &principal->common_name); + nxou::ParsePrincipalValueByNID(x509_name, NID_localityName, + &principal->locality_name); + nxou::ParsePrincipalValueByNID(x509_name, NID_stateOrProvinceName, + &principal->state_or_province_name); + nxou::ParsePrincipalValueByNID(x509_name, NID_countryName, + &principal->country_name); } void ParseSubjectAltNames(X509Certificate::OSCertHandle cert, @@ -351,8 +293,8 @@ void X509Certificate::Initialize() { fingerprint_ = CalculateFingerprint(cert_handle_); ParsePrincipal(cert_handle_, X509_get_subject_name(cert_handle_), &subject_); ParsePrincipal(cert_handle_, X509_get_issuer_name(cert_handle_), &issuer_); - ParseDate(X509_get_notBefore(cert_handle_), &valid_start_); - ParseDate(X509_get_notAfter(cert_handle_), &valid_expiry_); + nxou::ParseDate(X509_get_notBefore(cert_handle_), &valid_start_); + nxou::ParseDate(X509_get_notAfter(cert_handle_), &valid_expiry_); } SHA1Fingerprint X509Certificate::CalculateFingerprint(OSCertHandle cert) { diff --git a/net/base/x509_certificate_unittest.cc b/net/base/x509_certificate_unittest.cc index 9bb81cb..31173e4 100644 --- a/net/base/x509_certificate_unittest.cc +++ b/net/base/x509_certificate_unittest.cc @@ -252,9 +252,9 @@ void CheckGoogleCert(const scoped_refptr<X509Certificate>& google_cert, } TEST(X509CertificateTest, GoogleCertParsing) { - scoped_refptr<X509Certificate> google_cert = + scoped_refptr<X509Certificate> google_cert( X509Certificate::CreateFromBytes( - reinterpret_cast<const char*>(google_der), sizeof(google_der)); + reinterpret_cast<const char*>(google_der), sizeof(google_der))); CheckGoogleCert(google_cert, google_fingerprint, 1238192407, // Mar 27 22:20:07 2009 GMT @@ -262,8 +262,8 @@ TEST(X509CertificateTest, GoogleCertParsing) { } TEST(X509CertificateTest, WebkitCertParsing) { - scoped_refptr<X509Certificate> webkit_cert = X509Certificate::CreateFromBytes( - reinterpret_cast<const char*>(webkit_der), sizeof(webkit_der)); + scoped_refptr<X509Certificate> webkit_cert(X509Certificate::CreateFromBytes( + reinterpret_cast<const char*>(webkit_der), sizeof(webkit_der))); ASSERT_NE(static_cast<X509Certificate*>(NULL), webkit_cert); @@ -318,8 +318,8 @@ TEST(X509CertificateTest, WebkitCertParsing) { } TEST(X509CertificateTest, ThawteCertParsing) { - scoped_refptr<X509Certificate> thawte_cert = X509Certificate::CreateFromBytes( - reinterpret_cast<const char*>(thawte_der), sizeof(thawte_der)); + scoped_refptr<X509Certificate> thawte_cert(X509Certificate::CreateFromBytes( + reinterpret_cast<const char*>(thawte_der), sizeof(thawte_der))); ASSERT_NE(static_cast<X509Certificate*>(NULL), thawte_cert); @@ -379,10 +379,10 @@ TEST(X509CertificateTest, ThawteCertParsing) { } TEST(X509CertificateTest, PaypalNullCertParsing) { - scoped_refptr<X509Certificate> paypal_null_cert = + scoped_refptr<X509Certificate> paypal_null_cert( X509Certificate::CreateFromBytes( reinterpret_cast<const char*>(paypal_null_der), - sizeof(paypal_null_der)); + sizeof(paypal_null_der))); ASSERT_NE(static_cast<X509Certificate*>(NULL), paypal_null_cert); @@ -409,8 +409,8 @@ TEST(X509CertificateTest, PaypalNullCertParsing) { // This certificate will expire on 2011-09-08. TEST(X509CertificateTest, UnoSoftCertParsing) { FilePath certs_dir = GetTestCertsDirectory(); - scoped_refptr<X509Certificate> unosoft_hu_cert = - ImportCertFromFile(certs_dir, "unosoft_hu_cert.der"); + scoped_refptr<X509Certificate> unosoft_hu_cert( + ImportCertFromFile(certs_dir, "unosoft_hu_cert.der")); ASSERT_NE(static_cast<X509Certificate*>(NULL), unosoft_hu_cert); @@ -481,18 +481,18 @@ TEST(X509CertificateTest, Cache) { // certificate cache. google_cert_handle = X509Certificate::CreateOSCertHandleFromBytes( reinterpret_cast<const char*>(google_der), sizeof(google_der)); - scoped_refptr<X509Certificate> cert1 = X509Certificate::CreateFromHandle( + scoped_refptr<X509Certificate> cert1(X509Certificate::CreateFromHandle( google_cert_handle, X509Certificate::SOURCE_LONE_CERT_IMPORT, - X509Certificate::OSCertHandles()); + X509Certificate::OSCertHandles())); X509Certificate::FreeOSCertHandle(google_cert_handle); // Add a certificate from the same source (SOURCE_LONE_CERT_IMPORT). This // should return the cached certificate (cert1). google_cert_handle = X509Certificate::CreateOSCertHandleFromBytes( reinterpret_cast<const char*>(google_der), sizeof(google_der)); - scoped_refptr<X509Certificate> cert2 = X509Certificate::CreateFromHandle( + scoped_refptr<X509Certificate> cert2(X509Certificate::CreateFromHandle( google_cert_handle, X509Certificate::SOURCE_LONE_CERT_IMPORT, - X509Certificate::OSCertHandles()); + X509Certificate::OSCertHandles())); X509Certificate::FreeOSCertHandle(google_cert_handle); EXPECT_EQ(cert1, cert2); @@ -501,9 +501,9 @@ TEST(X509CertificateTest, Cache) { // cached certificate (cert1) and return a new certificate. google_cert_handle = X509Certificate::CreateOSCertHandleFromBytes( reinterpret_cast<const char*>(google_der), sizeof(google_der)); - scoped_refptr<X509Certificate> cert3 = X509Certificate::CreateFromHandle( + scoped_refptr<X509Certificate> cert3(X509Certificate::CreateFromHandle( google_cert_handle, X509Certificate::SOURCE_FROM_NETWORK, - X509Certificate::OSCertHandles()); + X509Certificate::OSCertHandles())); X509Certificate::FreeOSCertHandle(google_cert_handle); EXPECT_NE(cert1, cert3); @@ -512,43 +512,43 @@ TEST(X509CertificateTest, Cache) { // certificate (cert3). google_cert_handle = X509Certificate::CreateOSCertHandleFromBytes( reinterpret_cast<const char*>(google_der), sizeof(google_der)); - scoped_refptr<X509Certificate> cert4 = X509Certificate::CreateFromHandle( + scoped_refptr<X509Certificate> cert4(X509Certificate::CreateFromHandle( google_cert_handle, X509Certificate::SOURCE_FROM_NETWORK, - X509Certificate::OSCertHandles()); + X509Certificate::OSCertHandles())); X509Certificate::FreeOSCertHandle(google_cert_handle); EXPECT_EQ(cert3, cert4); google_cert_handle = X509Certificate::CreateOSCertHandleFromBytes( reinterpret_cast<const char*>(google_der), sizeof(google_der)); - scoped_refptr<X509Certificate> cert5 = X509Certificate::CreateFromHandle( + scoped_refptr<X509Certificate> cert5(X509Certificate::CreateFromHandle( google_cert_handle, X509Certificate::SOURCE_FROM_NETWORK, - X509Certificate::OSCertHandles()); + X509Certificate::OSCertHandles())); X509Certificate::FreeOSCertHandle(google_cert_handle); EXPECT_EQ(cert3, cert5); } TEST(X509CertificateTest, Pickle) { - scoped_refptr<X509Certificate> cert1 = X509Certificate::CreateFromBytes( - reinterpret_cast<const char*>(google_der), sizeof(google_der)); + scoped_refptr<X509Certificate> cert1(X509Certificate::CreateFromBytes( + reinterpret_cast<const char*>(google_der), sizeof(google_der))); Pickle pickle; cert1->Persist(&pickle); void* iter = NULL; - scoped_refptr<X509Certificate> cert2 = - X509Certificate::CreateFromPickle(pickle, &iter); + scoped_refptr<X509Certificate> cert2( + X509Certificate::CreateFromPickle(pickle, &iter)); EXPECT_EQ(cert1, cert2); } TEST(X509CertificateTest, Policy) { - scoped_refptr<X509Certificate> google_cert = X509Certificate::CreateFromBytes( - reinterpret_cast<const char*>(google_der), sizeof(google_der)); + scoped_refptr<X509Certificate> google_cert(X509Certificate::CreateFromBytes( + reinterpret_cast<const char*>(google_der), sizeof(google_der))); - scoped_refptr<X509Certificate> webkit_cert = X509Certificate::CreateFromBytes( - reinterpret_cast<const char*>(webkit_der), sizeof(webkit_der)); + scoped_refptr<X509Certificate> webkit_cert(X509Certificate::CreateFromBytes( + reinterpret_cast<const char*>(webkit_der), sizeof(webkit_der))); CertPolicy policy; @@ -581,18 +581,18 @@ TEST(X509CertificateTest, Policy) { #if defined(OS_MACOSX) || defined(OS_WIN) TEST(X509CertificateTest, IntermediateCertificates) { - scoped_refptr<X509Certificate> webkit_cert = + scoped_refptr<X509Certificate> webkit_cert( X509Certificate::CreateFromBytes( - reinterpret_cast<const char*>(webkit_der), sizeof(webkit_der)); + reinterpret_cast<const char*>(webkit_der), sizeof(webkit_der))); - scoped_refptr<X509Certificate> thawte_cert = + scoped_refptr<X509Certificate> thawte_cert( X509Certificate::CreateFromBytes( - reinterpret_cast<const char*>(thawte_der), sizeof(thawte_der)); + reinterpret_cast<const char*>(thawte_der), sizeof(thawte_der))); - scoped_refptr<X509Certificate> paypal_cert = + scoped_refptr<X509Certificate> paypal_cert( X509Certificate::CreateFromBytes( reinterpret_cast<const char*>(paypal_null_der), - sizeof(paypal_null_der)); + sizeof(paypal_null_der))); X509Certificate::OSCertHandle google_handle; // Create object with no intermediates: @@ -645,8 +645,8 @@ TEST(X509CertificateTest, IsIssuedBy) { FilePath certs_dir = GetTestCertsDirectory(); // Test a client certificate from MIT. - scoped_refptr<X509Certificate> mit_davidben_cert = - ImportCertFromFile(certs_dir, "mit.davidben.der"); + scoped_refptr<X509Certificate> mit_davidben_cert( + ImportCertFromFile(certs_dir, "mit.davidben.der")); ASSERT_NE(static_cast<X509Certificate*>(NULL), mit_davidben_cert); CertPrincipal mit_issuer; @@ -662,8 +662,8 @@ TEST(X509CertificateTest, IsIssuedBy) { EXPECT_TRUE(mit_davidben_cert->IsIssuedBy(mit_issuers)); // Test a client certificate from FOAF.ME. - scoped_refptr<X509Certificate> foaf_me_chromium_test_cert = - ImportCertFromFile(certs_dir, "foaf.me.chromium-test-cert.der"); + scoped_refptr<X509Certificate> foaf_me_chromium_test_cert( + ImportCertFromFile(certs_dir, "foaf.me.chromium-test-cert.der")); ASSERT_NE(static_cast<X509Certificate*>(NULL), foaf_me_chromium_test_cert); CertPrincipal foaf_issuer; diff --git a/net/base/x509_certificate_win.cc b/net/base/x509_certificate_win.cc index 380ff3c..9e018fd 100644 --- a/net/base/x509_certificate_win.cc +++ b/net/base/x509_certificate_win.cc @@ -291,48 +291,6 @@ void GetCertChainInfo(PCCERT_CHAIN_CONTEXT chain_context, } } -/////////////////////////////////////////////////////////////////////////// -// -// Functions used by X509Certificate::IsEV -// -/////////////////////////////////////////////////////////////////////////// - -// Constructs a certificate chain starting from the end certificate -// 'cert_context', matching any of the certificate policies. -// -// Returns the certificate chain context on success, or NULL on failure. -// The caller is responsible for freeing the certificate chain context with -// CertFreeCertificateChain. -PCCERT_CHAIN_CONTEXT ConstructCertChain( - PCCERT_CONTEXT cert_context, - const char* const* policies, - int num_policies) { - CERT_CHAIN_PARA chain_para; - memset(&chain_para, 0, sizeof(chain_para)); - chain_para.cbSize = sizeof(chain_para); - chain_para.RequestedUsage.dwType = USAGE_MATCH_TYPE_AND; - chain_para.RequestedUsage.Usage.cUsageIdentifier = 0; - chain_para.RequestedUsage.Usage.rgpszUsageIdentifier = NULL; // LPSTR* - chain_para.RequestedIssuancePolicy.dwType = USAGE_MATCH_TYPE_OR; - chain_para.RequestedIssuancePolicy.Usage.cUsageIdentifier = num_policies; - chain_para.RequestedIssuancePolicy.Usage.rgpszUsageIdentifier = - const_cast<char**>(policies); - PCCERT_CHAIN_CONTEXT chain_context; - if (!CertGetCertificateChain( - NULL, // default chain engine, HCCE_CURRENT_USER - cert_context, - NULL, // current system time - cert_context->hCertStore, // search this store - &chain_para, - CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT | - CERT_CHAIN_CACHE_END_CERT, - NULL, // reserved - &chain_context)) { - return NULL; - } - return chain_context; -} - // Decodes the cert's certificatePolicies extension into a CERT_POLICIES_INFO // structure and stores it in *output. void GetCertPoliciesInfo(PCCERT_CONTEXT cert, @@ -362,18 +320,6 @@ void GetCertPoliciesInfo(PCCERT_CONTEXT cert, output->reset(policies_info); } -// Returns true if the policy is in the array of CERT_POLICY_INFO in -// the CERT_POLICIES_INFO structure. -bool ContainsPolicy(const CERT_POLICIES_INFO* policies_info, - const char* policy) { - int num_policies = policies_info->cPolicyInfo; - for (int i = 0; i < num_policies; i++) { - if (!strcmp(policies_info->rgPolicyInfo[i].pszPolicyIdentifier, policy)) - return true; - } - return false; -} - // Helper function to parse a principal from a WinInet description of that // principal. void ParsePrincipal(const std::string& description, @@ -575,6 +521,33 @@ void X509Certificate::GetDNSNames(std::vector<std::string>* dns_names) const { dns_names->push_back(subject_.common_name); } +class GlobalCertStore { + public: + HCERTSTORE cert_store() { + return cert_store_; + } + + private: + friend struct DefaultSingletonTraits<GlobalCertStore>; + + GlobalCertStore() + : cert_store_(CertOpenStore(CERT_STORE_PROV_MEMORY, 0, NULL, 0, NULL)) { + } + + ~GlobalCertStore() { + CertCloseStore(cert_store_, 0 /* flags */); + } + + const HCERTSTORE cert_store_; + + DISALLOW_COPY_AND_ASSIGN(GlobalCertStore); +}; + +// static +HCERTSTORE X509Certificate::cert_store() { + return Singleton<GlobalCertStore>::get()->cert_store(); +} + int X509Certificate::Verify(const std::string& hostname, int flags, CertVerifyResult* verify_result) const { @@ -610,6 +583,28 @@ int X509Certificate::Verify(const std::string& hostname, // EV requires revocation checking. flags &= ~VERIFY_EV_CERT; } + + // Get the certificatePolicies extension of the certificate. + scoped_ptr_malloc<CERT_POLICIES_INFO> policies_info; + LPSTR ev_policy_oid = NULL; + if (flags & VERIFY_EV_CERT) { + GetCertPoliciesInfo(cert_handle_, &policies_info); + if (policies_info.get()) { + EVRootCAMetadata* metadata = EVRootCAMetadata::GetInstance(); + for (DWORD i = 0; i < policies_info->cPolicyInfo; ++i) { + LPSTR policy_oid = policies_info->rgPolicyInfo[i].pszPolicyIdentifier; + if (metadata->IsEVPolicyOID(policy_oid)) { + ev_policy_oid = policy_oid; + chain_para.RequestedIssuancePolicy.dwType = USAGE_MATCH_TYPE_AND; + chain_para.RequestedIssuancePolicy.Usage.cUsageIdentifier = 1; + chain_para.RequestedIssuancePolicy.Usage.rgpszUsageIdentifier = + &ev_policy_oid; + break; + } + } + } + } + PCCERT_CHAIN_CONTEXT chain_context; // IE passes a non-NULL pTime argument that specifies the current system // time. IE passes CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT as the @@ -625,6 +620,24 @@ int X509Certificate::Verify(const std::string& hostname, &chain_context)) { return MapSecurityError(GetLastError()); } + if (chain_context->TrustStatus.dwErrorStatus & + CERT_TRUST_IS_NOT_VALID_FOR_USAGE) { + ev_policy_oid = NULL; + chain_para.RequestedIssuancePolicy.Usage.cUsageIdentifier = 0; + chain_para.RequestedIssuancePolicy.Usage.rgpszUsageIdentifier = NULL; + CertFreeCertificateChain(chain_context); + if (!CertGetCertificateChain( + NULL, // default chain engine, HCCE_CURRENT_USER + cert_handle_, + NULL, // current system time + cert_handle_->hCertStore, // search this store + &chain_para, + chain_flags, + NULL, // reserved + &chain_context)) { + return MapSecurityError(GetLastError()); + } + } ScopedCertChainContext scoped_chain_context(chain_context); GetCertChainInfo(chain_context, verify_result); @@ -729,8 +742,7 @@ int X509Certificate::Verify(const std::string& hostname, if (IsCertStatusError(verify_result->cert_status)) return MapCertStatusToNetError(verify_result->cert_status); - // TODO(ukai): combine regular cert verification and EV cert verification. - if ((flags & VERIFY_EV_CERT) && VerifyEV()) + if (ev_policy_oid && CheckEV(chain_context, ev_policy_oid)) verify_result->cert_status |= CERT_STATUS_IS_EV; return OK; } @@ -741,16 +753,8 @@ int X509Certificate::Verify(const std::string& hostname, // certificates in the certificate chain according to Section 7 (pp. 11-12) // of the EV Certificate Guidelines Version 1.0 at // http://cabforum.org/EV_Certificate_Guidelines.pdf. -bool X509Certificate::VerifyEV() const { - DCHECK(cert_handle_); - net::EVRootCAMetadata* metadata = net::EVRootCAMetadata::GetInstance(); - - PCCERT_CHAIN_CONTEXT chain_context = ConstructCertChain(cert_handle_, - metadata->GetPolicyOIDs(), metadata->NumPolicyOIDs()); - if (!chain_context) - return false; - ScopedCertChainContext scoped_chain_context(chain_context); - +bool X509Certificate::CheckEV(PCCERT_CHAIN_CONTEXT chain_context, + const char* policy_oid) const { DCHECK(chain_context->cChain != 0); // If the cert doesn't match any of the policies, the // CERT_TRUST_IS_NOT_VALID_FOR_USAGE bit (0x10) in @@ -771,19 +775,16 @@ bool X509Certificate::VerifyEV() const { // Look up the EV policy OID of the root CA. PCCERT_CONTEXT root_cert = element[num_elements - 1]->pCertContext; SHA1Fingerprint fingerprint = CalculateFingerprint(root_cert); - const char* ev_policy_oid = NULL; - if (!metadata->GetPolicyOID(fingerprint, &ev_policy_oid)) - return false; - DCHECK(ev_policy_oid); - - // Get the certificatePolicies extension of the end certificate. - PCCERT_CONTEXT end_cert = element[0]->pCertContext; - scoped_ptr_malloc<CERT_POLICIES_INFO> policies_info; - GetCertPoliciesInfo(end_cert, &policies_info); - if (!policies_info.get()) - return false; + EVRootCAMetadata* metadata = EVRootCAMetadata::GetInstance(); + return metadata->HasEVPolicyOID(fingerprint, policy_oid); +} - return ContainsPolicy(policies_info.get(), ev_policy_oid); +bool X509Certificate::VerifyEV() const { + // We don't call this private method, but we do need to implement it because + // it's defined in x509_certificate.h. We perform EV checking in the + // Verify() above. + NOTREACHED(); + return false; } // static diff --git a/net/base/x509_openssl_util.cc b/net/base/x509_openssl_util.cc new file mode 100644 index 0000000..22ab59a --- /dev/null +++ b/net/base/x509_openssl_util.cc @@ -0,0 +1,113 @@ +// Copyright (c) 2006-2008 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/x509_openssl_util.h" + +#include "base/logging.h" +#include "base/string_number_conversions.h" +#include "base/string_piece.h" +#include "base/time.h" + +namespace net { + +namespace x509_openssl_util { + +namespace { + +// Helper for ParseDate. |*field| must contain at least |field_len| characters. +// |*field| will be advanced by |field_len| on exit. |*ok| is set to false if +// there is an error in parsing the number, but left untouched otherwise. +// Returns the parsed integer. +int ParseIntAndAdvance(const char** field, size_t field_len, bool* ok) { + int result = 0; + *ok &= base::StringToInt(*field, *field + field_len, &result); + *field += field_len; + return result; +} + +} // namespace + +bool ParsePrincipalKeyAndValueByIndex(X509_NAME* name, + int index, + std::string* key, + std::string* value) { + X509_NAME_ENTRY* entry = X509_NAME_get_entry(name, index); + if (!entry) + return false; + + if (key) { + ASN1_OBJECT* object = X509_NAME_ENTRY_get_object(entry); + key->assign(OBJ_nid2sn(OBJ_obj2nid(object))); + } + + ASN1_STRING* data = X509_NAME_ENTRY_get_data(entry); + if (!data) + return false; + + unsigned char* buf = NULL; + int len = ASN1_STRING_to_UTF8(&buf, data); + if (len <= 0) + return false; + + value->assign(reinterpret_cast<const char*>(buf), len); + OPENSSL_free(buf); + return true; +} + +bool ParsePrincipalValueByIndex(X509_NAME* name, + int index, + std::string* value) { + return ParsePrincipalKeyAndValueByIndex(name, index, NULL, value); +} + +bool ParsePrincipalValueByNID(X509_NAME* name, int nid, std::string* value) { + int index = X509_NAME_get_index_by_NID(name, nid, -1); + if (index < 0) + return false; + + return ParsePrincipalValueByIndex(name, index, value); +} + +bool ParseDate(ASN1_TIME* x509_time, base::Time* time) { + if (!x509_time || + (x509_time->type != V_ASN1_UTCTIME && + x509_time->type != V_ASN1_GENERALIZEDTIME)) + return false; + + base::StringPiece str_date(reinterpret_cast<const char*>(x509_time->data), + x509_time->length); + // UTCTime: YYMMDDHHMMSSZ + // GeneralizedTime: YYYYMMDDHHMMSSZ + size_t year_length = x509_time->type == V_ASN1_UTCTIME ? 2 : 4; + + if (str_date.length() < 11 + year_length) + return false; + + const char* field = str_date.data(); + bool valid = true; + base::Time::Exploded exploded = {0}; + + exploded.year = ParseIntAndAdvance(&field, year_length, &valid); + exploded.month = ParseIntAndAdvance(&field, 2, &valid); + exploded.day_of_month = ParseIntAndAdvance(&field, 2, &valid); + exploded.hour = ParseIntAndAdvance(&field, 2, &valid); + exploded.minute = ParseIntAndAdvance(&field, 2, &valid); + exploded.second = ParseIntAndAdvance(&field, 2, &valid); + if (valid && year_length == 2) + exploded.year += exploded.year < 50 ? 2000 : 1900; + + valid &= exploded.HasValidValues(); + + if (!valid) { + NOTREACHED() << "can't parse x509 date " << str_date; + return false; + } + + *time = base::Time::FromUTCExploded(exploded); + return true; +} + +} // namespace x509_openssl_util + +} // namespace net diff --git a/net/base/x509_openssl_util.h b/net/base/x509_openssl_util.h new file mode 100644 index 0000000..5ac511b --- /dev/null +++ b/net/base/x509_openssl_util.h @@ -0,0 +1,39 @@ +// Copyright (c) 2006-2008 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_X509_OPENSSL_UTIL_H_ +#define NET_BASE_X509_OPENSSL_UTIL_H_ +#pragma once + +#include <openssl/asn1.h> +#include <openssl/x509v3.h> + +#include <string> + +namespace base { +class Time; +} // namespace base + +namespace net { + +// A collection of helper functions to fetch data from OpenSSL X509 certificates +// into more convenient std / base datatypes. +namespace x509_openssl_util { + +bool ParsePrincipalKeyAndValueByIndex(X509_NAME* name, + int index, + std::string* key, + std::string* value); + +bool ParsePrincipalValueByIndex(X509_NAME* name, int index, std::string* value); + +bool ParsePrincipalValueByNID(X509_NAME* name, int nid, std::string* value); + +bool ParseDate(ASN1_TIME* x509_time, base::Time* time); + +} // namespace x509_openssl_util + +} // namespace net + +#endif // NET_BASE_X509_OPENSSL_UTIL_H_ diff --git a/net/data/ftp/dir-listing-ls-19 b/net/data/ftp/dir-listing-ls-19 new file mode 100644 index 0000000..c7c66fe --- /dev/null +++ b/net/data/ftp/dir-listing-ls-19 @@ -0,0 +1,2 @@ +drwxr-xr-x 2 0 0 4096 Mar 18 2007 +-rw-r--r-- 1 48 0 4327486 Jun 16 2006 junorelease.zip diff --git a/net/data/ftp/dir-listing-ls-19.expected b/net/data/ftp/dir-listing-ls-19.expected new file mode 100644 index 0000000..9f0f297 --- /dev/null +++ b/net/data/ftp/dir-listing-ls-19.expected @@ -0,0 +1,8 @@ +- +junorelease.zip +4327486 +2006 +6 +16 +0 +0 diff --git a/net/data/valgrind/DIRECTORY_MOVED b/net/data/valgrind/DIRECTORY_MOVED new file mode 100644 index 0000000..96449fe --- /dev/null +++ b/net/data/valgrind/DIRECTORY_MOVED @@ -0,0 +1,4 @@ +For those who got a merge conflict in this directory on update: +The files from this dir has been moved to tools/valgrind/gtest_exclude + +TODO(timurrrr): remove this in a couple of weeks diff --git a/net/data/valgrind/net_unittests.gtest-drmemory_win32.txt b/net/data/valgrind/net_unittests.gtest-drmemory_win32.txt deleted file mode 100644 index 10b8617..0000000 --- a/net/data/valgrind/net_unittests.gtest-drmemory_win32.txt +++ /dev/null @@ -1,14 +0,0 @@ -# See http://crbug.com/51145 -HttpNetworkTransactionTest.* -HttpNetworkLayerTest.GET - -# TODO(timurrrr): investigate these -ClientSocketPoolBaseTest.* -SSLClientSocketTest.* -ProxyResolverJS* -X509CertificateTest.* -UrlToFilenameEncoderTest.* -DirectoryListerTest.* -WebSocketHandshake* -HTTPSRequestTest.* -NetUtilTest.* diff --git a/net/data/valgrind/net_unittests.gtest-memcheck.txt b/net/data/valgrind/net_unittests.gtest-memcheck.txt deleted file mode 100644 index e7f42dd..0000000 --- a/net/data/valgrind/net_unittests.gtest-memcheck.txt +++ /dev/null @@ -1,19 +0,0 @@ -# These tests leak data intentionally, so are inappropriate for Valgrind tests. -# Similar list in ../purify/net_unittests.exe.gtest.txt -# TODO(dkegel): either merge the two files or keep them in sync, -# see http://code.google.com/p/chromium/issues/detail?id=8951 -DiskCacheBackendTest.AppCacheInvalidEntry -DiskCacheBackendTest.AppCacheInvalidEntryRead -DiskCacheBackendTest.AppCacheInvalidEntryWithLoad -DiskCacheBackendTest.InvalidEntry -DiskCacheBackendTest.InvalidEntryRead -DiskCacheBackendTest.InvalidEntryWithLoad -DiskCacheBackendTest.TrimInvalidEntry -DiskCacheBackendTest.TrimInvalidEntry2 -DiskCacheBackendTest.InvalidEntryEnumeration -DiskCacheBackendTest.NewEvictionInvalidEntry -DiskCacheBackendTest.NewEvictionInvalidEntryRead -DiskCacheBackendTest.NewEvictionInvalidEntryWithLoad -DiskCacheBackendTest.NewEvictionTrimInvalidEntry -DiskCacheBackendTest.NewEvictionTrimInvalidEntry2 -DiskCacheBackendTest.NewEvictionInvalidEntryEnumeration diff --git a/net/data/valgrind/net_unittests.gtest-tsan.txt b/net/data/valgrind/net_unittests.gtest-tsan.txt deleted file mode 100644 index 1ddf884..0000000 --- a/net/data/valgrind/net_unittests.gtest-tsan.txt +++ /dev/null @@ -1,18 +0,0 @@ -# These huge tests are flaky and sometimes crash the following tests. -# See http://crbug.com/50346 -DiskCacheEntryTest.*HugeSparse* - -# SPDY tests tend to crash on both Mac and Windows. -# See http://crbug.com/51144 -Spdy/SpdyNetworkTransactionTest.SocketWriteReturnsZero* -# See http://crbug.com/50918 -Spdy/SpdyNetworkTransactionTest.CancelledTransactionSendRst* -# See http://crbug.com/51087 -Spdy* - -# See http://crbug.com/44570 -HttpNetworkTransactionTest.StopsReading204 -# See http://crbug.com/51145 -HttpNetworkTransactionTest.Incomplete100ThenEOF -HttpNetworkTransactionTest.UseAlternateProtocolForNpnSpdyWithExistingSpdySession -HttpNetworkTransactionTest.KeepAliveConnectionEOF diff --git a/net/data/valgrind/net_unittests.gtest-tsan_mac.txt b/net/data/valgrind/net_unittests.gtest-tsan_mac.txt deleted file mode 100644 index 6359e4b..0000000 --- a/net/data/valgrind/net_unittests.gtest-tsan_mac.txt +++ /dev/null @@ -1,8 +0,0 @@ -# WebSocketTest tests are extraordinary slow under ThreadSanitizer, -# (see http://crbug.com/25392) -# TODO(glider): investigate this. -WebSocketTest.* - -# Strange reports from __NSThread__main__ appeared with the new TSan binaries -# See http://crbug.com/38926 -DirectoryLister* diff --git a/net/data/valgrind/net_unittests.gtest-tsan_win32.txt b/net/data/valgrind/net_unittests.gtest-tsan_win32.txt deleted file mode 100644 index b7b6e2c..0000000 --- a/net/data/valgrind/net_unittests.gtest-tsan_win32.txt +++ /dev/null @@ -1,35 +0,0 @@ -# These tests fail due to unknown reasons -# TODO(timurrrr): investigate -CookieMonsterTest.TestLastAccess -SpdyNetwork*Error* -SpdyNetwork*Get* -SpdyNetworkTransactionTest.SynReplyHeadersVary -X509CertificateTest.UnoSoftCertParsing -URLRequestTest.DoNotSaveCookies -URLRequestTest.QuitTest - -# See http://crbug.com/46647 -DiskCacheBackendTest.* - -# See http://crbug.com/53304 -URLRequestTest.* - -# See http://crbug.com/47836 -ClientSocketPoolBaseTest.CancelPendingSocketAtSocketLimit - -# See http://crbug.com/51145 -HttpNetworkTransactionTest.* -HttpNetworkLayerTest.GET - -# Timing out under TSan, see http://crbug.com/59642 -CookieMonsterTest.GarbageCollectionTriggers - -######################################### -# These tests fail if you don't have our SSL certificate installed. -# Please see http://dev.chromium.org/developers/testing#TOC-SSL-tests -# if you think you want to un-comment one of the following lines. -#SSLClientSocketTest.* -#URLRequestTest* -#HTTPSRequestTest.* -#X509CertificateTest.* -#ProxyScriptFetcherTest.* diff --git a/net/data/valgrind/net_unittests.gtest.txt b/net/data/valgrind/net_unittests.gtest.txt deleted file mode 100644 index 0af617c..0000000 --- a/net/data/valgrind/net_unittests.gtest.txt +++ /dev/null @@ -1,6 +0,0 @@ -# Very slow under Valgrind. -KeygenHandlerTest.*SmokeTest -KeygenHandlerTest.*ConcurrencyTest - -# Fails Valgrind with varying stack traces. http://crbug.com/43179 -SpdyNetworkTransactionTest.PostWithEarlySynReply diff --git a/net/data/valgrind/net_unittests.gtest_linux.txt b/net/data/valgrind/net_unittests.gtest_linux.txt deleted file mode 100644 index 1b69eec..0000000 --- a/net/data/valgrind/net_unittests.gtest_linux.txt +++ /dev/null @@ -1,3 +0,0 @@ -# These tests fail due to certificate errors; see http://crbug.com/36770 -HTTPSRequestTest.HTTPSMismatchedTest -SSLClientSocketTest.ConnectMismatched diff --git a/net/data/valgrind/net_unittests.gtest_mac.txt b/net/data/valgrind/net_unittests.gtest_mac.txt deleted file mode 100644 index 57f2365..0000000 --- a/net/data/valgrind/net_unittests.gtest_mac.txt +++ /dev/null @@ -1,2 +0,0 @@ -# Very slow under Valgrind, (see <http://crbug.com/37289>). -KeygenHandlerTest.SmokeTest diff --git a/net/data/valgrind/net_unittests.gtest_wine.txt b/net/data/valgrind/net_unittests.gtest_wine.txt deleted file mode 100644 index 2492f86..0000000 --- a/net/data/valgrind/net_unittests.gtest_wine.txt +++ /dev/null @@ -1,49 +0,0 @@ -# crash Crashes in Wine -# crash-valgrind Crashes in Wine + Valgrind -# dontcare Safe to ignore -# dontcare-hangwin Ignore, hangs on Windows too -# dontcare-winfail Ignore, fails on Windows too -# dontcare-flaky Ignore, flaky test -# dontcare-hang Ignore, hangs we don't care about -# fail Fails, needs triaging or needs to be fixed -# fail-valgrind Fails only under Valgrind -# fail_wine_vmware Fails in Wine under VMware? TODO(dank) clarify -# flaky-valgrind Flaky under Valgrind, needs investigation -# hang Test that hangs for some reason -# hang-valgrind Test that hangs under valgrind, or just takes too long - -# fail -http://bugs.winehq.org/show_bug.cgi?id=20748 -SSLClientSocketTest.Read_Interrupted - -# fail -# https/ssl failing on the bot, bad Wine? TODO(thestig): investigate -HTTPSRequestTest.HTTPSExpiredTest - -# fail -# https/ssl failing on the bot, bad Wine? TODO(thestig): investigate -HTTPSRequestTest.HTTPSGetTest - -# fail -# https/ssl failing on the bot, bad Wine? TODO(thestig): investigate -HTTPSRequestTest.HTTPSMismatchedTest - -# fail -# https/ssl failing on the bot, bad Wine? TODO(thestig): investigate -SSLClientSocketTest.Connect - -# fail -# https/ssl failing on the bot, bad Wine? TODO(thestig): investigate -SSLClientSocketTest.Read - -# fail -# https/ssl failing on the bot, bad Wine? TODO(thestig): investigate -SSLClientSocketTest.Read_FullDuplex - -# fail -# https/ssl failing on the bot, bad Wine? TODO(thestig): investigate -SSLClientSocketTest.Read_SmallChunks - -# fail -# https/ssl failing on the bot, bad Wine? TODO(thestig): investigate -URLRequestTestHTTP.HTTPSToHTTPRedirectNoRefererTest diff --git a/net/data/valgrind/suppressions.txt b/net/data/valgrind/suppressions.txt deleted file mode 100644 index e8cc210..0000000 --- a/net/data/valgrind/suppressions.txt +++ /dev/null @@ -1,39 +0,0 @@ -{ - Test DiskCacheBackendTest.InvalidEntryEnumeration leaks. - Memcheck:Leak - fun:_Znwj - fun:_ZN10disk_cache12StorageBlockINS_12RankingsNodeEE12AllocateDataEv - fun:_ZN10disk_cache12StorageBlockINS_12RankingsNodeEE4LoadEv - fun:_ZN10disk_cache9EntryImpl15LoadNodeAddressEv - fun:_ZN10disk_cache11BackendImpl8NewEntryENS_4AddrEPPNS_9EntryImplEPb - fun:_ZN10disk_cache11BackendImpl10MatchEntryERKSsjb - fun:_ZN10disk_cache11BackendImpl9OpenEntryERKSsPPNS_5EntryE - fun:_ZN49DiskCacheBackendTest_InvalidEntryEnumeration_Test8TestBodyEv - fun:_ZN7testing4Test3RunEv -} -{ - Test DiskCacheBackendTest.InvalidEntryRead leaks. - Memcheck:Leak - fun:_Znwj - fun:_ZN10disk_cache11BackendImpl8NewEntryENS_4AddrEPPNS_9EntryImplEPb - fun:_ZN10disk_cache11BackendImpl10MatchEntryERKSsjb - fun:_ZN10disk_cache11BackendImpl9OpenEntryERKSsPPNS_5EntryE - fun:_ZN42DiskCacheBackendTest_InvalidEntryRead_Test8TestBodyEv - fun:_ZN7testing4Test3RunEv -} -{ - Test DiskCacheBackendTest.InvalidEntryWithLoad leaks. - Memcheck:Leak - fun:_Znwj - fun:_ZN10disk_cache11BackendImpl11CreateEntryERKSsPPNS_5EntryE - fun:_ZN46DiskCacheBackendTest_InvalidEntryWithLoad_Test8TestBodyEv - fun:_ZN7testing4Test3RunEv -} -{ - Test FlipNetworkTransactionTest.WriteError Bug 29004 - Memcheck:Leak - fun:_Znw* - ... - fun:_ZN3net26FlipNetworkTransactionTest17TransactionHelperERKNS_15HttpRequestInfoEPNS_17DelayedSocketDataE - fun:_ZN3net42FlipNetworkTransactionTest_WriteError_Test8TestBodyEv -} diff --git a/net/disk_cache/backend_impl.cc b/net/disk_cache/backend_impl.cc index 0709238..6162a77 100644 --- a/net/disk_cache/backend_impl.cc +++ b/net/disk_cache/backend_impl.cc @@ -13,6 +13,7 @@ #include "base/string_util.h" #include "base/stringprintf.h" #include "base/sys_info.h" +#include "base/thread_restrictions.h" #include "base/time.h" #include "base/timer.h" #include "base/worker_pool.h" @@ -115,6 +116,10 @@ FilePath GetTempCacheName(const FilePath& path, const std::string& name) { // Moves the cache files to a new folder and creates a task to delete them. bool DelayedCacheCleanup(const FilePath& full_path) { + // GetTempCacheName() and MoveCache() use synchronous file + // operations. + base::ThreadRestrictions::ScopedAllowIO allow_io; + FilePath current_path = full_path.StripTrailingSeparators(); FilePath path = current_path.DirName(); @@ -169,13 +174,13 @@ bool SetFieldTrialInfo(int size_group) { // Field trials involve static objects so we have to do this only once. first = false; - scoped_refptr<base::FieldTrial> trial1 = - new base::FieldTrial("CacheSize", 10); + scoped_refptr<base::FieldTrial> trial1( + new base::FieldTrial("CacheSize", 10)); std::string group1 = base::StringPrintf("CacheSizeGroup_%d", size_group); trial1->AppendGroup(group1, base::FieldTrial::kAllRemainingProbability); - scoped_refptr<base::FieldTrial> trial2 = - new base::FieldTrial("CacheThrottle", 100); + scoped_refptr<base::FieldTrial> trial2( + new base::FieldTrial("CacheThrottle", 100)); int group2a = trial2->AppendGroup("CacheThrottle_On", 10); // 10 % in. trial2->AppendGroup("CacheThrottle_Off", 10); // 10 % control. @@ -1310,6 +1315,13 @@ int BackendImpl::RunTaskForTest(Task* task, CompletionCallback* callback) { return net::ERR_IO_PENDING; } +void BackendImpl::ThrottleRequestsForTest(bool throttle) { + if (throttle) + background_queue_.StartQueingOperations(); + else + background_queue_.StopQueingOperations(); +} + int BackendImpl::SelfCheck() { if (!init_) { LOG(ERROR) << "Init failed"; diff --git a/net/disk_cache/backend_impl.h b/net/disk_cache/backend_impl.h index a8880d1..05e5016 100644 --- a/net/disk_cache/backend_impl.h +++ b/net/disk_cache/backend_impl.h @@ -249,6 +249,9 @@ class BackendImpl : public Backend { // deleted after it runs. int RunTaskForTest(Task* task, CompletionCallback* callback); + // Starts or stops throttling requests. + void ThrottleRequestsForTest(bool throttle); + // Peforms a simple self-check, and returns the number of dirty items // or an error code (negative value). int SelfCheck(); diff --git a/net/disk_cache/backend_unittest.cc b/net/disk_cache/backend_unittest.cc index adfc95c..4298456 100644 --- a/net/disk_cache/backend_unittest.cc +++ b/net/disk_cache/backend_unittest.cc @@ -230,7 +230,7 @@ TEST_F(DiskCacheBackendTest, ExternalFiles) { FilePath filename = GetCacheFilePath().AppendASCII("f_000001"); const int kSize = 50; - scoped_refptr<net::IOBuffer> buffer1 = new net::IOBuffer(kSize); + scoped_refptr<net::IOBuffer> buffer1(new net::IOBuffer(kSize)); CacheTestFillBuffer(buffer1->data(), kSize, false); ASSERT_EQ(kSize, file_util::WriteFile(filename, buffer1->data(), kSize)); @@ -241,7 +241,7 @@ TEST_F(DiskCacheBackendTest, ExternalFiles) { entry->Close(); // And verify that the first file is still there. - scoped_refptr<net::IOBuffer> buffer2 = new net::IOBuffer(kSize); + scoped_refptr<net::IOBuffer> buffer2(new net::IOBuffer(kSize)); ASSERT_EQ(kSize, file_util::ReadFile(filename, buffer2->data(), kSize)); EXPECT_EQ(0, memcmp(buffer1->data(), buffer2->data(), kSize)); } @@ -269,7 +269,7 @@ TEST_F(DiskCacheTest, ShutdownWithPendingIO) { ASSERT_EQ(net::OK, cb.GetResult(rv)); const int kSize = 25000; - scoped_refptr<net::IOBuffer> buffer = new net::IOBuffer(kSize); + scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kSize)); CacheTestFillBuffer(buffer->data(), kSize, false); for (int i = 0; i < 10 * 1024 * 1024; i += 64 * 1024) { @@ -319,7 +319,7 @@ TEST_F(DiskCacheTest, ShutdownWithPendingIO2) { ASSERT_EQ(net::OK, cb.GetResult(rv)); const int kSize = 25000; - scoped_refptr<net::IOBuffer> buffer = new net::IOBuffer(kSize); + scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kSize)); CacheTestFillBuffer(buffer->data(), kSize, false); rv = entry->WriteData(0, 0, buffer, kSize, &cb, false); @@ -366,7 +366,7 @@ void DiskCacheBackendTest::BackendSetSize() { disk_cache::Entry* entry; ASSERT_EQ(net::OK, CreateEntry(first, &entry)); - scoped_refptr<net::IOBuffer> buffer = new net::IOBuffer(cache_size); + scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(cache_size)); memset(buffer->data(), 0, cache_size); EXPECT_EQ(cache_size / 10, WriteData(entry, 0, 0, buffer, cache_size / 10, false)) << "normal file"; @@ -497,7 +497,7 @@ void DiskCacheBackendTest::BackendValidEntry() { ASSERT_EQ(net::OK, CreateEntry(key, &entry)); const int kSize = 50; - scoped_refptr<net::IOBuffer> buffer1 = new net::IOBuffer(kSize); + scoped_refptr<net::IOBuffer> buffer1(new net::IOBuffer(kSize)); memset(buffer1->data(), 0, kSize); base::strlcpy(buffer1->data(), "And the data to save", kSize); EXPECT_EQ(kSize, WriteData(entry, 0, 0, buffer1, kSize, false)); @@ -506,7 +506,7 @@ void DiskCacheBackendTest::BackendValidEntry() { ASSERT_EQ(net::OK, OpenEntry(key, &entry)); - scoped_refptr<net::IOBuffer> buffer2 = new net::IOBuffer(kSize); + scoped_refptr<net::IOBuffer> buffer2(new net::IOBuffer(kSize)); memset(buffer2->data(), 0, kSize); EXPECT_EQ(kSize, ReadData(entry, 0, 0, buffer2, kSize)); entry->Close(); @@ -535,7 +535,7 @@ void DiskCacheBackendTest::BackendInvalidEntry() { ASSERT_EQ(net::OK, CreateEntry(key, &entry)); const int kSize = 50; - scoped_refptr<net::IOBuffer> buffer = new net::IOBuffer(kSize); + scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kSize)); memset(buffer->data(), 0, kSize); base::strlcpy(buffer->data(), "And the data to save", kSize); EXPECT_EQ(kSize, WriteData(entry, 0, 0, buffer, kSize, false)); @@ -579,7 +579,7 @@ void DiskCacheBackendTest::BackendInvalidEntryRead() { ASSERT_EQ(net::OK, CreateEntry(key, &entry)); const int kSize = 50; - scoped_refptr<net::IOBuffer> buffer = new net::IOBuffer(kSize); + scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kSize)); memset(buffer->data(), 0, kSize); base::strlcpy(buffer->data(), "And the data to save", kSize); EXPECT_EQ(kSize, WriteData(entry, 0, 0, buffer, kSize, false)); @@ -697,7 +697,7 @@ void DiskCacheBackendTest::BackendTrimInvalidEntry() { disk_cache::Entry* entry; ASSERT_EQ(net::OK, CreateEntry(first, &entry)); - scoped_refptr<net::IOBuffer> buffer = new net::IOBuffer(kSize); + scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kSize)); memset(buffer->data(), 0, kSize); EXPECT_EQ(kSize, WriteData(entry, 0, 0, buffer, kSize, false)); @@ -748,7 +748,7 @@ void DiskCacheBackendTest::BackendTrimInvalidEntry2() { SetMaxSize(kSize * 40); InitCache(); - scoped_refptr<net::IOBuffer> buffer = new net::IOBuffer(kSize); + scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kSize)); memset(buffer->data(), 0, kSize); disk_cache::Entry* entry; @@ -940,7 +940,7 @@ void DiskCacheBackendTest::BackendInvalidEntryEnumeration() { ASSERT_EQ(net::OK, CreateEntry(key, &entry1)); const int kSize = 50; - scoped_refptr<net::IOBuffer> buffer1 = new net::IOBuffer(kSize); + scoped_refptr<net::IOBuffer> buffer1(new net::IOBuffer(kSize)); memset(buffer1->data(), 0, kSize); base::strlcpy(buffer1->data(), "And the data to save", kSize); EXPECT_EQ(kSize, WriteData(entry1, 0, 0, buffer1, kSize, false)); @@ -1574,7 +1574,7 @@ void DiskCacheBackendTest::BackendDisable4() { ASSERT_EQ(net::OK, CreateEntry(key3, &entry3)); const int kBufSize = 20000; - scoped_refptr<net::IOBuffer> buf = new net::IOBuffer(kBufSize); + scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(kBufSize)); memset(buf->data(), 0, kBufSize); EXPECT_EQ(100, WriteData(entry2, 0, 0, buf, 100, false)); EXPECT_EQ(kBufSize, WriteData(entry3, 0, 0, buf, kBufSize, false)); @@ -1840,7 +1840,7 @@ TEST_F(DiskCacheBackendTest, TotalBuffersSize1) { ASSERT_EQ(net::OK, CreateEntry(key, &entry)); const int kSize = 200; - scoped_refptr<net::IOBuffer> buffer = new net::IOBuffer(kSize); + scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kSize)); CacheTestFillBuffer(buffer->data(), kSize, true); for (int i = 0; i < 10; i++) { diff --git a/net/disk_cache/disk_cache_perftest.cc b/net/disk_cache/disk_cache_perftest.cc index 1f1514d..c86955f 100644 --- a/net/disk_cache/disk_cache_perftest.cc +++ b/net/disk_cache/disk_cache_perftest.cc @@ -44,8 +44,8 @@ const int kMaxSize = 16 * 1024 - 1; int TimeWrite(int num_entries, disk_cache::Backend* cache, TestEntries* entries) { const int kSize1 = 200; - scoped_refptr<net::IOBuffer> buffer1 = new net::IOBuffer(kSize1); - scoped_refptr<net::IOBuffer> buffer2 = new net::IOBuffer(kMaxSize); + scoped_refptr<net::IOBuffer> buffer1(new net::IOBuffer(kSize1)); + scoped_refptr<net::IOBuffer> buffer2(new net::IOBuffer(kMaxSize)); CacheTestFillBuffer(buffer1->data(), kSize1, false); CacheTestFillBuffer(buffer2->data(), kMaxSize, false); @@ -95,8 +95,8 @@ int TimeWrite(int num_entries, disk_cache::Backend* cache, int TimeRead(int num_entries, disk_cache::Backend* cache, const TestEntries& entries, bool cold) { const int kSize1 = 200; - scoped_refptr<net::IOBuffer> buffer1 = new net::IOBuffer(kSize1); - scoped_refptr<net::IOBuffer> buffer2 = new net::IOBuffer(kMaxSize); + scoped_refptr<net::IOBuffer> buffer1(new net::IOBuffer(kSize1)); + scoped_refptr<net::IOBuffer> buffer2(new net::IOBuffer(kMaxSize)); CacheTestFillBuffer(buffer1->data(), kSize1, false); CacheTestFillBuffer(buffer2->data(), kMaxSize, false); diff --git a/net/disk_cache/entry_impl.cc b/net/disk_cache/entry_impl.cc index 7fabbe5..ce59270 100644 --- a/net/disk_cache/entry_impl.cc +++ b/net/disk_cache/entry_impl.cc @@ -148,6 +148,7 @@ bool EntryImpl::UserBuffer::PreWrite(int offset, int len) { void EntryImpl::UserBuffer::Truncate(int offset) { DCHECK_GE(offset, 0); DCHECK_GE(offset, offset_); + DVLOG(3) << "Buffer truncate at " << offset << " current " << offset_; offset -= offset_; if (Size() >= offset) @@ -159,6 +160,7 @@ void EntryImpl::UserBuffer::Write(int offset, net::IOBuffer* buf, int len) { DCHECK_GE(len, 0); DCHECK_GE(offset + len, 0); DCHECK_GE(offset, offset_); + DVLOG(3) << "Buffer write at " << offset << " current " << offset_; if (!Size() && offset > kMaxBlockSize) offset_ = offset; @@ -268,6 +270,8 @@ bool EntryImpl::UserBuffer::GrowBuffer(int required, int limit) { if (!grow_allowed_) return false; + DVLOG(3) << "Buffer grow to " << required; + buffer_.reserve(required); return true; } @@ -480,6 +484,7 @@ void EntryImpl::DoomImpl() { int EntryImpl::ReadDataImpl(int index, int offset, net::IOBuffer* buf, int buf_len, CompletionCallback* callback) { DCHECK(node_.Data()->dirty || read_only_); + DVLOG(2) << "Read from " << index << " at " << offset << " : " << buf_len; if (index < 0 || index >= kNumStreams) return net::ERR_INVALID_ARGUMENT; @@ -500,8 +505,8 @@ int EntryImpl::ReadDataImpl(int index, int offset, net::IOBuffer* buf, backend_->OnEvent(Stats::READ_DATA); backend_->OnRead(buf_len); - // We need the current size in disk. - int eof = entry_size - unreported_size_[index]; + Addr address(entry_.Data()->data_addr[index]); + int eof = address.is_initialized() ? entry_size : 0; if (user_buffers_[index].get() && user_buffers_[index]->PreRead(eof, offset, &buf_len)) { // Complete the operation locally. @@ -510,7 +515,7 @@ int EntryImpl::ReadDataImpl(int index, int offset, net::IOBuffer* buf, return buf_len; } - Addr address(entry_.Data()->data_addr[index]); + address.set_value(entry_.Data()->data_addr[index]); DCHECK(address.is_initialized()); if (!address.is_initialized()) return net::ERR_FAILED; @@ -548,6 +553,7 @@ int EntryImpl::WriteDataImpl(int index, int offset, net::IOBuffer* buf, int buf_len, CompletionCallback* callback, bool truncate) { DCHECK(node_.Data()->dirty || read_only_); + DVLOG(2) << "Write to " << index << " at " << offset << " : " << buf_len; if (index < 0 || index >= kNumStreams) return net::ERR_INVALID_ARGUMENT; @@ -1142,14 +1148,20 @@ bool EntryImpl::ImportSeparateFile(int index, int new_size) { bool EntryImpl::PrepareBuffer(int index, int offset, int buf_len) { DCHECK(user_buffers_[index].get()); - if (offset > user_buffers_[index]->End()) { - // We are about to extend the buffer (with zeros), so make sure that we are - // not overwriting anything. + if ((user_buffers_[index]->End() && offset > user_buffers_[index]->End()) || + offset > entry_.Data()->data_size[index]) { + // We are about to extend the buffer or the file (with zeros), so make sure + // that we are not overwriting anything. Addr address(entry_.Data()->data_addr[index]); if (address.is_initialized() && address.is_separate_file()) { - int eof = entry_.Data()->data_size[index]; - if (eof > user_buffers_[index]->Start() && !Flush(index, 0)) + if (!Flush(index, 0)) return false; + // There is an actual file already, and we don't want to keep track of + // its length so we let this operation go straight to disk. + // The only case when a buffer is allowed to extend the file (as in fill + // with zeros before the start) is when there is no file yet to extend. + user_buffers_[index].reset(); + return true; } } @@ -1158,7 +1170,8 @@ bool EntryImpl::PrepareBuffer(int index, int offset, int buf_len) { return false; // Lets try again. - if (!user_buffers_[index]->PreWrite(offset, buf_len)) { + if (offset > user_buffers_[index]->End() || + !user_buffers_[index]->PreWrite(offset, buf_len)) { // We cannot complete the operation with a buffer. DCHECK(!user_buffers_[index]->Size()); DCHECK(!user_buffers_[index]->Start()); @@ -1172,6 +1185,7 @@ bool EntryImpl::Flush(int index, int min_len) { Addr address(entry_.Data()->data_addr[index]); DCHECK(user_buffers_[index].get()); DCHECK(!address.is_initialized() || address.is_separate_file()); + DVLOG(3) << "Flush"; int size = std::max(entry_.Data()->data_size[index], min_len); if (size && !address.is_initialized() && !CreateDataBlock(index, size)) diff --git a/net/disk_cache/entry_unittest.cc b/net/disk_cache/entry_unittest.cc index c4dc705..bea940c 100644 --- a/net/disk_cache/entry_unittest.cc +++ b/net/disk_cache/entry_unittest.cc @@ -76,7 +76,7 @@ class InternalSyncIOTask : public SyncIOTask { // This part of the test runs on the background thread. void DiskCacheEntryTest::InternalSyncIOBackground(disk_cache::Entry* entry) { const int kSize1 = 10; - scoped_refptr<net::IOBuffer> buffer1 = new net::IOBuffer(kSize1); + scoped_refptr<net::IOBuffer> buffer1(new net::IOBuffer(kSize1)); CacheTestFillBuffer(buffer1->data(), kSize1, false); EXPECT_EQ(0, entry->ReadData(0, 0, buffer1, kSize1, NULL)); base::strlcpy(buffer1->data(), "the data", kSize1); @@ -87,8 +87,8 @@ void DiskCacheEntryTest::InternalSyncIOBackground(disk_cache::Entry* entry) { const int kSize2 = 5000; const int kSize3 = 10000; - scoped_refptr<net::IOBuffer> buffer2 = new net::IOBuffer(kSize2); - scoped_refptr<net::IOBuffer> buffer3 = new net::IOBuffer(kSize3); + scoped_refptr<net::IOBuffer> buffer2(new net::IOBuffer(kSize2)); + scoped_refptr<net::IOBuffer> buffer3(new net::IOBuffer(kSize3)); memset(buffer3->data(), 0, kSize3); CacheTestFillBuffer(buffer2->data(), kSize2, false); base::strlcpy(buffer2->data(), "The really big data goes here", kSize2); @@ -179,9 +179,9 @@ void DiskCacheEntryTest::InternalAsyncIO() { const int kSize1 = 10; const int kSize2 = 5000; const int kSize3 = 10000; - scoped_refptr<net::IOBuffer> buffer1 = new net::IOBuffer(kSize1); - scoped_refptr<net::IOBuffer> buffer2 = new net::IOBuffer(kSize2); - scoped_refptr<net::IOBuffer> buffer3 = new net::IOBuffer(kSize3); + scoped_refptr<net::IOBuffer> buffer1(new net::IOBuffer(kSize1)); + scoped_refptr<net::IOBuffer> buffer2(new net::IOBuffer(kSize2)); + scoped_refptr<net::IOBuffer> buffer3(new net::IOBuffer(kSize3)); CacheTestFillBuffer(buffer1->data(), kSize1, false); CacheTestFillBuffer(buffer2->data(), kSize2, false); CacheTestFillBuffer(buffer3->data(), kSize3, false); @@ -298,8 +298,8 @@ class ExternalSyncIOTask : public SyncIOTask { void DiskCacheEntryTest::ExternalSyncIOBackground(disk_cache::Entry* entry) { const int kSize1 = 17000; const int kSize2 = 25000; - scoped_refptr<net::IOBuffer> buffer1 = new net::IOBuffer(kSize1); - scoped_refptr<net::IOBuffer> buffer2 = new net::IOBuffer(kSize2); + scoped_refptr<net::IOBuffer> buffer1(new net::IOBuffer(kSize1)); + scoped_refptr<net::IOBuffer> buffer2(new net::IOBuffer(kSize2)); CacheTestFillBuffer(buffer1->data(), kSize1, false); CacheTestFillBuffer(buffer2->data(), kSize2, false); base::strlcpy(buffer1->data(), "the data", kSize1); @@ -383,9 +383,9 @@ void DiskCacheEntryTest::ExternalAsyncIO() { const int kSize1 = 17000; const int kSize2 = 25000; const int kSize3 = 25000; - scoped_refptr<net::IOBuffer> buffer1 = new net::IOBuffer(kSize1); - scoped_refptr<net::IOBuffer> buffer2 = new net::IOBuffer(kSize2); - scoped_refptr<net::IOBuffer> buffer3 = new net::IOBuffer(kSize3); + scoped_refptr<net::IOBuffer> buffer1(new net::IOBuffer(kSize1)); + scoped_refptr<net::IOBuffer> buffer2(new net::IOBuffer(kSize2)); + scoped_refptr<net::IOBuffer> buffer3(new net::IOBuffer(kSize3)); CacheTestFillBuffer(buffer1->data(), kSize1, false); CacheTestFillBuffer(buffer2->data(), kSize2, false); CacheTestFillBuffer(buffer3->data(), kSize3, false); @@ -475,14 +475,83 @@ TEST_F(DiskCacheEntryTest, MemoryOnlyExternalAsyncIO) { ExternalAsyncIO(); } +TEST_F(DiskCacheEntryTest, RequestThrottling) { + SetDirectMode(); + InitCache(); + disk_cache::Entry* entry = NULL; + ASSERT_EQ(net::OK, CreateEntry("the first key", &entry)); + ASSERT_TRUE(NULL != entry); + + // Let's verify that each IO goes to the right callback object. + CallbackTest cb(true); + + g_cache_tests_error = false; + g_cache_tests_received = 0; + + MessageLoopHelper helper; + + const int kSize = 200; + scoped_refptr<net::IOBuffer> buffer = new net::IOBuffer(kSize); + CacheTestFillBuffer(buffer->data(), kSize, false); + + int expected = 0; + // Start with no throttling. + for (; expected < 10; expected++) { + int ret = entry->WriteData(0, 0, buffer, kSize, &cb, false); + EXPECT_EQ(net::ERR_IO_PENDING, ret); + } + EXPECT_TRUE(helper.WaitUntilCacheIoFinished(expected)); + + // And now with full throttling. + cache_impl_->ThrottleRequestsForTest(true); + for (; expected < 20; expected++) { + int ret = entry->WriteData(0, 0, buffer, kSize, &cb, false); + EXPECT_EQ(net::ERR_IO_PENDING, ret); + } + EXPECT_TRUE(helper.WaitUntilCacheIoFinished(expected)); + + for (; expected < 30; expected++) { + int ret = entry->WriteData(0, 0, buffer, kSize, &cb, false); + EXPECT_EQ(net::ERR_IO_PENDING, ret); + } + // We have 9 queued requests, lets dispatch them all at once. + cache_impl_->ThrottleRequestsForTest(false); + EXPECT_TRUE(helper.WaitUntilCacheIoFinished(expected)); + + cache_impl_->ThrottleRequestsForTest(true); + for (; expected < 40; expected++) { + int ret = entry->WriteData(0, 0, buffer, kSize, &cb, false); + EXPECT_EQ(net::ERR_IO_PENDING, ret); + } + + // We can close the entry and keep receiving notifications. + entry->Close(); + EXPECT_TRUE(helper.WaitUntilCacheIoFinished(expected)); + + ASSERT_EQ(net::OK, OpenEntry("the first key", &entry)); + for (; expected < 50; expected++) { + int ret = entry->WriteData(0, 0, buffer, kSize, &cb, false); + EXPECT_EQ(net::ERR_IO_PENDING, ret); + } + + // ... and even close the cache. + entry->Close(); + delete cache_impl_; + cache_ = cache_impl_ = NULL; + EXPECT_TRUE(helper.WaitUntilCacheIoFinished(expected)); + + EXPECT_FALSE(g_cache_tests_error); + EXPECT_EQ(expected, g_cache_tests_received); +} + void DiskCacheEntryTest::StreamAccess() { disk_cache::Entry* entry = NULL; ASSERT_EQ(net::OK, CreateEntry("the first key", &entry)); ASSERT_TRUE(NULL != entry); const int kBufferSize = 1024; - scoped_refptr<net::IOBuffer> buffer1 = new net::IOBuffer(kBufferSize); - scoped_refptr<net::IOBuffer> buffer2 = new net::IOBuffer(kBufferSize); + scoped_refptr<net::IOBuffer> buffer1(new net::IOBuffer(kBufferSize)); + scoped_refptr<net::IOBuffer> buffer2(new net::IOBuffer(kBufferSize)); const int kNumStreams = 3; for (int i = 0; i < kNumStreams; i++) { @@ -579,7 +648,7 @@ void DiskCacheEntryTest::GetTimes() { Time t3 = Time::Now(); EXPECT_TRUE(t3 > t2); const int kSize = 200; - scoped_refptr<net::IOBuffer> buffer = new net::IOBuffer(kSize); + scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kSize)); EXPECT_EQ(kSize, ReadData(entry, 0, 0, buffer, kSize)); if (type_ == net::APP_CACHE) { EXPECT_TRUE(entry->GetLastUsed() < t2); @@ -614,8 +683,8 @@ void DiskCacheEntryTest::GrowData() { ASSERT_EQ(net::OK, CreateEntry(key1, &entry)); const int kSize = 20000; - scoped_refptr<net::IOBuffer> buffer1 = new net::IOBuffer(kSize); - scoped_refptr<net::IOBuffer> buffer2 = new net::IOBuffer(kSize); + scoped_refptr<net::IOBuffer> buffer1(new net::IOBuffer(kSize)); + scoped_refptr<net::IOBuffer> buffer2(new net::IOBuffer(kSize)); CacheTestFillBuffer(buffer1->data(), kSize, false); memset(buffer2->data(), 0, kSize); @@ -699,8 +768,8 @@ void DiskCacheEntryTest::TruncateData() { const int kSize1 = 20000; const int kSize2 = 20000; - scoped_refptr<net::IOBuffer> buffer1 = new net::IOBuffer(kSize1); - scoped_refptr<net::IOBuffer> buffer2 = new net::IOBuffer(kSize2); + scoped_refptr<net::IOBuffer> buffer1(new net::IOBuffer(kSize1)); + scoped_refptr<net::IOBuffer> buffer2(new net::IOBuffer(kSize2)); CacheTestFillBuffer(buffer1->data(), kSize1, false); memset(buffer2->data(), 0, kSize2); @@ -755,11 +824,6 @@ void DiskCacheEntryTest::TruncateData() { TEST_F(DiskCacheEntryTest, TruncateData) { InitCache(); TruncateData(); - - // We generate asynchronous IO that is not really tracked until completion - // so we just wait here before running the next test. - MessageLoopHelper helper; - helper.WaitUntilCacheIoFinished(1); } TEST_F(DiskCacheEntryTest, TruncateDataNoBuffer) { @@ -767,11 +831,6 @@ TEST_F(DiskCacheEntryTest, TruncateDataNoBuffer) { InitCache(); cache_impl_->SetFlags(disk_cache::kNoBuffering); TruncateData(); - - // We generate asynchronous IO that is not really tracked until completion - // so we just wait here before running the next test. - MessageLoopHelper helper; - helper.WaitUntilCacheIoFinished(1); } TEST_F(DiskCacheEntryTest, MemoryOnlyTruncateData) { @@ -801,7 +860,7 @@ void DiskCacheEntryTest::ZeroLengthIO() { // Lets verify the actual content. const int kSize = 20; const char zeros[kSize] = {}; - scoped_refptr<net::IOBuffer> buffer = new net::IOBuffer(kSize); + scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kSize)); CacheTestFillBuffer(buffer->data(), kSize, false); EXPECT_EQ(kSize, ReadData(entry, 0, 500, buffer, kSize)); @@ -843,8 +902,8 @@ void DiskCacheEntryTest::Buffering() { ASSERT_EQ(net::OK, CreateEntry(key, &entry)); const int kSize = 200; - scoped_refptr<net::IOBuffer> buffer1 = new net::IOBuffer(kSize); - scoped_refptr<net::IOBuffer> buffer2 = new net::IOBuffer(kSize); + scoped_refptr<net::IOBuffer> buffer1(new net::IOBuffer(kSize)); + scoped_refptr<net::IOBuffer> buffer2(new net::IOBuffer(kSize)); CacheTestFillBuffer(buffer1->data(), kSize, true); CacheTestFillBuffer(buffer2->data(), kSize, true); @@ -900,6 +959,16 @@ void DiskCacheEntryTest::Buffering() { EXPECT_EQ(100, ReadData(entry, 1, 23100, buffer2, kSize)); EXPECT_TRUE(!memcmp(buffer2->data(), buffer1->data() + 100, 100)); + // Extend the file again and read before without closing the entry. + EXPECT_EQ(kSize, WriteData(entry, 1, 25000, buffer1, kSize, false)); + EXPECT_EQ(kSize, WriteData(entry, 1, 45000, buffer1, kSize, false)); + CacheTestFillBuffer(buffer2->data(), kSize, true); + EXPECT_EQ(kSize, ReadData(entry, 1, 25000, buffer2, kSize)); + EXPECT_TRUE(!memcmp(buffer2->data(), buffer1->data(), kSize)); + CacheTestFillBuffer(buffer2->data(), kSize, true); + EXPECT_EQ(kSize, ReadData(entry, 1, 45000, buffer2, kSize)); + EXPECT_TRUE(!memcmp(buffer2->data(), buffer1->data(), kSize)); + entry->Close(); } @@ -924,8 +993,8 @@ void DiskCacheEntryTest::SizeChanges() { const int kSize = 200; const char zeros[kSize] = {}; - scoped_refptr<net::IOBuffer> buffer1 = new net::IOBuffer(kSize); - scoped_refptr<net::IOBuffer> buffer2 = new net::IOBuffer(kSize); + scoped_refptr<net::IOBuffer> buffer1(new net::IOBuffer(kSize)); + scoped_refptr<net::IOBuffer> buffer2(new net::IOBuffer(kSize)); CacheTestFillBuffer(buffer1->data(), kSize, true); CacheTestFillBuffer(buffer2->data(), kSize, true); @@ -943,7 +1012,7 @@ void DiskCacheEntryTest::SizeChanges() { EXPECT_TRUE(!memcmp(buffer2->data(), zeros, kSize)); // Read at the end of the old file size. - EXPECT_EQ(35, ReadData(entry, 1, 23000 + kSize - 35, buffer2, kSize)); + EXPECT_EQ(kSize, ReadData(entry, 1, 23000 + kSize - 35, buffer2, kSize)); EXPECT_TRUE(!memcmp(buffer2->data(), buffer1->data() + kSize - 35, 35)); // Read slightly before the last write. @@ -1013,7 +1082,7 @@ void DiskCacheEntryTest::ReuseEntry(int size) { std::string key2("the second key"); ASSERT_EQ(net::OK, CreateEntry(key2, &entry)); - scoped_refptr<net::IOBuffer> buffer = new net::IOBuffer(size); + scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(size)); CacheTestFillBuffer(buffer->data(), size, false); for (int i = 0; i < 15; i++) { @@ -1067,9 +1136,9 @@ void DiskCacheEntryTest::InvalidData() { const int kSize1 = 20000; const int kSize2 = 20000; const int kSize3 = 20000; - scoped_refptr<net::IOBuffer> buffer1 = new net::IOBuffer(kSize1); - scoped_refptr<net::IOBuffer> buffer2 = new net::IOBuffer(kSize2); - scoped_refptr<net::IOBuffer> buffer3 = new net::IOBuffer(kSize3); + scoped_refptr<net::IOBuffer> buffer1(new net::IOBuffer(kSize1)); + scoped_refptr<net::IOBuffer> buffer2(new net::IOBuffer(kSize2)); + scoped_refptr<net::IOBuffer> buffer3(new net::IOBuffer(kSize3)); CacheTestFillBuffer(buffer1->data(), kSize1, false); memset(buffer2->data(), 0, kSize2); @@ -1149,7 +1218,7 @@ TEST_F(DiskCacheEntryTest, ReadWriteDestroyBuffer) { ASSERT_EQ(net::OK, CreateEntry(key, &entry)); const int kSize = 200; - scoped_refptr<net::IOBuffer> buffer = new net::IOBuffer(kSize); + scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kSize)); CacheTestFillBuffer(buffer->data(), kSize, false); TestCompletionCallback cb; @@ -1179,7 +1248,7 @@ void DiskCacheEntryTest::DoomNormalEntry() { entry->Close(); const int kSize = 20000; - scoped_refptr<net::IOBuffer> buffer = new net::IOBuffer(kSize); + scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kSize)); CacheTestFillBuffer(buffer->data(), kSize, true); buffer->data()[19999] = '\0'; @@ -1220,8 +1289,8 @@ void DiskCacheEntryTest::DoomedEntry() { const int kSize1 = 2000; const int kSize2 = 2000; - scoped_refptr<net::IOBuffer> buffer1 = new net::IOBuffer(kSize1); - scoped_refptr<net::IOBuffer> buffer2 = new net::IOBuffer(kSize2); + scoped_refptr<net::IOBuffer> buffer1(new net::IOBuffer(kSize1)); + scoped_refptr<net::IOBuffer> buffer2(new net::IOBuffer(kSize2)); CacheTestFillBuffer(buffer1->data(), kSize1, false); memset(buffer2->data(), 0, kSize2); @@ -1254,7 +1323,7 @@ TEST_F(DiskCacheEntryTest, MemoryOnlyEnumerationWithSparseEntries) { InitCache(); const int kSize = 4096; - scoped_refptr<net::IOBuffer> buf = new net::IOBuffer(kSize); + scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(kSize)); CacheTestFillBuffer(buf->data(), kSize, false); std::string key("the first key"); @@ -1308,7 +1377,7 @@ void VerifyContentSparseIO(disk_cache::Entry* entry, int64 offset, char* buffer, int size) { TestCompletionCallback cb; - scoped_refptr<net::IOBuffer> buf_1 = new net::IOBuffer(size); + scoped_refptr<net::IOBuffer> buf_1(new net::IOBuffer(size)); memset(buf_1->data(), 0, size); int ret = entry->ReadSparseData(offset, buf_1, size, &cb); EXPECT_EQ(size, cb.GetResult(ret)); @@ -1322,8 +1391,8 @@ void DiskCacheEntryTest::BasicSparseIO() { ASSERT_EQ(net::OK, CreateEntry(key, &entry)); const int kSize = 2048; - scoped_refptr<net::IOBuffer> buf_1 = new net::IOBuffer(kSize); - scoped_refptr<net::IOBuffer> buf_2 = new net::IOBuffer(kSize); + scoped_refptr<net::IOBuffer> buf_1(new net::IOBuffer(kSize)); + scoped_refptr<net::IOBuffer> buf_2(new net::IOBuffer(kSize)); CacheTestFillBuffer(buf_1->data(), kSize, false); // Write at offset 0. @@ -1363,8 +1432,8 @@ void DiskCacheEntryTest::HugeSparseIO() { // Write 1.2 MB so that we cover multiple entries. const int kSize = 1200 * 1024; - scoped_refptr<net::IOBuffer> buf_1 = new net::IOBuffer(kSize); - scoped_refptr<net::IOBuffer> buf_2 = new net::IOBuffer(kSize); + scoped_refptr<net::IOBuffer> buf_1(new net::IOBuffer(kSize)); + scoped_refptr<net::IOBuffer> buf_2(new net::IOBuffer(kSize)); CacheTestFillBuffer(buf_1->data(), kSize, false); // Write at offset 0x20F0000 (33 MB - 64 KB). @@ -1394,7 +1463,7 @@ void DiskCacheEntryTest::GetAvailableRange() { ASSERT_EQ(net::OK, CreateEntry(key, &entry)); const int kSize = 16 * 1024; - scoped_refptr<net::IOBuffer> buf = new net::IOBuffer(kSize); + scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(kSize)); CacheTestFillBuffer(buf->data(), kSize, false); // Write at offset 0x20F0000 (33 MB - 64 KB), and 0x20F4400 (33 MB - 47 KB). @@ -1456,7 +1525,7 @@ void DiskCacheEntryTest::CouldBeSparse() { ASSERT_EQ(net::OK, CreateEntry(key, &entry)); const int kSize = 16 * 1024; - scoped_refptr<net::IOBuffer> buf = new net::IOBuffer(kSize); + scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(kSize)); CacheTestFillBuffer(buf->data(), kSize, false); // Write at offset 0x20F0000 (33 MB - 64 KB). @@ -1502,8 +1571,8 @@ TEST_F(DiskCacheEntryTest, MemoryOnlyMisalignedSparseIO) { InitCache(); const int kSize = 8192; - scoped_refptr<net::IOBuffer> buf_1 = new net::IOBuffer(kSize); - scoped_refptr<net::IOBuffer> buf_2 = new net::IOBuffer(kSize); + scoped_refptr<net::IOBuffer> buf_1(new net::IOBuffer(kSize)); + scoped_refptr<net::IOBuffer> buf_2(new net::IOBuffer(kSize)); CacheTestFillBuffer(buf_1->data(), kSize, false); std::string key("the first key"); @@ -1512,8 +1581,8 @@ TEST_F(DiskCacheEntryTest, MemoryOnlyMisalignedSparseIO) { // This loop writes back to back starting from offset 0 and 9000. for (int i = 0; i < kSize; i += 1024) { - scoped_refptr<net::WrappedIOBuffer> buf_3 = - new net::WrappedIOBuffer(buf_1->data() + i); + scoped_refptr<net::WrappedIOBuffer> buf_3( + new net::WrappedIOBuffer(buf_1->data() + i)); VerifySparseIO(entry, i, buf_3, 1024, buf_2); VerifySparseIO(entry, 9000 + i, buf_3, 1024, buf_2); } @@ -1533,7 +1602,7 @@ TEST_F(DiskCacheEntryTest, MemoryOnlyMisalignedGetAvailableRange) { InitCache(); const int kSize = 8192; - scoped_refptr<net::IOBuffer> buf = new net::IOBuffer(kSize); + scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(kSize)); CacheTestFillBuffer(buf->data(), kSize, false); disk_cache::Entry* entry; @@ -1594,7 +1663,7 @@ void DiskCacheEntryTest::DoomSparseEntry() { ASSERT_EQ(net::OK, CreateEntry(key2, &entry2)); const int kSize = 4 * 1024; - scoped_refptr<net::IOBuffer> buf = new net::IOBuffer(kSize); + scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(kSize)); CacheTestFillBuffer(buf->data(), kSize, false); int64 offset = 1024; @@ -1681,7 +1750,7 @@ TEST_F(DiskCacheEntryTest, DoomSparseEntry2) { ASSERT_EQ(net::OK, CreateEntry(key, &entry)); const int kSize = 4 * 1024; - scoped_refptr<net::IOBuffer> buf = new net::IOBuffer(kSize); + scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(kSize)); CacheTestFillBuffer(buf->data(), kSize, false); int64 offset = 1024; @@ -1711,7 +1780,7 @@ void DiskCacheEntryTest::PartialSparseEntry() { // of a sparse entry, at least to write a big range without leaving holes. const int kSize = 4 * 1024; const int kSmallSize = 128; - scoped_refptr<net::IOBuffer> buf1 = new net::IOBuffer(kSize); + scoped_refptr<net::IOBuffer> buf1(new net::IOBuffer(kSize)); CacheTestFillBuffer(buf1->data(), kSize, false); // The first write is just to extend the entry. The third write occupies @@ -1723,7 +1792,7 @@ void DiskCacheEntryTest::PartialSparseEntry() { entry->Close(); ASSERT_EQ(net::OK, OpenEntry(key, &entry)); - scoped_refptr<net::IOBuffer> buf2 = new net::IOBuffer(kSize); + scoped_refptr<net::IOBuffer> buf2(new net::IOBuffer(kSize)); memset(buf2->data(), 0, kSize); EXPECT_EQ(0, ReadSparseData(entry, 8000, buf2, kSize)); @@ -1805,7 +1874,7 @@ TEST_F(DiskCacheEntryTest, CleanupSparseEntry) { ASSERT_EQ(net::OK, CreateEntry(key, &entry)); const int kSize = 4 * 1024; - scoped_refptr<net::IOBuffer> buf1 = new net::IOBuffer(kSize); + scoped_refptr<net::IOBuffer> buf1(new net::IOBuffer(kSize)); CacheTestFillBuffer(buf1->data(), kSize, false); const int k1Meg = 1024 * 1024; @@ -1856,7 +1925,7 @@ TEST_F(DiskCacheEntryTest, CancelSparseIO) { ASSERT_EQ(net::OK, CreateEntry(key, &entry)); const int kSize = 40 * 1024; - scoped_refptr<net::IOBuffer> buf = new net::IOBuffer(kSize); + scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(kSize)); CacheTestFillBuffer(buf->data(), kSize, false); // This will open and write two "real" entries. diff --git a/net/disk_cache/file_posix.cc b/net/disk_cache/file_posix.cc index 9d810c7..a8d74ae 100644 --- a/net/disk_cache/file_posix.cc +++ b/net/disk_cache/file_posix.cc @@ -182,9 +182,9 @@ void BackgroundIO::OnIOSignalled() { void InFlightIO::PostRead(disk_cache::File *file, void* buf, size_t buf_len, size_t offset, disk_cache::FileIOCallback *callback) { - scoped_refptr<BackgroundIO> operation = - new BackgroundIO(file, buf, buf_len, offset, callback, this); - io_list_.insert(operation.get()); + scoped_refptr<BackgroundIO> operation( + new BackgroundIO(file, buf, buf_len, offset, callback, this)); + io_list_.insert(operation); file->AddRef(); // Balanced on InvokeCallback() if (!callback_thread_) @@ -198,9 +198,9 @@ void InFlightIO::PostRead(disk_cache::File *file, void* buf, size_t buf_len, void InFlightIO::PostWrite(disk_cache::File* file, const void* buf, size_t buf_len, size_t offset, disk_cache::FileIOCallback* callback) { - scoped_refptr<BackgroundIO> operation = - new BackgroundIO(file, buf, buf_len, offset, callback, this); - io_list_.insert(operation.get()); + scoped_refptr<BackgroundIO> operation( + new BackgroundIO(file, buf, buf_len, offset, callback, this)); + io_list_.insert(operation); file->AddRef(); // Balanced on InvokeCallback() if (!callback_thread_) @@ -241,7 +241,7 @@ void InFlightIO::InvokeCallback(BackgroundIO* operation, bool cancel_task) { // Release the references acquired in PostRead / PostWrite. operation->file()->Release(); - io_list_.erase(operation); + io_list_.erase(make_scoped_refptr(operation)); callback->OnFileIOComplete(bytes); } diff --git a/net/disk_cache/in_flight_backend_io.cc b/net/disk_cache/in_flight_backend_io.cc index fe53829..d83bd10 100644 --- a/net/disk_cache/in_flight_backend_io.cc +++ b/net/disk_cache/in_flight_backend_io.cc @@ -42,8 +42,9 @@ bool BackendIO::IsEntryOperation() { return operation_ > OP_MAX_BACKEND; } -void BackendIO::ReleaseEntry() { - entry_ = NULL; +// Runs on the background thread. +void BackendIO::ReferenceEntry() { + entry_->AddRef(); } base::TimeDelta BackendIO::ElapsedTime() const { @@ -274,6 +275,8 @@ void BackendIO::ExecuteEntryOperation() { NOTREACHED() << "Invalid Operation"; result_ = net::ERR_UNEXPECTED; } + // We added a reference to protect the queued operation. + entry_->Release(); if (result_ != net::ERR_IO_PENDING) controller_->OnIOComplete(this); } @@ -291,34 +294,34 @@ InFlightBackendIO::~InFlightBackendIO() { } void InFlightBackendIO::Init(CompletionCallback* callback) { - scoped_refptr<BackendIO> operation = new BackendIO(this, backend_, callback); + scoped_refptr<BackendIO> operation(new BackendIO(this, backend_, callback)); operation->Init(); QueueOperation(operation); } void InFlightBackendIO::OpenEntry(const std::string& key, Entry** entry, CompletionCallback* callback) { - scoped_refptr<BackendIO> operation = new BackendIO(this, backend_, callback); + scoped_refptr<BackendIO> operation(new BackendIO(this, backend_, callback)); operation->OpenEntry(key, entry); QueueOperation(operation); } void InFlightBackendIO::CreateEntry(const std::string& key, Entry** entry, CompletionCallback* callback) { - scoped_refptr<BackendIO> operation = new BackendIO(this, backend_, callback); + scoped_refptr<BackendIO> operation(new BackendIO(this, backend_, callback)); operation->CreateEntry(key, entry); QueueOperation(operation); } void InFlightBackendIO::DoomEntry(const std::string& key, CompletionCallback* callback) { - scoped_refptr<BackendIO> operation = new BackendIO(this, backend_, callback); + scoped_refptr<BackendIO> operation(new BackendIO(this, backend_, callback)); operation->DoomEntry(key); QueueOperation(operation); } void InFlightBackendIO::DoomAllEntries(CompletionCallback* callback) { - scoped_refptr<BackendIO> operation = new BackendIO(this, backend_, callback); + scoped_refptr<BackendIO> operation(new BackendIO(this, backend_, callback)); operation->DoomAllEntries(); QueueOperation(operation); } @@ -326,58 +329,58 @@ void InFlightBackendIO::DoomAllEntries(CompletionCallback* callback) { void InFlightBackendIO::DoomEntriesBetween(const base::Time initial_time, const base::Time end_time, CompletionCallback* callback) { - scoped_refptr<BackendIO> operation = new BackendIO(this, backend_, callback); + scoped_refptr<BackendIO> operation(new BackendIO(this, backend_, callback)); operation->DoomEntriesBetween(initial_time, end_time); QueueOperation(operation); } void InFlightBackendIO::DoomEntriesSince(const base::Time initial_time, CompletionCallback* callback) { - scoped_refptr<BackendIO> operation = new BackendIO(this, backend_, callback); + scoped_refptr<BackendIO> operation(new BackendIO(this, backend_, callback)); operation->DoomEntriesSince(initial_time); QueueOperation(operation); } void InFlightBackendIO::OpenNextEntry(void** iter, Entry** next_entry, CompletionCallback* callback) { - scoped_refptr<BackendIO> operation = new BackendIO(this, backend_, callback); + scoped_refptr<BackendIO> operation(new BackendIO(this, backend_, callback)); operation->OpenNextEntry(iter, next_entry); QueueOperation(operation); } void InFlightBackendIO::OpenPrevEntry(void** iter, Entry** prev_entry, CompletionCallback* callback) { - scoped_refptr<BackendIO> operation = new BackendIO(this, backend_, callback); + scoped_refptr<BackendIO> operation(new BackendIO(this, backend_, callback)); operation->OpenPrevEntry(iter, prev_entry); QueueOperation(operation); } void InFlightBackendIO::EndEnumeration(void* iterator) { - scoped_refptr<BackendIO> operation = new BackendIO(this, backend_, NULL); + scoped_refptr<BackendIO> operation(new BackendIO(this, backend_, NULL)); operation->EndEnumeration(iterator); QueueOperation(operation); } void InFlightBackendIO::CloseEntryImpl(EntryImpl* entry) { - scoped_refptr<BackendIO> operation = new BackendIO(this, backend_, NULL); + scoped_refptr<BackendIO> operation(new BackendIO(this, backend_, NULL)); operation->CloseEntryImpl(entry); QueueOperation(operation); } void InFlightBackendIO::DoomEntryImpl(EntryImpl* entry) { - scoped_refptr<BackendIO> operation = new BackendIO(this, backend_, NULL); + scoped_refptr<BackendIO> operation(new BackendIO(this, backend_, NULL)); operation->DoomEntryImpl(entry); QueueOperation(operation); } void InFlightBackendIO::FlushQueue(net::CompletionCallback* callback) { - scoped_refptr<BackendIO> operation = new BackendIO(this, backend_, callback); + scoped_refptr<BackendIO> operation(new BackendIO(this, backend_, callback)); operation->FlushQueue(); QueueOperation(operation); } void InFlightBackendIO::RunTask(Task* task, net::CompletionCallback* callback) { - scoped_refptr<BackendIO> operation = new BackendIO(this, backend_, callback); + scoped_refptr<BackendIO> operation(new BackendIO(this, backend_, callback)); operation->RunTask(task); QueueOperation(operation); } @@ -385,7 +388,7 @@ void InFlightBackendIO::RunTask(Task* task, net::CompletionCallback* callback) { void InFlightBackendIO::ReadData(EntryImpl* entry, int index, int offset, net::IOBuffer* buf, int buf_len, CompletionCallback* callback) { - scoped_refptr<BackendIO> operation = new BackendIO(this, backend_, callback); + scoped_refptr<BackendIO> operation(new BackendIO(this, backend_, callback)); operation->ReadData(entry, index, offset, buf, buf_len); QueueOperation(operation); } @@ -394,7 +397,7 @@ void InFlightBackendIO::WriteData(EntryImpl* entry, int index, int offset, net::IOBuffer* buf, int buf_len, bool truncate, CompletionCallback* callback) { - scoped_refptr<BackendIO> operation = new BackendIO(this, backend_, callback); + scoped_refptr<BackendIO> operation(new BackendIO(this, backend_, callback)); operation->WriteData(entry, index, offset, buf, buf_len, truncate); QueueOperation(operation); } @@ -402,7 +405,7 @@ void InFlightBackendIO::WriteData(EntryImpl* entry, int index, int offset, void InFlightBackendIO::ReadSparseData(EntryImpl* entry, int64 offset, net::IOBuffer* buf, int buf_len, CompletionCallback* callback) { - scoped_refptr<BackendIO> operation = new BackendIO(this, backend_, callback); + scoped_refptr<BackendIO> operation(new BackendIO(this, backend_, callback)); operation->ReadSparseData(entry, offset, buf, buf_len); QueueOperation(operation); } @@ -410,7 +413,7 @@ void InFlightBackendIO::ReadSparseData(EntryImpl* entry, int64 offset, void InFlightBackendIO::WriteSparseData(EntryImpl* entry, int64 offset, net::IOBuffer* buf, int buf_len, CompletionCallback* callback) { - scoped_refptr<BackendIO> operation = new BackendIO(this, backend_, callback); + scoped_refptr<BackendIO> operation(new BackendIO(this, backend_, callback)); operation->WriteSparseData(entry, offset, buf, buf_len); QueueOperation(operation); } @@ -418,28 +421,25 @@ void InFlightBackendIO::WriteSparseData(EntryImpl* entry, int64 offset, void InFlightBackendIO::GetAvailableRange(EntryImpl* entry, int64 offset, int len, int64* start, CompletionCallback* callback) { - scoped_refptr<BackendIO> operation = new BackendIO(this, backend_, callback); + scoped_refptr<BackendIO> operation(new BackendIO(this, backend_, callback)); operation->GetAvailableRange(entry, offset, len, start); QueueOperation(operation); } void InFlightBackendIO::CancelSparseIO(EntryImpl* entry) { - scoped_refptr<BackendIO> operation = new BackendIO(this, backend_, NULL); + scoped_refptr<BackendIO> operation(new BackendIO(this, backend_, NULL)); operation->CancelSparseIO(entry); QueueOperation(operation); } void InFlightBackendIO::ReadyForSparseIO(EntryImpl* entry, CompletionCallback* callback) { - scoped_refptr<BackendIO> operation = new BackendIO(this, backend_, callback); + scoped_refptr<BackendIO> operation(new BackendIO(this, backend_, callback)); operation->ReadyForSparseIO(entry); QueueOperation(operation); } void InFlightBackendIO::WaitForPendingIO() { - // We clear the list first so that we don't post more operations after this - // point. - pending_ops_.clear(); InFlightIO::WaitForPendingIO(); } @@ -455,45 +455,51 @@ void InFlightBackendIO::OnOperationComplete(BackgroundIO* operation, bool cancel) { BackendIO* op = static_cast<BackendIO*>(operation); - if (!op->IsEntryOperation() && !pending_ops_.empty()) { - // Process the next request. Note that invoking the callback may result - // in the backend destruction (and with it this object), so we should deal - // with the next operation before invoking the callback. - PostQueuedOperation(&pending_ops_); - } - if (op->IsEntryOperation()) { backend_->OnOperationCompleted(op->ElapsedTime()); - if (!pending_entry_ops_.empty()) { - PostQueuedOperation(&pending_entry_ops_); - - // If we are not throttling requests anymore, dispatch the whole queue. - if (!queue_entry_ops_) { + if (!pending_ops_.empty() && RemoveFirstQueuedOperation(op)) { + // Process the next request. Note that invoking the callback may result + // in the backend destruction (and with it this object), so we should deal + // with the next operation before invoking the callback. + if (queue_entry_ops_) { + PostQueuedOperation(); + } else { + // If we are not throttling requests anymore, dispatch the whole queue. CACHE_UMA(COUNTS_10000, "FinalQueuedOperations", 0, - pending_entry_ops_.size()); - while (!pending_entry_ops_.empty()) - PostQueuedOperation(&pending_entry_ops_); + pending_ops_.size()); + PostAllQueuedOperations(); } } } if (op->callback() && (!cancel || op->IsEntryOperation())) op->callback()->Run(op->result()); - - if (cancel) - op->ReleaseEntry(); } void InFlightBackendIO::QueueOperation(BackendIO* operation) { if (!operation->IsEntryOperation()) - return QueueOperationToList(operation, &pending_ops_); + return PostOperation(operation); - if (!queue_entry_ops_) + // We have to protect the entry from deletion while it is on the queue. + // If the caller closes the entry right after writing to it, and the write is + // waiting on the queue, we could end up deleting the entry before the write + // operation is actually posted. Sending a task to reference the entry we make + // sure that there is an extra reference before the caller can post a task to + // release its reference. + background_thread_->PostTask(FROM_HERE, + NewRunnableMethod(operation, &BackendIO::ReferenceEntry)); + + bool empty_list = pending_ops_.empty(); + if (!queue_entry_ops_ && empty_list) return PostOperation(operation); - CACHE_UMA(COUNTS_10000, "QueuedOperations", 0, pending_entry_ops_.size()); + CACHE_UMA(COUNTS_10000, "QueuedOperations", 0, pending_ops_.size()); - QueueOperationToList(operation, &pending_entry_ops_); + // We keep the operation that we are executing in the list so that we know + // when it completes. + pending_ops_.push_back(operation); + if (empty_list) + PostOperation(operation); } void InFlightBackendIO::PostOperation(BackendIO* operation) { @@ -502,18 +508,31 @@ void InFlightBackendIO::PostOperation(BackendIO* operation) { OnOperationPosted(operation); } -void InFlightBackendIO::PostQueuedOperation(OperationList* from_list) { - scoped_refptr<BackendIO> next_op = from_list->front(); - from_list->pop_front(); +void InFlightBackendIO::PostQueuedOperation() { + if (pending_ops_.empty()) + return; + + // Keep it in the list until it's done. + scoped_refptr<BackendIO> next_op = pending_ops_.front(); PostOperation(next_op); } -void InFlightBackendIO::QueueOperationToList(BackendIO* operation, - OperationList* list) { - if (list->empty()) - return PostOperation(operation); +void InFlightBackendIO::PostAllQueuedOperations() { + for (OperationList::iterator it = pending_ops_.begin(); + it != pending_ops_.end(); ++it) { + PostOperation(*it); + } + pending_ops_.clear(); +} + +bool InFlightBackendIO::RemoveFirstQueuedOperation(BackendIO* operation) { + DCHECK(!pending_ops_.empty()); + scoped_refptr<BackendIO> next_op = pending_ops_.front(); + if (operation != next_op) + return false; - list->push_back(operation); + pending_ops_.pop_front(); + return true; } } // namespace diff --git a/net/disk_cache/in_flight_backend_io.h b/net/disk_cache/in_flight_backend_io.h index 5eba131..ca239dd 100644 --- a/net/disk_cache/in_flight_backend_io.h +++ b/net/disk_cache/in_flight_backend_io.h @@ -37,7 +37,8 @@ class BackendIO : public BackgroundIO { net::CompletionCallback* callback() { return callback_; } - void ReleaseEntry(); + // Grabs an extra reference of entry_. + void ReferenceEntry(); // Returns the time that has passed since the operation was created. base::TimeDelta ElapsedTime() const; @@ -72,12 +73,10 @@ class BackendIO : public BackgroundIO { private: // There are two types of operations to proxy: regular backend operations are - // queued so that we don't have more than one operation going on at the same - // time (for instance opening an entry and creating the same entry). On the - // other hand, operations targeted to a given entry can be long lived and - // support multiple simultaneous users (multiple reads or writes to the same - // entry), so they are not queued, just posted to the worker thread as they - // come. + // executed sequentially (queued by the message loop). On the other hand, + // operations targeted to a given entry can be long lived and support multiple + // simultaneous users (multiple reads or writes to the same entry), and they + // are subject to throttling, so we keep an explicit queue. enum Operation { OP_NONE = 0, OP_INIT, @@ -200,13 +199,13 @@ class InFlightBackendIO : public InFlightIO { typedef std::list<scoped_refptr<BackendIO> > OperationList; void QueueOperation(BackendIO* operation); void PostOperation(BackendIO* operation); - void PostQueuedOperation(OperationList* from_list); - void QueueOperationToList(BackendIO* operation, OperationList* list); + void PostQueuedOperation(); + void PostAllQueuedOperations(); + bool RemoveFirstQueuedOperation(BackendIO* operation); BackendImpl* backend_; scoped_refptr<base::MessageLoopProxy> background_thread_; - OperationList pending_ops_; // The list of operations to be posted. - OperationList pending_entry_ops_; // Entry (async) operations to be posted. + OperationList pending_ops_; // Entry (async) operations to be posted. bool queue_entry_ops_; // True if we are queuing entry (async) operations. DISALLOW_COPY_AND_ASSIGN(InFlightBackendIO); diff --git a/net/disk_cache/in_flight_io.cc b/net/disk_cache/in_flight_io.cc index 5c859af..ba24d61 100644 --- a/net/disk_cache/in_flight_io.cc +++ b/net/disk_cache/in_flight_io.cc @@ -74,14 +74,14 @@ void InFlightIO::InvokeCallback(BackgroundIO* operation, bool cancel_task) { // Make sure that we remove the operation from the list before invoking the // callback (so that a subsequent cancel does not invoke the callback again). DCHECK(io_list_.find(operation) != io_list_.end()); - io_list_.erase(operation); + io_list_.erase(make_scoped_refptr(operation)); OnOperationComplete(operation, cancel_task); } // Runs on the primary thread. void InFlightIO::OnOperationPosted(BackgroundIO* operation) { DCHECK(callback_thread_->BelongsToCurrentThread()); - io_list_.insert(operation); + io_list_.insert(make_scoped_refptr(operation)); } } // namespace disk_cache diff --git a/net/disk_cache/mem_entry_impl.cc b/net/disk_cache/mem_entry_impl.cc index 8d8bb4c..a9e599c 100644 --- a/net/disk_cache/mem_entry_impl.cc +++ b/net/disk_cache/mem_entry_impl.cc @@ -172,8 +172,8 @@ int MemEntryImpl::ReadSparseData(int64 offset, net::IOBuffer* buf, int buf_len, return net::ERR_INVALID_ARGUMENT; // We will keep using this buffer and adjust the offset in this buffer. - scoped_refptr<net::DrainableIOBuffer> io_buf = - new net::DrainableIOBuffer(buf, buf_len); + scoped_refptr<net::DrainableIOBuffer> io_buf( + new net::DrainableIOBuffer(buf, buf_len)); // Iterate until we have read enough. while (io_buf->BytesRemaining()) { @@ -218,8 +218,8 @@ int MemEntryImpl::WriteSparseData(int64 offset, net::IOBuffer* buf, int buf_len, if (offset < 0 || buf_len < 0) return net::ERR_INVALID_ARGUMENT; - scoped_refptr<net::DrainableIOBuffer> io_buf = - new net::DrainableIOBuffer(buf, buf_len); + scoped_refptr<net::DrainableIOBuffer> io_buf( + new net::DrainableIOBuffer(buf, buf_len)); // This loop walks through child entries continuously starting from |offset| // and writes blocks of data (of maximum size kMaxSparseEntrySize) into each diff --git a/net/disk_cache/sparse_control.cc b/net/disk_cache/sparse_control.cc index e94a1bc..32f44ab 100644 --- a/net/disk_cache/sparse_control.cc +++ b/net/disk_cache/sparse_control.cc @@ -319,8 +319,8 @@ int SparseControl::CreateSparseEntry() { children_map_.Resize(kNumSparseBits, true); // Save the header. The bitmap is saved in the destructor. - scoped_refptr<net::IOBuffer> buf = - new net::WrappedIOBuffer(reinterpret_cast<char*>(&sparse_header_)); + scoped_refptr<net::IOBuffer> buf( + new net::WrappedIOBuffer(reinterpret_cast<char*>(&sparse_header_))); int rv = entry_->WriteData(kSparseIndex, 0, buf, sizeof(sparse_header_), NULL, false); @@ -349,8 +349,8 @@ int SparseControl::OpenSparseEntry(int data_len) { if (map_len > kMaxMapSize || map_len % 4) return net::ERR_CACHE_OPERATION_NOT_SUPPORTED; - scoped_refptr<net::IOBuffer> buf = - new net::WrappedIOBuffer(reinterpret_cast<char*>(&sparse_header_)); + scoped_refptr<net::IOBuffer> buf( + new net::WrappedIOBuffer(reinterpret_cast<char*>(&sparse_header_))); // Read header. int rv = entry_->ReadData(kSparseIndex, 0, buf, sizeof(sparse_header_), NULL); @@ -402,8 +402,8 @@ bool SparseControl::OpenChild() { static_cast<int>(sizeof(child_data_))) return KillChildAndContinue(key, false); - scoped_refptr<net::WrappedIOBuffer> buf = - new net::WrappedIOBuffer(reinterpret_cast<char*>(&child_data_)); + scoped_refptr<net::WrappedIOBuffer> buf( + new net::WrappedIOBuffer(reinterpret_cast<char*>(&child_data_))); // Read signature. int rv = child_->ReadData(kSparseIndex, 0, buf, sizeof(child_data_), NULL); @@ -425,8 +425,8 @@ bool SparseControl::OpenChild() { } void SparseControl::CloseChild() { - scoped_refptr<net::WrappedIOBuffer> buf = - new net::WrappedIOBuffer(reinterpret_cast<char*>(&child_data_)); + scoped_refptr<net::WrappedIOBuffer> buf( + new net::WrappedIOBuffer(reinterpret_cast<char*>(&child_data_))); // Save the allocation bitmap before closing the child entry. int rv = child_->WriteData(kSparseIndex, 0, buf, sizeof(child_data_), @@ -492,8 +492,8 @@ void SparseControl::SetChildBit(bool value) { } void SparseControl::WriteSparseData() { - scoped_refptr<net::IOBuffer> buf = new net::WrappedIOBuffer( - reinterpret_cast<const char*>(children_map_.GetMap())); + scoped_refptr<net::IOBuffer> buf(new net::WrappedIOBuffer( + reinterpret_cast<const char*>(children_map_.GetMap()))); int len = children_map_.ArraySize() * 4; int rv = entry_->WriteData(kSparseIndex, sizeof(sparse_header_), buf, len, @@ -597,8 +597,8 @@ void SparseControl::InitChildData() { memset(&child_data_, 0, sizeof(child_data_)); child_data_.header = sparse_header_; - scoped_refptr<net::WrappedIOBuffer> buf = - new net::WrappedIOBuffer(reinterpret_cast<char*>(&child_data_)); + scoped_refptr<net::WrappedIOBuffer> buf( + new net::WrappedIOBuffer(reinterpret_cast<char*>(&child_data_))); int rv = child_->WriteData(kSparseIndex, 0, buf, sizeof(child_data_), NULL, false); diff --git a/net/disk_cache/stats_histogram.cc b/net/disk_cache/stats_histogram.cc index 06ed1b3..366a7e1 100644 --- a/net/disk_cache/stats_histogram.cc +++ b/net/disk_cache/stats_histogram.cc @@ -42,7 +42,7 @@ scoped_refptr<StatsHistogram> StatsHistogram::StatsHistogramFactoryGet( Histogram* temp_histogram = histogram.get(); StatsHistogram* temp_stats_histogram = static_cast<StatsHistogram*>(temp_histogram); - scoped_refptr<StatsHistogram> return_histogram = temp_stats_histogram; + scoped_refptr<StatsHistogram> return_histogram(temp_stats_histogram); return return_histogram; } @@ -86,4 +86,10 @@ void StatsHistogram::SnapshotSample(SampleSet* sample) const { mutable_me->ClearFlags(kUmaTargetedHistogramFlag); } +Histogram::Inconsistencies StatsHistogram::FindCorruption( + const SampleSet& snapshot) const { + return NO_INCONSISTENCIES; // This class won't monitor inconsistencies. +} + + } // namespace disk_cache diff --git a/net/disk_cache/stats_histogram.h b/net/disk_cache/stats_histogram.h index cbd8f03..499784c 100644 --- a/net/disk_cache/stats_histogram.h +++ b/net/disk_cache/stats_histogram.h @@ -44,6 +44,7 @@ class StatsHistogram : public base::Histogram { virtual Sample ranges(size_t i) const; virtual size_t bucket_count() const; virtual void SnapshotSample(SampleSet* sample) const; + virtual Inconsistencies FindCorruption(const SampleSet& snapshot) const; private: bool init_; diff --git a/net/disk_cache/stress_cache.cc b/net/disk_cache/stress_cache.cc index 98dcbe1..ae2f981 100644 --- a/net/disk_cache/stress_cache.cc +++ b/net/disk_cache/stress_cache.cc @@ -27,7 +27,7 @@ #include "base/at_exit.h" #include "base/command_line.h" -#include "base/debug_util.h" +#include "base/debug/debugger.h" #include "base/file_path.h" #include "base/logging.h" #include "base/message_loop.h" @@ -130,7 +130,7 @@ void StressTheCache(int iteration) { } const int kSize = 4000; - scoped_refptr<net::IOBuffer> buffer = new net::IOBuffer(kSize); + scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kSize)); memset(buffer->data(), 'k', kSize); for (int i = 0;; i++) { @@ -213,7 +213,7 @@ bool StartCrashThread() { void CrashHandler(const std::string& str) { g_crashing = true; - DebugUtil::BreakDebugger(); + base::debug::BreakDebugger(); } // ----------------------------------------------------------------------- diff --git a/net/ftp/ftp_ctrl_response_buffer.cc b/net/ftp/ftp_ctrl_response_buffer.cc index 950e1e0..4aeef1f 100644 --- a/net/ftp/ftp_ctrl_response_buffer.cc +++ b/net/ftp/ftp_ctrl_response_buffer.cc @@ -91,7 +91,7 @@ FtpCtrlResponseBuffer::ParsedLine FtpCtrlResponseBuffer::ParseLine( ParsedLine result; if (line.length() >= 3) { - if (base::StringToInt(line.substr(0, 3), &result.status_code)) + if (base::StringToInt(line.begin(), line.begin() + 3, &result.status_code)) result.has_status_code = (100 <= result.status_code && result.status_code <= 599); if (result.has_status_code && line.length() >= 4 && line[3] == ' ') { diff --git a/net/ftp/ftp_directory_listing_buffer_unittest.cc b/net/ftp/ftp_directory_listing_buffer_unittest.cc index 86fc6e7..683e2f7 100644 --- a/net/ftp/ftp_directory_listing_buffer_unittest.cc +++ b/net/ftp/ftp_directory_listing_buffer_unittest.cc @@ -41,6 +41,7 @@ TEST(FtpDirectoryListingBufferTest, Parse) { "dir-listing-ls-16", "dir-listing-ls-17", "dir-listing-ls-18", + "dir-listing-ls-19", "dir-listing-mlsd-1", "dir-listing-mlsd-2", "dir-listing-netware-1", diff --git a/net/ftp/ftp_directory_listing_parser_ls.cc b/net/ftp/ftp_directory_listing_parser_ls.cc index 89fc3d8..40546c8 100644 --- a/net/ftp/ftp_directory_listing_parser_ls.cc +++ b/net/ftp/ftp_directory_listing_parser_ls.cc @@ -126,8 +126,20 @@ bool FtpDirectoryListingParserLs::ConsumeLine(const string16& line) { // We may receive file names containing spaces, which can make the number of // columns arbitrarily large. We will handle that later. For now just make - // sure we have all the columns that should normally be there. - if (columns.size() < 7U + column_offset) + // sure we have all the columns that should normally be there: + // + // 1. permission listing + // 2. number of links (optional) + // 3. owner name + // 4. group name (optional) + // 5. size in bytes + // 6. month + // 7. day of month + // 8. year or time + // + // The number of optional columns is stored in |column_offset| + // and is between 0 and 2 (inclusive). + if (columns.size() < 6U + column_offset) return false; if (!LooksLikeUnixPermissionsListing(columns[0])) @@ -165,6 +177,14 @@ bool FtpDirectoryListingParserLs::ConsumeLine(const string16& line) { } entry.name = FtpUtil::GetStringPartAfterColumns(line, 6 + column_offset); + + if (entry.name.empty()) { + // Some FTP servers send listing entries with empty names. It's not obvious + // how to display such an entry, so we ignore them. We don't want to make + // the parsing fail at this point though. Other entries can still be useful. + return true; + } + if (entry.type == FtpDirectoryListingEntry::SYMLINK) { string16::size_type pos = entry.name.rfind(ASCIIToUTF16(" -> ")); diff --git a/net/ftp/ftp_directory_listing_parser_ls_unittest.cc b/net/ftp/ftp_directory_listing_parser_ls_unittest.cc index 4b36544..3e777cc 100644 --- a/net/ftp/ftp_directory_listing_parser_ls_unittest.cc +++ b/net/ftp/ftp_directory_listing_parser_ls_unittest.cc @@ -91,6 +91,28 @@ TEST_F(FtpDirectoryListingParserLsTest, Good) { } } +TEST_F(FtpDirectoryListingParserLsTest, Ignored) { + const char* ignored_cases[] = { + "drwxr-xr-x 2 0 0 4096 Mar 18 2007 ", // http://crbug.com/60065 + + // Tests important for security: verify that after we detect the column + // offset we don't try to access invalid memory on malformed input. + "drwxr-xr-x 3 ftp ftp 4096 May 15 18:11", + "drwxr-xr-x 3 ftp 4096 May 15 18:11", + "drwxr-xr-x folder 0 May 15 18:11", + }; + for (size_t i = 0; i < arraysize(ignored_cases); i++) { + SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS "]: %s", i, + ignored_cases[i])); + + net::FtpDirectoryListingParserLs parser(GetMockCurrentTime()); + EXPECT_TRUE(parser.ConsumeLine(UTF8ToUTF16(ignored_cases[i]))); + EXPECT_FALSE(parser.EntryAvailable()); + EXPECT_TRUE(parser.OnEndOfInput()); + EXPECT_FALSE(parser.EntryAvailable()); + } +} + TEST_F(FtpDirectoryListingParserLsTest, Bad) { const char* bad_cases[] = { " foo", @@ -112,12 +134,6 @@ TEST_F(FtpDirectoryListingParserLsTest, Bad) { "d-wx-wx-wt++ 4 ftp 989 512 Dec 8 15:54 incoming", "d-wx-wx-wt$ 4 ftp 989 512 Dec 8 15:54 incoming", "-qqqqqqqqq+ 2 sys 512 Mar 27 2009 pub", - - // Tests important for security: verify that after we detect the column - // offset we don't try to access invalid memory on malformed input. - "drwxr-xr-x 3 ftp ftp 4096 May 15 18:11", - "drwxr-xr-x 3 ftp 4096 May 15 18:11", - "drwxr-xr-x folder 0 May 15 18:11", }; for (size_t i = 0; i < arraysize(bad_cases); i++) { net::FtpDirectoryListingParserLs parser(GetMockCurrentTime()); diff --git a/net/ftp/ftp_directory_listing_parser_mlsd.cc b/net/ftp/ftp_directory_listing_parser_mlsd.cc index fa9a44e..d8ae618 100644 --- a/net/ftp/ftp_directory_listing_parser_mlsd.cc +++ b/net/ftp/ftp_directory_listing_parser_mlsd.cc @@ -28,15 +28,23 @@ bool MlsdDateListingToTime(const string16& text, base::Time* time) { if (text.length() < 14) return false; - if (!base::StringToInt(text.substr(0, 4), &time_exploded.year)) + if (!base::StringToInt(text.begin(), text.begin() + 4, &time_exploded.year)) return false; - if (!base::StringToInt(text.substr(4, 2), &time_exploded.month)) + if (!base::StringToInt(text.begin() + 4, + text.begin() + 6, + &time_exploded.month)) return false; - if (!base::StringToInt(text.substr(6, 2), &time_exploded.day_of_month)) + if (!base::StringToInt(text.begin() + 6, + text.begin() + 8, + &time_exploded.day_of_month)) return false; - if (!base::StringToInt(text.substr(8, 2), &time_exploded.hour)) + if (!base::StringToInt(text.begin() + 8, + text.begin() + 10, + &time_exploded.hour)) return false; - if (!base::StringToInt(text.substr(10, 2), &time_exploded.minute)) + if (!base::StringToInt(text.begin() + 10, + text.begin() + 12, + &time_exploded.minute)) return false; // We don't know the time zone of the server, so just use local time. diff --git a/net/ftp/ftp_network_transaction.cc b/net/ftp/ftp_network_transaction.cc index 02e4be0..bc1c2a9 100644 --- a/net/ftp/ftp_network_transaction.cc +++ b/net/ftp/ftp_network_transaction.cc @@ -977,8 +977,14 @@ int FtpNetworkTransaction::ProcessResponseSIZE( return Stop(ERR_INVALID_RESPONSE); if (size < 0) return Stop(ERR_INVALID_RESPONSE); - response_.expected_content_size = size; - resource_type_ = RESOURCE_TYPE_FILE; + + // Some FTP servers respond with success to the SIZE command + // for directories, and return 0 size. Make sure we don't set + // the resource type to file if that's the case. + if (size > 0) { + response_.expected_content_size = size; + resource_type_ = RESOURCE_TYPE_FILE; + } break; case ERROR_CLASS_INFO_NEEDED: break; @@ -1298,6 +1304,7 @@ void FtpNetworkTransaction::RecordDataConnectionError(int result) { type = NET_ERROR_OK; break; case ERR_ACCESS_DENIED: + case ERR_NETWORK_ACCESS_DENIED: type = NET_ERROR_ACCESS_DENIED; break; case ERR_TIMED_OUT: diff --git a/net/ftp/ftp_network_transaction_unittest.cc b/net/ftp/ftp_network_transaction_unittest.cc index b504ae8..9c9f62e 100644 --- a/net/ftp/ftp_network_transaction_unittest.cc +++ b/net/ftp/ftp_network_transaction_unittest.cc @@ -231,6 +231,27 @@ class FtpSocketDataProviderDirectoryListingWithPasvFallback FtpSocketDataProviderDirectoryListingWithPasvFallback); }; +class FtpSocketDataProviderDirectoryListingZeroSize + : public FtpSocketDataProviderDirectoryListing { + public: + FtpSocketDataProviderDirectoryListingZeroSize() { + } + + virtual MockWriteResult OnWrite(const std::string& data) { + if (InjectFault()) + return MockWriteResult(true, data.length()); + switch (state()) { + case PRE_SIZE: + return Verify("SIZE /\r\n", data, PRE_CWD, "213 0\r\n"); + default: + return FtpSocketDataProviderDirectoryListing::OnWrite(data); + } + } + + private: + DISALLOW_COPY_AND_ASSIGN(FtpSocketDataProviderDirectoryListingZeroSize); +}; + class FtpSocketDataProviderVMSDirectoryListing : public FtpSocketDataProvider { public: FtpSocketDataProviderVMSDirectoryListing() { @@ -385,6 +406,31 @@ class FtpSocketDataProviderFileDownloadWithPasvFallback DISALLOW_COPY_AND_ASSIGN(FtpSocketDataProviderFileDownloadWithPasvFallback); }; +class FtpSocketDataProviderFileDownloadZeroSize + : public FtpSocketDataProviderFileDownload { + public: + FtpSocketDataProviderFileDownloadZeroSize() { + } + + virtual MockWriteResult OnWrite(const std::string& data) { + if (InjectFault()) + return MockWriteResult(true, data.length()); + switch (state()) { + case PRE_SIZE: + return Verify("SIZE /file\r\n", data, PRE_CWD, + "213 0\r\n"); + case PRE_CWD: + return Verify("CWD /file\r\n", data, PRE_RETR, + "550 not a directory\r\n"); + default: + return FtpSocketDataProviderFileDownload::OnWrite(data); + } + } + + private: + DISALLOW_COPY_AND_ASSIGN(FtpSocketDataProviderFileDownloadZeroSize); +}; + class FtpSocketDataProviderVMSFileDownload : public FtpSocketDataProvider { public: FtpSocketDataProviderVMSFileDownload() { @@ -807,6 +853,12 @@ TEST_F(FtpNetworkTransactionTest, DirectoryTransactionMultilineWelcomeShort) { ExecuteTransaction(&ctrl_socket, "ftp://host", OK); } +// Regression test for http://crbug.com/60555. +TEST_F(FtpNetworkTransactionTest, DirectoryTransactionZeroSize) { + FtpSocketDataProviderDirectoryListingZeroSize ctrl_socket; + ExecuteTransaction(&ctrl_socket, "ftp://host", OK); +} + TEST_F(FtpNetworkTransactionTest, DirectoryTransactionVMS) { FtpSocketDataProviderVMSDirectoryListing ctrl_socket; ExecuteTransaction(&ctrl_socket, "ftp://host/dir", OK); @@ -873,6 +925,11 @@ TEST_F(FtpNetworkTransactionTest, DownloadTransactionShortReads5) { ExecuteTransaction(&ctrl_socket, "ftp://host/file", OK); } +TEST_F(FtpNetworkTransactionTest, DownloadTransactionZeroSize) { + FtpSocketDataProviderFileDownloadZeroSize ctrl_socket; + ExecuteTransaction(&ctrl_socket, "ftp://host/file", OK); +} + TEST_F(FtpNetworkTransactionTest, DownloadTransactionVMS) { FtpSocketDataProviderVMSFileDownload ctrl_socket; ExecuteTransaction(&ctrl_socket, "ftp://host/file", OK); diff --git a/net/ftp/ftp_util.cc b/net/ftp/ftp_util.cc index aeb2355..2633e9d 100644 --- a/net/ftp/ftp_util.cc +++ b/net/ftp/ftp_util.cc @@ -162,17 +162,25 @@ bool FtpUtil::LsDateListingToTime(const string16& month, const string16& day, if (!base::StringToInt(rest, &time_exploded.year)) { // Maybe it's time. Does it look like time (HH:MM)? if (rest.length() == 5 && rest[2] == ':') { - if (!base::StringToInt(rest.substr(0, 2), &time_exploded.hour)) + if (!base::StringToInt(rest.begin(), + rest.begin() + 2, + &time_exploded.hour)) return false; - if (!base::StringToInt(rest.substr(3, 2), &time_exploded.minute)) + if (!base::StringToInt(rest.begin() + 3, + rest.begin() + 5, + &time_exploded.minute)) return false; } else if (rest.length() == 4 && rest[1] == ':') { // Sometimes it's just H:MM. - if (!base::StringToInt(rest.substr(0, 1), &time_exploded.hour)) + if (!base::StringToInt(rest.begin(), + rest.begin() + 1, + &time_exploded.hour)) return false; - if (!base::StringToInt(rest.substr(2, 2), &time_exploded.minute)) + if (!base::StringToInt(rest.begin() + 2, + rest.begin() + 4, + &time_exploded.minute)) return false; } else { return false; diff --git a/net/http/des.cc b/net/http/des.cc index a083149..943f612 100644 --- a/net/http/des.cc +++ b/net/http/des.cc @@ -84,7 +84,14 @@ void DESMakeKey(const uint8* raw, uint8* key) { key[7] = DESSetKeyParity((raw[6] << 1)); } -#if defined(USE_NSS) +#if defined(USE_OPENSSL) + +void DESEncrypt(const uint8* key, const uint8* src, uint8* hash) { + // TODO(joth): When implementing consider splitting up this file by platform. + NOTIMPLEMENTED(); +} + +#elif defined(USE_NSS) void DESEncrypt(const uint8* key, const uint8* src, uint8* hash) { CK_MECHANISM_TYPE cipher_mech = CKM_DES_ECB; diff --git a/net/http/disk_cache_based_ssl_host_info.cc b/net/http/disk_cache_based_ssl_host_info.cc index 10b2e15..cd1cac8 100644 --- a/net/http/disk_cache_based_ssl_host_info.cc +++ b/net/http/disk_cache_based_ssl_host_info.cc @@ -13,8 +13,11 @@ namespace net { DiskCacheBasedSSLHostInfo::DiskCacheBasedSSLHostInfo( - const std::string& hostname, HttpCache* http_cache) - : callback_(new CancelableCompletionCallback<DiskCacheBasedSSLHostInfo>( + const std::string& hostname, + const SSLConfig& ssl_config, + HttpCache* http_cache) + : SSLHostInfo(hostname, ssl_config), + callback_(new CancelableCompletionCallback<DiskCacheBasedSSLHostInfo>( ALLOW_THIS_IN_INITIALIZER_LIST(this), &DiskCacheBasedSSLHostInfo::DoLoop)), state_(GET_BACKEND), diff --git a/net/http/disk_cache_based_ssl_host_info.h b/net/http/disk_cache_based_ssl_host_info.h index 51a4a91..1d53b90 100644 --- a/net/http/disk_cache_based_ssl_host_info.h +++ b/net/http/disk_cache_based_ssl_host_info.h @@ -16,8 +16,9 @@ namespace net { -class IOBuffer; class HttpCache; +class IOBuffer; +struct SSLConfig; // DiskCacheBasedSSLHostInfo fetches information about an SSL host from our // standard disk cache. Since the information is defined to be non-sensitive, @@ -25,7 +26,9 @@ class HttpCache; class DiskCacheBasedSSLHostInfo : public SSLHostInfo, public NonThreadSafe { public: - DiskCacheBasedSSLHostInfo(const std::string& hostname, HttpCache* http_cache); + DiskCacheBasedSSLHostInfo(const std::string& hostname, + const SSLConfig& ssl_config, + HttpCache* http_cache); // Implementation of SSLHostInfo virtual void Start(); diff --git a/net/http/http_auth.h b/net/http/http_auth.h index 3611612..0034b1f 100644 --- a/net/http/http_auth.h +++ b/net/http/http_auth.h @@ -133,7 +133,8 @@ class HttpAuth { // // |headers| must be non-NULL and contain the new HTTP response. // - // |target| specifies whether the headers came from a server or proxy. + // |target| specifies whether the authentication challenge response came + // from a server or a proxy. // // |disabled_schemes| are the authentication schemes to ignore. // diff --git a/net/http/http_auth_handler_basic.cc b/net/http/http_auth_handler_basic.cc index 054357a..35b088f 100644 --- a/net/http/http_auth_handler_basic.cc +++ b/net/http/http_auth_handler_basic.cc @@ -41,7 +41,7 @@ bool HttpAuthHandlerBasic::ParseChallenge( std::string realm; while (parameters.GetNext()) { if (LowerCaseEqualsASCII(parameters.name(), "realm")) - realm = parameters.unquoted_value(); + realm = parameters.value(); } if (!parameters.valid()) diff --git a/net/http/http_auth_handler_digest.cc b/net/http/http_auth_handler_digest.cc index f7f178c..82aa9af 100644 --- a/net/http/http_auth_handler_digest.cc +++ b/net/http/http_auth_handler_digest.cc @@ -221,7 +221,7 @@ HttpAuth::AuthorizationResult HttpAuthHandlerDigest::HandleAnotherChallenge( while (parameters.GetNext()) { if (!LowerCaseEqualsASCII(parameters.name(), "stale")) continue; - if (LowerCaseEqualsASCII(parameters.unquoted_value(), "true")) + if (LowerCaseEqualsASCII(parameters.value(), "true")) return HttpAuth::AUTHORIZATION_RESULT_STALE; } @@ -266,14 +266,9 @@ bool HttpAuthHandlerDigest::ParseChallenge( // Loop through all the properties. while (parameters.GetNext()) { - if (parameters.value().empty()) { - DVLOG(1) << "Invalid digest property"; - return false; - } - // FAIL -- couldn't parse a property. if (!ParseChallengeProperty(parameters.name(), - parameters.unquoted_value())) + parameters.value())) return false; } diff --git a/net/http/http_auth_unittest.cc b/net/http/http_auth_unittest.cc index 3068135..63ae3b0 100644 --- a/net/http/http_auth_unittest.cc +++ b/net/http/http_auth_unittest.cc @@ -149,22 +149,22 @@ TEST(HttpAuthTest, ChooseBestChallenge) { TEST(HttpAuthTest, HandleChallengeResponse) { std::string challenge_used; - const char* kMockChallenge = + const char* const kMockChallenge = "HTTP/1.1 401 Unauthorized\n" "WWW-Authenticate: Mock token_here\n"; - const char* kBasicChallenge = + const char* const kBasicChallenge = "HTTP/1.1 401 Unauthorized\n" "WWW-Authenticate: Basic realm=\"happy\"\n"; - const char* kMissingChallenge = + const char* const kMissingChallenge = "HTTP/1.1 401 Unauthorized\n"; - const char* kEmptyChallenge = + const char* const kEmptyChallenge = "HTTP/1.1 401 Unauthorized\n" "WWW-Authenticate: \n"; - const char* kBasicAndMockChallenges = + const char* const kBasicAndMockChallenges = "HTTP/1.1 401 Unauthorized\n" "WWW-Authenticate: Basic realm=\"happy\"\n" "WWW-Authenticate: Mock token_here\n"; - const char* kTwoMockChallenges = + const char* const kTwoMockChallenges = "HTTP/1.1 401 Unauthorized\n" "WWW-Authenticate: Mock token_a\n" "WWW-Authenticate: Mock token_b\n"; @@ -249,9 +249,7 @@ TEST(HttpAuthTest, ChallengeTokenizer) { EXPECT_TRUE(parameters.GetNext()); EXPECT_TRUE(parameters.valid()); EXPECT_EQ(std::string("realm"), parameters.name()); - EXPECT_EQ(std::string("foobar"), parameters.unquoted_value()); - EXPECT_EQ(std::string("\"foobar\""), parameters.value()); - EXPECT_TRUE(parameters.value_is_quoted()); + EXPECT_EQ(std::string("foobar"), parameters.value()); EXPECT_FALSE(parameters.GetNext()); } @@ -268,8 +266,6 @@ TEST(HttpAuthTest, ChallengeTokenizerNoQuotes) { EXPECT_TRUE(parameters.valid()); EXPECT_EQ(std::string("realm"), parameters.name()); EXPECT_EQ(std::string("foobar@baz.com"), parameters.value()); - EXPECT_EQ(std::string("foobar@baz.com"), parameters.unquoted_value()); - EXPECT_FALSE(parameters.value_is_quoted()); EXPECT_FALSE(parameters.GetNext()); } @@ -286,8 +282,6 @@ TEST(HttpAuthTest, ChallengeTokenizerMismatchedQuotes) { EXPECT_TRUE(parameters.valid()); EXPECT_EQ(std::string("realm"), parameters.name()); EXPECT_EQ(std::string("foobar@baz.com"), parameters.value()); - EXPECT_EQ(std::string("foobar@baz.com"), parameters.unquoted_value()); - EXPECT_FALSE(parameters.value_is_quoted()); EXPECT_FALSE(parameters.GetNext()); } @@ -304,7 +298,6 @@ TEST(HttpAuthTest, ChallengeTokenizerMismatchedQuotesNoValue) { EXPECT_TRUE(parameters.valid()); EXPECT_EQ(std::string("realm"), parameters.name()); EXPECT_EQ(std::string(""), parameters.value()); - EXPECT_FALSE(parameters.value_is_quoted()); EXPECT_FALSE(parameters.GetNext()); } @@ -322,15 +315,13 @@ TEST(HttpAuthTest, ChallengeTokenizerMismatchedQuotesSpaces) { EXPECT_TRUE(parameters.valid()); EXPECT_EQ(std::string("realm"), parameters.name()); EXPECT_EQ(std::string("foo bar"), parameters.value()); - EXPECT_EQ(std::string("foo bar"), parameters.unquoted_value()); - EXPECT_FALSE(parameters.value_is_quoted()); EXPECT_FALSE(parameters.GetNext()); } // Use multiple name=value properties with mismatching quote marks in the last // value. TEST(HttpAuthTest, ChallengeTokenizerMismatchedQuotesMultiple) { - std::string challenge_str = "Digest qop=, algorithm=md5, realm=\"foo"; + std::string challenge_str = "Digest qop=auth-int, algorithm=md5, realm=\"foo"; HttpAuth::ChallengeTokenizer challenge(challenge_str.begin(), challenge_str.end()); HttpUtil::NameValuePairsIterator parameters = challenge.param_pairs(); @@ -340,20 +331,15 @@ TEST(HttpAuthTest, ChallengeTokenizerMismatchedQuotesMultiple) { EXPECT_TRUE(parameters.GetNext()); EXPECT_TRUE(parameters.valid()); EXPECT_EQ(std::string("qop"), parameters.name()); - EXPECT_EQ(std::string(""), parameters.value()); - EXPECT_FALSE(parameters.value_is_quoted()); + EXPECT_EQ(std::string("auth-int"), parameters.value()); EXPECT_TRUE(parameters.GetNext()); EXPECT_TRUE(parameters.valid()); EXPECT_EQ(std::string("algorithm"), parameters.name()); EXPECT_EQ(std::string("md5"), parameters.value()); - EXPECT_EQ(std::string("md5"), parameters.unquoted_value()); - EXPECT_FALSE(parameters.value_is_quoted()); EXPECT_TRUE(parameters.GetNext()); EXPECT_TRUE(parameters.valid()); EXPECT_EQ(std::string("realm"), parameters.name()); EXPECT_EQ(std::string("foo"), parameters.value()); - EXPECT_EQ(std::string("foo"), parameters.unquoted_value()); - EXPECT_FALSE(parameters.value_is_quoted()); EXPECT_FALSE(parameters.GetNext()); } @@ -366,12 +352,8 @@ TEST(HttpAuthTest, ChallengeTokenizerNoValue) { EXPECT_TRUE(parameters.valid()); EXPECT_EQ(std::string("Digest"), challenge.scheme()); - EXPECT_TRUE(parameters.GetNext()); - EXPECT_TRUE(parameters.valid()); - EXPECT_EQ(std::string("qop"), parameters.name()); - EXPECT_EQ(std::string(""), parameters.value()); - EXPECT_FALSE(parameters.value_is_quoted()); EXPECT_FALSE(parameters.GetNext()); + EXPECT_FALSE(parameters.valid()); } // Specify multiple properties, comma separated. @@ -388,18 +370,16 @@ TEST(HttpAuthTest, ChallengeTokenizerMultiple) { EXPECT_TRUE(parameters.valid()); EXPECT_EQ(std::string("algorithm"), parameters.name()); EXPECT_EQ(std::string("md5"), parameters.value()); - EXPECT_FALSE(parameters.value_is_quoted()); EXPECT_TRUE(parameters.GetNext()); EXPECT_TRUE(parameters.valid()); EXPECT_EQ(std::string("realm"), parameters.name()); - EXPECT_EQ(std::string("Oblivion"), parameters.unquoted_value()); - EXPECT_TRUE(parameters.value_is_quoted()); + EXPECT_EQ(std::string("Oblivion"), parameters.value()); EXPECT_TRUE(parameters.GetNext()); EXPECT_TRUE(parameters.valid()); EXPECT_EQ(std::string("qop"), parameters.name()); EXPECT_EQ(std::string("auth-int"), parameters.value()); - EXPECT_FALSE(parameters.value_is_quoted()); EXPECT_FALSE(parameters.GetNext()); + EXPECT_TRUE(parameters.valid()); } // Use a challenge which has no property. diff --git a/net/http/http_basic_stream.cc b/net/http/http_basic_stream.cc index ecd692b..433b08e 100644 --- a/net/http/http_basic_stream.cc +++ b/net/http/http_basic_stream.cc @@ -4,33 +4,48 @@ #include "net/http/http_basic_stream.h" +#include "base/stringprintf.h" #include "net/base/io_buffer.h" #include "net/base/net_errors.h" +#include "net/http/http_request_headers.h" +#include "net/http/http_request_info.h" #include "net/http/http_stream_parser.h" +#include "net/http/http_util.h" #include "net/socket/client_socket_handle.h" namespace net { -HttpBasicStream::HttpBasicStream(ClientSocketHandle* connection) +HttpBasicStream::HttpBasicStream(ClientSocketHandle* connection, + bool using_proxy) : read_buf_(new GrowableIOBuffer()), - connection_(connection) { + connection_(connection), + using_proxy_(using_proxy), + request_info_(NULL) { } int HttpBasicStream::InitializeStream(const HttpRequestInfo* request_info, const BoundNetLog& net_log, CompletionCallback* callback) { + request_info_ = request_info; parser_.reset(new HttpStreamParser(connection_.get(), request_info, read_buf_, net_log)); return OK; } -int HttpBasicStream::SendRequest(const std::string& headers, +int HttpBasicStream::SendRequest(const HttpRequestHeaders& headers, UploadDataStream* request_body, HttpResponseInfo* response, CompletionCallback* callback) { DCHECK(parser_.get()); - return parser_->SendRequest(headers, request_body, response, callback); + const std::string path = using_proxy_ ? + HttpUtil::SpecForRequest(request_info_->url) : + HttpUtil::PathForRequest(request_info_->url); + request_line_ = base::StringPrintf("%s %s HTTP/1.1\r\n", + request_info_->method.c_str(), + path.c_str()) + headers.ToString(); + + return parser_->SendRequest(request_line_, request_body, response, callback); } HttpBasicStream::~HttpBasicStream() {} @@ -60,7 +75,7 @@ HttpStream* HttpBasicStream::RenewStreamForAuth() { DCHECK(IsResponseBodyComplete()); DCHECK(!IsMoreDataBuffered()); parser_.reset(); - return new HttpBasicStream(connection_.release()); + return new HttpBasicStream(connection_.release(), using_proxy_); } bool HttpBasicStream::IsResponseBodyComplete() const { diff --git a/net/http/http_basic_stream.h b/net/http/http_basic_stream.h index ffab967..83136c0 100644 --- a/net/http/http_basic_stream.h +++ b/net/http/http_basic_stream.h @@ -23,13 +23,14 @@ class ClientSocketHandle; class GrowableIOBuffer; class HttpResponseInfo; struct HttpRequestInfo; +class HttpRequestHeaders; class HttpStreamParser; class IOBuffer; class UploadDataStream; class HttpBasicStream : public HttpStream { public: - explicit HttpBasicStream(ClientSocketHandle* connection); + HttpBasicStream(ClientSocketHandle* connection, bool using_proxy); virtual ~HttpBasicStream(); // HttpStream methods: @@ -37,7 +38,7 @@ class HttpBasicStream : public HttpStream { const BoundNetLog& net_log, CompletionCallback* callback); - virtual int SendRequest(const std::string& headers, + virtual int SendRequest(const HttpRequestHeaders& headers, UploadDataStream* request_body, HttpResponseInfo* response, CompletionCallback* callback); @@ -76,6 +77,12 @@ class HttpBasicStream : public HttpStream { scoped_ptr<ClientSocketHandle> connection_; + bool using_proxy_; + + std::string request_line_; + + const HttpRequestInfo* request_info_; + DISALLOW_COPY_AND_ASSIGN(HttpBasicStream); }; diff --git a/net/http/http_cache.cc b/net/http/http_cache.cc index eca95ef..0372222 100644 --- a/net/http/http_cache.cc +++ b/net/http/http_cache.cc @@ -267,8 +267,9 @@ class HttpCache::SSLHostInfoFactoryAdaptor : public SSLHostInfoFactory { : http_cache_(http_cache) { } - SSLHostInfo* GetForHost(const std::string& hostname) { - return new DiskCacheBasedSSLHostInfo(hostname, http_cache_); + SSLHostInfo* GetForHost(const std::string& hostname, + const SSLConfig& ssl_config) { + return new DiskCacheBasedSSLHostInfo(hostname, ssl_config, http_cache_); } private: @@ -601,11 +602,10 @@ HttpCache::ActiveEntry* HttpCache::FindActiveEntry(const std::string& key) { } HttpCache::ActiveEntry* HttpCache::ActivateEntry( - const std::string& key, disk_cache::Entry* disk_entry) { - DCHECK(!FindActiveEntry(key)); + DCHECK(!FindActiveEntry(disk_entry->GetKey())); ActiveEntry* entry = new ActiveEntry(disk_entry); - active_entries_[key] = entry; + active_entries_[disk_entry->GetKey()] = entry; return entry; } @@ -990,7 +990,7 @@ void HttpCache::OnIOComplete(int result, PendingOp* pending_op) { fail_requests = true; } else if (item->IsValid()) { key = pending_op->disk_entry->GetKey(); - entry = ActivateEntry(key, pending_op->disk_entry); + entry = ActivateEntry(pending_op->disk_entry); } else { // The writer transaction is gone. if (op == WI_CREATE_ENTRY) diff --git a/net/http/http_cache.h b/net/http/http_cache.h index 255d7b6..0ce22e5 100644 --- a/net/http/http_cache.h +++ b/net/http/http_cache.h @@ -257,10 +257,8 @@ class HttpCache : public HttpTransactionFactory, ActiveEntry* FindActiveEntry(const std::string& key); // Creates a new ActiveEntry and starts tracking it. |disk_entry| is the disk - // cache entry that corresponds to the desired |key|. - // TODO(rvargas): remove the |key| argument. - ActiveEntry* ActivateEntry(const std::string& key, - disk_cache::Entry* disk_entry); + // cache entry. + ActiveEntry* ActivateEntry(disk_cache::Entry* disk_entry); // Deletes an ActiveEntry. void DeactivateEntry(ActiveEntry* entry); diff --git a/net/http/http_cache_transaction.cc b/net/http/http_cache_transaction.cc index 58288f4..873ccf4 100644 --- a/net/http/http_cache_transaction.cc +++ b/net/http/http_cache_transaction.cc @@ -1801,7 +1801,7 @@ int HttpCache::Transaction::WriteResponseInfoToEntry(bool truncated) { DCHECK_EQ(200, response_.headers->response_code()); } - scoped_refptr<PickledIOBuffer> data = new PickledIOBuffer(); + scoped_refptr<PickledIOBuffer> data(new PickledIOBuffer()); response_.Persist(data->pickle(), skip_transient_headers, truncated); data->Done(); diff --git a/net/http/http_cache_unittest.cc b/net/http/http_cache_unittest.cc index eec8098..f71cec9 100644 --- a/net/http/http_cache_unittest.cc +++ b/net/http/http_cache_unittest.cc @@ -573,7 +573,7 @@ class MockHttpCache { int size = disk_entry->GetDataSize(0); TestCompletionCallback cb; - scoped_refptr<net::IOBuffer> buffer = new net::IOBuffer(size); + scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(size)); int rv = disk_entry->ReadData(0, 0, buffer, size, &cb); rv = cb.GetResult(rv); EXPECT_EQ(size, rv); @@ -593,8 +593,8 @@ class MockHttpCache { &pickle, skip_transient_headers, response_truncated); TestCompletionCallback cb; - scoped_refptr<net::WrappedIOBuffer> data = new net::WrappedIOBuffer( - reinterpret_cast<const char*>(pickle.data())); + scoped_refptr<net::WrappedIOBuffer> data(new net::WrappedIOBuffer( + reinterpret_cast<const char*>(pickle.data()))); int len = static_cast<int>(pickle.size()); int rv = disk_entry->WriteData(0, 0, data, len, &cb, true); @@ -951,8 +951,8 @@ const MockTransaction kRangeGET_TransactionOK = { void Verify206Response(std::string response, int start, int end) { std::string raw_headers(net::HttpUtil::AssembleRawHeaders(response.data(), response.size())); - scoped_refptr<net::HttpResponseHeaders> headers = - new net::HttpResponseHeaders(raw_headers); + scoped_refptr<net::HttpResponseHeaders> headers( + new net::HttpResponseHeaders(raw_headers)); ASSERT_EQ(206, headers->response_code()); @@ -1854,7 +1854,7 @@ TEST(HttpCache, SimpleGET_AbandonedCacheRead) { rv = callback.WaitForResult(); ASSERT_EQ(net::OK, rv); - scoped_refptr<net::IOBuffer> buf = new net::IOBuffer(256); + scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(256)); rv = trans->Read(buf, 256, &callback); EXPECT_EQ(net::ERR_IO_PENDING, rv); @@ -3544,7 +3544,7 @@ TEST(HttpCache, RangeGET_Cancel) { EXPECT_EQ(1, cache.disk_cache()->create_count()); // Make sure that the entry has some data stored. - scoped_refptr<net::IOBufferWithSize> buf = new net::IOBufferWithSize(10); + scoped_refptr<net::IOBufferWithSize> buf(new net::IOBufferWithSize(10)); rv = c->trans->Read(buf, buf->size(), &c->callback); if (rv == net::ERR_IO_PENDING) rv = c->callback.WaitForResult(); @@ -3585,7 +3585,7 @@ TEST(HttpCache, RangeGET_Cancel2) { // Make sure that we revalidate the entry and read from the cache (a single // read will return while waiting for the network). - scoped_refptr<net::IOBufferWithSize> buf = new net::IOBufferWithSize(5); + scoped_refptr<net::IOBufferWithSize> buf(new net::IOBufferWithSize(5)); rv = c->trans->Read(buf, buf->size(), &c->callback); EXPECT_EQ(5, c->callback.GetResult(rv)); rv = c->trans->Read(buf, buf->size(), &c->callback); @@ -3631,7 +3631,7 @@ TEST(HttpCache, RangeGET_Cancel3) { // Make sure that we revalidate the entry and read from the cache (a single // read will return while waiting for the network). - scoped_refptr<net::IOBufferWithSize> buf = new net::IOBufferWithSize(5); + scoped_refptr<net::IOBufferWithSize> buf(new net::IOBufferWithSize(5)); rv = c->trans->Read(buf, buf->size(), &c->callback); EXPECT_EQ(5, c->callback.GetResult(rv)); rv = c->trans->Read(buf, buf->size(), &c->callback); @@ -4029,7 +4029,7 @@ TEST(HttpCache, DoomOnDestruction2) { EXPECT_EQ(1, cache.disk_cache()->create_count()); // Make sure that the entry has some data stored. - scoped_refptr<net::IOBufferWithSize> buf = new net::IOBufferWithSize(10); + scoped_refptr<net::IOBufferWithSize> buf(new net::IOBufferWithSize(10)); rv = c->trans->Read(buf, buf->size(), &c->callback); if (rv == net::ERR_IO_PENDING) rv = c->callback.WaitForResult(); @@ -4073,7 +4073,7 @@ TEST(HttpCache, DoomOnDestruction3) { EXPECT_EQ(1, cache.disk_cache()->create_count()); // Make sure that the entry has some data stored. - scoped_refptr<net::IOBufferWithSize> buf = new net::IOBufferWithSize(10); + scoped_refptr<net::IOBufferWithSize> buf(new net::IOBufferWithSize(10)); rv = c->trans->Read(buf, buf->size(), &c->callback); if (rv == net::ERR_IO_PENDING) rv = c->callback.WaitForResult(); @@ -4117,7 +4117,7 @@ TEST(HttpCache, Set_Truncated_Flag) { EXPECT_EQ(1, cache.disk_cache()->create_count()); // Make sure that the entry has some data stored. - scoped_refptr<net::IOBufferWithSize> buf = new net::IOBufferWithSize(10); + scoped_refptr<net::IOBufferWithSize> buf(new net::IOBufferWithSize(10)); rv = c->trans->Read(buf, buf->size(), &c->callback); if (rv == net::ERR_IO_PENDING) rv = c->callback.WaitForResult(); diff --git a/net/http/http_chunked_decoder.cc b/net/http/http_chunked_decoder.cc index 455c9ed..d5b16dd 100644 --- a/net/http/http_chunked_decoder.cc +++ b/net/http/http_chunked_decoder.cc @@ -192,7 +192,7 @@ bool HttpChunkedDecoder::ParseChunkSize(const char* start, int len, int* out) { return false; int parsed_number; - bool ok = base::HexStringToInt(std::string(start, len), &parsed_number); + bool ok = base::HexStringToInt(start, start + len, &parsed_number); if (ok && parsed_number >= 0) { *out = parsed_number; return true; diff --git a/net/http/http_network_transaction.cc b/net/http/http_network_transaction.cc index e0b9c39..bc2d322 100644 --- a/net/http/http_network_transaction.cc +++ b/net/http/http_network_transaction.cc @@ -89,6 +89,7 @@ HttpNetworkTransaction::HttpNetworkTransaction(HttpNetworkSession* session) request_(NULL), headers_valid_(false), logged_response_time_(false), + request_headers_(), read_buf_len_(0), next_state_(STATE_NONE), establishing_tunnel_(false) { @@ -284,7 +285,7 @@ int HttpNetworkTransaction::Read(IOBuffer* buf, int buf_len, State next_state = STATE_NONE; - scoped_refptr<HttpResponseHeaders> headers = GetResponseHeaders(); + scoped_refptr<HttpResponseHeaders> headers(GetResponseHeaders()); if (headers_valid_ && headers.get() && stream_request_.get()) { // We're trying to read the body of the response but we're still trying // to establish an SSL tunnel through the proxy. We can't read these @@ -535,6 +536,8 @@ int HttpNetworkTransaction::DoCreateStreamComplete(int result) { if (result == OK) { next_state_ = STATE_INIT_STREAM; DCHECK(stream_.get()); + } else if (result == ERR_SSL_CLIENT_AUTH_CERT_NEEDED) { + result = HandleCertificateRequest(result); } // At this point we are done with the stream_request_. @@ -552,9 +555,6 @@ int HttpNetworkTransaction::DoInitStreamComplete(int result) { if (result == OK) { next_state_ = STATE_GENERATE_PROXY_AUTH_TOKEN; } else { - if (result == ERR_SSL_CLIENT_AUTH_CERT_NEEDED) - result = HandleCertificateRequest(result); - if (result < 0) result = HandleIOError(result); @@ -624,38 +624,22 @@ int HttpNetworkTransaction::DoSendRequest() { // This is constructed lazily (instead of within our Start method), so that // we have proxy info available. - if (request_headers_.empty() && !response_.was_fetched_via_spdy) { + if (request_headers_.IsEmpty()) { bool using_proxy = (proxy_info_.is_http()|| proxy_info_.is_https()) && !is_https_request(); - const std::string path = using_proxy ? - HttpUtil::SpecForRequest(request_->url) : - HttpUtil::PathForRequest(request_->url); - std::string request_line = base::StringPrintf( - "%s %s HTTP/1.1\r\n", request_->method.c_str(), path.c_str()); - - HttpRequestHeaders request_headers; HttpUtil::BuildRequestHeaders(request_, request_body, auth_controllers_, ShouldApplyServerAuth(), ShouldApplyProxyAuth(), using_proxy, - &request_headers); + &request_headers_); if (session_->network_delegate()) - session_->network_delegate()->OnSendHttpRequest(&request_headers); - - if (net_log_.IsLoggingAllEvents()) { - net_log_.AddEvent( - NetLog::TYPE_HTTP_TRANSACTION_SEND_REQUEST_HEADERS, - new NetLogHttpRequestParameter(request_line, request_headers)); - } - - request_headers_ = request_line + request_headers.ToString(); - } else { - if (net_log_.IsLoggingAllEvents()) { - net_log_.AddEvent( - NetLog::TYPE_HTTP_TRANSACTION_SEND_REQUEST_HEADERS, - new NetLogHttpRequestParameter(request_->url.spec(), - request_->extra_headers)); - } + session_->network_delegate()->OnSendHttpRequest(&request_headers_); + } + if (net_log_.IsLoggingAllEvents()) { + net_log_.AddEvent( + NetLog::TYPE_HTTP_TRANSACTION_SEND_REQUEST_HEADERS, + make_scoped_refptr(new NetLogHttpRequestParameter( + request_->url.spec(), request_->extra_headers))); } headers_valid_ = false; @@ -748,7 +732,7 @@ int HttpNetworkTransaction::DoReadHeadersComplete(int result) { if (net_log_.IsLoggingAllEvents()) { net_log_.AddEvent( NetLog::TYPE_HTTP_TRANSACTION_READ_RESPONSE_HEADERS, - new NetLogHttpResponseParameter(response_.headers)); + make_scoped_refptr(new NetLogHttpResponseParameter(response_.headers))); } if (response_.headers->GetParsedHttpVersion() < HttpVersion(1, 0)) { @@ -1050,7 +1034,7 @@ void HttpNetworkTransaction::ResetStateForAuthRestart() { read_buf_ = NULL; read_buf_len_ = 0; headers_valid_ = false; - request_headers_.clear(); + request_headers_.Clear(); response_ = HttpResponseInfo(); establishing_tunnel_ = false; } @@ -1080,7 +1064,7 @@ void HttpNetworkTransaction::ResetConnectionAndRequestForResend() { // We need to clear request_headers_ because it contains the real request // headers, but we may need to resend the CONNECT request first to recreate // the SSL tunnel. - request_headers_.clear(); + request_headers_.Clear(); next_state_ = STATE_CREATE_STREAM; // Resend the request. } @@ -1094,7 +1078,7 @@ bool HttpNetworkTransaction::ShouldApplyServerAuth() const { } int HttpNetworkTransaction::HandleAuthChallenge() { - scoped_refptr<HttpResponseHeaders> headers = GetResponseHeaders(); + scoped_refptr<HttpResponseHeaders> headers(GetResponseHeaders()); DCHECK(headers); int status = headers->response_code(); @@ -1105,6 +1089,11 @@ int HttpNetworkTransaction::HandleAuthChallenge() { if (target == HttpAuth::AUTH_PROXY && proxy_info_.is_direct()) return ERR_UNEXPECTED_PROXY_AUTH; + // This case can trigger when an HTTPS server responds with a 407 status + // code through a non-authenticating proxy. + if (!auth_controllers_[target].get()) + return ERR_UNEXPECTED_PROXY_AUTH; + int rv = auth_controllers_[target]->HandleAuthChallenge( headers, (request_->load_flags & LOAD_DO_NOT_SEND_AUTH_DATA) != 0, false, net_log_); diff --git a/net/http/http_network_transaction.h b/net/http/http_network_transaction.h index ce0c5bd..255fcdf 100644 --- a/net/http/http_network_transaction.h +++ b/net/http/http_network_transaction.h @@ -17,6 +17,7 @@ #include "net/base/request_priority.h" #include "net/base/ssl_config_service.h" #include "net/http/http_auth.h" +#include "net/http/http_request_headers.h" #include "net/http/http_response_info.h" #include "net/http/http_transaction.h" #include "net/http/stream_factory.h" @@ -222,7 +223,7 @@ class HttpNetworkTransaction : public HttpTransaction, SSLConfig ssl_config_; - std::string request_headers_; + HttpRequestHeaders request_headers_; // The size in bytes of the buffer we use to drain the response body that // we want to throw away. The response body is typically a small error diff --git a/net/http/http_network_transaction_unittest.cc b/net/http/http_network_transaction_unittest.cc index 2066264..b060d7c 100644 --- a/net/http/http_network_transaction_unittest.cc +++ b/net/http/http_network_transaction_unittest.cc @@ -460,6 +460,67 @@ TEST_F(HttpNetworkTransactionTest, } TEST_F(HttpNetworkTransactionTest, + DuplicateContentLengthHeadersNoTransferEncoding) { + MockRead data_reads[] = { + MockRead("HTTP/1.1 200 OK\r\n"), + MockRead("Content-Length: 5\r\n"), + MockRead("Content-Length: 5\r\n\r\n"), + MockRead("Hello"), + }; + SimpleGetHelperResult out = SimpleGetHelper(data_reads, + arraysize(data_reads)); + EXPECT_EQ(OK, out.rv); + EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); + EXPECT_EQ("Hello", out.response_data); +} + +TEST_F(HttpNetworkTransactionTest, + ComplexContentLengthHeadersNoTransferEncoding) { + // More than 2 dupes. + { + MockRead data_reads[] = { + MockRead("HTTP/1.1 200 OK\r\n"), + MockRead("Content-Length: 5\r\n"), + MockRead("Content-Length: 5\r\n"), + MockRead("Content-Length: 5\r\n\r\n"), + MockRead("Hello"), + }; + SimpleGetHelperResult out = SimpleGetHelper(data_reads, + arraysize(data_reads)); + EXPECT_EQ(OK, out.rv); + EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); + EXPECT_EQ("Hello", out.response_data); + } + // HTTP/1.0 + { + MockRead data_reads[] = { + MockRead("HTTP/1.0 200 OK\r\n"), + MockRead("Content-Length: 5\r\n"), + MockRead("Content-Length: 5\r\n"), + MockRead("Content-Length: 5\r\n\r\n"), + MockRead("Hello"), + }; + SimpleGetHelperResult out = SimpleGetHelper(data_reads, + arraysize(data_reads)); + EXPECT_EQ(OK, out.rv); + EXPECT_EQ("HTTP/1.0 200 OK", out.status_line); + EXPECT_EQ("Hello", out.response_data); + } + // 2 dupes and one mismatched. + { + MockRead data_reads[] = { + MockRead("HTTP/1.1 200 OK\r\n"), + MockRead("Content-Length: 10\r\n"), + MockRead("Content-Length: 10\r\n"), + MockRead("Content-Length: 5\r\n\r\n"), + }; + SimpleGetHelperResult out = SimpleGetHelper(data_reads, + arraysize(data_reads)); + EXPECT_EQ(ERR_RESPONSE_HEADERS_MULTIPLE_CONTENT_LENGTH, out.rv); + } +} + +TEST_F(HttpNetworkTransactionTest, MultipleContentLengthHeadersTransferEncoding) { MockRead data_reads[] = { MockRead("HTTP/1.1 200 OK\r\n"), @@ -544,7 +605,7 @@ TEST_F(HttpNetworkTransactionTest, Head) { TEST_F(HttpNetworkTransactionTest, ReuseConnection) { SessionDependencies session_deps; - scoped_refptr<HttpNetworkSession> session = CreateSession(&session_deps); + scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); MockRead data_reads[] = { MockRead("HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\n"), @@ -733,7 +794,7 @@ TEST_F(HttpNetworkTransactionTest, EmptyResponse) { void HttpNetworkTransactionTest::KeepAliveConnectionResendRequestTest( const MockRead& read_failure) { SessionDependencies session_deps; - scoped_refptr<HttpNetworkSession> session = CreateSession(&session_deps); + scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); HttpRequestInfo request; request.method = "GET"; @@ -850,7 +911,7 @@ TEST_F(HttpNetworkTransactionTest, NonKeepAliveConnectionEOF) { // reading the body. TEST_F(HttpNetworkTransactionTest, KeepAliveAfterUnreadBody) { SessionDependencies session_deps; - scoped_refptr<HttpNetworkSession> session = CreateSession(&session_deps); + scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); HttpRequestInfo request; request.method = "GET"; @@ -1707,6 +1768,66 @@ TEST_F(HttpNetworkTransactionTest, UnexpectedProxyAuth) { EXPECT_EQ(ERR_UNEXPECTED_PROXY_AUTH, rv); } +// Tests when an HTTPS server (non-proxy) returns a 407 (proxy-authentication) +// through a non-authenticating proxy. The request should fail with +// ERR_UNEXPECTED_PROXY_AUTH. +// Note that it is impossible to detect if an HTTP server returns a 407 through +// a non-authenticating proxy - there is nothing to indicate whether the +// response came from the proxy or the server, so it is treated as if the proxy +// issued the challenge. +TEST_F(HttpNetworkTransactionTest, HttpsServerRequestsProxyAuthThroughProxy) { + SessionDependencies session_deps(ProxyService::CreateFixed("myproxy:70")); + CapturingBoundNetLog log(CapturingNetLog::kUnbounded); + session_deps.net_log = log.bound().net_log(); + scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); + + HttpRequestInfo request; + request.method = "GET"; + request.url = GURL("https://www.google.com/"); + + // Since we have proxy, should try to establish tunnel. + MockWrite data_writes1[] = { + MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" + "Host: www.google.com\r\n" + "Proxy-Connection: keep-alive\r\n\r\n"), + + MockWrite("GET / HTTP/1.1\r\n" + "Host: www.google.com\r\n" + "Connection: keep-alive\r\n\r\n"), + }; + + MockRead data_reads1[] = { + MockRead("HTTP/1.1 200 Connection Established\r\n\r\n"), + + MockRead("HTTP/1.1 407 Unauthorized\r\n"), + MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"), + MockRead("\r\n"), + MockRead(false, OK), + }; + + StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), + data_writes1, arraysize(data_writes1)); + session_deps.socket_factory.AddSocketDataProvider(&data1); + SSLSocketDataProvider ssl(true, OK); + session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); + + TestCompletionCallback callback1; + + scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); + + int rv = trans->Start(&request, &callback1, log.bound()); + EXPECT_EQ(ERR_IO_PENDING, rv); + + rv = callback1.WaitForResult(); + EXPECT_EQ(ERR_UNEXPECTED_PROXY_AUTH, rv); + size_t pos = ExpectLogContainsSomewhere( + log.entries(), 0, NetLog::TYPE_HTTP_TRANSACTION_SEND_TUNNEL_HEADERS, + NetLog::PHASE_NONE); + ExpectLogContainsSomewhere( + log.entries(), pos, + NetLog::TYPE_HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS, + NetLog::PHASE_NONE); +} // Test a simple get through an HTTPS Proxy. TEST_F(HttpNetworkTransactionTest, HttpsProxyGet) { @@ -3189,7 +3310,7 @@ TEST_F(HttpNetworkTransactionTest, ResendRequestOnWriteBodyError) { request[1].load_flags = 0; SessionDependencies session_deps; - scoped_refptr<HttpNetworkSession> session = CreateSession(&session_deps); + scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); // The first socket is used for transaction 1 and the first attempt of // transaction 2. @@ -3457,7 +3578,7 @@ TEST_F(HttpNetworkTransactionTest, WrongAuthIdentityInURL) { // Test that previously tried username/passwords for a realm get re-used. TEST_F(HttpNetworkTransactionTest, BasicAuthCacheAndPreauth) { SessionDependencies session_deps; - scoped_refptr<HttpNetworkSession> session = CreateSession(&session_deps); + scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); // Transaction 1: authenticate (foo, bar) on MyRealm1 { @@ -3850,7 +3971,7 @@ TEST_F(HttpNetworkTransactionTest, BasicAuthCacheAndPreauth) { // are started with the same nonce. TEST_F(HttpNetworkTransactionTest, DigestPreAuthNonceCount) { SessionDependencies session_deps; - scoped_refptr<HttpNetworkSession> session = CreateSession(&session_deps); + scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); HttpAuthHandlerDigest::SetFixedCnonce(true); // Transaction 1: authenticate (foo, bar) on MyRealm1 @@ -3991,7 +4112,7 @@ TEST_F(HttpNetworkTransactionTest, ResetStateForRestart) { // Setup some state (which we expect ResetStateForRestart() will clear). trans->read_buf_ = new IOBuffer(15); trans->read_buf_len_ = 15; - trans->request_headers_ = "Authorization: NTLM"; + trans->request_headers_.SetHeader("Authorization", "NTLM"); // Setup state in response_ HttpResponseInfo* response = &trans->response_; @@ -4004,7 +4125,7 @@ TEST_F(HttpNetworkTransactionTest, ResetStateForRestart) { HttpRequestInfo request; std::string temp("HTTP/1.1 200 OK\nVary: foo, bar\n\n"); std::replace(temp.begin(), temp.end(), '\n', '\0'); - scoped_refptr<HttpResponseHeaders> headers = new HttpResponseHeaders(temp); + scoped_refptr<HttpResponseHeaders> headers(new HttpResponseHeaders(temp)); request.extra_headers.SetHeader("Foo", "1"); request.extra_headers.SetHeader("bar", "23"); EXPECT_TRUE(response->vary_data.Init(request, *headers)); @@ -4016,7 +4137,7 @@ TEST_F(HttpNetworkTransactionTest, ResetStateForRestart) { // Verify that the state that needed to be reset, has been reset. EXPECT_TRUE(trans->read_buf_.get() == NULL); EXPECT_EQ(0, trans->read_buf_len_); - EXPECT_EQ(0U, trans->request_headers_.size()); + EXPECT_TRUE(trans->request_headers_.IsEmpty()); EXPECT_TRUE(response->auth_challenge.get() == NULL); EXPECT_TRUE(response->headers.get() == NULL); EXPECT_FALSE(response->was_cached); @@ -5317,7 +5438,7 @@ TEST_F(HttpNetworkTransactionTest, BypassHostCacheOnRefresh3) { // Make sure we can handle an error when writing the request. TEST_F(HttpNetworkTransactionTest, RequestWriteError) { SessionDependencies session_deps; - scoped_refptr<HttpNetworkSession> session = CreateSession(&session_deps); + scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); HttpRequestInfo request; request.method = "GET"; @@ -5346,7 +5467,7 @@ TEST_F(HttpNetworkTransactionTest, RequestWriteError) { // Check that a connection closed after the start of the headers finishes ok. TEST_F(HttpNetworkTransactionTest, ConnectionClosedAfterStartOfHeaders) { SessionDependencies session_deps; - scoped_refptr<HttpNetworkSession> session = CreateSession(&session_deps); + scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); HttpRequestInfo request; request.method = "GET"; @@ -5388,7 +5509,7 @@ TEST_F(HttpNetworkTransactionTest, ConnectionClosedAfterStartOfHeaders) { // restart does the right thing. TEST_F(HttpNetworkTransactionTest, DrainResetOK) { SessionDependencies session_deps; - scoped_refptr<HttpNetworkSession> session = CreateSession(&session_deps); + scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); HttpRequestInfo request; request.method = "GET"; @@ -6412,8 +6533,8 @@ TEST_F(HttpNetworkTransactionTest, scoped_refptr<SpdySession> spdy_session = session->spdy_session_pool()->Get(pair, session->mutable_spdy_settings(), BoundNetLog()); - scoped_refptr<TCPSocketParams> tcp_params = - new TCPSocketParams("www.google.com", 443, MEDIUM, GURL(), false); + scoped_refptr<TCPSocketParams> tcp_params( + new TCPSocketParams("www.google.com", 443, MEDIUM, GURL(), false)); scoped_ptr<ClientSocketHandle> connection(new ClientSocketHandle); EXPECT_EQ(ERR_IO_PENDING, @@ -6887,7 +7008,7 @@ TEST_F(HttpNetworkTransactionTest, MultiRoundAuth) { origin, BoundNetLog()); auth_factory->set_mock_handler(auth_handler, HttpAuth::AUTH_SERVER); - scoped_refptr<HttpNetworkSession> session = CreateSession(&session_deps); + scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); int rv = OK; @@ -7588,8 +7709,8 @@ TEST_F(HttpNetworkTransactionTest, PreconnectWithExistingSpdySession) { scoped_refptr<SpdySession> spdy_session = session->spdy_session_pool()->Get(pair, session->mutable_spdy_settings(), BoundNetLog()); - scoped_refptr<TCPSocketParams> tcp_params = - new TCPSocketParams("www.google.com", 443, MEDIUM, GURL(), false); + scoped_refptr<TCPSocketParams> tcp_params( + new TCPSocketParams("www.google.com", 443, MEDIUM, GURL(), false)); TestCompletionCallback callback; scoped_ptr<ClientSocketHandle> connection(new ClientSocketHandle); diff --git a/net/http/http_proxy_client_socket.cc b/net/http/http_proxy_client_socket.cc index b5ede3d..186b459 100644 --- a/net/http/http_proxy_client_socket.cc +++ b/net/http/http_proxy_client_socket.cc @@ -185,6 +185,14 @@ bool HttpProxyClientSocket::WasEverUsed() const { return false; } +bool HttpProxyClientSocket::UsingTCPFastOpen() const { + if (transport_.get() && transport_->socket()) { + return transport_->socket()->UsingTCPFastOpen(); + } + NOTREACHED(); + return false; +} + int HttpProxyClientSocket::Read(IOBuffer* buf, int buf_len, CompletionCallback* callback) { DCHECK(!user_callback_); @@ -335,8 +343,8 @@ int HttpProxyClientSocket::DoSendRequest() { if (net_log_.IsLoggingAllEvents()) { net_log_.AddEvent( NetLog::TYPE_HTTP_TRANSACTION_SEND_TUNNEL_HEADERS, - new NetLogHttpRequestParameter( - request_line, request_headers)); + make_scoped_refptr(new NetLogHttpRequestParameter( + request_line, request_headers))); } request_headers_ = request_line + request_headers.ToString(); } @@ -373,7 +381,7 @@ int HttpProxyClientSocket::DoReadHeadersComplete(int result) { if (net_log_.IsLoggingAllEvents()) { net_log_.AddEvent( NetLog::TYPE_HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS, - new NetLogHttpResponseParameter(response_.headers)); + make_scoped_refptr(new NetLogHttpResponseParameter(response_.headers))); } switch (response_.headers->response_code()) { diff --git a/net/http/http_proxy_client_socket.h b/net/http/http_proxy_client_socket.h index 6530285..b42c78b 100644 --- a/net/http/http_proxy_client_socket.h +++ b/net/http/http_proxy_client_socket.h @@ -78,6 +78,7 @@ class HttpProxyClientSocket : public ClientSocket { virtual void SetSubresourceSpeculation(); virtual void SetOmniboxSpeculation(); virtual bool WasEverUsed() const; + virtual bool UsingTCPFastOpen() const; // Socket methods: virtual int Read(IOBuffer* buf, int buf_len, CompletionCallback* callback); diff --git a/net/http/http_proxy_client_socket_pool_unittest.cc b/net/http/http_proxy_client_socket_pool_unittest.cc index e1ca2fe..ae84ecc 100644 --- a/net/http/http_proxy_client_socket_pool_unittest.cc +++ b/net/http/http_proxy_client_socket_pool_unittest.cc @@ -244,7 +244,8 @@ TEST_P(HttpProxyClientSocketPoolTest, NeedAuth) { CreateMockWrite(*rst, 2, true), }; scoped_ptr<spdy::SpdyFrame> resp( - ConstructSpdySynReplyError("407 Proxy Authentication Required", 1)); + ConstructSpdySynReplyError( + "407 Proxy Authentication Required", NULL, 0, 1)); MockRead spdy_reads[] = { CreateMockWrite(*resp, 1, true), MockRead(true, 0, 3) diff --git a/net/http/http_response_body_drainer_unittest.cc b/net/http/http_response_body_drainer_unittest.cc index d57952d..d8c9bb7 100644 --- a/net/http/http_response_body_drainer_unittest.cc +++ b/net/http/http_response_body_drainer_unittest.cc @@ -78,7 +78,7 @@ class MockHttpStream : public HttpStream { CompletionCallback* callback) { return ERR_UNEXPECTED; } - virtual int SendRequest(const std::string& request_headers, + virtual int SendRequest(const HttpRequestHeaders& request_headers, UploadDataStream* request_body, HttpResponseInfo* response, CompletionCallback* callback) { diff --git a/net/http/http_response_headers.cc b/net/http/http_response_headers.cc index 99c5404..c2d098c 100644 --- a/net/http/http_response_headers.cc +++ b/net/http/http_response_headers.cc @@ -484,7 +484,7 @@ bool HttpResponseHeaders::HasHeaderValue(const std::string& name, while (EnumerateHeader(&iter, name, &temp)) { if (value.size() == temp.size() && std::equal(temp.begin(), temp.end(), value.begin(), - CaseInsensitiveCompare<char>())) + base::CaseInsensitiveCompare<char>())) return true; } return false; @@ -598,7 +598,7 @@ void HttpResponseHeaders::ParseStatusLine( raw_headers_.push_back(' '); raw_headers_.append(code, p); raw_headers_.push_back(' '); - base::StringToInt(std::string(code, p), &response_code_); + base::StringToInt(code, p, &response_code_); // Skip whitespace. while (*p == ' ') @@ -629,7 +629,7 @@ size_t HttpResponseHeaders::FindHeader(size_t from, const std::string::const_iterator& name_end = parsed_[i].name_end; if (static_cast<size_t>(name_end - name_begin) == search.size() && std::equal(name_begin, name_end, search.begin(), - CaseInsensitiveCompare<char>())) + base::CaseInsensitiveCompare<char>())) return i; } @@ -973,7 +973,9 @@ bool HttpResponseHeaders::GetMaxAgeValue(TimeDelta* result) const { value.begin() + kMaxAgePrefixLen, kMaxAgePrefix)) { int64 seconds; - base::StringToInt64(value.substr(kMaxAgePrefixLen), &seconds); + base::StringToInt64(value.begin() + kMaxAgePrefixLen, + value.end(), + &seconds); *result = TimeDelta::FromSeconds(seconds); return true; } @@ -1148,9 +1150,9 @@ bool HttpResponseHeaders::GetContentRange(int64* first_byte_position, byte_range_resp_spec.begin() + minus_position; HttpUtil::TrimLWS(&first_byte_pos_begin, &first_byte_pos_end); - bool ok = base::StringToInt64( - std::string(first_byte_pos_begin, first_byte_pos_end), - first_byte_position); + bool ok = base::StringToInt64(first_byte_pos_begin, + first_byte_pos_end, + first_byte_position); // Obtain last-byte-pos. std::string::const_iterator last_byte_pos_begin = @@ -1159,9 +1161,9 @@ bool HttpResponseHeaders::GetContentRange(int64* first_byte_position, byte_range_resp_spec.end(); HttpUtil::TrimLWS(&last_byte_pos_begin, &last_byte_pos_end); - ok &= base::StringToInt64( - std::string(last_byte_pos_begin, last_byte_pos_end), - last_byte_position); + ok &= base::StringToInt64(last_byte_pos_begin, + last_byte_pos_end, + last_byte_position); if (!ok) { *first_byte_position = *last_byte_position = -1; return false; @@ -1184,9 +1186,9 @@ bool HttpResponseHeaders::GetContentRange(int64* first_byte_position, if (LowerCaseEqualsASCII(instance_length_begin, instance_length_end, "*")) { return false; - } else if (!base::StringToInt64( - std::string(instance_length_begin, instance_length_end), - instance_length)) { + } else if (!base::StringToInt64(instance_length_begin, + instance_length_end, + instance_length)) { *instance_length = -1; return false; } diff --git a/net/http/http_response_headers_unittest.cc b/net/http/http_response_headers_unittest.cc index 18cd1c4..6986723 100644 --- a/net/http/http_response_headers_unittest.cc +++ b/net/http/http_response_headers_unittest.cc @@ -51,8 +51,8 @@ void TestCommon(const TestData& test) { string expected_headers(test.expected_headers); string headers; - scoped_refptr<HttpResponseHeaders> parsed = - new HttpResponseHeaders(raw_headers); + scoped_refptr<HttpResponseHeaders> parsed( + new HttpResponseHeaders(raw_headers)); parsed->GetNormalizedHeaders(&headers); // Transform to readable output format (so it's easier to see diffs). @@ -281,7 +281,7 @@ TEST(HttpResponseHeadersTest, GetNormalizedHeader) { "Cache-control: private\n" "cache-Control: no-store\n"; HeadersToRaw(&headers); - scoped_refptr<HttpResponseHeaders> parsed = new HttpResponseHeaders(headers); + scoped_refptr<HttpResponseHeaders> parsed(new HttpResponseHeaders(headers)); std::string value; EXPECT_TRUE(parsed->GetNormalizedHeader("cache-control", &value)); @@ -448,15 +448,15 @@ TEST(HttpResponseHeadersTest, Persist) { for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) { std::string headers = tests[i].raw_headers; HeadersToRaw(&headers); - scoped_refptr<HttpResponseHeaders> parsed1 = - new HttpResponseHeaders(headers); + scoped_refptr<HttpResponseHeaders> parsed1( + new HttpResponseHeaders(headers)); Pickle pickle; parsed1->Persist(&pickle, tests[i].options); void* iter = NULL; - scoped_refptr<HttpResponseHeaders> parsed2 = - new HttpResponseHeaders(pickle, &iter); + scoped_refptr<HttpResponseHeaders> parsed2( + new HttpResponseHeaders(pickle, &iter)); std::string h2; parsed2->GetNormalizedHeaders(&h2); @@ -472,7 +472,7 @@ TEST(HttpResponseHeadersTest, EnumerateHeader_Coalesced) { "Cache-control:private , no-cache=\"set-cookie,server\" \n" "cache-Control: no-store\n"; HeadersToRaw(&headers); - scoped_refptr<HttpResponseHeaders> parsed = new HttpResponseHeaders(headers); + scoped_refptr<HttpResponseHeaders> parsed(new HttpResponseHeaders(headers)); void* iter = NULL; std::string value; @@ -493,7 +493,7 @@ TEST(HttpResponseHeadersTest, EnumerateHeader_Challenge) { "WWW-Authenticate:Digest realm=foobar, nonce=x, domain=y\n" "WWW-Authenticate:Basic realm=quatar\n"; HeadersToRaw(&headers); - scoped_refptr<HttpResponseHeaders> parsed = new HttpResponseHeaders(headers); + scoped_refptr<HttpResponseHeaders> parsed(new HttpResponseHeaders(headers)); void* iter = NULL; std::string value; @@ -512,7 +512,7 @@ TEST(HttpResponseHeadersTest, EnumerateHeader_DateValued) { "Date: Tue, 07 Aug 2007 23:10:55 GMT\n" "Last-Modified: Wed, 01 Aug 2007 23:23:45 GMT\n"; HeadersToRaw(&headers); - scoped_refptr<HttpResponseHeaders> parsed = new HttpResponseHeaders(headers); + scoped_refptr<HttpResponseHeaders> parsed(new HttpResponseHeaders(headers)); std::string value; EXPECT_TRUE(parsed->EnumerateHeader(NULL, "date", &value)); @@ -656,8 +656,8 @@ TEST(HttpResponseHeadersTest, GetMimeType) { for (size_t i = 0; i < arraysize(tests); ++i) { string headers(tests[i].raw_headers); HeadersToRaw(&headers); - scoped_refptr<HttpResponseHeaders> parsed = - new HttpResponseHeaders(headers); + scoped_refptr<HttpResponseHeaders> parsed( + new HttpResponseHeaders(headers)); std::string value; EXPECT_EQ(tests[i].has_mimetype, parsed->GetMimeType(&value)); @@ -807,8 +807,8 @@ TEST(HttpResponseHeadersTest, RequiresValidation) { for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) { string headers(tests[i].headers); HeadersToRaw(&headers); - scoped_refptr<HttpResponseHeaders> parsed = - new HttpResponseHeaders(headers); + scoped_refptr<HttpResponseHeaders> parsed( + new HttpResponseHeaders(headers)); bool requires_validation = parsed->RequiresValidation(request_time, response_time, current_time); @@ -871,13 +871,13 @@ TEST(HttpResponseHeadersTest, Update) { for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) { string orig_headers(tests[i].orig_headers); HeadersToRaw(&orig_headers); - scoped_refptr<HttpResponseHeaders> parsed = - new HttpResponseHeaders(orig_headers); + scoped_refptr<HttpResponseHeaders> parsed( + new HttpResponseHeaders(orig_headers)); string new_headers(tests[i].new_headers); HeadersToRaw(&new_headers); - scoped_refptr<HttpResponseHeaders> new_parsed = - new HttpResponseHeaders(new_headers); + scoped_refptr<HttpResponseHeaders> new_parsed( + new HttpResponseHeaders(new_headers)); parsed->Update(*new_parsed); @@ -917,8 +917,8 @@ TEST(HttpResponseHeadersTest, EnumerateHeaderLines) { for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) { string headers(tests[i].headers); HeadersToRaw(&headers); - scoped_refptr<HttpResponseHeaders> parsed = - new HttpResponseHeaders(headers); + scoped_refptr<HttpResponseHeaders> parsed( + new HttpResponseHeaders(headers)); string name, value, lines; @@ -1001,8 +1001,8 @@ TEST(HttpResponseHeadersTest, IsRedirect) { for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) { string headers(tests[i].headers); HeadersToRaw(&headers); - scoped_refptr<HttpResponseHeaders> parsed = - new HttpResponseHeaders(headers); + scoped_refptr<HttpResponseHeaders> parsed( + new HttpResponseHeaders(headers)); std::string location; EXPECT_EQ(parsed->IsRedirect(&location), tests[i].is_redirect); @@ -1087,8 +1087,8 @@ TEST(HttpResponseHeadersTest, GetContentLength) { for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) { string headers(tests[i].headers); HeadersToRaw(&headers); - scoped_refptr<HttpResponseHeaders> parsed = - new HttpResponseHeaders(headers); + scoped_refptr<HttpResponseHeaders> parsed( + new HttpResponseHeaders(headers)); EXPECT_EQ(tests[i].expected_len, parsed->GetContentLength()); } @@ -1338,8 +1338,8 @@ TEST(HttpResponseHeaders, GetContentRange) { for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) { string headers(tests[i].headers); HeadersToRaw(&headers); - scoped_refptr<HttpResponseHeaders> parsed = - new HttpResponseHeaders(headers); + scoped_refptr<HttpResponseHeaders> parsed( + new HttpResponseHeaders(headers)); int64 first_byte_position; int64 last_byte_position; @@ -1420,8 +1420,8 @@ TEST(HttpResponseHeadersTest, IsKeepAlive) { for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) { string headers(tests[i].headers); HeadersToRaw(&headers); - scoped_refptr<HttpResponseHeaders> parsed = - new HttpResponseHeaders(headers); + scoped_refptr<HttpResponseHeaders> parsed( + new HttpResponseHeaders(headers)); EXPECT_EQ(tests[i].expected_keep_alive, parsed->IsKeepAlive()); } @@ -1473,8 +1473,8 @@ TEST(HttpResponseHeadersTest, HasStrongValidators) { for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) { string headers(tests[i].headers); HeadersToRaw(&headers); - scoped_refptr<HttpResponseHeaders> parsed = - new HttpResponseHeaders(headers); + scoped_refptr<HttpResponseHeaders> parsed( + new HttpResponseHeaders(headers)); EXPECT_EQ(tests[i].expected_result, parsed->HasStrongValidators()) << "Failed test case " << i; @@ -1484,14 +1484,14 @@ TEST(HttpResponseHeadersTest, HasStrongValidators) { TEST(HttpResponseHeadersTest, GetStatusText) { std::string headers("HTTP/1.1 404 Not Found"); HeadersToRaw(&headers); - scoped_refptr<HttpResponseHeaders> parsed = new HttpResponseHeaders(headers); + scoped_refptr<HttpResponseHeaders> parsed(new HttpResponseHeaders(headers)); EXPECT_EQ(std::string("Not Found"), parsed->GetStatusText()); } TEST(HttpResponseHeadersTest, GetStatusTextMissing) { std::string headers("HTTP/1.1 404"); HeadersToRaw(&headers); - scoped_refptr<HttpResponseHeaders> parsed = new HttpResponseHeaders(headers); + scoped_refptr<HttpResponseHeaders> parsed(new HttpResponseHeaders(headers)); // Since the status line gets normalized, we have OK EXPECT_EQ(std::string("OK"), parsed->GetStatusText()); } @@ -1499,14 +1499,14 @@ TEST(HttpResponseHeadersTest, GetStatusTextMissing) { TEST(HttpResponseHeadersTest, GetStatusTextMultiSpace) { std::string headers("HTTP/1.0 404 Not Found"); HeadersToRaw(&headers); - scoped_refptr<HttpResponseHeaders> parsed = new HttpResponseHeaders(headers); + scoped_refptr<HttpResponseHeaders> parsed(new HttpResponseHeaders(headers)); EXPECT_EQ(std::string("Not Found"), parsed->GetStatusText()); } TEST(HttpResponseHeadersTest, GetStatusBadStatusLine) { std::string headers("Foo bar."); HeadersToRaw(&headers); - scoped_refptr<HttpResponseHeaders> parsed = new HttpResponseHeaders(headers); + scoped_refptr<HttpResponseHeaders> parsed(new HttpResponseHeaders(headers)); // The bad status line would have gotten rewritten as // HTTP/1.0 200 OK. EXPECT_EQ(std::string("OK"), parsed->GetStatusText()); @@ -1545,8 +1545,8 @@ TEST(HttpResponseHeadersTest, AddHeader) { for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) { string orig_headers(tests[i].orig_headers); HeadersToRaw(&orig_headers); - scoped_refptr<HttpResponseHeaders> parsed = - new HttpResponseHeaders(orig_headers); + scoped_refptr<HttpResponseHeaders> parsed( + new HttpResponseHeaders(orig_headers)); string new_header(tests[i].new_header); parsed->AddHeader(new_header); @@ -1590,8 +1590,8 @@ TEST(HttpResponseHeadersTest, RemoveHeader) { for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) { string orig_headers(tests[i].orig_headers); HeadersToRaw(&orig_headers); - scoped_refptr<HttpResponseHeaders> parsed = - new HttpResponseHeaders(orig_headers); + scoped_refptr<HttpResponseHeaders> parsed( + new HttpResponseHeaders(orig_headers)); string name(tests[i].to_remove); parsed->RemoveHeader(name); @@ -1645,8 +1645,8 @@ TEST(HttpResponseHeadersTest, ReplaceStatus) { for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) { string orig_headers(tests[i].orig_headers); HeadersToRaw(&orig_headers); - scoped_refptr<HttpResponseHeaders> parsed = - new HttpResponseHeaders(orig_headers); + scoped_refptr<HttpResponseHeaders> parsed( + new HttpResponseHeaders(orig_headers)); string name(tests[i].new_status); parsed->ReplaceStatusLine(name); diff --git a/net/http/http_response_info.cc b/net/http/http_response_info.cc index dc90d1f..00bfb92 100644 --- a/net/http/http_response_info.cc +++ b/net/http/http_response_info.cc @@ -182,6 +182,7 @@ void HttpResponseInfo::Persist(Pickle* pickle, } if (ssl_info.security_bits != -1) flags |= RESPONSE_INFO_HAS_SECURITY_BITS; + // TODO(wtc): we should persist ssl_info.connection_status. if (vary_data.is_valid()) flags |= RESPONSE_INFO_HAS_VARY_DATA; if (response_truncated) diff --git a/net/http/http_stream.h b/net/http/http_stream.h index 5aa84e0..16f84cc 100644 --- a/net/http/http_stream.h +++ b/net/http/http_stream.h @@ -22,12 +22,13 @@ namespace net { class BoundNetLog; +class HttpRequestHeaders; +struct HttpRequestInfo; class HttpResponseInfo; class IOBuffer; class SSLCertRequestInfo; class SSLInfo; class UploadDataStream; -struct HttpRequestInfo; class HttpStream { public: @@ -45,7 +46,7 @@ class HttpStream { // synchronously, in which case the result will be passed to the callback // when available. Returns OK on success. The HttpStream takes ownership // of the request_body. - virtual int SendRequest(const std::string& request_headers, + virtual int SendRequest(const HttpRequestHeaders& request_headers, UploadDataStream* request_body, HttpResponseInfo* response, CompletionCallback* callback) = 0; diff --git a/net/http/http_stream_parser.cc b/net/http/http_stream_parser.cc index 0e7610c..d3e4abd 100644 --- a/net/http/http_stream_parser.cc +++ b/net/http/http_stream_parser.cc @@ -53,7 +53,7 @@ int HttpStreamParser::SendRequest(const std::string& headers, DCHECK(response); response_ = response; - scoped_refptr<StringIOBuffer> headers_io_buf = new StringIOBuffer(headers); + scoped_refptr<StringIOBuffer> headers_io_buf(new StringIOBuffer(headers)); request_headers_ = new DrainableIOBuffer(headers_io_buf, headers_io_buf->size()); request_body_.reset(request_body); @@ -510,13 +510,20 @@ int HttpStreamParser::DoParseResponseHeaders(int end_offset) { void* it = NULL; const std::string content_length_header("Content-Length"); - std::string ignored_header_value; + std::string content_length_value; if (!headers->HasHeader("Transfer-Encoding") && headers->EnumerateHeader( - &it, content_length_header, &ignored_header_value) && - headers->EnumerateHeader( - &it, content_length_header, &ignored_header_value)) { - return ERR_RESPONSE_HEADERS_MULTIPLE_CONTENT_LENGTH; + &it, content_length_header, &content_length_value)) { + // Ok, there's no Transfer-Encoding header and there's at least one + // Content-Length header. Check if there are any more Content-Length + // headers, and if so, make sure they have the same value. Otherwise, it's + // a possible response smuggling attack. + std::string content_length_value2; + while (headers->EnumerateHeader( + &it, content_length_header, &content_length_value2)) { + if (content_length_value != content_length_value2) + return ERR_RESPONSE_HEADERS_MULTIPLE_CONTENT_LENGTH; + } } response_->headers = headers; diff --git a/net/http/http_stream_request.cc b/net/http/http_stream_request.cc index 2409d86..71bbdda 100644 --- a/net/http/http_stream_request.cc +++ b/net/http/http_stream_request.cc @@ -21,7 +21,6 @@ #include "net/socket/client_socket_pool.h" #include "net/socket/socks_client_socket_pool.h" #include "net/socket/ssl_client_socket.h" -#include "net/socket/ssl_client_socket.h" #include "net/socket/ssl_client_socket_pool.h" #include "net/socket/tcp_client_socket_pool.h" #include "net/spdy/spdy_http_stream.h" @@ -481,9 +480,9 @@ int HttpStreamRequest::DoInitConnection() { } else { ProxyServer proxy_server = proxy_info()->proxy_server(); proxy_host_port.reset(new HostPortPair(proxy_server.host_port_pair())); - scoped_refptr<TCPSocketParams> proxy_tcp_params = + scoped_refptr<TCPSocketParams> proxy_tcp_params( new TCPSocketParams(*proxy_host_port, request_info().priority, - request_info().referrer, disable_resolver_cache); + request_info().referrer, disable_resolver_cache)); if (proxy_info()->is_http() || proxy_info()->is_https()) { GURL authentication_url = request_info().url; @@ -727,8 +726,12 @@ int HttpStreamRequest::DoCreateStream() { if (connection_->socket() && !connection_->is_reused()) SetSocketMotivation(); + const ProxyServer& proxy_server = proxy_info()->proxy_server(); + if (!using_spdy_) { - stream_.reset(new HttpBasicStream(connection_.release())); + bool using_proxy = (proxy_info()->is_http() || proxy_info()->is_https()) && + request_info().url.SchemeIs("http"); + stream_.reset(new HttpBasicStream(connection_.release(), using_proxy)); return OK; } @@ -738,7 +741,6 @@ int HttpStreamRequest::DoCreateStream() { SpdySessionPool* spdy_pool = session_->spdy_session_pool(); scoped_refptr<SpdySession> spdy_session; - const ProxyServer& proxy_server = proxy_info()->proxy_server(); HostPortProxyPair pair(endpoint_, proxy_server); if (spdy_pool->HasSession(pair)) { // We have a SPDY session to the origin server. This might be a direct @@ -850,17 +852,17 @@ scoped_refptr<SSLSocketParams> HttpStreamRequest::GenerateSslParams( if (request_info().load_flags & LOAD_VERIFY_EV_CERT) ssl_config()->verify_ev_cert = true; - if (proxy_info()->proxy_server().scheme() == ProxyServer::SCHEME_HTTP || - proxy_info()->proxy_server().scheme() == ProxyServer::SCHEME_HTTPS) { - ssl_config()->mitm_proxies_allowed = true; - } + if (proxy_info()->proxy_server().scheme() == ProxyServer::SCHEME_HTTP || + proxy_info()->proxy_server().scheme() == ProxyServer::SCHEME_HTTPS) { + ssl_config()->mitm_proxies_allowed = true; + } - scoped_refptr<SSLSocketParams> ssl_params = + scoped_refptr<SSLSocketParams> ssl_params( new SSLSocketParams(tcp_params, socks_params, http_proxy_params, proxy_scheme, hostname, *ssl_config(), load_flags, force_spdy_always_ && force_spdy_over_ssl_, - want_spdy_over_npn); + want_spdy_over_npn)); return ssl_params; } diff --git a/net/http/http_transaction_unittest.cc b/net/http/http_transaction_unittest.cc index 4d9daa5..518c1f8 100644 --- a/net/http/http_transaction_unittest.cc +++ b/net/http/http_transaction_unittest.cc @@ -147,7 +147,7 @@ int ReadTransaction(net::HttpTransaction* trans, std::string* result) { std::string content; do { - scoped_refptr<net::IOBuffer> buf = new net::IOBuffer(256); + scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(256)); rv = trans->Read(buf, 256, &callback); if (rv == net::ERR_IO_PENDING) rv = callback.WaitForResult(); diff --git a/net/http/http_util.cc b/net/http/http_util.cc index 5c7a4fc..a3d1ec5 100644 --- a/net/http/http_util.cc +++ b/net/http/http_util.cc @@ -292,7 +292,7 @@ bool HttpUtil::HasHeader(const std::string& headers, const char* name) { headers.end(), name, name + name_len, - CaseInsensitiveCompareASCII<char>()); + base::CaseInsensitiveCompareASCII<char>()); if (it == headers.end()) return false; @@ -828,12 +828,12 @@ bool HttpUtil::NameValuePairsIterator::GetNext() { // Scan for the equals sign. std::string::const_iterator equals = std::find(value_begin_, value_end_, '='); if (equals == value_end_ || equals == value_begin_) - return valid_ = false; // Malformed + return valid_ = false; // Malformed, no equals sign // Verify that the equals sign we found wasn't inside of quote marks. for (std::string::const_iterator it = value_begin_; it != equals; ++it) { if (HttpUtil::IsQuote(*it)) - return valid_ = false; // Malformed + return valid_ = false; // Malformed, quote appears before equals sign } name_begin_ = value_begin_; @@ -843,25 +843,28 @@ bool HttpUtil::NameValuePairsIterator::GetNext() { TrimLWS(&name_begin_, &name_end_); TrimLWS(&value_begin_, &value_end_); value_is_quoted_ = false; - if (value_begin_ != value_end_ && HttpUtil::IsQuote(*value_begin_)) { + unquoted_value_.clear(); + + if (value_begin_ == value_end_) + return valid_ = false; // Malformed, value is empty + + if (HttpUtil::IsQuote(*value_begin_)) { // Trim surrounding quotemarks off the value - if (*value_begin_ != *(value_end_ - 1) || value_begin_ + 1 == value_end_) + if (*value_begin_ != *(value_end_ - 1) || value_begin_ + 1 == value_end_) { // NOTE: This is not as graceful as it sounds: // * quoted-pairs will no longer be unquoted // (["\"hello] should give ["hello]). // * Does not detect when the final quote is escaped // (["value\"] should give [value"]) ++value_begin_; // Gracefully recover from mismatching quotes. - else + } else { value_is_quoted_ = true; + // Do not store iterators into this. See declaration of unquoted_value_. + unquoted_value_ = HttpUtil::Unquote(value_begin_, value_end_); + } } return true; } -// If value() has quotemarks, unquote it. -std::string HttpUtil::NameValuePairsIterator::unquoted_value() const { - return HttpUtil::Unquote(value_begin_, value_end_); -} - } // namespace net diff --git a/net/http/http_util.h b/net/http/http_util.h index f41c4e4..2f5bd85 100644 --- a/net/http/http_util.h +++ b/net/http/http_util.h @@ -275,6 +275,9 @@ class HttpUtil { // Each pair consists of a token (the name), an equals sign, and either a // token or quoted-string (the value). Arbitrary HTTP LWS is permitted outside // of and between names, values, and delimiters. + // + // String iterators returned from this class' methods may be invalidated upon + // calls to GetNext() or after the NameValuePairsIterator is destroyed. class NameValuePairsIterator { public: NameValuePairsIterator(std::string::const_iterator begin, @@ -295,15 +298,16 @@ class HttpUtil { std::string name() const { return std::string(name_begin_, name_end_); } // The value of the current name-value pair. - std::string::const_iterator value_begin() const { return value_begin_; } - std::string::const_iterator value_end() const { return value_end_; } - std::string value() const { return std::string(value_begin_, value_end_); } - - // If value() has quotemarks, unquote it. - std::string unquoted_value() const; - - // True if the name-value pair's value has quote marks. - bool value_is_quoted() const { return value_is_quoted_; } + std::string::const_iterator value_begin() const { + return value_is_quoted_ ? unquoted_value_.begin() : value_begin_; + } + std::string::const_iterator value_end() const { + return value_is_quoted_ ? unquoted_value_.end() : value_end_; + } + std::string value() const { + return value_is_quoted_ ? unquoted_value_ : std::string(value_begin_, + value_end_); + } private: HttpUtil::ValuesIterator props_; @@ -318,6 +322,11 @@ class HttpUtil { std::string::const_iterator value_begin_; std::string::const_iterator value_end_; + // Do not store iterators into this string. The NameValuePairsIterator + // is copyable/assignable, and if copied the copy's iterators would point + // into the original's unquoted_value_ member. + std::string unquoted_value_; + bool value_is_quoted_; }; }; diff --git a/net/http/http_util_unittest.cc b/net/http/http_util_unittest.cc index 4ebbd2e..47242d2 100644 --- a/net/http/http_util_unittest.cc +++ b/net/http/http_util_unittest.cc @@ -673,27 +673,48 @@ TEST(HttpUtilTest, ParseRanges) { } namespace { - -void CheckNameValuePair(HttpUtil::NameValuePairsIterator* parser, - bool expect_next, - bool expect_valid, - std::string expected_name, - std::string expected_value, - std::string expected_unquoted_value) { - ASSERT_EQ(expect_next, parser->GetNext()); +void CheckCurrentNameValuePair(HttpUtil::NameValuePairsIterator* parser, + bool expect_valid, + std::string expected_name, + std::string expected_value) { ASSERT_EQ(expect_valid, parser->valid()); - if (!expect_next || !expect_valid) { + if (!expect_valid) { return; } + + // Let's make sure that these never change (i.e., when a quoted value is + // unquoted, it should be cached on the first calls and not regenerated + // later). + std::string::const_iterator first_value_begin = parser->value_begin(); + std::string::const_iterator first_value_end = parser->value_end(); + ASSERT_EQ(expected_name, std::string(parser->name_begin(), parser->name_end())); ASSERT_EQ(expected_name, parser->name()); ASSERT_EQ(expected_value, std::string(parser->value_begin(), parser->value_end())); ASSERT_EQ(expected_value, parser->value()); - ASSERT_EQ(expected_unquoted_value, parser->unquoted_value()); - ASSERT_EQ(expected_value != expected_unquoted_value, - parser->value_is_quoted()); + + // Make sure they didn't/don't change. + ASSERT_TRUE(first_value_begin == parser->value_begin()); + ASSERT_TRUE(first_value_end == parser->value_end()); +} + +void CheckNextNameValuePair(HttpUtil::NameValuePairsIterator* parser, + bool expect_next, + bool expect_valid, + std::string expected_name, + std::string expected_value) { + ASSERT_EQ(expect_next, parser->GetNext()); + ASSERT_EQ(expect_valid, parser->valid()); + if (!expect_next || !expect_valid) { + return; + } + + CheckCurrentNameValuePair(parser, + expect_valid, + expected_name, + expected_value); } void CheckInvalidNameValuePair(std::string valid_part, @@ -731,35 +752,78 @@ void CheckInvalidNameValuePair(std::string valid_part, } // anonymous namespace +TEST(HttpUtilTest, NameValuePairsIteratorCopyAndAssign) { + std::string data = "alpha='\\'a\\''; beta=\" b \"; cappa='c;'; delta=\"d\""; + HttpUtil::NameValuePairsIterator parser_a(data.begin(), data.end(), ';'); + + EXPECT_TRUE(parser_a.valid()); + ASSERT_NO_FATAL_FAILURE( + CheckNextNameValuePair(&parser_a, true, true, "alpha", "'a'")); + + HttpUtil::NameValuePairsIterator parser_b(parser_a); + // a and b now point to same location + ASSERT_NO_FATAL_FAILURE( + CheckCurrentNameValuePair(&parser_b, true, "alpha", "'a'")); + ASSERT_NO_FATAL_FAILURE( + CheckCurrentNameValuePair(&parser_a, true, "alpha", "'a'")); + + // advance a, no effect on b + ASSERT_NO_FATAL_FAILURE( + CheckNextNameValuePair(&parser_a, true, true, "beta", " b ")); + ASSERT_NO_FATAL_FAILURE( + CheckCurrentNameValuePair(&parser_b, true, "alpha", "'a'")); + + // assign b the current state of a, no effect on a + parser_b = parser_a; + ASSERT_NO_FATAL_FAILURE( + CheckCurrentNameValuePair(&parser_b, true, "beta", " b ")); + ASSERT_NO_FATAL_FAILURE( + CheckCurrentNameValuePair(&parser_a, true, "beta", " b ")); + + // advance b, no effect on a + ASSERT_NO_FATAL_FAILURE( + CheckNextNameValuePair(&parser_b, true, true, "cappa", "c;")); + ASSERT_NO_FATAL_FAILURE( + CheckCurrentNameValuePair(&parser_a, true, "beta", " b ")); +} + TEST(HttpUtilTest, NameValuePairsIteratorEmptyInput) { std::string data = ""; HttpUtil::NameValuePairsIterator parser(data.begin(), data.end(), ';'); EXPECT_TRUE(parser.valid()); ASSERT_NO_FATAL_FAILURE( - CheckNameValuePair(&parser, false, true, "", "", "")); + CheckNextNameValuePair(&parser, false, true, "", "")); } TEST(HttpUtilTest, NameValuePairsIterator) { - std::string data = "alpha=1; beta= 2 ;cappa =' 3 ';" - "delta= \" 4 \"; e= \" '5'\"; e=6"; + std::string data = "alpha=1; beta= 2 ;cappa =' 3; ';" + "delta= \" \\\"4\\\" \"; e= \" '5'\"; e=6;" + "f='\\'\\h\\e\\l\\l\\o\\ \\w\\o\\r\\l\\d\\'';" + "g=''; h='hello'"; HttpUtil::NameValuePairsIterator parser(data.begin(), data.end(), ';'); EXPECT_TRUE(parser.valid()); ASSERT_NO_FATAL_FAILURE( - CheckNameValuePair(&parser, true, true, "alpha", "1", "1")); + CheckNextNameValuePair(&parser, true, true, "alpha", "1")); + ASSERT_NO_FATAL_FAILURE( + CheckNextNameValuePair(&parser, true, true, "beta", "2")); + ASSERT_NO_FATAL_FAILURE( + CheckNextNameValuePair(&parser, true, true, "cappa", " 3; ")); + ASSERT_NO_FATAL_FAILURE( + CheckNextNameValuePair(&parser, true, true, "delta", " \"4\" ")); ASSERT_NO_FATAL_FAILURE( - CheckNameValuePair(&parser, true, true, "beta", "2", "2")); + CheckNextNameValuePair(&parser, true, true, "e", " '5'")); ASSERT_NO_FATAL_FAILURE( - CheckNameValuePair(&parser, true, true, "cappa", "' 3 '", " 3 ")); + CheckNextNameValuePair(&parser, true, true, "e", "6")); ASSERT_NO_FATAL_FAILURE( - CheckNameValuePair(&parser, true, true, "delta", "\" 4 \"", " 4 ")); + CheckNextNameValuePair(&parser, true, true, "f", "'hello world'")); ASSERT_NO_FATAL_FAILURE( - CheckNameValuePair(&parser, true, true, "e", "\" '5'\"", " '5'")); + CheckNextNameValuePair(&parser, true, true, "g", "")); ASSERT_NO_FATAL_FAILURE( - CheckNameValuePair(&parser, true, true, "e", "6", "6")); + CheckNextNameValuePair(&parser, true, true, "h", "hello")); ASSERT_NO_FATAL_FAILURE( - CheckNameValuePair(&parser, false, true, "", "", "")); + CheckNextNameValuePair(&parser, false, true, "", "")); } TEST(HttpUtilTest, NameValuePairsIteratorIllegalInputs) { @@ -768,6 +832,9 @@ TEST(HttpUtilTest, NameValuePairsIteratorIllegalInputs) { ASSERT_NO_FATAL_FAILURE(CheckInvalidNameValuePair("alpha=1", "; 'beta'=2")); ASSERT_NO_FATAL_FAILURE(CheckInvalidNameValuePair("", "'beta'=2")); + ASSERT_NO_FATAL_FAILURE(CheckInvalidNameValuePair("alpha=1", ";beta=")); + ASSERT_NO_FATAL_FAILURE(CheckInvalidNameValuePair("alpha=1", + ";beta=;cappa=2")); // According to the spec this is an error, but it doesn't seem appropriate to // change our behaviour to be less permissive at this time. @@ -783,13 +850,13 @@ TEST(HttpUtilTest, NameValuePairsIteratorExtraSeparators) { EXPECT_TRUE(parser.valid()); ASSERT_NO_FATAL_FAILURE( - CheckNameValuePair(&parser, true, true, "alpha", "1", "1")); + CheckNextNameValuePair(&parser, true, true, "alpha", "1")); ASSERT_NO_FATAL_FAILURE( - CheckNameValuePair(&parser, true, true, "beta", "2", "2")); + CheckNextNameValuePair(&parser, true, true, "beta", "2")); ASSERT_NO_FATAL_FAILURE( - CheckNameValuePair(&parser, true, true, "cappa", "3", "3")); + CheckNextNameValuePair(&parser, true, true, "cappa", "3")); ASSERT_NO_FATAL_FAILURE( - CheckNameValuePair(&parser, false, true, "", "", "")); + CheckNextNameValuePair(&parser, false, true, "", "")); } // See comments on the implementation of NameValuePairsIterator::GetNext @@ -800,7 +867,7 @@ TEST(HttpUtilTest, NameValuePairsIteratorMissingEndQuote) { EXPECT_TRUE(parser.valid()); ASSERT_NO_FATAL_FAILURE( - CheckNameValuePair(&parser, true, true, "name", "value", "value")); + CheckNextNameValuePair(&parser, true, true, "name", "value")); ASSERT_NO_FATAL_FAILURE( - CheckNameValuePair(&parser, false, true, "", "", "")); + CheckNextNameValuePair(&parser, false, true, "", "")); } diff --git a/net/net.gyp b/net/net.gyp index 3c19189..083aac4 100644 --- a/net/net.gyp +++ b/net/net.gyp @@ -196,6 +196,8 @@ 'base/x509_cert_types.cc', 'base/x509_cert_types.h', 'base/x509_cert_types_mac.cc', + 'base/x509_openssl_util.cc', + 'base/x509_openssl_util.h', 'third_party/mozilla_security_manager/nsKeygenHandler.cpp', 'third_party/mozilla_security_manager/nsKeygenHandler.h', 'third_party/mozilla_security_manager/nsNSSCertificateDB.cpp', @@ -232,9 +234,19 @@ 'dependencies': [ '../build/linux/system.gyp:gconf', '../build/linux/system.gyp:gdk', - '../build/linux/system.gyp:nss', '../build/linux/system.gyp:libresolv', ], + 'conditions': [ + ['use_openssl==1', { + 'dependencies': [ + '../build/linux/system.gyp:openssl', + ], + }, { # else: not using openssl. Use NSS. + 'dependencies': [ + '../build/linux/system.gyp:nss', + ], + }], + ], }, { # else: OS is not in the above list 'sources!': [ @@ -252,12 +264,14 @@ ], }, ], - [ 'use_openssl == 1 and OS == "linux"', { - # When building for OpenSSL, we need to exclude some NSS files. - # TODO(bulach): remove once we fully support OpenSSL. + [ 'use_openssl==1', { 'sources!': [ 'base/cert_database_nss.cc', + 'base/dnssec_keyset.cc', + 'base/dnssec_keyset.h', 'base/keygen_handler_nss.cc', + 'base/nss_memio.c', + 'base/nss_memio.h', 'base/x509_certificate_nss.cc', 'third_party/mozilla_security_manager/nsKeygenHandler.cpp', 'third_party/mozilla_security_manager/nsKeygenHandler.h', @@ -269,13 +283,15 @@ 'third_party/mozilla_security_manager/nsPKCS12Blob.h', ], }, - { # else: not using openssl. + { # else: not using openssl. 'sources!': [ 'base/cert_database_openssl.cc', 'base/keygen_handler_openssl.cc', 'base/openssl_util.cc', 'base/openssl_util.h', 'base/x509_certificate_openssl.cc', + 'base/x509_openssl_util.cc', + 'base/x509_openssl_util.h', ], }, ], @@ -570,6 +586,8 @@ 'socket/client_socket_pool_histograms.h', 'socket/client_socket_pool_manager.cc', 'socket/client_socket_pool_manager.h', + 'socket/dns_cert_provenance_check.cc', + 'socket/dns_cert_provenance_check.h', 'socket/socket.h', 'socket/socks5_client_socket.cc', 'socket/socks5_client_socket.h', @@ -592,6 +610,7 @@ 'socket/ssl_client_socket_pool.h', 'socket/ssl_client_socket_win.cc', 'socket/ssl_client_socket_win.h', + 'socket/tcp_client_socket.cc', 'socket/tcp_client_socket.h', 'socket/tcp_client_socket_libevent.cc', 'socket/tcp_client_socket_libevent.h', @@ -701,11 +720,10 @@ 'proxy/proxy_config_service_linux.h', ], }], - ['use_openssl==1 and OS == "linux"', { - 'dependencies': [ - '../build/linux/system.gyp:openssl', - ], + ['use_openssl==1', { 'sources!': [ + 'socket/dns_cert_provenance_check.cc', + 'socket/dns_cert_provenance_check.h', 'socket/ssl_client_socket_nss.cc', 'socket/ssl_client_socket_nss.h', 'socket/ssl_client_socket_nss_factory.cc', @@ -723,7 +741,18 @@ 'dependencies': [ '../build/linux/system.gyp:gconf', '../build/linux/system.gyp:gdk', - '../build/linux/system.gyp:nss', + ], + 'conditions': [ + ['use_openssl==1', { + 'dependencies': [ + '../build/linux/system.gyp:openssl', + ], + }, + { # else use_openssl==0, use NSS + 'dependencies': [ + '../build/linux/system.gyp:nss', + ], + }], ], }, { # else: OS is not in the above list @@ -784,7 +813,6 @@ 'net_test_support', '../base/base.gyp:base', '../base/base.gyp:base_i18n', - '../base/base.gyp:test_support_base', '../testing/gmock.gyp:gmock', '../testing/gtest.gyp:gtest', '../third_party/zlib/zlib.gyp:zlib', @@ -972,11 +1000,13 @@ }], ], }], - [ 'use_openssl == 1 and OS == "linux"', { - # When building for OpenSSL, we need to exclude some NSS files. - # TODO(bulach): remove once we fully support OpenSSL. + [ 'use_openssl==1', { + # When building for OpenSSL, we need to exclude NSS specific tests. + # TODO(bulach): Add equivalent tests when the underlying + # functionality is ported to OpenSSL. 'sources!': [ 'base/cert_database_nss_unittest.cc', + 'base/dnssec_unittest.cc', ], }, ], @@ -1041,7 +1071,6 @@ 'net_test_support', '../base/base.gyp:base', '../base/base.gyp:base_i18n', - '../base/base.gyp:test_support_base', '../base/base.gyp:test_support_perf', '../testing/gtest.gyp:gtest', ], @@ -1120,6 +1149,7 @@ 'dependencies': [ 'net', '../base/base.gyp:base', + '../base/base.gyp:test_support_base', '../testing/gtest.gyp:gtest', ], 'sources': [ @@ -1146,8 +1176,16 @@ ], }], ['OS == "linux" or OS == "freebsd" or OS == "openbsd"', { - 'dependencies': [ - '../build/linux/system.gyp:nss', + 'conditions': [ + ['use_openssl==1', { + 'dependencies': [ + '../build/linux/system.gyp:openssl', + ] + }, { + 'dependencies': [ + '../build/linux/system.gyp:nss', + ], + }], ], }], ['OS == "linux"', { @@ -1159,11 +1197,6 @@ }], ], }], - ['use_openssl == 1 and OS == "linux"', { - 'dependencies': [ - '../build/linux/system.gyp:openssl', - ] - }], ], }, { diff --git a/net/ocsp/nss_ocsp.cc b/net/ocsp/nss_ocsp.cc index b7fcb65..fafaa68 100644 --- a/net/ocsp/nss_ocsp.cc +++ b/net/ocsp/nss_ocsp.cc @@ -22,9 +22,10 @@ #include "base/logging.h" #include "base/message_loop.h" #include "base/metrics/histogram.h" +#include "base/stl_util-inl.h" #include "base/string_util.h" #include "base/stringprintf.h" -#include "base/thread.h" +#include "base/thread_checker.h" #include "base/time.h" #include "googleurl/src/gurl.h" #include "net/base/io_buffer.h" @@ -40,16 +41,16 @@ namespace { pthread_mutex_t g_request_context_lock = PTHREAD_MUTEX_INITIALIZER; static URLRequestContext* g_request_context = NULL; -class OCSPIOLoop : public MessageLoop::DestructionObserver { - public: - // MessageLoop::DestructionObserver: - virtual void WillDestroyCurrentMessageLoop() { Shutdown(); } +class OCSPRequestSession; +class OCSPIOLoop { + public: void StartUsing() { AutoLock autolock(lock_); used_ = true; } + // Called on IO loop. void Shutdown(); bool used() const { @@ -62,69 +63,28 @@ class OCSPIOLoop : public MessageLoop::DestructionObserver { void EnsureIOLoop(); + void AddRequest(OCSPRequestSession* request); + void RemoveRequest(OCSPRequestSession* request); + private: friend struct base::DefaultLazyInstanceTraits<OCSPIOLoop>; OCSPIOLoop(); ~OCSPIOLoop(); + void CancelAllRequests(); + mutable Lock lock_; + bool shutdown_; // Protected by |lock_|. + std::set<OCSPRequestSession*> requests_; // Protected by |lock_|. bool used_; // Protected by |lock_|. // This should not be modified after |used_|. MessageLoopForIO* io_loop_; // Protected by |lock_|. + ThreadChecker thread_checker_; DISALLOW_COPY_AND_ASSIGN(OCSPIOLoop); }; -OCSPIOLoop::OCSPIOLoop() - : used_(false), - io_loop_(MessageLoopForIO::current()) { - DCHECK(io_loop_); - io_loop_->AddDestructionObserver(this); -} - -OCSPIOLoop::~OCSPIOLoop() { - // IO thread was already deleted before the singleton is deleted - // in AtExitManager. - { - AutoLock autolock(lock_); - DCHECK(!io_loop_); - DCHECK(!used_); - } - - pthread_mutex_lock(&g_request_context_lock); - DCHECK(!g_request_context); - pthread_mutex_unlock(&g_request_context_lock); -} - -void OCSPIOLoop::Shutdown() { - MessageLoopForIO::current()->RemoveDestructionObserver(this); - - // Prevent the worker thread from trying to access |io_loop_|. - { - AutoLock autolock(lock_); - DCHECK_EQ(MessageLoopForIO::current(), io_loop_); - io_loop_ = NULL; - used_ = false; - } - - pthread_mutex_lock(&g_request_context_lock); - g_request_context = NULL; - pthread_mutex_unlock(&g_request_context_lock); -} - -void OCSPIOLoop::PostTaskToIOLoop( - const tracked_objects::Location& from_here, Task* task) { - AutoLock autolock(lock_); - if (io_loop_) - io_loop_->PostTask(from_here, task); -} - -void OCSPIOLoop::EnsureIOLoop() { - AutoLock autolock(lock_); - DCHECK_EQ(MessageLoopForIO::current(), io_loop_); -} - base::LazyInstance<OCSPIOLoop> g_ocsp_io_loop(base::LINKER_INITIALIZED); const int kRecvBufferSize = 4096; @@ -175,44 +135,6 @@ class OCSPNSSInitialization { DISALLOW_COPY_AND_ASSIGN(OCSPNSSInitialization); }; -OCSPNSSInitialization::OCSPNSSInitialization() { - // NSS calls the functions in the function table to download certificates - // or CRLs or talk to OCSP responders over HTTP. These functions must - // set an NSS/NSPR error code when they fail. Otherwise NSS will get the - // residual error code from an earlier failed function call. - client_fcn_.version = 1; - SEC_HttpClientFcnV1Struct *ft = &client_fcn_.fcnTable.ftable1; - ft->createSessionFcn = OCSPCreateSession; - ft->keepAliveSessionFcn = OCSPKeepAliveSession; - ft->freeSessionFcn = OCSPFreeSession; - ft->createFcn = OCSPCreate; - ft->setPostDataFcn = OCSPSetPostData; - ft->addHeaderFcn = OCSPAddHeader; - ft->trySendAndReceiveFcn = OCSPTrySendAndReceive; - ft->cancelFcn = NULL; - ft->freeFcn = OCSPFree; - SECStatus status = SEC_RegisterDefaultHttpClient(&client_fcn_); - if (status != SECSuccess) { - NOTREACHED() << "Error initializing OCSP: " << PR_GetError(); - } - - // Work around NSS bugs 524013 and 564334. NSS incorrectly thinks the - // CRLs for Network Solutions Certificate Authority have bad signatures, - // which causes certificates issued by that CA to be reported as revoked. - // By using OCSP for those certificates, which don't have AIA extensions, - // we can work around these bugs. See http://crbug.com/41730. - CERT_StringFromCertFcn old_callback = NULL; - status = CERT_RegisterAlternateOCSPAIAInfoCallBack( - GetAlternateOCSPAIAInfo, &old_callback); - if (status == SECSuccess) { - DCHECK(!old_callback); - } else { - NOTREACHED() << "Error initializing OCSP: " << PR_GetError(); - } -} - -OCSPNSSInitialization::~OCSPNSSInitialization() {} - base::LazyInstance<OCSPNSSInitialization> g_ocsp_nss_initialization( base::LINKER_INITIALIZED); @@ -223,8 +145,7 @@ base::LazyInstance<OCSPNSSInitialization> g_ocsp_nss_initialization( // on IO thread. class OCSPRequestSession : public base::RefCountedThreadSafe<OCSPRequestSession>, - public URLRequest::Delegate, - public MessageLoop::DestructionObserver { + public URLRequest::Delegate { public: OCSPRequestSession(const GURL& url, const char* http_request_method, @@ -353,7 +274,7 @@ class OCSPRequestSession if (!request_->status().is_io_pending()) { delete request_; request_ = NULL; - io_loop_->RemoveDestructionObserver(this); + g_ocsp_io_loop.Get().RemoveRequest(this); { AutoLock autolock(lock_); finished_ = true; @@ -364,13 +285,28 @@ class OCSPRequestSession } } - virtual void WillDestroyCurrentMessageLoop() { - DCHECK_EQ(MessageLoopForIO::current(), io_loop_); + // Must be called on the IO loop thread. + void CancelURLRequest() { +#ifndef NDEBUG { AutoLock autolock(lock_); - io_loop_ = NULL; + if (io_loop_) + DCHECK_EQ(MessageLoopForIO::current(), io_loop_); + } +#endif + if (request_) { + request_->Cancel(); + delete request_; + request_ = NULL; + g_ocsp_io_loop.Get().RemoveRequest(this); + { + AutoLock autolock(lock_); + finished_ = true; + io_loop_ = NULL; + } + cv_.Signal(); + Release(); // Balanced with StartURLRequest(). } - CancelURLRequest(); } private: @@ -409,7 +345,7 @@ class OCSPRequestSession AutoLock autolock(lock_); DCHECK(!io_loop_); io_loop_ = MessageLoopForIO::current(); - io_loop_->AddDestructionObserver(this); + g_ocsp_io_loop.Get().AddRequest(this); } request_ = new URLRequest(url_, this); @@ -436,32 +372,6 @@ class OCSPRequestSession AddRef(); // Release after |request_| deleted. } - void CancelURLRequest() { -#ifndef NDEBUG - { - AutoLock autolock(lock_); - if (io_loop_) - DCHECK_EQ(MessageLoopForIO::current(), io_loop_); - } -#endif - if (request_) { - request_->Cancel(); - delete request_; - request_ = NULL; - // |io_loop_| may be NULL here if it called from - // WillDestroyCurrentMessageLoop(). - if (io_loop_) - io_loop_->RemoveDestructionObserver(this); - { - AutoLock autolock(lock_); - finished_ = true; - io_loop_ = NULL; - } - cv_.Signal(); - Release(); // Balanced with StartURLRequest(). - } - } - GURL url_; // The URL we eventually wound up at std::string http_request_method_; base::TimeDelta timeout_; // The timeout for OCSP @@ -527,6 +437,123 @@ class OCSPServerSession { DISALLOW_COPY_AND_ASSIGN(OCSPServerSession); }; +OCSPIOLoop::OCSPIOLoop() + : shutdown_(false), + used_(false), + io_loop_(MessageLoopForIO::current()) { + DCHECK(io_loop_); +} + +OCSPIOLoop::~OCSPIOLoop() { + // IO thread was already deleted before the singleton is deleted + // in AtExitManager. + { + AutoLock autolock(lock_); + DCHECK(!io_loop_); + DCHECK(!used_); + DCHECK(shutdown_); + } + + pthread_mutex_lock(&g_request_context_lock); + DCHECK(!g_request_context); + pthread_mutex_unlock(&g_request_context_lock); +} + +void OCSPIOLoop::Shutdown() { + // Safe to read outside lock since we only write on IO thread anyway. + DCHECK(thread_checker_.CalledOnValidThread()); + + // Prevent the worker thread from trying to access |io_loop_|. + { + AutoLock autolock(lock_); + io_loop_ = NULL; + used_ = false; + shutdown_ = true; + } + + CancelAllRequests(); + + pthread_mutex_lock(&g_request_context_lock); + g_request_context = NULL; + pthread_mutex_unlock(&g_request_context_lock); +} + +void OCSPIOLoop::PostTaskToIOLoop( + const tracked_objects::Location& from_here, Task* task) { + AutoLock autolock(lock_); + if (io_loop_) + io_loop_->PostTask(from_here, task); +} + +void OCSPIOLoop::EnsureIOLoop() { + AutoLock autolock(lock_); + DCHECK_EQ(MessageLoopForIO::current(), io_loop_); +} + +void OCSPIOLoop::AddRequest(OCSPRequestSession* request) { + DCHECK(!ContainsKey(requests_, request)); + requests_.insert(request); +} + +void OCSPIOLoop::RemoveRequest(OCSPRequestSession* request) { + { + // Ignore if we've already shutdown. + AutoLock auto_lock(lock_); + if (shutdown_) + return; + } + + DCHECK(ContainsKey(requests_, request)); + requests_.erase(request); +} + +void OCSPIOLoop::CancelAllRequests() { + std::set<OCSPRequestSession*> requests; + requests.swap(requests_); + + for (std::set<OCSPRequestSession*>::iterator it = requests.begin(); + it != requests.end(); ++it) + (*it)->CancelURLRequest(); +} + +OCSPNSSInitialization::OCSPNSSInitialization() { + // NSS calls the functions in the function table to download certificates + // or CRLs or talk to OCSP responders over HTTP. These functions must + // set an NSS/NSPR error code when they fail. Otherwise NSS will get the + // residual error code from an earlier failed function call. + client_fcn_.version = 1; + SEC_HttpClientFcnV1Struct *ft = &client_fcn_.fcnTable.ftable1; + ft->createSessionFcn = OCSPCreateSession; + ft->keepAliveSessionFcn = OCSPKeepAliveSession; + ft->freeSessionFcn = OCSPFreeSession; + ft->createFcn = OCSPCreate; + ft->setPostDataFcn = OCSPSetPostData; + ft->addHeaderFcn = OCSPAddHeader; + ft->trySendAndReceiveFcn = OCSPTrySendAndReceive; + ft->cancelFcn = NULL; + ft->freeFcn = OCSPFree; + SECStatus status = SEC_RegisterDefaultHttpClient(&client_fcn_); + if (status != SECSuccess) { + NOTREACHED() << "Error initializing OCSP: " << PR_GetError(); + } + + // Work around NSS bugs 524013 and 564334. NSS incorrectly thinks the + // CRLs for Network Solutions Certificate Authority have bad signatures, + // which causes certificates issued by that CA to be reported as revoked. + // By using OCSP for those certificates, which don't have AIA extensions, + // we can work around these bugs. See http://crbug.com/41730. + CERT_StringFromCertFcn old_callback = NULL; + status = CERT_RegisterAlternateOCSPAIAInfoCallBack( + GetAlternateOCSPAIAInfo, &old_callback); + if (status == SECSuccess) { + DCHECK(!old_callback); + } else { + NOTREACHED() << "Error initializing OCSP: " << PR_GetError(); + } +} + +OCSPNSSInitialization::~OCSPNSSInitialization() {} + // OCSP Http Client functions. // Our Http Client functions operate in blocking mode. @@ -878,7 +905,7 @@ URLRequestContext* GetURLRequestContextForOCSP() { pthread_mutex_lock(&g_request_context_lock); URLRequestContext* request_context = g_request_context; pthread_mutex_unlock(&g_request_context_lock); - DCHECK(request_context->is_main()); + DCHECK(!request_context || request_context->is_main()); return request_context; } diff --git a/net/proxy/init_proxy_resolver.cc b/net/proxy/init_proxy_resolver.cc index 368fcf0..4bf250e 100644 --- a/net/proxy/init_proxy_resolver.cc +++ b/net/proxy/init_proxy_resolver.cc @@ -169,8 +169,8 @@ int InitProxyResolver::DoFetchPacScript() { net_log_.BeginEvent( NetLog::TYPE_INIT_PROXY_RESOLVER_FETCH_PAC_SCRIPT, - new NetLogStringParameter("url", - effective_pac_url.possibly_invalid_spec())); + make_scoped_refptr(new NetLogStringParameter( + "url", effective_pac_url.possibly_invalid_spec()))); if (!proxy_script_fetcher_) { net_log_.AddEvent(NetLog::TYPE_INIT_PROXY_RESOLVER_HAS_NO_FETCHER, NULL); @@ -190,7 +190,7 @@ int InitProxyResolver::DoFetchPacScriptComplete(int result) { } else { net_log_.EndEvent( NetLog::TYPE_INIT_PROXY_RESOLVER_FETCH_PAC_SCRIPT, - new NetLogIntegerParameter("net_error", result)); + make_scoped_refptr(new NetLogIntegerParameter("net_error", result))); return TryToFallbackPacUrl(result); } @@ -222,7 +222,7 @@ int InitProxyResolver::DoSetPacScriptComplete(int result) { if (result != OK) { net_log_.EndEvent( NetLog::TYPE_INIT_PROXY_RESOLVER_SET_PAC_SCRIPT, - new NetLogIntegerParameter("net_error", result)); + make_scoped_refptr(new NetLogIntegerParameter("net_error", result))); return TryToFallbackPacUrl(result); } diff --git a/net/proxy/multi_threaded_proxy_resolver.cc b/net/proxy/multi_threaded_proxy_resolver.cc index 95071b1..d696438 100644 --- a/net/proxy/multi_threaded_proxy_resolver.cc +++ b/net/proxy/multi_threaded_proxy_resolver.cc @@ -247,8 +247,8 @@ class MultiThreadedProxyResolver::GetProxyForURLJob net_log_.AddEvent( NetLog::TYPE_SUBMITTED_TO_RESOLVER_THREAD, - new NetLogIntegerParameter( - "thread_number", executor()->thread_number())); + make_scoped_refptr(new NetLogIntegerParameter( + "thread_number", executor()->thread_number()))); } // Runs on the worker thread. @@ -410,8 +410,8 @@ int MultiThreadedProxyResolver::GetProxyForURL(const GURL& url, DCHECK(current_script_data_.get()) << "Resolver is un-initialized. Must call SetPacScript() first!"; - scoped_refptr<GetProxyForURLJob> job = - new GetProxyForURLJob(url, results, callback, net_log); + scoped_refptr<GetProxyForURLJob> job( + new GetProxyForURLJob(url, results, callback, net_log)); // Completion will be notified through |callback|, unless the caller cancels // the request using |request|. @@ -557,7 +557,7 @@ MultiThreadedProxyResolver::AddNewExecutor() { ProxyResolver* resolver = resolver_factory_->CreateProxyResolver(); Executor* executor = new Executor( this, resolver, thread_number); - executors_.push_back(executor); + executors_.push_back(make_scoped_refptr(executor)); return executor; } diff --git a/net/proxy/proxy_bypass_rules.cc b/net/proxy/proxy_bypass_rules.cc index 757d817..d80e6f1 100644 --- a/net/proxy/proxy_bypass_rules.cc +++ b/net/proxy/proxy_bypass_rules.cc @@ -171,14 +171,14 @@ bool ProxyBypassRules::AddRuleForHostname(const std::string& optional_scheme, if (hostname_pattern.empty()) return false; - rules_.push_back(new HostnamePatternRule(optional_scheme, - hostname_pattern, - optional_port)); + rules_.push_back(make_scoped_refptr(new HostnamePatternRule(optional_scheme, + hostname_pattern, + optional_port))); return true; } void ProxyBypassRules::AddRuleToBypassLocal() { - rules_.push_back(new BypassLocalRule); + rules_.push_back(make_scoped_refptr(new BypassLocalRule)); } bool ProxyBypassRules::AddRuleFromString(const std::string& raw) { @@ -241,8 +241,8 @@ bool ProxyBypassRules::AddRuleFromStringInternal( if (!ParseCIDRBlock(raw, &ip_prefix, &prefix_length_in_bits)) return false; - rules_.push_back( - new BypassIPBlockRule(raw, scheme, ip_prefix, prefix_length_in_bits)); + rules_.push_back(make_scoped_refptr( + new BypassIPBlockRule(raw, scheme, ip_prefix, prefix_length_in_bits))); return true; } @@ -264,7 +264,7 @@ bool ProxyBypassRules::AddRuleFromStringInternal( host = raw; port = -1; if (pos_colon != std::string::npos) { - if (!base::StringToInt(raw.substr(pos_colon + 1), &port) || + if (!base::StringToInt(raw.begin() + pos_colon + 1, raw.end(), &port) || (port < 0 || port > 0xFFFF)) { return false; // Port was invalid. } diff --git a/net/proxy/proxy_config_service_win.cc b/net/proxy/proxy_config_service_win.cc index d0a387f..5aca4ae 100644 --- a/net/proxy/proxy_config_service_win.cc +++ b/net/proxy/proxy_config_service_win.cc @@ -12,6 +12,7 @@ #include "base/string_tokenizer.h" #include "base/string_util.h" #include "base/stl_util-inl.h" +#include "base/thread_restrictions.h" #include "base/win/registry.h" #include "net/base/net_errors.h" #include "net/proxy/proxy_config.h" @@ -72,6 +73,9 @@ ProxyConfigServiceWin::ProxyConfigServiceWin() } ProxyConfigServiceWin::~ProxyConfigServiceWin() { + // The registry functions below will end up going to disk. Do this on another + // thread to avoid slowing the IO thread. http://crbug.com/61453 + base::ThreadRestrictions::ScopedAllowIO allow_io; STLDeleteElements(&keys_to_watch_); } @@ -87,6 +91,10 @@ void ProxyConfigServiceWin::StartWatchingRegistryForChanges() { if (!keys_to_watch_.empty()) return; // Already initialized. + // The registry functions below will end up going to disk. Do this on another + // thread to avoid slowing the IO thread. http://crbug.com/61453 + base::ThreadRestrictions::ScopedAllowIO allow_io; + // There are a number of different places where proxy settings can live // in the registry. In some cases it appears in a binary value, in other // cases string values. Furthermore winhttp and wininet appear to have diff --git a/net/proxy/proxy_script_fetcher_impl_unittest.cc b/net/proxy/proxy_script_fetcher_impl_unittest.cc index f84be57..2642f4d 100644 --- a/net/proxy/proxy_script_fetcher_impl_unittest.cc +++ b/net/proxy/proxy_script_fetcher_impl_unittest.cc @@ -36,7 +36,7 @@ class RequestContext : public URLRequestContext { net::ProxyConfig no_proxy; host_resolver_ = net::CreateSystemHostResolver(net::HostResolver::kDefaultParallelism, - NULL); + NULL, NULL); proxy_service_ = net::ProxyService::CreateFixed(no_proxy); ssl_config_service_ = new net::SSLConfigServiceDefaults; @@ -78,7 +78,7 @@ class ProxyScriptFetcherImplTest : public PlatformTest { }; TEST_F(ProxyScriptFetcherImplTest, FileUrl) { - scoped_refptr<URLRequestContext> context = new RequestContext; + scoped_refptr<URLRequestContext> context(new RequestContext); scoped_ptr<ProxyScriptFetcher> pac_fetcher( new ProxyScriptFetcherImpl(context)); @@ -107,7 +107,7 @@ TEST_F(ProxyScriptFetcherImplTest, FileUrl) { TEST_F(ProxyScriptFetcherImplTest, HttpMimeType) { ASSERT_TRUE(test_server_.Start()); - scoped_refptr<URLRequestContext> context = new RequestContext; + scoped_refptr<URLRequestContext> context(new RequestContext); scoped_ptr<ProxyScriptFetcher> pac_fetcher( new ProxyScriptFetcherImpl(context)); @@ -143,7 +143,7 @@ TEST_F(ProxyScriptFetcherImplTest, HttpMimeType) { TEST_F(ProxyScriptFetcherImplTest, HttpStatusCode) { ASSERT_TRUE(test_server_.Start()); - scoped_refptr<URLRequestContext> context = new RequestContext; + scoped_refptr<URLRequestContext> context(new RequestContext); scoped_ptr<ProxyScriptFetcher> pac_fetcher( new ProxyScriptFetcherImpl(context)); @@ -170,7 +170,7 @@ TEST_F(ProxyScriptFetcherImplTest, HttpStatusCode) { TEST_F(ProxyScriptFetcherImplTest, ContentDisposition) { ASSERT_TRUE(test_server_.Start()); - scoped_refptr<URLRequestContext> context = new RequestContext; + scoped_refptr<URLRequestContext> context(new RequestContext); scoped_ptr<ProxyScriptFetcher> pac_fetcher( new ProxyScriptFetcherImpl(context)); @@ -188,7 +188,7 @@ TEST_F(ProxyScriptFetcherImplTest, ContentDisposition) { TEST_F(ProxyScriptFetcherImplTest, NoCache) { ASSERT_TRUE(test_server_.Start()); - scoped_refptr<URLRequestContext> context = new RequestContext; + scoped_refptr<URLRequestContext> context(new RequestContext); scoped_ptr<ProxyScriptFetcher> pac_fetcher( new ProxyScriptFetcherImpl(context)); @@ -221,7 +221,7 @@ TEST_F(ProxyScriptFetcherImplTest, NoCache) { TEST_F(ProxyScriptFetcherImplTest, TooLarge) { ASSERT_TRUE(test_server_.Start()); - scoped_refptr<URLRequestContext> context = new RequestContext; + scoped_refptr<URLRequestContext> context(new RequestContext); scoped_ptr<ProxyScriptFetcherImpl> pac_fetcher( new ProxyScriptFetcherImpl(context)); @@ -263,7 +263,7 @@ TEST_F(ProxyScriptFetcherImplTest, TooLarge) { TEST_F(ProxyScriptFetcherImplTest, Hang) { ASSERT_TRUE(test_server_.Start()); - scoped_refptr<URLRequestContext> context = new RequestContext; + scoped_refptr<URLRequestContext> context(new RequestContext); scoped_ptr<ProxyScriptFetcherImpl> pac_fetcher( new ProxyScriptFetcherImpl(context)); @@ -302,7 +302,7 @@ TEST_F(ProxyScriptFetcherImplTest, Hang) { TEST_F(ProxyScriptFetcherImplTest, Encodings) { ASSERT_TRUE(test_server_.Start()); - scoped_refptr<URLRequestContext> context = new RequestContext; + scoped_refptr<URLRequestContext> context(new RequestContext); scoped_ptr<ProxyScriptFetcher> pac_fetcher( new ProxyScriptFetcherImpl(context)); diff --git a/net/proxy/proxy_service.cc b/net/proxy/proxy_service.cc index 5e11ef1..b4aa96d 100644 --- a/net/proxy/proxy_service.cc +++ b/net/proxy/proxy_service.cc @@ -525,8 +525,8 @@ int ProxyService::ResolveProxy(const GURL& raw_url, if (rv != ERR_IO_PENDING) return DidFinishResolvingProxy(result, rv, net_log); - scoped_refptr<PacRequest> req = - new PacRequest(this, url, result, callback, net_log); + scoped_refptr<PacRequest> req( + new PacRequest(this, url, result, callback, net_log)); if (current_state_ == STATE_READY) { // Start the resolve request. @@ -715,13 +715,15 @@ int ProxyService::DidFinishResolvingProxy(ProxyInfo* result, if (net_log.IsLoggingAllEvents()) { net_log.AddEvent( NetLog::TYPE_PROXY_SERVICE_RESOLVED_PROXY_LIST, - new NetLogStringParameter("pac_string", result->ToPacString())); + make_scoped_refptr(new NetLogStringParameter( + "pac_string", result->ToPacString()))); } result->DeprioritizeBadProxies(proxy_retry_info_); } else { net_log.AddEvent( NetLog::TYPE_PROXY_SERVICE_RESOLVED_PROXY_LIST, - new NetLogIntegerParameter("net_error", result_code)); + make_scoped_refptr(new NetLogIntegerParameter( + "net_error", result_code))); // Fall-back to direct when the proxy resolver fails. This corresponds // with a javascript runtime error in the PAC script. @@ -831,8 +833,8 @@ ProxyConfigService* ProxyService::CreateSystemProxyConfigService( void ProxyService::OnProxyConfigChanged(const ProxyConfig& config) { // Emit the proxy settings change to the NetLog stream. if (net_log_) { - scoped_refptr<NetLog::EventParameters> params = - new ProxyConfigChangedNetLogParam(fetched_config_, config); + scoped_refptr<NetLog::EventParameters> params( + new ProxyConfigChangedNetLogParam(fetched_config_, config)); net_log_->AddEntry(net::NetLog::TYPE_PROXY_CONFIG_CHANGED, base::TimeTicks::Now(), NetLog::Source(), diff --git a/net/server/http_listen_socket.cc b/net/server/http_listen_socket.cc index b4f05d9..f35582b 100644 --- a/net/server/http_listen_socket.cc +++ b/net/server/http_listen_socket.cc @@ -37,8 +37,8 @@ void HttpListenSocket::Accept() { if (conn == ListenSocket::kInvalidSocket) { // TODO } else { - scoped_refptr<HttpListenSocket> sock = - new HttpListenSocket(conn, delegate_); + scoped_refptr<HttpListenSocket> sock( + new HttpListenSocket(conn, delegate_)); #if defined(OS_POSIX) sock->WatchSocket(WAITING_READ); #endif diff --git a/net/socket/client_socket.cc b/net/socket/client_socket.cc index 6f38eae..6b12841 100644 --- a/net/socket/client_socket.cc +++ b/net/socket/client_socket.cc @@ -58,6 +58,14 @@ ClientSocket::UseHistory::~UseHistory() { EmitPreconnectionHistograms(); } +void ClientSocket::UseHistory::Reset() { + EmitPreconnectionHistograms(); + was_ever_connected_ = false; + was_used_to_convey_data_ = false; + // omnibox_speculation_ and subresource_speculation_ values + // are intentionally preserved. +} + void ClientSocket::UseHistory::EmitPreconnectionHistograms() const { DCHECK(!subresource_speculation_ || !omnibox_speculation_); // 0 ==> non-speculative, never connected. diff --git a/net/socket/client_socket.h b/net/socket/client_socket.h index b4173c0..358716c 100644 --- a/net/socket/client_socket.h +++ b/net/socket/client_socket.h @@ -69,6 +69,10 @@ class ClientSocket : public Socket { // this call to the transport socket. virtual bool WasEverUsed() const = 0; + // Returns true if the underlying transport socket is using TCP FastOpen. + // TCP FastOpen is an experiment with sending data in the TCP SYN packet. + virtual bool UsingTCPFastOpen() const = 0; + protected: // The following class is only used to gather statistics about the history of // a socket. It is only instantiated and used in basic sockets, such as @@ -80,6 +84,10 @@ class ClientSocket : public Socket { UseHistory(); ~UseHistory(); + // Resets the state of UseHistory and emits histograms for the + // current state. + void Reset(); + void set_was_ever_connected(); void set_was_used_to_convey_data(); diff --git a/net/socket/client_socket_factory.cc b/net/socket/client_socket_factory.cc index 3ac5a00..947a2fa 100644 --- a/net/socket/client_socket_factory.cc +++ b/net/socket/client_socket_factory.cc @@ -16,7 +16,6 @@ #elif defined(USE_OPENSSL) && defined(ANDROID) #include "net/socket/ssl_client_socket_openssl.h" #elif defined(OS_MACOSX) -#include "net/socket/ssl_client_socket_mac.h" #include "net/socket/ssl_client_socket_nss.h" #endif #include "net/socket/ssl_host_info.h" @@ -24,13 +23,16 @@ namespace net { +class DnsRRResolver; + namespace { SSLClientSocket* DefaultSSLClientSocketFactory( ClientSocketHandle* transport_socket, const std::string& hostname, const SSLConfig& ssl_config, - SSLHostInfo* ssl_host_info) { + SSLHostInfo* ssl_host_info, + DnsRRResolver* dnsrr_resolver) { scoped_ptr<SSLHostInfo> shi(ssl_host_info); #if defined(OS_WIN) return new SSLClientSocketWin(transport_socket, hostname, ssl_config); @@ -38,16 +40,10 @@ SSLClientSocket* DefaultSSLClientSocketFactory( return new SSLClientSocketOpenSSL(transport_socket, hostname, ssl_config); #elif defined(USE_NSS) return new SSLClientSocketNSS(transport_socket, hostname, ssl_config, - shi.release()); + shi.release(), dnsrr_resolver); #elif defined(OS_MACOSX) - // TODO(wtc): SSLClientSocketNSS can't do SSL client authentication using - // Mac OS X CDSA/CSSM yet (http://crbug.com/45369), so fall back on - // SSLClientSocketMac. - if (ssl_config.send_client_cert) - return new SSLClientSocketMac(transport_socket, hostname, ssl_config); - return new SSLClientSocketNSS(transport_socket, hostname, ssl_config, - shi.release()); + shi.release(), dnsrr_resolver); #else NOTIMPLEMENTED(); return NULL; @@ -69,8 +65,10 @@ class DefaultClientSocketFactory : public ClientSocketFactory { ClientSocketHandle* transport_socket, const std::string& hostname, const SSLConfig& ssl_config, - SSLHostInfo* ssl_host_info) { - return g_ssl_factory(transport_socket, hostname, ssl_config, ssl_host_info); + SSLHostInfo* ssl_host_info, + DnsRRResolver* dnsrr_resolver) { + return g_ssl_factory(transport_socket, hostname, ssl_config, ssl_host_info, + dnsrr_resolver); } }; @@ -96,7 +94,7 @@ SSLClientSocket* ClientSocketFactory::CreateSSLClientSocket( ClientSocketHandle* socket_handle = new ClientSocketHandle(); socket_handle->set_socket(transport_socket); return CreateSSLClientSocket(socket_handle, hostname, ssl_config, - ssl_host_info); + ssl_host_info, NULL /* DnsRRResolver */); } } // namespace net diff --git a/net/socket/client_socket_factory.h b/net/socket/client_socket_factory.h index ad2cc54..4814b9c 100644 --- a/net/socket/client_socket_factory.h +++ b/net/socket/client_socket_factory.h @@ -15,6 +15,7 @@ namespace net { class AddressList; class ClientSocket; class ClientSocketHandle; +class DnsRRResolver; class SSLClientSocket; struct SSLConfig; class SSLHostInfo; @@ -24,7 +25,8 @@ typedef SSLClientSocket* (*SSLClientSocketFactory)( ClientSocketHandle* transport_socket, const std::string& hostname, const SSLConfig& ssl_config, - SSLHostInfo* ssl_host_info); + SSLHostInfo* ssl_host_info, + DnsRRResolver* dnsrr_resolver); // An interface used to instantiate ClientSocket objects. Used to facilitate // testing code with mock socket implementations. @@ -43,7 +45,8 @@ class ClientSocketFactory { ClientSocketHandle* transport_socket, const std::string& hostname, const SSLConfig& ssl_config, - SSLHostInfo* ssl_host_info) = 0; + SSLHostInfo* ssl_host_info, + DnsRRResolver* dnsrr_resolver) = 0; // Deprecated function (http://crbug.com/37810) that takes a ClientSocket. virtual SSLClientSocket* CreateSSLClientSocket(ClientSocket* transport_socket, diff --git a/net/socket/client_socket_handle.cc b/net/socket/client_socket_handle.cc index 6184905..29b5bd3 100644 --- a/net/socket/client_socket_handle.cc +++ b/net/socket/client_socket_handle.cc @@ -116,7 +116,8 @@ void ClientSocketHandle::HandleInitCompletion(int result) { DCHECK(socket_.get()); socket_->NetLog().BeginEvent( NetLog::TYPE_SOCKET_IN_USE, - new NetLogSourceParameter("source_dependency", requesting_source_)); + make_scoped_refptr(new NetLogSourceParameter( + "source_dependency", requesting_source_))); } } // namespace net diff --git a/net/socket/client_socket_pool_base.cc b/net/socket/client_socket_pool_base.cc index 75abae6..2228729 100644 --- a/net/socket/client_socket_pool_base.cc +++ b/net/socket/client_socket_pool_base.cc @@ -87,9 +87,9 @@ void ConnectJob::UseForNormalRequest() { void ConnectJob::set_socket(ClientSocket* socket) { if (socket) { - net_log().AddEvent(NetLog::TYPE_CONNECT_JOB_SET_SOCKET, - new NetLogSourceParameter("source_dependency", - socket->NetLog().source())); + net_log().AddEvent(NetLog::TYPE_CONNECT_JOB_SET_SOCKET, make_scoped_refptr( + new NetLogSourceParameter("source_dependency", + socket->NetLog().source()))); } socket_.reset(socket); } @@ -110,7 +110,7 @@ void ConnectJob::ResetTimer(base::TimeDelta remaining_time) { void ConnectJob::LogConnectStart() { net_log().BeginEvent(NetLog::TYPE_SOCKET_POOL_CONNECT_JOB_CONNECT, - new NetLogStringParameter("group_name", group_name_)); + make_scoped_refptr(new NetLogStringParameter("group_name", group_name_))); } void ConnectJob::LogConnectCompletion(int net_error) { @@ -239,7 +239,8 @@ void ClientSocketPoolBaseHelper::RequestSockets( request.net_log().BeginEvent( NetLog::TYPE_SOCKET_POOL_CONNECTING_N_SOCKETS, - new NetLogIntegerParameter("num_sockets", num_sockets)); + make_scoped_refptr(new NetLogIntegerParameter( + "num_sockets", num_sockets))); Group* group = GetOrCreateGroup(group_name); @@ -394,7 +395,8 @@ void ClientSocketPoolBaseHelper::LogBoundConnectJobToRequest( const NetLog::Source& connect_job_source, const Request* request) { request->net_log().AddEvent( NetLog::TYPE_SOCKET_POOL_BOUND_TO_CONNECT_JOB, - new NetLogSourceParameter("source_dependency", connect_job_source)); + make_scoped_refptr(new NetLogSourceParameter( + "source_dependency", connect_job_source))); } void ClientSocketPoolBaseHelper::CancelRequest( @@ -763,8 +765,8 @@ void ClientSocketPoolBaseHelper::OnConnectJobComplete( HandOutSocket(socket.release(), false /* unused socket */, r->handle(), base::TimeDelta(), group, r->net_log()); } - r->net_log().EndEvent(NetLog::TYPE_SOCKET_POOL, - new NetLogIntegerParameter("net_error", result)); + r->net_log().EndEvent(NetLog::TYPE_SOCKET_POOL, make_scoped_refptr( + new NetLogIntegerParameter("net_error", result))); InvokeUserCallbackLater(r->handle(), r->callback(), result); } else { RemoveConnectJob(job, group); @@ -849,13 +851,13 @@ void ClientSocketPoolBaseHelper::HandOutSocket( if (reused) { net_log.AddEvent( NetLog::TYPE_SOCKET_POOL_REUSED_AN_EXISTING_SOCKET, - new NetLogIntegerParameter( - "idle_ms", static_cast<int>(idle_time.InMilliseconds()))); + make_scoped_refptr(new NetLogIntegerParameter( + "idle_ms", static_cast<int>(idle_time.InMilliseconds())))); } net_log.AddEvent(NetLog::TYPE_SOCKET_POOL_BOUND_TO_SOCKET, - new NetLogSourceParameter( - "source_dependency", socket->NetLog().source())); + make_scoped_refptr(new NetLogSourceParameter( + "source_dependency", socket->NetLog().source()))); handed_out_socket_count_++; group->IncrementActiveSocketCount(); diff --git a/net/socket/client_socket_pool_base_unittest.cc b/net/socket/client_socket_pool_base_unittest.cc index 820b030..7b83162 100644 --- a/net/socket/client_socket_pool_base_unittest.cc +++ b/net/socket/client_socket_pool_base_unittest.cc @@ -81,6 +81,7 @@ class MockClientSocket : public ClientSocket { virtual void SetSubresourceSpeculation() {} virtual void SetOmniboxSpeculation() {} virtual bool WasEverUsed() const { return was_used_to_convey_data_; } + virtual bool UsingTCPFastOpen() const { return false; } private: bool connected_; @@ -108,7 +109,8 @@ class MockClientSocketFactory : public ClientSocketFactory { ClientSocketHandle* transport_socket, const std::string& hostname, const SSLConfig& ssl_config, - SSLHostInfo* ssl_host_info) { + SSLHostInfo* ssl_host_info, + DnsRRResolver* dnsrr_resolver) { NOTIMPLEMENTED(); delete ssl_host_info; return NULL; @@ -1280,7 +1282,7 @@ class RequestSocketCallback : public CallbackRunner< Tuple1<int> > { } within_callback_ = true; TestCompletionCallback next_job_callback; - scoped_refptr<TestSocketParams> params = new TestSocketParams(); + scoped_refptr<TestSocketParams> params(new TestSocketParams()); int rv = handle_->Init("a", params, kDefaultPriority, @@ -2086,7 +2088,7 @@ class TestReleasingSocketRequest : public CallbackRunner< Tuple1<int> > { callback_.RunWithParams(params); if (reset_releasing_handle_) handle_.Reset(); - scoped_refptr<TestSocketParams> con_params = new TestSocketParams(); + scoped_refptr<TestSocketParams> con_params(new TestSocketParams()); EXPECT_EQ(expected_result_, handle2_.Init("a", con_params, kDefaultPriority, diff --git a/net/socket/deterministic_socket_data_unittest.cc b/net/socket/deterministic_socket_data_unittest.cc index 199dd0b..5e25aa0 100644 --- a/net/socket/deterministic_socket_data_unittest.cc +++ b/net/socket/deterministic_socket_data_unittest.cc @@ -131,7 +131,7 @@ void DeterministicSocketDataTest::AssertReadBufferEquals(const char* data, void DeterministicSocketDataTest::AssertSyncWriteEquals(const char* data, int len) { - scoped_refptr<IOBuffer> buf = new IOBuffer(len); + scoped_refptr<IOBuffer> buf(new IOBuffer(len)); memcpy(buf->data(), data, len); // Issue the write, which will complete immediately @@ -152,7 +152,7 @@ void DeterministicSocketDataTest::AssertAsyncWriteEquals(const char* data, void DeterministicSocketDataTest::AssertWriteReturns(const char* data, int len, int rv) { - scoped_refptr<IOBuffer> buf = new IOBuffer(len); + scoped_refptr<IOBuffer> buf(new IOBuffer(len)); memcpy(buf->data(), data, len); // Issue the read, which will complete asynchronously diff --git a/net/socket/dns_cert_provenance_check.cc b/net/socket/dns_cert_provenance_check.cc new file mode 100644 index 0000000..e83cb5e --- /dev/null +++ b/net/socket/dns_cert_provenance_check.cc @@ -0,0 +1,111 @@ +// Copyright (c) 2010 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/socket/dns_cert_provenance_check.h" + +#include <nspr.h> +#include <hasht.h> +#include <sechash.h> + +#include <string> + +#include "base/non_thread_safe.h" +#include "net/base/completion_callback.h" +#include "net/base/dns_util.h" +#include "net/base/dnsrr_resolver.h" +#include "net/base/net_log.h" +#include "net/base/net_errors.h" + +namespace net { + +namespace { + +class DNSCertProvenanceChecker : public NonThreadSafe { + public: + DNSCertProvenanceChecker(const std::string hostname, + DnsRRResolver* dnsrr_resolver, + const std::vector<base::StringPiece>& der_certs) + : hostname_(hostname), + dnsrr_resolver_(dnsrr_resolver), + der_certs_(der_certs.size()), + handle_(DnsRRResolver::kInvalidHandle), + ALLOW_THIS_IN_INITIALIZER_LIST(callback_( + this, &DNSCertProvenanceChecker::ResolutionComplete)) { + for (size_t i = 0; i < der_certs.size(); i++) + der_certs_[i] = der_certs[i].as_string(); + } + + void Start() { + DCHECK(CalledOnValidThread()); + + if (der_certs_.empty()) + return; + + uint8 fingerprint[SHA1_LENGTH]; + SECStatus rv = HASH_HashBuf( + HASH_AlgSHA1, fingerprint, (uint8*) der_certs_[0].data(), + der_certs_[0].size()); + DCHECK_EQ(SECSuccess, rv); + char fingerprint_hex[SHA1_LENGTH * 2 + 1]; + for (unsigned i = 0; i < sizeof(fingerprint); i++) { + static const char hextable[] = "0123456789abcdef"; + fingerprint_hex[i*2] = hextable[fingerprint[i] >> 4]; + fingerprint_hex[i*2 + 1] = hextable[fingerprint[i] & 15]; + } + fingerprint_hex[SHA1_LENGTH * 2] = 0; + + static const char kBaseCertName[] = ".certs.links.org"; + domain_.assign(fingerprint_hex); + domain_.append(kBaseCertName); + + handle_ = dnsrr_resolver_->Resolve( + domain_, kDNS_TXT, 0 /* flags */, &callback_, &response_, + 0 /* priority */, BoundNetLog()); + if (handle_ == DnsRRResolver::kInvalidHandle) { + LOG(ERROR) << "Failed to resolve " << domain_ << " for " << hostname_; + delete this; + } + } + + private: + void ResolutionComplete(int status) { + DCHECK(CalledOnValidThread()); + + if (status == ERR_NAME_NOT_RESOLVED || + (status == OK && response_.rrdatas.empty())) { + LOG(ERROR) << "FAILED" + << " hostname:" << hostname_ + << " domain:" << domain_; + } else if (status == OK) { + LOG(ERROR) << "GOOD" + << " hostname:" << hostname_ + << " resp:" << response_.rrdatas[0]; + } else { + LOG(ERROR) << "Unknown error " << status << " for " << domain_; + } + + delete this; + } + + const std::string hostname_; + std::string domain_; + DnsRRResolver* const dnsrr_resolver_; + std::vector<std::string> der_certs_; + RRResponse response_; + DnsRRResolver::Handle handle_; + CompletionCallbackImpl<DNSCertProvenanceChecker> callback_; +}; + +} // anonymous namespace + +void DoAsyncDNSCertProvenanceVerification( + const std::string& hostname, + DnsRRResolver* dnsrr_resolver, + const std::vector<base::StringPiece>& der_certs) { + DNSCertProvenanceChecker* c(new DNSCertProvenanceChecker( + hostname, dnsrr_resolver, der_certs)); + c->Start(); +} + +} // namespace net diff --git a/net/socket/dns_cert_provenance_check.h b/net/socket/dns_cert_provenance_check.h new file mode 100644 index 0000000..289cccf --- /dev/null +++ b/net/socket/dns_cert_provenance_check.h @@ -0,0 +1,26 @@ +// Copyright (c) 2010 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_SOCKET_DNS_CERT_PROVENANCE_CHECK_H +#define NET_SOCKET_DNS_CERT_PROVENANCE_CHECK_H + +#include <string> +#include <vector> + +#include "base/string_piece.h" + +namespace net { + +class DnsRRResolver; + +// DoAsyncDNSCertProvenanceVerification starts an asynchronous check for the +// given certificate chain. It must be run on the network thread. +void DoAsyncDNSCertProvenanceVerification( + const std::string& hostname, + DnsRRResolver* dnsrr_resolver, + const std::vector<base::StringPiece>& der_certs); + +} // namespace net + +#endif // NET_SOCKET_DNS_CERT_PROVENANCE_CHECK_H diff --git a/net/socket/socket_test_util.cc b/net/socket/socket_test_util.cc index 53bcf89..57aef05 100644 --- a/net/socket/socket_test_util.cc +++ b/net/socket/socket_test_util.cc @@ -513,6 +513,10 @@ bool MockSSLClientSocket::WasEverUsed() const { return transport_->socket()->WasEverUsed(); } +bool MockSSLClientSocket::UsingTCPFastOpen() const { + return transport_->socket()->UsingTCPFastOpen(); +} + int MockSSLClientSocket::Read(net::IOBuffer* buf, int buf_len, net::CompletionCallback* callback) { return transport_->socket()->Read(buf, buf_len, callback); @@ -1011,7 +1015,8 @@ SSLClientSocket* MockClientSocketFactory::CreateSSLClientSocket( ClientSocketHandle* transport_socket, const std::string& hostname, const SSLConfig& ssl_config, - SSLHostInfo* ssl_host_info) { + SSLHostInfo* ssl_host_info, + DnsRRResolver* dnsrr_resolver) { MockSSLClientSocket* socket = new MockSSLClientSocket(transport_socket, hostname, ssl_config, ssl_host_info, mock_ssl_data_.GetNext()); @@ -1060,7 +1065,8 @@ SSLClientSocket* DeterministicMockClientSocketFactory::CreateSSLClientSocket( ClientSocketHandle* transport_socket, const std::string& hostname, const SSLConfig& ssl_config, - SSLHostInfo* ssl_host_info) { + SSLHostInfo* ssl_host_info, + DnsRRResolver* dnsrr_resolver) { MockSSLClientSocket* socket = new MockSSLClientSocket(transport_socket, hostname, ssl_config, ssl_host_info, mock_ssl_data_.GetNext()); diff --git a/net/socket/socket_test_util.h b/net/socket/socket_test_util.h index a8e4537..349013e 100644 --- a/net/socket/socket_test_util.h +++ b/net/socket/socket_test_util.h @@ -534,7 +534,8 @@ class MockClientSocketFactory : public ClientSocketFactory { ClientSocketHandle* transport_socket, const std::string& hostname, const SSLConfig& ssl_config, - SSLHostInfo* ssl_host_info); + SSLHostInfo* ssl_host_info, + DnsRRResolver* dnsrr_resolver); SocketDataProviderArray<SocketDataProvider>& mock_data() { return mock_data_; } @@ -609,6 +610,7 @@ class MockTCPClientSocket : public MockClientSocket { virtual bool IsConnected() const; virtual bool IsConnectedAndIdle() const { return IsConnected(); } virtual bool WasEverUsed() const { return was_used_to_convey_data_; } + virtual bool UsingTCPFastOpen() const { return false; } // Socket methods: virtual int Read(net::IOBuffer* buf, int buf_len, @@ -654,6 +656,7 @@ class DeterministicMockTCPClientSocket : public MockClientSocket, virtual bool IsConnected() const; virtual bool IsConnectedAndIdle() const { return IsConnected(); } virtual bool WasEverUsed() const { return was_used_to_convey_data_; } + virtual bool UsingTCPFastOpen() const { return false; } // Socket methods: virtual int Write(net::IOBuffer* buf, int buf_len, @@ -698,6 +701,7 @@ class MockSSLClientSocket : public MockClientSocket { virtual void Disconnect(); virtual bool IsConnected() const; virtual bool WasEverUsed() const; + virtual bool UsingTCPFastOpen() const; // Socket methods: virtual int Read(net::IOBuffer* buf, int buf_len, @@ -875,7 +879,8 @@ class DeterministicMockClientSocketFactory : public ClientSocketFactory { ClientSocketHandle* transport_socket, const std::string& hostname, const SSLConfig& ssl_config, - SSLHostInfo* ssl_host_info); + SSLHostInfo* ssl_host_info, + DnsRRResolver* dnsrr_resolver); SocketDataProviderArray<DeterministicSocketData>& mock_data() { return mock_data_; diff --git a/net/socket/socks5_client_socket.cc b/net/socket/socks5_client_socket.cc index 42bb859..02e5b1f 100644 --- a/net/socket/socks5_client_socket.cc +++ b/net/socket/socks5_client_socket.cc @@ -10,6 +10,7 @@ #include "base/basictypes.h" #include "base/compiler_specific.h" +#include "base/debug/trace_event.h" #include "base/format_macros.h" #include "base/string_util.h" #include "net/base/io_buffer.h" @@ -133,6 +134,14 @@ bool SOCKS5ClientSocket::WasEverUsed() const { return false; } +bool SOCKS5ClientSocket::UsingTCPFastOpen() const { + if (transport_.get() && transport_->socket()) { + return transport_->socket()->UsingTCPFastOpen(); + } + NOTREACHED(); + return false; +} + // Read is called by the transport layer above to read. This can only be done // if the SOCKS handshake is complete. int SOCKS5ClientSocket::Read(IOBuffer* buf, int buf_len, @@ -303,13 +312,15 @@ int SOCKS5ClientSocket::DoGreetReadComplete(int result) { // Got the greet data. if (buffer_[0] != kSOCKS5Version) { - net_log_.AddEvent(NetLog::TYPE_SOCKS_UNEXPECTED_VERSION, - new NetLogIntegerParameter("version", buffer_[0])); + net_log_.AddEvent( + NetLog::TYPE_SOCKS_UNEXPECTED_VERSION, + make_scoped_refptr(new NetLogIntegerParameter("version", buffer_[0]))); return ERR_SOCKS_CONNECTION_FAILED; } if (buffer_[1] != 0x00) { - net_log_.AddEvent(NetLog::TYPE_SOCKS_UNEXPECTED_AUTH, - new NetLogIntegerParameter("method", buffer_[1])); + net_log_.AddEvent( + NetLog::TYPE_SOCKS_UNEXPECTED_AUTH, + make_scoped_refptr(new NetLogIntegerParameter("method", buffer_[1]))); return ERR_SOCKS_CONNECTION_FAILED; } @@ -412,13 +423,17 @@ int SOCKS5ClientSocket::DoHandshakeReadComplete(int result) { // and accordingly increase them if (bytes_received_ == kReadHeaderSize) { if (buffer_[0] != kSOCKS5Version || buffer_[2] != kNullByte) { - net_log_.AddEvent(NetLog::TYPE_SOCKS_UNEXPECTED_VERSION, - new NetLogIntegerParameter("version", buffer_[0])); + net_log_.AddEvent( + NetLog::TYPE_SOCKS_UNEXPECTED_VERSION, + make_scoped_refptr( + new NetLogIntegerParameter("version", buffer_[0]))); return ERR_SOCKS_CONNECTION_FAILED; } if (buffer_[1] != 0x00) { - net_log_.AddEvent(NetLog::TYPE_SOCKS_SERVER_ERROR, - new NetLogIntegerParameter("error_code", buffer_[1])); + net_log_.AddEvent( + NetLog::TYPE_SOCKS_SERVER_ERROR, + make_scoped_refptr( + new NetLogIntegerParameter("error_code", buffer_[1]))); return ERR_SOCKS_CONNECTION_FAILED; } @@ -436,8 +451,10 @@ int SOCKS5ClientSocket::DoHandshakeReadComplete(int result) { else if (address_type == kEndPointResolvedIPv6) read_header_size += sizeof(struct in6_addr) - 1; else { - net_log_.AddEvent(NetLog::TYPE_SOCKS_UNKNOWN_ADDRESS_TYPE, - new NetLogIntegerParameter("address_type", buffer_[3])); + net_log_.AddEvent( + NetLog::TYPE_SOCKS_UNKNOWN_ADDRESS_TYPE, + make_scoped_refptr( + new NetLogIntegerParameter("address_type", buffer_[3]))); return ERR_SOCKS_CONNECTION_FAILED; } diff --git a/net/socket/socks5_client_socket.h b/net/socket/socks5_client_socket.h index 72e27db..5a918cc 100644 --- a/net/socket/socks5_client_socket.h +++ b/net/socket/socks5_client_socket.h @@ -59,6 +59,7 @@ class SOCKS5ClientSocket : public ClientSocket { virtual void SetSubresourceSpeculation(); virtual void SetOmniboxSpeculation(); virtual bool WasEverUsed() const; + virtual bool UsingTCPFastOpen() const; // Socket methods: virtual int Read(IOBuffer* buf, int buf_len, CompletionCallback* callback); diff --git a/net/socket/socks5_client_socket_unittest.cc b/net/socket/socks5_client_socket_unittest.cc index 43a441d..2152c86 100644 --- a/net/socket/socks5_client_socket_unittest.cc +++ b/net/socket/socks5_client_socket_unittest.cc @@ -141,7 +141,7 @@ TEST_F(SOCKS5ClientSocketTest, CompleteHandshake) { EXPECT_TRUE(LogContainsEndEvent(net_log_.entries(), -1, NetLog::TYPE_SOCKS5_CONNECT)); - scoped_refptr<IOBuffer> buffer = new IOBuffer(payload_write.size()); + scoped_refptr<IOBuffer> buffer(new IOBuffer(payload_write.size())); memcpy(buffer->data(), payload_write.data(), payload_write.size()); rv = user_sock_->Write(buffer, payload_write.size(), &callback_); EXPECT_EQ(ERR_IO_PENDING, rv); diff --git a/net/socket/socks_client_socket.cc b/net/socket/socks_client_socket.cc index 26cad34..4dad417 100644 --- a/net/socket/socks_client_socket.cc +++ b/net/socket/socks_client_socket.cc @@ -168,6 +168,15 @@ bool SOCKSClientSocket::WasEverUsed() const { return false; } +bool SOCKSClientSocket::UsingTCPFastOpen() const { + if (transport_.get() && transport_->socket()) { + return transport_->socket()->UsingTCPFastOpen(); + } + NOTREACHED(); + return false; +} + + // Read is called by the transport layer above to read. This can only be done // if the SOCKS handshake is complete. int SOCKSClientSocket::Read(IOBuffer* buf, int buf_len, diff --git a/net/socket/socks_client_socket.h b/net/socket/socks_client_socket.h index e9e9695..86511cf 100644 --- a/net/socket/socks_client_socket.h +++ b/net/socket/socks_client_socket.h @@ -56,6 +56,7 @@ class SOCKSClientSocket : public ClientSocket { virtual void SetSubresourceSpeculation(); virtual void SetOmniboxSpeculation(); virtual bool WasEverUsed() const; + virtual bool UsingTCPFastOpen() const; // Socket methods: virtual int Read(IOBuffer* buf, int buf_len, CompletionCallback* callback); diff --git a/net/socket/socks_client_socket_unittest.cc b/net/socket/socks_client_socket_unittest.cc index 086b21d..11a88ae 100644 --- a/net/socket/socks_client_socket_unittest.cc +++ b/net/socket/socks_client_socket_unittest.cc @@ -153,7 +153,7 @@ TEST_F(SOCKSClientSocketTest, CompleteHandshake) { EXPECT_TRUE(LogContainsEndEvent( log.entries(), -1, NetLog::TYPE_SOCKS_CONNECT)); - scoped_refptr<IOBuffer> buffer = new IOBuffer(payload_write.size()); + scoped_refptr<IOBuffer> buffer(new IOBuffer(payload_write.size())); memcpy(buffer->data(), payload_write.data(), payload_write.size()); rv = user_sock_->Write(buffer, payload_write.size(), &callback_); EXPECT_EQ(ERR_IO_PENDING, rv); diff --git a/net/socket/ssl_client_socket_mac.cc b/net/socket/ssl_client_socket_mac.cc index 6a8270e..d6fca9b 100644 --- a/net/socket/ssl_client_socket_mac.cc +++ b/net/socket/ssl_client_socket_mac.cc @@ -614,6 +614,14 @@ bool SSLClientSocketMac::WasEverUsed() const { return false; } +bool SSLClientSocketMac::UsingTCPFastOpen() const { + if (transport_.get() && transport_->socket()) { + return transport_->socket()->UsingTCPFastOpen(); + } + NOTREACHED(); + return false; +} + int SSLClientSocketMac::Read(IOBuffer* buf, int buf_len, CompletionCallback* callback) { DCHECK(completed_handshake()); @@ -1124,8 +1132,8 @@ int SSLClientSocketMac::DidCompleteHandshake() { DCHECK(!server_cert_ || renegotiating_); VLOG(1) << "Handshake completed, next verify cert"; - scoped_refptr<X509Certificate> new_server_cert = - GetServerCert(ssl_context_); + scoped_refptr<X509Certificate> new_server_cert( + GetServerCert(ssl_context_)); if (!new_server_cert) return ERR_UNEXPECTED; diff --git a/net/socket/ssl_client_socket_mac.h b/net/socket/ssl_client_socket_mac.h index 00438fc..0763fd3 100644 --- a/net/socket/ssl_client_socket_mac.h +++ b/net/socket/ssl_client_socket_mac.h @@ -50,6 +50,7 @@ class SSLClientSocketMac : public SSLClientSocket { virtual void SetSubresourceSpeculation(); virtual void SetOmniboxSpeculation(); virtual bool WasEverUsed() const; + virtual bool UsingTCPFastOpen() const; // Socket methods: virtual int Read(IOBuffer* buf, int buf_len, CompletionCallback* callback); diff --git a/net/socket/ssl_client_socket_mac_factory.cc b/net/socket/ssl_client_socket_mac_factory.cc index 7f0c5ce..d10e10d 100644 --- a/net/socket/ssl_client_socket_mac_factory.cc +++ b/net/socket/ssl_client_socket_mac_factory.cc @@ -13,7 +13,8 @@ SSLClientSocket* SSLClientSocketMacFactory( ClientSocketHandle* transport_socket, const std::string& hostname, const SSLConfig& ssl_config, - SSLHostInfo* ssl_host_info) { + SSLHostInfo* ssl_host_info, + DnsRRResolver* dnsrr_resolver) { delete ssl_host_info; return new SSLClientSocketMac(transport_socket, hostname, ssl_config); } diff --git a/net/socket/ssl_client_socket_mac_factory.h b/net/socket/ssl_client_socket_mac_factory.h index ca97b00..6f12883 100644 --- a/net/socket/ssl_client_socket_mac_factory.h +++ b/net/socket/ssl_client_socket_mac_factory.h @@ -10,6 +10,7 @@ namespace net { +class DnsRRResolver; class SSLHostInfo; // Creates SSLClientSocketMac objects. @@ -17,7 +18,8 @@ SSLClientSocket* SSLClientSocketMacFactory( ClientSocketHandle* transport_socket, const std::string& hostname, const SSLConfig& ssl_config, - SSLHostInfo* ssl_host_info); + SSLHostInfo* ssl_host_info, + DnsRRResolver* dnsrr_resolver); } // namespace net diff --git a/net/socket/ssl_client_socket_nss.cc b/net/socket/ssl_client_socket_nss.cc index 136f138..a6aa458 100644 --- a/net/socket/ssl_client_socket_nss.cc +++ b/net/socket/ssl_client_socket_nss.cc @@ -50,6 +50,9 @@ #if defined(USE_SYSTEM_SSL) #include <dlfcn.h> #endif +#if defined(OS_MACOSX) +#include <Security/Security.h> +#endif #include <certdb.h> #include <hasht.h> #include <keyhi.h> @@ -60,6 +63,7 @@ #include <sechash.h> #include <ssl.h> #include <sslerr.h> +#include <sslproto.h> #include <limits> @@ -71,10 +75,12 @@ #include "base/string_number_conversions.h" #include "base/string_util.h" #include "base/stringprintf.h" +#include "base/thread_restrictions.h" #include "base/values.h" #include "net/base/address_list.h" #include "net/base/cert_status_flags.h" #include "net/base/cert_verifier.h" +#include "net/base/connection_type_histograms.h" #include "net/base/dns_util.h" #include "net/base/dnsrr_resolver.h" #include "net/base/dnssec_chain_verifier.h" @@ -87,6 +93,7 @@ #include "net/base/sys_addrinfo.h" #include "net/ocsp/nss_ocsp.h" #include "net/socket/client_socket_handle.h" +#include "net/socket/dns_cert_provenance_check.h" #include "net/socket/ssl_host_info.h" static const int kRecvBufferSize = 4096; @@ -176,6 +183,11 @@ class NSSSSLInitSingleton { // thread-safe, and the NSS SSL library will only ever be initialized once. // The NSS SSL library will be properly shut down on program exit. void EnsureNSSSSLInit() { + // Initializing SSL causes us to do blocking IO. + // Temporarily allow it until we fix + // http://code.google.com/p/chromium/issues/detail?id=59847 + base::ThreadRestrictions::ScopedAllowIO allow_io; + Singleton<NSSSSLInitSingleton>::get(); } @@ -206,6 +218,8 @@ int MapNSPRError(PRErrorCode err) { return ERR_INVALID_ARGUMENT; case PR_END_OF_FILE_ERROR: return ERR_CONNECTION_CLOSED; + case PR_NOT_IMPLEMENTED_ERROR: + return ERR_NOT_IMPLEMENTED; case SEC_ERROR_INVALID_ARGS: return ERR_INVALID_ARGUMENT; @@ -309,52 +323,13 @@ class SSLFailedNSSFunctionParams : public NetLog::EventParameters { void LogFailedNSSFunction(const BoundNetLog& net_log, const char* function, const char* param) { - net_log.AddEvent(NetLog::TYPE_SSL_NSS_ERROR, - new SSLFailedNSSFunctionParams(function, param)); + net_log.AddEvent( + NetLog::TYPE_SSL_NSS_ERROR, + make_scoped_refptr(new SSLFailedNSSFunctionParams(function, param))); } #if defined(OS_WIN) -// A certificate for COMODO EV SGC CA, issued by AddTrust External CA Root, -// causes CertGetCertificateChain to report CERT_TRUST_IS_NOT_VALID_FOR_USAGE. -// It seems to be caused by the szOID_APPLICATION_CERT_POLICIES extension in -// that certificate. -// -// This function is used in the workaround for http://crbug.com/43538 -bool IsProblematicComodoEVCACert(const CERTCertificate& cert) { - // Issuer: - // CN = AddTrust External CA Root - // OU = AddTrust External TTP Network - // O = AddTrust AB - // C = SE - static const uint8 kIssuer[] = { - 0x30, 0x6f, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, - 0x06, 0x13, 0x02, 0x53, 0x45, 0x31, 0x14, 0x30, 0x12, 0x06, - 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0b, 0x41, 0x64, 0x64, 0x54, - 0x72, 0x75, 0x73, 0x74, 0x20, 0x41, 0x42, 0x31, 0x26, 0x30, - 0x24, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x1d, 0x41, 0x64, - 0x64, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x45, 0x78, 0x74, - 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x20, 0x54, 0x54, 0x50, 0x20, - 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x31, 0x22, 0x30, - 0x20, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x19, 0x41, 0x64, - 0x64, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x45, 0x78, 0x74, - 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x20, 0x43, 0x41, 0x20, 0x52, - 0x6f, 0x6f, 0x74 - }; - - // Serial number: 79:0A:83:4D:48:40:6B:AB:6C:35:2A:D5:1F:42:83:FE. - static const uint8 kSerialNumber[] = { - 0x79, 0x0a, 0x83, 0x4d, 0x48, 0x40, 0x6b, 0xab, 0x6c, 0x35, - 0x2a, 0xd5, 0x1f, 0x42, 0x83, 0xfe - }; - - return cert.derIssuer.len == sizeof(kIssuer) && - memcmp(cert.derIssuer.data, kIssuer, cert.derIssuer.len) == 0 && - cert.serialNumber.len == sizeof(kSerialNumber) && - memcmp(cert.serialNumber.data, kSerialNumber, - cert.serialNumber.len) == 0; -} - // This callback is intended to be used with CertFindChainInStore. In addition // to filtering by extended/enhanced key usage, we do not show expired // certificates and require digital signature usage in the key usage @@ -391,17 +366,61 @@ BOOL WINAPI ClientCertFindCallback(PCCERT_CONTEXT cert_context, #endif -} // namespace +// PeerCertificateChain is a helper object which extracts the certificate +// chain, as given by the server, from an NSS socket and performs the needed +// resource management. The first element of the chain is the leaf certificate +// and the other elements are in the order given by the server. +class PeerCertificateChain { + public: + explicit PeerCertificateChain(PRFileDesc* nss_fd) + : num_certs_(0), + certs_(NULL) { + SECStatus rv = SSL_PeerCertificateChain(nss_fd, NULL, &num_certs_); + DCHECK_EQ(rv, SECSuccess); -#if defined(OS_WIN) -// static -HCERTSTORE SSLClientSocketNSS::cert_store_ = NULL; -#endif + certs_ = new CERTCertificate*[num_certs_]; + const unsigned expected_num_certs = num_certs_; + rv = SSL_PeerCertificateChain(nss_fd, certs_, &num_certs_); + DCHECK_EQ(rv, SECSuccess); + DCHECK_EQ(num_certs_, expected_num_certs); + } + + ~PeerCertificateChain() { + for (unsigned i = 0; i < num_certs_; i++) + CERT_DestroyCertificate(certs_[i]); + delete[] certs_; + } + + unsigned size() const { return num_certs_; } + + CERTCertificate* operator[](unsigned i) { + DCHECK_LT(i, num_certs_); + return certs_[i]; + } + + std::vector<base::StringPiece> AsStringPieceVector() const { + std::vector<base::StringPiece> v(size()); + for (unsigned i = 0; i < size(); i++) { + v[i] = base::StringPiece( + reinterpret_cast<const char*>(certs_[i]->derCert.data), + certs_[i]->derCert.len); + } + + return v; + } + + private: + unsigned num_certs_; + CERTCertificate** certs_; +}; + +} // namespace SSLClientSocketNSS::SSLClientSocketNSS(ClientSocketHandle* transport_socket, const std::string& hostname, const SSLConfig& ssl_config, - SSLHostInfo* ssl_host_info) + SSLHostInfo* ssl_host_info, + DnsRRResolver* dnsrr_resolver) : ALLOW_THIS_IN_INITIALIZER_LIST(buffer_send_callback_( this, &SSLClientSocketNSS::BufferSendComplete)), ALLOW_THIS_IN_INITIALIZER_LIST(buffer_recv_callback_( @@ -420,12 +439,15 @@ SSLClientSocketNSS::SSLClientSocketNSS(ClientSocketHandle* transport_socket, user_read_buf_len_(0), user_write_buf_len_(0), server_cert_nss_(NULL), + server_cert_verify_result_(NULL), + ssl_connection_status_(0), client_auth_cert_needed_(false), handshake_callback_called_(false), completed_handshake_(false), pseudo_connected_(false), eset_mitm_detected_(false), - netnanny_mitm_detected_(false), + predicted_cert_chain_correct_(false), + peername_initialized_(false), dnssec_provider_(NULL), next_handshake_state_(STATE_NONE), nss_fd_(NULL), @@ -433,7 +455,8 @@ SSLClientSocketNSS::SSLClientSocketNSS(ClientSocketHandle* transport_socket, net_log_(transport_socket->socket()->NetLog()), predicted_npn_status_(kNextProtoUnsupported), predicted_npn_proto_used_(false), - ssl_host_info_(ssl_host_info) { + ssl_host_info_(ssl_host_info), + dnsrr_resolver_(dnsrr_resolver) { EnterFunction(""); } @@ -475,6 +498,8 @@ void SSLClientSocketNSS::SaveSnapStartInfo() { NOTREACHED(); return; } + net_log_.AddEvent(NetLog::TYPE_SSL_SNAP_START, + new NetLogIntegerParameter("type", snap_start_type)); LOG(ERROR) << "Snap Start: " << snap_start_type << " " << hostname_; if (snap_start_type == SSL_SNAP_START_FULL || snap_start_type == SSL_SNAP_START_RESUME) { @@ -490,43 +515,32 @@ void SSLClientSocketNSS::SaveSnapStartInfo() { NOTREACHED(); return; } - // If the server doesn't support Snap Start then |hello_data_len| is zero. - if (!hello_data_len) - return; if (hello_data_len > std::numeric_limits<uint16>::max()) return; SSLHostInfo::State* state = ssl_host_info_->mutable_state(); state->server_hello = std::string(reinterpret_cast<const char *>(hello_data), hello_data_len); - state->npn_valid = true; - state->npn_status = GetNextProto(&state->npn_protocol); - - // TODO(wtc): CERT_GetCertChainFromCert might not return the same cert chain - // that the Certificate message actually contained. http://crbug.com/48854 - CERTCertList* cert_list = CERT_GetCertChainFromCert( - server_cert_nss_, PR_Now(), certUsageSSLCA); - if (!cert_list) - return; + if (hello_data_len > 0) { + state->npn_valid = true; + state->npn_status = GetNextProto(&state->npn_protocol); + } else { + state->npn_valid = false; + } - for (CERTCertListNode* node = CERT_LIST_HEAD(cert_list); - !CERT_LIST_END(node, cert_list); - node = CERT_LIST_NEXT(node)) { - if (node->cert->derCert.len > std::numeric_limits<uint16>::max()) { - CERT_DestroyCertList(cert_list); + state->certs.clear(); + PeerCertificateChain certs(nss_fd_); + for (unsigned i = 0; i < certs.size(); i++) { + if (certs[i]->derCert.len > std::numeric_limits<uint16>::max()) return; - } - if (node->cert->isRoot == PR_TRUE) - continue; + state->certs.push_back(std::string( - reinterpret_cast<char*>(node->cert->derCert.data), - node->cert->derCert.len)); + reinterpret_cast<char*>(certs[i]->derCert.data), + certs[i]->derCert.len)); } LOG(ERROR) << "Setting Snap Start info " << hostname_; ssl_host_info_->Persist(); - - CERT_DestroyCertList(cert_list); } static void DestroyCertificates(CERTCertificate** certs, unsigned len) { @@ -625,6 +639,16 @@ int SSLClientSocketNSS::Connect(CompletionCallback* callback) { return rv; } + // Attempt to initialize the peer name. In the case of TCP FastOpen, + // we don't have the peer yet. + if (!UsingTCPFastOpen()) { + rv = InitializeSSLPeerName(); + if (rv != OK) { + net_log_.EndEvent(NetLog::TYPE_SSL_CONNECT, NULL); + return rv; + } + } + if (ssl_config_.snap_start_enabled && ssl_host_info_.get()) { GotoState(STATE_SNAP_START_LOAD_INFO); } else { @@ -655,28 +679,6 @@ int SSLClientSocketNSS::InitializeSSLOptions() { return ERR_OUT_OF_MEMORY; // TODO(port): map NSPR error code. } - // Tell NSS who we're connected to - AddressList peer_address; - int err = transport_->socket()->GetPeerAddress(&peer_address); - if (err != OK) - return err; - - const struct addrinfo* ai = peer_address.head(); - - PRNetAddr peername; - memset(&peername, 0, sizeof(peername)); - DCHECK_LE(ai->ai_addrlen, sizeof(peername)); - size_t len = std::min(static_cast<size_t>(ai->ai_addrlen), sizeof(peername)); - memcpy(&peername, ai->ai_addr, len); - - // Adjust the address family field for BSD, whose sockaddr - // structure has a one-byte length and one-byte address family - // field at the beginning. PRNetAddr has a two-byte address - // family field at the beginning. - peername.raw.family = ai->ai_addr->sa_family; - - memio_SetPeerName(nss_fd_, &peername); - // Grab pointer to buffers nss_bufs_ = memio_GetSecret(nss_fd_); @@ -761,7 +763,7 @@ int SSLClientSocketNSS::InitializeSSLOptions() { // TODO(agl): check that SSL_ENABLE_SNAP_START actually does something in the // current NSS code. rv = SSL_OptionSet(nss_fd_, SSL_ENABLE_SNAP_START, - SSLConfigService::snap_start_enabled()); + ssl_config_.snap_start_enabled); if (rv != SECSuccess) VLOG(1) << "SSL_ENABLE_SNAP_START failed. Old system nss?"; #endif @@ -816,7 +818,12 @@ int SSLClientSocketNSS::InitializeSSLOptions() { return ERR_UNEXPECTED; } +#if defined(NSS_PLATFORM_CLIENT_AUTH) + rv = SSL_GetPlatformClientAuthDataHook(nss_fd_, PlatformClientAuthHandler, + this); +#else rv = SSL_GetClientAuthDataHook(nss_fd_, ClientAuthHandler, this); +#endif if (rv != SECSuccess) { LogFailedNSSFunction(net_log_, "SSL_GetClientAuthDataHook", ""); return ERR_UNEXPECTED; @@ -831,6 +838,36 @@ int SSLClientSocketNSS::InitializeSSLOptions() { // Tell SSL the hostname we're trying to connect to. SSL_SetURL(nss_fd_, hostname_.c_str()); + // Tell SSL we're a client; needed if not letting NSPR do socket I/O + SSL_ResetHandshake(nss_fd_, 0); + + return OK; +} + +int SSLClientSocketNSS::InitializeSSLPeerName() { + // Tell NSS who we're connected to + AddressList peer_address; + int err = transport_->socket()->GetPeerAddress(&peer_address); + if (err != OK) + return err; + + const struct addrinfo* ai = peer_address.head(); + + PRNetAddr peername; + memset(&peername, 0, sizeof(peername)); + DCHECK_LE(ai->ai_addrlen, sizeof(peername)); + size_t len = std::min(static_cast<size_t>(ai->ai_addrlen), + sizeof(peername)); + memcpy(&peername, ai->ai_addr, len); + + // Adjust the address family field for BSD, whose sockaddr + // structure has a one-byte length and one-byte address family + // field at the beginning. PRNetAddr has a two-byte address + // family field at the beginning. + peername.raw.family = ai->ai_addr->sa_family; + + memio_SetPeerName(nss_fd_, &peername); + // Set the peer ID for session reuse. This is necessary when we create an // SSL tunnel through a proxy -- GetPeerName returns the proxy's address // rather than the destination server's address in that case. @@ -838,13 +875,11 @@ int SSLClientSocketNSS::InitializeSSLOptions() { // used. std::string peer_id = base::StringPrintf("%s:%d", hostname_.c_str(), peer_address.GetPort()); - rv = SSL_SetSockPeerID(nss_fd_, const_cast<char*>(peer_id.c_str())); + SECStatus rv = SSL_SetSockPeerID(nss_fd_, const_cast<char*>(peer_id.c_str())); if (rv != SECSuccess) LogFailedNSSFunction(net_log_, "SSL_SetSockPeerID", peer_id.c_str()); - // Tell SSL we're a client; needed if not letting NSPR do socket I/O - SSL_ResetHandshake(nss_fd_, 0); - + peername_initialized_ = true; return OK; } @@ -885,11 +920,14 @@ void SSLClientSocketNSS::Disconnect() { CERT_DestroyCertificate(server_cert_nss_); server_cert_nss_ = NULL; } - server_cert_verify_result_.Reset(); + local_server_cert_verify_result_.Reset(); + server_cert_verify_result_ = NULL; + ssl_connection_status_ = 0; completed_handshake_ = false; pseudo_connected_ = false; eset_mitm_detected_ = false; - netnanny_mitm_detected_= false; + predicted_cert_chain_correct_ = false; + peername_initialized_ = false; nss_bufs_ = NULL; client_certs_.clear(); client_auth_cert_needed_ = false; @@ -955,6 +993,14 @@ bool SSLClientSocketNSS::WasEverUsed() const { return false; } +bool SSLClientSocketNSS::UsingTCPFastOpen() const { + if (transport_.get() && transport_->socket()) { + return transport_->socket()->UsingTCPFastOpen(); + } + NOTREACHED(); + return false; +} + int SSLClientSocketNSS::Read(IOBuffer* buf, int buf_len, CompletionCallback* callback) { EnterFunction(buf_len); @@ -1044,157 +1090,110 @@ bool SSLClientSocketNSS::SetSendBufferSize(int32 size) { return transport_->socket()->SetSendBufferSize(size); } -#if defined(OS_WIN) -// static -X509Certificate::OSCertHandle SSLClientSocketNSS::CreateOSCert( - const SECItem& der_cert) { - // TODO(wtc): close cert_store_ at shutdown. - if (!cert_store_) - cert_store_ = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, NULL, 0, NULL); - - X509Certificate::OSCertHandle cert_handle = NULL; - BOOL ok = CertAddEncodedCertificateToStore( - cert_store_, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, - der_cert.data, der_cert.len, CERT_STORE_ADD_USE_EXISTING, &cert_handle); - return ok ? cert_handle : NULL; -} -#elif defined(OS_MACOSX) -// static -X509Certificate::OSCertHandle SSLClientSocketNSS::CreateOSCert( - const SECItem& der_cert) { - return X509Certificate::CreateOSCertHandleFromBytes( - reinterpret_cast<char*>(der_cert.data), der_cert.len); -} -#endif - +// Sets server_cert_ and server_cert_nss_ if not yet set. +// Returns server_cert_. X509Certificate *SSLClientSocketNSS::UpdateServerCert() { - // We set the server_cert_ from HandshakeCallback(), but this handler - // does not necessarily get called if we are continuing a cached SSL - // session. + // We set the server_cert_ from HandshakeCallback(). if (server_cert_ == NULL) { server_cert_nss_ = SSL_PeerCertificate(nss_fd_); if (server_cert_nss_) { -#if defined(OS_MACOSX) || defined(OS_WIN) - // Get each of the intermediate certificates in the server's chain. - // These will be added to the server's X509Certificate object, making - // them available to X509Certificate::Verify() for chain building. - X509Certificate::OSCertHandles intermediate_ca_certs; - X509Certificate::OSCertHandle cert_handle = NULL; - CERTCertList* cert_list = CERT_GetCertChainFromCert( - server_cert_nss_, PR_Now(), certUsageSSLCA); - if (cert_list) { - for (CERTCertListNode* node = CERT_LIST_HEAD(cert_list); - !CERT_LIST_END(node, cert_list); - node = CERT_LIST_NEXT(node)) { - if (node->cert == server_cert_nss_) - continue; -#if defined(OS_WIN) - // Work around http://crbug.com/43538 by not importing the - // problematic COMODO EV SGC CA certificate. CryptoAPI will - // download a good certificate for that CA, issued by COMODO - // Certification Authority, using the AIA extension in the server - // certificate. - if (IsProblematicComodoEVCACert(*node->cert)) - continue; -#endif - cert_handle = CreateOSCert(node->cert->derCert); - DCHECK(cert_handle); - intermediate_ca_certs.push_back(cert_handle); - } - CERT_DestroyCertList(cert_list); - } - - // Finally create the X509Certificate object. - cert_handle = CreateOSCert(server_cert_nss_->derCert); - DCHECK(cert_handle); - server_cert_ = X509Certificate::CreateFromHandle( - cert_handle, - X509Certificate::SOURCE_FROM_NETWORK, - intermediate_ca_certs); - X509Certificate::FreeOSCertHandle(cert_handle); - for (size_t i = 0; i < intermediate_ca_certs.size(); ++i) - X509Certificate::FreeOSCertHandle(intermediate_ca_certs[i]); -#else - server_cert_ = X509Certificate::CreateFromHandle( - server_cert_nss_, - X509Certificate::SOURCE_FROM_NETWORK, - X509Certificate::OSCertHandles()); -#endif + PeerCertificateChain certs(nss_fd_); + server_cert_ = X509Certificate::CreateFromDERCertChain( + certs.AsStringPieceVector()); } } return server_cert_; } -// Log an informational message if the server does not support secure -// renegotiation (RFC 5746). -void SSLClientSocketNSS::CheckSecureRenegotiation() const { - // SSL_HandshakeNegotiatedExtension was added in NSS 3.12.6. - // Since SSL_MAX_EXTENSIONS was added at the same time, we can test - // SSL_MAX_EXTENSIONS for the presence of SSL_HandshakeNegotiatedExtension. -#if defined(SSL_MAX_EXTENSIONS) - PRBool received_renego_info; - if (SSL_HandshakeNegotiatedExtension(nss_fd_, ssl_renegotiation_info_xtn, - &received_renego_info) == SECSuccess && - !received_renego_info) { - VLOG(1) << "The server " << hostname_ - << " does not support the TLS renegotiation_info extension."; - } -#endif -} - -void SSLClientSocketNSS::GetSSLInfo(SSLInfo* ssl_info) { - EnterFunction(""); - ssl_info->Reset(); - - if (!server_cert_) { - LOG(DFATAL) << "!server_cert_"; - return; - } - +// Sets ssl_connection_status_. +void SSLClientSocketNSS::UpdateConnectionStatus() { SSLChannelInfo channel_info; SECStatus ok = SSL_GetChannelInfo(nss_fd_, &channel_info, sizeof(channel_info)); if (ok == SECSuccess && channel_info.length == sizeof(channel_info) && channel_info.cipherSuite) { - SSLCipherSuiteInfo cipher_info; - ok = SSL_GetCipherSuiteInfo(channel_info.cipherSuite, - &cipher_info, sizeof(cipher_info)); - if (ok == SECSuccess) { - ssl_info->security_bits = cipher_info.effectiveKeyBits; - } else { - ssl_info->security_bits = -1; - LOG(DFATAL) << "SSL_GetCipherSuiteInfo returned " << PR_GetError() - << " for cipherSuite " << channel_info.cipherSuite; - } - ssl_info->connection_status |= - (((int)channel_info.cipherSuite) & SSL_CONNECTION_CIPHERSUITE_MASK) << + ssl_connection_status_ |= + (static_cast<int>(channel_info.cipherSuite) & + SSL_CONNECTION_CIPHERSUITE_MASK) << SSL_CONNECTION_CIPHERSUITE_SHIFT; - ssl_info->connection_status |= - (((int)channel_info.compressionMethod) & + ssl_connection_status_ |= + (static_cast<int>(channel_info.compressionMethod) & SSL_CONNECTION_COMPRESSION_MASK) << SSL_CONNECTION_COMPRESSION_SHIFT; - UpdateServerCert(); + // NSS 3.12.x doesn't have version macros for TLS 1.1 and 1.2 (because NSS + // doesn't support them yet), so we use 0x0302 and 0x0303 directly. + int version = SSL_CONNECTION_VERSION_UNKNOWN; + if (channel_info.protocolVersion < SSL_LIBRARY_VERSION_3_0) { + // All versions less than SSL_LIBRARY_VERSION_3_0 are treated as SSL + // version 2. + version = SSL_CONNECTION_VERSION_SSL2; + } else if (channel_info.protocolVersion == SSL_LIBRARY_VERSION_3_0) { + version = SSL_CONNECTION_VERSION_SSL3; + } else if (channel_info.protocolVersion == SSL_LIBRARY_VERSION_3_1_TLS) { + version = SSL_CONNECTION_VERSION_TLS1; + } else if (channel_info.protocolVersion == 0x0302) { + version = SSL_CONNECTION_VERSION_TLS1_1; + } else if (channel_info.protocolVersion == 0x0303) { + version = SSL_CONNECTION_VERSION_TLS1_2; + } + ssl_connection_status_ |= + (version & SSL_CONNECTION_VERSION_MASK) << + SSL_CONNECTION_VERSION_SHIFT; } - ssl_info->cert_status = server_cert_verify_result_.cert_status; - DCHECK(server_cert_ != NULL); - ssl_info->cert = server_cert_; + // SSL_HandshakeNegotiatedExtension was added in NSS 3.12.6. + // Since SSL_MAX_EXTENSIONS was added at the same time, we can test + // SSL_MAX_EXTENSIONS for the presence of SSL_HandshakeNegotiatedExtension. +#if defined(SSL_MAX_EXTENSIONS) PRBool peer_supports_renego_ext; ok = SSL_HandshakeNegotiatedExtension(nss_fd_, ssl_renegotiation_info_xtn, &peer_supports_renego_ext); if (ok == SECSuccess) { - if (!peer_supports_renego_ext) - ssl_info->connection_status |= SSL_CONNECTION_NO_RENEGOTIATION_EXTENSION; + if (!peer_supports_renego_ext) { + ssl_connection_status_ |= SSL_CONNECTION_NO_RENEGOTIATION_EXTENSION; + // Log an informational message if the server does not support secure + // renegotiation (RFC 5746). + VLOG(1) << "The server " << hostname_ + << " does not support the TLS renegotiation_info extension."; + } UMA_HISTOGRAM_ENUMERATION("Net.RenegotiationExtensionSupported", - (int)peer_supports_renego_ext, 2); + peer_supports_renego_ext, 2); } +#endif if (ssl_config_.ssl3_fallback) - ssl_info->connection_status |= SSL_CONNECTION_SSL3_FALLBACK; + ssl_connection_status_ |= SSL_CONNECTION_SSL3_FALLBACK; +} + +void SSLClientSocketNSS::GetSSLInfo(SSLInfo* ssl_info) { + EnterFunction(""); + ssl_info->Reset(); + if (!server_cert_) { + LOG(DFATAL) << "!server_cert_"; + return; + } + + ssl_info->cert_status = server_cert_verify_result_->cert_status; + DCHECK(server_cert_ != NULL); + ssl_info->cert = server_cert_; + ssl_info->connection_status = ssl_connection_status_; + + PRUint16 cipher_suite = + SSLConnectionStatusToCipherSuite(ssl_connection_status_); + SSLCipherSuiteInfo cipher_info; + SECStatus ok = SSL_GetCipherSuiteInfo(cipher_suite, + &cipher_info, sizeof(cipher_info)); + if (ok == SECSuccess) { + ssl_info->security_bits = cipher_info.effectiveKeyBits; + } else { + ssl_info->security_bits = -1; + LOG(DFATAL) << "SSL_GetCipherSuiteInfo returned " << PR_GetError() + << " for cipherSuite " << cipher_suite; + } LeaveFunction(""); } @@ -1378,8 +1377,11 @@ static PRErrorCode MapErrorToNSS(int result) { case ERR_IO_PENDING: return PR_WOULD_BLOCK_ERROR; case ERR_ACCESS_DENIED: + case ERR_NETWORK_ACCESS_DENIED: // For connect, this could be mapped to PR_ADDRESS_NOT_SUPPORTED_ERROR. return PR_NO_ACCESS_RIGHTS_ERROR; + case ERR_NOT_IMPLEMENTED: + return PR_NOT_IMPLEMENTED_ERROR; case ERR_INTERNET_DISCONNECTED: // Equivalent to ENETDOWN. return PR_NETWORK_UNREACHABLE_ERROR; // Best approximation. case ERR_CONNECTION_TIMED_OUT: @@ -1437,7 +1439,7 @@ int SSLClientSocketNSS::BufferSend(void) { int rv = 0; if (len) { - scoped_refptr<IOBuffer> send_buffer = new IOBuffer(len); + scoped_refptr<IOBuffer> send_buffer(new IOBuffer(len)); memcpy(send_buffer->data(), buf1, len1); memcpy(send_buffer->data() + len1, buf2, len2); rv = transport_->socket()->Write(send_buffer, len, @@ -1455,6 +1457,11 @@ int SSLClientSocketNSS::BufferSend(void) { void SSLClientSocketNSS::BufferSendComplete(int result) { EnterFunction(result); + + // In the case of TCP FastOpen, connect is now finished. + if (!peername_initialized_ && UsingTCPFastOpen()) + InitializeSSLPeerName(); + memio_PutWriteResult(nss_bufs_, MapErrorToNSS(result)); transport_send_busy_ = false; OnSendComplete(result); @@ -1565,7 +1572,8 @@ int SSLClientSocketNSS::DoReadLoop(int result) { if (!nss_bufs_) { LOG(DFATAL) << "!nss_bufs_"; int rv = ERR_UNEXPECTED; - net_log_.AddEvent(NetLog::TYPE_SSL_READ_ERROR, new SSLErrorParams(rv, 0)); + net_log_.AddEvent(NetLog::TYPE_SSL_READ_ERROR, + make_scoped_refptr(new SSLErrorParams(rv, 0))); return rv; } @@ -1591,7 +1599,8 @@ int SSLClientSocketNSS::DoWriteLoop(int result) { if (!nss_bufs_) { LOG(DFATAL) << "!nss_bufs_"; int rv = ERR_UNEXPECTED; - net_log_.AddEvent(NetLog::TYPE_SSL_WRITE_ERROR, new SSLErrorParams(rv, 0)); + net_log_.AddEvent(NetLog::TYPE_SSL_WRITE_ERROR, + make_scoped_refptr(new SSLErrorParams(rv, 0))); return rv; } @@ -1624,16 +1633,10 @@ SECStatus SSLClientSocketNSS::OwnAuthCertHandler(void* arg, // different reads or not, depending on network conditions. PRBool false_start = 0; SECStatus rv = SSL_OptionGet(socket, SSL_ENABLE_FALSE_START, &false_start); - if (rv != SECSuccess) - NOTREACHED(); + DCHECK_EQ(SECSuccess, rv); + if (false_start) { SSLClientSocketNSS* that = reinterpret_cast<SSLClientSocketNSS*>(arg); - if (!that->handshake_callback_called_) { - that->corked_ = true; - that->uncork_timer_.Start( - base::TimeDelta::FromMilliseconds(kCorkTimeoutMs), - that, &SSLClientSocketNSS::UncorkAfterTimeout); - } // ESET anti-virus is capable of intercepting HTTPS connections on Windows. // However, it is False Start intolerant and causes the connections to hang @@ -1646,12 +1649,24 @@ SECStatus SSLClientSocketNSS::OwnAuthCertHandler(void* arg, if (common_name) { if (strcmp(common_name, "ESET_RootSslCert") == 0) that->eset_mitm_detected_ = true; - if (strcmp(common_name, "ContentWatch Root Certificate Authority") == 0) - that->netnanny_mitm_detected_ = true; + if (strcmp(common_name, "ContentWatch Root Certificate Authority") == 0) { + // This is NetNanny. NetNanny are updating their product so we + // silently disable False Start for now. + rv = SSL_OptionSet(socket, SSL_ENABLE_FALSE_START, PR_FALSE); + DCHECK_EQ(SECSuccess, rv); + false_start = 0; + } PORT_Free(common_name); } CERT_DestroyCertificate(cert); } + + if (false_start && !that->handshake_callback_called_) { + that->corked_ = true; + that->uncork_timer_.Start( + base::TimeDelta::FromMilliseconds(kCorkTimeoutMs), + that, &SSLClientSocketNSS::UncorkAfterTimeout); + } } #endif @@ -1659,24 +1674,69 @@ SECStatus SSLClientSocketNSS::OwnAuthCertHandler(void* arg, return SECSuccess; } +#if defined(NSS_PLATFORM_CLIENT_AUTH) // static // NSS calls this if a client certificate is needed. -// Based on Mozilla's NSS_GetClientAuthData. -SECStatus SSLClientSocketNSS::ClientAuthHandler( +SECStatus SSLClientSocketNSS::PlatformClientAuthHandler( void* arg, PRFileDesc* socket, CERTDistNames* ca_names, - CERTCertificate** result_certificate, - SECKEYPrivateKey** result_private_key) { + CERTCertList** result_certs, + void** result_private_key) { SSLClientSocketNSS* that = reinterpret_cast<SSLClientSocketNSS*>(arg); that->client_auth_cert_needed_ = !that->ssl_config_.send_client_cert; - #if defined(OS_WIN) if (that->ssl_config_.send_client_cert) { - // TODO(wtc): SSLClientSocketNSS can't do SSL client authentication using - // CryptoAPI yet (http://crbug.com/37560), so client_cert must be NULL. - DCHECK(!that->ssl_config_.client_cert); + if (that->ssl_config_.client_cert) { + PCCERT_CONTEXT cert_context = + that->ssl_config_.client_cert->os_cert_handle(); + HCRYPTPROV provider = NULL; + DWORD key_spec = AT_KEYEXCHANGE; + BOOL must_free = FALSE; + BOOL acquired_key = CryptAcquireCertificatePrivateKey( + cert_context, + CRYPT_ACQUIRE_CACHE_FLAG | CRYPT_ACQUIRE_COMPARE_KEY_FLAG, + NULL, &provider, &key_spec, &must_free); + if (acquired_key && provider) { + DCHECK_NE(key_spec, CERT_NCRYPT_KEY_SPEC); + + // The certificate cache may have been updated/used, in which case, + // duplicate the existing handle, since NSS will free it when no + // longer in use. + if (!must_free) + CryptContextAddRef(provider, NULL, 0); + + SECItem der_cert; + der_cert.type = siDERCertBuffer; + der_cert.data = cert_context->pbCertEncoded; + der_cert.len = cert_context->cbCertEncoded; + + // TODO(rsleevi): Error checking for NSS allocation errors. + *result_certs = CERT_NewCertList(); + CERTCertDBHandle* db_handle = CERT_GetDefaultCertDB(); + CERTCertificate* user_cert = CERT_NewTempCertificate( + db_handle, &der_cert, NULL, PR_FALSE, PR_TRUE); + CERT_AddCertToListTail(*result_certs, user_cert); + + // Add the intermediates. + X509Certificate::OSCertHandles intermediates = + that->ssl_config_.client_cert->GetIntermediateCertificates(); + for (X509Certificate::OSCertHandles::const_iterator it = + intermediates.begin(); it != intermediates.end(); ++it) { + der_cert.data = (*it)->pbCertEncoded; + der_cert.len = (*it)->cbCertEncoded; + + CERTCertificate* intermediate = CERT_NewTempCertificate( + db_handle, &der_cert, NULL, PR_FALSE, PR_TRUE); + CERT_AddCertToListTail(*result_certs, intermediate); + } + // TODO(wtc): |key_spec| should be passed along with |provider|. + *result_private_key = reinterpret_cast<void*>(provider); + return SECSuccess; + } + LOG(WARNING) << "Client cert found without private key"; + } // Send no client certificate. return SECFailure; } @@ -1708,10 +1768,6 @@ SECStatus SSLClientSocketNSS::ClientAuthHandler( PCCERT_CHAIN_CONTEXT chain_context = NULL; - // TODO(wtc): close cert_store_ at shutdown. - if (!cert_store_) - cert_store_ = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, NULL, 0, NULL); - for (;;) { // Find a certificate chain. chain_context = CertFindChainInStore(my_cert_store, @@ -1733,18 +1789,42 @@ SECStatus SSLClientSocketNSS::ClientAuthHandler( // Copy it to our own certificate store, so that we can close the "MY" // certificate store before returning from this function. PCCERT_CONTEXT cert_context2; - BOOL ok = CertAddCertificateContextToStore(cert_store_, cert_context, + BOOL ok = CertAddCertificateContextToStore(X509Certificate::cert_store(), + cert_context, CERT_STORE_ADD_USE_EXISTING, &cert_context2); if (!ok) { NOTREACHED(); continue; } + + // Copy the rest of the chain to our own store as well. Copying the chain + // stops gracefully if an error is encountered, with the partial chain + // being used as the intermediates, rather than failing to consider the + // client certificate. + net::X509Certificate::OSCertHandles intermediates; + for (DWORD i = 1; i < chain_context->rgpChain[0]->cElement; i++) { + PCCERT_CONTEXT intermediate_copy; + ok = CertAddCertificateContextToStore(X509Certificate::cert_store(), + chain_context->rgpChain[0]->rgpElement[i]->pCertContext, + CERT_STORE_ADD_USE_EXISTING, &intermediate_copy); + if (!ok) { + NOTREACHED(); + break; + } + intermediates.push_back(intermediate_copy); + } + scoped_refptr<X509Certificate> cert = X509Certificate::CreateFromHandle( cert_context2, X509Certificate::SOURCE_LONE_CERT_IMPORT, - X509Certificate::OSCertHandles()); - X509Certificate::FreeOSCertHandle(cert_context2); + intermediates); that->client_certs_.push_back(cert); + + X509Certificate::FreeOSCertHandle(cert_context2); + for (net::X509Certificate::OSCertHandles::iterator it = + intermediates.begin(); it != intermediates.end(); ++it) { + net::X509Certificate::FreeOSCertHandle(*it); + } } BOOL ok = CertCloseStore(my_cert_store, CERT_CLOSE_STORE_CHECK_FLAG); @@ -1755,9 +1835,63 @@ SECStatus SSLClientSocketNSS::ClientAuthHandler( return SECWouldBlock; #elif defined(OS_MACOSX) if (that->ssl_config_.send_client_cert) { - // TODO(wtc): SSLClientSocketNSS can't do SSL client authentication using - // CDSA/CSSM yet (http://crbug.com/45369), so client_cert must be NULL. - DCHECK(!that->ssl_config_.client_cert); + if (that->ssl_config_.client_cert) { + OSStatus os_error = noErr; + SecIdentityRef identity = NULL; + SecKeyRef private_key = NULL; + CFArrayRef chain = + that->ssl_config_.client_cert->CreateClientCertificateChain(); + if (chain) { + identity = reinterpret_cast<SecIdentityRef>( + const_cast<void*>(CFArrayGetValueAtIndex(chain, 0))); + } + if (identity) + os_error = SecIdentityCopyPrivateKey(identity, &private_key); + + if (chain && identity && os_error == noErr) { + // TODO(rsleevi): Error checking for NSS allocation errors. + *result_certs = CERT_NewCertList(); + *result_private_key = reinterpret_cast<void*>(private_key); + + for (CFIndex i = 0; i < CFArrayGetCount(chain); ++i) { + CSSM_DATA cert_data; + SecCertificateRef cert_ref; + if (i == 0) { + cert_ref = that->ssl_config_.client_cert->os_cert_handle(); + } else { + cert_ref = reinterpret_cast<SecCertificateRef>( + const_cast<void*>(CFArrayGetValueAtIndex(chain, i))); + } + os_error = SecCertificateGetData(cert_ref, &cert_data); + if (os_error != noErr) + break; + + SECItem der_cert; + der_cert.type = siDERCertBuffer; + der_cert.data = cert_data.Data; + der_cert.len = cert_data.Length; + CERTCertificate* nss_cert = CERT_NewTempCertificate( + CERT_GetDefaultCertDB(), &der_cert, NULL, PR_FALSE, PR_TRUE); + CERT_AddCertToListTail(*result_certs, nss_cert); + } + } + if (os_error == noErr) { + CFRelease(chain); + return SECSuccess; + } + LOG(WARNING) << "Client cert found, but could not be used: " + << os_error; + if (*result_certs) { + CERT_DestroyCertList(*result_certs); + *result_certs = NULL; + } + if (*result_private_key) + *result_private_key = NULL; + if (private_key) + CFRelease(private_key); + if (chain) + CFRelease(chain); + } // Send no client certificate. return SECFailure; } @@ -1785,6 +1919,24 @@ SECStatus SSLClientSocketNSS::ClientAuthHandler( // handshake by returning ERR_SSL_CLIENT_AUTH_CERT_NEEDED. return SECWouldBlock; #else + return SECFailure; +#endif +} + +#else // NSS_PLATFORM_CLIENT_AUTH + +// static +// NSS calls this if a client certificate is needed. +// Based on Mozilla's NSS_GetClientAuthData. +SECStatus SSLClientSocketNSS::ClientAuthHandler( + void* arg, + PRFileDesc* socket, + CERTDistNames* ca_names, + CERTCertificate** result_certificate, + SECKEYPrivateKey** result_private_key) { + SSLClientSocketNSS* that = reinterpret_cast<SSLClientSocketNSS*>(arg); + + that->client_auth_cert_needed_ = !that->ssl_config_.send_client_cert; void* wincx = SSL_RevealPinArg(socket); // Second pass: a client certificate should have been selected. @@ -1838,8 +1990,8 @@ SECStatus SSLClientSocketNSS::ClientAuthHandler( // Tell NSS to suspend the client authentication. We will then abort the // handshake by returning ERR_SSL_CLIENT_AUTH_CERT_NEEDED. return SECWouldBlock; -#endif } +#endif // NSS_PLATFORM_CLIENT_AUTH // static // NSS calls this when handshake is completed. @@ -1852,22 +2004,32 @@ void SSLClientSocketNSS::HandshakeCallback(PRFileDesc* socket, that->handshake_callback_called_ = true; that->UpdateServerCert(); - - that->CheckSecureRenegotiation(); + that->UpdateConnectionStatus(); } int SSLClientSocketNSS::DoSnapStartLoadInfo() { EnterFunction(""); int rv = ssl_host_info_->WaitForDataReady(&handshake_io_callback_); + GotoState(STATE_HANDSHAKE); if (rv == OK) { - if (LoadSnapStartInfo()) { - pseudo_connected_ = true; - GotoState(STATE_SNAP_START_WAIT_FOR_WRITE); - if (user_connect_callback_) - DoConnectCallback(OK); - } else { - GotoState(STATE_HANDSHAKE); + if (ssl_host_info_->WaitForCertVerification(NULL) == OK) { + if (LoadSnapStartInfo()) { + pseudo_connected_ = true; + GotoState(STATE_SNAP_START_WAIT_FOR_WRITE); + if (user_connect_callback_) + DoConnectCallback(OK); + } + } else if (!ssl_host_info_->state().server_hello.empty()) { + // A non-empty ServerHello suggests that we would have tried a Snap Start + // connection. + base::TimeTicks now = base::TimeTicks::Now(); + const base::TimeDelta duration = + now - ssl_host_info_->verification_start_time(); + UMA_HISTOGRAM_TIMES("Net.SSLSnapStartNeededVerificationInMs", duration); + VLOG(1) << "Cannot snap start because verification isn't ready. " + << "Wanted verification after " + << duration.InMilliseconds() << "ms"; } } else { DCHECK_EQ(ERR_IO_PENDING, rv); @@ -1909,7 +2071,6 @@ int SSLClientSocketNSS::DoSnapStartWaitForWrite() { nss_fd_, reinterpret_cast<const unsigned char*>(user_write_buf_->data()), user_write_buf_len_); DCHECK_EQ(SECSuccess, rv); - user_write_buf_ = NULL; GotoState(STATE_HANDSHAKE); LeaveFunction(""); @@ -1924,7 +2085,7 @@ int SSLClientSocketNSS::DoHandshake() { if (client_auth_cert_needed_) { net_error = ERR_SSL_CLIENT_AUTH_CERT_NEEDED; net_log_.AddEvent(NetLog::TYPE_SSL_HANDSHAKE_ERROR, - new SSLErrorParams(net_error, 0)); + make_scoped_refptr(new SSLErrorParams(net_error, 0))); // If the handshake already succeeded (because the server requests but // doesn't require a client cert), we need to invalidate the SSL session // so that we won't try to resume the non-client-authenticated session in @@ -1937,9 +2098,27 @@ int SSLClientSocketNSS::DoHandshake() { if (handshake_callback_called_) { if (eset_mitm_detected_) { net_error = ERR_ESET_ANTI_VIRUS_SSL_INTERCEPTION; - } else if (netnanny_mitm_detected_) { - net_error = ERR_NETNANNY_SSL_INTERCEPTION; } else { + // We need to see if the predicted certificate chain (in + // |ssl_host_info_->state().certs) matches the actual certificate chain + // before we call SaveSnapStartInfo, as that will update + // |ssl_host_info_|. + if (ssl_host_info_.get() && !ssl_host_info_->state().certs.empty()) { + PeerCertificateChain certs(nss_fd_); + const SSLHostInfo::State& state = ssl_host_info_->state(); + predicted_cert_chain_correct_ = certs.size() == state.certs.size(); + if (predicted_cert_chain_correct_) { + for (unsigned i = 0; i < certs.size(); i++) { + if (certs[i]->derCert.len != state.certs[i].size() || + memcmp(certs[i]->derCert.data, state.certs[i].data(), + certs[i]->derCert.len) != 0) { + predicted_cert_chain_correct_ = false; + break; + } + } + } + } + SaveSnapStartInfo(); // SSL handshake is completed. It's possible that we mispredicted the // NPN agreed protocol. In this case, we've just sent a request in the @@ -1961,7 +2140,7 @@ int SSLClientSocketNSS::DoHandshake() { rv = SECFailure; net_error = ERR_SSL_PROTOCOL_ERROR; net_log_.AddEvent(NetLog::TYPE_SSL_HANDSHAKE_ERROR, - new SSLErrorParams(net_error, 0)); + make_scoped_refptr(new SSLErrorParams(net_error, 0))); } } else { PRErrorCode prerr = PR_GetError(); @@ -1973,8 +2152,9 @@ int SSLClientSocketNSS::DoHandshake() { } else { LOG(ERROR) << "handshake failed; NSS error code " << prerr << ", net_error " << net_error; - net_log_.AddEvent(NetLog::TYPE_SSL_HANDSHAKE_ERROR, - new SSLErrorParams(net_error, prerr)); + net_log_.AddEvent( + NetLog::TYPE_SSL_HANDSHAKE_ERROR, + make_scoped_refptr(new SSLErrorParams(net_error, prerr))); } } @@ -2135,10 +2315,19 @@ static DNSValidationResult CheckDNSSECChain( } int SSLClientSocketNSS::DoVerifyDNSSEC(int result) { +#if !defined(USE_OPENSSL) + if (ssl_config_.dns_cert_provenance_checking_enabled && dnsrr_resolver_) { + PeerCertificateChain certs(nss_fd_); + DoAsyncDNSCertProvenanceVerification( + hostname_, dnsrr_resolver_, certs.AsStringPieceVector()); + } +#endif + if (ssl_config_.dnssec_enabled) { DNSValidationResult r = CheckDNSSECChain(hostname_, server_cert_nss_); if (r == DNSVR_SUCCESS) { - server_cert_verify_result_.cert_status |= CERT_STATUS_IS_DNSSEC; + local_server_cert_verify_result_.cert_status |= CERT_STATUS_IS_DNSSEC; + server_cert_verify_result_ = &local_server_cert_verify_result_; GotoState(STATE_VERIFY_CERT_COMPLETE); return OK; } @@ -2183,13 +2372,15 @@ int SSLClientSocketNSS::DoVerifyDNSSECComplete(int result) { switch (r) { case DNSVR_FAILURE: GotoState(STATE_VERIFY_CERT_COMPLETE); - server_cert_verify_result_.cert_status |= CERT_STATUS_NOT_IN_DNS; + local_server_cert_verify_result_.cert_status |= CERT_STATUS_NOT_IN_DNS; + server_cert_verify_result_ = &local_server_cert_verify_result_; return ERR_CERT_NOT_IN_DNS; case DNSVR_CONTINUE: GotoState(STATE_VERIFY_CERT); break; case DNSVR_SUCCESS: - server_cert_verify_result_.cert_status |= CERT_STATUS_IS_DNSSEC; + local_server_cert_verify_result_.cert_status |= CERT_STATUS_IS_DNSSEC; + server_cert_verify_result_ = &local_server_cert_verify_result_; GotoState(STATE_VERIFY_CERT_COMPLETE); break; default: @@ -2202,16 +2393,35 @@ int SSLClientSocketNSS::DoVerifyDNSSECComplete(int result) { int SSLClientSocketNSS::DoVerifyCert(int result) { DCHECK(server_cert_); + GotoState(STATE_VERIFY_CERT_COMPLETE); - int flags = 0; + if (ssl_host_info_.get() && !ssl_host_info_->state().certs.empty() && + predicted_cert_chain_correct_) { + // If the SSLHostInfo had a prediction for the certificate chain of this + // server then it will have optimistically started a verification of that + // chain. So, if the prediction was correct, we should wait for that + // verification to finish rather than start our own. + net_log_.AddEvent(NetLog::TYPE_SSL_VERIFICATION_MERGED, NULL); + UMA_HISTOGRAM_ENUMERATION("Net.SSLVerificationMerged", 1 /* true */, 2); + base::TimeTicks now = base::TimeTicks::Now(); + UMA_HISTOGRAM_TIMES("Net.SSLVerificationMergedMsSaved", + now - ssl_host_info_->verification_start_time()); + server_cert_verify_result_ = &ssl_host_info_->cert_verify_result(); + return ssl_host_info_->WaitForCertVerification(&handshake_io_callback_); + } else { + UMA_HISTOGRAM_ENUMERATION("Net.SSLVerificationMerged", 0 /* false */, 2); + } + + int flags = 0; if (ssl_config_.rev_checking_enabled) flags |= X509Certificate::VERIFY_REV_CHECKING_ENABLED; if (ssl_config_.verify_ev_cert) flags |= X509Certificate::VERIFY_EV_CERT; verifier_.reset(new CertVerifier); + server_cert_verify_result_ = &local_server_cert_verify_result_; return verifier_->Verify(server_cert_, hostname_, flags, - &server_cert_verify_result_, + &local_server_cert_verify_result_, &handshake_io_callback_); } @@ -2220,45 +2430,15 @@ int SSLClientSocketNSS::DoVerifyCert(int result) { int SSLClientSocketNSS::DoVerifyCertComplete(int result) { verifier_.reset(); - // Using Snap Start disables certificate verification for now. - if (SSLConfigService::snap_start_enabled()) - result = OK; - - if (result == OK) { - // Remember the intermediate CA certs if the server sends them to us. - // - // We used to remember the intermediate CA certs in the NSS database - // persistently. However, NSS opens a connection to the SQLite database - // during NSS initialization and doesn't close the connection until NSS - // shuts down. If the file system where the database resides is gone, - // the database connection goes bad. What's worse, the connection won't - // recover when the file system comes back. Until this NSS or SQLite bug - // is fixed, we need to avoid using the NSS database for non-essential - // purposes. See https://bugzilla.mozilla.org/show_bug.cgi?id=508081 and - // http://crbug.com/15630 for more info. - CERTCertList* cert_list = CERT_GetCertChainFromCert( - server_cert_nss_, PR_Now(), certUsageSSLCA); - if (cert_list) { - for (CERTCertListNode* node = CERT_LIST_HEAD(cert_list); - !CERT_LIST_END(node, cert_list); - node = CERT_LIST_NEXT(node)) { - if (node->cert->slot || node->cert->isRoot || node->cert->isperm || - node->cert == server_cert_nss_) { - // Some certs we don't want to remember are: - // - found on a token. - // - the root cert. - // - already stored in perm db. - // - the server cert itself. - continue; - } - - // We have found a CA cert that we want to remember. - // TODO(wtc): Remember the intermediate CA certs in a std::set - // temporarily (http://crbug.com/15630). - } - CERT_DestroyCertList(cert_list); - } - } + // We used to remember the intermediate CA certs in the NSS database + // persistently. However, NSS opens a connection to the SQLite database + // during NSS initialization and doesn't close the connection until NSS + // shuts down. If the file system where the database resides is gone, + // the database connection goes bad. What's worse, the connection won't + // recover when the file system comes back. Until this NSS or SQLite bug + // is fixed, we need to avoid using the NSS database for non-essential + // purposes. See https://bugzilla.mozilla.org/show_bug.cgi?id=508081 and + // http://crbug.com/15630 for more info. // If we have been explicitly told to accept this certificate, override the // result of verifier_.Verify. @@ -2272,16 +2452,45 @@ int SSLClientSocketNSS::DoVerifyCertComplete(int result) { result = OK; } + if (result == OK) + LogConnectionTypeMetrics(); + completed_handshake_ = true; // TODO(ukai): we may not need this call because it is now harmless to have a // session with a bad cert. InvalidateSessionIfBadCertificate(); - // Likewise, if we merged a Write call into the handshake we need to make the + // If we merged a Write call into the handshake we need to make the // callback now. if (user_write_callback_) { corked_ = false; - DoWriteCallback(user_write_buf_len_); + if (result != OK) { + DoWriteCallback(result); + } else { + SSLSnapStartResult snap_start_type; + SECStatus rv = SSL_GetSnapStartResult(nss_fd_, &snap_start_type); + DCHECK_EQ(rv, SECSuccess); + DCHECK_NE(snap_start_type, SSL_SNAP_START_NONE); + if (snap_start_type == SSL_SNAP_START_RECOVERY || + snap_start_type == SSL_SNAP_START_RESUME_RECOVERY) { + // If we mispredicted the server's handshake then Snap Start will have + // triggered a recovery mode. The misprediction could have been caused + // by the server having a different certificate so the application data + // wasn't resent. Now that we have verified the certificate, we need to + // resend the application data. + int bytes_written = DoPayloadWrite(); + if (bytes_written != ERR_IO_PENDING) + DoWriteCallback(bytes_written); + } else { + DoWriteCallback(user_write_buf_len_); + } + } + } + + if (user_read_callback_) { + int rv = DoReadLoop(OK); + if (rv != ERR_IO_PENDING) + DoReadCallback(rv); } // Exit DoHandshakeLoop and return the result to the caller to Connect. @@ -2300,7 +2509,7 @@ int SSLClientSocketNSS::DoPayloadRead() { LeaveFunction(""); rv = ERR_SSL_CLIENT_AUTH_CERT_NEEDED; net_log_.AddEvent(NetLog::TYPE_SSL_READ_ERROR, - new SSLErrorParams(rv, 0)); + make_scoped_refptr(new SSLErrorParams(rv, 0))); return rv; } if (rv >= 0) { @@ -2315,7 +2524,8 @@ int SSLClientSocketNSS::DoPayloadRead() { } LeaveFunction(""); rv = MapNSPRError(prerr); - net_log_.AddEvent(NetLog::TYPE_SSL_READ_ERROR, new SSLErrorParams(rv, prerr)); + net_log_.AddEvent(NetLog::TYPE_SSL_READ_ERROR, + make_scoped_refptr(new SSLErrorParams(rv, prerr))); return rv; } @@ -2336,8 +2546,40 @@ int SSLClientSocketNSS::DoPayloadWrite() { LeaveFunction(""); rv = MapNSPRError(prerr); net_log_.AddEvent(NetLog::TYPE_SSL_WRITE_ERROR, - new SSLErrorParams(rv, prerr)); + make_scoped_refptr(new SSLErrorParams(rv, prerr))); return rv; } +void SSLClientSocketNSS::LogConnectionTypeMetrics() const { + UpdateConnectionTypeHistograms(CONNECTION_SSL); + if (server_cert_verify_result_->has_md5) + UpdateConnectionTypeHistograms(CONNECTION_SSL_MD5); + if (server_cert_verify_result_->has_md2) + UpdateConnectionTypeHistograms(CONNECTION_SSL_MD2); + if (server_cert_verify_result_->has_md4) + UpdateConnectionTypeHistograms(CONNECTION_SSL_MD4); + if (server_cert_verify_result_->has_md5_ca) + UpdateConnectionTypeHistograms(CONNECTION_SSL_MD5_CA); + if (server_cert_verify_result_->has_md2_ca) + UpdateConnectionTypeHistograms(CONNECTION_SSL_MD2_CA); + int ssl_version = SSLConnectionStatusToVersion(ssl_connection_status_); + switch (ssl_version) { + case SSL_CONNECTION_VERSION_SSL2: + UpdateConnectionTypeHistograms(CONNECTION_SSL_SSL2); + break; + case SSL_CONNECTION_VERSION_SSL3: + UpdateConnectionTypeHistograms(CONNECTION_SSL_SSL3); + break; + case SSL_CONNECTION_VERSION_TLS1: + UpdateConnectionTypeHistograms(CONNECTION_SSL_TLS1); + break; + case SSL_CONNECTION_VERSION_TLS1_1: + UpdateConnectionTypeHistograms(CONNECTION_SSL_TLS1_1); + break; + case SSL_CONNECTION_VERSION_TLS1_2: + UpdateConnectionTypeHistograms(CONNECTION_SSL_TLS1_2); + break; + }; +} + } // namespace net diff --git a/net/socket/ssl_client_socket_nss.h b/net/socket/ssl_client_socket_nss.h index 56d16b2..87f7b92 100644 --- a/net/socket/ssl_client_socket_nss.h +++ b/net/socket/ssl_client_socket_nss.h @@ -30,6 +30,7 @@ namespace net { class BoundNetLog; class CertVerifier; class ClientSocketHandle; +class DnsRRResolver; class SSLHostInfo; class X509Certificate; @@ -43,14 +44,15 @@ class SSLClientSocketNSS : public SSLClientSocket { SSLClientSocketNSS(ClientSocketHandle* transport_socket, const std::string& hostname, const SSLConfig& ssl_config, - SSLHostInfo* ssl_host_info); + SSLHostInfo* ssl_host_info, + DnsRRResolver* dnsrr_resolver); ~SSLClientSocketNSS(); // SSLClientSocket methods: virtual void GetSSLInfo(SSLInfo* ssl_info); virtual void GetSSLCertRequestInfo(SSLCertRequestInfo* cert_request_info); virtual NextProtoStatus GetNextProto(std::string* proto); - virtual void UseDNSSEC(DNSSECProvider*); + virtual void UseDNSSEC(DNSSECProvider* provider); // ClientSocket methods: virtual int Connect(CompletionCallback* callback); @@ -62,6 +64,7 @@ class SSLClientSocketNSS : public SSLClientSocket { virtual void SetSubresourceSpeculation(); virtual void SetOmniboxSpeculation(); virtual bool WasEverUsed() const; + virtual bool UsingTCPFastOpen() const; // Socket methods: virtual int Read(IOBuffer* buf, int buf_len, CompletionCallback* callback); @@ -73,13 +76,16 @@ class SSLClientSocketNSS : public SSLClientSocket { // Initializes NSS SSL options. Returns a net error code. int InitializeSSLOptions(); + // Initializes the socket peer name in SSL. Returns a net error code. + int InitializeSSLPeerName(); + void InvalidateSessionIfBadCertificate(); #if defined(OS_MACOSX) || defined(OS_WIN) // Creates an OS certificate from a DER-encoded certificate. static X509Certificate::OSCertHandle CreateOSCert(const SECItem& der_cert); #endif X509Certificate* UpdateServerCert(); - void CheckSecureRenegotiation() const; + void UpdateConnectionStatus(); void DoReadCallback(int result); void DoWriteCallback(int result); void DoConnectCallback(int result); @@ -101,6 +107,7 @@ class SSLClientSocketNSS : public SSLClientSocket { int DoVerifyCertComplete(int result); int DoPayloadRead(); int DoPayloadWrite(); + void LogConnectionTypeMetrics() const; int Init(); void SaveSnapStartInfo(); bool LoadSnapStartInfo(); @@ -118,11 +125,19 @@ class SSLClientSocketNSS : public SSLClientSocket { static SECStatus OwnAuthCertHandler(void* arg, PRFileDesc* socket, PRBool checksig, PRBool is_server); // NSS calls this when client authentication is requested. +#if defined(NSS_PLATFORM_CLIENT_AUTH) + static SECStatus PlatformClientAuthHandler(void* arg, + PRFileDesc* socket, + CERTDistNames* ca_names, + CERTCertList** result_certs, + void** result_private_key); +#else static SECStatus ClientAuthHandler(void* arg, PRFileDesc* socket, CERTDistNames* ca_names, CERTCertificate** result_certificate, SECKEYPrivateKey** result_private_key); +#endif // NSS calls this when handshake is completed. We pass 'this' as the second // argument. static void HandshakeCallback(PRFileDesc* socket, void* arg); @@ -161,7 +176,12 @@ class SSLClientSocketNSS : public SSLClientSocket { // converted into an X509Certificate object (server_cert_). scoped_refptr<X509Certificate> server_cert_; CERTCertificate* server_cert_nss_; - CertVerifyResult server_cert_verify_result_; + // |server_cert_verify_result_| points at the verification result, which may, + // or may not be, |&local_server_cert_verify_result_|, depending on whether + // we used an SSLHostInfo's verification. + const CertVerifyResult* server_cert_verify_result_; + CertVerifyResult local_server_cert_verify_result_; + int ssl_connection_status_; // Stores client authentication information between ClientAuthHandler and // GetSSLCertRequestInfo calls. @@ -184,9 +204,12 @@ class SSLClientSocketNSS : public SSLClientSocket { // HTTPS connections. bool eset_mitm_detected_; - // True iff we believe that the user has NetNanny intercepting our HTTPS - // connections. - bool netnanny_mitm_detected_; + // True iff |ssl_host_info_| contained a predicted certificate chain and + // that we found the prediction to be correct. + bool predicted_cert_chain_correct_; + + // True if the peer name has been initialized. + bool peername_initialized_; // This pointer is owned by the caller of UseDNSSEC. DNSSECProvider* dnssec_provider_; @@ -222,16 +245,7 @@ class SSLClientSocketNSS : public SSLClientSocket { bool predicted_npn_proto_used_; scoped_ptr<SSLHostInfo> ssl_host_info_; - -#if defined(OS_WIN) - // A CryptoAPI in-memory certificate store. We use it for two purposes: - // 1. Import server certificates into this store so that we can verify and - // display the certificates using CryptoAPI. - // 2. Copy client certificates from the "MY" system certificate store into - // this store so that we can close the system store when we finish - // searching for client certificates. - static HCERTSTORE cert_store_; -#endif + DnsRRResolver* const dnsrr_resolver_; }; } // namespace net diff --git a/net/socket/ssl_client_socket_nss_factory.cc b/net/socket/ssl_client_socket_nss_factory.cc index efa6e23..f4e8215 100644 --- a/net/socket/ssl_client_socket_nss_factory.cc +++ b/net/socket/ssl_client_socket_nss_factory.cc @@ -4,12 +4,8 @@ #include "net/socket/client_socket_factory.h" -#include "build/build_config.h" #include "net/socket/ssl_client_socket_nss.h" #include "net/socket/ssl_host_info.h" -#if defined(OS_WIN) -#include "net/socket/ssl_client_socket_win.h" -#endif // This file is only used on platforms where NSS is not the system SSL // library. When compiled, this file is the only object module that pulls @@ -22,18 +18,11 @@ SSLClientSocket* SSLClientSocketNSSFactory( ClientSocketHandle* transport_socket, const std::string& hostname, const SSLConfig& ssl_config, - SSLHostInfo* ssl_host_info) { + SSLHostInfo* ssl_host_info, + DnsRRResolver* dnsrr_resolver) { scoped_ptr<SSLHostInfo> shi(ssl_host_info); - // TODO(wtc): SSLClientSocketNSS can't do SSL client authentication using - // CryptoAPI yet (http://crbug.com/37560), so we fall back on - // SSLClientSocketWin. -#if defined(OS_WIN) - if (ssl_config.send_client_cert) - return new SSLClientSocketWin(transport_socket, hostname, ssl_config); -#endif - return new SSLClientSocketNSS(transport_socket, hostname, ssl_config, - shi.release()); + shi.release(), dnsrr_resolver); } } // namespace net diff --git a/net/socket/ssl_client_socket_nss_factory.h b/net/socket/ssl_client_socket_nss_factory.h index d454bb9..29f9af4 100644 --- a/net/socket/ssl_client_socket_nss_factory.h +++ b/net/socket/ssl_client_socket_nss_factory.h @@ -10,6 +10,7 @@ namespace net { +class DnsRRResolver; class SSLHostInfo; // Creates SSLClientSocketNSS objects. @@ -17,7 +18,8 @@ SSLClientSocket* SSLClientSocketNSSFactory( ClientSocketHandle* transport_socket, const std::string& hostname, const SSLConfig& ssl_config, - SSLHostInfo* ssl_host_info); + SSLHostInfo* ssl_host_info, + DnsRRResolver* dnsrr_resolver); } // namespace net diff --git a/net/socket/ssl_client_socket_openssl.cc b/net/socket/ssl_client_socket_openssl.cc index bbe3ee4..3aae457 100644 --- a/net/socket/ssl_client_socket_openssl.cc +++ b/net/socket/ssl_client_socket_openssl.cc @@ -631,6 +631,14 @@ bool SSLClientSocketOpenSSL::WasEverUsed() const { return false; } +bool SSLClientSocketOpenSSL::UsingTCPFastOpen() const { + if (transport_.get() && transport_->socket()) + return transport_->socket()->UsingTCPFastOpen(); + + NOTREACHED(); + return false; +} + // Socket methods int SSLClientSocketOpenSSL::Read(IOBuffer* buf, diff --git a/net/socket/ssl_client_socket_openssl.h b/net/socket/ssl_client_socket_openssl.h index 20f321e..31d5c1c 100644 --- a/net/socket/ssl_client_socket_openssl.h +++ b/net/socket/ssl_client_socket_openssl.h @@ -51,6 +51,7 @@ class SSLClientSocketOpenSSL : public SSLClientSocket { virtual void SetSubresourceSpeculation(); virtual void SetOmniboxSpeculation(); virtual bool WasEverUsed() const; + virtual bool UsingTCPFastOpen() const; // Socket methods: virtual int Read(IOBuffer* buf, int buf_len, CompletionCallback* callback); diff --git a/net/socket/ssl_client_socket_pool.cc b/net/socket/ssl_client_socket_pool.cc index 98e3b09..a7eea3a 100644 --- a/net/socket/ssl_client_socket_pool.cc +++ b/net/socket/ssl_client_socket_pool.cc @@ -193,7 +193,8 @@ int SSLConnectJob::DoTCPConnect() { if (ssl_host_info_factory_ && SSLConfigService::snap_start_enabled()) { ssl_host_info_.reset( - ssl_host_info_factory_->GetForHost(params_->hostname())); + ssl_host_info_factory_->GetForHost(params_->hostname(), + params_->ssl_config())); } if (ssl_host_info_.get()) { // This starts fetching the SSL host info from the disk cache for Snap @@ -284,7 +285,8 @@ int SSLConnectJob::DoSSLConnect() { ssl_socket_.reset(client_socket_factory_->CreateSSLClientSocket( transport_socket_handle_.release(), params_->hostname(), - params_->ssl_config(), ssl_host_info_.release())); + params_->ssl_config(), ssl_host_info_.release(), + dnsrr_resolver_)); return ssl_socket_->Connect(&callback_); } diff --git a/net/socket/ssl_client_socket_unittest.cc b/net/socket/ssl_client_socket_unittest.cc index bfcbe81..a32d5df 100644 --- a/net/socket/ssl_client_socket_unittest.cc +++ b/net/socket/ssl_client_socket_unittest.cc @@ -93,8 +93,9 @@ TEST_F(SSLClientSocketTest, Connect) { } TEST_F(SSLClientSocketTest, ConnectExpired) { - net::TestServer test_server(net::TestServer::TYPE_HTTPS_EXPIRED_CERTIFICATE, - FilePath()); + net::TestServer::HTTPSOptions https_options( + net::TestServer::HTTPSOptions::CERT_EXPIRED); + net::TestServer test_server(https_options, FilePath()); ASSERT_TRUE(test_server.Start()); net::AddressList addr; @@ -136,8 +137,9 @@ TEST_F(SSLClientSocketTest, ConnectExpired) { } TEST_F(SSLClientSocketTest, ConnectMismatched) { - net::TestServer test_server(net::TestServer::TYPE_HTTPS_MISMATCHED_HOSTNAME, - FilePath()); + net::TestServer::HTTPSOptions https_options( + net::TestServer::HTTPSOptions::CERT_MISMATCHED_NAME); + net::TestServer test_server(https_options, FilePath()); ASSERT_TRUE(test_server.Start()); net::AddressList addr; @@ -181,9 +183,11 @@ TEST_F(SSLClientSocketTest, ConnectMismatched) { // Attempt to connect to a page which requests a client certificate. It should // return an error code on connect. +// Flaky: http://crbug.com/54445 TEST_F(SSLClientSocketTest, FLAKY_ConnectClientAuthCertRequested) { - net::TestServer test_server(net::TestServer::TYPE_HTTPS_CLIENT_AUTH, - FilePath()); + net::TestServer::HTTPSOptions https_options; + https_options.request_client_certificate = true; + net::TestServer test_server(https_options, FilePath()); ASSERT_TRUE(test_server.Start()); net::AddressList addr; @@ -229,8 +233,9 @@ TEST_F(SSLClientSocketTest, FLAKY_ConnectClientAuthCertRequested) { // // TODO(davidben): Also test providing an actual certificate. TEST_F(SSLClientSocketTest, ConnectClientAuthSendNullCert) { - net::TestServer test_server(net::TestServer::TYPE_HTTPS_CLIENT_AUTH, - FilePath()); + net::TestServer::HTTPSOptions https_options; + https_options.request_client_certificate = true; + net::TestServer test_server(https_options, FilePath()); ASSERT_TRUE(test_server.Start()); net::AddressList addr; @@ -315,8 +320,8 @@ TEST_F(SSLClientSocketTest, Read) { EXPECT_TRUE(sock->IsConnected()); const char request_text[] = "GET / HTTP/1.0\r\n\r\n"; - scoped_refptr<net::IOBuffer> request_buffer = - new net::IOBuffer(arraysize(request_text) - 1); + scoped_refptr<net::IOBuffer> request_buffer( + new net::IOBuffer(arraysize(request_text) - 1)); memcpy(request_buffer->data(), request_text, arraysize(request_text) - 1); rv = sock->Write(request_buffer, arraysize(request_text) - 1, &callback); @@ -326,7 +331,7 @@ TEST_F(SSLClientSocketTest, Read) { rv = callback.WaitForResult(); EXPECT_EQ(static_cast<int>(arraysize(request_text) - 1), rv); - scoped_refptr<net::IOBuffer> buf = new net::IOBuffer(4096); + scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(4096)); for (;;) { rv = sock->Read(buf, 4096, &callback); EXPECT_TRUE(rv >= 0 || rv == net::ERR_IO_PENDING); @@ -376,7 +381,7 @@ TEST_F(SSLClientSocketTest, Read_FullDuplex) { EXPECT_TRUE(sock->IsConnected()); // Issue a "hanging" Read first. - scoped_refptr<net::IOBuffer> buf = new net::IOBuffer(4096); + scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(4096)); rv = sock->Read(buf, 4096, &callback); // We haven't written the request, so there should be no response yet. ASSERT_EQ(net::ERR_IO_PENDING, rv); @@ -389,8 +394,8 @@ TEST_F(SSLClientSocketTest, Read_FullDuplex) { for (int i = 0; i < 3800; ++i) request_text.push_back('*'); request_text.append("\r\n\r\n"); - scoped_refptr<net::IOBuffer> request_buffer = - new net::StringIOBuffer(request_text); + scoped_refptr<net::IOBuffer> request_buffer( + new net::StringIOBuffer(request_text)); rv = sock->Write(request_buffer, request_text.size(), &callback2); EXPECT_TRUE(rv >= 0 || rv == net::ERR_IO_PENDING); @@ -433,8 +438,8 @@ TEST_F(SSLClientSocketTest, Read_SmallChunks) { } const char request_text[] = "GET / HTTP/1.0\r\n\r\n"; - scoped_refptr<net::IOBuffer> request_buffer = - new net::IOBuffer(arraysize(request_text) - 1); + scoped_refptr<net::IOBuffer> request_buffer( + new net::IOBuffer(arraysize(request_text) - 1)); memcpy(request_buffer->data(), request_text, arraysize(request_text) - 1); rv = sock->Write(request_buffer, arraysize(request_text) - 1, &callback); @@ -444,7 +449,7 @@ TEST_F(SSLClientSocketTest, Read_SmallChunks) { rv = callback.WaitForResult(); EXPECT_EQ(static_cast<int>(arraysize(request_text) - 1), rv); - scoped_refptr<net::IOBuffer> buf = new net::IOBuffer(1); + scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(1)); for (;;) { rv = sock->Read(buf, 1, &callback); EXPECT_TRUE(rv >= 0 || rv == net::ERR_IO_PENDING); @@ -487,8 +492,8 @@ TEST_F(SSLClientSocketTest, Read_Interrupted) { } const char request_text[] = "GET / HTTP/1.0\r\n\r\n"; - scoped_refptr<net::IOBuffer> request_buffer = - new net::IOBuffer(arraysize(request_text) - 1); + scoped_refptr<net::IOBuffer> request_buffer( + new net::IOBuffer(arraysize(request_text) - 1)); memcpy(request_buffer->data(), request_text, arraysize(request_text) - 1); rv = sock->Write(request_buffer, arraysize(request_text) - 1, &callback); @@ -499,7 +504,7 @@ TEST_F(SSLClientSocketTest, Read_Interrupted) { EXPECT_EQ(static_cast<int>(arraysize(request_text) - 1), rv); // Do a partial read and then exit. This test should not crash! - scoped_refptr<net::IOBuffer> buf = new net::IOBuffer(512); + scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(512)); rv = sock->Read(buf, 512, &callback); EXPECT_TRUE(rv > 0 || rv == net::ERR_IO_PENDING); diff --git a/net/socket/ssl_client_socket_win.cc b/net/socket/ssl_client_socket_win.cc index 7e8c29e..eead7ed 100644 --- a/net/socket/ssl_client_socket_win.cc +++ b/net/socket/ssl_client_socket_win.cc @@ -705,6 +705,14 @@ bool SSLClientSocketWin::WasEverUsed() const { return false; } +bool SSLClientSocketWin::UsingTCPFastOpen() const { + if (transport_.get() && transport_->socket()) { + return transport_->socket()->UsingTCPFastOpen(); + } + NOTREACHED(); + return false; +} + int SSLClientSocketWin::Read(IOBuffer* buf, int buf_len, CompletionCallback* callback) { DCHECK(completed_handshake()); diff --git a/net/socket/ssl_client_socket_win.h b/net/socket/ssl_client_socket_win.h index 38cdb32..4f96e80 100644 --- a/net/socket/ssl_client_socket_win.h +++ b/net/socket/ssl_client_socket_win.h @@ -54,6 +54,7 @@ class SSLClientSocketWin : public SSLClientSocket { virtual void SetSubresourceSpeculation(); virtual void SetOmniboxSpeculation(); virtual bool WasEverUsed() const; + virtual bool UsingTCPFastOpen() const; // Socket methods: virtual int Read(IOBuffer* buf, int buf_len, CompletionCallback* callback); diff --git a/net/socket/ssl_host_info.cc b/net/socket/ssl_host_info.cc index cc29545..4f6c1bb 100644 --- a/net/socket/ssl_host_info.cc +++ b/net/socket/ssl_host_info.cc @@ -4,6 +4,11 @@ #include "net/socket/ssl_host_info.h" +#include "base/metrics/histogram.h" +#include "base/string_piece.h" +#include "net/base/cert_verifier.h" +#include "net/base/ssl_config_service.h" +#include "net/base/x509_certificate.h" #include "net/socket/ssl_client_socket.h" #ifdef ANDROID // the android platform build system use a fixed include path relative to the @@ -15,7 +20,25 @@ namespace net { -SSLHostInfo::SSLHostInfo() { +SSLHostInfo::State::State() + : npn_valid(false), + npn_status(SSLClientSocket::kNextProtoUnsupported) { +} + +SSLHostInfo::State::~State() {} + +SSLHostInfo::SSLHostInfo( + const std::string& hostname, + const SSLConfig& ssl_config) + : hostname_(hostname), + cert_verification_complete_(false), + cert_parsing_failed_(false), + cert_verification_callback_(NULL), + rev_checking_enabled_(ssl_config.rev_checking_enabled), + verify_ev_cert_(ssl_config.verify_ev_cert), + callback_(new CancelableCompletionCallback<SSLHostInfo>( + ALLOW_THIS_IN_INITIALIZER_LIST(this), + &SSLHostInfo::VerifyCallback)) { state_.npn_valid = false; } @@ -66,6 +89,7 @@ bool SSLHostInfo::Parse(const std::string& data) { state->certs.clear(); state->server_hello.clear(); state->npn_valid = false; + cert_verification_complete_ = false; if (!proto.ParseFromString(data)) return false; @@ -80,6 +104,30 @@ bool SSLHostInfo::Parse(const std::string& data) { state->npn_protocol = proto.npn_protocol(); } + if (state->certs.size() > 0) { + std::vector<base::StringPiece> der_certs(state->certs.size()); + for (size_t i = 0; i < state->certs.size(); i++) + der_certs[i] = state->certs[i]; + cert_ = X509Certificate::CreateFromDERCertChain(der_certs); + if (cert_.get()) { + int flags = 0; + if (verify_ev_cert_) + flags |= X509Certificate::VERIFY_EV_CERT; + if (rev_checking_enabled_) + flags |= X509Certificate::VERIFY_REV_CHECKING_ENABLED; + verifier_.reset(new CertVerifier); + VLOG(1) << "Kicking off verification for " << hostname_; + verification_start_time_ = base::TimeTicks::Now(); + if (verifier_->Verify(cert_.get(), hostname_, flags, + &cert_verify_result_, callback_) == OK) { + VerifyCallback(OK); + } + } else { + cert_parsing_failed_ = true; + DCHECK(!cert_verification_callback_); + } + } + return true; } @@ -101,6 +149,35 @@ std::string SSLHostInfo::Serialize() const { return proto.SerializeAsString(); } +const CertVerifyResult& SSLHostInfo::cert_verify_result() const { + return cert_verify_result_; +} + +int SSLHostInfo::WaitForCertVerification(CompletionCallback* callback) { + if (cert_verification_complete_) + return cert_verification_result_; + DCHECK(!cert_parsing_failed_); + DCHECK(!cert_verification_callback_); + DCHECK(!state_.certs.empty()); + cert_verification_callback_ = callback; + return ERR_IO_PENDING; +} + +void SSLHostInfo::VerifyCallback(int rv) { + DCHECK(!verification_start_time_.is_null()); + base::TimeTicks now = base::TimeTicks::Now(); + const base::TimeDelta duration = now - verification_start_time(); + UMA_HISTOGRAM_TIMES("Net.SSLHostInfoVerificationTimeMs", duration); + VLOG(1) << "Verification took " << duration.InMilliseconds() << "ms"; + cert_verification_complete_ = true; + cert_verification_result_ = rv; + if (cert_verification_callback_) { + CompletionCallback* callback = cert_verification_callback_; + cert_verification_callback_ = NULL; + callback->Run(rv); + } +} + SSLHostInfoFactory::~SSLHostInfoFactory() {} } // namespace net diff --git a/net/socket/ssl_host_info.h b/net/socket/ssl_host_info.h index 8065b47..5f515fb 100644 --- a/net/socket/ssl_host_info.h +++ b/net/socket/ssl_host_info.h @@ -9,18 +9,25 @@ #include <vector> #include "base/ref_counted.h" +#include "base/scoped_ptr.h" +#include "base/time.h" +#include "net/base/cert_verify_result.h" #include "net/base/completion_callback.h" #include "net/socket/ssl_client_socket.h" namespace net { +class CertVerifier; +class X509Certificate; +struct SSLConfig; + // SSLHostInfo is an interface for fetching information about an SSL server. // This information may be stored on disk so does not include keys or session // information etc. Primarily it's intended for caching the server's // certificates. class SSLHostInfo { public: - SSLHostInfo(); + SSLHostInfo(const std::string& hostname, const SSLConfig& ssl_config); virtual ~SSLHostInfo(); // Start will commence the lookup. This must be called before any other @@ -48,6 +55,9 @@ class SSLHostInfo { virtual void Persist() = 0; struct State { + State(); + ~State(); + // certs is a vector of DER encoded X.509 certificates, as the server // returned them and in the same order. std::vector<std::string> certs; @@ -59,6 +69,9 @@ class SSLHostInfo { // these members contain the NPN result of a connection to the server. SSLClientSocket::NextProtoStatus npn_status; std::string npn_protocol; + + private: + DISALLOW_COPY_AND_ASSIGN(State); }; // Once the data is ready, it can be read using the following members. These @@ -66,6 +79,21 @@ class SSLHostInfo { const State& state() const; State* mutable_state(); + // If |cert_valid()| returns true, then this contains the result of verifying + // the certificate. + const CertVerifyResult& cert_verify_result() const; + + // WaitForCertVerification returns ERR_IO_PENDING if the certificate chain in + // |state().certs| is still being validated and arranges for the given + // callback to be called when the verification completes. If the verification has + // already finished then WaitForCertVerification returns the result of that + // verification. + int WaitForCertVerification(CompletionCallback* callback); + + base::TimeTicks verification_start_time() const { + return verification_start_time_; + } + protected: // Parse parses an opaque blob of data and fills out the public member fields // of this object. It returns true iff the parse was successful. The public @@ -73,6 +101,25 @@ class SSLHostInfo { bool Parse(const std::string& data); std::string Serialize() const; State state_; + + private: + // This is the callback function which the CertVerifier calls via |callback_|. + void VerifyCallback(int rv); + + // This is the hostname that we'll validate the certificates against. + const std::string hostname_; + bool cert_verification_complete_; + bool cert_parsing_failed_; + int cert_verification_result_; + CompletionCallback* cert_verification_callback_; + // These two members are taken from the SSLConfig. + bool rev_checking_enabled_; + bool verify_ev_cert_; + base::TimeTicks verification_start_time_; + CertVerifyResult cert_verify_result_; + scoped_ptr<CertVerifier> verifier_; + scoped_refptr<X509Certificate> cert_; + scoped_refptr<CancelableCompletionCallback<SSLHostInfo> > callback_; }; class SSLHostInfoFactory { @@ -81,7 +128,8 @@ class SSLHostInfoFactory { // GetForHost returns a fresh, allocated SSLHostInfo for the given hostname // or NULL on failure. - virtual SSLHostInfo* GetForHost(const std::string& hostname) = 0; + virtual SSLHostInfo* GetForHost(const std::string& hostname, + const SSLConfig& ssl_config) = 0; }; } // namespace net diff --git a/net/socket/tcp_client_socket.cc b/net/socket/tcp_client_socket.cc new file mode 100644 index 0000000..d3d4e20 --- /dev/null +++ b/net/socket/tcp_client_socket.cc @@ -0,0 +1,19 @@ +// Copyright (c) 2006-2009 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/socket/tcp_client_socket.h" + +namespace net { + +static bool g_tcp_fastopen_enabled = false; + +void set_tcp_fastopen_enabled(bool value) { + g_tcp_fastopen_enabled = value; +} + +bool is_tcp_fastopen_enabled() { + return g_tcp_fastopen_enabled; +} + +} // namespace net diff --git a/net/socket/tcp_client_socket.h b/net/socket/tcp_client_socket.h index 6139b5b..13d2dfb 100644 --- a/net/socket/tcp_client_socket.h +++ b/net/socket/tcp_client_socket.h @@ -23,6 +23,13 @@ typedef TCPClientSocketWin TCPClientSocket; typedef TCPClientSocketLibevent TCPClientSocket; #endif +// Enable/disable experimental TCP FastOpen option. +// Not thread safe. Must be called during initialization/startup only. +void set_tcp_fastopen_enabled(bool value); + +// Check if the TCP FastOpen option is enabled. +bool is_tcp_fastopen_enabled(); + } // namespace net #endif // NET_SOCKET_TCP_CLIENT_SOCKET_H_ diff --git a/net/socket/tcp_client_socket_libevent.cc b/net/socket/tcp_client_socket_libevent.cc index aedbf8a..1bbe827 100644 --- a/net/socket/tcp_client_socket_libevent.cc +++ b/net/socket/tcp_client_socket_libevent.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "net/socket/tcp_client_socket_libevent.h" +#include "net/socket/tcp_client_socket.h" #include <errno.h> #include <fcntl.h> @@ -86,6 +86,8 @@ int MapPosixError(int os_error) { int MapConnectError(int os_error) { switch (os_error) { + case EACCES: + return ERR_NETWORK_ACCESS_DENIED; case ETIMEDOUT: return ERR_CONNECTION_TIMED_OUT; default: { @@ -120,11 +122,17 @@ TCPClientSocketLibevent::TCPClientSocketLibevent( write_callback_(NULL), next_connect_state_(CONNECT_STATE_NONE), connect_os_error_(0), - net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_SOCKET)) { + net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_SOCKET)), + previously_disconnected_(false), + use_tcp_fastopen_(false), + tcp_fastopen_connected_(false) { scoped_refptr<NetLog::EventParameters> params; if (source.is_valid()) params = new NetLogSourceParameter("source_dependency", source); net_log_.BeginEvent(NetLog::TYPE_SOCKET_ALIVE, params); + + if (is_tcp_fastopen_enabled()) + use_tcp_fastopen_ = true; } TCPClientSocketLibevent::~TCPClientSocketLibevent() { @@ -144,8 +152,9 @@ int TCPClientSocketLibevent::Connect(CompletionCallback* callback) { DCHECK(!waiting_connect()); - net_log_.BeginEvent(NetLog::TYPE_TCP_CONNECT, - new AddressListNetLogParam(addresses_)); + net_log_.BeginEvent( + NetLog::TYPE_TCP_CONNECT, + make_scoped_refptr(new AddressListNetLogParam(addresses_))); // We will try to connect to each address in addresses_. Start with the // first one in the list. @@ -194,9 +203,14 @@ int TCPClientSocketLibevent::DoConnect() { DCHECK_EQ(0, connect_os_error_); + if (previously_disconnected_) { + use_history_.Reset(); + previously_disconnected_ = false; + } + net_log_.BeginEvent(NetLog::TYPE_TCP_CONNECT_ATTEMPT, - new NetLogStringParameter( - "address", NetAddressToStringWithPort(current_ai_))); + make_scoped_refptr(new NetLogStringParameter( + "address", NetAddressToStringWithPort(current_ai_)))); next_connect_state_ = CONNECT_STATE_CONNECT_COMPLETE; @@ -206,9 +220,15 @@ int TCPClientSocketLibevent::DoConnect() { return MapPosixError(connect_os_error_); // Connect the socket. - if (!HANDLE_EINTR(connect(socket_, current_ai_->ai_addr, - static_cast<int>(current_ai_->ai_addrlen)))) { - // Connected without waiting! + if (!use_tcp_fastopen_) { + if (!HANDLE_EINTR(connect(socket_, current_ai_->ai_addr, + static_cast<int>(current_ai_->ai_addrlen)))) { + // Connected without waiting! + return OK; + } + } else { + // With TCP FastOpen, we pretend that the socket is connected. + DCHECK(!tcp_fastopen_connected_); return OK; } @@ -278,6 +298,7 @@ void TCPClientSocketLibevent::DoDisconnect() { if (HANDLE_EINTR(close(socket_)) < 0) PLOG(ERROR) << "close"; socket_ = kInvalidSocket; + previously_disconnected_ = true; } bool TCPClientSocketLibevent::IsConnected() const { @@ -365,7 +386,7 @@ int TCPClientSocketLibevent::Write(IOBuffer* buf, DCHECK(callback); DCHECK_GT(buf_len, 0); - int nwrite = HANDLE_EINTR(write(socket_, buf->data(), buf_len)); + int nwrite = InternalWrite(buf, buf_len); if (nwrite >= 0) { static base::StatsCounter write_bytes("tcp.write_bytes"); write_bytes.Add(nwrite); @@ -391,6 +412,38 @@ int TCPClientSocketLibevent::Write(IOBuffer* buf, return ERR_IO_PENDING; } +int TCPClientSocketLibevent::InternalWrite(IOBuffer* buf, int buf_len) { + int nwrite; + if (use_tcp_fastopen_ && !tcp_fastopen_connected_) { + // We have a limited amount of data to send in the SYN packet. + int kMaxFastOpenSendLength = 1420; + + buf_len = std::min(kMaxFastOpenSendLength, buf_len); + + int flags = 0x20000000; // Magic flag to enable TCP_FASTOPEN + nwrite = HANDLE_EINTR(sendto(socket_, + buf->data(), + buf_len, + flags, + current_ai_->ai_addr, + static_cast<int>(current_ai_->ai_addrlen))); + tcp_fastopen_connected_ = true; + + if (nwrite < 0) { + // Non-blocking mode is returning EINPROGRESS rather than EAGAIN. + if (errno == EINPROGRESS) + errno = EAGAIN; + + // Unlike "normal" nonblocking sockets, the data is already queued, + // so tell the app that we've consumed it. + return buf_len; + } + } else { + nwrite = HANDLE_EINTR(write(socket_, buf->data(), buf_len)); + } + return nwrite; +} + bool TCPClientSocketLibevent::SetReceiveBufferSize(int32 size) { DCHECK(CalledOnValidThread()); int rv = setsockopt(socket_, SOL_SOCKET, SO_RCVBUF, @@ -553,4 +606,8 @@ bool TCPClientSocketLibevent::WasEverUsed() const { return use_history_.was_used_to_convey_data(); } +bool TCPClientSocketLibevent::UsingTCPFastOpen() const { + return use_tcp_fastopen_; +} + } // namespace net diff --git a/net/socket/tcp_client_socket_libevent.h b/net/socket/tcp_client_socket_libevent.h index 980e4cd..890d0c2 100644 --- a/net/socket/tcp_client_socket_libevent.h +++ b/net/socket/tcp_client_socket_libevent.h @@ -43,6 +43,7 @@ class TCPClientSocketLibevent : public ClientSocket, NonThreadSafe { virtual void SetSubresourceSpeculation(); virtual void SetOmniboxSpeculation(); virtual bool WasEverUsed() const; + virtual bool UsingTCPFastOpen() const; // Socket methods: // Multiple outstanding requests are not supported. @@ -127,6 +128,9 @@ class TCPClientSocketLibevent : public ClientSocket, NonThreadSafe { // Helper to add a TCP_CONNECT (end) event to the NetLog. void LogConnectCompletion(int net_error); + // Internal function to write to a socket. + int InternalWrite(IOBuffer* buf, int buf_len); + int socket_; // The list of addresses we should try in order to establish a connection. @@ -165,10 +169,19 @@ class TCPClientSocketLibevent : public ClientSocket, NonThreadSafe { BoundNetLog net_log_; + // This socket was previously disconnected and has not been re-connected. + bool previously_disconnected_; + // Record of connectivity and transmissions, for use in speculative connection // histograms. UseHistory use_history_; + // Enables experimental TCP FastOpen option. + bool use_tcp_fastopen_; + + // True when TCP FastOpen is in use and we have done the connect. + bool tcp_fastopen_connected_; + DISALLOW_COPY_AND_ASSIGN(TCPClientSocketLibevent); }; diff --git a/net/socket/tcp_client_socket_pool.cc b/net/socket/tcp_client_socket_pool.cc index 5f1f43f..8ec9cac 100644 --- a/net/socket/tcp_client_socket_pool.cc +++ b/net/socket/tcp_client_socket_pool.cc @@ -222,9 +222,9 @@ int TCPClientSocketPool::RequestSocket( // TODO(eroman): Split out the host and port parameters. net_log.AddEvent( NetLog::TYPE_TCP_CLIENT_SOCKET_POOL_REQUESTED_SOCKET, - new NetLogStringParameter( + make_scoped_refptr(new NetLogStringParameter( "host_and_port", - casted_params->get()->destination().host_port_pair().ToString())); + casted_params->get()->destination().host_port_pair().ToString()))); } return base_.RequestSocket(group_name, *casted_params, priority, handle, @@ -243,9 +243,9 @@ void TCPClientSocketPool::RequestSockets( // TODO(eroman): Split out the host and port parameters. net_log.AddEvent( NetLog::TYPE_TCP_CLIENT_SOCKET_POOL_REQUESTED_SOCKETS, - new NetLogStringParameter( + make_scoped_refptr(new NetLogStringParameter( "host_and_port", - casted_params->get()->destination().host_port_pair().ToString())); + casted_params->get()->destination().host_port_pair().ToString()))); } base_.RequestSockets(group_name, *casted_params, num_sockets, net_log); diff --git a/net/socket/tcp_client_socket_pool_unittest.cc b/net/socket/tcp_client_socket_pool_unittest.cc index 80de0aa..e53e264 100644 --- a/net/socket/tcp_client_socket_pool_unittest.cc +++ b/net/socket/tcp_client_socket_pool_unittest.cc @@ -54,6 +54,7 @@ class MockClientSocket : public ClientSocket { virtual void SetSubresourceSpeculation() {} virtual void SetOmniboxSpeculation() {} virtual bool WasEverUsed() const { return false; } + virtual bool UsingTCPFastOpen() const { return false; } // Socket methods: virtual int Read(IOBuffer* buf, int buf_len, @@ -99,6 +100,7 @@ class MockFailingClientSocket : public ClientSocket { virtual void SetSubresourceSpeculation() {} virtual void SetOmniboxSpeculation() {} virtual bool WasEverUsed() const { return false; } + virtual bool UsingTCPFastOpen() const { return false; } // Socket methods: virtual int Read(IOBuffer* buf, int buf_len, @@ -157,6 +159,7 @@ class MockPendingClientSocket : public ClientSocket { virtual void SetSubresourceSpeculation() {} virtual void SetOmniboxSpeculation() {} virtual bool WasEverUsed() const { return false; } + virtual bool UsingTCPFastOpen() const { return false; } // Socket methods: virtual int Read(IOBuffer* buf, int buf_len, @@ -247,7 +250,8 @@ class MockClientSocketFactory : public ClientSocketFactory { ClientSocketHandle* transport_socket, const std::string& hostname, const SSLConfig& ssl_config, - SSLHostInfo* ssl_host_info) { + SSLHostInfo* ssl_host_info, + DnsRRResolver* dnsrr_resolver) { NOTIMPLEMENTED(); delete ssl_host_info; return NULL; @@ -294,8 +298,8 @@ class TCPClientSocketPoolTest : public testing::Test { } int StartRequest(const std::string& group_name, RequestPriority priority) { - scoped_refptr<TCPSocketParams> params = new TCPSocketParams( - HostPortPair("www.google.com", 80), MEDIUM, GURL(), false); + scoped_refptr<TCPSocketParams> params(new TCPSocketParams( + HostPortPair("www.google.com", 80), MEDIUM, GURL(), false)); return test_base_.StartRequestUsingPool( &pool_, group_name, priority, params); } @@ -343,8 +347,8 @@ TEST_F(TCPClientSocketPoolTest, InitHostResolutionFailure) { host_resolver_->rules()->AddSimulatedFailure("unresolvable.host.name"); TestCompletionCallback callback; ClientSocketHandle handle; - scoped_refptr<TCPSocketParams> dest = new TCPSocketParams( - "unresolvable.host.name", 80, kDefaultPriority, GURL(), false); + scoped_refptr<TCPSocketParams> dest(new TCPSocketParams( + "unresolvable.host.name", 80, kDefaultPriority, GURL(), false)); EXPECT_EQ(ERR_IO_PENDING, handle.Init("a", dest, kDefaultPriority, &callback, &pool_, BoundNetLog())); @@ -602,8 +606,8 @@ class RequestSocketCallback : public CallbackRunner< Tuple1<int> > { MessageLoop::current()->RunAllPending(); } within_callback_ = true; - scoped_refptr<TCPSocketParams> dest = new TCPSocketParams( - HostPortPair("www.google.com", 80), LOWEST, GURL(), false); + scoped_refptr<TCPSocketParams> dest(new TCPSocketParams( + HostPortPair("www.google.com", 80), LOWEST, GURL(), false)); int rv = handle_->Init("a", dest, LOWEST, this, pool_, BoundNetLog()); EXPECT_EQ(OK, rv); } @@ -623,8 +627,8 @@ class RequestSocketCallback : public CallbackRunner< Tuple1<int> > { TEST_F(TCPClientSocketPoolTest, RequestTwice) { ClientSocketHandle handle; RequestSocketCallback callback(&handle, &pool_); - scoped_refptr<TCPSocketParams> dest = new TCPSocketParams( - HostPortPair("www.google.com", 80), LOWEST, GURL(), false); + scoped_refptr<TCPSocketParams> dest(new TCPSocketParams( + HostPortPair("www.google.com", 80), LOWEST, GURL(), false)); int rv = handle.Init("a", dest, LOWEST, &callback, &pool_, BoundNetLog()); ASSERT_EQ(ERR_IO_PENDING, rv); diff --git a/net/socket/tcp_client_socket_unittest.cc b/net/socket/tcp_client_socket_unittest.cc index fdd966c..64d78f3 100644 --- a/net/socket/tcp_client_socket_unittest.cc +++ b/net/socket/tcp_client_socket_unittest.cc @@ -93,7 +93,7 @@ void TCPClientSocketTest::SetUp() { AddressList addr; scoped_ptr<HostResolver> resolver( CreateSystemHostResolver(HostResolver::kDefaultParallelism, - NULL)); + NULL, NULL)); HostResolver::RequestInfo info(HostPortPair("localhost", listen_port_)); int rv = resolver->Resolve(info, &addr, NULL, NULL, BoundNetLog()); CHECK_EQ(rv, OK); @@ -138,8 +138,8 @@ TEST_F(TCPClientSocketTest, Read) { } const char request_text[] = "GET / HTTP/1.0\r\n\r\n"; - scoped_refptr<IOBuffer> request_buffer = - new IOBuffer(arraysize(request_text) - 1); + scoped_refptr<IOBuffer> request_buffer( + new IOBuffer(arraysize(request_text) - 1)); memcpy(request_buffer->data(), request_text, arraysize(request_text) - 1); rv = sock_->Write(request_buffer, arraysize(request_text) - 1, &callback); @@ -150,7 +150,7 @@ TEST_F(TCPClientSocketTest, Read) { EXPECT_EQ(rv, static_cast<int>(arraysize(request_text) - 1)); } - scoped_refptr<IOBuffer> buf = new IOBuffer(4096); + scoped_refptr<IOBuffer> buf(new IOBuffer(4096)); uint32 bytes_read = 0; while (bytes_read < arraysize(kServerReply) - 1) { rv = sock_->Read(buf, 4096, &callback); @@ -183,8 +183,8 @@ TEST_F(TCPClientSocketTest, Read_SmallChunks) { } const char request_text[] = "GET / HTTP/1.0\r\n\r\n"; - scoped_refptr<IOBuffer> request_buffer = - new IOBuffer(arraysize(request_text) - 1); + scoped_refptr<IOBuffer> request_buffer( + new IOBuffer(arraysize(request_text) - 1)); memcpy(request_buffer->data(), request_text, arraysize(request_text) - 1); rv = sock_->Write(request_buffer, arraysize(request_text) - 1, &callback); @@ -195,7 +195,7 @@ TEST_F(TCPClientSocketTest, Read_SmallChunks) { EXPECT_EQ(rv, static_cast<int>(arraysize(request_text) - 1)); } - scoped_refptr<IOBuffer> buf = new IOBuffer(1); + scoped_refptr<IOBuffer> buf(new IOBuffer(1)); uint32 bytes_read = 0; while (bytes_read < arraysize(kServerReply) - 1) { rv = sock_->Read(buf, 1, &callback); @@ -228,8 +228,8 @@ TEST_F(TCPClientSocketTest, Read_Interrupted) { } const char request_text[] = "GET / HTTP/1.0\r\n\r\n"; - scoped_refptr<IOBuffer> request_buffer = - new IOBuffer(arraysize(request_text) - 1); + scoped_refptr<IOBuffer> request_buffer( + new IOBuffer(arraysize(request_text) - 1)); memcpy(request_buffer->data(), request_text, arraysize(request_text) - 1); rv = sock_->Write(request_buffer, arraysize(request_text) - 1, &callback); @@ -241,7 +241,7 @@ TEST_F(TCPClientSocketTest, Read_Interrupted) { } // Do a partial read and then exit. This test should not crash! - scoped_refptr<IOBuffer> buf = new IOBuffer(16); + scoped_refptr<IOBuffer> buf(new IOBuffer(16)); rv = sock_->Read(buf, 16, &callback); EXPECT_TRUE(rv >= 0 || rv == ERR_IO_PENDING); @@ -263,13 +263,13 @@ TEST_F(TCPClientSocketTest, DISABLED_FullDuplex_ReadFirst) { // Read first. There's no data, so it should return ERR_IO_PENDING. const int kBufLen = 4096; - scoped_refptr<IOBuffer> buf = new IOBuffer(kBufLen); + scoped_refptr<IOBuffer> buf(new IOBuffer(kBufLen)); rv = sock_->Read(buf, kBufLen, &callback); EXPECT_EQ(ERR_IO_PENDING, rv); PauseServerReads(); const int kWriteBufLen = 64 * 1024; - scoped_refptr<IOBuffer> request_buffer = new IOBuffer(kWriteBufLen); + scoped_refptr<IOBuffer> request_buffer(new IOBuffer(kWriteBufLen)); char* request_data = request_buffer->data(); memset(request_data, 'A', kWriteBufLen); TestCompletionCallback write_callback; @@ -305,7 +305,7 @@ TEST_F(TCPClientSocketTest, DISABLED_FullDuplex_WriteFirst) { PauseServerReads(); const int kWriteBufLen = 64 * 1024; - scoped_refptr<IOBuffer> request_buffer = new IOBuffer(kWriteBufLen); + scoped_refptr<IOBuffer> request_buffer(new IOBuffer(kWriteBufLen)); char* request_data = request_buffer->data(); memset(request_data, 'A', kWriteBufLen); TestCompletionCallback write_callback; @@ -322,7 +322,7 @@ TEST_F(TCPClientSocketTest, DISABLED_FullDuplex_WriteFirst) { // Read() to block on ERR_IO_PENDING too. const int kBufLen = 4096; - scoped_refptr<IOBuffer> buf = new IOBuffer(kBufLen); + scoped_refptr<IOBuffer> buf(new IOBuffer(kBufLen)); while (true) { rv = sock_->Read(buf, kBufLen, &callback); ASSERT_TRUE(rv >= 0 || rv == ERR_IO_PENDING); diff --git a/net/socket/tcp_client_socket_win.cc b/net/socket/tcp_client_socket_win.cc index 9143b81..b3b79a0 100644 --- a/net/socket/tcp_client_socket_win.cc +++ b/net/socket/tcp_client_socket_win.cc @@ -64,8 +64,6 @@ int MapWinsockError(int os_error) { // There are numerous Winsock error codes, but these are the ones we thus far // find interesting. switch (os_error) { - // connect fails with WSAEACCES when Windows Firewall blocks the - // connection. case WSAEACCES: return ERR_ACCESS_DENIED; case WSAENETDOWN: @@ -104,6 +102,10 @@ int MapWinsockError(int os_error) { int MapConnectError(int os_error) { switch (os_error) { + // connect fails with WSAEACCES when Windows Firewall blocks the + // connection. + case WSAEACCES: + return ERR_NETWORK_ACCESS_DENIED; case WSAETIMEDOUT: return ERR_CONNECTION_TIMED_OUT; default: { @@ -290,8 +292,8 @@ TCPClientSocketWin::TCPClientSocketWin(const AddressList& addresses, write_callback_(NULL), next_connect_state_(CONNECT_STATE_NONE), connect_os_error_(0), - net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_SOCKET)) { - + net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_SOCKET)), + previously_disconnected_(false) { scoped_refptr<NetLog::EventParameters> params; if (source.is_valid()) params = new NetLogSourceParameter("source_dependency", source); @@ -364,6 +366,11 @@ int TCPClientSocketWin::DoConnect() { DCHECK(ai); DCHECK_EQ(0, connect_os_error_); + if (previously_disconnected_) { + use_history_.Reset(); + previously_disconnected_ = false; + } + net_log_.BeginEvent(NetLog::TYPE_TCP_CONNECT_ATTEMPT, new NetLogStringParameter( "address", NetAddressToStringWithPort(current_ai_))); @@ -478,6 +485,8 @@ void TCPClientSocketWin::DoDisconnect() { core_->Detach(); core_ = NULL; + + previously_disconnected_ = true; } bool TCPClientSocketWin::IsConnected() const { @@ -536,6 +545,11 @@ bool TCPClientSocketWin::WasEverUsed() const { return use_history_.was_used_to_convey_data(); } +bool TCPClientSocketWin::UsingTCPFastOpen() const { + // Not supported on windows. + return false; +} + int TCPClientSocketWin::Read(IOBuffer* buf, int buf_len, CompletionCallback* callback) { diff --git a/net/socket/tcp_client_socket_win.h b/net/socket/tcp_client_socket_win.h index be25157..cd6b066 100644 --- a/net/socket/tcp_client_socket_win.h +++ b/net/socket/tcp_client_socket_win.h @@ -40,6 +40,7 @@ class TCPClientSocketWin : public ClientSocket, NonThreadSafe { virtual void SetSubresourceSpeculation(); virtual void SetOmniboxSpeculation(); virtual bool WasEverUsed() const; + virtual bool UsingTCPFastOpen() const; // Socket methods: // Multiple outstanding requests are not supported. @@ -117,6 +118,9 @@ class TCPClientSocketWin : public ClientSocket, NonThreadSafe { BoundNetLog net_log_; + // This socket was previously disconnected and has not been re-connected. + bool previously_disconnected_; + // Record of connectivity and transmissions, for use in speculative connection // histograms. UseHistory use_history_; diff --git a/net/socket_stream/socket_stream.cc b/net/socket_stream/socket_stream.cc index 7c3c5e9..6d6efbe 100644 --- a/net/socket_stream/socket_stream.cc +++ b/net/socket_stream/socket_stream.cc @@ -138,7 +138,8 @@ void SocketStream::Connect() { next_state_ = STATE_RESOLVE_PROXY; net_log_.BeginEvent( NetLog::TYPE_SOCKET_STREAM_CONNECT, - new NetLogStringParameter("url", url_.possibly_invalid_spec())); + make_scoped_refptr( + new NetLogStringParameter("url", url_.possibly_invalid_spec()))); MessageLoop::current()->PostTask( FROM_HERE, NewRunnableMethod(this, &SocketStream::DoLoop, OK)); @@ -162,7 +163,8 @@ bool SocketStream::SendData(const char* data, int len) { if (current_amount_send > max_pending_send_allowed_) return false; - pending_write_bufs_.push_back(new IOBufferWithSize(len)); + pending_write_bufs_.push_back(make_scoped_refptr( + new IOBufferWithSize(len))); memcpy(pending_write_bufs_.back()->data(), data, len); return true; } @@ -445,8 +447,9 @@ void SocketStream::DoLoop(int result) { // close the connection. if (state != STATE_READ_WRITE && result < ERR_IO_PENDING) { DCHECK_EQ(next_state_, STATE_CLOSE); - net_log_.EndEvent(NetLog::TYPE_SOCKET_STREAM_CONNECT, - new NetLogIntegerParameter("net_error", result)); + net_log_.EndEvent( + NetLog::TYPE_SOCKET_STREAM_CONNECT, + make_scoped_refptr(new NetLogIntegerParameter("net_error", result))); } } while (result != ERR_IO_PENDING); } diff --git a/net/socket_stream/socket_stream_unittest.cc b/net/socket_stream/socket_stream_unittest.cc index 25ce17b..832b0ab 100644 --- a/net/socket_stream/socket_stream_unittest.cc +++ b/net/socket_stream/socket_stream_unittest.cc @@ -240,8 +240,8 @@ TEST_F(SocketStreamTest, CloseFlushPendingWrite) { MockHostResolver host_resolver; - scoped_refptr<SocketStream> socket_stream = - new SocketStream(GURL("ws://example.com/demo"), delegate.get()); + scoped_refptr<SocketStream> socket_stream( + new SocketStream(GURL("ws://example.com/demo"), delegate.get())); socket_stream->set_context(new TestURLRequestContext()); socket_stream->SetHostResolver(&host_resolver); @@ -331,8 +331,8 @@ TEST_F(SocketStreamTest, BasicAuthProxy) { NewCallback(delegate.get(), &SocketStreamEventRecorder::DoRestartWithAuth)); - scoped_refptr<SocketStream> socket_stream = - new SocketStream(GURL("ws://example.com/demo"), delegate.get()); + scoped_refptr<SocketStream> socket_stream( + new SocketStream(GURL("ws://example.com/demo"), delegate.get())); socket_stream->set_context(new TestURLRequestContext("myproxy:70")); MockHostResolver host_resolver; diff --git a/net/spdy/spdy_http_stream.cc b/net/spdy/spdy_http_stream.cc index 6fede6c..89002cb 100644 --- a/net/spdy/spdy_http_stream.cc +++ b/net/spdy/spdy_http_stream.cc @@ -12,6 +12,7 @@ #include "base/message_loop.h" #include "net/base/load_flags.h" #include "net/base/net_util.h" +#include "net/http/http_request_headers.h" #include "net/http/http_request_info.h" #include "net/http/http_response_info.h" #include "net/http/http_util.h" @@ -112,7 +113,7 @@ int SpdyHttpStream::ReadResponseBody( memcpy(new_buffer->data(), &(data->data()[bytes_to_copy]), bytes_remaining); response_body_.pop_front(); - response_body_.push_front(new_buffer); + response_body_.push_front(make_scoped_refptr(new_buffer)); } bytes_read += bytes_to_copy; } @@ -139,7 +140,7 @@ void SpdyHttpStream::Close(bool not_reusable) { Cancel(); } -int SpdyHttpStream::SendRequest(const std::string& /*headers_string*/, +int SpdyHttpStream::SendRequest(const HttpRequestHeaders& request_headers, UploadDataStream* request_body, HttpResponseInfo* response, CompletionCallback* callback) { @@ -148,9 +149,6 @@ int SpdyHttpStream::SendRequest(const std::string& /*headers_string*/, stream_->SetDelegate(this); - HttpRequestHeaders request_headers; - HttpUtil::BuildRequestHeaders(request_info_, request_body, NULL, false, false, - !direct_, &request_headers); linked_ptr<spdy::SpdyHeaderBlock> headers(new spdy::SpdyHeaderBlock); CreateSpdyHeadersFromHttpRequest(*request_info_, request_headers, headers.get(), direct_); @@ -275,7 +273,7 @@ void SpdyHttpStream::OnDataReceived(const char* data, int length) { // Save the received data. IOBufferWithSize* io_buffer = new IOBufferWithSize(length); memcpy(io_buffer->data(), data, length); - response_body_.push_back(io_buffer); + response_body_.push_back(make_scoped_refptr(io_buffer)); if (user_buffer_) { // Handing small chunks of data to the caller creates measurable overhead. diff --git a/net/spdy/spdy_http_stream.h b/net/spdy/spdy_http_stream.h index 372db57..a878ff9 100644 --- a/net/spdy/spdy_http_stream.h +++ b/net/spdy/spdy_http_stream.h @@ -49,7 +49,7 @@ class SpdyHttpStream : public SpdyStream::Delegate, public HttpStream { // |callback| is used when this completes asynchronously. // SpdyHttpStream takes ownership of |upload_data|. |upload_data| may be NULL. // The actual SYN_STREAM packet will be sent if the stream is non-pushed. - virtual int SendRequest(const std::string& headers, + virtual int SendRequest(const HttpRequestHeaders& headers, UploadDataStream* request_body, HttpResponseInfo* response, CompletionCallback* callback); diff --git a/net/spdy/spdy_http_stream_unittest.cc b/net/spdy/spdy_http_stream_unittest.cc index ee1a34e..df979ec 100644 --- a/net/spdy/spdy_http_stream_unittest.cc +++ b/net/spdy/spdy_http_stream_unittest.cc @@ -74,6 +74,7 @@ TEST_F(SpdyHttpStreamTest, SendRequest) { request.url = GURL("http://www.google.com/"); TestCompletionCallback callback; HttpResponseInfo response; + HttpRequestHeaders headers; BoundNetLog net_log; scoped_ptr<SpdyHttpStream> http_stream( new SpdyHttpStream(session_.get(), true)); @@ -82,7 +83,7 @@ TEST_F(SpdyHttpStreamTest, SendRequest) { http_stream->InitializeStream(&request, net_log, NULL)); EXPECT_EQ(ERR_IO_PENDING, - http_stream->SendRequest("", NULL, &response, &callback)); + http_stream->SendRequest(headers, NULL, &response, &callback)); EXPECT_TRUE(http_session_->spdy_session_pool()->HasSession(pair)); // This triggers the MockWrite and read 2 @@ -125,6 +126,7 @@ TEST_F(SpdyHttpStreamTest, SpdyURLTest) { request.url = GURL(full_url); TestCompletionCallback callback; HttpResponseInfo response; + HttpRequestHeaders headers; BoundNetLog net_log; scoped_ptr<SpdyHttpStream> http_stream(new SpdyHttpStream(session_, true)); ASSERT_EQ( @@ -132,7 +134,7 @@ TEST_F(SpdyHttpStreamTest, SpdyURLTest) { http_stream->InitializeStream(&request, net_log, NULL)); EXPECT_EQ(ERR_IO_PENDING, - http_stream->SendRequest("", NULL, &response, &callback)); + http_stream->SendRequest(headers, NULL, &response, &callback)); spdy::SpdyHeaderBlock* spdy_header = http_stream->stream()->spdy_headers().get(); diff --git a/net/spdy/spdy_network_transaction_unittest.cc b/net/spdy/spdy_network_transaction_unittest.cc index 99b5089..d72a2a7 100644 --- a/net/spdy/spdy_network_transaction_unittest.cc +++ b/net/spdy/spdy_network_transaction_unittest.cc @@ -5,6 +5,7 @@ #include <string> #include <vector> +#include "net/base/auth.h" #include "net/base/net_log_unittest.h" #include "net/http/http_network_session_peer.h" #include "net/http/http_transaction_unittest.h" @@ -345,7 +346,7 @@ class SpdyNetworkTransactionTest const int kSize = 3000; int bytes_read = 0; - scoped_refptr<net::IOBufferWithSize> buf = new net::IOBufferWithSize(kSize); + scoped_refptr<net::IOBufferWithSize> buf(new net::IOBufferWithSize(kSize)); TestCompletionCallback callback; while (true) { int rv = trans->Read(buf, kSize, &callback); @@ -461,8 +462,8 @@ INSTANTIATE_TEST_CASE_P(Spdy, // Verify HttpNetworkTransaction constructor. TEST_P(SpdyNetworkTransactionTest, Constructor) { SpdySessionDependencies session_deps; - scoped_refptr<HttpNetworkSession> session = - SpdySessionDependencies::SpdyCreateSession(&session_deps); + scoped_refptr<HttpNetworkSession> session( + SpdySessionDependencies::SpdyCreateSession(&session_deps)); scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); } @@ -1708,7 +1709,7 @@ TEST_P(SpdyNetworkTransactionTest, WindowUpdateSent) { // Issue a read which will cause a WINDOW_UPDATE to be sent and window // size increased to default. - scoped_refptr<net::IOBuffer> buf = new net::IOBuffer(kUploadDataSize); + scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(kUploadDataSize)); rv = trans->Read(buf, kUploadDataSize, NULL); EXPECT_EQ(kUploadDataSize, rv); std::string content(buf->data(), buf->data()+kUploadDataSize); @@ -2074,7 +2075,7 @@ TEST_P(SpdyNetworkTransactionTest, StartTransactionOnReadCallback) { StartTransactionCallback callback2(helper.session(), helper); const int kSize = 3000; - scoped_refptr<net::IOBuffer> buf = new net::IOBuffer(kSize); + scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(kSize)); rv = trans->Read(buf, kSize, &callback2); // This forces an err_IO_pending, which sets the callback. data->CompleteRead(); @@ -2134,7 +2135,7 @@ TEST_P(SpdyNetworkTransactionTest, DeleteSessionOnReadCallback) { // memory holding the stream object. Note that the callback deletes trans. DeleteSessionCallback callback2(helper); const int kSize = 3000; - scoped_refptr<net::IOBuffer> buf = new net::IOBuffer(kSize); + scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(kSize)); rv = trans->Read(buf, kSize, &callback2); ASSERT_EQ(ERR_IO_PENDING, rv); data->CompleteRead(); @@ -3417,7 +3418,7 @@ TEST_P(SpdyNetworkTransactionTest, BufferFull) { do { // Read small chunks at a time. const int kSmallReadSize = 3; - scoped_refptr<net::IOBuffer> buf = new net::IOBuffer(kSmallReadSize); + scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(kSmallReadSize)); rv = trans->Read(buf, kSmallReadSize, &read_callback); if (rv == net::ERR_IO_PENDING) { data->CompleteRead(); @@ -3583,7 +3584,7 @@ TEST_P(SpdyNetworkTransactionTest, Buffering) { do { // Read small chunks at a time. const int kSmallReadSize = 14; - scoped_refptr<net::IOBuffer> buf = new net::IOBuffer(kSmallReadSize); + scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(kSmallReadSize)); rv = trans->Read(buf, kSmallReadSize, &read_callback); if (rv == net::ERR_IO_PENDING) { data->CompleteRead(); @@ -3678,7 +3679,7 @@ TEST_P(SpdyNetworkTransactionTest, BufferedAll) { do { // Read small chunks at a time. const int kSmallReadSize = 14; - scoped_refptr<net::IOBuffer> buf = new net::IOBuffer(kSmallReadSize); + scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(kSmallReadSize)); rv = trans->Read(buf, kSmallReadSize, &read_callback); if (rv > 0) { EXPECT_EQ(kSmallReadSize, rv); @@ -3767,7 +3768,7 @@ TEST_P(SpdyNetworkTransactionTest, BufferedClosed) { do { // Read small chunks at a time. const int kSmallReadSize = 14; - scoped_refptr<net::IOBuffer> buf = new net::IOBuffer(kSmallReadSize); + scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(kSmallReadSize)); rv = trans->Read(buf, kSmallReadSize, &read_callback); if (rv == net::ERR_IO_PENDING) { data->CompleteRead(); @@ -3843,7 +3844,7 @@ TEST_P(SpdyNetworkTransactionTest, BufferedCancelled) { do { const int kReadSize = 256; - scoped_refptr<net::IOBuffer> buf = new net::IOBuffer(kReadSize); + scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(kReadSize)); rv = trans->Read(buf, kReadSize, &read_callback); if (rv == net::ERR_IO_PENDING) { // Complete the read now, which causes buffering to start. @@ -4150,8 +4151,8 @@ TEST_P(SpdyNetworkTransactionTest, ProxyConnect) { BoundNetLog(), GetParam()); helper.session_deps().reset(new SpdySessionDependencies( ProxyService::CreateFixedFromPacResult("PROXY myproxy:70"))); - helper.SetSession(SpdySessionDependencies::SpdyCreateSession( - helper.session_deps().get())); + helper.SetSession(make_scoped_refptr( + SpdySessionDependencies::SpdyCreateSession(helper.session_deps().get()))); helper.RunPreTestSetup(); HttpNetworkTransaction* trans = helper.trans(); @@ -4253,8 +4254,8 @@ TEST_P(SpdyNetworkTransactionTest, DirectConnectProxyReconnect) { // that the session pool key used does is just "DIRECT". helper.session_deps().reset(new SpdySessionDependencies( ProxyService::CreateFixedFromPacResult("DIRECT; PROXY myproxy:70"))); - helper.SetSession(SpdySessionDependencies::SpdyCreateSession( - helper.session_deps().get())); + helper.SetSession(make_scoped_refptr( + SpdySessionDependencies::SpdyCreateSession(helper.session_deps().get()))); SpdySessionPool* spdy_session_pool = helper.session()->spdy_session_pool(); helper.RunPreTestSetup(); @@ -4381,8 +4382,8 @@ TEST_P(SpdyNetworkTransactionTest, DirectConnectProxyReconnect) { request_proxy.load_flags = 0; scoped_ptr<SpdySessionDependencies> ssd_proxy(new SpdySessionDependencies()); // Ensure that this transaction uses the same SpdySessionPool. - scoped_refptr<HttpNetworkSession> session_proxy = - SpdySessionDependencies::SpdyCreateSession(ssd_proxy.get()); + scoped_refptr<HttpNetworkSession> session_proxy( + SpdySessionDependencies::SpdyCreateSession(ssd_proxy.get())); NormalSpdyTransactionHelper helper_proxy(request_proxy, BoundNetLog(), GetParam()); HttpNetworkSessionPeer session_peer(session_proxy); @@ -4511,7 +4512,8 @@ TEST_P(SpdyNetworkTransactionTest, SpdyOnOffToggle) { }; scoped_refptr<DelayedSocketData> data( - new DelayedSocketData(1, spdy_reads, arraysize(spdy_reads), + new DelayedSocketData(1, + spdy_reads, arraysize(spdy_reads), spdy_writes, arraysize(spdy_writes))); NormalSpdyTransactionHelper helper(CreateGetRequest(), BoundNetLog(), GetParam()); @@ -4541,4 +4543,94 @@ TEST_P(SpdyNetworkTransactionTest, SpdyOnOffToggle) { net::HttpStreamFactory::set_spdy_enabled(true); } + +// Tests that Basic authentication works over SPDY +TEST_P(SpdyNetworkTransactionTest, SpdyBasicAuth) { + net::HttpStreamFactory::set_spdy_enabled(true); + + // The first request will be a bare GET, the second request will be a + // GET with an Authorization header. + scoped_ptr<spdy::SpdyFrame> req_get( + ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); + const char* const kExtraAuthorizationHeaders[] = { + "authorization", + "Basic Zm9vOmJhcg==", + }; + scoped_ptr<spdy::SpdyFrame> req_get_authorization( + ConstructSpdyGet( + kExtraAuthorizationHeaders, arraysize(kExtraAuthorizationHeaders)/2, + false, 3, LOWEST)); + MockWrite spdy_writes[] = { + CreateMockWrite(*req_get, 1), + CreateMockWrite(*req_get_authorization, 4), + }; + + // The first response is a 401 authentication challenge, and the second + // response will be a 200 response since the second request includes a valid + // Authorization header. + const char* const kExtraAuthenticationHeaders[] = { + "WWW-Authenticate", + "Basic realm=\"MyRealm\"" + }; + scoped_ptr<spdy::SpdyFrame> resp_authentication( + ConstructSpdySynReplyError( + "401 Authentication Required", + kExtraAuthenticationHeaders, arraysize(kExtraAuthenticationHeaders)/2, + 1)); + scoped_ptr<spdy::SpdyFrame> body_authentication( + ConstructSpdyBodyFrame(1, true)); + scoped_ptr<spdy::SpdyFrame> resp_data(ConstructSpdyGetSynReply(NULL, 0, 3)); + scoped_ptr<spdy::SpdyFrame> body_data(ConstructSpdyBodyFrame(3, true)); + MockRead spdy_reads[] = { + CreateMockRead(*resp_authentication, 2), + CreateMockRead(*body_authentication, 3), + CreateMockRead(*resp_data, 5), + CreateMockRead(*body_data, 6), + MockRead(true, 0, 7), + }; + + scoped_refptr<OrderedSocketData> data( + new OrderedSocketData(spdy_reads, arraysize(spdy_reads), + spdy_writes, arraysize(spdy_writes))); + HttpRequestInfo request(CreateGetRequest()); + BoundNetLog net_log; + NormalSpdyTransactionHelper helper(request, net_log, GetParam()); + + helper.RunPreTestSetup(); + helper.AddData(data.get()); + HttpNetworkTransaction* trans = helper.trans(); + TestCompletionCallback callback_start; + const int rv_start = trans->Start(&request, &callback_start, net_log); + EXPECT_EQ(ERR_IO_PENDING, rv_start); + const int rv_start_complete = callback_start.WaitForResult(); + EXPECT_EQ(OK, rv_start_complete); + + // Make sure the response has an auth challenge. + const HttpResponseInfo* const response_start = trans->GetResponseInfo(); + ASSERT_TRUE(response_start != NULL); + ASSERT_TRUE(response_start->headers != NULL); + EXPECT_EQ(401, response_start->headers->response_code()); + EXPECT_TRUE(response_start->was_fetched_via_spdy); + ASSERT_TRUE(response_start->auth_challenge.get() != NULL); + EXPECT_FALSE(response_start->auth_challenge->is_proxy); + EXPECT_EQ(L"basic", response_start->auth_challenge->scheme); + EXPECT_EQ(L"MyRealm", response_start->auth_challenge->realm); + + // Restart with a username/password. + const string16 kFoo(ASCIIToUTF16("foo")); + const string16 kBar(ASCIIToUTF16("bar")); + TestCompletionCallback callback_restart; + const int rv_restart = trans->RestartWithAuth(kFoo, kBar, &callback_restart); + EXPECT_EQ(ERR_IO_PENDING, rv_restart); + const int rv_restart_complete = callback_restart.WaitForResult(); + EXPECT_EQ(OK, rv_restart_complete); + // TODO(cbentzel): This is actually the same response object as before, but + // data has changed. + const HttpResponseInfo* const response_restart = trans->GetResponseInfo(); + ASSERT_TRUE(response_restart != NULL); + ASSERT_TRUE(response_restart->headers != NULL); + EXPECT_EQ(200, response_restart->headers->response_code()); + EXPECT_TRUE(response_restart->auth_challenge.get() == NULL); +} + } // namespace net diff --git a/net/spdy/spdy_proxy_client_socket.cc b/net/spdy/spdy_proxy_client_socket.cc index 53bcb0d..8066007 100644 --- a/net/spdy/spdy_proxy_client_socket.cc +++ b/net/spdy/spdy_proxy_client_socket.cc @@ -120,6 +120,10 @@ bool SpdyProxyClientSocket::WasEverUsed() const { return was_ever_used_ || (spdy_stream_ && spdy_stream_->WasEverUsed()); } +bool SpdyProxyClientSocket::UsingTCPFastOpen() const { + return false; +} + int SpdyProxyClientSocket::Read(IOBuffer* buf, int buf_len, CompletionCallback* callback) { DCHECK(!read_callback_); @@ -306,8 +310,8 @@ int SpdyProxyClientSocket::DoSendRequest() { if (net_log_.IsLoggingAllEvents()) { net_log_.AddEvent( NetLog::TYPE_HTTP_TRANSACTION_SEND_TUNNEL_HEADERS, - new NetLogHttpRequestParameter( - request_line, request_headers)); + make_scoped_refptr(new NetLogHttpRequestParameter( + request_line, request_headers))); } request_.extra_headers.MergeFrom(request_headers); @@ -346,7 +350,7 @@ int SpdyProxyClientSocket::DoReadReplyComplete(int result) { if (net_log_.IsLoggingAllEvents()) { net_log_.AddEvent( NetLog::TYPE_HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS, - new NetLogHttpResponseParameter(response_.headers)); + make_scoped_refptr(new NetLogHttpResponseParameter(response_.headers))); } if (response_.headers->response_code() == 200) @@ -400,9 +404,10 @@ int SpdyProxyClientSocket::OnResponseReceived( void SpdyProxyClientSocket::OnDataReceived(const char* data, int length) { if (length > 0) { // Save the received data. - scoped_refptr<IOBuffer> io_buffer = new IOBuffer(length); + scoped_refptr<IOBuffer> io_buffer(new IOBuffer(length)); memcpy(io_buffer->data(), data, length); - read_buffer_.push_back(new DrainableIOBuffer(io_buffer, length)); + read_buffer_.push_back( + make_scoped_refptr(new DrainableIOBuffer(io_buffer, length))); } if (read_callback_) { diff --git a/net/spdy/spdy_proxy_client_socket.h b/net/spdy/spdy_proxy_client_socket.h index b993b5e..4a0747e 100644 --- a/net/spdy/spdy_proxy_client_socket.h +++ b/net/spdy/spdy_proxy_client_socket.h @@ -71,6 +71,7 @@ class SpdyProxyClientSocket : public ClientSocket, public SpdyStream::Delegate { virtual void SetSubresourceSpeculation(); virtual void SetOmniboxSpeculation(); virtual bool WasEverUsed() const; + virtual bool UsingTCPFastOpen() const; // Socket methods: diff --git a/net/spdy/spdy_session.cc b/net/spdy/spdy_session.cc index f94dfd3..7035bb8 100644 --- a/net/spdy/spdy_session.cc +++ b/net/spdy/spdy_session.cc @@ -216,6 +216,9 @@ bool SpdySession::use_ssl_ = true; // static bool SpdySession::use_flow_control_ = false; +// static +size_t SpdySession::max_concurrent_stream_limit_ = 256; + SpdySession::SpdySession(const HostPortProxyPair& host_port_proxy_pair, SpdySessionPool* spdy_session_pool, SpdySettingsStorage* spdy_settings, @@ -252,7 +255,8 @@ SpdySession::SpdySession(const HostPortProxyPair& host_port_proxy_pair, DCHECK(HttpStreamFactory::spdy_enabled()); net_log_.BeginEvent( NetLog::TYPE_SPDY_SESSION, - new NetLogSpdySessionParameter(host_port_proxy_pair_)); + make_scoped_refptr( + new NetLogSpdySessionParameter(host_port_proxy_pair_))); // TODO(mbelshe): consider randomization of the stream_hi_water_mark. @@ -460,7 +464,8 @@ int SpdySession::WriteSynStream( if (net_log().IsLoggingAllEvents()) { net_log().AddEvent( NetLog::TYPE_SPDY_SESSION_SYN_STREAM, - new NetLogSpdySynParameter(headers, flags, stream_id)); + make_scoped_refptr( + new NetLogSpdySynParameter(headers, flags, stream_id))); } return ERR_IO_PENDING; @@ -491,8 +496,10 @@ int SpdySession::WriteStreamData(spdy::SpdyStreamId stream_id, // as stalled - because only the session knows for sure when the // stall occurs. stream->set_stalled_by_flow_control(true); - net_log().AddEvent(NetLog::TYPE_SPDY_SESSION_STALLED_ON_SEND_WINDOW, - new NetLogIntegerParameter("stream_id", stream_id)); + net_log().AddEvent( + NetLog::TYPE_SPDY_SESSION_STALLED_ON_SEND_WINDOW, + make_scoped_refptr( + new NetLogIntegerParameter("stream_id", stream_id))); return ERR_IO_PENDING; } int new_len = std::min(len, stream->send_window_size()); @@ -503,9 +510,11 @@ int SpdySession::WriteStreamData(spdy::SpdyStreamId stream_id, stream->DecreaseSendWindowSize(len); } - if (net_log().IsLoggingAllEvents()) - net_log().AddEvent(NetLog::TYPE_SPDY_SESSION_SEND_DATA, - new NetLogSpdyDataParameter(stream_id, len, flags)); + if (net_log().IsLoggingAllEvents()) { + net_log().AddEvent( + NetLog::TYPE_SPDY_SESSION_SEND_DATA, + make_scoped_refptr(new NetLogSpdyDataParameter(stream_id, len, flags))); + } // TODO(mbelshe): reduce memory copies here. scoped_ptr<spdy::SpdyDataFrame> frame( @@ -526,7 +535,7 @@ void SpdySession::ResetStream( net_log().AddEvent( NetLog::TYPE_SPDY_SESSION_SEND_RST_STREAM, - new NetLogSpdyRstParameter(stream_id, status)); + make_scoped_refptr(new NetLogSpdyRstParameter(stream_id, status))); scoped_ptr<spdy::SpdyRstStreamControlFrame> rst_frame( spdy_framer_.CreateRstStream(stream_id, status)); @@ -826,8 +835,9 @@ void SpdySession::CloseSessionOnError(net::Error err, bool remove_from_pool) { scoped_refptr<SpdySession> self(this); DCHECK_LT(err, OK); - net_log_.AddEvent(NetLog::TYPE_SPDY_SESSION_CLOSE, - new NetLogIntegerParameter("status", err)); + net_log_.AddEvent( + NetLog::TYPE_SPDY_SESSION_CLOSE, + make_scoped_refptr(new NetLogIntegerParameter("status", err))); // Don't close twice. This can occur because we can have both // a read and a write outstanding, and each can complete with @@ -909,7 +919,7 @@ void SpdySession::DeleteStream(spdy::SpdyStreamId id, int status) { void SpdySession::RemoveFromPool() { if (spdy_session_pool_) { - spdy_session_pool_->Remove(this); + spdy_session_pool_->Remove(make_scoped_refptr(this)); spdy_session_pool_ = NULL; } } @@ -960,9 +970,12 @@ void SpdySession::OnError(spdy::SpdyFramer* framer) { void SpdySession::OnStreamFrameData(spdy::SpdyStreamId stream_id, const char* data, size_t len) { - if (net_log().IsLoggingAllEvents()) - net_log().AddEvent(NetLog::TYPE_SPDY_SESSION_RECV_DATA, - new NetLogSpdyDataParameter(stream_id, len, spdy::SpdyDataFlags())); + if (net_log().IsLoggingAllEvents()) { + net_log().AddEvent( + NetLog::TYPE_SPDY_SESSION_RECV_DATA, + make_scoped_refptr(new NetLogSpdyDataParameter( + stream_id, len, spdy::SpdyDataFlags()))); + } if (!IsStreamActive(stream_id)) { // NOTE: it may just be that the stream was cancelled. @@ -996,9 +1009,9 @@ void SpdySession::OnSyn(const spdy::SpdySynStreamControlFrame& frame, if (net_log_.IsLoggingAllEvents()) { net_log_.AddEvent( NetLog::TYPE_SPDY_SESSION_PUSHED_SYN_STREAM, - new NetLogSpdySynParameter( + make_scoped_refptr(new NetLogSpdySynParameter( headers, static_cast<spdy::SpdyControlFlags>(frame.flags()), - stream_id)); + stream_id))); } // Server-initiated streams should have even sequence numbers. @@ -1051,8 +1064,8 @@ void SpdySession::OnSyn(const spdy::SpdySynStreamControlFrame& frame, return; } - scoped_refptr<SpdyStream> stream = - new SpdyStream(this, stream_id, true, net_log_); + scoped_refptr<SpdyStream> stream( + new SpdyStream(this, stream_id, true, net_log_)); stream->set_path(path); @@ -1094,9 +1107,9 @@ void SpdySession::OnSynReply(const spdy::SpdySynReplyControlFrame& frame, if (net_log().IsLoggingAllEvents()) { net_log().AddEvent( NetLog::TYPE_SPDY_SESSION_SYN_REPLY, - new NetLogSpdySynParameter( + make_scoped_refptr(new NetLogSpdySynParameter( headers, static_cast<spdy::SpdyControlFlags>(frame.flags()), - stream_id)); + stream_id))); } Respond(*headers, stream); @@ -1157,7 +1170,8 @@ void SpdySession::OnRst(const spdy::SpdyRstStreamControlFrame& frame) { net_log().AddEvent( NetLog::TYPE_SPDY_SESSION_RST_STREAM, - new NetLogSpdyRstParameter(stream_id, frame.status())); + make_scoped_refptr( + new NetLogSpdyRstParameter(stream_id, frame.status()))); bool valid_stream = IsStreamActive(stream_id); if (!valid_stream) { @@ -1182,9 +1196,10 @@ void SpdySession::OnRst(const spdy::SpdyRstStreamControlFrame& frame) { void SpdySession::OnGoAway(const spdy::SpdyGoAwayControlFrame& frame) { net_log_.AddEvent( NetLog::TYPE_SPDY_SESSION_GOAWAY, - new NetLogSpdyGoAwayParameter(frame.last_accepted_stream_id(), - active_streams_.size(), - unclaimed_pushed_streams_.size())); + make_scoped_refptr( + new NetLogSpdyGoAwayParameter(frame.last_accepted_stream_id(), + active_streams_.size(), + unclaimed_pushed_streams_.size()))); RemoveFromPool(); CloseAllStreams(net::ERR_ABORTED); @@ -1207,7 +1222,7 @@ void SpdySession::OnSettings(const spdy::SpdySettingsControlFrame& frame) { net_log_.AddEvent( NetLog::TYPE_SPDY_SESSION_RECV_SETTINGS, - new NetLogSpdySettingsParameter(settings)); + make_scoped_refptr(new NetLogSpdySettingsParameter(settings))); } void SpdySession::OnWindowUpdate( @@ -1235,9 +1250,8 @@ void SpdySession::OnWindowUpdate( net_log_.AddEvent( NetLog::TYPE_SPDY_SESSION_SEND_WINDOW_UPDATE, - new NetLogSpdyWindowUpdateParameter(stream_id, - delta_window_size, - stream->send_window_size())); + make_scoped_refptr(new NetLogSpdyWindowUpdateParameter( + stream_id, delta_window_size, stream->send_window_size()))); } void SpdySession::SendWindowUpdate(spdy::SpdyStreamId stream_id, @@ -1248,9 +1262,8 @@ void SpdySession::SendWindowUpdate(spdy::SpdyStreamId stream_id, net_log_.AddEvent( NetLog::TYPE_SPDY_SESSION_RECV_WINDOW_UPDATE, - new NetLogSpdyWindowUpdateParameter(stream_id, - delta_window_size, - stream->recv_window_size())); + make_scoped_refptr(new NetLogSpdyWindowUpdateParameter( + stream_id, delta_window_size, stream->recv_window_size()))); scoped_ptr<spdy::SpdyWindowUpdateControlFrame> window_update_frame( spdy_framer_.CreateWindowUpdate(stream_id, delta_window_size)); @@ -1265,7 +1278,7 @@ void SpdySession::SendSettings() { net_log_.AddEvent( NetLog::TYPE_SPDY_SESSION_SEND_SETTINGS, - new NetLogSpdySettingsParameter(settings)); + make_scoped_refptr(new NetLogSpdySettingsParameter(settings))); // Create the SETTINGS frame and send it. scoped_ptr<spdy::SpdySettingsControlFrame> settings_frame( @@ -1281,7 +1294,8 @@ void SpdySession::HandleSettings(const spdy::SpdySettings& settings) { const uint32 val = i->second; switch (id) { case spdy::SETTINGS_MAX_CONCURRENT_STREAMS: - max_concurrent_streams_ = val; + max_concurrent_streams_ = std::min(static_cast<size_t>(val), + max_concurrent_stream_limit_); ProcessPendingCreateStreams(); break; } diff --git a/net/spdy/spdy_session.h b/net/spdy/spdy_session.h index f90907d..7d12d50 100644 --- a/net/spdy/spdy_session.h +++ b/net/spdy/spdy_session.h @@ -140,6 +140,14 @@ class SpdySession : public base::RefCounted<SpdySession>, static void set_flow_control(bool enable) { use_flow_control_ = enable; } static bool flow_control() { return use_flow_control_; } + // Sets the max concurrent streams per session. + static void set_max_concurrent_streams(size_t value) { + max_concurrent_stream_limit_ = value; + } + static size_t max_concurrent_streams() { + return max_concurrent_stream_limit_; + } + // Send WINDOW_UPDATE frame, called by a stream whenever receive window // size is increased. void SendWindowUpdate(spdy::SpdyStreamId stream_id, int delta_window_size); @@ -199,7 +207,7 @@ class SpdySession : public base::RefCounted<SpdySession>, CLOSED }; - enum { kDefaultMaxConcurrentStreams = 100 }; // TODO(mbelshe) remove this + enum { kDefaultMaxConcurrentStreams = 6 }; // TODO(mbelshe) remove this struct PendingCreateStream { const GURL* url; @@ -400,6 +408,7 @@ class SpdySession : public base::RefCounted<SpdySession>, static bool use_ssl_; static bool use_flow_control_; + static size_t max_concurrent_stream_limit_; }; } // namespace net diff --git a/net/spdy/spdy_session_pool.cc b/net/spdy/spdy_session_pool.cc index fe2a310..aa807af 100644 --- a/net/spdy/spdy_session_pool.cc +++ b/net/spdy/spdy_session_pool.cc @@ -41,9 +41,10 @@ scoped_refptr<SpdySession> SpdySessionPool::Get( if (list->size() >= static_cast<unsigned int>(g_max_sessions_per_domain)) { spdy_session = list->front(); list->pop_front(); - net_log.AddEvent(NetLog::TYPE_SPDY_SESSION_POOL_FOUND_EXISTING_SESSION, - new NetLogSourceParameter("session", - spdy_session->net_log().source())); + net_log.AddEvent( + NetLog::TYPE_SPDY_SESSION_POOL_FOUND_EXISTING_SESSION, + make_scoped_refptr(new NetLogSourceParameter( + "session", spdy_session->net_log().source()))); } } else { list = AddSessionList(host_port_proxy_pair); @@ -53,9 +54,10 @@ scoped_refptr<SpdySession> SpdySessionPool::Get( if (!spdy_session) { spdy_session = new SpdySession(host_port_proxy_pair, this, spdy_settings, net_log.net_log()); - net_log.AddEvent(NetLog::TYPE_SPDY_SESSION_POOL_CREATED_NEW_SESSION, - new NetLogSourceParameter("session", - spdy_session->net_log().source())); + net_log.AddEvent( + NetLog::TYPE_SPDY_SESSION_POOL_CREATED_NEW_SESSION, + make_scoped_refptr(new NetLogSourceParameter( + "session", spdy_session->net_log().source()))); } DCHECK(spdy_session); @@ -81,9 +83,10 @@ net::Error SpdySessionPool::GetSpdySessionFromSocket( DCHECK(list->empty()); list->push_back(*spdy_session); - net_log.AddEvent(NetLog::TYPE_SPDY_SESSION_POOL_IMPORTED_SESSION_FROM_SOCKET, - new NetLogSourceParameter("session", - (*spdy_session)->net_log().source())); + net_log.AddEvent( + NetLog::TYPE_SPDY_SESSION_POOL_IMPORTED_SESSION_FROM_SOCKET, + make_scoped_refptr(new NetLogSourceParameter( + "session", (*spdy_session)->net_log().source()))); // Now we can initialize the session with the SSL socket. return (*spdy_session)->InitializeWithSocket(connection, is_secure, @@ -103,9 +106,10 @@ void SpdySessionPool::Remove(const scoped_refptr<SpdySession>& session) { if (!list) return; list->remove(session); - session->net_log().AddEvent(NetLog::TYPE_SPDY_SESSION_POOL_REMOVE_SESSION, - new NetLogSourceParameter("session", - session->net_log().source())); + session->net_log().AddEvent( + NetLog::TYPE_SPDY_SESSION_POOL_REMOVE_SESSION, + make_scoped_refptr(new NetLogSourceParameter( + "session", session->net_log().source()))); if (list->empty()) RemoveSessionList(session->host_port_proxy_pair()); } diff --git a/net/spdy/spdy_session_unittest.cc b/net/spdy/spdy_session_unittest.cc index 4a66406..0cfbe48 100644 --- a/net/spdy/spdy_session_unittest.cc +++ b/net/spdy/spdy_session_unittest.cc @@ -91,8 +91,8 @@ TEST_F(SpdySessionTest, GoAway) { BoundNetLog()); EXPECT_TRUE(spdy_session_pool->HasSession(pair)); - scoped_refptr<TCPSocketParams> tcp_params = - new TCPSocketParams(kTestHost, kTestPort, MEDIUM, GURL(), false); + scoped_refptr<TCPSocketParams> tcp_params( + new TCPSocketParams(kTestHost, kTestPort, MEDIUM, GURL(), false)); scoped_ptr<ClientSocketHandle> connection(new ClientSocketHandle); EXPECT_EQ(OK, connection->Init(test_host_port_pair.ToString(), tcp_params, MEDIUM, @@ -200,8 +200,8 @@ TEST_F(SpdySessionTest, OnSettings) { BoundNetLog()); ASSERT_TRUE(spdy_session_pool->HasSession(pair)); - scoped_refptr<TCPSocketParams> tcp_params = - new TCPSocketParams(kTestHost, kTestPort, MEDIUM, GURL(), false); + scoped_refptr<TCPSocketParams> tcp_params( + new TCPSocketParams(kTestHost, kTestPort, MEDIUM, GURL(), false)); scoped_ptr<ClientSocketHandle> connection(new ClientSocketHandle); EXPECT_EQ(OK, connection->Init(test_host_port_pair.ToString(), tcp_params, MEDIUM, diff --git a/net/spdy/spdy_stream.cc b/net/spdy/spdy_stream.cc index 102d318..f26dd6d 100644 --- a/net/spdy/spdy_stream.cc +++ b/net/spdy/spdy_stream.cc @@ -60,8 +60,9 @@ SpdyStream::SpdyStream(SpdySession* session, net_log_(net_log), send_bytes_(0), recv_bytes_(0) { - net_log_.BeginEvent(NetLog::TYPE_SPDY_STREAM, - new NetLogIntegerParameter("stream_id", stream_id_)); + net_log_.BeginEvent( + NetLog::TYPE_SPDY_STREAM, + make_scoped_refptr(new NetLogIntegerParameter("stream_id", stream_id_))); } SpdyStream::~SpdyStream() { @@ -148,9 +149,10 @@ void SpdyStream::IncreaseSendWindowSize(int delta_window_size) { send_window_size_ = new_window_size; - net_log_.AddEvent(NetLog::TYPE_SPDY_STREAM_SEND_WINDOW_UPDATE, - new NetLogSpdyStreamWindowUpdateParameter(stream_id_, - delta_window_size, send_window_size_)); + net_log_.AddEvent( + NetLog::TYPE_SPDY_STREAM_SEND_WINDOW_UPDATE, + make_scoped_refptr(new NetLogSpdyStreamWindowUpdateParameter( + stream_id_, delta_window_size, send_window_size_))); if (stalled_by_flow_control_) { stalled_by_flow_control_ = false; io_state_ = STATE_SEND_BODY; @@ -170,9 +172,10 @@ void SpdyStream::DecreaseSendWindowSize(int delta_window_size) { send_window_size_ -= delta_window_size; - net_log_.AddEvent(NetLog::TYPE_SPDY_STREAM_SEND_WINDOW_UPDATE, - new NetLogSpdyStreamWindowUpdateParameter(stream_id_, - -delta_window_size, send_window_size_)); + net_log_.AddEvent( + NetLog::TYPE_SPDY_STREAM_SEND_WINDOW_UPDATE, + make_scoped_refptr(new NetLogSpdyStreamWindowUpdateParameter( + stream_id_, -delta_window_size, send_window_size_))); } void SpdyStream::IncreaseRecvWindowSize(int delta_window_size) { @@ -185,9 +188,10 @@ void SpdyStream::IncreaseRecvWindowSize(int delta_window_size) { DCHECK(new_window_size > 0); recv_window_size_ = new_window_size; - net_log_.AddEvent(NetLog::TYPE_SPDY_STREAM_RECV_WINDOW_UPDATE, - new NetLogSpdyStreamWindowUpdateParameter(stream_id_, - delta_window_size, recv_window_size_)); + net_log_.AddEvent( + NetLog::TYPE_SPDY_STREAM_RECV_WINDOW_UPDATE, + make_scoped_refptr(new NetLogSpdyStreamWindowUpdateParameter( + stream_id_, delta_window_size, recv_window_size_))); session_->SendWindowUpdate(stream_id_, delta_window_size); } @@ -195,9 +199,10 @@ void SpdyStream::DecreaseRecvWindowSize(int delta_window_size) { DCHECK_GE(delta_window_size, 1); recv_window_size_ -= delta_window_size; - net_log_.AddEvent(NetLog::TYPE_SPDY_STREAM_RECV_WINDOW_UPDATE, - new NetLogSpdyStreamWindowUpdateParameter(stream_id_, - -delta_window_size, recv_window_size_)); + net_log_.AddEvent( + NetLog::TYPE_SPDY_STREAM_RECV_WINDOW_UPDATE, + make_scoped_refptr(new NetLogSpdyStreamWindowUpdateParameter( + stream_id_, -delta_window_size, recv_window_size_))); // Since we never decrease the initial window size, we should never hit // a negative |recv_window_size_|, if we do, it's a flow-control violation. @@ -257,7 +262,7 @@ void SpdyStream::OnDataReceived(const char* data, int length) { if (length > 0) { IOBufferWithSize* buf = new IOBufferWithSize(length); memcpy(buf->data(), data, length); - pending_buffers_.push_back(buf); + pending_buffers_.push_back(make_scoped_refptr(buf)); } else { pending_buffers_.push_back(NULL); metrics_.StopStream(); @@ -298,7 +303,7 @@ void SpdyStream::OnDataReceived(const char* data, int length) { // We'll return received data when delegate gets attached to the stream. IOBufferWithSize* buf = new IOBufferWithSize(length); memcpy(buf->data(), data, length); - pending_buffers_.push_back(buf); + pending_buffers_.push_back(make_scoped_refptr(buf)); return; } diff --git a/net/spdy/spdy_stream_unittest.cc b/net/spdy/spdy_stream_unittest.cc index 5ece945..cdb116f 100644 --- a/net/spdy/spdy_stream_unittest.cc +++ b/net/spdy/spdy_stream_unittest.cc @@ -192,8 +192,8 @@ TEST_F(SpdyStreamTest, SendDataAfterOpen) { GURL url("http://www.google.com/"); HostPortPair host_port_pair("www.google.com", 80); - scoped_refptr<TCPSocketParams> tcp_params = - new TCPSocketParams(host_port_pair, LOWEST, GURL(), false); + scoped_refptr<TCPSocketParams> tcp_params( + new TCPSocketParams(host_port_pair, LOWEST, GURL(), false)); scoped_ptr<ClientSocketHandle> connection(new ClientSocketHandle); EXPECT_EQ(OK, diff --git a/net/spdy/spdy_test_util.cc b/net/spdy/spdy_test_util.cc index d3b82c0..896cd9d 100644 --- a/net/spdy/spdy_test_util.cc +++ b/net/spdy/spdy_test_util.cc @@ -519,23 +519,23 @@ spdy::SpdyFrame* ConstructSpdyPush(const char* const extra_headers[], associated_stream_id); } -// Constructs a standard SPDY SYN_REPLY packet to match the SPDY GET. -// |extra_headers| are the extra header-value pairs, which typically -// will vary the most between calls. +// Constructs a standard SPDY SYN_REPLY packet with the specified status code. // Returns a SpdyFrame. -spdy::SpdyFrame* ConstructSpdyGetSynReplyRedirect(int stream_id) { - static const char* const kStandardGetHeaders[] = { +spdy::SpdyFrame* ConstructSpdySynReplyError( + const char* const status, + const char* const* const extra_headers, + int extra_header_count, + int stream_id) { + const char* const kStandardGetHeaders[] = { "hello", "bye", "status", - "301 Moved Permanently", - "location", - "http://www.foo.com/index.php", + status, "version", "HTTP/1.1" }; - return ConstructSpdyControlFrame(NULL, - 0, + return ConstructSpdyControlFrame(extra_headers, + extra_header_count, false, stream_id, LOWEST, @@ -545,35 +545,28 @@ spdy::SpdyFrame* ConstructSpdyGetSynReplyRedirect(int stream_id) { arraysize(kStandardGetHeaders)); } +// Constructs a standard SPDY SYN_REPLY packet to match the SPDY GET. +// |extra_headers| are the extra header-value pairs, which typically +// will vary the most between calls. +// Returns a SpdyFrame. +spdy::SpdyFrame* ConstructSpdyGetSynReplyRedirect(int stream_id) { + static const char* const kExtraHeaders[] = { + "location", + "http://www.foo.com/index.php", + }; + return ConstructSpdySynReplyError("301 Moved Permanently", kExtraHeaders, + arraysize(kExtraHeaders)/2, stream_id); +} + // Constructs a standard SPDY SYN_REPLY packet with an Internal Server // Error status code. // Returns a SpdyFrame. spdy::SpdyFrame* ConstructSpdySynReplyError(int stream_id) { - return ConstructSpdySynReplyError("500 Internal Server Error", 1); + return ConstructSpdySynReplyError("500 Internal Server Error", NULL, 0, 1); } -// Constructs a standard SPDY SYN_REPLY packet with the specified status code. -// Returns a SpdyFrame. -spdy::SpdyFrame* ConstructSpdySynReplyError(const char* const status, - int stream_id) { - static const char* const kStandardGetHeaders[] = { - "hello", - "bye", - "status", - status, - "version", - "HTTP/1.1" - }; - return ConstructSpdyControlFrame(NULL, - 0, - false, - stream_id, - LOWEST, - spdy::SYN_REPLY, - spdy::CONTROL_FLAG_NONE, - kStandardGetHeaders, - arraysize(kStandardGetHeaders)); -} + + // Constructs a standard SPDY SYN_REPLY packet to match the SPDY GET. // |extra_headers| are the extra header-value pairs, which typically diff --git a/net/spdy/spdy_test_util.h b/net/spdy/spdy_test_util.h index e3e85c8..aecf08e 100644 --- a/net/spdy/spdy_test_util.h +++ b/net/spdy/spdy_test_util.h @@ -260,8 +260,12 @@ spdy::SpdyFrame* ConstructSpdySynReplyError(int stream_id); // Constructs a standard SPDY SYN_REPLY packet with the specified status code. // Returns a SpdyFrame. -spdy::SpdyFrame* ConstructSpdySynReplyError(const char* const status, - int stream_id); +spdy::SpdyFrame* ConstructSpdySynReplyError( + const char* const status, + const char* const* const extra_headers, + int extra_header_count, + int stream_id); + // Constructs a standard SPDY POST SYN packet. // |extra_headers| are the extra header-value pairs, which typically // will vary the most between calls. diff --git a/net/test/test_server.cc b/net/test/test_server.cc index c3359a4..4b426eb 100644 --- a/net/test/test_server.cc +++ b/net/test/test_server.cc @@ -15,8 +15,8 @@ #endif #include "base/command_line.h" +#include "base/debug/leak_annotations.h" #include "base/file_util.h" -#include "base/leak_annotations.h" #include "base/logging.h" #include "base/path_service.h" #include "base/string_number_conversions.h" @@ -30,6 +30,8 @@ #include "net/test/python_utils.h" #include "testing/platform_test.h" +namespace net { + namespace { // Number of connection attempts for tests. @@ -40,30 +42,43 @@ const int kServerConnectionTimeoutMs = 1000; const char kTestServerShardFlag[] = "test-server-shard"; -int GetPortBase(net::TestServer::Type type) { - switch (type) { - case net::TestServer::TYPE_FTP: - return 3117; - case net::TestServer::TYPE_HTTP: - return 1337; - case net::TestServer::TYPE_HTTPS: +int GetHTTPSPortBase(const TestServer::HTTPSOptions& options) { + if (options.request_client_certificate) + return 9543; + + switch (options.server_certificate) { + case TestServer::HTTPSOptions::CERT_OK: return 9443; - case net::TestServer::TYPE_HTTPS_CLIENT_AUTH: - return 9543; - case net::TestServer::TYPE_HTTPS_EXPIRED_CERTIFICATE: + case TestServer::HTTPSOptions::CERT_MISMATCHED_NAME: + return 9643; + case TestServer::HTTPSOptions::CERT_EXPIRED: // TODO(phajdan.jr): Some tests rely on this hardcoded value. // Some uses of this are actually in .html/.js files. return 9666; - case net::TestServer::TYPE_HTTPS_MISMATCHED_HOSTNAME: - return 9643; default: NOTREACHED(); } return -1; } -int GetPort(net::TestServer::Type type) { - int port = GetPortBase(type); +int GetPortBase(TestServer::Type type, + const TestServer::HTTPSOptions& options) { + switch (type) { + case TestServer::TYPE_FTP: + return 3117; + case TestServer::TYPE_HTTP: + return 1337; + case TestServer::TYPE_HTTPS: + return GetHTTPSPortBase(options); + default: + NOTREACHED(); + } + return -1; +} + +int GetPort(TestServer::Type type, + const TestServer::HTTPSOptions& options) { + int port = GetPortBase(type, options); if (CommandLine::ForCurrentProcess()->HasSwitch(kTestServerShardFlag)) { std::string shard_str(CommandLine::ForCurrentProcess()->GetSwitchValueASCII( kTestServerShardFlag)); @@ -78,8 +93,11 @@ int GetPort(net::TestServer::Type type) { return port; } -std::string GetHostname(net::TestServer::Type type) { - if (type == net::TestServer::TYPE_HTTPS_MISMATCHED_HOSTNAME) { +std::string GetHostname(TestServer::Type type, + const TestServer::HTTPSOptions& options) { + if (type == TestServer::TYPE_HTTPS && + options.server_certificate == + TestServer::HTTPSOptions::CERT_MISMATCHED_NAME) { // Return a different hostname string that resolves to the same hostname. return "localhost"; } @@ -89,16 +107,59 @@ std::string GetHostname(net::TestServer::Type type) { } // namespace -namespace net { - #if defined(OS_MACOSX) void SetMacTestCertificate(X509Certificate* cert); #endif +TestServer::HTTPSOptions::HTTPSOptions() + : server_certificate(CERT_OK), + request_client_certificate(false), + bulk_ciphers(HTTPSOptions::BULK_CIPHER_ANY) {} + +TestServer::HTTPSOptions::HTTPSOptions( + TestServer::HTTPSOptions::ServerCertificate cert) + : server_certificate(cert), + request_client_certificate(false), + bulk_ciphers(HTTPSOptions::BULK_CIPHER_ANY) {} + +TestServer::HTTPSOptions::~HTTPSOptions() {} + +FilePath TestServer::HTTPSOptions::GetCertificateFile() const { + switch (server_certificate) { + case CERT_OK: + case CERT_MISMATCHED_NAME: + return FilePath(FILE_PATH_LITERAL("ok_cert.pem")); + case CERT_EXPIRED: + return FilePath(FILE_PATH_LITERAL("expired_cert.pem")); + default: + NOTREACHED(); + } + return FilePath(); +} + TestServer::TestServer(Type type, const FilePath& document_root) - : host_port_pair_(GetHostname(type), GetPort(type)), - process_handle_(base::kNullProcessHandle), - type_(type) { + : type_(type) { + Init(document_root); +} + +TestServer::TestServer(const HTTPSOptions& https_options, + const FilePath& document_root) + : https_options_(https_options), type_(TYPE_HTTPS) { + Init(document_root); +} + +TestServer::~TestServer() { +#if defined(OS_MACOSX) + SetMacTestCertificate(NULL); +#endif + Stop(); +} + +void TestServer::Init(const FilePath& document_root) { + host_port_pair_ = HostPortPair(GetHostname(type_, https_options_), + GetPort(type_, https_options_)); + process_handle_ = base::kNullProcessHandle; + FilePath src_dir; PathService::Get(base::DIR_SOURCE_ROOT, &src_dir); @@ -110,15 +171,8 @@ TestServer::TestServer(Type type, const FilePath& document_root) .Append(FILE_PATH_LITERAL("certificates")); } -TestServer::~TestServer() { -#if defined(OS_MACOSX) - SetMacTestCertificate(NULL); -#endif - Stop(); -} - bool TestServer::Start() { - if (GetScheme() == "https") { + if (type_ == TYPE_HTTPS) { if (!LoadTestRootCert()) return false; if (!CheckCATrusted()) @@ -177,9 +231,6 @@ std::string TestServer::GetScheme() const { case TYPE_HTTP: return "http"; case TYPE_HTTPS: - case TYPE_HTTPS_CLIENT_AUTH: - case TYPE_HTTPS_MISMATCHED_HOSTNAME: - case TYPE_HTTPS_EXPIRED_CERTIFICATE: return "https"; default: NOTREACHED(); @@ -191,7 +242,7 @@ bool TestServer::GetAddressList(AddressList* address_list) const { DCHECK(address_list); scoped_ptr<HostResolver> resolver( - CreateSystemHostResolver(HostResolver::kDefaultParallelism, NULL)); + CreateSystemHostResolver(HostResolver::kDefaultParallelism, NULL, NULL)); HostResolver::RequestInfo info(host_port_pair_); int rv = resolver->Resolve(info, address_list, NULL, NULL, BoundNetLog()); if (rv != net::OK) { @@ -292,21 +343,51 @@ bool TestServer::LoadTestRootCert() { #endif } -FilePath TestServer::GetCertificatePath() { - switch (type_) { - case TYPE_FTP: - case TYPE_HTTP: - return FilePath(); - case TYPE_HTTPS: - case TYPE_HTTPS_CLIENT_AUTH: - case TYPE_HTTPS_MISMATCHED_HOSTNAME: - return certificates_dir_.AppendASCII("ok_cert.pem"); - case TYPE_HTTPS_EXPIRED_CERTIFICATE: - return certificates_dir_.AppendASCII("expired_cert.pem"); - default: - NOTREACHED(); +bool TestServer::AddCommandLineArguments(CommandLine* command_line) const { + command_line->AppendSwitchASCII("port", + base::IntToString(host_port_pair_.port())); + command_line->AppendSwitchPath("data-dir", document_root_); + + if (type_ == TYPE_FTP) { + command_line->AppendArg("-f"); + } else if (type_ == TYPE_HTTPS) { + FilePath certificate_path(certificates_dir_); + certificate_path = certificate_path.Append( + https_options_.GetCertificateFile()); + if (!file_util::PathExists(certificate_path)) { + LOG(ERROR) << "Certificate path " << certificate_path.value() + << " doesn't exist. Can't launch https server."; + return false; + } + command_line->AppendSwitchPath("https", certificate_path); + + if (https_options_.request_client_certificate) + command_line->AppendSwitch("ssl-client-auth"); + + for (std::vector<FilePath>::const_iterator it = + https_options_.client_authorities.begin(); + it != https_options_.client_authorities.end(); ++it) { + if (!file_util::PathExists(*it)) { + LOG(ERROR) << "Client authority path " << it->value() + << " doesn't exist. Can't launch https server."; + return false; + } + + command_line->AppendSwitchPath("ssl-client-ca", *it); + } + + const char kBulkCipherSwitch[] = "ssl-bulk-cipher"; + if (https_options_.bulk_ciphers & HTTPSOptions::BULK_CIPHER_RC4) + command_line->AppendSwitchASCII(kBulkCipherSwitch, "rc4"); + if (https_options_.bulk_ciphers & HTTPSOptions::BULK_CIPHER_AES128) + command_line->AppendSwitchASCII(kBulkCipherSwitch, "aes128"); + if (https_options_.bulk_ciphers & HTTPSOptions::BULK_CIPHER_AES256) + command_line->AppendSwitchASCII(kBulkCipherSwitch, "aes256"); + if (https_options_.bulk_ciphers & HTTPSOptions::BULK_CIPHER_3DES) + command_line->AppendSwitchASCII(kBulkCipherSwitch, "3des"); } - return FilePath(); + + return true; } } // namespace net diff --git a/net/test/test_server.h b/net/test/test_server.h index 4e68fd9..8affc12 100644 --- a/net/test/test_server.h +++ b/net/test/test_server.h @@ -6,9 +6,10 @@ #define NET_TEST_TEST_SERVER_H_ #pragma once -#include "build/build_config.h" - #include <string> +#include <vector> + +#include "build/build_config.h" #include "base/compiler_specific.h" #include "base/file_path.h" @@ -25,6 +26,7 @@ #include "net/base/x509_certificate.h" #endif +class CommandLine; class GURL; namespace net { @@ -39,12 +41,70 @@ class TestServer { TYPE_FTP, TYPE_HTTP, TYPE_HTTPS, - TYPE_HTTPS_CLIENT_AUTH, - TYPE_HTTPS_MISMATCHED_HOSTNAME, - TYPE_HTTPS_EXPIRED_CERTIFICATE, + }; + + // Container for various options to control how the HTTPS server is + // initialized. + struct HTTPSOptions { + enum ServerCertificate { + CERT_OK, + CERT_MISMATCHED_NAME, + CERT_EXPIRED, + }; + + // Bitmask of bulk encryption algorithms that the test server supports + // and that can be selectively enabled or disabled. + enum BulkCipher { + // Special value used to indicate that any algorithm the server supports + // is acceptable. Preferred over explicitly OR-ing all ciphers. + BULK_CIPHER_ANY = 0, + + BULK_CIPHER_RC4 = (1 << 0), + BULK_CIPHER_AES128 = (1 << 1), + BULK_CIPHER_AES256 = (1 << 2), + + // NOTE: 3DES support in the Python test server has external + // dependencies and not be available on all machines. Clients may not + // be able to connect if only 3DES is specified. + BULK_CIPHER_3DES = (1 << 3), + }; + + // Initialize a new HTTPSOptions using CERT_OK as the certificate. + HTTPSOptions(); + + // Initialize a new HTTPSOptions that will use the specified certificate. + explicit HTTPSOptions(ServerCertificate cert); + ~HTTPSOptions(); + + // Returns the relative filename of the file that contains the + // |server_certificate|. + FilePath GetCertificateFile() const; + + // The certificate to use when serving requests. + ServerCertificate server_certificate; + + // True if a CertificateRequest should be sent to the client during + // handshaking. + bool request_client_certificate; + + // If |request_client_certificate| is true, an optional list of files, + // each containing a single, PEM-encoded X.509 certificates. The subject + // from each certificate will be added to the certificate_authorities + // field of the CertificateRequest. + std::vector<FilePath> client_authorities; + + // A bitwise-OR of BulkCipher that should be used by the + // HTTPS server, or BULK_CIPHER_ANY to indicate that all implemented + // ciphers are acceptable. + int bulk_ciphers; }; TestServer(Type type, const FilePath& document_root); + + // Initialize a HTTPS TestServer with a specific set of HTTPSOptions. + TestServer(const HTTPSOptions& https_options, + const FilePath& document_root); + ~TestServer(); bool Start() WARN_UNUSED_RESULT; @@ -67,6 +127,8 @@ class TestServer { const std::string& password); private: + void Init(const FilePath& document_root); + // Modify PYTHONPATH to contain libraries we need. bool SetPythonPath() WARN_UNUSED_RESULT; @@ -85,9 +147,9 @@ class TestServer { // Load the test root cert, if it hasn't been loaded yet. bool LoadTestRootCert() WARN_UNUSED_RESULT; - // Returns path to the SSL certificate we should use, or empty path - // if not applicable. - FilePath GetCertificatePath(); + // Add the command line arguments for the Python test server to + // |command_line|. Return true on success. + bool AddCommandLineArguments(CommandLine* command_line) const; // Document root of the test server. FilePath document_root_; @@ -105,8 +167,11 @@ class TestServer { // JobObject used to clean up orphaned child processes. ScopedHandle job_handle_; - // The file handle the child writes to when it starts. - ScopedHandle child_fd_; + // The pipe file handle we read from. + ScopedHandle child_read_fd_; + + // The pipe file handle the child and we write to. + ScopedHandle child_write_fd_; #endif #if defined(OS_POSIX) @@ -115,6 +180,9 @@ class TestServer { file_util::ScopedFD child_fd_closer_; #endif + // If |type_| is TYPE_HTTPS, the TLS settings to use for the test server. + HTTPSOptions https_options_; + #if defined(USE_NSS) scoped_refptr<X509Certificate> cert_; #endif diff --git a/net/test/test_server_posix.cc b/net/test/test_server_posix.cc index 6e65bcf..707eb93 100644 --- a/net/test/test_server_posix.cc +++ b/net/test/test_server_posix.cc @@ -4,13 +4,17 @@ #include "net/test/test_server.h" +#include <poll.h> + #include <vector> +#include "base/command_line.h" #include "base/file_util.h" #include "base/logging.h" #include "base/process_util.h" #include "base/string_number_conversions.h" #include "base/string_util.h" +#include "base/test/test_timeouts.h" namespace { @@ -52,28 +56,12 @@ class OrphanedTestServerFilter : public base::ProcessFilter { } // namespace namespace net { -bool TestServer::LaunchPython(const FilePath& testserver_path) { - std::vector<std::string> command_line; - command_line.push_back("python"); - command_line.push_back(testserver_path.value()); - command_line.push_back("--port=" + base::IntToString(host_port_pair_.port())); - command_line.push_back("--data-dir=" + document_root_.value()); - - if (type_ == TYPE_FTP) - command_line.push_back("-f"); - - FilePath certificate_path(GetCertificatePath()); - if (!certificate_path.value().empty()) { - if (!file_util::PathExists(certificate_path)) { - LOG(ERROR) << "Certificate path " << certificate_path.value() - << " doesn't exist. Can't launch https server."; - return false; - } - command_line.push_back("--https=" + certificate_path.value()); - } - if (type_ == TYPE_HTTPS_CLIENT_AUTH) - command_line.push_back("--ssl-client-auth"); +bool TestServer::LaunchPython(const FilePath& testserver_path) { + CommandLine python_command(FilePath(FILE_PATH_LITERAL("python"))); + python_command.AppendArgPath(testserver_path); + if (!AddCommandLineArguments(&python_command)) + return false; int pipefd[2]; if (pipe(pipefd) != 0) { @@ -88,7 +76,8 @@ bool TestServer::LaunchPython(const FilePath& testserver_path) { base::file_handle_mapping_vector map_write_fd; map_write_fd.push_back(std::make_pair(pipefd[1], pipefd[1])); - command_line.push_back("--startup-pipe=" + base::IntToString(pipefd[1])); + python_command.AppendSwitchASCII("startup-pipe", + base::IntToString(pipefd[1])); // Try to kill any orphaned testserver processes that may be running. OrphanedTestServerFilter filter(testserver_path.value(), @@ -98,8 +87,10 @@ bool TestServer::LaunchPython(const FilePath& testserver_path) { } // Launch a new testserver process. - if (!base::LaunchApp(command_line, map_write_fd, false, &process_handle_)) { - LOG(ERROR) << "Failed to launch " << command_line[0] << " ..."; + if (!base::LaunchApp(python_command.argv(), map_write_fd, false, + &process_handle_)) { + LOG(ERROR) << "Failed to launch " << python_command.command_line_string() + << " ..."; return false; } @@ -107,6 +98,19 @@ bool TestServer::LaunchPython(const FilePath& testserver_path) { } bool TestServer::WaitToStart() { + struct pollfd poll_fds[1]; + + poll_fds[0].fd = child_fd_; + poll_fds[0].events = POLLIN | POLLPRI; + poll_fds[0].revents = 0; + + int rv = HANDLE_EINTR(poll(poll_fds, 1, + TestTimeouts::action_max_timeout_ms())); + if (rv != 1) { + LOG(ERROR) << "Failed to poll for the child file descriptor."; + return false; + } + char buf[8]; ssize_t n = HANDLE_EINTR(read(child_fd_, buf, sizeof(buf))); // We don't need the FD anymore. diff --git a/net/test/test_server_win.cc b/net/test/test_server_win.cc index a8b3678..c6e10d5 100644 --- a/net/test/test_server_win.cc +++ b/net/test/test_server_win.cc @@ -8,17 +8,21 @@ #include <wincrypt.h> #include "base/base_paths.h" +#include "base/command_line.h" #include "base/file_util.h" +#include "base/message_loop.h" #include "base/path_service.h" #include "base/string_number_conversions.h" #include "base/string_util.h" +#include "base/test/test_timeouts.h" +#include "base/thread.h" #include "base/utf_string_conversions.h" #pragma comment(lib, "crypt32.lib") namespace { -bool LaunchTestServerAsJob(const std::wstring& cmdline, +bool LaunchTestServerAsJob(const CommandLine& cmdline, bool start_hidden, base::ProcessHandle* process_handle, ScopedHandle* job_handle) { @@ -32,10 +36,10 @@ bool LaunchTestServerAsJob(const std::wstring& cmdline, // If this code is run under a debugger, the test server process is // automatically associated with a job object created by the debugger. // The CREATE_BREAKAWAY_FROM_JOB flag is used to prevent this. - if (!CreateProcess(NULL, - const_cast<wchar_t*>(cmdline.c_str()), NULL, NULL, - TRUE, CREATE_BREAKAWAY_FROM_JOB, NULL, NULL, - &startup_info, &process_info)) { + if (!CreateProcess( + NULL, const_cast<wchar_t*>(cmdline.command_line_string().c_str()), + NULL, NULL, TRUE, CREATE_BREAKAWAY_FROM_JOB, NULL, NULL, + &startup_info, &process_info)) { LOG(ERROR) << "Could not create process."; return false; } @@ -71,9 +75,21 @@ bool LaunchTestServerAsJob(const std::wstring& cmdline, return true; } +void UnblockPipe(HANDLE handle, bool* unblocked) { + static const char kUnblock[] = "UNBLOCK"; + // Unblock the ReadFile in TestServer::WaitToStart by writing to the pipe. + // Make sure the call succeeded, otherwise we are very likely to hang. + DWORD bytes_written = 0; + CHECK(WriteFile(handle, kUnblock, arraysize(kUnblock), &bytes_written, + NULL)); + CHECK_EQ(arraysize(kUnblock), bytes_written); + *unblocked = true; +} + } // namespace namespace net { + bool TestServer::LaunchPython(const FilePath& testserver_path) { FilePath python_exe; if (!PathService::Get(base::DIR_SOURCE_ROOT, &python_exe)) @@ -83,29 +99,10 @@ bool TestServer::LaunchPython(const FilePath& testserver_path) { .Append(FILE_PATH_LITERAL("python_24")) .Append(FILE_PATH_LITERAL("python.exe")); - std::wstring command_line = - L"\"" + python_exe.value() + L"\" " + - L"\"" + testserver_path.value() + - L"\" --port=" + ASCIIToWide(base::IntToString(host_port_pair_.port())) + - L" --data-dir=\"" + document_root_.value() + L"\""; - - if (type_ == TYPE_FTP) - command_line.append(L" -f"); - - FilePath certificate_path(GetCertificatePath()); - if (!certificate_path.value().empty()) { - if (!file_util::PathExists(certificate_path)) { - LOG(ERROR) << "Certificate path " << certificate_path.value() - << " doesn't exist. Can't launch https server."; - return false; - } - command_line.append(L" --https=\""); - command_line.append(certificate_path.value()); - command_line.append(L"\""); - } - - if (type_ == TYPE_HTTPS_CLIENT_AUTH) - command_line.append(L" --ssl-client-auth"); + CommandLine python_command(python_exe); + python_command.AppendArgPath(testserver_path); + if (!AddCommandLineArguments(&python_command)) + return false; HANDLE child_read = NULL; HANDLE child_write = NULL; @@ -113,8 +110,8 @@ bool TestServer::LaunchPython(const FilePath& testserver_path) { PLOG(ERROR) << "Failed to create pipe"; return false; } - child_fd_.Set(child_read); - ScopedHandle scoped_child_write(child_write); + child_read_fd_.Set(child_read); + child_write_fd_.Set(child_write); // Have the child inherit the write half. if (!SetHandleInformation(child_write, HANDLE_FLAG_INHERIT, @@ -133,15 +130,15 @@ bool TestServer::LaunchPython(const FilePath& testserver_path) { // safe to truncate the handle (when passing it from 64-bit to // 32-bit) or sign-extend the handle (when passing it from 32-bit to // 64-bit)." - command_line.append( - L" --startup-pipe=" + - ASCIIToWide(base::IntToString(reinterpret_cast<uintptr_t>(child_write)))); + python_command.AppendSwitchASCII( + "startup-pipe", + base::IntToString(reinterpret_cast<uintptr_t>(child_write))); - if (!LaunchTestServerAsJob(command_line, + if (!LaunchTestServerAsJob(python_command, true, &process_handle_, &job_handle_)) { - LOG(ERROR) << "Failed to launch " << command_line; + LOG(ERROR) << "Failed to launch " << python_command.command_line_string(); return false; } @@ -149,10 +146,29 @@ bool TestServer::LaunchPython(const FilePath& testserver_path) { } bool TestServer::WaitToStart() { + base::Thread thread("test_server_watcher"); + if (!thread.Start()) + return false; + + // Prepare a timeout in case the server fails to start. + bool unblocked = false; + thread.message_loop()->PostDelayedTask(FROM_HERE, + NewRunnableFunction(UnblockPipe, child_write_fd_.Get(), &unblocked), + TestTimeouts::action_max_timeout_ms()); + char buf[8]; DWORD bytes_read; - BOOL result = ReadFile(child_fd_, buf, sizeof(buf), &bytes_read, NULL); - child_fd_.Close(); + BOOL result = ReadFile(child_read_fd_.Get(), buf, sizeof(buf), &bytes_read, + NULL); + + thread.Stop(); + child_read_fd_.Close(); + child_write_fd_.Close(); + + // If we hit the timeout, fail. + if (unblocked) + return false; + return result && bytes_read > 0; } diff --git a/net/third_party/mozilla_security_manager/nsNSSCertificateDB.cpp b/net/third_party/mozilla_security_manager/nsNSSCertificateDB.cpp index f4ec31a..4b49929 100644 --- a/net/third_party/mozilla_security_manager/nsNSSCertificateDB.cpp +++ b/net/third_party/mozilla_security_manager/nsNSSCertificateDB.cpp @@ -221,15 +221,8 @@ SetCertTrust(const net::X509Certificate* cert, srv = CERT_ChangeCertTrust(CERT_GetDefaultCertDB(), nsscert, trust.GetTrust()); - } else if (type == net::EMAIL_CERT) { - // always start with untrusted and move up - trust.SetValidPeer(); - trust.AddPeerTrust(0, trusted & net::CertDatabase::TRUSTED_EMAIL, 0); - srv = CERT_ChangeCertTrust(CERT_GetDefaultCertDB(), - nsscert, - trust.GetTrust()); } else { - // ignore user certs + // ignore user and email/unknown certs return true; } if (srv != SECSuccess) diff --git a/net/third_party/nss/ssl.gyp b/net/third_party/nss/ssl.gyp index a804e92..7a0d21e 100644 --- a/net/third_party/nss/ssl.gyp +++ b/net/third_party/nss/ssl.gyp @@ -53,6 +53,7 @@ 'ssl/sslmutex.c', 'ssl/sslmutex.h', 'ssl/sslnonce.c', + 'ssl/sslplatf.c', 'ssl/sslproto.h', 'ssl/sslreveal.c', 'ssl/sslsecur.c', @@ -83,6 +84,13 @@ 'NO_NSPR_10_SUPPORT', ], 'conditions': [ + [ 'OS=="mac"', { + 'defines': [ + 'XP_UNIX', + 'DARWIN', + 'XP_MACOSX', + ], + }], [ 'OS == "win"', { 'sources!': [ 'ssl/unix_err.c', @@ -122,6 +130,9 @@ 'sources/': [ ['exclude', 'ssl/bodge/'], ], + 'defines': [ + 'NSS_PLATFORM_CLIENT_AUTH', + ], 'dependencies': [ '../../../third_party/zlib/zlib.gyp:zlib', '../../../third_party/nss/nss.gyp:nss', @@ -130,6 +141,9 @@ 'include_dirs': [ 'ssl', ], + 'defines': [ + 'NSS_PLATFORM_CLIENT_AUTH', + ], }, }], ], diff --git a/net/third_party/nss/ssl/snapstart.c b/net/third_party/nss/ssl/snapstart.c index ca2cafa..92406a7 100644 --- a/net/third_party/nss/ssl/snapstart.c +++ b/net/third_party/nss/ssl/snapstart.c @@ -48,10 +48,6 @@ /* TODO(agl): Add support for snap starting with compression. */ -/* TODO(agl): Free snapStartApplicationData as soon as the handshake has -** completed. -*/ - #include "pk11pub.h" #include "ssl.h" #include "sslimpl.h" @@ -821,6 +817,7 @@ ssl3_SendSnapStartXtn(sslSocket *ss, PRBool append, PRUint32 maxBytes) rv = ssl3_AppendSnapStartApplicationData( ss, ss->ssl3.snapStartApplicationData.data, ss->ssl3.snapStartApplicationData.len); + SECITEM_FreeItem(&ss->ssl3.snapStartApplicationData, PR_FALSE); if (rv != SECSuccess) goto loser; } @@ -1056,6 +1053,8 @@ ssl3_ResetForSnapStartRecovery(sslSocket *ss, SSL3Opaque *b, PRUint32 length) ss->ssl3.hs.snapStartType = snap_start_resume_recovery; } + ss->ssl3.nextProtoState = SSL_NEXT_PROTO_NO_SUPPORT; + ssl3_DestroyCipherSpec(ss->ssl3.pwSpec, PR_TRUE/*freeSrvName*/); return SECSuccess; diff --git a/net/third_party/nss/ssl/ssl.def b/net/third_party/nss/ssl/ssl.def index effc35d..60ebbb1 100644 --- a/net/third_party/nss/ssl/ssl.def +++ b/net/third_party/nss/ssl/ssl.def @@ -163,6 +163,7 @@ SSL_SetNextProtoNego; ;+ global: SSL_GetPredictedServerHelloData; SSL_GetSnapStartResult; +SSL_PeerCertificateChain; SSL_SetPredictedPeerCertificates; SSL_SetPredictedServerHelloData; SSL_SetSnapStartApplicationData; diff --git a/net/third_party/nss/ssl/ssl.h b/net/third_party/nss/ssl/ssl.h index 8217d2e..9d3da0c 100644 --- a/net/third_party/nss/ssl/ssl.h +++ b/net/third_party/nss/ssl/ssl.h @@ -273,6 +273,17 @@ SSL_IMPORT SECStatus SSL_SecurityStatus(PRFileDesc *fd, int *on, char **cipher, SSL_IMPORT CERTCertificate *SSL_PeerCertificate(PRFileDesc *fd); /* +** Return references to the certificates presented by the SSL peer. On entry, +** |*certs_size| must contain the size of the |certs| array. On successful +** return, |*certs_size| contains the number of certificates available and +** |certs| will contain references to as many certificates as would fit. +** Therefore if, on exit, |*certs_size| contains a value less than, or equal to, +** the entry value then all certificates were returned. +*/ +SSL_IMPORT SECStatus SSL_PeerCertificateChain( + PRFileDesc *fd, CERTCertificate **certs, unsigned int *certs_size); + +/* ** Authenticate certificate hook. Called when a certificate comes in ** (because of SSL_REQUIRE_CERTIFICATE in SSL_Enable) to authenticate the ** certificate. @@ -312,6 +323,35 @@ typedef SECStatus (PR_CALLBACK *SSLGetClientAuthData)(void *arg, SSL_IMPORT SECStatus SSL_GetClientAuthDataHook(PRFileDesc *fd, SSLGetClientAuthData f, void *a); +/* + * Prototype for SSL callback to get client auth data from the application, + * when using the underlying platform's cryptographic primitives. Returning + * SECFailure will cause the socket to send no client certificate. + * arg - application passed argument + * caNames - pointer to distinguished names of CAs that the server likes + * pRetCerts - pointer to pointer to list of certs, with the first being + * the client cert, and any following being used for chain + * building + * pRetKey - pointer to native key pointer, for return of key + * - Windows: pointer to HCRYPTPROV + * - Mac OS X: pointer to SecKeyRef + */ +typedef SECStatus (PR_CALLBACK *SSLGetPlatformClientAuthData)(void *arg, + PRFileDesc *fd, + CERTDistNames *caNames, + CERTCertList **pRetCerts,/*return */ + void **pRetKey);/* return */ + +/* + * Set the client side callback for SSL to retrieve user's private key + * and certificate. + * fd - the file descriptor for the connection in question + * f - the application's callback that delivers the key and cert + * a - application specific data + */ +SSL_IMPORT SECStatus +SSL_GetPlatformClientAuthDataHook(PRFileDesc *fd, + SSLGetPlatformClientAuthData f, void *a); /* ** SNI extension processing callback function. diff --git a/net/third_party/nss/ssl/ssl3con.c b/net/third_party/nss/ssl/ssl3con.c index 1a6612f..d3d2727 100644 --- a/net/third_party/nss/ssl/ssl3con.c +++ b/net/third_party/nss/ssl/ssl3con.c @@ -2011,6 +2011,12 @@ ssl3_ComputeRecordMAC( static PRBool ssl3_ClientAuthTokenPresent(sslSessionID *sid) { +#ifdef NSS_PLATFORM_CLIENT_AUTH + if (!sid || !sid->u.ssl3.clPlatformAuthValid) { + return PR_TRUE; + } + return ssl_PlatformAuthTokenPresent(&sid->u.ssl3.clPlatformAuthInfo); +#else PK11SlotInfo *slot = NULL; PRBool isPresent = PR_TRUE; @@ -2034,6 +2040,7 @@ ssl3_ClientAuthTokenPresent(sslSessionID *sid) { PK11_FreeSlot(slot); } return isPresent; +#endif /* NSS_PLATFORM_CLIENT_AUTH */ } SECStatus @@ -4827,6 +4834,20 @@ ssl3_SendCertificateVerify(sslSocket *ss) } isTLS = (PRBool)(ss->ssl3.pwSpec->version > SSL_LIBRARY_VERSION_3_0); +#ifdef NSS_PLATFORM_CLIENT_AUTH + rv = ssl3_PlatformSignHashes(&hashes, ss->ssl3.platformClientKey, + &buf, isTLS); + if (rv == SECSuccess) { + sslSessionID * sid = ss->sec.ci.sid; + ssl_GetPlatformAuthInfoForKey(ss->ssl3.platformClientKey, + &sid->u.ssl3.clPlatformAuthInfo); + sid->u.ssl3.clPlatformAuthValid = PR_TRUE; + } + if (ss->ssl3.hs.kea_def->exchKeyType == kt_rsa) { + ssl_FreePlatformKey(ss->ssl3.platformClientKey); + ss->ssl3.platformClientKey = (PlatformKey)NULL; + } +#else /* NSS_PLATFORM_CLIENT_AUTH */ rv = ssl3_SignHashes(&hashes, ss->ssl3.clientPrivateKey, &buf, isTLS); if (rv == SECSuccess) { PK11SlotInfo * slot; @@ -4851,6 +4872,7 @@ ssl3_SendCertificateVerify(sslSocket *ss) SECKEY_DestroyPrivateKey(ss->ssl3.clientPrivateKey); ss->ssl3.clientPrivateKey = NULL; } +#endif /* NSS_PLATFORM_CLIENT_AUTH */ if (rv != SECSuccess) { goto done; /* err code was set by ssl3_SignHashes */ } @@ -5481,6 +5503,10 @@ ssl3_HandleCertificateRequest(sslSocket *ss, SSL3Opaque *b, PRUint32 length) SSL3AlertDescription desc = illegal_parameter; SECItem cert_types = {siBuffer, NULL, 0}; CERTDistNames ca_list; +#ifdef NSS_PLATFORM_CLIENT_AUTH + CERTCertList * platform_cert_list = NULL; + CERTCertListNode * certNode = NULL; +#endif /* NSS_PLATFORM_CLIENT_AUTH */ SSL_TRC(3, ("%d: SSL3[%d]: handle certificate_request handshake", SSL_GETPID(), ss->fd)); @@ -5507,6 +5533,12 @@ ssl3_HandleCertificateRequest(sslSocket *ss, SSL3Opaque *b, PRUint32 length) SECKEY_DestroyPrivateKey(ss->ssl3.clientPrivateKey); ss->ssl3.clientPrivateKey = NULL; } +#ifdef NSS_PLATFORM_CLIENT_AUTH + if (ss->ssl3.platformClientKey) { + ssl_FreePlatformKey(ss->ssl3.platformClientKey); + ss->ssl3.platformClientKey = (PlatformKey)NULL; + } +#endif /* NSS_PLATFORM_CLIENT_AUTH */ isTLS = (PRBool)(ss->ssl3.prSpec->version > SSL_LIBRARY_VERSION_3_0); rv = ssl3_ConsumeHandshakeVariable(ss, &cert_types, 1, &b, &length); @@ -5573,6 +5605,18 @@ ssl3_HandleCertificateRequest(sslSocket *ss, SSL3Opaque *b, PRUint32 length) desc = no_certificate; ss->ssl3.hs.ws = wait_hello_done; +#ifdef NSS_PLATFORM_CLIENT_AUTH + if (ss->getPlatformClientAuthData == NULL) { + rv = SECFailure; /* force it to send a no_certificate alert */ + } else { + /* XXX Should pass cert_types in this call!! */ + rv = (SECStatus)(*ss->getPlatformClientAuthData)( + ss->getPlatformClientAuthDataArg, + ss->fd, &ca_list, + &platform_cert_list, + (void**)&ss->ssl3.platformClientKey); + } +#else if (ss->getClientAuthData == NULL) { rv = SECFailure; /* force it to send a no_certificate alert */ } else { @@ -5582,12 +5626,51 @@ ssl3_HandleCertificateRequest(sslSocket *ss, SSL3Opaque *b, PRUint32 length) &ss->ssl3.clientCertificate, &ss->ssl3.clientPrivateKey); } +#endif /* NSS_PLATFORM_CLIENT_AUTH */ switch (rv) { case SECWouldBlock: /* getClientAuthData has put up a dialog box. */ ssl_SetAlwaysBlock(ss); break; /* not an error */ case SECSuccess: +#ifdef NSS_PLATFORM_CLIENT_AUTH + if (!platform_cert_list || CERT_LIST_EMPTY(platform_cert_list) || + !ss->ssl3.platformClientKey) { + if (platform_cert_list) { + CERT_DestroyCertList(platform_cert_list); + platform_cert_list = NULL; + } + if (ss->ssl3.platformClientKey) { + ssl_FreePlatformKey(ss->ssl3.platformClientKey); + ss->ssl3.platformClientKey = (PlatformKey)NULL; + } + goto send_no_certificate; + } + + certNode = CERT_LIST_HEAD(platform_cert_list); + ss->ssl3.clientCertificate = CERT_DupCertificate(certNode->cert); + + /* Setting ssl3.clientCertChain non-NULL will cause + * ssl3_HandleServerHelloDone to call SendCertificate. + * Note: clientCertChain should include the EE cert as + * clientCertificate is ignored during the actual sending + */ + ss->ssl3.clientCertChain = + hack_NewCertificateListFromCertList(platform_cert_list); + CERT_DestroyCertList(platform_cert_list); + platform_cert_list = NULL; + if (ss->ssl3.clientCertChain == NULL) { + if (ss->ssl3.clientCertificate != NULL) { + CERT_DestroyCertificate(ss->ssl3.clientCertificate); + ss->ssl3.clientCertificate = NULL; + } + if (ss->ssl3.platformClientKey) { + ssl_FreePlatformKey(ss->ssl3.platformClientKey); + ss->ssl3.platformClientKey = (PlatformKey)NULL; + } + goto send_no_certificate; + } +#else /* check what the callback function returned */ if ((!ss->ssl3.clientCertificate) || (!ss->ssl3.clientPrivateKey)) { /* we are missing either the key or cert */ @@ -5620,6 +5703,7 @@ ssl3_HandleCertificateRequest(sslSocket *ss, SSL3Opaque *b, PRUint32 length) } goto send_no_certificate; } +#endif /* NSS_PLATFORM_CLIENT_AUTH */ break; /* not an error */ case SECFailure: @@ -5650,6 +5734,10 @@ loser: done: if (arena != NULL) PORT_FreeArena(arena, PR_FALSE); +#ifdef NSS_PLATFORM_CLIENT_AUTH + if (platform_cert_list) + CERT_DestroyCertList(platform_cert_list); +#endif return rv; } @@ -5758,6 +5846,16 @@ ssl3_HandleServerHelloDone(sslSocket *ss) goto loser; /* error code is set. */ } } else +#ifdef NSS_PLATFORM_CLIENT_AUTH + if (ss->ssl3.clientCertChain != NULL && + ss->ssl3.platformClientKey) { + send_verify = PR_TRUE; + rv = ssl3_SendCertificate(ss); + if (rv != SECSuccess) { + goto loser; /* error code is set. */ + } + } +#else if (ss->ssl3.clientCertChain != NULL && ss->ssl3.clientPrivateKey != NULL) { send_verify = PR_TRUE; @@ -5766,6 +5864,7 @@ ssl3_HandleServerHelloDone(sslSocket *ss) goto loser; /* error code is set. */ } } +#endif /* NSS_PLATFORM_CLIENT_AUTH */ rv = ssl3_SendClientKeyExchange(ss); if (rv != SECSuccess) { @@ -8366,20 +8465,6 @@ ssl3_SendFinished(sslSocket *ss, PRInt32 flags) } } - if ((ss->ssl3.hs.snapStartType == snap_start_recovery || - ss->ssl3.hs.snapStartType == snap_start_resume_recovery) && - ss->ssl3.snapStartApplicationData.data) { - /* In the event that the server ignored the application data in our - * snap start extension, we need to retransmit it now. */ - PRInt32 sent = ssl3_SendRecord(ss, content_application_data, - ss->ssl3.snapStartApplicationData.data, - ss->ssl3.snapStartApplicationData.len, - flags); - SECITEM_FreeItem(&ss->ssl3.snapStartApplicationData, PR_FALSE); - if (sent < 0) - return (SECStatus)sent; /* error code set by ssl3_SendRecord */ - } - return SECSuccess; fail: @@ -9640,6 +9725,10 @@ ssl3_DestroySSL3Info(sslSocket *ss) if (ss->ssl3.clientPrivateKey != NULL) SECKEY_DestroyPrivateKey(ss->ssl3.clientPrivateKey); +#ifdef NSS_PLATFORM_CLIENT_AUTH + if (ss->ssl3.platformClientKey) + ssl_FreePlatformKey(ss->ssl3.platformClientKey); +#endif /* NSS_PLATFORM_CLIENT_AUTH */ if (ss->ssl3.peerCertArena != NULL) ssl3_CleanupPeerCerts(ss); diff --git a/net/third_party/nss/ssl/ssl3ext.c b/net/third_party/nss/ssl/ssl3ext.c index a7ae062..f044e1c 100644 --- a/net/third_party/nss/ssl/ssl3ext.c +++ b/net/third_party/nss/ssl/ssl3ext.c @@ -46,8 +46,8 @@ #include "nssrenam.h" #include "nss.h" #include "ssl.h" -#include "sslproto.h" #include "sslimpl.h" +#include "sslproto.h" #include "pk11pub.h" #include "blapi.h" #include "prinit.h" diff --git a/net/third_party/nss/ssl/sslauth.c b/net/third_party/nss/ssl/sslauth.c index 39c630d..3f4924d 100644 --- a/net/third_party/nss/ssl/sslauth.c +++ b/net/third_party/nss/ssl/sslauth.c @@ -60,6 +60,42 @@ SSL_PeerCertificate(PRFileDesc *fd) } /* NEED LOCKS IN HERE. */ +SECStatus +SSL_PeerCertificateChain(PRFileDesc *fd, CERTCertificate **certs, + unsigned int *certsSize) +{ + sslSocket *ss; + unsigned int inSize = *certsSize; + ssl3CertNode* cur; + + ss = ssl_FindSocket(fd); + if (!ss) { + SSL_DBG(("%d: SSL[%d]: bad socket in PeerCertificateChain", + SSL_GETPID(), fd)); + return SECFailure; + } + if (!ss->opt.useSecurity) + return SECFailure; + + if (ss->sec.peerCert == NULL) { + *certsSize = 0; + return SECSuccess; + } + + *certsSize = 1; /* for the leaf certificate */ + if (inSize > 0) + certs[0] = CERT_DupCertificate(ss->sec.peerCert); + + for (cur = ss->ssl3.peerCertChain; cur; cur = cur->next) { + if (*certsSize < inSize) + certs[*certsSize] = CERT_DupCertificate(cur->cert); + (*certsSize)++; + } + + return SECSuccess; +} + +/* NEED LOCKS IN HERE. */ CERTCertificate * SSL_LocalCertificate(PRFileDesc *fd) { @@ -216,6 +252,28 @@ SSL_GetClientAuthDataHook(PRFileDesc *s, SSLGetClientAuthData func, return SECSuccess; } +#ifdef NSS_PLATFORM_CLIENT_AUTH +/* NEED LOCKS IN HERE. */ +SECStatus +SSL_GetPlatformClientAuthDataHook(PRFileDesc *s, + SSLGetPlatformClientAuthData func, + void *arg) +{ + sslSocket *ss; + + ss = ssl_FindSocket(s); + if (!ss) { + SSL_DBG(("%d: SSL[%d]: bad socket in GetPlatformClientAuthDataHook", + SSL_GETPID(), s)); + return SECFailure; + } + + ss->getPlatformClientAuthData = func; + ss->getPlatformClientAuthDataArg = arg; + return SECSuccess; +} +#endif /* NSS_PLATFORM_CLIENT_AUTH */ + /* NEED LOCKS IN HERE. */ SECStatus SSL_SetPKCS11PinArg(PRFileDesc *s, void *arg) diff --git a/net/third_party/nss/ssl/sslimpl.h b/net/third_party/nss/ssl/sslimpl.h index f708696..b84511b 100644 --- a/net/third_party/nss/ssl/sslimpl.h +++ b/net/third_party/nss/ssl/sslimpl.h @@ -65,6 +65,15 @@ #include "sslt.h" /* for some formerly private types, now public */ +#ifdef NSS_PLATFORM_CLIENT_AUTH +#if defined(XP_WIN32) +#include <windows.h> +#include <wincrypt.h> +#elif defined(XP_MACOSX) +#include <Security/Security.h> +#endif +#endif + /* to make some of these old enums public without namespace pollution, ** it was necessary to prepend ssl_ to the names. ** These #defines preserve compatibility with the old code here in libssl. @@ -573,6 +582,19 @@ typedef enum { never_cached, #define MAX_PEER_CERT_CHAIN_SIZE 8 +#ifdef NSS_PLATFORM_CLIENT_AUTH +typedef struct { +#if defined(XP_WIN32) + char * provider; + char * container; + DWORD provType; +#elif defined(XP_MACOSX) + SecKeychainRef keychain; + CFDataRef persistentKey; +#endif +} PlatformAuthInfo; +#endif /* NSS_PLATFORM_CLIENT_AUTH */ + struct sslSessionIDStr { sslSessionID * next; /* chain used for client sockets, only */ @@ -657,6 +679,11 @@ struct sslSessionIDStr { char masterValid; char clAuthValid; +#ifdef NSS_PLATFORM_CLIENT_AUTH + PlatformAuthInfo clPlatformAuthInfo; + char clPlatformAuthValid; +#endif /* NSS_PLATFORM_CLIENT_AUTH */ + /* Session ticket if we have one, is sent as an extension in the * ClientHello message. This field is used by clients. */ @@ -816,6 +843,15 @@ const ssl3CipherSuiteDef *suite_def; PRBool nextProtoNego;/* Our peer has sent this extension */ } SSL3HandshakeState; +#ifdef NSS_PLATFORM_CLIENT_AUTH +#if defined(XP_WIN32) +typedef HCRYPTPROV PlatformKey; +#elif defined(XP_MACOSX) +typedef SecKeyRef PlatformKey; +#else +typedef void *PlatformKey; +#endif +#endif /* @@ -839,6 +875,9 @@ struct ssl3StateStr { CERTCertificate * clientCertificate; /* used by client */ SECKEYPrivateKey * clientPrivateKey; /* used by client */ +#ifdef NSS_PLATFORM_CLIENT_AUTH + PlatformKey platformClientKey; /* used by client */ +#endif /* NSS_PLATFORM_CLIENT_AUTH */ CERTCertificateList *clientCertChain; /* used by client */ PRBool sendEmptyCert; /* used by client */ @@ -1100,6 +1139,10 @@ const unsigned char * preferredCipher; void *authCertificateArg; SSLGetClientAuthData getClientAuthData; void *getClientAuthDataArg; +#ifdef NSS_PLATFORM_CLIENT_AUTH + SSLGetPlatformClientAuthData getPlatformClientAuthData; + void *getPlatformClientAuthDataArg; +#endif /* NSS_PLATFORM_CLIENT_AUTH */ SSLSNISocketConfig sniSocketConfig; void *sniSocketConfigArg; SSLBadCertHandler handleBadCert; @@ -1691,6 +1734,43 @@ extern SECStatus ssl_InitSessionCacheLocks(PRBool lazyInit); extern SECStatus ssl_FreeSessionCacheLocks(void); +/***************** platform client auth ****************/ + +#ifdef NSS_PLATFORM_CLIENT_AUTH +// Releases the platform key. +extern void ssl_FreePlatformKey(PlatformKey key); + +// Frees any memory allocated to store a persistent reference to the +// platform key. +extern void ssl_FreePlatformAuthInfo(PlatformAuthInfo* info); + +// Initializes the PlatformAuthInfo to empty/invalid values. +extern void ssl_InitPlatformAuthInfo(PlatformAuthInfo* info); + +// Determine if the given key is still present in the system. This is used +// to check for things like smart cards being ejected after handshaking, +// since no further operations on the key will happen which would detect this. +extern PRBool ssl_PlatformAuthTokenPresent(PlatformAuthInfo* info); + +// Obtain a persistent reference to a key, sufficient for +// ssl_PlatformAuthTokenPresent to determine if the key is still present. +extern void ssl_GetPlatformAuthInfoForKey(PlatformKey key, + PlatformAuthInfo* info); + +// Implement the client CertificateVerify message for SSL3/TLS1.0 +extern SECStatus ssl3_PlatformSignHashes(SSL3Hashes *hash, + PlatformKey key, SECItem *buf, + PRBool isTLS); + +// Converts a CERTCertList* (A collection of CERTCertificates) into a +// CERTCertificateList* (A collection of SECItems), or returns NULL if +// it cannot be converted. +// This is to allow the platform-supplied chain to be created with purely +// public API functions, using the preferred CERTCertList mutators, rather +// pushing this hack to clients. +extern CERTCertificateList* hack_NewCertificateListFromCertList( + CERTCertList* list); +#endif /* NSS_PLATFORM_CLIENT_AUTH */ /********************** misc calls *********************/ diff --git a/net/third_party/nss/ssl/sslnonce.c b/net/third_party/nss/ssl/sslnonce.c index 64adc1f..345f041 100644 --- a/net/third_party/nss/ssl/sslnonce.c +++ b/net/third_party/nss/ssl/sslnonce.c @@ -226,6 +226,11 @@ ssl_DestroySID(sslSessionID *sid) if (sid->u.ssl3.sessionTicket.ticket.data) { SECITEM_FreeItem(&sid->u.ssl3.sessionTicket.ticket, PR_FALSE); } +#ifdef NSS_PLATFORM_CLIENT_AUTH + if (sid->u.ssl3.clPlatformAuthValid) { + ssl_FreePlatformAuthInfo(&sid->u.ssl3.clPlatformAuthInfo); + } +#endif /* NSS_PLATFORM_CLIENT_AUTH */ PORT_ZFree(sid, sizeof(sslSessionID)); } diff --git a/net/third_party/nss/ssl/sslplatf.c b/net/third_party/nss/ssl/sslplatf.c new file mode 100644 index 0000000..7119543 --- /dev/null +++ b/net/third_party/nss/ssl/sslplatf.c @@ -0,0 +1,561 @@ +/* + * Platform specific crypto wrappers + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1994-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Ryan Sleevi <ryan.sleevi@gmail.com> + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +/* $Id$ */ +#include "ssl.h" +#include "certt.h" +#include "keythi.h" +#include "sslimpl.h" +#include "cryptohi.h" +#include "secitem.h" + +#ifdef NSS_PLATFORM_CLIENT_AUTH +CERTCertificateList* +hack_NewCertificateListFromCertList(CERTCertList* list) +{ + CERTCertificateList * chain = NULL; + PRArenaPool * arena = NULL; + CERTCertListNode * node; + int len; + + if (CERT_LIST_EMPTY(list)) + goto loser; + + arena = PORT_NewArena(4096); + if (arena == NULL) + goto loser; + + for (len = 0, node = CERT_LIST_HEAD(list); !CERT_LIST_END(node, list); + len++, node = CERT_LIST_NEXT(node)) { + } + + chain = PORT_ArenaNew(arena, CERTCertificateList); + if (chain == NULL) + goto loser; + + chain->certs = PORT_ArenaNewArray(arena, SECItem, len); + if (!chain->certs) + goto loser; + chain->len = len; + + for (len = 0, node = CERT_LIST_HEAD(list); !CERT_LIST_END(node, list); + len++, node = CERT_LIST_NEXT(node)) { + // Check to see if the last cert to be sent is a self-signed cert, + // and if so, omit it from the list of certificates. However, if + // there is only one cert (len == 0), include the cert, as it means + // the EE cert is self-signed. + if (len > 0 && (len == chain->len - 1) && node->cert->isRoot) { + chain->len = len; + break; + } + SECITEM_CopyItem(arena, &chain->certs[len], &node->cert->derCert); + } + + chain->arena = arena; + return chain; + +loser: + if (arena) { + PORT_FreeArena(arena, PR_FALSE); + } + return NULL; +} + +#if defined(XP_WIN32) +void +ssl_FreePlatformKey(PlatformKey key) +{ + CryptReleaseContext(key, 0); +} + +void +ssl_FreePlatformAuthInfo(PlatformAuthInfo* info) +{ + if (info->provider != NULL) { + PORT_Free(info->provider); + info->provider = NULL; + } + if (info->container != NULL) { + PORT_Free(info->container); + info->container = NULL; + } + info->provType = 0; +} + +void +ssl_InitPlatformAuthInfo(PlatformAuthInfo* info) +{ + info->provider = NULL; + info->container = NULL; + info->provType = 0; +} + +PRBool +ssl_PlatformAuthTokenPresent(PlatformAuthInfo *info) +{ + HCRYPTPROV prov = 0; + + if (!info || !info->provider || !info->container) + return PR_FALSE; + + if (!CryptAcquireContextA(&prov, info->container, info->provider, + info->provType, 0)) + return PR_FALSE; + + CryptReleaseContext(prov, 0); + return PR_TRUE; +} + +void +ssl_GetPlatformAuthInfoForKey(PlatformKey key, + PlatformAuthInfo *info) +{ + DWORD bytesNeeded = 0; + ssl_InitPlatformAuthInfo(info); + bytesNeeded = sizeof(info->provType); + if (!CryptGetProvParam(key, PP_PROVTYPE, (BYTE*)&info->provType, + &bytesNeeded, 0)) + goto error; + + bytesNeeded = 0; + if (!CryptGetProvParam(key, PP_CONTAINER, NULL, &bytesNeeded, 0)) + goto error; + info->container = (char*)PORT_Alloc(bytesNeeded); + if (info->container == NULL) + goto error; + if (!CryptGetProvParam(key, PP_CONTAINER, (BYTE*)info->container, + &bytesNeeded, 0)) + goto error; + + bytesNeeded = 0; + if (!CryptGetProvParam(key, PP_NAME, NULL, &bytesNeeded, 0)) + goto error; + info->provider = (char*)PORT_Alloc(bytesNeeded); + if (info->provider == NULL) + goto error; + if (!CryptGetProvParam(key, PP_NAME, (BYTE*)info->provider, + &bytesNeeded, 0)) + goto error; + + goto done; +error: + ssl_FreePlatformAuthInfo(info); + +done: + return; +} + +SECStatus +ssl3_PlatformSignHashes(SSL3Hashes *hash, PlatformKey key, SECItem *buf, + PRBool isTLS) +{ + SECStatus rv = SECFailure; + PRBool doDerEncode = PR_FALSE; + SECItem hashItem; + /* TODO(rsleevi): Should AT_SIGNATURE also be checked if doing client + * auth? + */ + DWORD keySpec = AT_KEYEXCHANGE; + HCRYPTKEY hKey = 0; + DWORD argLen = 0; + ALG_ID keyAlg = 0; + DWORD signatureLen = 0; + ALG_ID hashAlg = 0; + HCRYPTHASH hHash = 0; + DWORD hashLen = 0; + unsigned int i = 0; + + buf->data = NULL; + if (!CryptGetUserKey(key, keySpec, &hKey)) { + PORT_SetError(SEC_ERROR_INVALID_KEY); + goto done; + } + + argLen = sizeof(keyAlg); + if (!CryptGetKeyParam(hKey, KP_ALGID, (BYTE*)&keyAlg, &argLen, 0)) { + PORT_SetError(SEC_ERROR_INVALID_KEY); + goto done; + } + + switch (keyAlg) { + case CALG_RSA_KEYX: + case CALG_RSA_SIGN: + hashAlg = CALG_SSL3_SHAMD5; + hashItem.data = hash->md5; + hashItem.len = sizeof(SSL3Hashes); + break; + case CALG_DSS_SIGN: + /* TODO: Support CALG_ECDSA once tested */ + case CALG_ECDSA: + if (keyAlg == CALG_ECDSA) { + doDerEncode = PR_TRUE; + } else { + doDerEncode = isTLS; + } + hashAlg = CALG_SHA1; + hashItem.data = hash->sha; + hashItem.len = sizeof(hash->sha); + break; + default: + PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG); + goto done; + } + PRINT_BUF(60, (NULL, "hash(es) to be signed", hashItem.data, hashItem.len)); + + if (!CryptCreateHash(key, hashAlg, 0, 0, &hHash)) { + ssl_MapLowLevelError(SSL_ERROR_SIGN_HASHES_FAILURE); + goto done; + } + argLen = sizeof(hashLen); + if (!CryptGetHashParam(hHash, HP_HASHSIZE, (BYTE*)&hashLen, &argLen, 0)) { + ssl_MapLowLevelError(SSL_ERROR_SIGN_HASHES_FAILURE); + goto done; + } + if (hashLen != hashItem.len) { + ssl_MapLowLevelError(SSL_ERROR_SIGN_HASHES_FAILURE); + goto done; + } + if (!CryptSetHashParam(hHash, HP_HASHVAL, (BYTE*)hashItem.data, 0)) { + ssl_MapLowLevelError(SSL_ERROR_SIGN_HASHES_FAILURE); + goto done; + } + if (!CryptSignHash(hHash, keySpec, NULL, CRYPT_NOHASHOID, + NULL, &signatureLen) || signatureLen == 0) { + ssl_MapLowLevelError(SSL_ERROR_SIGN_HASHES_FAILURE); + goto done; + } + buf->len = signatureLen; + buf->data = (unsigned char *)PORT_Alloc(signatureLen); + if (!buf->data) + goto done; /* error code was set. */ + + if (!CryptSignHash(hHash, keySpec, NULL, CRYPT_NOHASHOID, + (BYTE*)buf->data, &signatureLen)) { + ssl_MapLowLevelError(SSL_ERROR_SIGN_HASHES_FAILURE); + goto done; + } + + /* CryptoAPI signs in little-endian, so reverse */ + for (i = 0; i < buf->len / 2; ++i) { + unsigned char tmp = buf->data[i]; + buf->data[i] = buf->data[buf->len - 1 - i]; + buf->data[buf->len - 1 - i] = tmp; + } + if (doDerEncode) { + SECItem derSig = {siBuffer, NULL, 0}; + + /* This also works for an ECDSA signature */ + rv = DSAU_EncodeDerSigWithLen(&derSig, buf, buf->len); + if (rv == SECSuccess) { + PORT_Free(buf->data); /* discard unencoded signature. */ + *buf = derSig; /* give caller encoded signature. */ + } else if (derSig.data) { + PORT_Free(derSig.data); + } + } + + PRINT_BUF(60, (NULL, "signed hashes", buf->data, buf->len)); + rv = SECSuccess; +done: + if (hHash) + CryptDestroyHash(hHash); + if (hKey) + CryptDestroyKey(hKey); + if (rv != SECSuccess && buf->data) { + PORT_Free(buf->data); + buf->data = NULL; + } + return rv; +} + +#elif defined(XP_MACOSX) +#include <Security/cssm.h> + +/* + * In Mac OS X 10.5, these two functions are private but implemented, and + * in Mac OS X 10.6, these are exposed publicly. To compile with the 10.5 + * SDK, we declare them here. + */ +OSStatus SecKeychainItemCreatePersistentReference(SecKeychainItemRef itemRef, CFDataRef *persistentItemRef); +OSStatus SecKeychainItemCopyFromPersistentReference(CFDataRef persistentItemRef, SecKeychainItemRef *itemRef); + +void +ssl_FreePlatformKey(PlatformKey key) +{ + CFRelease(key); +} + +void +ssl_FreePlatformAuthInfo(PlatformAuthInfo* info) +{ + if (info->keychain != NULL) { + CFRelease(info->keychain); + info->keychain = NULL; + } + if (info->persistentKey != NULL) { + CFRelease(info->persistentKey); + info->persistentKey = NULL; + } +} + +void +ssl_InitPlatformAuthInfo(PlatformAuthInfo* info) +{ + info->keychain = NULL; + info->persistentKey = NULL; +} + +PRBool +ssl_PlatformAuthTokenPresent(PlatformAuthInfo* info) +{ + if (!info || !info->keychain || !info->persistentKey) + return PR_FALSE; + + // Not actually interested in the status, but it can be used to make sure + // that the keychain still exists (as smart card ejection will remove + // the keychain) + SecKeychainStatus keychainStatus; + OSStatus rv = SecKeychainGetStatus(info->keychain, &keychainStatus); + if (rv != noErr) + return PR_FALSE; + + // Make sure the individual key still exists within the keychain, if + // the keychain is present + SecKeychainItemRef keychainItem; + rv = SecKeychainItemCopyFromPersistentReference(info->persistentKey, + &keychainItem); + if (rv != noErr) + return PR_FALSE; + + CFRelease(keychainItem); + return PR_TRUE; +} + +void +ssl_GetPlatformAuthInfoForKey(PlatformKey key, + PlatformAuthInfo *info) +{ + SecKeychainItemRef keychainItem = (SecKeychainItemRef)key; + OSStatus rv = SecKeychainItemCopyKeychain(keychainItem, &info->keychain); + if (rv == noErr) { + rv = SecKeychainItemCreatePersistentReference(keychainItem, + &info->persistentKey); + } + if (rv != noErr) { + ssl_FreePlatformAuthInfo(info); + } + return; +} + +SECStatus +ssl3_PlatformSignHashes(SSL3Hashes *hash, PlatformKey key, SECItem *buf, + PRBool isTLS) +{ + SECStatus rv = SECFailure; + PRBool doDerEncode = PR_FALSE; + unsigned int signatureLen; + OSStatus status = noErr; + CSSM_CSP_HANDLE cspHandle = 0; + const CSSM_KEY *cssmKey = NULL; + CSSM_ALGORITHMS sigAlg; + const CSSM_ACCESS_CREDENTIALS * cssmCreds = NULL; + CSSM_RETURN cssmRv; + CSSM_DATA hashData; + CSSM_DATA signatureData; + CSSM_CC_HANDLE cssmSignature = 0; + + buf->data = NULL; + + status = SecKeyGetCSPHandle(key, &cspHandle); + if (status != noErr) { + PORT_SetError(SEC_ERROR_INVALID_KEY); + goto done; + } + + status = SecKeyGetCSSMKey(key, &cssmKey); + if (status != noErr || !cssmKey) { + PORT_SetError(SEC_ERROR_INVALID_KEY); + goto done; + } + + /* SecKeyGetBlockSize wasn't addeded until OS X 10.6 - but the + * needed information is readily available on the key itself. + */ + signatureLen = (cssmKey->KeyHeader.LogicalKeySizeInBits + 7) / 8; + + if (signatureLen == 0) { + PORT_SetError(SEC_ERROR_INVALID_KEY); + goto done; + } + + buf->len = signatureLen; + buf->data = (unsigned char *)PORT_Alloc(signatureLen); + if (!buf->data) + goto done; /* error code was set. */ + + sigAlg = cssmKey->KeyHeader.AlgorithmId; + switch (sigAlg) { + case CSSM_ALGID_RSA: + hashData.Data = hash->md5; + hashData.Length = sizeof(SSL3Hashes); + break; + case CSSM_ALGID_ECDSA: + case CSSM_ALGID_DSA: + if (sigAlg == CSSM_ALGID_ECDSA) { + doDerEncode = PR_TRUE; + } else { + doDerEncode = isTLS; + } + hashData.Data = hash->sha; + hashData.Length = sizeof(hash->sha); + break; + default: + PORT_SetError(SEC_ERROR_INVALID_KEY); + goto done; + } + PRINT_BUF(60, (NULL, "hash(es) to be signed", hashData.Data, hashData.Length)); + + /* TODO(rsleevi): Should it be kSecCredentialTypeNoUI? In Win32, at least, + * you can prevent the UI by setting the provider handle on the + * certificate to be opened with CRYPT_SILENT, but is there an equivalent? + */ + status = SecKeyGetCredentials(key, CSSM_ACL_AUTHORIZATION_SIGN, + kSecCredentialTypeDefault, &cssmCreds); + if (status != noErr) { + ssl_MapLowLevelError(SSL_ERROR_SIGN_HASHES_FAILURE); + goto done; + } + + signatureData.Length = buf->len; + signatureData.Data = (uint8*)buf->data; + + cssmRv = CSSM_CSP_CreateSignatureContext(cspHandle, sigAlg, cssmCreds, + cssmKey, &cssmSignature); + if (cssmRv) { + ssl_MapLowLevelError(SSL_ERROR_SIGN_HASHES_FAILURE); + goto done; + } + + /* See "Apple Cryptographic Service Provider Functional Specification" */ + if (cssmKey->KeyHeader.AlgorithmId == CSSM_ALGID_RSA) { + /* To set RSA blinding for RSA keys */ + CSSM_CONTEXT_ATTRIBUTE blindingAttr; + blindingAttr.AttributeType = CSSM_ATTRIBUTE_RSA_BLINDING; + blindingAttr.AttributeLength = sizeof(uint32); + blindingAttr.Attribute.Uint32 = 1; + cssmRv = CSSM_UpdateContextAttributes(cssmSignature, 1, &blindingAttr); + if (cssmRv) { + ssl_MapLowLevelError(SSL_ERROR_SIGN_HASHES_FAILURE); + goto done; + } + } + + cssmRv = CSSM_SignData(cssmSignature, &hashData, 1, CSSM_ALGID_NONE, + &signatureData); + if (cssmRv) { + ssl_MapLowLevelError(SSL_ERROR_SIGN_HASHES_FAILURE); + goto done; + } + + if (doDerEncode) { + SECItem derSig = {siBuffer, NULL, 0}; + + /* This also works for an ECDSA signature */ + rv = DSAU_EncodeDerSigWithLen(&derSig, buf, buf->len); + if (rv == SECSuccess) { + PORT_Free(buf->data); /* discard unencoded signature. */ + *buf = derSig; /* give caller encoded signature. */ + } else if (derSig.data) { + PORT_Free(derSig.data); + } + } + + PRINT_BUF(60, (NULL, "signed hashes", buf->data, buf->len)); + rv = SECSuccess; +done: + /* cspHandle, cssmKey, and cssmCreds are owned by the SecKeyRef and + * should not be freed. When the PlatformKey is freed, they will be + * released. + */ + if (cssmSignature) + CSSM_DeleteContext(cssmSignature); + + if (rv != SECSuccess && buf->data) { + PORT_Free(buf->data); + buf->data = NULL; + } + return rv; +} +#else +void +ssl_FreePlatformKey(PlatformKey key) +{ +} + +void +ssl_FreePlatformAuthInfo(PlatformAuthInfo *info) +{ +} + +void +ssl_InitPlatformAuthInfo(PlatformAuthInfo *info) +{ +} + +PRBool +ssl_PlatformAuthTokenPresent(PlatformAuthInfo *info) +{ + return PR_FALSE; +} + +void +ssl_GetPlatformAuthInfoForKey(PlatformKey key, PlatformAuthInfo *info) +{ +} + +SECStatus +ssl3_PlatformSignHashes(SSL3Hashes *hash, PlatformKey key, SECItem *buf, + PRBool isTLS) +{ + PORT_SetError(PR_NOT_IMPLEMENTED_ERROR); + return SECFailure; +} +#endif + +#endif /* NSS_PLATFORM_CLIENT_AUTH */ diff --git a/net/third_party/nss/ssl/sslsnce.c b/net/third_party/nss/ssl/sslsnce.c index 6c73f25..4176ac8 100644 --- a/net/third_party/nss/ssl/sslsnce.c +++ b/net/third_party/nss/ssl/sslsnce.c @@ -638,6 +638,11 @@ ConvertToSID(sidCacheEntry * from, to->u.ssl3.clAuthSeries = 0; to->u.ssl3.clAuthValid = PR_FALSE; +#ifdef NSS_PLATFORM_CLIENT_AUTH + ssl_InitPlatformAuthInfo(&to->u.ssl3.clPlatformAuthInfo); + to->u.ssl3.clPlatformAuthValid = PR_FALSE; +#endif /* NSS_PLATFORM_CLIENT_AUTH */ + if (from->u.ssl3.certIndex != -1 && pcce) { SECItem derCert; diff --git a/net/third_party/nss/ssl/sslsock.c b/net/third_party/nss/ssl/sslsock.c index 2898b88..33e7f3e 100644 --- a/net/third_party/nss/ssl/sslsock.c +++ b/net/third_party/nss/ssl/sslsock.c @@ -336,6 +336,10 @@ ssl_DupSocket(sslSocket *os) ss->authCertificateArg = os->authCertificateArg; ss->getClientAuthData = os->getClientAuthData; ss->getClientAuthDataArg = os->getClientAuthDataArg; +#ifdef NSS_PLATFORM_CLIENT_AUTH + ss->getPlatformClientAuthData = os->getPlatformClientAuthData; + ss->getPlatformClientAuthDataArg = os->getPlatformClientAuthDataArg; +#endif ss->sniSocketConfig = os->sniSocketConfig; ss->sniSocketConfigArg = os->sniSocketConfigArg; ss->handleBadCert = os->handleBadCert; @@ -1443,6 +1447,12 @@ SSL_ReconfigFD(PRFileDesc *model, PRFileDesc *fd) ss->getClientAuthData = sm->getClientAuthData; if (sm->getClientAuthDataArg) ss->getClientAuthDataArg = sm->getClientAuthDataArg; +#ifdef NSS_PLATFORM_CLIENT_AUTH + if (sm->getPlatformClientAuthData) + ss->getPlatformClientAuthData = sm->getPlatformClientAuthData; + if (sm->getPlatformClientAuthDataArg) + ss->getPlatformClientAuthDataArg = sm->getPlatformClientAuthDataArg; +#endif if (sm->sniSocketConfig) ss->sniSocketConfig = sm->sniSocketConfig; if (sm->sniSocketConfigArg) @@ -2456,6 +2466,10 @@ ssl_NewSocket(PRBool makeLocks) ss->sniSocketConfig = NULL; ss->sniSocketConfigArg = NULL; ss->getClientAuthData = NULL; +#ifdef NSS_PLATFORM_CLIENT_AUTH + ss->getPlatformClientAuthData = NULL; + ss->getPlatformClientAuthDataArg = NULL; +#endif /* NSS_PLATFORM_CLIENT_AUTH */ ss->handleBadCert = NULL; ss->badCertArg = NULL; ss->pkcs11PinArg = NULL; diff --git a/net/tools/fetch/fetch_client.cc b/net/tools/fetch/fetch_client.cc index 42949c8..3bdbcbf 100644 --- a/net/tools/fetch/fetch_client.cc +++ b/net/tools/fetch/fetch_client.cc @@ -137,7 +137,7 @@ int main(int argc, char**argv) { scoped_ptr<net::HostResolver> host_resolver( net::CreateSystemHostResolver(net::HostResolver::kDefaultParallelism, - NULL)); + NULL, NULL)); scoped_refptr<net::ProxyService> proxy_service( net::ProxyService::CreateDirect()); diff --git a/net/tools/fetch/http_listen_socket.cc b/net/tools/fetch/http_listen_socket.cc index fd788c8..0db714f 100644 --- a/net/tools/fetch/http_listen_socket.cc +++ b/net/tools/fetch/http_listen_socket.cc @@ -30,8 +30,8 @@ void HttpListenSocket::Accept() { if (conn == ListenSocket::kInvalidSocket) { // TODO } else { - scoped_refptr<HttpListenSocket> sock = - new HttpListenSocket(conn, delegate_); + scoped_refptr<HttpListenSocket> sock( + new HttpListenSocket(conn, delegate_)); // it's up to the delegate to AddRef if it wants to keep it around DidAccept(this, sock); } diff --git a/net/tools/testserver/testserver.py b/net/tools/testserver/testserver.py index c3fe86b..55aa6a9 100644..100755 --- a/net/tools/testserver/testserver.py +++ b/net/tools/testserver/testserver.py @@ -21,7 +21,7 @@ import shutil import SocketServer import sys import time -import urllib2 +import urlparse import warnings # Ignore deprecation warnings, they make our output more cluttered. @@ -64,7 +64,7 @@ class HTTPSServer(tlslite.api.TLSSocketServerMixIn, StoppableHTTPServer): """This is a specialization of StoppableHTTPerver that add https support.""" def __init__(self, server_address, request_hander_class, cert_path, - ssl_client_auth, ssl_client_cas): + ssl_client_auth, ssl_client_cas, ssl_bulk_ciphers): s = open(cert_path).read() x509 = tlslite.api.X509() x509.parse(s) @@ -78,6 +78,9 @@ class HTTPSServer(tlslite.api.TLSSocketServerMixIn, StoppableHTTPServer): x509 = tlslite.api.X509() x509.parse(s) self.ssl_client_cas.append(x509.subject) + self.ssl_handshake_settings = tlslite.api.HandshakeSettings() + if ssl_bulk_ciphers is not None: + self.ssl_handshake_settings.cipherNames = ssl_bulk_ciphers self.session_cache = tlslite.api.SessionCache() StoppableHTTPServer.__init__(self, server_address, request_hander_class) @@ -89,6 +92,7 @@ class HTTPSServer(tlslite.api.TLSSocketServerMixIn, StoppableHTTPServer): privateKey=self.private_key, sessionCache=self.session_cache, reqCert=self.ssl_client_auth, + settings=self.ssl_handshake_settings, reqCAs=self.ssl_client_cas) tlsConnection.ignoreAbruptClose = True return True @@ -569,6 +573,24 @@ class TestPageHandler(BaseHTTPServer.BaseHTTPRequestHandler): self.end_headers() return True + def _ReplaceFileData(self, data, query_parameters): + """Replaces matching substrings in a file. + + If the 'replace_orig' and 'replace_new' URL query parameters are present, + a new string is returned with all occasions of the 'replace_orig' value + replaced by the 'replace_new' value. + + If the parameters are not present, |data| is returned. + """ + query_dict = cgi.parse_qs(query_parameters) + orig_values = query_dict.get('replace_orig', []) + new_values = query_dict.get('replace_new', []) + if not orig_values or not new_values: + return data + orig_value = orig_values[0] + new_value = new_values[0] + return data.replace(orig_value, new_value) + def FileHandler(self): """This handler sends the contents of the requested file. Wow, it's like a real webserver!""" @@ -581,29 +603,27 @@ class TestPageHandler(BaseHTTPServer.BaseHTTPRequestHandler): if self.command == 'POST' or self.command == 'PUT' : self.rfile.read(int(self.headers.getheader('content-length'))) - file = self.path[len(prefix):] - if file.find('?') > -1: - # Ignore the query parameters entirely. - url, querystring = file.split('?') - else: - url = file - entries = url.split('/') - path = os.path.join(self.server.data_dir, *entries) - if os.path.isdir(path): - path = os.path.join(path, 'index.html') - - if not os.path.isfile(path): - print "File not found " + file + " full path:" + path + _, _, url_path, _, query, _ = urlparse.urlparse(self.path) + sub_path = url_path[len(prefix):] + entries = sub_path.split('/') + file_path = os.path.join(self.server.data_dir, *entries) + if os.path.isdir(file_path): + file_path = os.path.join(file_path, 'index.html') + + if not os.path.isfile(file_path): + print "File not found " + sub_path + " full path:" + file_path self.send_error(404) return True - f = open(path, "rb") + f = open(file_path, "rb") data = f.read() f.close() + data = self._ReplaceFileData(data, query) + # If file.mock-http-headers exists, it contains the headers we # should send. Read them in and parse them. - headers_path = path + '.mock-http-headers' + headers_path = file_path + '.mock-http-headers' if os.path.isfile(headers_path): f = open(headers_path, "r") @@ -623,7 +643,7 @@ class TestPageHandler(BaseHTTPServer.BaseHTTPRequestHandler): # Could be more generic once we support mime-type sniffing, but for # now we need to set it explicitly. self.send_response(200) - self.send_header('Content-type', self.GetMIMETypeFromName(file)) + self.send_header('Content-type', self.GetMIMETypeFromName(file_path)) self.send_header('Content-Length', len(data)) self.end_headers() @@ -1169,7 +1189,8 @@ def main(options, args): ' exiting...' return server = HTTPSServer(('127.0.0.1', port), TestPageHandler, options.cert, - options.ssl_client_auth, options.ssl_client_ca) + options.ssl_client_auth, options.ssl_client_ca, + options.ssl_bulk_cipher) print 'HTTPS server started on port %d...' % port else: server = StoppableHTTPServer(('127.0.0.1', port), TestPageHandler) @@ -1240,8 +1261,18 @@ if __name__ == '__main__': help='Require SSL client auth on every connection.') option_parser.add_option('', '--ssl-client-ca', action='append', default=[], help='Specify that the client certificate request ' - 'should indicate that it supports the CA contained ' - 'in the specified certificate file') + 'should include the CA named in the subject of ' + 'the DER-encoded certificate contained in the ' + 'specified file. This option may appear multiple ' + 'times, indicating multiple CA names should be ' + 'sent in the request.') + option_parser.add_option('', '--ssl-bulk-cipher', action='append', + help='Specify the bulk encryption algorithm(s)' + 'that will be accepted by the SSL server. Valid ' + 'values are "aes256", "aes128", "3des", "rc4". If ' + 'omitted, all algorithms will be used. This ' + 'option may appear multiple times, indicating ' + 'multiple algorithms should be enabled.'); option_parser.add_option('', '--file-root-url', default='/files/', help='Specify a root URL for files served.') option_parser.add_option('', '--startup-pipe', type='int', diff --git a/net/tools/testserver/xmppserver.py b/net/tools/testserver/xmppserver.py new file mode 100644 index 0000000..ad99571 --- /dev/null +++ b/net/tools/testserver/xmppserver.py @@ -0,0 +1,527 @@ +#!/usr/bin/python2.4 +# Copyright (c) 2010 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. + +"""A bare-bones and non-compliant XMPP server. + +Just enough of the protocol is implemented to get it to work with +Chrome's sync notification system. +""" + +import asynchat +import asyncore +import base64 +import re +import socket +from xml.dom import minidom + +# pychecker complains about the use of fileno(), which is implemented +# by asyncore by forwarding to an internal object via __getattr__. +__pychecker__ = 'no-classattr' + + +class Error(Exception): + """Error class for this module.""" + pass + + +class UnexpectedXml(Error): + """Raised when an unexpected XML element has been encountered.""" + + def __init__(self, xml_element): + xml_text = xml_element.toxml() + Error.__init__(self, 'Unexpected XML element', xml_text) + + +def ParseXml(xml_string): + """Parses the given string as XML and returns a minidom element + object. + """ + dom = minidom.parseString(xml_string) + + # minidom handles xmlns specially, but there's a bug where it sets + # the attribute value to None, which causes toxml() or toprettyxml() + # to break. + def FixMinidomXmlnsBug(xml_element): + if xml_element.getAttribute('xmlns') is None: + xml_element.setAttribute('xmlns', '') + + def ApplyToAllDescendantElements(xml_element, fn): + fn(xml_element) + for node in xml_element.childNodes: + if node.nodeType == node.ELEMENT_NODE: + ApplyToAllDescendantElements(node, fn) + + root = dom.documentElement + ApplyToAllDescendantElements(root, FixMinidomXmlnsBug) + return root + + +def CloneXml(xml): + """Returns a deep copy of the given XML element. + + Args: + xml: The XML element, which should be something returned from + ParseXml() (i.e., a root element). + """ + return xml.ownerDocument.cloneNode(True).documentElement + + +class StanzaParser(object): + """A hacky incremental XML parser. + + StanzaParser consumes data incrementally via FeedString() and feeds + its delegate complete parsed stanzas (i.e., XML documents) via + FeedStanza(). Any stanzas passed to FeedStanza() are unlinked after + the callback is done. + + Use like so: + + class MyClass(object): + ... + def __init__(self, ...): + ... + self._parser = StanzaParser(self) + ... + + def SomeFunction(self, ...): + ... + self._parser.FeedString(some_data) + ... + + def FeedStanza(self, stanza): + ... + print stanza.toprettyxml() + ... + """ + + # NOTE(akalin): The following regexps are naive, but necessary since + # none of the existing Python 2.4/2.5 XML libraries support + # incremental parsing. This works well enough for our purposes. + # + # The regexps below assume that any present XML element starts at + # the beginning of the string, but there may be trailing whitespace. + + # Matches an opening stream tag (e.g., '<stream:stream foo="bar">') + # (assumes that the stream XML namespace is defined in the tag). + _stream_re = re.compile(r'^(<stream:stream [^>]*>)\s*') + + # Matches an empty element tag (e.g., '<foo bar="baz"/>'). + _empty_element_re = re.compile(r'^(<[^>]*/>)\s*') + + # Matches a non-empty element (e.g., '<foo bar="baz">quux</foo>'). + # Does *not* handle nested elements. + _non_empty_element_re = re.compile(r'^(<([^ >]*)[^>]*>.*?</\2>)\s*') + + # The closing tag for a stream tag. We have to insert this + # ourselves since all XML stanzas are children of the stream tag, + # which is never closed until the connection is closed. + _stream_suffix = '</stream:stream>' + + def __init__(self, delegate): + self._buffer = '' + self._delegate = delegate + + def FeedString(self, data): + """Consumes the given string data, possibly feeding one or more + stanzas to the delegate. + """ + self._buffer += data + while (self._ProcessBuffer(self._stream_re, self._stream_suffix) or + self._ProcessBuffer(self._empty_element_re) or + self._ProcessBuffer(self._non_empty_element_re)): + pass + + def _ProcessBuffer(self, regexp, xml_suffix=''): + """If the buffer matches the given regexp, removes the match from + the buffer, appends the given suffix, parses it, and feeds it to + the delegate. + + Returns: + Whether or not the buffer matched the given regexp. + """ + results = regexp.match(self._buffer) + if not results: + return False + xml_text = self._buffer[:results.end()] + xml_suffix + self._buffer = self._buffer[results.end():] + stanza = ParseXml(xml_text) + self._delegate.FeedStanza(stanza) + # Needed because stanza may have cycles. + stanza.unlink() + return True + + +class Jid(object): + """Simple struct for an XMPP jid (essentially an e-mail address with + an optional resource string). + """ + + def __init__(self, username, domain, resource=''): + self.username = username + self.domain = domain + self.resource = resource + + def __str__(self): + jid_str = "%s@%s" % (self.username, self.domain) + if self.resource: + jid_str += '/' + self.resource + return jid_str + + def GetBareJid(self): + return Jid(self.username, self.domain) + + +class IdGenerator(object): + """Simple class to generate unique IDs for XMPP messages.""" + + def __init__(self, prefix): + self._prefix = prefix + self._id = 0 + + def GetNextId(self): + next_id = "%s.%s" % (self._prefix, self._id) + self._id += 1 + return next_id + + +class HandshakeTask(object): + """Class to handle the initial handshake with a connected XMPP + client. + """ + + # The handshake states in order. + (_INITIAL_STREAM_NEEDED, + _AUTH_NEEDED, + _AUTH_STREAM_NEEDED, + _BIND_NEEDED, + _SESSION_NEEDED, + _FINISHED) = range(6) + + # Used when in the _INITIAL_STREAM_NEEDED and _AUTH_STREAM_NEEDED + # states. Not an XML object as it's only the opening tag. + # + # The from and id attributes are filled in later. + _STREAM_DATA = ( + '<stream:stream from="%s" id="%s" ' + 'version="1.0" xmlns:stream="http://etherx.jabber.org/streams" ' + 'xmlns="jabber:client">') + + # Used when in the _INITIAL_STREAM_NEEDED state. + _AUTH_STANZA = ParseXml( + '<stream:features xmlns:stream="http://etherx.jabber.org/streams">' + ' <mechanisms xmlns="urn:ietf:params:xml:ns:xmpp-sasl">' + ' <mechanism>PLAIN</mechanism>' + ' <mechanism>X-GOOGLE-TOKEN</mechanism>' + ' </mechanisms>' + '</stream:features>') + + # Used when in the _AUTH_NEEDED state. + _AUTH_SUCCESS_STANZA = ParseXml( + '<success xmlns="urn:ietf:params:xml:ns:xmpp-sasl"/>') + + # Used when in the _AUTH_STREAM_NEEDED state. + _BIND_STANZA = ParseXml( + '<stream:features xmlns:stream="http://etherx.jabber.org/streams">' + ' <bind xmlns="urn:ietf:params:xml:ns:xmpp-bind"/>' + ' <session xmlns="urn:ietf:params:xml:ns:xmpp-session"/>' + '</stream:features>') + + # Used when in the _BIND_NEEDED state. + # + # The id and jid attributes are filled in later. + _BIND_RESULT_STANZA = ParseXml( + '<iq id="" type="result">' + ' <bind xmlns="urn:ietf:params:xml:ns:xmpp-bind">' + ' <jid/>' + ' </bind>' + '</iq>') + + # Used when in the _SESSION_NEEDED state. + # + # The id attribute is filled in later. + _IQ_RESPONSE_STANZA = ParseXml('<iq id="" type="result"/>') + + def __init__(self, connection, id_generator, resource_prefix): + self._connection = connection + self._id_generator = id_generator + self._username = '' + self._domain = '' + self._jid = None + self._resource_prefix = resource_prefix + self._state = self._INITIAL_STREAM_NEEDED + + def FeedStanza(self, stanza): + """Inspects the given stanza and changes the handshake state if needed. + + Called when a stanza is received from the client. Inspects the + stanza to make sure it has the expected attributes given the + current state, advances the state if needed, and sends a reply to + the client if needed. + """ + def ExpectStanza(stanza, name): + if stanza.tagName != name: + raise UnexpectedXml(stanza) + + def ExpectIq(stanza, type, name): + ExpectStanza(stanza, 'iq') + if (stanza.getAttribute('type') != type or + stanza.firstChild.tagName != name): + raise UnexpectedXml(stanza) + + def GetStanzaId(stanza): + return stanza.getAttribute('id') + + def HandleStream(stanza): + ExpectStanza(stanza, 'stream:stream') + domain = stanza.getAttribute('to') + if domain: + self._domain = domain + SendStreamData() + + def SendStreamData(): + next_id = self._id_generator.GetNextId() + stream_data = self._STREAM_DATA % (self._domain, next_id) + self._connection.SendData(stream_data) + + def GetUserDomain(stanza): + encoded_username_password = stanza.firstChild.data + username_password = base64.b64decode(encoded_username_password) + (_, username_domain, _) = username_password.split('\0') + # The domain may be omitted. + # + # If we were using python 2.5, we'd be able to do: + # + # username, _, domain = username_domain.partition('@') + # if not domain: + # domain = self._domain + at_pos = username_domain.find('@') + if at_pos != -1: + username = username_domain[:at_pos] + domain = username_domain[at_pos+1:] + else: + username = username_domain + domain = self._domain + return (username, domain) + + if self._state == self._INITIAL_STREAM_NEEDED: + HandleStream(stanza) + self._connection.SendStanza(self._AUTH_STANZA, False) + self._state = self._AUTH_NEEDED + + elif self._state == self._AUTH_NEEDED: + ExpectStanza(stanza, 'auth') + (self._username, self._domain) = GetUserDomain(stanza) + self._connection.SendStanza(self._AUTH_SUCCESS_STANZA, False) + self._state = self._AUTH_STREAM_NEEDED + + elif self._state == self._AUTH_STREAM_NEEDED: + HandleStream(stanza) + self._connection.SendStanza(self._BIND_STANZA, False) + self._state = self._BIND_NEEDED + + elif self._state == self._BIND_NEEDED: + ExpectIq(stanza, 'set', 'bind') + stanza_id = GetStanzaId(stanza) + resource_element = stanza.getElementsByTagName('resource')[0] + resource = resource_element.firstChild.data + full_resource = '%s.%s' % (self._resource_prefix, resource) + response = CloneXml(self._BIND_RESULT_STANZA) + response.setAttribute('id', stanza_id) + self._jid = Jid(self._username, self._domain, full_resource) + jid_text = response.parentNode.createTextNode(str(self._jid)) + response.getElementsByTagName('jid')[0].appendChild(jid_text) + self._connection.SendStanza(response) + self._state = self._SESSION_NEEDED + + elif self._state == self._SESSION_NEEDED: + ExpectIq(stanza, 'set', 'session') + stanza_id = GetStanzaId(stanza) + xml = CloneXml(self._IQ_RESPONSE_STANZA) + xml.setAttribute('id', stanza_id) + self._connection.SendStanza(xml) + self._state = self._FINISHED + self._connection.HandshakeDone(self._jid) + + +def AddrString(addr): + return '%s:%d' % addr + + +class XmppConnection(asynchat.async_chat): + """A single XMPP client connection. + + This class handles the connection to a single XMPP client (via a + socket). It does the XMPP handshake and also implements the (old) + Google notification protocol. + """ + + # We use this XML template for subscription responses as well as + # notifications (conveniently enough, the same template works + # for both). + # + # The from, to, id, and type attributes are filled in later. + _NOTIFIER_STANZA = ParseXml( + """<iq from="" to="" id="" type=""> + <not:getAll xmlns:not="google:notifier"> + <Result xmlns=""/> + </not:getAll> + </iq> + """) + + def __init__(self, sock, socket_map, connections, addr): + """Starts up the xmpp connection. + + Args: + sock: The socket to the client. + socket_map: A map from sockets to their owning objects. + connections: The set of handshake-completed connections. + addr: The host/port of the client. + """ + asynchat.async_chat.__init__(self, sock) + self.set_terminator(None) + # async_chat in Python 2.4 has a bug where it ignores a + # socket_map argument. So we handle that ourselves. + self._socket_map = socket_map + self._socket_map[self.fileno()] = self + + self._connections = connections + self._parser = StanzaParser(self) + self._jid = None + + self._addr = addr + addr_str = AddrString(self._addr) + self._id_generator = IdGenerator(addr_str) + self._handshake_task = ( + HandshakeTask(self, self._id_generator, addr_str)) + print 'Starting connection to %s' % self + + def __str__(self): + if self._jid: + return str(self._jid) + else: + return AddrString(self._addr) + + # async_chat implementation. + + def collect_incoming_data(self, data): + self._parser.FeedString(data) + + # This is only here to make pychecker happy. + def found_terminator(self): + asynchat.async_chat.found_terminator(self) + + def handle_close(self): + print "Closing connection to %s" % self + # Remove ourselves from anywhere we possibly installed ourselves. + self._connections.discard(self) + del self._socket_map[self.fileno()] + + # Called by self._parser.FeedString(). + def FeedStanza(self, stanza): + if self._handshake_task: + self._handshake_task.FeedStanza(stanza) + elif stanza.tagName == 'iq': + self._HandleIq(stanza) + else: + raise UnexpectedXml(stanza) + + # Called by self._handshake_task. + def HandshakeDone(self, jid): + self._jid = jid + self._handshake_task = None + self._connections.add(self) + print "Handshake done for %s" % self + + def _HandleIq(self, iq): + if (iq.firstChild and + iq.firstChild.namespaceURI == 'google:notifier'): + iq_id = iq.getAttribute('id') + self._HandleNotifierCommand(iq_id, iq.firstChild) + elif iq.getAttribute('type') == 'result': + # Ignore all client acks. + pass + else: + raise UnexpectedXml(iq) + + def _HandleNotifierCommand(self, id, command_xml): + command = command_xml.tagName + if command == 'getAll': + # Subscription request. + if not command_xml.getElementsByTagName('SubscribedServiceUrl'): + raise UnexpectedXml(command_xml) + self._SendNotifierStanza(id, 'result') + elif command == 'set': + # Send notification request. + SendNotification(self._connections) + else: + raise UnexpectedXml(command_xml) + + def _SendNotifierStanza(self, id, type): + stanza = CloneXml(self._NOTIFIER_STANZA) + stanza.setAttribute('from', str(self._jid.GetBareJid())) + stanza.setAttribute('to', str(self._jid)) + stanza.setAttribute('id', id) + stanza.setAttribute('type', type) + self.SendStanza(stanza) + + def SendStanza(self, stanza, unlink=True): + """Sends a stanza to the client. + + Args: + stanza: The stanza to send. + unlink: Whether to unlink stanza after sending it. (Pass in + False if stanza is a constant.) + """ + self.SendData(stanza.toxml()) + if unlink: + stanza.unlink() + + def SendData(self, data): + """Sends raw data to the client. + """ + # We explicitly encode to ascii as that is what the client expects + # (some minidom library functions return unicode strings). + self.push(data.encode('ascii')) + + def SendNotification(self): + """Sends a notification to the client.""" + next_id = self._id_generator.GetNextId() + self._SendNotifierStanza(next_id, 'set') + + +def SendNotification(connections): + """Sends a notification to all connections in the given sequence.""" + for connection in connections: + print 'Sending notification to %s' % connection + connection.SendNotification() + + +class XmppServer(asyncore.dispatcher): + """The main XMPP server class. + + The XMPP server starts accepting connections on the given address + and spawns off XmppConnection objects for each one. + + Use like so: + + socket_map = {} + xmpp_server = xmppserver.XmppServer(socket_map, ('127.0.0.1', 5222)) + asyncore.loop(30.0, False, socket_map) + """ + + def __init__(self, socket_map, addr): + asyncore.dispatcher.__init__(self, None, socket_map) + self.create_socket(socket.AF_INET, socket.SOCK_STREAM) + self.set_reuse_addr() + self.bind(addr) + self.listen(5) + self._socket_map = socket_map + self._socket_map[self.fileno()] = self + self._connections = set() + print 'XMPP server running at %s' % AddrString(addr) + + def handle_accept(self): + (sock, addr) = self.accept() + XmppConnection(sock, self._socket_map, self._connections, addr) diff --git a/net/tools/testserver/xmppserver_test.py b/net/tools/testserver/xmppserver_test.py new file mode 100644 index 0000000..e033a69 --- /dev/null +++ b/net/tools/testserver/xmppserver_test.py @@ -0,0 +1,250 @@ +#!/usr/bin/python2.4 +# Copyright (c) 2010 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. + +"""Tests exercising the various classes in xmppserver.py.""" + +import unittest + +import base64 +import xmppserver + +class XmlUtilsTest(unittest.TestCase): + + def testParseXml(self): + xml_text = """<foo xmlns=""><bar xmlns=""><baz/></bar></foo>""" + xml = xmppserver.ParseXml(xml_text) + self.assertEqual(xml.toxml(), xml_text) + + def testCloneXml(self): + xml = xmppserver.ParseXml('<foo/>') + xml_clone = xmppserver.CloneXml(xml) + xml_clone.setAttribute('bar', 'baz') + self.assertEqual(xml, xml) + self.assertEqual(xml_clone, xml_clone) + self.assertNotEqual(xml, xml_clone) + + def testCloneXmlUnlink(self): + xml_text = '<foo/>' + xml = xmppserver.ParseXml(xml_text) + xml_clone = xmppserver.CloneXml(xml) + xml.unlink() + self.assertEqual(xml.parentNode, None) + self.assertNotEqual(xml_clone.parentNode, None) + self.assertEqual(xml_clone.toxml(), xml_text) + +class StanzaParserTest(unittest.TestCase): + + def setUp(self): + self.stanzas = [] + + def FeedStanza(self, stanza): + # We can't append stanza directly because it is unlinked after + # this callback. + self.stanzas.append(stanza.toxml()) + + def testBasic(self): + parser = xmppserver.StanzaParser(self) + parser.FeedString('<foo') + self.assertEqual(len(self.stanzas), 0) + parser.FeedString('/><bar></bar>') + self.assertEqual(self.stanzas[0], '<foo/>') + self.assertEqual(self.stanzas[1], '<bar/>') + + def testStream(self): + parser = xmppserver.StanzaParser(self) + parser.FeedString('<stream') + self.assertEqual(len(self.stanzas), 0) + parser.FeedString(':stream foo="bar" xmlns:stream="baz">') + self.assertEqual(self.stanzas[0], + '<stream:stream foo="bar" xmlns:stream="baz"/>') + + def testNested(self): + parser = xmppserver.StanzaParser(self) + parser.FeedString('<foo') + self.assertEqual(len(self.stanzas), 0) + parser.FeedString(' bar="baz"') + parser.FeedString('><baz/><blah>meh</blah></foo>') + self.assertEqual(self.stanzas[0], + '<foo bar="baz"><baz/><blah>meh</blah></foo>') + + +class JidTest(unittest.TestCase): + + def testBasic(self): + jid = xmppserver.Jid('foo', 'bar.com') + self.assertEqual(str(jid), 'foo@bar.com') + + def testResource(self): + jid = xmppserver.Jid('foo', 'bar.com', 'resource') + self.assertEqual(str(jid), 'foo@bar.com/resource') + + def testGetBareJid(self): + jid = xmppserver.Jid('foo', 'bar.com', 'resource') + self.assertEqual(str(jid.GetBareJid()), 'foo@bar.com') + + +class IdGeneratorTest(unittest.TestCase): + + def testBasic(self): + id_generator = xmppserver.IdGenerator('foo') + for i in xrange(0, 100): + self.assertEqual('foo.%d' % i, id_generator.GetNextId()) + + +class HandshakeTaskTest(unittest.TestCase): + + def setUp(self): + self.data_received = 0 + + def SendData(self, _): + self.data_received += 1 + + def SendStanza(self, _, unused=True): + self.data_received += 1 + + def HandshakeDone(self, jid): + self.jid = jid + + def DoHandshake(self, resource_prefix, resource, username, + initial_stream_domain, auth_domain, auth_stream_domain): + self.data_received = 0 + id_generator = xmppserver.IdGenerator('foo') + handshake_task = ( + xmppserver.HandshakeTask(self, id_generator, resource_prefix)) + stream_xml = xmppserver.ParseXml('<stream:stream xmlns:stream="foo"/>') + stream_xml.setAttribute('to', initial_stream_domain) + self.assertEqual(self.data_received, 0) + handshake_task.FeedStanza(stream_xml) + self.assertEqual(self.data_received, 2) + + if auth_domain: + username_domain = '%s@%s' % (username, auth_domain) + else: + username_domain = username + auth_string = base64.b64encode('\0%s\0bar' % username_domain) + auth_xml = xmppserver.ParseXml('<auth>%s</auth>'% auth_string) + handshake_task.FeedStanza(auth_xml) + self.assertEqual(self.data_received, 3) + + stream_xml = xmppserver.ParseXml('<stream:stream xmlns:stream="foo"/>') + stream_xml.setAttribute('to', auth_stream_domain) + handshake_task.FeedStanza(stream_xml) + self.assertEqual(self.data_received, 5) + + bind_xml = xmppserver.ParseXml( + '<iq type="set"><bind><resource>%s</resource></bind></iq>' % resource) + handshake_task.FeedStanza(bind_xml) + self.assertEqual(self.data_received, 6) + + session_xml = xmppserver.ParseXml( + '<iq type="set"><session></session></iq>') + handshake_task.FeedStanza(session_xml) + self.assertEqual(self.data_received, 7) + + self.assertEqual(self.jid.username, username) + self.assertEqual(self.jid.domain, + auth_stream_domain or auth_domain or + initial_stream_domain) + self.assertEqual(self.jid.resource, + '%s.%s' % (resource_prefix, resource)) + + def testBasic(self): + self.DoHandshake('resource_prefix', 'resource', + 'foo', 'bar.com', 'baz.com', 'quux.com') + + def testDomainBehavior(self): + self.DoHandshake('resource_prefix', 'resource', + 'foo', 'bar.com', 'baz.com', 'quux.com') + self.DoHandshake('resource_prefix', 'resource', + 'foo', 'bar.com', 'baz.com', '') + self.DoHandshake('resource_prefix', 'resource', + 'foo', 'bar.com', '', '') + self.DoHandshake('resource_prefix', 'resource', + 'foo', '', '', '') + + +class XmppConnectionTest(unittest.TestCase): + + def setUp(self): + self.data = [] + + # socket-like methods. + def fileno(self): + return 0 + + def setblocking(self, int): + pass + + def getpeername(self): + return ('', 0) + + def send(self, data): + self.data.append(data) + pass + + def testBasic(self): + connections = set() + xmpp_connection = xmppserver.XmppConnection( + self, {}, connections, ('', 0)) + self.assertEqual(len(connections), 0) + xmpp_connection.HandshakeDone(xmppserver.Jid('foo', 'bar')) + self.assertEqual(len(connections), 1) + + # Test subscription request. + self.assertEqual(len(self.data), 0) + xmpp_connection.collect_incoming_data( + '<iq><getAll xmlns="google:notifier">' + '<SubscribedServiceUrl/></getAll></iq>') + self.assertEqual(len(self.data), 1) + + # Test acks. + xmpp_connection.collect_incoming_data('<iq type="result"/>') + self.assertEqual(len(self.data), 1) + + # Test notification. + xmpp_connection.collect_incoming_data( + '<iq><set xmlns="google:notifier"/></iq>') + self.assertEqual(len(self.data), 2) + + # Test unexpected stanza. + def SendUnexpectedStanza(): + xmpp_connection.collect_incoming_data('<foo/>') + self.assertRaises(xmppserver.UnexpectedXml, SendUnexpectedStanza) + + # Test unexpected notifier command. + def SendUnexpectedNotifierCommand(): + xmpp_connection.collect_incoming_data( + '<iq><foo xmlns="google:notifier"/></iq>') + self.assertRaises(xmppserver.UnexpectedXml, + SendUnexpectedNotifierCommand) + + +class XmppServerTest(unittest.TestCase): + + # socket-like methods. + def fileno(self): + return 0 + + def setblocking(self, int): + pass + + def getpeername(self): + return ('', 0) + + def testBasic(self): + class FakeXmppServer(xmppserver.XmppServer): + def accept(self2): + return (self, ('', 0)) + + socket_map = {} + self.assertEqual(len(socket_map), 0) + xmpp_server = FakeXmppServer(socket_map, ('', 0)) + self.assertEqual(len(socket_map), 1) + xmpp_server.handle_accept() + self.assertEqual(len(socket_map), 2) + + +if __name__ == '__main__': + unittest.main() diff --git a/net/url_request/url_request.cc b/net/url_request/url_request.cc index c8dd874..c4f20c4 100644 --- a/net/url_request/url_request.cc +++ b/net/url_request/url_request.cc @@ -315,8 +315,8 @@ void URLRequest::StartJob(URLRequestJob* job) { net_log_.BeginEvent( net::NetLog::TYPE_URL_REQUEST_START_JOB, - new URLRequestStartEventParameters( - url_, method_, load_flags_, priority_)); + make_scoped_refptr(new URLRequestStartEventParameters( + url_, method_, load_flags_, priority_))); job_ = job; job_->SetExtraRequestHeaders(extra_request_headers_); @@ -493,8 +493,8 @@ int URLRequest::Redirect(const GURL& location, int http_status_code) { if (net_log_.IsLoggingAllEvents()) { net_log_.AddEvent( net::NetLog::TYPE_URL_REQUEST_REDIRECTED, - new net::NetLogStringParameter( - "location", location.possibly_invalid_spec())); + make_scoped_refptr(new net::NetLogStringParameter( + "location", location.possibly_invalid_spec()))); } if (redirect_limit_ <= 0) { DVLOG(1) << "disallowing redirect: exceeds limit"; diff --git a/net/url_request/url_request.h b/net/url_request/url_request.h index 31b732e..f573111 100644 --- a/net/url_request/url_request.h +++ b/net/url_request/url_request.h @@ -10,7 +10,7 @@ #include <string> #include <vector> -#include "base/leak_tracker.h" +#include "base/debug/leak_tracker.h" #include "base/linked_ptr.h" #include "base/logging.h" #include "base/non_thread_safe.h" @@ -634,7 +634,7 @@ class URLRequest : public NonThreadSafe { // this to determine which URLRequest to allocate sockets to first. net::RequestPriority priority_; - base::LeakTracker<URLRequest> leak_tracker_; + base::debug::LeakTracker<URLRequest> leak_tracker_; DISALLOW_COPY_AND_ASSIGN(URLRequest); }; diff --git a/net/url_request/url_request_file_job.cc b/net/url_request/url_request_file_job.cc index 8c282ff..fff85c3 100644 --- a/net/url_request/url_request_file_job.cc +++ b/net/url_request/url_request_file_job.cc @@ -23,6 +23,7 @@ #include "base/message_loop.h" #include "base/platform_file.h" #include "base/string_util.h" +#include "base/thread_restrictions.h" #include "build/build_config.h" #include "googleurl/src/gurl.h" #include "net/base/io_buffer.h" @@ -128,8 +129,15 @@ void URLRequestFileJob::Start() { return; } #endif + + // URL requests should not block on the disk! + // http://code.google.com/p/chromium/issues/detail?id=59849 + bool exists; base::PlatformFileInfo file_info; - bool exists = file_util::GetFileInfo(file_path_, &file_info); + { + base::ThreadRestrictions::ScopedAllowIO allow_io; + exists = file_util::GetFileInfo(file_path_, &file_info); + } // Continue asynchronously. MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod( @@ -195,6 +203,10 @@ bool URLRequestFileJob::GetContentEncodings( } bool URLRequestFileJob::GetMimeType(std::string* mime_type) const { + // URL requests should not block on the disk! On Windows this goes to the + // registry. + // http://code.google.com/p/chromium/issues/detail?id=59849 + base::ThreadRestrictions::ScopedAllowIO allow_io; DCHECK(request_); return net::GetMimeTypeFromFile(file_path_, mime_type); } @@ -244,6 +256,10 @@ void URLRequestFileJob::DidResolve( if (!exists) { rv = net::ERR_FILE_NOT_FOUND; } else if (!is_directory_) { + // URL requests should not block on the disk! + // http://code.google.com/p/chromium/issues/detail?id=59849 + base::ThreadRestrictions::ScopedAllowIO allow_io; + int flags = base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ | base::PLATFORM_FILE_ASYNC; diff --git a/net/url_request/url_request_file_job.h b/net/url_request/url_request_file_job.h index adf9d24..c5e1d2f 100644 --- a/net/url_request/url_request_file_job.h +++ b/net/url_request/url_request_file_job.h @@ -1,4 +1,4 @@ -// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved. +// Copyright (c) 2010 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. @@ -7,6 +7,7 @@ #pragma once #include <string> +#include <vector> #include "base/file_path.h" #include "net/base/completion_callback.h" diff --git a/net/url_request/url_request_ftp_job.cc b/net/url_request/url_request_ftp_job.cc index 37d6ab0..aec8248 100644 --- a/net/url_request/url_request_ftp_job.cc +++ b/net/url_request/url_request_ftp_job.cc @@ -82,7 +82,7 @@ void URLRequestFtpJob::GetAuthChallengeInfo( scoped_refptr<net::AuthChallengeInfo>* result) { DCHECK((server_auth_ != NULL) && (server_auth_->state == net::AUTH_STATE_NEED_AUTH)); - scoped_refptr<net::AuthChallengeInfo> auth_info = new net::AuthChallengeInfo; + scoped_refptr<net::AuthChallengeInfo> auth_info(new net::AuthChallengeInfo); auth_info->is_proxy = false; auth_info->host_and_port = ASCIIToWide( net::GetHostAndPort(request_->url())); diff --git a/net/url_request/url_request_job.cc b/net/url_request/url_request_job.cc index 2a4d036..a059a00 100644 --- a/net/url_request/url_request_job.cc +++ b/net/url_request/url_request_job.cc @@ -452,7 +452,7 @@ void URLRequestJob::NotifyHeadersComplete() { // check the request pointer to see if it still exists, and return // immediately if it has been destroyed. self_preservation ensures our // survival until we can get out of this method. - scoped_refptr<URLRequestJob> self_preservation = this; + scoped_refptr<URLRequestJob> self_preservation(this); GURL new_location; int http_status_code; @@ -558,7 +558,7 @@ void URLRequestJob::NotifyReadComplete(int bytes_read) { // check the request pointer to see if it still exists, and return // immediately if it has been destroyed. self_preservation ensures our // survival until we can get out of this method. - scoped_refptr<URLRequestJob> self_preservation = this; + scoped_refptr<URLRequestJob> self_preservation(this); prefilter_bytes_read_ += bytes_read; if (filter_.get()) { diff --git a/net/url_request/url_request_unittest.cc b/net/url_request/url_request_unittest.cc index 3c5d05f..d0f488d 100644 --- a/net/url_request/url_request_unittest.cc +++ b/net/url_request/url_request_unittest.cc @@ -69,7 +69,7 @@ bool ContainsString(const std::string& haystack, const char* needle) { haystack.end(), needle, needle + strlen(needle), - CaseInsensitiveCompare<char>()); + base::CaseInsensitiveCompare<char>()); return it != haystack.end(); } @@ -89,7 +89,7 @@ void FillBuffer(char* buffer, size_t len) { } scoped_refptr<net::UploadData> CreateSimpleUploadData(const char* data) { - scoped_refptr<net::UploadData> upload = new net::UploadData; + scoped_refptr<net::UploadData> upload(new net::UploadData); upload->AppendBytes(data, strlen(data)); return upload; } @@ -146,7 +146,7 @@ class URLRequestTestHTTP : public URLRequestTest { } uploadBytes[kMsgSize] = '\0'; - scoped_refptr<URLRequestContext> context = new TestURLRequestContext(); + scoped_refptr<URLRequestContext> context(new TestURLRequestContext()); for (int i = 0; i < kIterations; ++i) { TestDelegate d; @@ -310,7 +310,9 @@ TEST_F(HTTPSRequestTest, HTTPSGetTest) { } TEST_F(HTTPSRequestTest, HTTPSMismatchedTest) { - net::TestServer test_server(net::TestServer::TYPE_HTTPS_MISMATCHED_HOSTNAME, + net::TestServer::HTTPSOptions https_options( + net::TestServer::HTTPSOptions::CERT_MISMATCHED_NAME); + net::TestServer test_server(https_options, FilePath(FILE_PATH_LITERAL("net/data/ssl"))); ASSERT_TRUE(test_server.Start()); @@ -340,7 +342,9 @@ TEST_F(HTTPSRequestTest, HTTPSMismatchedTest) { } TEST_F(HTTPSRequestTest, HTTPSExpiredTest) { - net::TestServer test_server(net::TestServer::TYPE_HTTPS_EXPIRED_CERTIFICATE, + net::TestServer::HTTPSOptions https_options( + net::TestServer::HTTPSOptions::CERT_EXPIRED); + net::TestServer test_server(https_options, FilePath(FILE_PATH_LITERAL("net/data/ssl"))); ASSERT_TRUE(test_server.Start()); @@ -398,7 +402,9 @@ class SSLClientAuthTestDelegate : public TestDelegate { // - Getting a certificate request in an SSL renegotiation sending the // HTTP request. TEST_F(HTTPSRequestTest, ClientAuthTest) { - net::TestServer test_server(net::TestServer::TYPE_HTTPS_CLIENT_AUTH, + net::TestServer::HTTPSOptions https_options; + https_options.request_client_certificate = true; + net::TestServer test_server(https_options, FilePath(FILE_PATH_LITERAL("net/data/ssl"))); ASSERT_TRUE(test_server.Start()); @@ -521,7 +527,7 @@ TEST_F(URLRequestTestHTTP, CancelTest4) { TEST_F(URLRequestTestHTTP, CancelTest5) { ASSERT_TRUE(test_server_.Start()); - scoped_refptr<URLRequestContext> context = new TestURLRequestContext(); + scoped_refptr<URLRequestContext> context(new TestURLRequestContext()); // populate cache { @@ -1128,7 +1134,7 @@ TEST_F(URLRequestTestHTTP, CancelDeferredRedirect) { TEST_F(URLRequestTestHTTP, VaryHeader) { ASSERT_TRUE(test_server_.Start()); - scoped_refptr<URLRequestContext> context = new TestURLRequestContext(); + scoped_refptr<URLRequestContext> context(new TestURLRequestContext()); // populate the cache { @@ -1174,7 +1180,7 @@ TEST_F(URLRequestTestHTTP, VaryHeader) { TEST_F(URLRequestTestHTTP, BasicAuth) { ASSERT_TRUE(test_server_.Start()); - scoped_refptr<URLRequestContext> context = new TestURLRequestContext(); + scoped_refptr<URLRequestContext> context(new TestURLRequestContext()); // populate the cache { @@ -1224,7 +1230,7 @@ TEST_F(URLRequestTestHTTP, BasicAuthWithCookies) { // Request a page that will give a 401 containing a Set-Cookie header. // Verify that when the transaction is restarted, it includes the new cookie. { - scoped_refptr<URLRequestContext> context = new TestURLRequestContext(); + scoped_refptr<URLRequestContext> context(new TestURLRequestContext()); TestDelegate d; d.set_username(kUser); d.set_password(kSecret); @@ -1245,7 +1251,7 @@ TEST_F(URLRequestTestHTTP, BasicAuthWithCookies) { // Same test as above, except this time the restart is initiated earlier // (without user intervention since identity is embedded in the URL). { - scoped_refptr<URLRequestContext> context = new TestURLRequestContext(); + scoped_refptr<URLRequestContext> context(new TestURLRequestContext()); TestDelegate d; GURL::Replacements replacements; @@ -1273,7 +1279,7 @@ TEST_F(URLRequestTest, DoNotSendCookies) { net::TestServer test_server(net::TestServer::TYPE_HTTP, FilePath()); ASSERT_TRUE(test_server.Start()); - scoped_refptr<URLRequestContext> context = new TestURLRequestContext(); + scoped_refptr<URLRequestContext> context(new TestURLRequestContext()); // Set up a cookie. { @@ -1322,7 +1328,7 @@ TEST_F(URLRequestTest, DoNotSaveCookies) { net::TestServer test_server(net::TestServer::TYPE_HTTP, FilePath()); ASSERT_TRUE(test_server.Start()); - scoped_refptr<URLRequestContext> context = new TestURLRequestContext(); + scoped_refptr<URLRequestContext> context(new TestURLRequestContext()); // Set up a cookie. { @@ -1378,7 +1384,7 @@ TEST_F(URLRequestTest, DoNotSendCookies_ViaPolicy) { net::TestServer test_server(net::TestServer::TYPE_HTTP, FilePath()); ASSERT_TRUE(test_server.Start()); - scoped_refptr<TestURLRequestContext> context = new TestURLRequestContext(); + scoped_refptr<TestURLRequestContext> context(new TestURLRequestContext()); // Set up a cookie. { @@ -1432,7 +1438,7 @@ TEST_F(URLRequestTest, DoNotSaveCookies_ViaPolicy) { net::TestServer test_server(net::TestServer::TYPE_HTTP, FilePath()); ASSERT_TRUE(test_server.Start()); - scoped_refptr<TestURLRequestContext> context = new TestURLRequestContext(); + scoped_refptr<TestURLRequestContext> context(new TestURLRequestContext()); // Set up a cookie. { @@ -1489,7 +1495,7 @@ TEST_F(URLRequestTest, DoNotSaveEmptyCookies) { net::TestServer test_server(net::TestServer::TYPE_HTTP, FilePath()); ASSERT_TRUE(test_server.Start()); - scoped_refptr<TestURLRequestContext> context = new TestURLRequestContext(); + scoped_refptr<TestURLRequestContext> context(new TestURLRequestContext()); // Set up an empty cookie. { @@ -1509,7 +1515,7 @@ TEST_F(URLRequestTest, DoNotSendCookies_ViaPolicy_Async) { net::TestServer test_server(net::TestServer::TYPE_HTTP, FilePath()); ASSERT_TRUE(test_server.Start()); - scoped_refptr<TestURLRequestContext> context = new TestURLRequestContext(); + scoped_refptr<TestURLRequestContext> context(new TestURLRequestContext()); // Set up a cookie. { @@ -1564,7 +1570,7 @@ TEST_F(URLRequestTest, DoNotSaveCookies_ViaPolicy_Async) { net::TestServer test_server(net::TestServer::TYPE_HTTP, FilePath()); ASSERT_TRUE(test_server.Start()); - scoped_refptr<TestURLRequestContext> context = new TestURLRequestContext(); + scoped_refptr<TestURLRequestContext> context(new TestURLRequestContext()); // Set up a cookie. { @@ -1621,7 +1627,7 @@ TEST_F(URLRequestTest, CancelTest_During_CookiePolicy) { net::TestServer test_server(net::TestServer::TYPE_HTTP, FilePath()); ASSERT_TRUE(test_server.Start()); - scoped_refptr<TestURLRequestContext> context = new TestURLRequestContext(); + scoped_refptr<TestURLRequestContext> context(new TestURLRequestContext()); TestCookiePolicy cookie_policy(TestCookiePolicy::ASYNC); context->set_cookie_policy(&cookie_policy); @@ -1652,7 +1658,7 @@ TEST_F(URLRequestTest, CancelTest_During_OnGetCookies) { net::TestServer test_server(net::TestServer::TYPE_HTTP, FilePath()); ASSERT_TRUE(test_server.Start()); - scoped_refptr<TestURLRequestContext> context = new TestURLRequestContext(); + scoped_refptr<TestURLRequestContext> context(new TestURLRequestContext()); TestCookiePolicy cookie_policy(TestCookiePolicy::NO_GET_COOKIES); context->set_cookie_policy(&cookie_policy); @@ -1681,7 +1687,7 @@ TEST_F(URLRequestTest, CancelTest_During_OnSetCookie) { net::TestServer test_server(net::TestServer::TYPE_HTTP, FilePath()); ASSERT_TRUE(test_server.Start()); - scoped_refptr<TestURLRequestContext> context = new TestURLRequestContext(); + scoped_refptr<TestURLRequestContext> context(new TestURLRequestContext()); TestCookiePolicy cookie_policy(TestCookiePolicy::NO_SET_COOKIE); context->set_cookie_policy(&cookie_policy); @@ -1715,7 +1721,7 @@ TEST_F(URLRequestTest, CookiePolicy_ForceSession) { net::TestServer test_server(net::TestServer::TYPE_HTTP, FilePath()); ASSERT_TRUE(test_server.Start()); - scoped_refptr<TestURLRequestContext> context = new TestURLRequestContext(); + scoped_refptr<TestURLRequestContext> context(new TestURLRequestContext()); TestCookiePolicy cookie_policy(TestCookiePolicy::FORCE_SESSION); context->set_cookie_policy(&cookie_policy); diff --git a/net/url_request/url_request_unittest.h b/net/url_request/url_request_unittest.h index 2a3ae41..abb6ab5 100644 --- a/net/url_request/url_request_unittest.h +++ b/net/url_request/url_request_unittest.h @@ -126,7 +126,7 @@ class TestURLRequestContext : public URLRequestContext { TestURLRequestContext() { host_resolver_ = net::CreateSystemHostResolver(net::HostResolver::kDefaultParallelism, - NULL); + NULL, NULL); proxy_service_ = net::ProxyService::CreateDirect(); Init(); } @@ -134,7 +134,7 @@ class TestURLRequestContext : public URLRequestContext { explicit TestURLRequestContext(const std::string& proxy) { host_resolver_ = net::CreateSystemHostResolver(net::HostResolver::kDefaultParallelism, - NULL); + NULL, NULL); net::ProxyConfig proxy_config; proxy_config.proxy_rules().ParseFromString(proxy); proxy_service_ = net::ProxyService::CreateFixed(proxy_config); diff --git a/net/url_request/view_cache_helper_unittest.cc b/net/url_request/view_cache_helper_unittest.cc index e82ff15..5338ee5 100644 --- a/net/url_request/view_cache_helper_unittest.cc +++ b/net/url_request/view_cache_helper_unittest.cc @@ -40,8 +40,8 @@ void WriteHeaders(disk_cache::Entry* entry, int flags, const std::string data) { pickle.WriteInt64(0); pickle.WriteString(data); - scoped_refptr<net::WrappedIOBuffer> buf = new net::WrappedIOBuffer( - reinterpret_cast<const char*>(pickle.data())); + scoped_refptr<net::WrappedIOBuffer> buf(new net::WrappedIOBuffer( + reinterpret_cast<const char*>(pickle.data()))); int len = static_cast<int>(pickle.size()); TestCompletionCallback cb; diff --git a/net/websockets/websocket.cc b/net/websockets/websocket.cc index 3bf1da8..f8d9eb9 100644 --- a/net/websockets/websocket.cc +++ b/net/websockets/websocket.cc @@ -80,7 +80,7 @@ void WebSocket::Send(const std::string& msg) { *p = '\0'; memcpy(p + 1, msg.data(), msg.size()); *(p + 1 + msg.size()) = '\xff'; - pending_write_bufs_.push_back(buf); + pending_write_bufs_.push_back(make_scoped_refptr(buf)); SendPending(); } @@ -172,7 +172,7 @@ void WebSocket::OnConnected(SocketStream* socket_stream, const std::string msg = handshake_->CreateClientHandshakeMessage(); IOBufferWithSize* buf = new IOBufferWithSize(msg.size()); memcpy(buf->data(), msg.data(), msg.size()); - pending_write_bufs_.push_back(buf); + pending_write_bufs_.push_back(make_scoped_refptr(buf)); origin_loop_->PostTask(FROM_HERE, NewRunnableMethod(this, &WebSocket::SendPending)); } @@ -430,7 +430,7 @@ void WebSocket::StartClosingHandshake() { client_closing_handshake_ = true; IOBufferWithSize* buf = new IOBufferWithSize(2); memcpy(buf->data(), kClosingFrame, 2); - pending_write_bufs_.push_back(buf); + pending_write_bufs_.push_back(make_scoped_refptr(buf)); SendPending(); } diff --git a/net/websockets/websocket_job.cc b/net/websockets/websocket_job.cc index 64af45b..a1e2dde 100644 --- a/net/websockets/websocket_job.cc +++ b/net/websockets/websocket_job.cc @@ -313,7 +313,8 @@ void WebSocketJob::OnCanGetCookiesCompleted(int policy) { handshake_request_sent_ = 0; socket_->net_log()->AddEvent( NetLog::TYPE_WEB_SOCKET_SEND_REQUEST_HEADERS, - new NetLogWebSocketHandshakeParameter(handshake_request)); + make_scoped_refptr( + new NetLogWebSocketHandshakeParameter(handshake_request))); socket_->SendData(handshake_request.data(), handshake_request.size()); } @@ -354,8 +355,8 @@ void WebSocketJob::OnReceivedHandshakeResponse( // handshake message is completed. socket_->net_log()->AddEvent( NetLog::TYPE_WEB_SOCKET_READ_RESPONSE_HEADERS, - new NetLogWebSocketHandshakeParameter( - handshake_response_->GetRawResponse())); + make_scoped_refptr(new NetLogWebSocketHandshakeParameter( + handshake_response_->GetRawResponse()))); if (len - response_length > 0) { // If we received extra data, it should be frame data. receive_frame_handler_->AppendData(data + response_length, diff --git a/net/websockets/websocket_throttle_unittest.cc b/net/websockets/websocket_throttle_unittest.cc index c4bf59f..7eb18fa 100644 --- a/net/websockets/websocket_throttle_unittest.cc +++ b/net/websockets/websocket_throttle_unittest.cc @@ -83,9 +83,9 @@ TEST_F(WebSocketThrottleTest, Throttle) { struct addrinfo* addr = AddAddr(1, 2, 3, 4, NULL); addr = AddAddr(1, 2, 3, 5, addr); addr = AddAddr(1, 2, 3, 6, addr); - scoped_refptr<WebSocketJob> w1 = new WebSocketJob(&delegate); - scoped_refptr<SocketStream> s1 = - new SocketStream(GURL("ws://host1/"), w1.get()); + scoped_refptr<WebSocketJob> w1(new WebSocketJob(&delegate)); + scoped_refptr<SocketStream> s1( + new SocketStream(GURL("ws://host1/"), w1.get())); w1->InitSocketStream(s1.get()); WebSocketThrottleTest::MockSocketStreamConnect(s1, addr); DeleteAddrInfo(addr); @@ -103,9 +103,9 @@ TEST_F(WebSocketThrottleTest, Throttle) { // For host2: 1.2.3.4 addr = AddAddr(1, 2, 3, 4, NULL); - scoped_refptr<WebSocketJob> w2 = new WebSocketJob(&delegate); - scoped_refptr<SocketStream> s2 = - new SocketStream(GURL("ws://host2/"), w2.get()); + scoped_refptr<WebSocketJob> w2(new WebSocketJob(&delegate)); + scoped_refptr<SocketStream> s2( + new SocketStream(GURL("ws://host2/"), w2.get())); w2->InitSocketStream(s2.get()); WebSocketThrottleTest::MockSocketStreamConnect(s2, addr); DeleteAddrInfo(addr); @@ -122,9 +122,9 @@ TEST_F(WebSocketThrottleTest, Throttle) { // For host3: 1.2.3.5 addr = AddAddr(1, 2, 3, 5, NULL); - scoped_refptr<WebSocketJob> w3 = new WebSocketJob(&delegate); - scoped_refptr<SocketStream> s3 = - new SocketStream(GURL("ws://host3/"), w3.get()); + scoped_refptr<WebSocketJob> w3(new WebSocketJob(&delegate)); + scoped_refptr<SocketStream> s3( + new SocketStream(GURL("ws://host3/"), w3.get())); w3->InitSocketStream(s3.get()); WebSocketThrottleTest::MockSocketStreamConnect(s3, addr); DeleteAddrInfo(addr); @@ -141,9 +141,9 @@ TEST_F(WebSocketThrottleTest, Throttle) { // For host4: 1.2.3.4, 1.2.3.6 addr = AddAddr(1, 2, 3, 4, NULL); addr = AddAddr(1, 2, 3, 6, addr); - scoped_refptr<WebSocketJob> w4 = new WebSocketJob(&delegate); - scoped_refptr<SocketStream> s4 = - new SocketStream(GURL("ws://host4/"), w4.get()); + scoped_refptr<WebSocketJob> w4(new WebSocketJob(&delegate)); + scoped_refptr<SocketStream> s4( + new SocketStream(GURL("ws://host4/"), w4.get())); w4->InitSocketStream(s4.get()); WebSocketThrottleTest::MockSocketStreamConnect(s4, addr); DeleteAddrInfo(addr); @@ -159,9 +159,9 @@ TEST_F(WebSocketThrottleTest, Throttle) { // For host5: 1.2.3.6 addr = AddAddr(1, 2, 3, 6, NULL); - scoped_refptr<WebSocketJob> w5 = new WebSocketJob(&delegate); - scoped_refptr<SocketStream> s5 = - new SocketStream(GURL("ws://host5/"), w5.get()); + scoped_refptr<WebSocketJob> w5(new WebSocketJob(&delegate)); + scoped_refptr<SocketStream> s5( + new SocketStream(GURL("ws://host5/"), w5.get())); w5->InitSocketStream(s5.get()); WebSocketThrottleTest::MockSocketStreamConnect(s5, addr); DeleteAddrInfo(addr); @@ -177,9 +177,9 @@ TEST_F(WebSocketThrottleTest, Throttle) { // For host6: 1.2.3.6 addr = AddAddr(1, 2, 3, 6, NULL); - scoped_refptr<WebSocketJob> w6 = new WebSocketJob(&delegate); - scoped_refptr<SocketStream> s6 = - new SocketStream(GURL("ws://host6/"), w6.get()); + scoped_refptr<WebSocketJob> w6(new WebSocketJob(&delegate)); + scoped_refptr<SocketStream> s6( + new SocketStream(GURL("ws://host6/"), w6.get())); w6->InitSocketStream(s6.get()); WebSocketThrottleTest::MockSocketStreamConnect(s6, addr); DeleteAddrInfo(addr); @@ -286,9 +286,9 @@ TEST_F(WebSocketThrottleTest, NoThrottleForDuplicateAddress) { // For localhost: 127.0.0.1, 127.0.0.1 struct addrinfo* addr = AddAddr(127, 0, 0, 1, NULL); addr = AddAddr(127, 0, 0, 1, addr); - scoped_refptr<WebSocketJob> w1 = new WebSocketJob(&delegate); - scoped_refptr<SocketStream> s1 = - new SocketStream(GURL("ws://localhost/"), w1.get()); + scoped_refptr<WebSocketJob> w1(new WebSocketJob(&delegate)); + scoped_refptr<SocketStream> s1( + new SocketStream(GURL("ws://localhost/"), w1.get())); w1->InitSocketStream(s1.get()); WebSocketThrottleTest::MockSocketStreamConnect(s1, addr); DeleteAddrInfo(addr); |
