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 "base/logging.h" 6c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "url/url_file.h" 7c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "url/url_parse.h" 8c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "url/url_parse_internal.h" 9c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 10c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Interesting IE file:isms... 11c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// 12c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// INPUT OUTPUT 13c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// ========================= ============================== 14c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// file:/foo/bar file:///foo/bar 15c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// The result here seems totally invalid!?!? This isn't UNC. 16c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// 17c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// file:/ 18c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// file:// or any other number of slashes 19c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// IE6 doesn't do anything at all if you click on this link. No error: 20c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// nothing. IE6's history system seems to always color this link, so I'm 21c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// guessing that it maps internally to the empty URL. 22c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// 23c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// C:\ file:///C:/ 24c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// When on a file: URL source page, this link will work. When over HTTP, 25c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// the file: URL will appear in the status bar but the link will not work 26c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// (security restriction for all file URLs). 27c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// 28c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// file:foo/ file:foo/ (invalid?!?!?) 29c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// file:/foo/ file:///foo/ (invalid?!?!?) 30c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// file://foo/ file://foo/ (UNC to server "foo") 31c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// file:///foo/ file:///foo/ (invalid, seems to be a file) 32c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// file:////foo/ file://foo/ (UNC to server "foo") 33c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Any more than four slashes is also treated as UNC. 34c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// 35c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// file:C:/ file://C:/ 36c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// file:/C:/ file://C:/ 37c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// The number of slashes after "file:" don't matter if the thing following 38c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// it looks like an absolute drive path. Also, slashes and backslashes are 39c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// equally valid here. 40c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 410529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochnamespace url { 42c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 43c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)namespace { 44c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 45c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// A subcomponent of DoInitFileURL, the input of this function should be a UNC 46c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// path name, with the index of the first character after the slashes following 47c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// the scheme given in |after_slashes|. This will initialize the host, path, 48c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// query, and ref, and leave the other output components untouched 49c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// (DoInitFileURL handles these for us). 50c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)template<typename CHAR> 51c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void DoParseUNC(const CHAR* spec, 52c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) int after_slashes, 53c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) int spec_len, 54c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) Parsed* parsed) { 55c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) int next_slash = FindNextSlash(spec, after_slashes, spec_len); 56c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (next_slash == spec_len) { 57c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // No additional slash found, as in "file://foo", treat the text as the 58c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // host with no path (this will end up being UNC to server "foo"). 59c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) int host_len = spec_len - after_slashes; 60c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (host_len) 61c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) parsed->host = Component(after_slashes, host_len); 62c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) else 63c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) parsed->host.reset(); 64c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) parsed->path.reset(); 65c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return; 66c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 67c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 68c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#ifdef WIN32 69c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // See if we have something that looks like a path following the first 70c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // component. As in "file://localhost/c:/", we get "c:/" out. We want to 71c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // treat this as a having no host but the path given. Works on Windows only. 72c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (DoesBeginWindowsDriveSpec(spec, next_slash + 1, spec_len)) { 73c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) parsed->host.reset(); 74c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ParsePathInternal(spec, MakeRange(next_slash, spec_len), 75c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) &parsed->path, &parsed->query, &parsed->ref); 76c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return; 77c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 78c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#endif 79c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 80c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Otherwise, everything up until that first slash we found is the host name, 81c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // which will end up being the UNC host. For example "file://foo/bar.txt" 82c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // will get a server name of "foo" and a path of "/bar". Later, on Windows, 83c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // this should be treated as the filename "\\foo\bar.txt" in proper UNC 84c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // notation. 85c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) int host_len = next_slash - after_slashes; 86c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (host_len) 87c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) parsed->host = MakeRange(after_slashes, next_slash); 88c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) else 89c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) parsed->host.reset(); 90c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (next_slash < spec_len) { 91c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ParsePathInternal(spec, MakeRange(next_slash, spec_len), 92c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) &parsed->path, &parsed->query, &parsed->ref); 93c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } else { 94c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) parsed->path.reset(); 95c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 96c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 97c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 98c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// A subcomponent of DoParseFileURL, the input should be a local file, with the 99c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// beginning of the path indicated by the index in |path_begin|. This will 100c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// initialize the host, path, query, and ref, and leave the other output 101c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// components untouched (DoInitFileURL handles these for us). 102c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)template<typename CHAR> 103c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void DoParseLocalFile(const CHAR* spec, 104c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) int path_begin, 105c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) int spec_len, 106c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) Parsed* parsed) { 107c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) parsed->host.reset(); 108c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ParsePathInternal(spec, MakeRange(path_begin, spec_len), 109c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) &parsed->path, &parsed->query, &parsed->ref); 110c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 111c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 112c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Backend for the external functions that operates on either char type. 113d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)// Handles cases where there is a scheme, but also when handed the first 114d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)// character following the "file:" at the beginning of the spec. If so, 115d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)// this is usually a slash, but needn't be; we allow paths like "file:c:\foo". 116c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)template<typename CHAR> 117c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void DoParseFileURL(const CHAR* spec, int spec_len, Parsed* parsed) { 118c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) DCHECK(spec_len >= 0); 119c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 120c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Get the parts we never use for file URLs out of the way. 121c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) parsed->username.reset(); 122c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) parsed->password.reset(); 123c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) parsed->port.reset(); 124c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 125c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Many of the code paths don't set these, so it's convenient to just clear 126c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // them. We'll write them in those cases we need them. 127c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) parsed->query.reset(); 128c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) parsed->ref.reset(); 129c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 130c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Strip leading & trailing spaces and control characters. 131c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) int begin = 0; 132c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) TrimURL(spec, &begin, &spec_len); 133c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 134d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // Find the scheme, if any. 135d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) int num_slashes = CountConsecutiveSlashes(spec, begin, spec_len); 136c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) int after_scheme; 137c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) int after_slashes; 138c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#ifdef WIN32 139c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // See how many slashes there are. We want to handle cases like UNC but also 140c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // "/c:/foo". This is when there is no scheme, so we can allow pages to do 141c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // links like "c:/foo/bar" or "//foo/bar". This is also called by the 142c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // relative URL resolver when it determines there is an absolute URL, which 143c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // may give us input like "/c:/foo". 144c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) after_slashes = begin + num_slashes; 145c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (DoesBeginWindowsDriveSpec(spec, after_slashes, spec_len)) { 146c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Windows path, don't try to extract the scheme (for example, "c:\foo"). 147c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) parsed->scheme.reset(); 148c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) after_scheme = after_slashes; 149c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } else if (DoesBeginUNCPath(spec, begin, spec_len, false)) { 150c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Windows UNC path: don't try to extract the scheme, but keep the slashes. 151c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) parsed->scheme.reset(); 152c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) after_scheme = begin; 153c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } else 154c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#endif 155c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) { 156d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // ExtractScheme doesn't understand the possibility of filenames with 157d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // colons in them, in which case it returns the entire spec up to the 158d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // colon as the scheme. So handle /foo.c:5 as a file but foo.c:5 as 159d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // the foo.c: scheme. 160d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) if (!num_slashes && 161d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) ExtractScheme(&spec[begin], spec_len - begin, &parsed->scheme)) { 162c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Offset the results since we gave ExtractScheme a substring. 163c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) parsed->scheme.begin += begin; 164c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) after_scheme = parsed->scheme.end() + 1; 165c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } else { 166c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // No scheme found, remember that. 167c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) parsed->scheme.reset(); 168c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) after_scheme = begin; 169c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 170c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 171c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 172c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Handle empty specs ones that contain only whitespace or control chars, 173c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // or that are just the scheme (for example "file:"). 174c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (after_scheme == spec_len) { 175c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) parsed->host.reset(); 176c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) parsed->path.reset(); 177c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return; 178c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 179c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 180c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) num_slashes = CountConsecutiveSlashes(spec, after_scheme, spec_len); 181c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) after_slashes = after_scheme + num_slashes; 182c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#ifdef WIN32 183c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Check whether the input is a drive again. We checked above for windows 184c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // drive specs, but that's only at the very beginning to see if we have a 185c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // scheme at all. This test will be duplicated in that case, but will 186c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // additionally handle all cases with a real scheme such as "file:///C:/". 187c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (!DoesBeginWindowsDriveSpec(spec, after_slashes, spec_len) && 188c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) num_slashes != 3) { 189c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Anything not beginning with a drive spec ("c:\") on Windows is treated 190c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // as UNC, with the exception of three slashes which always means a file. 191c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Even IE7 treats file:///foo/bar as "/foo/bar", which then fails. 192c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) DoParseUNC(spec, after_slashes, spec_len, parsed); 193c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return; 194c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 195c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#else 196c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // file: URL with exactly 2 slashes is considered to have a host component. 197c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (num_slashes == 2) { 198c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) DoParseUNC(spec, after_slashes, spec_len, parsed); 199c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return; 200c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 201c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#endif // WIN32 202c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 203c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Easy and common case, the full path immediately follows the scheme 204c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // (modulo slashes), as in "file://c:/foo". Just treat everything from 205c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // there to the end as the path. Empty hosts have 0 length instead of -1. 206c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // We include the last slash as part of the path if there is one. 207c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) DoParseLocalFile(spec, 208c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) num_slashes > 0 ? after_scheme + num_slashes - 1 : after_scheme, 209c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) spec_len, parsed); 210c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 211c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 212c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} // namespace 213c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 214c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void ParseFileURL(const char* url, int url_len, Parsed* parsed) { 215c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) DoParseFileURL(url, url_len, parsed); 216c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 217c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 2187d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)void ParseFileURL(const base::char16* url, int url_len, Parsed* parsed) { 219c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) DoParseFileURL(url, url_len, parsed); 220c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 221c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 2220529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch} // namespace url 223