1c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved.
2c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
3c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// found in the LICENSE file.
4c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
5c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "url/url_util.h"
6c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
7c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include <string.h>
8c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include <vector>
9c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
10116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "base/debug/leak_annotations.h"
11c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/logging.h"
12c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "url/url_canon_internal.h"
13c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "url/url_file.h"
14c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "url/url_util_internal.h"
15c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
160529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochnamespace url {
17c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
18c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)namespace {
19c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
20c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// ASCII-specific tolower.  The standard library's tolower is locale sensitive,
21c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// so we don't want to use it here.
220529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochtemplate<class Char>
230529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochinline Char ToLowerASCII(Char c) {
24c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return (c >= 'A' && c <= 'Z') ? (c + ('a' - 'A')) : c;
25c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
26c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
27c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Backend for LowerCaseEqualsASCII.
28c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)template<typename Iter>
29c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)inline bool DoLowerCaseEqualsASCII(Iter a_begin, Iter a_end, const char* b) {
30c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  for (Iter it = a_begin; it != a_end; ++it, ++b) {
31c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (!*b || ToLowerASCII(*it) != *b)
32c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      return false;
33c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
34c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return *b == 0;
35c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
36c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
37c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)const int kNumStandardURLSchemes = 8;
38c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)const char* kStandardURLSchemes[kNumStandardURLSchemes] = {
39f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  kHttpScheme,
40f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  kHttpsScheme,
41c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  kFileScheme,  // Yes, file urls can have a hostname!
42f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  kFtpScheme,
43f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  kGopherScheme,
44f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  kWsScheme,    // WebSocket.
45f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  kWssScheme,   // WebSocket secure.
46c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  kFileSystemScheme,
47c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)};
48c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
49c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// List of the currently installed standard schemes. This list is lazily
50c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// initialized by InitStandardSchemes and is leaked on shutdown to prevent
51c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// any destructors from being called that will slow us down or cause problems.
52c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)std::vector<const char*>* standard_schemes = NULL;
53c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
54c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// See the LockStandardSchemes declaration in the header.
55c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)bool standard_schemes_locked = false;
56c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
57c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Ensures that the standard_schemes list is initialized, does nothing if it
58c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// already has values.
59c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void InitStandardSchemes() {
60c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (standard_schemes)
61c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
62c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  standard_schemes = new std::vector<const char*>;
63c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  for (int i = 0; i < kNumStandardURLSchemes; i++)
64c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    standard_schemes->push_back(kStandardURLSchemes[i]);
65c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
66c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
67c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Given a string and a range inside the string, compares it to the given
68c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// lower-case |compare_to| buffer.
69c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)template<typename CHAR>
70c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)inline bool DoCompareSchemeComponent(const CHAR* spec,
710529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                                     const Component& component,
72c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                     const char* compare_to) {
73c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!component.is_nonempty())
74c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return compare_to[0] == 0;  // When component is empty, match empty scheme.
75c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return LowerCaseEqualsASCII(&spec[component.begin],
76c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                              &spec[component.end()],
77c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                              compare_to);
78c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
79c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
80c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Returns true if the given scheme identified by |scheme| within |spec| is one
81c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// of the registered "standard" schemes.
82c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)template<typename CHAR>
830529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochbool DoIsStandard(const CHAR* spec, const Component& scheme) {
84c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!scheme.is_nonempty())
85c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return false;  // Empty or invalid schemes are non-standard.
86c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
87c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  InitStandardSchemes();
88c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  for (size_t i = 0; i < standard_schemes->size(); i++) {
89c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (LowerCaseEqualsASCII(&spec[scheme.begin], &spec[scheme.end()],
90c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                             standard_schemes->at(i)))
91c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      return true;
92c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
93c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return false;
94c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
95c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
96c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)template<typename CHAR>
97c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)bool DoFindAndCompareScheme(const CHAR* str,
98c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                            int str_len,
99c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                            const char* compare,
1000529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                            Component* found_scheme) {
101c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Before extracting scheme, canonicalize the URL to remove any whitespace.
102c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // This matches the canonicalization done in DoCanonicalize function.
1030529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  RawCanonOutputT<CHAR> whitespace_buffer;
104c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  int spec_len;
105c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  const CHAR* spec = RemoveURLWhitespace(str, str_len,
106c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                         &whitespace_buffer, &spec_len);
107c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1080529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  Component our_scheme;
1090529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (!ExtractScheme(spec, spec_len, &our_scheme)) {
110c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // No scheme.
111c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (found_scheme)
1120529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      *found_scheme = Component();
113c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return false;
114c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
115c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (found_scheme)
116c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    *found_scheme = our_scheme;
117c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return DoCompareSchemeComponent(spec, our_scheme, compare);
118c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
119c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
120c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)template<typename CHAR>
1210529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochbool DoCanonicalize(const CHAR* in_spec,
1220529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                    int in_spec_len,
123f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                    bool trim_path_end,
1240529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                    CharsetConverter* charset_converter,
1250529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                    CanonOutput* output,
1260529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                    Parsed* output_parsed) {
127c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Remove any whitespace from the middle of the relative URL, possibly
128c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // copying to the new buffer.
1290529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  RawCanonOutputT<CHAR> whitespace_buffer;
130c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  int spec_len;
131c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  const CHAR* spec = RemoveURLWhitespace(in_spec, in_spec_len,
132c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                         &whitespace_buffer, &spec_len);
133c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1340529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  Parsed parsed_input;
135c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#ifdef WIN32
136c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // For Windows, we allow things that look like absolute Windows paths to be
137c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // fixed up magically to file URLs. This is done for IE compatability. For
138c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // example, this will change "c:/foo" into a file URL rather than treating
139c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // it as a URL with the protocol "c". It also works for UNC ("\\foo\bar.txt").
140c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // There is similar logic in url_canon_relative.cc for
141c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  //
142c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // For Max & Unix, we don't do this (the equivalent would be "/foo/bar" which
143c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // has no meaning as an absolute path name. This is because browsers on Mac
144c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // & Unix don't generally do this, so there is no compatibility reason for
145c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // doing so.
1460529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (DoesBeginUNCPath(spec, 0, spec_len, false) ||
1470529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      DoesBeginWindowsDriveSpec(spec, 0, spec_len)) {
1480529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    ParseFileURL(spec, spec_len, &parsed_input);
1490529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    return CanonicalizeFileURL(spec, spec_len, parsed_input, charset_converter,
1500529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                               output, output_parsed);
151c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
152c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#endif
153c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1540529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  Component scheme;
1550529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (!ExtractScheme(spec, spec_len, &scheme))
156c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return false;
157c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
158c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // This is the parsed version of the input URL, we have to canonicalize it
159c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // before storing it in our object.
160c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  bool success;
161cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (DoCompareSchemeComponent(spec, scheme, url::kFileScheme)) {
162c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // File URLs are special.
1630529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    ParseFileURL(spec, spec_len, &parsed_input);
1640529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    success = CanonicalizeFileURL(spec, spec_len, parsed_input,
1650529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                                  charset_converter, output, output_parsed);
166cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  } else if (DoCompareSchemeComponent(spec, scheme, url::kFileSystemScheme)) {
167c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // Filesystem URLs are special.
1680529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    ParseFileSystemURL(spec, spec_len, &parsed_input);
1690529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    success = CanonicalizeFileSystemURL(spec, spec_len, parsed_input,
1700529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                                        charset_converter, output,
1710529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                                        output_parsed);
172c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
173c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  } else if (DoIsStandard(spec, scheme)) {
174c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // All "normal" URLs.
1750529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    ParseStandardURL(spec, spec_len, &parsed_input);
1760529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    success = CanonicalizeStandardURL(spec, spec_len, parsed_input,
1770529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                                      charset_converter, output, output_parsed);
178c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
179cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  } else if (DoCompareSchemeComponent(spec, scheme, url::kMailToScheme)) {
180c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // Mailto are treated like a standard url with only a scheme, path, query
1810529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    ParseMailtoURL(spec, spec_len, &parsed_input);
1820529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    success = CanonicalizeMailtoURL(spec, spec_len, parsed_input, output,
1830529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                                    output_parsed);
184c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
185c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  } else {
186c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // "Weird" URLs like data: and javascript:
1870529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    ParsePathURL(spec, spec_len, trim_path_end, &parsed_input);
1880529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    success = CanonicalizePathURL(spec, spec_len, parsed_input, output,
1890529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                                  output_parsed);
190c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
191c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return success;
192c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
193c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
194c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)template<typename CHAR>
195c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)bool DoResolveRelative(const char* base_spec,
196c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                       int base_spec_len,
1970529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                       const Parsed& base_parsed,
198c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                       const CHAR* in_relative,
199c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                       int in_relative_length,
2000529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                       CharsetConverter* charset_converter,
2010529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                       CanonOutput* output,
2020529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                       Parsed* output_parsed) {
203c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Remove any whitespace from the middle of the relative URL, possibly
204c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // copying to the new buffer.
2050529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  RawCanonOutputT<CHAR> whitespace_buffer;
206c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  int relative_length;
207c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  const CHAR* relative = RemoveURLWhitespace(in_relative, in_relative_length,
208c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                             &whitespace_buffer,
209c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                             &relative_length);
210c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  bool base_is_authority_based = false;
211c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  bool base_is_hierarchical = false;
212c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (base_spec &&
213c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      base_parsed.scheme.is_nonempty()) {
214c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    int after_scheme = base_parsed.scheme.end() + 1;  // Skip past the colon.
2150529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    int num_slashes = CountConsecutiveSlashes(base_spec, after_scheme,
2160529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                                              base_spec_len);
217c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    base_is_authority_based = num_slashes > 1;
218c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    base_is_hierarchical = num_slashes > 0;
219c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
220c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
221c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  bool standard_base_scheme =
222c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      base_parsed.scheme.is_nonempty() &&
223c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      DoIsStandard(base_spec, base_parsed.scheme);
224c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
225c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  bool is_relative;
2260529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  Component relative_component;
2270529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (!IsRelativeURL(base_spec, base_parsed, relative, relative_length,
2280529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                     (base_is_hierarchical || standard_base_scheme),
2290529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                     &is_relative, &relative_component)) {
230c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // Error resolving.
231c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return false;
232c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
233c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
234c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Pretend for a moment that |base_spec| is a standard URL. Normally
235c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // non-standard URLs are treated as PathURLs, but if the base has an
236c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // authority we would like to preserve it.
237c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (is_relative && base_is_authority_based && !standard_base_scheme) {
2380529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    Parsed base_parsed_authority;
239c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    ParseStandardURL(base_spec, base_spec_len, &base_parsed_authority);
240c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (base_parsed_authority.host.is_nonempty()) {
241c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      bool did_resolve_succeed =
2420529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch          ResolveRelativeURL(base_spec, base_parsed_authority, false, relative,
2430529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                             relative_component, charset_converter, output,
2440529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                             output_parsed);
245c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      // The output_parsed is incorrect at this point (because it was built
246c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      // based on base_parsed_authority instead of base_parsed) and needs to be
247c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      // re-created.
248f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      ParsePathURL(output->data(), output->length(), true,
249f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                   output_parsed);
250c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      return did_resolve_succeed;
251c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
252c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  } else if (is_relative) {
253c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // Relative, resolve and canonicalize.
254c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    bool file_base_scheme = base_parsed.scheme.is_nonempty() &&
255c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        DoCompareSchemeComponent(base_spec, base_parsed.scheme, kFileScheme);
2560529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    return ResolveRelativeURL(base_spec, base_parsed, file_base_scheme, relative,
2570529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                              relative_component, charset_converter, output,
2580529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                              output_parsed);
259c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
260c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
261c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Not relative, canonicalize the input.
262f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  return DoCanonicalize(relative, relative_length, true, charset_converter,
263c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                        output, output_parsed);
264c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
265c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
266c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)template<typename CHAR>
267c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)bool DoReplaceComponents(const char* spec,
268c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                         int spec_len,
2690529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                         const Parsed& parsed,
2700529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                         const Replacements<CHAR>& replacements,
2710529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                         CharsetConverter* charset_converter,
2720529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                         CanonOutput* output,
2730529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                         Parsed* out_parsed) {
274c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // If the scheme is overridden, just do a simple string substitution and
275c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // reparse the whole thing. There are lots of edge cases that we really don't
276c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // want to deal with. Like what happens if I replace "http://e:8080/foo"
277c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // with a file. Does it become "file:///E:/8080/foo" where the port number
278c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // becomes part of the path? Parsing that string as a file URL says "yes"
279c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // but almost no sane rule for dealing with the components individually would
280c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // come up with that.
281c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  //
282c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Why allow these crazy cases at all? Programatically, there is almost no
283c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // case for replacing the scheme. The most common case for hitting this is
284c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // in JS when building up a URL using the location object. In this case, the
285c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // JS code expects the string substitution behavior:
286c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  //   http://www.w3.org/TR/2008/WD-html5-20080610/structured.html#common3
287c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (replacements.IsSchemeOverridden()) {
288c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // Canonicalize the new scheme so it is 8-bit and can be concatenated with
289c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // the existing spec.
2900529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    RawCanonOutput<128> scheme_replaced;
2910529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    Component scheme_replaced_parsed;
2920529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    CanonicalizeScheme(replacements.sources().scheme,
2930529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                       replacements.components().scheme,
2940529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                       &scheme_replaced, &scheme_replaced_parsed);
295c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
296c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // We can assume that the input is canonicalized, which means it always has
297c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // a colon after the scheme (or where the scheme would be).
298c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    int spec_after_colon = parsed.scheme.is_valid() ? parsed.scheme.end() + 1
299c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                                    : 1;
300c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (spec_len - spec_after_colon > 0) {
301c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      scheme_replaced.Append(&spec[spec_after_colon],
302c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                             spec_len - spec_after_colon);
303c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
304c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
305c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // We now need to completely re-parse the resulting string since its meaning
306c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // may have changed with the different scheme.
3070529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    RawCanonOutput<128> recanonicalized;
3080529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    Parsed recanonicalized_parsed;
309f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    DoCanonicalize(scheme_replaced.data(), scheme_replaced.length(), true,
310c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                   charset_converter,
311c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                   &recanonicalized, &recanonicalized_parsed);
312c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
313c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // Recurse using the version with the scheme already replaced. This will now
314c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // use the replacement rules for the new scheme.
315c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    //
316c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // Warning: this code assumes that ReplaceComponents will re-check all
317c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // components for validity. This is because we can't fail if DoCanonicalize
318c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // failed above since theoretically the thing making it fail could be
319c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // getting replaced here. If ReplaceComponents didn't re-check everything,
320c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // we wouldn't know if something *not* getting replaced is a problem.
321c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // If the scheme-specific replacers are made more intelligent so they don't
322c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // re-check everything, we should instead recanonicalize the whole thing
323c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // after this call to check validity (this assumes replacing the scheme is
324c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // much much less common than other types of replacements, like clearing the
325c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // ref).
3260529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    Replacements<CHAR> replacements_no_scheme = replacements;
3270529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    replacements_no_scheme.SetScheme(NULL, Component());
328c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return DoReplaceComponents(recanonicalized.data(), recanonicalized.length(),
329c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                               recanonicalized_parsed, replacements_no_scheme,
330c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                               charset_converter, output, out_parsed);
331c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
332c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
333c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // If we get here, then we know the scheme doesn't need to be replaced, so can
334c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // just key off the scheme in the spec to know how to do the replacements.
335cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (DoCompareSchemeComponent(spec, parsed.scheme, url::kFileScheme)) {
3360529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    return ReplaceFileURL(spec, parsed, replacements, charset_converter, output,
3370529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                          out_parsed);
338c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
339cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (DoCompareSchemeComponent(spec, parsed.scheme, url::kFileSystemScheme)) {
3400529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    return ReplaceFileSystemURL(spec, parsed, replacements, charset_converter,
3410529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                                output, out_parsed);
342c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
343c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (DoIsStandard(spec, parsed.scheme)) {
3440529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    return ReplaceStandardURL(spec, parsed, replacements, charset_converter,
3450529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                              output, out_parsed);
346c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
347cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (DoCompareSchemeComponent(spec, parsed.scheme, url::kMailToScheme)) {
3480529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    return ReplaceMailtoURL(spec, parsed, replacements, output, out_parsed);
349c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
350c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
351c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Default is a path URL.
3520529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  return ReplacePathURL(spec, parsed, replacements, output, out_parsed);
353c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
354c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
355c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}  // namespace
356c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
357c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void Initialize() {
358c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  InitStandardSchemes();
359c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
360c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
361c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void Shutdown() {
362c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (standard_schemes) {
363c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    delete standard_schemes;
364c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    standard_schemes = NULL;
365c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
366c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
367c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
368c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void AddStandardScheme(const char* new_scheme) {
369c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // If this assert triggers, it means you've called AddStandardScheme after
370c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // LockStandardSchemes have been called (see the header file for
371c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // LockStandardSchemes for more).
372c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  //
373c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // This normally means you're trying to set up a new standard scheme too late
374c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // in your application's init process. Locate where your app does this
375c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // initialization and calls LockStandardScheme, and add your new standard
376c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // scheme there.
377c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(!standard_schemes_locked) <<
378c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      "Trying to add a standard scheme after the list has been locked.";
379c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
380c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  size_t scheme_len = strlen(new_scheme);
381c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (scheme_len == 0)
382c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
383c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
384c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Dulicate the scheme into a new buffer and add it to the list of standard
385c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // schemes. This pointer will be leaked on shutdown.
386c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  char* dup_scheme = new char[scheme_len + 1];
387116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  ANNOTATE_LEAKING_OBJECT_PTR(dup_scheme);
388c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  memcpy(dup_scheme, new_scheme, scheme_len + 1);
389c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
390c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  InitStandardSchemes();
391c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  standard_schemes->push_back(dup_scheme);
392c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
393c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
394c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void LockStandardSchemes() {
395c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  standard_schemes_locked = true;
396c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
397c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
3980529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochbool IsStandard(const char* spec, const Component& scheme) {
399c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return DoIsStandard(spec, scheme);
400c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
401c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
4020529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochbool IsStandard(const base::char16* spec, const Component& scheme) {
403c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return DoIsStandard(spec, scheme);
404c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
405c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
406c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)bool FindAndCompareScheme(const char* str,
407c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          int str_len,
408c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          const char* compare,
4090529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                          Component* found_scheme) {
410c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return DoFindAndCompareScheme(str, str_len, compare, found_scheme);
411c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
412c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
4137d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)bool FindAndCompareScheme(const base::char16* str,
414c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          int str_len,
415c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          const char* compare,
4160529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                          Component* found_scheme) {
417c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return DoFindAndCompareScheme(str, str_len, compare, found_scheme);
418c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
419c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
420c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)bool Canonicalize(const char* spec,
421c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                  int spec_len,
422f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                  bool trim_path_end,
4230529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                  CharsetConverter* charset_converter,
4240529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                  CanonOutput* output,
4250529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                  Parsed* output_parsed) {
426f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  return DoCanonicalize(spec, spec_len, trim_path_end, charset_converter,
427c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                        output, output_parsed);
428c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
429c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
4307d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)bool Canonicalize(const base::char16* spec,
431c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                  int spec_len,
432f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                  bool trim_path_end,
4330529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                  CharsetConverter* charset_converter,
4340529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                  CanonOutput* output,
4350529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                  Parsed* output_parsed) {
436f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  return DoCanonicalize(spec, spec_len, trim_path_end, charset_converter,
437c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                        output, output_parsed);
438c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
439c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
440c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)bool ResolveRelative(const char* base_spec,
441c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                     int base_spec_len,
4420529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                     const Parsed& base_parsed,
443c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                     const char* relative,
444c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                     int relative_length,
4450529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                     CharsetConverter* charset_converter,
4460529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                     CanonOutput* output,
4470529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                     Parsed* output_parsed) {
448c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return DoResolveRelative(base_spec, base_spec_len, base_parsed,
449c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                           relative, relative_length,
450c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                           charset_converter, output, output_parsed);
451c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
452c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
453c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)bool ResolveRelative(const char* base_spec,
454c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                     int base_spec_len,
4550529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                     const Parsed& base_parsed,
4567d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                     const base::char16* relative,
457c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                     int relative_length,
4580529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                     CharsetConverter* charset_converter,
4590529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                     CanonOutput* output,
4600529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                     Parsed* output_parsed) {
461c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return DoResolveRelative(base_spec, base_spec_len, base_parsed,
462c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                           relative, relative_length,
463c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                           charset_converter, output, output_parsed);
464c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
465c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
466c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)bool ReplaceComponents(const char* spec,
467c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                       int spec_len,
4680529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                       const Parsed& parsed,
4690529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                       const Replacements<char>& replacements,
4700529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                       CharsetConverter* charset_converter,
4710529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                       CanonOutput* output,
4720529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                       Parsed* out_parsed) {
473c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return DoReplaceComponents(spec, spec_len, parsed, replacements,
474c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                             charset_converter, output, out_parsed);
475c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
476c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
4770529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochbool ReplaceComponents(const char* spec,
4780529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                       int spec_len,
4790529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                       const Parsed& parsed,
4800529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                       const Replacements<base::char16>& replacements,
4810529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                       CharsetConverter* charset_converter,
4820529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                       CanonOutput* output,
4830529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                       Parsed* out_parsed) {
484c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return DoReplaceComponents(spec, spec_len, parsed, replacements,
485c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                             charset_converter, output, out_parsed);
486c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
487c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
488c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Front-ends for LowerCaseEqualsASCII.
489c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)bool LowerCaseEqualsASCII(const char* a_begin,
490c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          const char* a_end,
491c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          const char* b) {
492c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return DoLowerCaseEqualsASCII(a_begin, a_end, b);
493c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
494c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
495c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)bool LowerCaseEqualsASCII(const char* a_begin,
496c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          const char* a_end,
497c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          const char* b_begin,
498c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          const char* b_end) {
499c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  while (a_begin != a_end && b_begin != b_end &&
500c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)         ToLowerASCII(*a_begin) == *b_begin) {
501c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    a_begin++;
502c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    b_begin++;
503c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
504c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return a_begin == a_end && b_begin == b_end;
505c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
506c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
5077d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)bool LowerCaseEqualsASCII(const base::char16* a_begin,
5087d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                          const base::char16* a_end,
509c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          const char* b) {
510c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return DoLowerCaseEqualsASCII(a_begin, a_end, b);
511c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
512c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
5130529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochvoid DecodeURLEscapeSequences(const char* input,
5140529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                              int length,
5150529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                              CanonOutputW* output) {
5160529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  RawCanonOutputT<char> unescaped_chars;
517c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  for (int i = 0; i < length; i++) {
518c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (input[i] == '%') {
519c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      unsigned char ch;
5200529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      if (DecodeEscaped(input, &i, length, &ch)) {
521c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        unescaped_chars.push_back(ch);
522c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      } else {
523c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        // Invalid escape sequence, copy the percent literal.
524c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        unescaped_chars.push_back('%');
525c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      }
526c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    } else {
527c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      // Regular non-escaped 8-bit character.
528c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      unescaped_chars.push_back(input[i]);
529c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
530c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
531c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
532c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Convert that 8-bit to UTF-16. It's not clear IE does this at all to
533c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // JavaScript URLs, but Firefox and Safari do.
534c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  for (int i = 0; i < unescaped_chars.length(); i++) {
535c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    unsigned char uch = static_cast<unsigned char>(unescaped_chars.at(i));
536c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (uch < 0x80) {
537c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      // Non-UTF-8, just append directly
538c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      output->push_back(uch);
539c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    } else {
540c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      // next_ch will point to the last character of the decoded
541c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      // character.
542c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      int next_character = i;
543c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      unsigned code_point;
5440529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      if (ReadUTFChar(unescaped_chars.data(), &next_character,
5450529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                      unescaped_chars.length(), &code_point)) {
546c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        // Valid UTF-8 character, convert to UTF-16.
5470529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        AppendUTF16Value(code_point, output);
548c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        i = next_character;
549c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      } else {
550c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        // If there are any sequences that are not valid UTF-8, we keep
551c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        // invalid code points and promote to UTF-16. We copy all characters
552c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        // from the current position to the end of the identified sequence.
553c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        while (i < next_character) {
554c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          output->push_back(static_cast<unsigned char>(unescaped_chars.at(i)));
555c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          i++;
556c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        }
557c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        output->push_back(static_cast<unsigned char>(unescaped_chars.at(i)));
558c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      }
559c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
560c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
561c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
562c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
5630529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochvoid EncodeURIComponent(const char* input, int length, CanonOutput* output) {
564c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  for (int i = 0; i < length; ++i) {
565c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    unsigned char c = static_cast<unsigned char>(input[i]);
5660529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    if (IsComponentChar(c))
567c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      output->push_back(c);
568c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    else
569c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      AppendEscapedChar(c, output);
570c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
571c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
572c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
573c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)bool CompareSchemeComponent(const char* spec,
5740529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                            const Component& component,
575c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                            const char* compare_to) {
576c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return DoCompareSchemeComponent(spec, component, compare_to);
577c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
578c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
5797d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)bool CompareSchemeComponent(const base::char16* spec,
5800529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                            const Component& component,
581c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                            const char* compare_to) {
582c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return DoCompareSchemeComponent(spec, component, compare_to);
583c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
584c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
5850529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch}  // namespace url
586