1d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved.
2d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
3d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)// found in the LICENSE file.
4d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
5d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "chrome/browser/history/url_utils.h"
6d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
7d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include <algorithm>
8d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
9010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "url/gurl.h"
10010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
11d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)namespace history {
12d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
13d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)namespace {
14d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
15d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)// Comparator to enforce '\0' < '?' < '#' < '/' < other characters.
16d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)int GetURLCharPriority(char ch) {
17d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  switch (ch) {
18d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    case '\0': return 0;
19d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    case '?': return 1;
20d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    case '#': return 2;
21d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    case '/': return 3;
22d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  }
23d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  return 4;
24d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)}
25d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
26d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)}  // namespace
27d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
28d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)// Instead of splitting URLs and extract path components, we can implement
29d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)// CanonicalURLStringCompare() using string operations only. The key idea is,
30d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)// treating '/' to be less than any valid path characters would make it behave
31d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)// as a separator, so e.g., "test" < "test-case" would be enforced by
32d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)// "test/..." < "test-case/...". We also force "?" < "/", so "test?query" <
33d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)// "test/stuff". Since the routine is merely lexicographical string comparison
34d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)// with remapping of chracter ordering, so it is a valid strict-weak ordering.
35d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)bool CanonicalURLStringCompare(const std::string& s1, const std::string& s2) {
36d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  const std::string::value_type* ch1 = s1.c_str();
37d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  const std::string::value_type* ch2 = s2.c_str();
38d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  while (*ch1 && *ch2 && *ch1 == *ch2) {
39d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    ++ch1;
40d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    ++ch2;
41d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  }
42d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  int pri_diff = GetURLCharPriority(*ch1) - GetURLCharPriority(*ch2);
43d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // We want false to be returned if |pri_diff| > 0.
44d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  return (pri_diff != 0) ? pri_diff < 0 : *ch1 < *ch2;
45d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)}
46d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
474e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)bool HaveSameSchemeHostAndPort(const GURL&url1, const GURL& url2) {
484e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  return url1.scheme() == url2.scheme() && url1.host() == url2.host() &&
494e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      url1.port() == url2.port();
504e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
514e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
524e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)bool IsPathPrefix(const std::string& p1, const std::string& p2) {
53d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  if (p1.length() > p2.length())
54d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    return false;
554e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  std::pair<std::string::const_iterator, std::string::const_iterator>
564e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      first_diff = std::mismatch(p1.begin(), p1.end(), p2.begin());
57d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // Necessary condition: |p1| is a string prefix of |p2|.
58d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  if (first_diff.first != p1.end())
59d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    return false;  // E.g.: (|p1| = "/test", |p2| = "/exam") => false.
60d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
61d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // |p1| is string prefix.
62d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  if (first_diff.second == p2.end())  // Is exact match?
63d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    return true;  // E.g.: ("/test", "/test") => true.
64d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // |p1| is strict string prefix, check full match of last path component.
65d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  if (!p1.empty() && *p1.rbegin() == '/')  // Ends in '/'?
66d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    return true;  // E.g.: ("/test/", "/test/stuff") => true.
67d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
68d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // Finally, |p1| does not end in "/": check first extra character in |p2|.
69d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // E.g.: ("/test", "/test/stuff") => true; ("/test", "/testing") => false.
70d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  return *(first_diff.second) == '/';
71d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)}
72d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
731e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)GURL ToggleHTTPAndHTTPS(const GURL& url) {
741e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  std::string new_scheme;
751e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  if (url.SchemeIs("http"))
761e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    new_scheme = "https";
771e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  else if (url.SchemeIs("https"))
781e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    new_scheme = "http";
791e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  else
801e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    return GURL::EmptyGURL();
815c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  url::Component comp;
821e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  comp.len = new_scheme.length();
831e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  GURL::Replacements replacement;
841e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  replacement.SetScheme(new_scheme.c_str(), comp);
851e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  return url.ReplaceComponents(replacement);
861e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
871e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
88d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)}  // namespace history
89