1c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Copyright 2007, Google Inc.
2c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// All rights reserved.
3c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott//
4c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Redistribution and use in source and binary forms, with or without
5c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// modification, are permitted provided that the following conditions are
6c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// met:
7c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott//
8c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott//     * Redistributions of source code must retain the above copyright
9c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// notice, this list of conditions and the following disclaimer.
10c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott//     * Redistributions in binary form must reproduce the above
11c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// copyright notice, this list of conditions and the following disclaimer
12c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// in the documentation and/or other materials provided with the
13c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// distribution.
14c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott//     * Neither the name of Google Inc. nor the names of its
15c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// contributors may be used to endorse or promote products derived from
16c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// this software without specific prior written permission.
17c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott//
18c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Canonicalization functions for the paths of URLs.
30c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
31c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "base/logging.h"
32c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "googleurl/src/url_canon.h"
33c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "googleurl/src/url_canon_internal.h"
34c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "googleurl/src/url_parse_internal.h"
35c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
36c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottnamespace url_canon {
37c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
38c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottnamespace {
39c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
40c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottenum CharacterFlags {
41c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Pass through unchanged, whether escaped or unescaped. This doesn't
42c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // actually set anything so you can't OR it to check, it's just to make the
43c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // table below more clear when neither ESCAPE or UNESCAPE is set.
44c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  PASS = 0,
45c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
46c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // This character requires special handling in DoPartialPath. Doing this test
47c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // first allows us to filter out the common cases of regular characters that
48c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // can be directly copied.
49c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  SPECIAL = 1,
50c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
51c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // This character must be escaped in the canonical output. Note that all
52c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // escaped chars also have the "special" bit set so that the code that looks
53c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // for this is triggered. Not valid with PASS or ESCAPE
54c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  ESCAPE_BIT = 2,
55c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  ESCAPE = ESCAPE_BIT | SPECIAL,
56c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
57c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // This character must be unescaped in canonical output. Not valid with
58c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // ESCAPE or PASS. We DON'T set the SPECIAL flag since if we encounter these
59c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // characters unescaped, they should just be copied.
60c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  UNESCAPE = 4,
61c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
62c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // This character is disallowed in URLs. Note that the "special" bit is also
63c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // set to trigger handling.
64c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  INVALID_BIT = 8,
65c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  INVALID = INVALID_BIT | SPECIAL,
66c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott};
67c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
68c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// This table contains one of the above flag values. Note some flags are more
69c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// than one bits because they also turn on the "special" flag. Special is the
70c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// only flag that may be combined with others.
71c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott//
72c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// This table is designed to match exactly what IE does with the characters.
73c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott//
74c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Dot is even more special, and the escaped version is handled specially by
75c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// IsDot. Therefore, we don't need the "escape" flag, and even the "unescape"
76c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// bit is never handled (we just need the "special") bit.
77c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottconst unsigned char kPathCharLookup[0x100] = {
78c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott//   NULL     control chars...
79c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott     INVALID, ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,
80c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott//   control chars...
81c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott     ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,
82c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott//   ' '      !        "        #        $        %        &        '        (        )        *        +        ,        -        .        /
83c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott     ESCAPE,  PASS,    ESCAPE,  ESCAPE,  PASS,    ESCAPE,  PASS,    PASS,    PASS,    PASS,    PASS,    PASS,    PASS,    UNESCAPE,SPECIAL, PASS,
84c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott//   0        1        2        3        4        5        6        7        8        9        :        ;        <        =        >        ?
85c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott     UNESCAPE,UNESCAPE,UNESCAPE,UNESCAPE,UNESCAPE,UNESCAPE,UNESCAPE,UNESCAPE,UNESCAPE,UNESCAPE,PASS,    PASS,    ESCAPE,  PASS,    ESCAPE,  ESCAPE,
86c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott//   @        A        B        C        D        E        F        G        H        I        J        K        L        M        N        O
87c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch     PASS,    UNESCAPE,UNESCAPE,UNESCAPE,UNESCAPE,UNESCAPE,UNESCAPE,UNESCAPE,UNESCAPE,UNESCAPE,UNESCAPE,UNESCAPE,UNESCAPE,UNESCAPE,UNESCAPE,UNESCAPE,
88c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott//   P        Q        R        S        T        U        V        W        X        Y        Z        [        \        ]        ^        _
89c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott     UNESCAPE,UNESCAPE,UNESCAPE,UNESCAPE,UNESCAPE,UNESCAPE,UNESCAPE,UNESCAPE,UNESCAPE,UNESCAPE,UNESCAPE,PASS,    ESCAPE,  PASS,    ESCAPE,  UNESCAPE,
90c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott//   `        a        b        c        d        e        f        g        h        i        j        k        l        m        n        o
91c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott     ESCAPE,  UNESCAPE,UNESCAPE,UNESCAPE,UNESCAPE,UNESCAPE,UNESCAPE,UNESCAPE,UNESCAPE,UNESCAPE,UNESCAPE,UNESCAPE,UNESCAPE,UNESCAPE,UNESCAPE,UNESCAPE,
92c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott//   p        q        r        s        t        u        v        w        x        y        z        {        |        }        ~        <NBSP>
93c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott     UNESCAPE,UNESCAPE,UNESCAPE,UNESCAPE,UNESCAPE,UNESCAPE,UNESCAPE,UNESCAPE,UNESCAPE,UNESCAPE,UNESCAPE,ESCAPE,  ESCAPE,  ESCAPE,  UNESCAPE,ESCAPE,
94c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott//   ...all the high-bit characters are escaped
95c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott     ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,
96c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott     ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,
97c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott     ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,
98c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott     ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,
99c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott     ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,
100c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott     ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,
101c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott     ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,
102c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott     ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE,  ESCAPE};
103c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
104c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottenum DotDisposition {
105c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // The given dot is just part of a filename and is not special.
106c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  NOT_A_DIRECTORY,
107c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
108c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // The given dot is the current directory.
109c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DIRECTORY_CUR,
110c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
111c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // The given dot is the first of a double dot that should take us up one.
112c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DIRECTORY_UP
113c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott};
114c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
115c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// When the path resolver finds a dot, this function is called with the
116c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// character following that dot to see what it is. The return value
117c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// indicates what type this dot is (see above). This code handles the case
118c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// where the dot is at the end of the input.
119c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott//
120c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// |*consumed_len| will contain the number of characters in the input that
121c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// express what we found.
122c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott//
123c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// If the input is "../foo", |after_dot| = 1, |end| = 6, and
124c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// at the end, |*consumed_len| = 2 for the "./" this function consumed. The
125c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// original dot length should be handled by the caller.
126c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scotttemplate<typename CHAR>
127c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottDotDisposition ClassifyAfterDot(const CHAR* spec, int after_dot,
128c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                                int end, int* consumed_len) {
129c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (after_dot == end) {
130c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // Single dot at the end.
131c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    *consumed_len = 0;
132c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return DIRECTORY_CUR;
133c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
134c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (url_parse::IsURLSlash(spec[after_dot])) {
135c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // Single dot followed by a slash.
136c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    *consumed_len = 1;  // Consume the slash
137c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return DIRECTORY_CUR;
138c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
139c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
140c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  int second_dot_len = IsDot(spec, after_dot, end);
141c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (second_dot_len) {
142c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    int after_second_dot = after_dot + second_dot_len;
143c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (after_second_dot == end) {
144c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      // Double dot at the end.
145c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      *consumed_len = second_dot_len;
146c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      return DIRECTORY_UP;
147c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    }
148c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (url_parse::IsURLSlash(spec[after_second_dot])) {
149c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      // Double dot followed by a slash.
150c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      *consumed_len = second_dot_len + 1;
151c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      return DIRECTORY_UP;
152c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    }
153c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
154c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
155c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // The dots are followed by something else, not a directory.
156c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  *consumed_len = 0;
157c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return NOT_A_DIRECTORY;
158c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
159c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
160c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Rewinds the output to the previous slash. It is assumed that the output
161c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// ends with a slash and this doesn't count (we call this when we are
162c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// appending directory paths, so the previous path component has and ending
163c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// slash).
164c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott//
165c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// This will stop at the first slash (assumed to be at position
166c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// |path_begin_in_output| and not go any higher than that. Some web pages
167c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// do ".." too many times, so we need to handle that brokenness.
168c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott//
169c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// It searches for a literal slash rather than including a backslash as well
170c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// because it is run only on the canonical output.
171c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott//
172c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// The output is guaranteed to end in a slash when this function completes.
173c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid BackUpToPreviousSlash(int path_begin_in_output,
174c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                           CanonOutput* output) {
175c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK(output->length() > 0);
176c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
177c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  int i = output->length() - 1;
178c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK(output->at(i) == '/');
179c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (i == path_begin_in_output)
180c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return;  // We're at the first slash, nothing to do.
181c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
182c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Now back up (skipping the trailing slash) until we find another slash.
183c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  i--;
184c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  while (output->at(i) != '/' && i > path_begin_in_output)
185c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    i--;
186c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
187c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Now shrink the output to just include that last slash we found.
188c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  output->set_length(i + 1);
189c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
190c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
191c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Appends the given path to the output. It assumes that if the input path
192c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// starts with a slash, it should be copied to the output. If no path has
193c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// already been appended to the output (the case when not resolving
194c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// relative URLs), the path should begin with a slash.
195c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott//
196c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// If there are already path components (this mode is used when appending
197c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// relative paths for resolving), it assumes that the output already has
198c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// a trailing slash and that if the input begins with a slash, it should be
199c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// copied to the output.
200c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott//
201c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// We do not collapse multiple slashes in a row to a single slash. It seems
202c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// no web browsers do this, and we don't want incompababilities, even though
203c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// it would be correct for most systems.
204c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scotttemplate<typename CHAR, typename UCHAR>
205c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottbool DoPartialPath(const CHAR* spec,
206c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                   const url_parse::Component& path,
207c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                   int path_begin_in_output,
208c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                   CanonOutput* output) {
209c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  int end = path.end();
210c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
211c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  bool success = true;
212c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  for (int i = path.begin; i < end; i++) {
213c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    UCHAR uch = static_cast<UCHAR>(spec[i]);
214c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (sizeof(CHAR) > sizeof(char) && uch >= 0x80) {
215c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      // We only need to test wide input for having non-ASCII characters. For
216c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      // narrow input, we'll always just use the lookup table. We don't try to
217c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      // do anything tricky with decoding/validating UTF-8. This function will
218c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      // read one or two UTF-16 characters and append the output as UTF-8. This
219c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      // call will be removed in 8-bit mode.
220c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      success &= AppendUTF8EscapedChar(spec, &i, end, output);
221c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    } else {
222c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      // Normal ASCII character or 8-bit input, use the lookup table.
223c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      unsigned char out_ch = static_cast<unsigned char>(uch);
224c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      unsigned char flags = kPathCharLookup[out_ch];
225c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      if (flags & SPECIAL) {
226c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        // Needs special handling of some sort.
227c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        int dotlen;
228c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        if ((dotlen = IsDot(spec, i, end)) > 0) {
229c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott          // See if this dot was preceeded by a slash in the output. We
230c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott          // assume that when canonicalizing paths, they will always
231c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott          // start with a slash and not a dot, so we don't have to
232c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott          // bounds check the output.
233c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott          //
234c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott          // Note that we check this in the case of dots so we don't have to
235c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott          // special case slashes. Since slashes are much more common than
236c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott          // dots, this actually increases performance measurably (though
237c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott          // slightly).
238c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott          DCHECK(output->length() > path_begin_in_output);
239c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott          if (output->length() > path_begin_in_output &&
240c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott              output->at(output->length() - 1) == '/') {
241c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott            // Slash followed by a dot, check to see if this is means relative
242c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott            int consumed_len;
243c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott            switch (ClassifyAfterDot<CHAR>(spec, i + dotlen, end,
244c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                                           &consumed_len)) {
245c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott              case NOT_A_DIRECTORY:
246c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                // Copy the dot to the output, it means nothing special.
247c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                output->push_back('.');
248c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                i += dotlen - 1;
249c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                break;
250c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott              case DIRECTORY_CUR:  // Current directory, just skip the input.
251c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                i += dotlen + consumed_len - 1;
252c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                break;
253c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott              case DIRECTORY_UP:
254c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                BackUpToPreviousSlash(path_begin_in_output, output);
255c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                i += dotlen + consumed_len - 1;
256c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                break;
257c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott            }
258c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott          } else {
259c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott            // This dot is not preceeded by a slash, it is just part of some
260c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott            // file name.
261c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott            output->push_back('.');
262c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott            i += dotlen - 1;
263c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott          }
264c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
265c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        } else if (out_ch == '\\') {
266c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott          // Convert backslashes to forward slashes
267c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott          output->push_back('/');
268c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
269c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        } else if (out_ch == '%') {
270c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott          // Handle escape sequences.
271c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott          unsigned char unescaped_value;
272c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott          if (DecodeEscaped(spec, &i, end, &unescaped_value)) {
273c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott            // Valid escape sequence, see if we keep, reject, or unescape it.
274c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott            char unescaped_flags = kPathCharLookup[unescaped_value];
275c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
276c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott            if (unescaped_flags & UNESCAPE) {
277c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott              // This escaped value shouldn't be escaped, copy it.
278c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott              output->push_back(unescaped_value);
279c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott            } else if (unescaped_flags & INVALID_BIT) {
280c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott              // Invalid escaped character, copy it and remember the error.
281c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott              output->push_back('%');
282c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott              output->push_back(static_cast<char>(spec[i - 1]));
283c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott              output->push_back(static_cast<char>(spec[i]));
284c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott              success = false;
285c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott            } else {
286c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott              // Valid escaped character but we should keep it escaped. We
287c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott              // don't want to change the case of any hex letters in case
288c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott              // the server is sensitive to that, so we just copy the two
289c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott              // characters without checking (DecodeEscape will have advanced
290c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott              // to the last character of the pair).
291c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott              output->push_back('%');
292c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott              output->push_back(static_cast<char>(spec[i - 1]));
293c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott              output->push_back(static_cast<char>(spec[i]));
294c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott            }
295c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott          } else {
296c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott            // Invalid escape sequence. IE7 rejects any URLs with such
297c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott            // sequences, while Firefox, IE6, and Safari all pass it through
298c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott            // unchanged. We are more permissive unlike IE7. I don't think this
299c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott            // can cause significant problems, if it does, we should change
300c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott            // to be more like IE7.
301c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott            output->push_back('%');
302c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott          }
303c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
304c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        } else if (flags & INVALID_BIT) {
305c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott          // For NULLs, etc. fail.
306c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott          AppendEscapedChar(out_ch, output);
307c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott          success = false;
308c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
309c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        } else if (flags & ESCAPE_BIT) {
310c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott          // This character should be escaped.
311c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott          AppendEscapedChar(out_ch, output);
312c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        }
313c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      } else {
314c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        // Nothing special about this character, just append it.
315c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        output->push_back(out_ch);
316c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      }
317c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    }
318c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
319c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return success;
320c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
321c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
322c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scotttemplate<typename CHAR, typename UCHAR>
323c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottbool DoPath(const CHAR* spec,
324c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott            const url_parse::Component& path,
325c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott            CanonOutput* output,
326c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott            url_parse::Component* out_path) {
327c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  bool success = true;
328c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (path.len > 0) {
329c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    out_path->begin = output->length();
330c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
331c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // Write out an initial slash if the input has none. If we just parse a URL
332c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // and then canonicalize it, it will of course have a slash already. This
333c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // check is for the replacement and relative URL resolving cases of file
334c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // URLs.
335c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (!url_parse::IsURLSlash(spec[path.begin]))
336c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      output->push_back('/');
337c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
338c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    success = DoPartialPath<CHAR, UCHAR>(spec, path, out_path->begin, output);
339c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    out_path->len = output->length() - out_path->begin;
340c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  } else {
341c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // No input, canonical path is a slash.
342c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    output->push_back('/');
343c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    *out_path = url_parse::Component();
344c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
345c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return success;
346c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
347c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
348c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}  // namespace
349c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
350c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottbool CanonicalizePath(const char* spec,
351c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                      const url_parse::Component& path,
352c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                      CanonOutput* output,
353c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                      url_parse::Component* out_path) {
354c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return DoPath<char, unsigned char>(spec, path, output, out_path);
355c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
356c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
357c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottbool CanonicalizePath(const char16* spec,
358c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                      const url_parse::Component& path,
359c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                      CanonOutput* output,
360c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                      url_parse::Component* out_path) {
361c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return DoPath<char16, char16>(spec, path, output, out_path);
362c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
363c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
364c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottbool CanonicalizePartialPath(const char* spec,
365c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                             const url_parse::Component& path,
366c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                             int path_begin_in_output,
367c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                             CanonOutput* output) {
368c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return DoPartialPath<char, unsigned char>(spec, path, path_begin_in_output,
369c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                                            output);
370c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
371c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
372c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottbool CanonicalizePartialPath(const char16* spec,
373c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                             const url_parse::Component& path,
374c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                             int path_begin_in_output,
375c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                             CanonOutput* output) {
376c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return DoPartialPath<char16, char16>(spec, path, path_begin_in_output,
377c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                                       output);
378c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
379c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
380c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}  // namespace url_canon
381