1// Copyright (c) 2010 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 <string>
6
7#include "base/string16.h"
8#include "base/string_util.h"
9#include "base/stringprintf.h"
10#include "base/utf_string_conversions.h"
11#include "net/base/net_errors.h"
12#include "net/http/http_auth_cache.h"
13#include "net/http/http_auth_handler.h"
14#include "testing/gtest/include/gtest/gtest.h"
15
16namespace net {
17
18namespace {
19
20class MockAuthHandler : public HttpAuthHandler {
21 public:
22  MockAuthHandler(HttpAuth::Scheme scheme,
23                  const std::string& realm,
24                  HttpAuth::Target target) {
25    // Can't use initializer list since these are members of the base class.
26    auth_scheme_ = scheme;
27    realm_ = realm;
28    score_ = 1;
29    target_ = target;
30    properties_ = 0;
31  }
32
33  virtual HttpAuth::AuthorizationResult HandleAnotherChallenge(
34      HttpAuth::ChallengeTokenizer* challenge) {
35    return HttpAuth::AUTHORIZATION_RESULT_REJECT;
36  }
37
38 protected:
39  virtual bool Init(HttpAuth::ChallengeTokenizer* challenge) {
40    return false;  // Unused.
41  }
42
43  virtual int GenerateAuthTokenImpl(const string16*,
44                                    const string16*,
45                                    const HttpRequestInfo*,
46                                    CompletionCallback* callback,
47                                    std::string* auth_token) {
48    *auth_token = "mock-credentials";
49    return OK;
50  }
51
52
53 private:
54  ~MockAuthHandler() {}
55};
56
57const char* kRealm1 = "Realm1";
58const char* kRealm2 = "Realm2";
59const char* kRealm3 = "Realm3";
60const char* kRealm4 = "Realm4";
61const char* kRealm5 = "Realm5";
62const string16 k123(ASCIIToUTF16("123"));
63const string16 k1234(ASCIIToUTF16("1234"));
64const string16 kAdmin(ASCIIToUTF16("admin"));
65const string16 kAlice(ASCIIToUTF16("alice"));
66const string16 kAlice2(ASCIIToUTF16("alice2"));
67const string16 kPassword(ASCIIToUTF16("password"));
68const string16 kRoot(ASCIIToUTF16("root"));
69const string16 kUsername(ASCIIToUTF16("username"));
70const string16 kWileCoyote(ASCIIToUTF16("wilecoyote"));
71
72}  // namespace
73
74// Test adding and looking-up cache entries (both by realm and by path).
75TEST(HttpAuthCacheTest, Basic) {
76  GURL origin("http://www.google.com");
77  HttpAuthCache cache;
78  HttpAuthCache::Entry* entry;
79
80  // Add cache entries for 4 realms: "Realm1", "Realm2", "Realm3" and
81  // "Realm4"
82
83  scoped_ptr<HttpAuthHandler> realm1_handler(
84      new MockAuthHandler(HttpAuth::AUTH_SCHEME_BASIC,
85                          kRealm1,
86                          HttpAuth::AUTH_SERVER));
87  cache.Add(origin, realm1_handler->realm(), realm1_handler->auth_scheme(),
88            "Basic realm=Realm1", ASCIIToUTF16("realm1-user"),
89            ASCIIToUTF16("realm1-password"), "/foo/bar/index.html");
90
91  scoped_ptr<HttpAuthHandler> realm2_handler(
92      new MockAuthHandler(HttpAuth::AUTH_SCHEME_BASIC,
93                          kRealm2,
94                          HttpAuth::AUTH_SERVER));
95  cache.Add(origin, realm2_handler->realm(), realm2_handler->auth_scheme(),
96            "Basic realm=Realm2", ASCIIToUTF16("realm2-user"),
97            ASCIIToUTF16("realm2-password"), "/foo2/index.html");
98
99  scoped_ptr<HttpAuthHandler> realm3_basic_handler(
100      new MockAuthHandler(HttpAuth::AUTH_SCHEME_BASIC,
101                          kRealm3,
102                          HttpAuth::AUTH_PROXY));
103  cache.Add(origin, realm3_basic_handler->realm(),
104            realm3_basic_handler->auth_scheme(), "Basic realm=Realm3",
105            ASCIIToUTF16("realm3-basic-user"),
106            ASCIIToUTF16("realm3-basic-password"), "");
107
108  scoped_ptr<HttpAuthHandler> realm3_digest_handler(
109      new MockAuthHandler(HttpAuth::AUTH_SCHEME_DIGEST,
110                          kRealm3,
111                          HttpAuth::AUTH_PROXY));
112  cache.Add(origin, realm3_digest_handler->realm(),
113            realm3_digest_handler->auth_scheme(), "Digest realm=Realm3",
114            ASCIIToUTF16("realm3-digest-user"),
115            ASCIIToUTF16("realm3-digest-password"), "/baz/index.html");
116
117  scoped_ptr<HttpAuthHandler> realm4_basic_handler(
118      new MockAuthHandler(HttpAuth::AUTH_SCHEME_BASIC,
119                          kRealm4,
120                          HttpAuth::AUTH_SERVER));
121  cache.Add(origin, realm4_basic_handler->realm(),
122            realm4_basic_handler->auth_scheme(), "Basic realm=Realm4",
123            ASCIIToUTF16("realm4-basic-user"),
124            ASCIIToUTF16("realm4-basic-password"), "/");
125
126  // There is no Realm5
127  entry = cache.Lookup(origin, kRealm5, HttpAuth::AUTH_SCHEME_BASIC);
128  EXPECT_TRUE(NULL == entry);
129
130  // While Realm3 does exist, the origin scheme is wrong.
131  entry = cache.Lookup(GURL("https://www.google.com"), kRealm3,
132                       HttpAuth::AUTH_SCHEME_BASIC);
133  EXPECT_TRUE(NULL == entry);
134
135  // Realm, origin scheme ok, authentication scheme wrong
136  entry = cache.Lookup
137      (GURL("http://www.google.com"), kRealm1, HttpAuth::AUTH_SCHEME_DIGEST);
138  EXPECT_TRUE(NULL == entry);
139
140  // Valid lookup by origin, realm, scheme.
141  entry = cache.Lookup(
142      GURL("http://www.google.com:80"), kRealm3, HttpAuth::AUTH_SCHEME_BASIC);
143  ASSERT_FALSE(NULL == entry);
144  EXPECT_EQ(HttpAuth::AUTH_SCHEME_BASIC, entry->scheme());
145  EXPECT_EQ(kRealm3, entry->realm());
146  EXPECT_EQ("Basic realm=Realm3", entry->auth_challenge());
147  EXPECT_EQ(ASCIIToUTF16("realm3-basic-user"), entry->username());
148  EXPECT_EQ(ASCIIToUTF16("realm3-basic-password"), entry->password());
149
150  // Valid lookup by origin, realm, scheme when there's a duplicate
151  // origin, realm in the cache
152  entry = cache.Lookup(
153      GURL("http://www.google.com:80"), kRealm3, HttpAuth::AUTH_SCHEME_DIGEST);
154  ASSERT_FALSE(NULL == entry);
155  EXPECT_EQ(HttpAuth::AUTH_SCHEME_DIGEST, entry->scheme());
156  EXPECT_EQ(kRealm3, entry->realm());
157  EXPECT_EQ("Digest realm=Realm3", entry->auth_challenge());
158  EXPECT_EQ(ASCIIToUTF16("realm3-digest-user"), entry->username());
159  EXPECT_EQ(ASCIIToUTF16("realm3-digest-password"), entry->password());
160
161  // Valid lookup by realm.
162  entry = cache.Lookup(origin, kRealm2, HttpAuth::AUTH_SCHEME_BASIC);
163  ASSERT_FALSE(NULL == entry);
164  EXPECT_EQ(HttpAuth::AUTH_SCHEME_BASIC, entry->scheme());
165  EXPECT_EQ(kRealm2, entry->realm());
166  EXPECT_EQ("Basic realm=Realm2", entry->auth_challenge());
167  EXPECT_EQ(ASCIIToUTF16("realm2-user"), entry->username());
168  EXPECT_EQ(ASCIIToUTF16("realm2-password"), entry->password());
169
170  // Check that subpaths are recognized.
171  HttpAuthCache::Entry* realm2_entry = cache.Lookup(
172      origin, kRealm2, HttpAuth::AUTH_SCHEME_BASIC);
173  HttpAuthCache::Entry* realm4_entry = cache.Lookup(
174      origin, kRealm4, HttpAuth::AUTH_SCHEME_BASIC);
175  EXPECT_FALSE(NULL == realm2_entry);
176  EXPECT_FALSE(NULL == realm4_entry);
177  // Realm4 applies to '/' and Realm2 applies to '/foo2/'.
178  // LookupByPath() should return the closest enclosing path.
179  // Positive tests:
180  entry = cache.LookupByPath(origin, "/foo2/index.html");
181  EXPECT_TRUE(realm2_entry == entry);
182  entry = cache.LookupByPath(origin, "/foo2/foobar.html");
183  EXPECT_TRUE(realm2_entry == entry);
184  entry = cache.LookupByPath(origin, "/foo2/bar/index.html");
185  EXPECT_TRUE(realm2_entry == entry);
186  entry = cache.LookupByPath(origin, "/foo2/");
187  EXPECT_TRUE(realm2_entry == entry);
188  entry = cache.LookupByPath(origin, "/foo2");
189  EXPECT_TRUE(realm4_entry == entry);
190  entry = cache.LookupByPath(origin, "/");
191  EXPECT_TRUE(realm4_entry == entry);
192
193  // Negative tests:
194  entry = cache.LookupByPath(origin, "/foo3/index.html");
195  EXPECT_FALSE(realm2_entry == entry);
196  entry = cache.LookupByPath(origin, "");
197  EXPECT_FALSE(realm2_entry == entry);
198
199  // Confirm we find the same realm, different auth scheme by path lookup
200  HttpAuthCache::Entry* realm3_digest_entry =
201      cache.Lookup(origin, kRealm3, HttpAuth::AUTH_SCHEME_DIGEST);
202  EXPECT_FALSE(NULL == realm3_digest_entry);
203  entry = cache.LookupByPath(origin, "/baz/index.html");
204  EXPECT_TRUE(realm3_digest_entry == entry);
205  entry = cache.LookupByPath(origin, "/baz/");
206  EXPECT_TRUE(realm3_digest_entry == entry);
207  entry = cache.LookupByPath(origin, "/baz");
208  EXPECT_FALSE(realm3_digest_entry == entry);
209
210  // Confirm we find the same realm, different auth scheme by path lookup
211  HttpAuthCache::Entry* realm3DigestEntry =
212      cache.Lookup(origin, kRealm3, HttpAuth::AUTH_SCHEME_DIGEST);
213  EXPECT_FALSE(NULL == realm3DigestEntry);
214  entry = cache.LookupByPath(origin, "/baz/index.html");
215  EXPECT_TRUE(realm3DigestEntry == entry);
216  entry = cache.LookupByPath(origin, "/baz/");
217  EXPECT_TRUE(realm3DigestEntry == entry);
218  entry = cache.LookupByPath(origin, "/baz");
219  EXPECT_FALSE(realm3DigestEntry == entry);
220
221  // Lookup using empty path (may be used for proxy).
222  entry = cache.LookupByPath(origin, "");
223  EXPECT_FALSE(NULL == entry);
224  EXPECT_EQ(HttpAuth::AUTH_SCHEME_BASIC, entry->scheme());
225  EXPECT_EQ(kRealm3, entry->realm());
226}
227
228TEST(HttpAuthCacheTest, AddPath) {
229  HttpAuthCache::Entry entry;
230
231  // All of these paths have a common root /1/2/2/4/5/
232  entry.AddPath("/1/2/3/4/5/x.txt");
233  entry.AddPath("/1/2/3/4/5/y.txt");
234  entry.AddPath("/1/2/3/4/5/z.txt");
235
236  EXPECT_EQ(1U, entry.paths_.size());
237  EXPECT_EQ("/1/2/3/4/5/", entry.paths_.front());
238
239  // Add a new entry (not a subpath).
240  entry.AddPath("/1/XXX/q");
241  EXPECT_EQ(2U, entry.paths_.size());
242  EXPECT_EQ("/1/XXX/", entry.paths_.front());
243  EXPECT_EQ("/1/2/3/4/5/", entry.paths_.back());
244
245  // Add containing paths of /1/2/3/4/5/ -- should swallow up the deeper paths.
246  entry.AddPath("/1/2/3/4/x.txt");
247  EXPECT_EQ(2U, entry.paths_.size());
248  EXPECT_EQ("/1/2/3/4/", entry.paths_.front());
249  EXPECT_EQ("/1/XXX/", entry.paths_.back());
250  entry.AddPath("/1/2/3/x");
251  EXPECT_EQ(2U, entry.paths_.size());
252  EXPECT_EQ("/1/2/3/", entry.paths_.front());
253  EXPECT_EQ("/1/XXX/", entry.paths_.back());
254
255  entry.AddPath("/index.html");
256  EXPECT_EQ(1U, entry.paths_.size());
257  EXPECT_EQ("/", entry.paths_.front());
258}
259
260// Calling Add when the realm entry already exists, should append that
261// path.
262TEST(HttpAuthCacheTest, AddToExistingEntry) {
263  HttpAuthCache cache;
264  GURL origin("http://www.foobar.com:70");
265  const std::string auth_challenge = "Basic realm=MyRealm";
266
267  scoped_ptr<HttpAuthHandler> handler(
268      new MockAuthHandler(
269          HttpAuth::AUTH_SCHEME_BASIC, "MyRealm", HttpAuth::AUTH_SERVER));
270  HttpAuthCache::Entry* orig_entry = cache.Add(
271      origin, handler->realm(), handler->auth_scheme(), auth_challenge,
272      ASCIIToUTF16("user1"), ASCIIToUTF16("password1"), "/x/y/z/");
273  cache.Add(origin, handler->realm(), handler->auth_scheme(), auth_challenge,
274            ASCIIToUTF16("user2"), ASCIIToUTF16("password2"), "/z/y/x/");
275  cache.Add(origin, handler->realm(), handler->auth_scheme(), auth_challenge,
276            ASCIIToUTF16("user3"), ASCIIToUTF16("password3"), "/z/y");
277
278  HttpAuthCache::Entry* entry = cache.Lookup(
279      origin, "MyRealm", HttpAuth::AUTH_SCHEME_BASIC);
280
281  EXPECT_TRUE(entry == orig_entry);
282  EXPECT_EQ(ASCIIToUTF16("user3"), entry->username());
283  EXPECT_EQ(ASCIIToUTF16("password3"), entry->password());
284
285  EXPECT_EQ(2U, entry->paths_.size());
286  EXPECT_EQ("/z/", entry->paths_.front());
287  EXPECT_EQ("/x/y/z/", entry->paths_.back());
288}
289
290TEST(HttpAuthCacheTest, Remove) {
291  GURL origin("http://foobar2.com");
292
293  scoped_ptr<HttpAuthHandler> realm1_handler(
294      new MockAuthHandler(
295          HttpAuth::AUTH_SCHEME_BASIC, kRealm1, HttpAuth::AUTH_SERVER));
296
297  scoped_ptr<HttpAuthHandler> realm2_handler(
298      new MockAuthHandler(
299          HttpAuth::AUTH_SCHEME_BASIC, kRealm2, HttpAuth::AUTH_SERVER));
300
301  scoped_ptr<HttpAuthHandler> realm3_basic_handler(
302      new MockAuthHandler(
303          HttpAuth::AUTH_SCHEME_BASIC, kRealm3, HttpAuth::AUTH_SERVER));
304
305  scoped_ptr<HttpAuthHandler> realm3_digest_handler(
306      new MockAuthHandler(
307          HttpAuth::AUTH_SCHEME_DIGEST, kRealm3, HttpAuth::AUTH_SERVER));
308
309  HttpAuthCache cache;
310  cache.Add(origin, realm1_handler->realm(), realm1_handler->auth_scheme(),
311            "basic realm=Realm1", kAlice, k123, "/");
312  cache.Add(origin, realm2_handler->realm(), realm2_handler->auth_scheme(),
313            "basic realm=Realm2", ASCIIToUTF16("bob"), ASCIIToUTF16("princess"),
314            "/");
315  cache.Add(origin, realm3_basic_handler->realm(),
316            realm3_basic_handler->auth_scheme(), "basic realm=Realm3",
317            kAdmin, kPassword, "/");
318  cache.Add(origin, realm3_digest_handler->realm(),
319            realm3_digest_handler->auth_scheme(), "digest realm=Realm3",
320            kRoot, kWileCoyote, "/");
321
322  // Fails, because there is no realm "Realm5".
323  EXPECT_FALSE(cache.Remove(
324      origin, kRealm5, HttpAuth::AUTH_SCHEME_BASIC, kAlice, k123));
325
326  // Fails because the origin is wrong.
327  EXPECT_FALSE(cache.Remove(GURL("http://foobar2.com:100"),
328                            kRealm1,
329                            HttpAuth::AUTH_SCHEME_BASIC,
330                            kAlice,
331                            k123));
332
333  // Fails because the username is wrong.
334  EXPECT_FALSE(cache.Remove(
335      origin, kRealm1, HttpAuth::AUTH_SCHEME_BASIC, kAlice2, k123));
336
337  // Fails because the password is wrong.
338  EXPECT_FALSE(cache.Remove(
339      origin, kRealm1, HttpAuth::AUTH_SCHEME_BASIC, kAlice, k1234));
340
341  // Fails because the authentication type is wrong.
342  EXPECT_FALSE(cache.Remove(
343      origin, kRealm1, HttpAuth::AUTH_SCHEME_DIGEST, kAlice, k123));
344
345  // Succeeds.
346  EXPECT_TRUE(cache.Remove(
347      origin, kRealm1, HttpAuth::AUTH_SCHEME_BASIC, kAlice, k123));
348
349  // Fails because we just deleted the entry!
350  EXPECT_FALSE(cache.Remove(
351      origin, kRealm1, HttpAuth::AUTH_SCHEME_BASIC, kAlice, k123));
352
353  // Succeed when there are two authentication types for the same origin,realm.
354  EXPECT_TRUE(cache.Remove(
355      origin, kRealm3, HttpAuth::AUTH_SCHEME_DIGEST, kRoot, kWileCoyote));
356
357  // Succeed as above, but when entries were added in opposite order
358  cache.Add(origin, realm3_digest_handler->realm(),
359            realm3_digest_handler->auth_scheme(), "digest realm=Realm3",
360            kRoot, kWileCoyote, "/");
361  EXPECT_TRUE(cache.Remove(
362      origin, kRealm3, HttpAuth::AUTH_SCHEME_BASIC, kAdmin, kPassword));
363
364  // Make sure that removing one entry still leaves the other available for
365  // lookup.
366  HttpAuthCache::Entry* entry = cache.Lookup(
367      origin, kRealm3, HttpAuth::AUTH_SCHEME_DIGEST);
368  EXPECT_FALSE(NULL == entry);
369}
370
371TEST(HttpAuthCacheTest, UpdateStaleChallenge) {
372  HttpAuthCache cache;
373  GURL origin("http://foobar2.com");
374  scoped_ptr<HttpAuthHandler> digest_handler(
375      new MockAuthHandler(
376          HttpAuth::AUTH_SCHEME_DIGEST, kRealm1, HttpAuth::AUTH_PROXY));
377  HttpAuthCache::Entry* entry_pre = cache.Add(
378      origin,
379      digest_handler->realm(),
380      digest_handler->auth_scheme(),
381      "Digest realm=Realm1,"
382      "nonce=\"s3MzvFhaBAA=4c520af5acd9d8d7ae26947529d18c8eae1e98f4\"",
383      ASCIIToUTF16("realm-digest-user"),
384      ASCIIToUTF16("realm-digest-password"),
385      "/baz/index.html");
386  ASSERT_TRUE(entry_pre != NULL);
387
388  EXPECT_EQ(2, entry_pre->IncrementNonceCount());
389  EXPECT_EQ(3, entry_pre->IncrementNonceCount());
390  EXPECT_EQ(4, entry_pre->IncrementNonceCount());
391
392  bool update_success = cache.UpdateStaleChallenge(
393      origin,
394      digest_handler->realm(),
395      digest_handler->auth_scheme(),
396      "Digest realm=Realm1,"
397      "nonce=\"claGgoRXBAA=7583377687842fdb7b56ba0555d175baa0b800e3\","
398      "stale=\"true\"");
399  EXPECT_TRUE(update_success);
400
401  // After the stale update, the entry should still exist in the cache and
402  // the nonce count should be reset to 0.
403  HttpAuthCache::Entry* entry_post = cache.Lookup(
404      origin,
405      digest_handler->realm(),
406      digest_handler->auth_scheme());
407  ASSERT_TRUE(entry_post != NULL);
408  EXPECT_EQ(2, entry_post->IncrementNonceCount());
409
410  // UpdateStaleChallenge will fail if an entry doesn't exist in the cache.
411  bool update_failure = cache.UpdateStaleChallenge(
412      origin,
413      kRealm2,
414      digest_handler->auth_scheme(),
415      "Digest realm=Realm2,"
416      "nonce=\"claGgoRXBAA=7583377687842fdb7b56ba0555d175baa0b800e3\","
417      "stale=\"true\"");
418  EXPECT_FALSE(update_failure);
419}
420
421// Test fixture class for eviction tests (contains helpers for bulk
422// insertion and existence testing).
423class HttpAuthCacheEvictionTest : public testing::Test {
424 protected:
425  HttpAuthCacheEvictionTest() : origin_("http://www.google.com") { }
426
427  std::string GenerateRealm(int realm_i) {
428    return base::StringPrintf("Realm %d", realm_i);
429  }
430
431  std::string GeneratePath(int realm_i, int path_i) {
432    return base::StringPrintf("/%d/%d/x/y", realm_i, path_i);
433  }
434
435  void AddRealm(int realm_i) {
436    AddPathToRealm(realm_i, 0);
437  }
438
439  void AddPathToRealm(int realm_i, int path_i) {
440    cache_.Add(origin_, GenerateRealm(realm_i), HttpAuth::AUTH_SCHEME_BASIC, "",
441               kUsername, kPassword, GeneratePath(realm_i, path_i));
442  }
443
444  void CheckRealmExistence(int realm_i, bool exists) {
445    const HttpAuthCache::Entry* entry =
446        cache_.Lookup(
447            origin_, GenerateRealm(realm_i), HttpAuth::AUTH_SCHEME_BASIC);
448    if (exists) {
449      EXPECT_FALSE(entry == NULL);
450      EXPECT_EQ(GenerateRealm(realm_i), entry->realm());
451    } else {
452      EXPECT_TRUE(entry == NULL);
453    }
454  }
455
456  void CheckPathExistence(int realm_i, int path_i, bool exists) {
457    const HttpAuthCache::Entry* entry =
458        cache_.LookupByPath(origin_, GeneratePath(realm_i, path_i));
459    if (exists) {
460      EXPECT_FALSE(entry == NULL);
461      EXPECT_EQ(GenerateRealm(realm_i), entry->realm());
462    } else {
463      EXPECT_TRUE(entry == NULL);
464    }
465  }
466
467  GURL origin_;
468  HttpAuthCache cache_;
469
470  static const int kMaxPaths = HttpAuthCache::kMaxNumPathsPerRealmEntry;
471  static const int kMaxRealms = HttpAuthCache::kMaxNumRealmEntries;
472};
473
474// Add the maxinim number of realm entries to the cache. Each of these entries
475// must still be retrievable. Next add three more entries -- since the cache is
476// full this causes FIFO eviction of the first three entries.
477TEST_F(HttpAuthCacheEvictionTest, RealmEntryEviction) {
478  for (int i = 0; i < kMaxRealms; ++i)
479    AddRealm(i);
480
481  for (int i = 0; i < kMaxRealms; ++i)
482    CheckRealmExistence(i, true);
483
484  for (int i = 0; i < 3; ++i)
485    AddRealm(i + kMaxRealms);
486
487  for (int i = 0; i < 3; ++i)
488    CheckRealmExistence(i, false);
489
490  for (int i = 0; i < kMaxRealms; ++i)
491    CheckRealmExistence(i + 3, true);
492}
493
494// Add the maximum number of paths to a single realm entry. Each of these
495// paths should be retrievable. Next add 3 more paths -- since the cache is
496// full this causes FIFO eviction of the first three paths.
497TEST_F(HttpAuthCacheEvictionTest, RealmPathEviction) {
498  for (int i = 0; i < kMaxPaths; ++i)
499    AddPathToRealm(0, i);
500
501  for (int i = 1; i < kMaxRealms; ++i)
502    AddRealm(i);
503
504  for (int i = 0; i < 3; ++i)
505    AddPathToRealm(0, i + kMaxPaths);
506
507  for (int i = 0; i < 3; ++i)
508    CheckPathExistence(0, i, false);
509
510  for (int i = 0; i < kMaxPaths; ++i)
511    CheckPathExistence(0, i + 3, true);
512
513  for (int i = 0; i < kMaxRealms; ++i)
514    CheckRealmExistence(i, true);
515}
516
517}  // namespace net
518