1 // Copyright (c) 2008 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "base/string_util.h" 6 #include "net/http/http_auth_cache.h" 7 8 #include "testing/gtest/include/gtest/gtest.h" 9 10 namespace net { 11 12 namespace { 13 14 class MockAuthHandler : public HttpAuthHandler { 15 public: 16 MockAuthHandler(const char* scheme, const std::string& realm, 17 HttpAuth::Target target) { 18 // Can't use initializer list since these are members of the base class. 19 scheme_ = scheme; 20 realm_ = realm; 21 score_ = 1; 22 target_ = target; 23 properties_ = 0; 24 } 25 26 virtual std::string GenerateCredentials(const std::wstring&, 27 const std::wstring&, 28 const HttpRequestInfo*, 29 const ProxyInfo*) { 30 return "mock-credentials"; // Unused. 31 } 32 33 protected: 34 virtual bool Init(std::string::const_iterator, std::string::const_iterator) { 35 return false; // Unused. 36 } 37 38 private: 39 ~MockAuthHandler() {} 40 }; 41 42 } // namespace 43 44 // Test adding and looking-up cache entries (both by realm and by path). 45 TEST(HttpAuthCacheTest, Basic) { 46 GURL origin("http://www.google.com"); 47 HttpAuthCache cache; 48 HttpAuthCache::Entry* entry; 49 50 // Add cache entries for 3 realms: "Realm1", "Realm2", "Realm3" 51 52 scoped_refptr<HttpAuthHandler> realm1_handler = 53 new MockAuthHandler("basic", "Realm1", HttpAuth::AUTH_SERVER); 54 cache.Add(origin, realm1_handler, L"realm1-user", L"realm1-password", 55 "/foo/bar/index.html"); 56 57 scoped_refptr<HttpAuthHandler> realm2_handler = 58 new MockAuthHandler("basic", "Realm2", HttpAuth::AUTH_SERVER); 59 cache.Add(origin, realm2_handler, L"realm2-user", L"realm2-password", 60 "/foo2/index.html"); 61 62 scoped_refptr<HttpAuthHandler> realm3_handler = 63 new MockAuthHandler("basic", "Realm3", HttpAuth::AUTH_PROXY); 64 cache.Add(origin, realm3_handler, L"realm3-user", L"realm3-password", ""); 65 66 // There is no Realm4 67 entry = cache.LookupByRealm(origin, "Realm4"); 68 EXPECT_TRUE(NULL == entry); 69 70 // While Realm3 does exist, the origin scheme is wrong. 71 entry = cache.LookupByRealm(GURL("https://www.google.com"), "Realm3"); 72 EXPECT_TRUE(NULL == entry); 73 74 // Valid lookup by realm. 75 entry = cache.LookupByRealm(GURL("http://www.google.com:80"), "Realm3"); 76 EXPECT_FALSE(NULL == entry); 77 EXPECT_TRUE(entry->handler() == realm3_handler.get()); 78 EXPECT_EQ(L"realm3-user", entry->username()); 79 EXPECT_EQ(L"realm3-password", entry->password()); 80 81 // Valid lookup by realm. 82 entry = cache.LookupByRealm(origin, "Realm2"); 83 EXPECT_FALSE(NULL == entry); 84 EXPECT_TRUE(entry->handler() == realm2_handler.get()); 85 EXPECT_EQ(L"realm2-user", entry->username()); 86 EXPECT_EQ(L"realm2-password", entry->password()); 87 88 // Check that subpaths are recognized. 89 HttpAuthCache::Entry* realm2Entry = cache.LookupByRealm(origin, "Realm2"); 90 EXPECT_FALSE(NULL == realm2Entry); 91 // Positive tests: 92 entry = cache.LookupByPath(origin, "/foo2/index.html"); 93 EXPECT_TRUE(realm2Entry == entry); 94 entry = cache.LookupByPath(origin, "/foo2/foobar.html"); 95 EXPECT_TRUE(realm2Entry == entry); 96 entry = cache.LookupByPath(origin, "/foo2/bar/index.html"); 97 EXPECT_TRUE(realm2Entry == entry); 98 entry = cache.LookupByPath(origin, "/foo2/"); 99 EXPECT_TRUE(realm2Entry == entry); 100 // Negative tests: 101 entry = cache.LookupByPath(origin, "/foo2"); 102 EXPECT_FALSE(realm2Entry == entry); 103 entry = cache.LookupByPath(origin, "/foo3/index.html"); 104 EXPECT_FALSE(realm2Entry == entry); 105 entry = cache.LookupByPath(origin, ""); 106 EXPECT_FALSE(realm2Entry == entry); 107 entry = cache.LookupByPath(origin, "/"); 108 EXPECT_FALSE(realm2Entry == entry); 109 110 // Lookup using empty path (may be used for proxy). 111 entry = cache.LookupByPath(origin, ""); 112 EXPECT_FALSE(NULL == entry); 113 EXPECT_TRUE(entry->handler() == realm3_handler.get()); 114 EXPECT_EQ("Realm3", entry->realm()); 115 } 116 117 TEST(HttpAuthCacheTest, AddPath) { 118 HttpAuthCache::Entry entry; 119 120 // All of these paths have a common root /1/2/2/4/5/ 121 entry.AddPath("/1/2/3/4/5/x.txt"); 122 entry.AddPath("/1/2/3/4/5/y.txt"); 123 entry.AddPath("/1/2/3/4/5/z.txt"); 124 125 EXPECT_EQ(1U, entry.paths_.size()); 126 EXPECT_EQ("/1/2/3/4/5/", entry.paths_.front()); 127 128 // Add a new entry (not a subpath). 129 entry.AddPath("/1/XXX/q"); 130 EXPECT_EQ(2U, entry.paths_.size()); 131 EXPECT_EQ("/1/XXX/", entry.paths_.front()); 132 EXPECT_EQ("/1/2/3/4/5/", entry.paths_.back()); 133 134 // Add containing paths of /1/2/3/4/5/ -- should swallow up the deeper paths. 135 entry.AddPath("/1/2/3/4/x.txt"); 136 EXPECT_EQ(2U, entry.paths_.size()); 137 EXPECT_EQ("/1/2/3/4/", entry.paths_.front()); 138 EXPECT_EQ("/1/XXX/", entry.paths_.back()); 139 entry.AddPath("/1/2/3/x"); 140 EXPECT_EQ(2U, entry.paths_.size()); 141 EXPECT_EQ("/1/2/3/", entry.paths_.front()); 142 EXPECT_EQ("/1/XXX/", entry.paths_.back()); 143 144 entry.AddPath("/index.html"); 145 EXPECT_EQ(1U, entry.paths_.size()); 146 EXPECT_EQ("/", entry.paths_.front()); 147 } 148 149 // Calling Add when the realm entry already exists, should append that 150 // path. 151 TEST(HttpAuthCacheTest, AddToExistingEntry) { 152 HttpAuthCache cache; 153 GURL origin("http://www.foobar.com:70"); 154 155 scoped_refptr<HttpAuthHandler> handler = 156 new MockAuthHandler("basic", "MyRealm", HttpAuth::AUTH_SERVER); 157 158 HttpAuthCache::Entry* orig_entry = cache.Add( 159 origin, handler, L"user1", L"password1", "/x/y/z/"); 160 cache.Add(origin, handler, L"user2", L"password2", "/z/y/x/"); 161 cache.Add(origin, handler, L"user3", L"password3", "/z/y"); 162 163 HttpAuthCache::Entry* entry = cache.LookupByRealm(origin, "MyRealm"); 164 165 EXPECT_TRUE(entry == orig_entry); 166 EXPECT_EQ(L"user3", entry->username()); 167 EXPECT_EQ(L"password3", entry->password()); 168 169 EXPECT_EQ(2U, entry->paths_.size()); 170 EXPECT_EQ("/z/", entry->paths_.front()); 171 EXPECT_EQ("/x/y/z/", entry->paths_.back()); 172 } 173 174 TEST(HttpAuthCacheTest, Remove) { 175 GURL origin("http://foobar2.com"); 176 177 scoped_refptr<HttpAuthHandler> realm1_handler = 178 new MockAuthHandler("basic", "Realm1", HttpAuth::AUTH_SERVER); 179 180 scoped_refptr<HttpAuthHandler> realm2_handler = 181 new MockAuthHandler("basic", "Realm2", HttpAuth::AUTH_SERVER); 182 183 scoped_refptr<HttpAuthHandler> realm3_handler = 184 new MockAuthHandler("basic", "Realm3", HttpAuth::AUTH_SERVER); 185 186 HttpAuthCache cache; 187 cache.Add(origin, realm1_handler, L"alice", L"123", "/"); 188 cache.Add(origin, realm2_handler, L"bob", L"princess", "/"); 189 cache.Add(origin, realm3_handler, L"admin", L"password", "/"); 190 191 // Fails, because there is no realm "Realm4". 192 EXPECT_FALSE(cache.Remove(origin, "Realm4", L"alice", L"123")); 193 194 // Fails because the origin is wrong. 195 EXPECT_FALSE(cache.Remove( 196 GURL("http://foobar2.com:100"), "Realm1", L"alice", L"123")); 197 198 // Fails because the username is wrong. 199 EXPECT_FALSE(cache.Remove(origin, "Realm1", L"alice2", L"123")); 200 201 // Fails because the password is wrong. 202 EXPECT_FALSE(cache.Remove(origin, "Realm1", L"alice", L"1234")); 203 204 // Succeeds. 205 EXPECT_TRUE(cache.Remove(origin, "Realm1", L"alice", L"123")); 206 207 // Fails because we just deleted the entry! 208 EXPECT_FALSE(cache.Remove(origin, "Realm1", L"alice", L"123")); 209 } 210 211 // Test fixture class for eviction tests (contains helpers for bulk 212 // insertion and existence testing). 213 class HttpAuthCacheEvictionTest : public testing::Test { 214 protected: 215 HttpAuthCacheEvictionTest() : origin_("http://www.google.com") { } 216 217 std::string GenerateRealm(int realm_i) { 218 return StringPrintf("Realm %d", realm_i); 219 } 220 221 std::string GeneratePath(int realm_i, int path_i) { 222 return StringPrintf("/%d/%d/x/y", realm_i, path_i); 223 } 224 225 void AddRealm(int realm_i) { 226 AddPathToRealm(realm_i, 0); 227 } 228 229 void AddPathToRealm(int realm_i, int path_i) { 230 scoped_refptr<HttpAuthHandler> handler = new MockAuthHandler("basic", 231 GenerateRealm(realm_i), HttpAuth::AUTH_SERVER); 232 std::string path = GeneratePath(realm_i, path_i); 233 cache_.Add(origin_, handler, L"username", L"password", path); 234 } 235 236 void CheckRealmExistence(int realm_i, bool exists) { 237 const HttpAuthCache::Entry* entry = 238 cache_.LookupByRealm(origin_, GenerateRealm(realm_i)); 239 if (exists) { 240 EXPECT_FALSE(entry == NULL); 241 EXPECT_EQ(GenerateRealm(realm_i), entry->realm()); 242 } else { 243 EXPECT_TRUE(entry == NULL); 244 } 245 } 246 247 void CheckPathExistence(int realm_i, int path_i, bool exists) { 248 const HttpAuthCache::Entry* entry = 249 cache_.LookupByPath(origin_, GeneratePath(realm_i, path_i)); 250 if (exists) { 251 EXPECT_FALSE(entry == NULL); 252 EXPECT_EQ(GenerateRealm(realm_i), entry->realm()); 253 } else { 254 EXPECT_TRUE(entry == NULL); 255 } 256 } 257 258 GURL origin_; 259 HttpAuthCache cache_; 260 261 static const int kMaxPaths = HttpAuthCache::kMaxNumPathsPerRealmEntry; 262 static const int kMaxRealms = HttpAuthCache::kMaxNumRealmEntries; 263 }; 264 265 // Add the maxinim number of realm entries to the cache. Each of these entries 266 // must still be retrievable. Next add three more entries -- since the cache is 267 // full this causes FIFO eviction of the first three entries. 268 TEST_F(HttpAuthCacheEvictionTest, RealmEntryEviction) { 269 for (int i = 0; i < kMaxRealms; ++i) 270 AddRealm(i); 271 272 for (int i = 0; i < kMaxRealms; ++i) 273 CheckRealmExistence(i, true); 274 275 for (int i = 0; i < 3; ++i) 276 AddRealm(i + kMaxRealms); 277 278 for (int i = 0; i < 3; ++i) 279 CheckRealmExistence(i, false); 280 281 for (int i = 0; i < kMaxRealms; ++i) 282 CheckRealmExistence(i + 3, true); 283 } 284 285 // Add the maximum number of paths to a single realm entry. Each of these 286 // paths should be retrievable. Next add 3 more paths -- since the cache is 287 // full this causes FIFO eviction of the first three paths. 288 TEST_F(HttpAuthCacheEvictionTest, RealmPathEviction) { 289 for (int i = 0; i < kMaxPaths; ++i) 290 AddPathToRealm(0, i); 291 292 for (int i = 1; i < kMaxRealms; ++i) 293 AddRealm(i); 294 295 for (int i = 0; i < 3; ++i) 296 AddPathToRealm(0, i + kMaxPaths); 297 298 for (int i = 0; i < 3; ++i) 299 CheckPathExistence(0, i, false); 300 301 for (int i = 0; i < kMaxPaths; ++i) 302 CheckPathExistence(0, i + 3, true); 303 304 for (int i = 0; i < kMaxRealms; ++i) 305 CheckRealmExistence(i, true); 306 } 307 308 } // namespace net 309