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