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)// Canonicalizers for random bits that aren't big enough for their own files.
6c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
7c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include <string.h>
8c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
9c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "url/url_canon.h"
10c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "url/url_canon_internal.h"
11c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
12c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)namespace url_canon {
13c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
14c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)namespace {
15c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
16c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Returns true if the given character should be removed from the middle of a
17c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// URL.
18c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)inline bool IsRemovableURLWhitespace(int ch) {
19c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return ch == '\r' || ch == '\n' || ch == '\t';
20c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
21c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
22c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Backend for RemoveURLWhitespace (see declaration in url_canon.h).
23c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// It sucks that we have to do this, since this takes about 13% of the total URL
24c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// canonicalization time.
25c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)template<typename CHAR>
26c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)const CHAR* DoRemoveURLWhitespace(const CHAR* input, int input_len,
27c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                  CanonOutputT<CHAR>* buffer,
28c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                  int* output_len) {
29c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Fast verification that there's nothing that needs removal. This is the 99%
30c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // case, so we want it to be fast and don't care about impacting the speed
31c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // when we do find whitespace.
32c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  int found_whitespace = false;
33c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  for (int i = 0; i < input_len; i++) {
34c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (!IsRemovableURLWhitespace(input[i]))
35c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      continue;
36c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    found_whitespace = true;
37c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    break;
38c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
39c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
40c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!found_whitespace) {
41c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // Didn't find any whitespace, we don't need to do anything. We can just
42c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // return the input as the output.
43c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    *output_len = input_len;
44c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return input;
45c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
46c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
47c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Remove the whitespace into the new buffer and return it.
48c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  for (int i = 0; i < input_len; i++) {
49c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (!IsRemovableURLWhitespace(input[i]))
50c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      buffer->push_back(input[i]);
51c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
52c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  *output_len = buffer->length();
53c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return buffer->data();
54c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
55c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
56c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Contains the canonical version of each possible input letter in the scheme
57c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// (basically, lower-cased). The corresponding entry will be 0 if the letter
58c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// is not allowed in a scheme.
59c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)const char kSchemeCanonical[0x80] = {
60c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// 00-1f: all are invalid
61c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
62c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
63c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)//  ' '   !    "    #    $    %    &    '    (    )    *    +    ,    -    .    /
64c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  '+',  0,  '-', '.',  0,
65c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)//   0    1    2    3    4    5    6    7    8    9    :    ;    <    =    >    ?
66c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,
67c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)//   @    A    B    C    D    E    F    G    H    I    J    K    L    M    N    O
68c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)     0 , 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
69c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)//   P    Q    R    S    T    U    V    W    X    Y    Z    [    \    ]    ^    _
70c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',  0,   0 ,  0,   0 ,  0,
71c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)//   `    a    b    c    d    e    f    g    h    i    j    k    l    m    n    o
72c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)     0 , 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
73c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)//   p    q    r    s    t    u    v    w    x    y    z    {    |    }    ~
74c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',  0 ,  0 ,  0 ,  0 ,  0 };
75c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
76c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// This could be a table lookup as well by setting the high bit for each
77c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// valid character, but it's only called once per URL, and it makes the lookup
78c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// table easier to read not having extra stuff in it.
79c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)inline bool IsSchemeFirstChar(unsigned char c) {
80c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
81c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
82c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
83c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)template<typename CHAR, typename UCHAR>
84c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)bool DoScheme(const CHAR* spec,
85c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)              const url_parse::Component& scheme,
86c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)              CanonOutput* output,
87c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)              url_parse::Component* out_scheme) {
88c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (scheme.len <= 0) {
89c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // Scheme is unspecified or empty, convert to empty by appending a colon.
90c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    *out_scheme = url_parse::Component(output->length(), 0);
91c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    output->push_back(':');
92c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return true;
93c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
94c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
95c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // The output scheme starts from the current position.
96c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  out_scheme->begin = output->length();
97c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
98c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Danger: it's important that this code does not strip any characters: it
99c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // only emits the canonical version (be it valid or escaped) of each of
100c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // the input characters. Stripping would put it out of sync with
101c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // url_util::FindAndCompareScheme, which could cause some security checks on
102c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // schemes to be incorrect.
103c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  bool success = true;
104c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  int end = scheme.end();
105c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  for (int i = scheme.begin; i < end; i++) {
106c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    UCHAR ch = static_cast<UCHAR>(spec[i]);
107c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    char replacement = 0;
108c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (ch < 0x80) {
109c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      if (i == scheme.begin) {
110c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        // Need to do a special check for the first letter of the scheme.
111c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        if (IsSchemeFirstChar(static_cast<unsigned char>(ch)))
112c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          replacement = kSchemeCanonical[ch];
113c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      } else {
114c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        replacement = kSchemeCanonical[ch];
115c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      }
116c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
117c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
118c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (replacement) {
119c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      output->push_back(replacement);
120c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    } else if (ch == '%') {
121c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      // Canonicalizing the scheme multiple times should lead to the same
122c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      // result. Since invalid characters will be escaped, we need to preserve
123c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      // the percent to avoid multiple escaping. The scheme will be invalid.
124c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      success = false;
125c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      output->push_back('%');
126c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    } else {
127c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      // Invalid character, store it but mark this scheme as invalid.
128c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      success = false;
129c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
130c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      // This will escape the output and also handle encoding issues.
131c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      // Ignore the return value since we already failed.
132c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      AppendUTF8EscapedChar(spec, &i, end, output);
133c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
134c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
135c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
136c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // The output scheme ends with the the current position, before appending
137c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // the colon.
138c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  out_scheme->len = output->length() - out_scheme->begin;
139c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  output->push_back(':');
140c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return success;
141c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
142c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
143c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// The username and password components reference ranges in the corresponding
144c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// *_spec strings. Typically, these specs will be the same (we're
145c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// canonicalizing a single source string), but may be different when
146c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// replacing components.
147c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)template<typename CHAR, typename UCHAR>
148c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)bool DoUserInfo(const CHAR* username_spec,
149c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                const url_parse::Component& username,
150c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                const CHAR* password_spec,
151c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                const url_parse::Component& password,
152c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                CanonOutput* output,
153c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                url_parse::Component* out_username,
154c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                url_parse::Component* out_password) {
155c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (username.len <= 0 && password.len <= 0) {
156c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // Common case: no user info. We strip empty username/passwords.
157c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    *out_username = url_parse::Component();
158c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    *out_password = url_parse::Component();
159c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return true;
160c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
161c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
162c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Write the username.
163c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  out_username->begin = output->length();
164c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (username.len > 0) {
165c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // This will escape characters not valid for the username.
166c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    AppendStringOfType(&username_spec[username.begin], username.len,
167c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                       CHAR_USERINFO, output);
168c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
169c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  out_username->len = output->length() - out_username->begin;
170c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
171c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // When there is a password, we need the separator. Note that we strip
172c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // empty but specified passwords.
173c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (password.len > 0) {
174c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    output->push_back(':');
175c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    out_password->begin = output->length();
176c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    AppendStringOfType(&password_spec[password.begin], password.len,
177c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                       CHAR_USERINFO, output);
178c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    out_password->len = output->length() - out_password->begin;
179c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  } else {
180c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    *out_password = url_parse::Component();
181c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
182c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
183c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  output->push_back('@');
184c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return true;
185c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
186c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
187c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Helper functions for converting port integers to strings.
188c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)inline void WritePortInt(char* output, int output_len, int port) {
189c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  _itoa_s(port, output, output_len, 10);
190c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
191c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
192c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// This function will prepend the colon if there will be a port.
193c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)template<typename CHAR, typename UCHAR>
194c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)bool DoPort(const CHAR* spec,
195c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            const url_parse::Component& port,
196c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            int default_port_for_scheme,
197c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            CanonOutput* output,
198c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            url_parse::Component* out_port) {
199c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  int port_num = url_parse::ParsePort(spec, port);
200c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (port_num == url_parse::PORT_UNSPECIFIED ||
201c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      port_num == default_port_for_scheme) {
202c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    *out_port = url_parse::Component();
203c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return true;  // Leave port empty.
204c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
205c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
206c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (port_num == url_parse::PORT_INVALID) {
207c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // Invalid port: We'll copy the text from the input so the user can see
208c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // what the error was, and mark the URL as invalid by returning false.
209c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    output->push_back(':');
210c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    out_port->begin = output->length();
211c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    AppendInvalidNarrowString(spec, port.begin, port.end(), output);
212c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    out_port->len = output->length() - out_port->begin;
213c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return false;
214c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
215c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
216c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Convert port number back to an integer. Max port value is 5 digits, and
217c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // the Parsed::ExtractPort will have made sure the integer is in range.
218c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  const int buf_size = 6;
219c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  char buf[buf_size];
220c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  WritePortInt(buf, buf_size, port_num);
221c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
222c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Append the port number to the output, preceeded by a colon.
223c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  output->push_back(':');
224c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  out_port->begin = output->length();
225c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  for (int i = 0; i < buf_size && buf[i]; i++)
226c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    output->push_back(buf[i]);
227c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
228c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  out_port->len = output->length() - out_port->begin;
229c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return true;
230c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
231c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
232c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)template<typename CHAR, typename UCHAR>
233c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void DoCanonicalizeRef(const CHAR* spec,
234c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                       const url_parse::Component& ref,
235c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                       CanonOutput* output,
236c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                       url_parse::Component* out_ref) {
237c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (ref.len < 0) {
238c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // Common case of no ref.
239c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    *out_ref = url_parse::Component();
240c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
241c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
242c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
243c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Append the ref separator. Note that we need to do this even when the ref
244c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // is empty but present.
245c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  output->push_back('#');
246c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  out_ref->begin = output->length();
247c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
248c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Now iterate through all the characters, converting to UTF-8 and validating.
249c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  int end = ref.end();
250c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  for (int i = ref.begin; i < end; i++) {
251c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (spec[i] == 0) {
252c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      // IE just strips NULLs, so we do too.
253c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      continue;
254c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    } else if (static_cast<UCHAR>(spec[i]) < 0x20) {
255c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      // Unline IE seems to, we escape control characters. This will probably
256c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      // make the reference fragment unusable on a web page, but people
257c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      // shouldn't be using control characters in their anchor names.
258c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      AppendEscapedChar(static_cast<unsigned char>(spec[i]), output);
259c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    } else if (static_cast<UCHAR>(spec[i]) < 0x80) {
260c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      // Normal ASCII characters are just appended.
261c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      output->push_back(static_cast<char>(spec[i]));
262c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    } else {
263c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      // Non-ASCII characters are appended unescaped, but only when they are
264c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      // valid. Invalid Unicode characters are replaced with the "invalid
265c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      // character" as IE seems to (ReadUTFChar puts the unicode replacement
266c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      // character in the output on failure for us).
267c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      unsigned code_point;
268c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      ReadUTFChar(spec, &i, end, &code_point);
269c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      AppendUTF8Value(code_point, output);
270c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
271c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
272c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
273c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  out_ref->len = output->length() - out_ref->begin;
274c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
275c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
276c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}  // namespace
277c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
278c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)const char* RemoveURLWhitespace(const char* input, int input_len,
279c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                CanonOutputT<char>* buffer,
280c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                int* output_len) {
281c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return DoRemoveURLWhitespace(input, input_len, buffer, output_len);
282c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
283c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
2847d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)const base::char16* RemoveURLWhitespace(const base::char16* input,
2857d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                                        int input_len,
2867d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                                        CanonOutputT<base::char16>* buffer,
2877d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                                        int* output_len) {
288c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return DoRemoveURLWhitespace(input, input_len, buffer, output_len);
289c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
290c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
2917d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)char CanonicalSchemeChar(base::char16 ch) {
292c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (ch >= 0x80)
293c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return 0;  // Non-ASCII is not supported by schemes.
294c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return kSchemeCanonical[ch];
295c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
296c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
297c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)bool CanonicalizeScheme(const char* spec,
298c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                        const url_parse::Component& scheme,
299c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                        CanonOutput* output,
300c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                        url_parse::Component* out_scheme) {
301c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return DoScheme<char, unsigned char>(spec, scheme, output, out_scheme);
302c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
303c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
3047d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)bool CanonicalizeScheme(const base::char16* spec,
305c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                        const url_parse::Component& scheme,
306c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                        CanonOutput* output,
307c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                        url_parse::Component* out_scheme) {
3087d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return DoScheme<base::char16, base::char16>(spec, scheme, output, out_scheme);
309c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
310c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
311c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)bool CanonicalizeUserInfo(const char* username_source,
312c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          const url_parse::Component& username,
313c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          const char* password_source,
314c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          const url_parse::Component& password,
315c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          CanonOutput* output,
316c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          url_parse::Component* out_username,
317c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          url_parse::Component* out_password) {
318c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return DoUserInfo<char, unsigned char>(
319c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      username_source, username, password_source, password,
320c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      output, out_username, out_password);
321c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
322c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
3237d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)bool CanonicalizeUserInfo(const base::char16* username_source,
324c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          const url_parse::Component& username,
3257d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                          const base::char16* password_source,
326c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          const url_parse::Component& password,
327c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          CanonOutput* output,
328c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          url_parse::Component* out_username,
329c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          url_parse::Component* out_password) {
3307d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return DoUserInfo<base::char16, base::char16>(
331c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      username_source, username, password_source, password,
332c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      output, out_username, out_password);
333c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
334c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
335c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)bool CanonicalizePort(const char* spec,
336c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                      const url_parse::Component& port,
337c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                      int default_port_for_scheme,
338c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                      CanonOutput* output,
339c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                      url_parse::Component* out_port) {
340c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return DoPort<char, unsigned char>(spec, port,
341c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                     default_port_for_scheme,
342c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                     output, out_port);
343c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
344c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
3457d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)bool CanonicalizePort(const base::char16* spec,
346c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                      const url_parse::Component& port,
347c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                      int default_port_for_scheme,
348c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                      CanonOutput* output,
349c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                      url_parse::Component* out_port) {
3507d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return DoPort<base::char16, base::char16>(spec, port, default_port_for_scheme,
3517d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                                            output, out_port);
352c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
353c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
354c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void CanonicalizeRef(const char* spec,
355c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                     const url_parse::Component& ref,
356c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                     CanonOutput* output,
357c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                     url_parse::Component* out_ref) {
358c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DoCanonicalizeRef<char, unsigned char>(spec, ref, output, out_ref);
359c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
360c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
3617d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)void CanonicalizeRef(const base::char16* spec,
362c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                     const url_parse::Component& ref,
363c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                     CanonOutput* output,
364c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                     url_parse::Component* out_ref) {
3657d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  DoCanonicalizeRef<base::char16, base::char16>(spec, ref, output, out_ref);
366c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
367c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
368c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}  // namespace url_canon
369