| // Copyright 2013 The Chromium Authors. All rights reserved. | 
 | // Use of this source code is governed by a BSD-style license that can be | 
 | // found in the LICENSE file. | 
 |  | 
 | // Functions for canonicalizing "file:" URLs. | 
 |  | 
 | #include "url/url_canon.h" | 
 | #include "url/url_canon_internal.h" | 
 | #include "url/url_file.h" | 
 | #include "url/url_parse_internal.h" | 
 |  | 
 | namespace url { | 
 |  | 
 | namespace { | 
 |  | 
 | #ifdef WIN32 | 
 |  | 
 | // Given a pointer into the spec, this copies and canonicalizes the drive | 
 | // letter and colon to the output, if one is found. If there is not a drive | 
 | // spec, it won't do anything. The index of the next character in the input | 
 | // spec is returned (after the colon when a drive spec is found, the begin | 
 | // offset if one is not). | 
 | template<typename CHAR> | 
 | int FileDoDriveSpec(const CHAR* spec, int begin, int end, | 
 |                     CanonOutput* output) { | 
 |   // The path could be one of several things: /foo/bar, c:/foo/bar, /c:/foo, | 
 |   // (with backslashes instead of slashes as well). | 
 |   int num_slashes = CountConsecutiveSlashes(spec, begin, end); | 
 |   int after_slashes = begin + num_slashes; | 
 |  | 
 |   if (!DoesBeginWindowsDriveSpec(spec, after_slashes, end)) | 
 |     return begin;  // Haven't consumed any characters | 
 |  | 
 |   // A drive spec is the start of a path, so we need to add a slash for the | 
 |   // authority terminator (typically the third slash). | 
 |   output->push_back('/'); | 
 |  | 
 |   // DoesBeginWindowsDriveSpec will ensure that the drive letter is valid | 
 |   // and that it is followed by a colon/pipe. | 
 |  | 
 |   // Normalize Windows drive letters to uppercase | 
 |   if (spec[after_slashes] >= 'a' && spec[after_slashes] <= 'z') | 
 |     output->push_back(static_cast<char>(spec[after_slashes] - 'a' + 'A')); | 
 |   else | 
 |     output->push_back(static_cast<char>(spec[after_slashes])); | 
 |  | 
 |   // Normalize the character following it to a colon rather than pipe. | 
 |   output->push_back(':'); | 
 |   return after_slashes + 2; | 
 | } | 
 |  | 
 | #endif  // WIN32 | 
 |  | 
 | template<typename CHAR, typename UCHAR> | 
 | bool DoFileCanonicalizePath(const CHAR* spec, | 
 |                             const Component& path, | 
 |                             CanonOutput* output, | 
 |                             Component* out_path) { | 
 |   // Copies and normalizes the "c:" at the beginning, if present. | 
 |   out_path->begin = output->length(); | 
 |   int after_drive; | 
 | #ifdef WIN32 | 
 |   after_drive = FileDoDriveSpec(spec, path.begin, path.end(), output); | 
 | #else | 
 |   after_drive = path.begin; | 
 | #endif | 
 |  | 
 |   // Copies the rest of the path, starting from the slash following the | 
 |   // drive colon (if any, Windows only), or the first slash of the path. | 
 |   bool success = true; | 
 |   if (after_drive < path.end()) { | 
 |     // Use the regular path canonicalizer to canonicalize the rest of the | 
 |     // path. Give it a fake output component to write into. DoCanonicalizeFile | 
 |     // will compute the full path component. | 
 |     Component sub_path = MakeRange(after_drive, path.end()); | 
 |     Component fake_output_path; | 
 |     success = CanonicalizePath(spec, sub_path, output, &fake_output_path); | 
 |   } else { | 
 |     // No input path, canonicalize to a slash. | 
 |     output->push_back('/'); | 
 |   } | 
 |  | 
 |   out_path->len = output->length() - out_path->begin; | 
 |   return success; | 
 | } | 
 |  | 
 | template<typename CHAR, typename UCHAR> | 
 | bool DoCanonicalizeFileURL(const URLComponentSource<CHAR>& source, | 
 |                            const Parsed& parsed, | 
 |                            CharsetConverter* query_converter, | 
 |                            CanonOutput* output, | 
 |                            Parsed* new_parsed) { | 
 |   // Things we don't set in file: URLs. | 
 |   new_parsed->username = Component(); | 
 |   new_parsed->password = Component(); | 
 |   new_parsed->port = Component(); | 
 |  | 
 |   // Scheme (known, so we don't bother running it through the more | 
 |   // complicated scheme canonicalizer). | 
 |   new_parsed->scheme.begin = output->length(); | 
 |   output->Append("file://", 7); | 
 |   new_parsed->scheme.len = 4; | 
 |  | 
 |   // Append the host. For many file URLs, this will be empty. For UNC, this | 
 |   // will be present. | 
 |   // TODO(brettw) This doesn't do any checking for host name validity. We | 
 |   // should probably handle validity checking of UNC hosts differently than | 
 |   // for regular IP hosts. | 
 |   bool success = CanonicalizeHost(source.host, parsed.host, | 
 |                                   output, &new_parsed->host); | 
 |   success &= DoFileCanonicalizePath<CHAR, UCHAR>(source.path, parsed.path, | 
 |                                     output, &new_parsed->path); | 
 |   CanonicalizeQuery(source.query, parsed.query, query_converter, | 
 |                     output, &new_parsed->query); | 
 |  | 
 |   // Ignore failure for refs since the URL can probably still be loaded. | 
 |   CanonicalizeRef(source.ref, parsed.ref, output, &new_parsed->ref); | 
 |  | 
 |   return success; | 
 | } | 
 |  | 
 | } // namespace | 
 |  | 
 | bool CanonicalizeFileURL(const char* spec, | 
 |                          int spec_len, | 
 |                          const Parsed& parsed, | 
 |                          CharsetConverter* query_converter, | 
 |                          CanonOutput* output, | 
 |                          Parsed* new_parsed) { | 
 |   return DoCanonicalizeFileURL<char, unsigned char>( | 
 |       URLComponentSource<char>(spec), parsed, query_converter, | 
 |       output, new_parsed); | 
 | } | 
 |  | 
 | bool CanonicalizeFileURL(const base::char16* spec, | 
 |                          int spec_len, | 
 |                          const Parsed& parsed, | 
 |                          CharsetConverter* query_converter, | 
 |                          CanonOutput* output, | 
 |                          Parsed* new_parsed) { | 
 |   return DoCanonicalizeFileURL<base::char16, base::char16>( | 
 |       URLComponentSource<base::char16>(spec), parsed, query_converter, | 
 |       output, new_parsed); | 
 | } | 
 |  | 
 | bool FileCanonicalizePath(const char* spec, | 
 |                           const Component& path, | 
 |                           CanonOutput* output, | 
 |                           Component* out_path) { | 
 |   return DoFileCanonicalizePath<char, unsigned char>(spec, path, | 
 |                                                      output, out_path); | 
 | } | 
 |  | 
 | bool FileCanonicalizePath(const base::char16* spec, | 
 |                           const Component& path, | 
 |                           CanonOutput* output, | 
 |                           Component* out_path) { | 
 |   return DoFileCanonicalizePath<base::char16, base::char16>(spec, path, | 
 |                                                             output, out_path); | 
 | } | 
 |  | 
 | bool ReplaceFileURL(const char* base, | 
 |                     const Parsed& base_parsed, | 
 |                     const Replacements<char>& replacements, | 
 |                     CharsetConverter* query_converter, | 
 |                     CanonOutput* output, | 
 |                     Parsed* new_parsed) { | 
 |   URLComponentSource<char> source(base); | 
 |   Parsed parsed(base_parsed); | 
 |   SetupOverrideComponents(base, replacements, &source, &parsed); | 
 |   return DoCanonicalizeFileURL<char, unsigned char>( | 
 |       source, parsed, query_converter, output, new_parsed); | 
 | } | 
 |  | 
 | bool ReplaceFileURL(const char* base, | 
 |                     const Parsed& base_parsed, | 
 |                     const Replacements<base::char16>& replacements, | 
 |                     CharsetConverter* query_converter, | 
 |                     CanonOutput* output, | 
 |                     Parsed* new_parsed) { | 
 |   RawCanonOutput<1024> utf8; | 
 |   URLComponentSource<char> source(base); | 
 |   Parsed parsed(base_parsed); | 
 |   SetupUTF16OverrideComponents(base, replacements, &utf8, &source, &parsed); | 
 |   return DoCanonicalizeFileURL<char, unsigned char>( | 
 |       source, parsed, query_converter, output, new_parsed); | 
 | } | 
 |  | 
 | }  // namespace url |