|  | // Copyright (c) 2012 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. | 
|  |  | 
|  | #include "net/base/net_util.h" | 
|  |  | 
|  | #include <algorithm> | 
|  | #include <iterator> | 
|  | #include <map> | 
|  |  | 
|  | #include "build/build_config.h" | 
|  |  | 
|  | #if defined(OS_WIN) | 
|  | #include <windows.h> | 
|  | #include <winsock2.h> | 
|  | #include <iphlpapi.h> | 
|  | #pragma comment(lib, "iphlpapi.lib") | 
|  | #elif defined(OS_POSIX) | 
|  | #include <fcntl.h> | 
|  | #if !defined(OS_ANDROID) | 
|  | #include <ifaddrs.h> | 
|  | #endif | 
|  | #include <netdb.h> | 
|  | #include <net/if.h> | 
|  | #include <netinet/in.h> | 
|  | #endif | 
|  |  | 
|  | #include "base/basictypes.h" | 
|  | #include "base/file_path.h" | 
|  | #include "base/file_util.h" | 
|  | #include "base/i18n/file_util_icu.h" | 
|  | #include "base/i18n/icu_string_conversions.h" | 
|  | #include "base/i18n/time_formatting.h" | 
|  | #include "base/json/string_escape.h" | 
|  | #include "base/lazy_instance.h" | 
|  | #include "base/logging.h" | 
|  | #include "base/memory/singleton.h" | 
|  | #include "base/message_loop.h" | 
|  | #include "base/metrics/histogram.h" | 
|  | #include "base/path_service.h" | 
|  | #include "base/stl_util.h" | 
|  | #include "base/string_number_conversions.h" | 
|  | #include "base/string_piece.h" | 
|  | #include "base/string_split.h" | 
|  | #include "base/string_tokenizer.h" | 
|  | #include "base/string_util.h" | 
|  | #include "base/stringprintf.h" | 
|  | #include "base/synchronization/lock.h" | 
|  | #include "base/sys_string_conversions.h" | 
|  | #include "base/sys_byteorder.h" | 
|  | #include "base/time.h" | 
|  | #include "base/utf_offset_string_conversions.h" | 
|  | #include "base/utf_string_conversions.h" | 
|  | #include "base/values.h" | 
|  | #include "googleurl/src/gurl.h" | 
|  | #include "googleurl/src/url_canon.h" | 
|  | #include "googleurl/src/url_canon_ip.h" | 
|  | #include "googleurl/src/url_parse.h" | 
|  | #if defined(OS_ANDROID) | 
|  | #include "net/android/network_library.h" | 
|  | #endif | 
|  | #include "net/base/dns_util.h" | 
|  | #include "net/base/escape.h" | 
|  | #include "net/base/mime_util.h" | 
|  | #include "net/base/net_module.h" | 
|  |  | 
|  | #if defined(OS_WIN) | 
|  | #include "net/base/winsock_init.h" | 
|  | #endif | 
|  | #if !defined(__LB_SHELL__) && !defined(COBALT) | 
|  | #include "grit/net_resources.h" | 
|  | #include "net/http/http_content_disposition.h" | 
|  | #endif  // !defined(__LB_SHELL__) && !defined(COBALT) | 
|  | #include "unicode/datefmt.h" | 
|  | #include "unicode/regex.h" | 
|  | #include "unicode/uidna.h" | 
|  | #include "unicode/ulocdata.h" | 
|  | #include "unicode/uniset.h" | 
|  | #include "unicode/uscript.h" | 
|  | #include "unicode/uset.h" | 
|  |  | 
|  | #if defined(OS_STARBOARD) | 
|  | #include "starboard/socket.h" | 
|  | #include "starboard/system.h" | 
|  | #endif  // defined(OS_STARBOARD) | 
|  |  | 
|  | using base::Time; | 
|  |  | 
|  | namespace net { | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | // what we prepend to get a file URL | 
|  | static const FilePath::CharType kFileURLPrefix[] = | 
|  | FILE_PATH_LITERAL("file:///"); | 
|  |  | 
|  | // The general list of blocked ports. Will be blocked unless a specific | 
|  | // protocol overrides it. (Ex: ftp can use ports 20 and 21) | 
|  | static const int kRestrictedPorts[] = { | 
|  | 1,    // tcpmux | 
|  | 7,    // echo | 
|  | 9,    // discard | 
|  | 11,   // systat | 
|  | 13,   // daytime | 
|  | 15,   // netstat | 
|  | 17,   // qotd | 
|  | 19,   // chargen | 
|  | 20,   // ftp data | 
|  | 21,   // ftp access | 
|  | 22,   // ssh | 
|  | 23,   // telnet | 
|  | 25,   // smtp | 
|  | 37,   // time | 
|  | 42,   // name | 
|  | 43,   // nicname | 
|  | 53,   // domain | 
|  | 77,   // priv-rjs | 
|  | 79,   // finger | 
|  | 87,   // ttylink | 
|  | 95,   // supdup | 
|  | 101,  // hostriame | 
|  | 102,  // iso-tsap | 
|  | 103,  // gppitnp | 
|  | 104,  // acr-nema | 
|  | 109,  // pop2 | 
|  | 110,  // pop3 | 
|  | 111,  // sunrpc | 
|  | 113,  // auth | 
|  | 115,  // sftp | 
|  | 117,  // uucp-path | 
|  | 119,  // nntp | 
|  | 123,  // NTP | 
|  | 135,  // loc-srv /epmap | 
|  | 139,  // netbios | 
|  | 143,  // imap2 | 
|  | 179,  // BGP | 
|  | 389,  // ldap | 
|  | 465,  // smtp+ssl | 
|  | 512,  // print / exec | 
|  | 513,  // login | 
|  | 514,  // shell | 
|  | 515,  // printer | 
|  | 526,  // tempo | 
|  | 530,  // courier | 
|  | 531,  // chat | 
|  | 532,  // netnews | 
|  | 540,  // uucp | 
|  | 556,  // remotefs | 
|  | 563,  // nntp+ssl | 
|  | 587,  // stmp? | 
|  | 601,  // ?? | 
|  | 636,  // ldap+ssl | 
|  | 993,  // ldap+ssl | 
|  | 995,  // pop3+ssl | 
|  | 2049, // nfs | 
|  | 3659, // apple-sasl / PasswordServer | 
|  | 4045, // lockd | 
|  | 6000, // X11 | 
|  | 6665, // Alternate IRC [Apple addition] | 
|  | 6666, // Alternate IRC [Apple addition] | 
|  | 6667, // Standard IRC [Apple addition] | 
|  | 6668, // Alternate IRC [Apple addition] | 
|  | 6669, // Alternate IRC [Apple addition] | 
|  | 0xFFFF, // Used to block all invalid port numbers (see | 
|  | // third_party/WebKit/Source/WebCore/platform/KURLGoogle.cpp, port()) | 
|  | }; | 
|  |  | 
|  | // FTP overrides the following restricted ports. | 
|  | static const int kAllowedFtpPorts[] = { | 
|  | 21,   // ftp data | 
|  | 22,   // ssh | 
|  | }; | 
|  |  | 
|  | #if defined(OS_WIN) | 
|  | std::string::size_type CountTrailingChars( | 
|  | const std::string& input, | 
|  | const std::string::value_type trailing_chars[]) { | 
|  | const size_t last_good_char = input.find_last_not_of(trailing_chars); | 
|  | return (last_good_char == std::string::npos) ? | 
|  | input.length() : (input.length() - last_good_char - 1); | 
|  | } | 
|  | #endif | 
|  |  | 
|  | // Does some simple normalization of scripts so we can allow certain scripts | 
|  | // to exist together. | 
|  | // TODO(brettw) bug 880223: we should allow some other languages to be | 
|  | // oombined such as Chinese and Latin. We will probably need a more | 
|  | // complicated system of language pairs to have more fine-grained control. | 
|  | UScriptCode NormalizeScript(UScriptCode code) { | 
|  | switch (code) { | 
|  | case USCRIPT_KATAKANA: | 
|  | case USCRIPT_HIRAGANA: | 
|  | case USCRIPT_KATAKANA_OR_HIRAGANA: | 
|  | case USCRIPT_HANGUL:  // This one is arguable. | 
|  | return USCRIPT_HAN; | 
|  | default: | 
|  | return code; | 
|  | } | 
|  | } | 
|  |  | 
|  | bool IsIDNComponentInSingleScript(const char16* str, int str_len) { | 
|  | UScriptCode first_script = USCRIPT_INVALID_CODE; | 
|  | bool is_first = true; | 
|  |  | 
|  | int i = 0; | 
|  | while (i < str_len) { | 
|  | unsigned code_point; | 
|  | U16_NEXT(str, i, str_len, code_point); | 
|  |  | 
|  | UErrorCode err = U_ZERO_ERROR; | 
|  | UScriptCode cur_script = uscript_getScript(code_point, &err); | 
|  | if (err != U_ZERO_ERROR) | 
|  | return false;  // Report mixed on error. | 
|  | cur_script = NormalizeScript(cur_script); | 
|  |  | 
|  | // TODO(brettw) We may have to check for USCRIPT_INHERENT as well. | 
|  | if (is_first && cur_script != USCRIPT_COMMON) { | 
|  | first_script = cur_script; | 
|  | is_first = false; | 
|  | } else { | 
|  | if (cur_script != USCRIPT_COMMON && cur_script != first_script) | 
|  | return false; | 
|  | } | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // Check if the script of a language can be 'safely' mixed with | 
|  | // Latin letters in the ASCII range. | 
|  | bool IsCompatibleWithASCIILetters(const std::string& lang) { | 
|  | // For now, just list Chinese, Japanese and Korean (positive list). | 
|  | // An alternative is negative-listing (languages using Greek and | 
|  | // Cyrillic letters), but it can be more dangerous. | 
|  | return !lang.substr(0, 2).compare("zh") || | 
|  | !lang.substr(0, 2).compare("ja") || | 
|  | !lang.substr(0, 2).compare("ko"); | 
|  | } | 
|  |  | 
|  | typedef std::map<std::string, icu::UnicodeSet*> LangToExemplarSetMap; | 
|  |  | 
|  | class LangToExemplarSet { | 
|  | public: | 
|  | static LangToExemplarSet* GetInstance() { | 
|  | return Singleton<LangToExemplarSet>::get(); | 
|  | } | 
|  |  | 
|  | private: | 
|  | LangToExemplarSetMap map; | 
|  | LangToExemplarSet() { } | 
|  | ~LangToExemplarSet() { | 
|  | STLDeleteContainerPairSecondPointers(map.begin(), map.end()); | 
|  | } | 
|  |  | 
|  | friend class Singleton<LangToExemplarSet>; | 
|  | friend struct DefaultSingletonTraits<LangToExemplarSet>; | 
|  | friend bool GetExemplarSetForLang(const std::string&, icu::UnicodeSet**); | 
|  | friend void SetExemplarSetForLang(const std::string&, icu::UnicodeSet*); | 
|  |  | 
|  | DISALLOW_COPY_AND_ASSIGN(LangToExemplarSet); | 
|  | }; | 
|  |  | 
|  | bool GetExemplarSetForLang(const std::string& lang, | 
|  | icu::UnicodeSet** lang_set) { | 
|  | const LangToExemplarSetMap& map = LangToExemplarSet::GetInstance()->map; | 
|  | LangToExemplarSetMap::const_iterator pos = map.find(lang); | 
|  | if (pos != map.end()) { | 
|  | *lang_set = pos->second; | 
|  | return true; | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | void SetExemplarSetForLang(const std::string& lang, | 
|  | icu::UnicodeSet* lang_set) { | 
|  | LangToExemplarSetMap& map = LangToExemplarSet::GetInstance()->map; | 
|  | map.insert(std::make_pair(lang, lang_set)); | 
|  | } | 
|  |  | 
|  | static base::LazyInstance<base::Lock>::Leaky | 
|  | g_lang_set_lock = LAZY_INSTANCE_INITIALIZER; | 
|  |  | 
|  | // Returns true if all the characters in component_characters are used by | 
|  | // the language |lang|. | 
|  | bool IsComponentCoveredByLang(const icu::UnicodeSet& component_characters, | 
|  | const std::string& lang) { | 
|  | CR_DEFINE_STATIC_LOCAL( | 
|  | const icu::UnicodeSet, kASCIILetters, ('a', 'z')); | 
|  | icu::UnicodeSet* lang_set; | 
|  | // We're called from both the UI thread and the history thread. | 
|  | { | 
|  | base::AutoLock lock(g_lang_set_lock.Get()); | 
|  | if (!GetExemplarSetForLang(lang, &lang_set)) { | 
|  | UErrorCode status = U_ZERO_ERROR; | 
|  | ULocaleData* uld = ulocdata_open(lang.c_str(), &status); | 
|  | // TODO(jungshik) Turn this check on when the ICU data file is | 
|  | // rebuilt with the minimal subset of locale data for languages | 
|  | // to which Chrome is not localized but which we offer in the list | 
|  | // of languages selectable for Accept-Languages. With the rebuilt ICU | 
|  | // data, ulocdata_open never should fall back to the default locale. | 
|  | // (issue 2078) | 
|  | // DCHECK(U_SUCCESS(status) && status != U_USING_DEFAULT_WARNING); | 
|  | if (U_SUCCESS(status) && status != U_USING_DEFAULT_WARNING) { | 
|  | lang_set = reinterpret_cast<icu::UnicodeSet *>( | 
|  | ulocdata_getExemplarSet(uld, NULL, 0, | 
|  | ULOCDATA_ES_STANDARD, &status)); | 
|  | // If |lang| is compatible with ASCII Latin letters, add them. | 
|  | if (IsCompatibleWithASCIILetters(lang)) | 
|  | lang_set->addAll(kASCIILetters); | 
|  | } else { | 
|  | lang_set = new icu::UnicodeSet(1, 0); | 
|  | } | 
|  | lang_set->freeze(); | 
|  | SetExemplarSetForLang(lang, lang_set); | 
|  | ulocdata_close(uld); | 
|  | } | 
|  | } | 
|  | return !lang_set->isEmpty() && lang_set->containsAll(component_characters); | 
|  | } | 
|  |  | 
|  | // Returns true if the given Unicode host component is safe to display to the | 
|  | // user. | 
|  | bool IsIDNComponentSafe(const char16* str, | 
|  | int str_len, | 
|  | const std::string& languages) { | 
|  | // Most common cases (non-IDN) do not reach here so that we don't | 
|  | // need a fast return path. | 
|  | // TODO(jungshik) : Check if there's any character inappropriate | 
|  | // (although allowed) for domain names. | 
|  | // See http://www.unicode.org/reports/tr39/#IDN_Security_Profiles and | 
|  | // http://www.unicode.org/reports/tr39/data/xidmodifications.txt | 
|  | // For now, we borrow the list from Mozilla and tweaked it slightly. | 
|  | // (e.g. Characters like U+00A0, U+3000, U+3002 are omitted because | 
|  | //  they're gonna be canonicalized to U+0020 and full stop before | 
|  | //  reaching here.) | 
|  | // The original list is available at | 
|  | // http://kb.mozillazine.org/Network.IDN.blacklist_chars and | 
|  | // at http://mxr.mozilla.org/seamonkey/source/modules/libpref/src/init/all.js#703 | 
|  |  | 
|  | // ICU's regular expression functionality is needed for this code to function. | 
|  | #if defined(UCONFIG_NO_REGULAR_EXPRESSIONS) | 
|  | return false; | 
|  | #else | 
|  |  | 
|  | UErrorCode status = U_ZERO_ERROR; | 
|  | #ifdef U_WCHAR_IS_UTF16 | 
|  | icu::UnicodeSet dangerous_characters(icu::UnicodeString( | 
|  | L"[[\\ \u00bc\u00bd\u01c3\u0337\u0338" | 
|  | L"\u05c3\u05f4\u06d4\u0702\u115f\u1160][\u2000-\u200b]" | 
|  | L"[\u2024\u2027\u2028\u2029\u2039\u203a\u2044\u205f]" | 
|  | L"[\u2154-\u2156][\u2159-\u215b][\u215f\u2215\u23ae" | 
|  | L"\u29f6\u29f8\u2afb\u2afd][\u2ff0-\u2ffb][\u3014" | 
|  | L"\u3015\u3033\u3164\u321d\u321e\u33ae\u33af\u33c6\u33df\ufe14" | 
|  | L"\ufe15\ufe3f\ufe5d\ufe5e\ufeff\uff0e\uff06\uff61\uffa0\ufff9]" | 
|  | L"[\ufffa-\ufffd]]"), status); | 
|  | DCHECK(U_SUCCESS(status)); | 
|  | icu::RegexMatcher dangerous_patterns(icu::UnicodeString( | 
|  | // Lone katakana no, so, or n | 
|  | L"[^\\p{Katakana}][\u30ce\u30f3\u30bd][^\\p{Katakana}]" | 
|  | // Repeating Japanese accent characters | 
|  | L"|[\u3099\u309a\u309b\u309c][\u3099\u309a\u309b\u309c]"), | 
|  | 0, status); | 
|  | #else | 
|  | icu::UnicodeSet dangerous_characters(icu::UnicodeString( | 
|  | "[[\\u0020\\u00bc\\u00bd\\u01c3\\u0337\\u0338" | 
|  | "\\u05c3\\u05f4\\u06d4\\u0702\\u115f\\u1160][\\u2000-\\u200b]" | 
|  | "[\\u2024\\u2027\\u2028\\u2029\\u2039\\u203a\\u2044\\u205f]" | 
|  | "[\\u2154-\\u2156][\\u2159-\\u215b][\\u215f\\u2215\\u23ae" | 
|  | "\\u29f6\\u29f8\\u2afb\\u2afd][\\u2ff0-\\u2ffb][\\u3014" | 
|  | "\\u3015\\u3033\\u3164\\u321d\\u321e\\u33ae\\u33af\\u33c6\\u33df\\ufe14" | 
|  | "\\ufe15\\ufe3f\\ufe5d\\ufe5e\\ufeff\\uff0e\\uff06\\uff61\\uffa0\\ufff9]" | 
|  | "[\\ufffa-\\ufffd]]", -1, US_INV), status); | 
|  | DCHECK(U_SUCCESS(status)); | 
|  | icu::RegexMatcher dangerous_patterns(icu::UnicodeString( | 
|  | // Lone katakana no, so, or n | 
|  | "[^\\p{Katakana}][\\u30ce\\u30f3\\u30bd][^\\p{Katakana}]" | 
|  | // Repeating Japanese accent characters | 
|  | "|[\\u3099\\u309a\\u309b\\u309c][\\u3099\\u309a\\u309b\\u309c]"), | 
|  | 0, status); | 
|  | #endif | 
|  | DCHECK(U_SUCCESS(status)); | 
|  | icu::UnicodeSet component_characters; | 
|  | icu::UnicodeString component_string(str, str_len); | 
|  | component_characters.addAll(component_string); | 
|  | if (dangerous_characters.containsSome(component_characters)) | 
|  | return false; | 
|  |  | 
|  | DCHECK(U_SUCCESS(status)); | 
|  | dangerous_patterns.reset(component_string); | 
|  | if (dangerous_patterns.find()) | 
|  | return false; | 
|  |  | 
|  | // If the language list is empty, the result is completely determined | 
|  | // by whether a component is a single script or not. This will block | 
|  | // even "safe" script mixing cases like <Chinese, Latin-ASCII> that are | 
|  | // allowed with |languages| (while it blocks Chinese + Latin letters with | 
|  | // an accent as should be the case), but we want to err on the safe side | 
|  | // when |languages| is empty. | 
|  | if (languages.empty()) | 
|  | return IsIDNComponentInSingleScript(str, str_len); | 
|  |  | 
|  | // |common_characters| is made up of  ASCII numbers, hyphen, plus and | 
|  | // underscore that are used across scripts and allowed in domain names. | 
|  | // (sync'd with characters allowed in url_canon_host with square | 
|  | // brackets excluded.) See kHostCharLookup[] array in url_canon_host.cc. | 
|  | icu::UnicodeSet common_characters(UNICODE_STRING_SIMPLE("[[0-9]\\-_+\\ ]"), | 
|  | status); | 
|  | DCHECK(U_SUCCESS(status)); | 
|  | // Subtract common characters because they're always allowed so that | 
|  | // we just have to check if a language-specific set contains | 
|  | // the remainder. | 
|  | component_characters.removeAll(common_characters); | 
|  |  | 
|  | StringTokenizer t(languages, ","); | 
|  | while (t.GetNext()) { | 
|  | if (IsComponentCoveredByLang(component_characters, t.token())) | 
|  | return true; | 
|  | } | 
|  | return false; | 
|  | #endif  // defined(UCONFIG_NO_REGULAR_EXPRESSIONS) | 
|  | } | 
|  |  | 
|  | // Converts one component of a host (between dots) to IDN if safe. The result | 
|  | // will be APPENDED to the given output string and will be the same as the input | 
|  | // if it is not IDN or the IDN is unsafe to display.  Returns whether any | 
|  | // conversion was performed. | 
|  | bool IDNToUnicodeOneComponent(const char16* comp, | 
|  | size_t comp_len, | 
|  | const std::string& languages, | 
|  | string16* out) { | 
|  | DCHECK(out); | 
|  | if (comp_len == 0) | 
|  | return false; | 
|  |  | 
|  | // Only transform if the input can be an IDN component. | 
|  | static const char16 kIdnPrefix[] = {'x', 'n', '-', '-'}; | 
|  | if ((comp_len > arraysize(kIdnPrefix)) && | 
|  | !memcmp(comp, kIdnPrefix, arraysize(kIdnPrefix) * sizeof(char16))) { | 
|  | // Repeatedly expand the output string until it's big enough.  It looks like | 
|  | // ICU will return the required size of the buffer, but that's not | 
|  | // documented, so we'll just grow by 2x. This should be rare and is not on a | 
|  | // critical path. | 
|  | size_t original_length = out->length(); | 
|  | for (int extra_space = 64; ; extra_space *= 2) { | 
|  | UErrorCode status = U_ZERO_ERROR; | 
|  | out->resize(out->length() + extra_space); | 
|  | int output_chars = uidna_IDNToUnicode(comp, | 
|  | static_cast<int32_t>(comp_len), &(*out)[original_length], extra_space, | 
|  | UIDNA_DEFAULT, NULL, &status); | 
|  | if (status == U_ZERO_ERROR) { | 
|  | // Converted successfully. | 
|  | out->resize(original_length + output_chars); | 
|  | if (IsIDNComponentSafe(out->data() + original_length, output_chars, | 
|  | languages)) | 
|  | return true; | 
|  | } | 
|  |  | 
|  | if (status != U_BUFFER_OVERFLOW_ERROR) | 
|  | break; | 
|  | } | 
|  | // Failed, revert back to original string. | 
|  | out->resize(original_length); | 
|  | } | 
|  |  | 
|  | // We get here with no IDN or on error, in which case we just append the | 
|  | // literal input. | 
|  | out->append(comp, comp_len); | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // Clamps the offsets in |offsets_for_adjustment| to the length of |str|. | 
|  | void LimitOffsets(const string16& str, | 
|  | std::vector<size_t>* offsets_for_adjustment) { | 
|  | if (offsets_for_adjustment) { | 
|  | std::for_each(offsets_for_adjustment->begin(), | 
|  | offsets_for_adjustment->end(), | 
|  | LimitOffset<string16>(str.length())); | 
|  | } | 
|  | } | 
|  |  | 
|  | // TODO(brettw) bug 734373: check the scripts for each host component and | 
|  | // don't un-IDN-ize if there is more than one. Alternatively, only IDN for | 
|  | // scripts that the user has installed. For now, just put the entire | 
|  | // path through IDN. Maybe this feature can be implemented in ICU itself? | 
|  | // | 
|  | // We may want to skip this step in the case of file URLs to allow unicode | 
|  | // UNC hostnames regardless of encodings. | 
|  | string16 IDNToUnicodeWithOffsets(const std::string& host, | 
|  | const std::string& languages, | 
|  | std::vector<size_t>* offsets_for_adjustment) { | 
|  | // Convert the ASCII input to a string16 for ICU. | 
|  | string16 input16; | 
|  | input16.reserve(host.length()); | 
|  | input16.insert(input16.end(), host.begin(), host.end()); | 
|  |  | 
|  | // Do each component of the host separately, since we enforce script matching | 
|  | // on a per-component basis. | 
|  | string16 out16; | 
|  | { | 
|  | OffsetAdjuster offset_adjuster(offsets_for_adjustment); | 
|  | for (size_t component_start = 0, component_end; | 
|  | component_start < input16.length(); | 
|  | component_start = component_end + 1) { | 
|  | // Find the end of the component. | 
|  | component_end = input16.find('.', component_start); | 
|  | if (component_end == string16::npos) | 
|  | component_end = input16.length();  // For getting the last component. | 
|  | size_t component_length = component_end - component_start; | 
|  | size_t new_component_start = out16.length(); | 
|  | bool converted_idn = false; | 
|  | if (component_end > component_start) { | 
|  | // Add the substring that we just found. | 
|  | converted_idn = IDNToUnicodeOneComponent( | 
|  | input16.data() + component_start, component_length, languages, | 
|  | &out16); | 
|  | } | 
|  | size_t new_component_length = out16.length() - new_component_start; | 
|  |  | 
|  | if (converted_idn && offsets_for_adjustment) { | 
|  | offset_adjuster.Add(OffsetAdjuster::Adjustment(component_start, | 
|  | component_length, new_component_length)); | 
|  | } | 
|  |  | 
|  | // Need to add the dot we just found (if we found one). | 
|  | if (component_end < input16.length()) | 
|  | out16.push_back('.'); | 
|  | } | 
|  | } | 
|  |  | 
|  | LimitOffsets(out16, offsets_for_adjustment); | 
|  | return out16; | 
|  | } | 
|  |  | 
|  | // Transforms |original_offsets| by subtracting |component_begin| from all | 
|  | // offsets.  Any offset which was not at least this large to begin with is set | 
|  | // to std::string::npos. | 
|  | std::vector<size_t> OffsetsIntoComponent( | 
|  | const std::vector<size_t>& original_offsets, | 
|  | size_t component_begin) { | 
|  | DCHECK_NE(std::string::npos, component_begin); | 
|  | std::vector<size_t> offsets_into_component(original_offsets); | 
|  | for (std::vector<size_t>::iterator i(offsets_into_component.begin()); | 
|  | i != offsets_into_component.end(); ++i) { | 
|  | if (*i != std::string::npos) | 
|  | *i = (*i < component_begin) ? std::string::npos : (*i - component_begin); | 
|  | } | 
|  | return offsets_into_component; | 
|  | } | 
|  |  | 
|  | // Called after we transform a component and append it to an output string. | 
|  | // Maps |transformed_offsets|, which represent offsets into the transformed | 
|  | // component itself, into appropriate offsets for the output string, by adding | 
|  | // |output_component_begin| to each.  Determines which offsets need mapping by | 
|  | // checking to see which of the |original_offsets| were within the designated | 
|  | // original component, using its provided endpoints. | 
|  | void AdjustForComponentTransform( | 
|  | const std::vector<size_t>& original_offsets, | 
|  | size_t original_component_begin, | 
|  | size_t original_component_end, | 
|  | const std::vector<size_t>& transformed_offsets, | 
|  | size_t output_component_begin, | 
|  | std::vector<size_t>* offsets_for_adjustment) { | 
|  | if (!offsets_for_adjustment) | 
|  | return; | 
|  |  | 
|  | DCHECK_NE(std::string::npos, original_component_begin); | 
|  | DCHECK_NE(std::string::npos, original_component_end); | 
|  | DCHECK_NE(string16::npos, output_component_begin); | 
|  | size_t offsets_size = offsets_for_adjustment->size(); | 
|  | DCHECK_EQ(offsets_size, original_offsets.size()); | 
|  | DCHECK_EQ(offsets_size, transformed_offsets.size()); | 
|  | for (size_t i = 0; i < offsets_size; ++i) { | 
|  | size_t original_offset = original_offsets[i]; | 
|  | if ((original_offset >= original_component_begin) && | 
|  | (original_offset < original_component_end)) { | 
|  | size_t transformed_offset = transformed_offsets[i]; | 
|  | (*offsets_for_adjustment)[i] = (transformed_offset == string16::npos) ? | 
|  | string16::npos : (output_component_begin + transformed_offset); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | // If |component| is valid, its begin is incremented by |delta|. | 
|  | void AdjustComponent(int delta, url_parse::Component* component) { | 
|  | if (!component->is_valid()) | 
|  | return; | 
|  |  | 
|  | DCHECK(delta >= 0 || component->begin >= -delta); | 
|  | component->begin += delta; | 
|  | } | 
|  |  | 
|  | // Adjusts all the components of |parsed| by |delta|, except for the scheme. | 
|  | void AdjustComponents(int delta, url_parse::Parsed* parsed) { | 
|  | AdjustComponent(delta, &(parsed->username)); | 
|  | AdjustComponent(delta, &(parsed->password)); | 
|  | AdjustComponent(delta, &(parsed->host)); | 
|  | AdjustComponent(delta, &(parsed->port)); | 
|  | AdjustComponent(delta, &(parsed->path)); | 
|  | AdjustComponent(delta, &(parsed->query)); | 
|  | AdjustComponent(delta, &(parsed->ref)); | 
|  | } | 
|  |  | 
|  | // Helper for FormatUrlWithOffsets(). | 
|  | string16 FormatViewSourceUrl(const GURL& url, | 
|  | const std::vector<size_t>& original_offsets, | 
|  | const std::string& languages, | 
|  | FormatUrlTypes format_types, | 
|  | UnescapeRule::Type unescape_rules, | 
|  | url_parse::Parsed* new_parsed, | 
|  | size_t* prefix_end, | 
|  | std::vector<size_t>* offsets_for_adjustment) { | 
|  | DCHECK(new_parsed); | 
|  | const char kViewSource[] = "view-source:"; | 
|  | const size_t kViewSourceLength = arraysize(kViewSource) - 1; | 
|  | std::vector<size_t> offsets_into_url( | 
|  | OffsetsIntoComponent(original_offsets, kViewSourceLength)); | 
|  |  | 
|  | GURL real_url(url.possibly_invalid_spec().substr(kViewSourceLength)); | 
|  | string16 result(ASCIIToUTF16(kViewSource) + | 
|  | FormatUrlWithOffsets(real_url, languages, format_types, unescape_rules, | 
|  | new_parsed, prefix_end, &offsets_into_url)); | 
|  |  | 
|  | // Adjust position values. | 
|  | if (new_parsed->scheme.is_nonempty()) { | 
|  | // Assume "view-source:real-scheme" as a scheme. | 
|  | new_parsed->scheme.len += kViewSourceLength; | 
|  | } else { | 
|  | new_parsed->scheme.begin = 0; | 
|  | new_parsed->scheme.len = kViewSourceLength - 1; | 
|  | } | 
|  | AdjustComponents(kViewSourceLength, new_parsed); | 
|  | if (prefix_end) | 
|  | *prefix_end += kViewSourceLength; | 
|  | AdjustForComponentTransform(original_offsets, kViewSourceLength, | 
|  | url.possibly_invalid_spec().length(), offsets_into_url, kViewSourceLength, | 
|  | offsets_for_adjustment); | 
|  | LimitOffsets(result, offsets_for_adjustment); | 
|  | return result; | 
|  | } | 
|  |  | 
|  | class AppendComponentTransform { | 
|  | public: | 
|  | AppendComponentTransform() {} | 
|  | virtual ~AppendComponentTransform() {} | 
|  |  | 
|  | virtual string16 Execute( | 
|  | const std::string& component_text, | 
|  | std::vector<size_t>* offsets_into_component) const = 0; | 
|  |  | 
|  | // NOTE: No DISALLOW_COPY_AND_ASSIGN here, since gcc < 4.3.0 requires an | 
|  | // accessible copy constructor in order to call AppendFormattedComponent() | 
|  | // with an inline temporary (see http://gcc.gnu.org/bugs/#cxx%5Frvalbind ). | 
|  | }; | 
|  |  | 
|  | class HostComponentTransform : public AppendComponentTransform { | 
|  | public: | 
|  | explicit HostComponentTransform(const std::string& languages) | 
|  | : languages_(languages) { | 
|  | } | 
|  |  | 
|  | private: | 
|  | virtual string16 Execute( | 
|  | const std::string& component_text, | 
|  | std::vector<size_t>* offsets_into_component) const OVERRIDE { | 
|  | return IDNToUnicodeWithOffsets(component_text, languages_, | 
|  | offsets_into_component); | 
|  | } | 
|  |  | 
|  | const std::string& languages_; | 
|  | }; | 
|  |  | 
|  | class NonHostComponentTransform : public AppendComponentTransform { | 
|  | public: | 
|  | explicit NonHostComponentTransform(UnescapeRule::Type unescape_rules) | 
|  | : unescape_rules_(unescape_rules) { | 
|  | } | 
|  |  | 
|  | private: | 
|  | virtual string16 Execute( | 
|  | const std::string& component_text, | 
|  | std::vector<size_t>* offsets_into_component) const OVERRIDE { | 
|  | return (unescape_rules_ == UnescapeRule::NONE) ? | 
|  | UTF8ToUTF16AndAdjustOffsets(component_text, offsets_into_component) : | 
|  | UnescapeAndDecodeUTF8URLComponentWithOffsets(component_text, | 
|  | unescape_rules_, offsets_into_component); | 
|  | } | 
|  |  | 
|  | const UnescapeRule::Type unescape_rules_; | 
|  | }; | 
|  |  | 
|  | void AppendFormattedComponent(const std::string& spec, | 
|  | const url_parse::Component& original_component, | 
|  | const std::vector<size_t>& original_offsets, | 
|  | const AppendComponentTransform& transform, | 
|  | string16* output, | 
|  | url_parse::Component* output_component, | 
|  | std::vector<size_t>* offsets_for_adjustment) { | 
|  | DCHECK(output); | 
|  | if (original_component.is_nonempty()) { | 
|  | size_t original_component_begin = | 
|  | static_cast<size_t>(original_component.begin); | 
|  | size_t output_component_begin = output->length(); | 
|  | if (output_component) | 
|  | output_component->begin = static_cast<int>(output_component_begin); | 
|  |  | 
|  | std::vector<size_t> offsets_into_component = | 
|  | OffsetsIntoComponent(original_offsets, original_component_begin); | 
|  | output->append(transform.Execute(std::string(spec, original_component_begin, | 
|  | static_cast<size_t>(original_component.len)), &offsets_into_component)); | 
|  |  | 
|  | if (output_component) { | 
|  | output_component->len = | 
|  | static_cast<int>(output->length() - output_component_begin); | 
|  | } | 
|  | AdjustForComponentTransform(original_offsets, original_component_begin, | 
|  | static_cast<size_t>(original_component.end()), | 
|  | offsets_into_component, output_component_begin, | 
|  | offsets_for_adjustment); | 
|  | } else if (output_component) { | 
|  | output_component->reset(); | 
|  | } | 
|  | } | 
|  |  | 
|  | void SanitizeGeneratedFileName(std::string& filename) { | 
|  | if (!filename.empty()) { | 
|  | // Remove "." from the beginning and end of the file name to avoid tricks | 
|  | // with hidden files, "..", and "." | 
|  | TrimString(filename, ".", &filename); | 
|  | #if defined(OS_WIN) | 
|  | // Handle CreateFile() stripping trailing dots and spaces on filenames | 
|  | // http://support.microsoft.com/kb/115827 | 
|  | std::string::size_type pos = filename.find_last_not_of(" ."); | 
|  | if (pos == std::string::npos) | 
|  | filename.resize(0); | 
|  | else | 
|  | filename.resize(++pos); | 
|  | #endif | 
|  | // Replace any path information by changing path separators with | 
|  | // underscores. | 
|  | ReplaceSubstringsAfterOffset(&filename, 0, "/", "_"); | 
|  | ReplaceSubstringsAfterOffset(&filename, 0, "\\", "_"); | 
|  | } | 
|  | } | 
|  |  | 
|  | // Returns the filename determined from the last component of the path portion | 
|  | // of the URL.  Returns an empty string if the URL doesn't have a path or is | 
|  | // invalid. If the generated filename is not reliable, | 
|  | // |should_overwrite_extension| will be set to true, in which case a better | 
|  | // extension should be determined based on the content type. | 
|  | std::string GetFileNameFromURL(const GURL& url, | 
|  | const std::string& referrer_charset, | 
|  | bool* should_overwrite_extension) { | 
|  | // about: and data: URLs don't have file names, but esp. data: URLs may | 
|  | // contain parts that look like ones (i.e., contain a slash).  Therefore we | 
|  | // don't attempt to divine a file name out of them. | 
|  | if (!url.is_valid() || url.SchemeIs("about") || url.SchemeIs("data")) | 
|  | return std::string(); | 
|  |  | 
|  | const std::string unescaped_url_filename = UnescapeURLComponent( | 
|  | url.ExtractFileName(), | 
|  | UnescapeRule::SPACES | UnescapeRule::URL_SPECIAL_CHARS); | 
|  |  | 
|  | // The URL's path should be escaped UTF-8, but may not be. | 
|  | std::string decoded_filename = unescaped_url_filename; | 
|  | if (!IsStringUTF8(decoded_filename)) { | 
|  | // TODO(jshin): this is probably not robust enough. To be sure, we need | 
|  | // encoding detection. | 
|  | string16 utf16_output; | 
|  | if (!referrer_charset.empty() && | 
|  | base::CodepageToUTF16(unescaped_url_filename, | 
|  | referrer_charset.c_str(), | 
|  | base::OnStringConversionError::FAIL, | 
|  | &utf16_output)) { | 
|  | decoded_filename = UTF16ToUTF8(utf16_output); | 
|  | } else { | 
|  | decoded_filename = WideToUTF8( | 
|  | base::SysNativeMBToWide(unescaped_url_filename)); | 
|  | } | 
|  | } | 
|  | // If the URL contains a (possibly empty) query, assume it is a generator, and | 
|  | // allow the determined extension to be overwritten. | 
|  | *should_overwrite_extension = !decoded_filename.empty() && url.has_query(); | 
|  |  | 
|  | return decoded_filename; | 
|  | } | 
|  |  | 
|  | #if defined(OS_WIN) | 
|  | // Returns whether the specified extension is automatically integrated into the | 
|  | // windows shell. | 
|  | bool IsShellIntegratedExtension(const string16& extension) { | 
|  | string16 extension_lower = StringToLowerASCII(extension); | 
|  |  | 
|  | static const wchar_t* const integrated_extensions[] = { | 
|  | // See <http://msdn.microsoft.com/en-us/library/ms811694.aspx>. | 
|  | L"local", | 
|  | // Right-clicking on shortcuts can be magical. | 
|  | L"lnk", | 
|  | }; | 
|  |  | 
|  | for (int i = 0; i < arraysize(integrated_extensions); ++i) { | 
|  | if (extension_lower == integrated_extensions[i]) | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // See <http://www.juniper.net/security/auto/vulnerabilities/vuln2612.html>. | 
|  | // That vulnerability report is not exactly on point, but files become magical | 
|  | // if their end in a CLSID.  Here we block extensions that look like CLSIDs. | 
|  | if (!extension_lower.empty() && extension_lower[0] == L'{' && | 
|  | extension_lower[extension_lower.length() - 1] == L'}') | 
|  | return true; | 
|  |  | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // Returns whether the specified file name is a reserved name on windows. | 
|  | // This includes names like "com2.zip" (which correspond to devices) and | 
|  | // desktop.ini and thumbs.db which have special meaning to the windows shell. | 
|  | bool IsReservedName(const string16& filename) { | 
|  | // This list is taken from the MSDN article "Naming a file" | 
|  | // http://msdn2.microsoft.com/en-us/library/aa365247(VS.85).aspx | 
|  | // I also added clock$ because GetSaveFileName seems to consider it as a | 
|  | // reserved name too. | 
|  | static const wchar_t* const known_devices[] = { | 
|  | L"con", L"prn", L"aux", L"nul", L"com1", L"com2", L"com3", L"com4", L"com5", | 
|  | L"com6", L"com7", L"com8", L"com9", L"lpt1", L"lpt2", L"lpt3", L"lpt4", | 
|  | L"lpt5", L"lpt6", L"lpt7", L"lpt8", L"lpt9", L"clock$" | 
|  | }; | 
|  | string16 filename_lower = StringToLowerASCII(filename); | 
|  |  | 
|  | for (int i = 0; i < arraysize(known_devices); ++i) { | 
|  | // Exact match. | 
|  | if (filename_lower == known_devices[i]) | 
|  | return true; | 
|  | // Starts with "DEVICE.". | 
|  | if (filename_lower.find(string16(known_devices[i]) + L".") == 0) | 
|  | return true; | 
|  | } | 
|  |  | 
|  | static const wchar_t* const magic_names[] = { | 
|  | // These file names are used by the "Customize folder" feature of the shell. | 
|  | L"desktop.ini", | 
|  | L"thumbs.db", | 
|  | }; | 
|  |  | 
|  | for (int i = 0; i < arraysize(magic_names); ++i) { | 
|  | if (filename_lower == magic_names[i]) | 
|  | return true; | 
|  | } | 
|  |  | 
|  | return false; | 
|  | } | 
|  | #endif  // OS_WIN | 
|  |  | 
|  | // Examines the current extension in |file_name| and modifies it if necessary in | 
|  | // order to ensure the filename is safe.  If |file_name| doesn't contain an | 
|  | // extension or if |ignore_extension| is true, then a new extension will be | 
|  | // constructed based on the |mime_type|. | 
|  | // | 
|  | // We're addressing two things here: | 
|  | // | 
|  | // 1) Usability.  If there is no reliable file extension, we want to guess a | 
|  | //    reasonable file extension based on the content type. | 
|  | // | 
|  | // 2) Shell integration.  Some file extensions automatically integrate with the | 
|  | //    shell.  We block these extensions to prevent a malicious web site from | 
|  | //    integrating with the user's shell. | 
|  | void EnsureSafeExtension(const std::string& mime_type, | 
|  | bool ignore_extension, | 
|  | FilePath* file_name) { | 
|  | // See if our file name already contains an extension. | 
|  | FilePath::StringType extension = file_name->Extension(); | 
|  | if (!extension.empty()) | 
|  | extension.erase(extension.begin());  // Erase preceding '.'. | 
|  |  | 
|  | if ((ignore_extension || extension.empty()) && !mime_type.empty()) { | 
|  | FilePath::StringType preferred_mime_extension; | 
|  | std::vector<FilePath::StringType> all_mime_extensions; | 
|  | // The GetPreferredExtensionForMimeType call will end up going to disk.  Do | 
|  | // this on another thread to avoid slowing the IO thread. | 
|  | // http://crbug.com/61827 | 
|  | // TODO(asanka): Remove this ScopedAllowIO once all callers have switched | 
|  | // over to IO safe threads. | 
|  | base::ThreadRestrictions::ScopedAllowIO allow_io; | 
|  | net::GetPreferredExtensionForMimeType(mime_type, &preferred_mime_extension); | 
|  | net::GetExtensionsForMimeType(mime_type, &all_mime_extensions); | 
|  | // If the existing extension is in the list of valid extensions for the | 
|  | // given type, use it. This avoids doing things like pointlessly renaming | 
|  | // "foo.jpg" to "foo.jpeg". | 
|  | if (std::find(all_mime_extensions.begin(), | 
|  | all_mime_extensions.end(), | 
|  | extension) != all_mime_extensions.end()) { | 
|  | // leave |extension| alone | 
|  | } else if (!preferred_mime_extension.empty()) { | 
|  | extension = preferred_mime_extension; | 
|  | } | 
|  | } | 
|  |  | 
|  | #if defined(OS_WIN) | 
|  | static const FilePath::CharType default_extension[] = | 
|  | FILE_PATH_LITERAL("download"); | 
|  |  | 
|  | // Rename shell-integrated extensions. | 
|  | // TODO(asanka): Consider stripping out the bad extension and replacing it | 
|  | // with the preferred extension for the MIME type if one is available. | 
|  | if (IsShellIntegratedExtension(extension)) | 
|  | extension.assign(default_extension); | 
|  | #endif | 
|  |  | 
|  | *file_name = file_name->ReplaceExtension(extension); | 
|  | } | 
|  |  | 
|  | }  // namespace | 
|  |  | 
|  | const FormatUrlType kFormatUrlOmitNothing                     = 0; | 
|  | const FormatUrlType kFormatUrlOmitUsernamePassword            = 1 << 0; | 
|  | const FormatUrlType kFormatUrlOmitHTTP                        = 1 << 1; | 
|  | const FormatUrlType kFormatUrlOmitTrailingSlashOnBareHostname = 1 << 2; | 
|  | const FormatUrlType kFormatUrlOmitAll = kFormatUrlOmitUsernamePassword | | 
|  | kFormatUrlOmitHTTP | kFormatUrlOmitTrailingSlashOnBareHostname; | 
|  |  | 
|  | static base::LazyInstance<std::multiset<int> >::Leaky | 
|  | g_explicitly_allowed_ports = LAZY_INSTANCE_INITIALIZER; | 
|  |  | 
|  | size_t GetCountOfExplicitlyAllowedPorts() { | 
|  | return g_explicitly_allowed_ports.Get().size(); | 
|  | } | 
|  |  | 
|  | GURL FilePathToFileURL(const FilePath& path) { | 
|  | // Produce a URL like "file:///C:/foo" for a regular file, or | 
|  | // "file://///server/path" for UNC. The URL canonicalizer will fix up the | 
|  | // latter case to be the canonical UNC form: "file://server/path" | 
|  | FilePath::StringType url_string(kFileURLPrefix); | 
|  | url_string.append(path.value()); | 
|  |  | 
|  | // Now do replacement of some characters. Since we assume the input is a | 
|  | // literal filename, anything the URL parser might consider special should | 
|  | // be escaped here. | 
|  |  | 
|  | // must be the first substitution since others will introduce percents as the | 
|  | // escape character | 
|  | ReplaceSubstringsAfterOffset(&url_string, 0, | 
|  | FILE_PATH_LITERAL("%"), FILE_PATH_LITERAL("%25")); | 
|  |  | 
|  | // semicolon is supposed to be some kind of separator according to RFC 2396 | 
|  | ReplaceSubstringsAfterOffset(&url_string, 0, | 
|  | FILE_PATH_LITERAL(";"), FILE_PATH_LITERAL("%3B")); | 
|  |  | 
|  | ReplaceSubstringsAfterOffset(&url_string, 0, | 
|  | FILE_PATH_LITERAL("#"), FILE_PATH_LITERAL("%23")); | 
|  |  | 
|  | ReplaceSubstringsAfterOffset(&url_string, 0, | 
|  | FILE_PATH_LITERAL("?"), FILE_PATH_LITERAL("%3F")); | 
|  |  | 
|  | #if defined(OS_POSIX) | 
|  | ReplaceSubstringsAfterOffset(&url_string, 0, | 
|  | FILE_PATH_LITERAL("\\"), FILE_PATH_LITERAL("%5C")); | 
|  | #endif | 
|  |  | 
|  | return GURL(url_string); | 
|  | } | 
|  |  | 
|  | std::string GetSpecificHeader(const std::string& headers, | 
|  | const std::string& name) { | 
|  | // We want to grab the Value from the "Key: Value" pairs in the headers, | 
|  | // which should look like this (no leading spaces, \n-separated) (we format | 
|  | // them this way in url_request_inet.cc): | 
|  | //    HTTP/1.1 200 OK\n | 
|  | //    ETag: "6d0b8-947-24f35ec0"\n | 
|  | //    Content-Length: 2375\n | 
|  | //    Content-Type: text/html; charset=UTF-8\n | 
|  | //    Last-Modified: Sun, 03 Sep 2006 04:34:43 GMT\n | 
|  | if (headers.empty()) | 
|  | return std::string(); | 
|  |  | 
|  | std::string match('\n' + name + ':'); | 
|  |  | 
|  | std::string::const_iterator begin = | 
|  | std::search(headers.begin(), headers.end(), match.begin(), match.end(), | 
|  | base::CaseInsensitiveCompareASCII<char>()); | 
|  |  | 
|  | if (begin == headers.end()) | 
|  | return std::string(); | 
|  |  | 
|  | begin += match.length(); | 
|  |  | 
|  | std::string ret; | 
|  | TrimWhitespace(std::string(begin, std::find(begin, headers.end(), '\n')), | 
|  | TRIM_ALL, &ret); | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | string16 IDNToUnicode(const std::string& host, | 
|  | const std::string& languages) { | 
|  | return IDNToUnicodeWithOffsets(host, languages, NULL); | 
|  | } | 
|  |  | 
|  | std::string CanonicalizeHost(const std::string& host, | 
|  | url_canon::CanonHostInfo* host_info) { | 
|  | // Try to canonicalize the host. | 
|  | const url_parse::Component raw_host_component( | 
|  | 0, static_cast<int>(host.length())); | 
|  | std::string canon_host; | 
|  | url_canon::StdStringCanonOutput canon_host_output(&canon_host); | 
|  | url_canon::CanonicalizeHostVerbose(host.c_str(), raw_host_component, | 
|  | &canon_host_output, host_info); | 
|  |  | 
|  | if (host_info->out_host.is_nonempty() && | 
|  | host_info->family != url_canon::CanonHostInfo::BROKEN) { | 
|  | // Success!  Assert that there's no extra garbage. | 
|  | canon_host_output.Complete(); | 
|  | DCHECK_EQ(host_info->out_host.len, static_cast<int>(canon_host.length())); | 
|  | } else { | 
|  | // Empty host, or canonicalization failed.  We'll return empty. | 
|  | canon_host.clear(); | 
|  | } | 
|  |  | 
|  | return canon_host; | 
|  | } | 
|  |  | 
|  | std::string GetDirectoryListingHeader(const string16& title) { | 
|  | #if !defined(COBALT) | 
|  | static const base::StringPiece header( | 
|  | NetModule::GetResource(IDR_DIR_HEADER_HTML)); | 
|  | // This can be null in unit tests. | 
|  | DLOG_IF(WARNING, header.empty()) << | 
|  | "Missing resource: directory listing header"; | 
|  |  | 
|  | std::string result; | 
|  | if (!header.empty()) | 
|  | result.assign(header.data(), header.size()); | 
|  |  | 
|  | result.append("<script>start("); | 
|  | base::JsonDoubleQuote(title, true, &result); | 
|  | result.append(");</script>\n"); | 
|  |  | 
|  | return result; | 
|  | #else | 
|  | // This function is only used by URLRequestFileDirJob, | 
|  | // which we don't support. | 
|  | NOTREACHED(); | 
|  | return ""; | 
|  | #endif | 
|  | } | 
|  |  | 
|  | inline bool IsHostCharAlpha(char c) { | 
|  | // We can just check lowercase because uppercase characters have already been | 
|  | // normalized. | 
|  | return (c >= 'a') && (c <= 'z'); | 
|  | } | 
|  |  | 
|  | inline bool IsHostCharDigit(char c) { | 
|  | return (c >= '0') && (c <= '9'); | 
|  | } | 
|  |  | 
|  | bool IsCanonicalizedHostCompliant(const std::string& host, | 
|  | const std::string& desired_tld) { | 
|  | if (host.empty()) | 
|  | return false; | 
|  |  | 
|  | bool in_component = false; | 
|  | bool most_recent_component_started_alpha = false; | 
|  | bool last_char_was_underscore = false; | 
|  |  | 
|  | for (std::string::const_iterator i(host.begin()); i != host.end(); ++i) { | 
|  | const char c = *i; | 
|  | if (!in_component) { | 
|  | most_recent_component_started_alpha = IsHostCharAlpha(c); | 
|  | if (!most_recent_component_started_alpha && !IsHostCharDigit(c) && | 
|  | (c != '-')) | 
|  | return false; | 
|  | in_component = true; | 
|  | } else { | 
|  | if (c == '.') { | 
|  | if (last_char_was_underscore) | 
|  | return false; | 
|  | in_component = false; | 
|  | } else if (IsHostCharAlpha(c) || IsHostCharDigit(c) || (c == '-')) { | 
|  | last_char_was_underscore = false; | 
|  | } else if (c == '_') { | 
|  | last_char_was_underscore = true; | 
|  | } else { | 
|  | return false; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | return most_recent_component_started_alpha || | 
|  | (!desired_tld.empty() && IsHostCharAlpha(desired_tld[0])); | 
|  | } | 
|  |  | 
|  | std::string GetDirectoryListingEntry(const string16& name, | 
|  | const std::string& raw_bytes, | 
|  | bool is_dir, | 
|  | int64 size, | 
|  | Time modified) { | 
|  | std::string result; | 
|  | result.append("<script>addRow("); | 
|  | base::JsonDoubleQuote(name, true, &result); | 
|  | result.append(","); | 
|  | if (raw_bytes.empty()) { | 
|  | base::JsonDoubleQuote(EscapePath(UTF16ToUTF8(name)), | 
|  | true, &result); | 
|  | } else { | 
|  | base::JsonDoubleQuote(EscapePath(raw_bytes), true, &result); | 
|  | } | 
|  | if (is_dir) { | 
|  | result.append(",1,"); | 
|  | } else { | 
|  | result.append(",0,"); | 
|  | } | 
|  |  | 
|  | // Negative size means unknown or not applicable (e.g. directory). | 
|  | string16 size_string; | 
|  | if (size >= 0) | 
|  | size_string = FormatBytesUnlocalized(size); | 
|  | base::JsonDoubleQuote(size_string, true, &result); | 
|  |  | 
|  | result.append(","); | 
|  |  | 
|  | string16 modified_str; | 
|  | // |modified| can be NULL in FTP listings. | 
|  | if (!modified.is_null()) { | 
|  | modified_str = base::TimeFormatShortDateAndTime(modified); | 
|  | } | 
|  | base::JsonDoubleQuote(modified_str, true, &result); | 
|  |  | 
|  | result.append(");</script>\n"); | 
|  |  | 
|  | return result; | 
|  | } | 
|  |  | 
|  | string16 StripWWW(const string16& text) { | 
|  | const string16 www(ASCIIToUTF16("www.")); | 
|  | return StartsWith(text, www, true) ? text.substr(www.length()) : text; | 
|  | } | 
|  |  | 
|  | string16 StripWWWFromHost(const GURL& url) { | 
|  | DCHECK(url.is_valid()); | 
|  | return StripWWW(ASCIIToUTF16(url.host())); | 
|  | } | 
|  |  | 
|  | void GenerateSafeFileName(const std::string& mime_type, | 
|  | bool ignore_extension, | 
|  | FilePath* file_path) { | 
|  | // Make sure we get the right file extension | 
|  | EnsureSafeExtension(mime_type, ignore_extension, file_path); | 
|  |  | 
|  | #if defined(OS_WIN) | 
|  | // Prepend "_" to the file name if it's a reserved name | 
|  | FilePath::StringType leaf_name = file_path->BaseName().value(); | 
|  | DCHECK(!leaf_name.empty()); | 
|  | if (IsReservedName(leaf_name)) { | 
|  | leaf_name = FilePath::StringType(FILE_PATH_LITERAL("_")) + leaf_name; | 
|  | *file_path = file_path->DirName(); | 
|  | if (file_path->value() == FilePath::kCurrentDirectory) { | 
|  | *file_path = FilePath(leaf_name); | 
|  | } else { | 
|  | *file_path = file_path->Append(leaf_name); | 
|  | } | 
|  | } | 
|  | #endif | 
|  | } | 
|  |  | 
|  | string16 GetSuggestedFilename(const GURL& url, | 
|  | const std::string& content_disposition, | 
|  | const std::string& referrer_charset, | 
|  | const std::string& suggested_name, | 
|  | const std::string& mime_type, | 
|  | const std::string& default_name) { | 
|  | // TODO: this function to be updated to match the httpbis recommendations. | 
|  | // Talk to abarth for the latest news. | 
|  |  | 
|  | // We don't translate this fallback string, "download". If localization is | 
|  | // needed, the caller should provide localized fallback in |default_name|. | 
|  | static const char* kFinalFallbackName = "download"; | 
|  | std::string filename;  // In UTF-8 | 
|  | bool overwrite_extension = false; | 
|  |  | 
|  | // Try to extract a filename from content-disposition first. | 
|  | #if !defined(__LB_SHELL__) && !defined(COBALT) | 
|  | if (!content_disposition.empty()) { | 
|  | HttpContentDisposition header(content_disposition, referrer_charset); | 
|  | filename = header.filename(); | 
|  | } | 
|  | #endif  // !defined(__LB_SHELL__) && !defined(COBALT) | 
|  |  | 
|  | // Then try to use the suggested name. | 
|  | if (filename.empty() && !suggested_name.empty()) | 
|  | filename = suggested_name; | 
|  |  | 
|  | // Now try extracting the filename from the URL.  GetFileNameFromURL() only | 
|  | // looks at the last component of the URL and doesn't return the hostname as a | 
|  | // failover. | 
|  | if (filename.empty()) | 
|  | filename = GetFileNameFromURL(url, referrer_charset, &overwrite_extension); | 
|  |  | 
|  | // Finally try the URL hostname, but only if there's no default specified in | 
|  | // |default_name|.  Some schemes (e.g.: file:, about:, data:) do not have a | 
|  | // host name. | 
|  | if (filename.empty() && default_name.empty() && | 
|  | url.is_valid() && !url.host().empty()) { | 
|  | // TODO(jungshik) : Decode a 'punycoded' IDN hostname. (bug 1264451) | 
|  | filename = url.host(); | 
|  | } | 
|  |  | 
|  | #if defined(OS_WIN) | 
|  | std::string::size_type trimmed_trailing_character_count = | 
|  | CountTrailingChars(filename, " ."); | 
|  | #endif | 
|  | SanitizeGeneratedFileName(filename); | 
|  | // Sanitization can cause the filename to disappear (e.g.: if the filename | 
|  | // consisted entirely of spaces and '.'s), in which case we use the default. | 
|  | if (filename.empty()) { | 
|  | #if defined(OS_WIN) | 
|  | trimmed_trailing_character_count = 0; | 
|  | #endif | 
|  | overwrite_extension = false; | 
|  | if (default_name.empty()) | 
|  | filename = kFinalFallbackName; | 
|  | } | 
|  |  | 
|  | #if defined(OS_WIN) | 
|  | string16 path = UTF8ToUTF16(filename.empty() ? default_name : filename); | 
|  | // On Windows we want to preserve or replace all characters including | 
|  | // whitespace to prevent file extension obfuscation on trusted websites | 
|  | // e.g. Gmail might think evil.exe. is safe, so we don't want it to become | 
|  | // evil.exe when we download it | 
|  | string16::size_type path_length_before_trim = path.length(); | 
|  | TrimWhitespace(path, TRIM_TRAILING, &path); | 
|  | trimmed_trailing_character_count += path_length_before_trim - path.length(); | 
|  | file_util::ReplaceIllegalCharactersInPath(&path, '-'); | 
|  | path.append(trimmed_trailing_character_count, '-'); | 
|  | FilePath result(path); | 
|  | GenerateSafeFileName(mime_type, overwrite_extension, &result); | 
|  | return result.value(); | 
|  | #else | 
|  | std::string path = filename.empty() ? default_name : filename; | 
|  | file_util::ReplaceIllegalCharactersInPath(&path, '-'); | 
|  | FilePath result(path); | 
|  | GenerateSafeFileName(mime_type, overwrite_extension, &result); | 
|  | return UTF8ToUTF16(result.value()); | 
|  | #endif | 
|  | } | 
|  |  | 
|  | #if !defined(__LB_SHELL__) && !defined(COBALT) | 
|  | FilePath GenerateFileName(const GURL& url, | 
|  | const std::string& content_disposition, | 
|  | const std::string& referrer_charset, | 
|  | const std::string& suggested_name, | 
|  | const std::string& mime_type, | 
|  | const std::string& default_file_name) { | 
|  | string16 file_name = GetSuggestedFilename(url, | 
|  | content_disposition, | 
|  | referrer_charset, | 
|  | suggested_name, | 
|  | mime_type, | 
|  | default_file_name); | 
|  |  | 
|  | #if defined(OS_WIN) | 
|  | FilePath generated_name(file_name); | 
|  | #else | 
|  | FilePath generated_name(base::SysWideToNativeMB(UTF16ToWide(file_name))); | 
|  | #endif | 
|  |  | 
|  | #if defined(OS_CHROMEOS) | 
|  | // When doing file manager operations on ChromeOS, the file paths get | 
|  | // normalized in WebKit layer, so let's ensure downloaded files have | 
|  | // normalized names. Otherwise, we won't be able to handle files with NFD | 
|  | // utf8 encoded characters in name. | 
|  | file_util::NormalizeFileNameEncoding(&generated_name); | 
|  | #endif | 
|  |  | 
|  | DCHECK(!generated_name.empty()); | 
|  |  | 
|  | return generated_name; | 
|  | } | 
|  | #endif  // !defined(__LB_SHELL__) && !defined(COBALT) | 
|  |  | 
|  | bool IsPortAllowedByDefault(int port) { | 
|  | int array_size = arraysize(kRestrictedPorts); | 
|  | for (int i = 0; i < array_size; i++) { | 
|  | if (kRestrictedPorts[i] == port) { | 
|  | return false; | 
|  | } | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool IsPortAllowedByFtp(int port) { | 
|  | int array_size = arraysize(kAllowedFtpPorts); | 
|  | for (int i = 0; i < array_size; i++) { | 
|  | if (kAllowedFtpPorts[i] == port) { | 
|  | return true; | 
|  | } | 
|  | } | 
|  | // Port not explicitly allowed by FTP, so return the default restrictions. | 
|  | return IsPortAllowedByDefault(port); | 
|  | } | 
|  |  | 
|  | bool IsPortAllowedByOverride(int port) { | 
|  | if (g_explicitly_allowed_ports.Get().empty()) | 
|  | return false; | 
|  |  | 
|  | return g_explicitly_allowed_ports.Get().count(port) > 0; | 
|  | } | 
|  |  | 
|  | #if defined(OS_STARBOARD) | 
|  | int SetNonBlocking(SbSocket fd) { | 
|  | // All Starboard sockets are created non-blocking. | 
|  | return 0; | 
|  | } | 
|  | #else  // defined(OS_STARBOARD) | 
|  | int SetNonBlocking(int fd) { | 
|  | #if defined(OS_WIN) | 
|  | unsigned long no_block = 1; | 
|  | return ioctlsocket(fd, FIONBIO, &no_block); | 
|  | #elif defined(COBALT_WIN) | 
|  | return -1; | 
|  | #elif defined(__LB_SHELL__) && !(defined(__LB_ANDROID__) || defined(__LB_LINUX__)) | 
|  | int val = 1; | 
|  | return setsockopt(fd, SOL_SOCKET, SO_NBIO, &val, sizeof(int)); | 
|  | #elif defined(OS_POSIX) | 
|  | int flags = fcntl(fd, F_GETFL, 0); | 
|  | if (-1 == flags) | 
|  | return flags; | 
|  | return fcntl(fd, F_SETFL, flags | O_NONBLOCK); | 
|  | #endif | 
|  | } | 
|  | #endif  // defined(OS_STARBOARD) | 
|  |  | 
|  | bool ParseHostAndPort(std::string::const_iterator host_and_port_begin, | 
|  | std::string::const_iterator host_and_port_end, | 
|  | std::string* host, | 
|  | int* port) { | 
|  | if (host_and_port_begin >= host_and_port_end) | 
|  | return false; | 
|  |  | 
|  | // When using url_parse, we use char*. | 
|  | const char* auth_begin = &(*host_and_port_begin); | 
|  | int auth_len = host_and_port_end - host_and_port_begin; | 
|  |  | 
|  | url_parse::Component auth_component(0, auth_len); | 
|  | url_parse::Component username_component; | 
|  | url_parse::Component password_component; | 
|  | url_parse::Component hostname_component; | 
|  | url_parse::Component port_component; | 
|  |  | 
|  | url_parse::ParseAuthority(auth_begin, auth_component, &username_component, | 
|  | &password_component, &hostname_component, &port_component); | 
|  |  | 
|  | // There shouldn't be a username/password. | 
|  | if (username_component.is_valid() || password_component.is_valid()) | 
|  | return false; | 
|  |  | 
|  | if (!hostname_component.is_nonempty()) | 
|  | return false;  // Failed parsing. | 
|  |  | 
|  | int parsed_port_number = -1; | 
|  | if (port_component.is_nonempty()) { | 
|  | parsed_port_number = url_parse::ParsePort(auth_begin, port_component); | 
|  |  | 
|  | // If parsing failed, port_number will be either PORT_INVALID or | 
|  | // PORT_UNSPECIFIED, both of which are negative. | 
|  | if (parsed_port_number < 0) | 
|  | return false;  // Failed parsing the port number. | 
|  | } | 
|  |  | 
|  | if (port_component.len == 0) | 
|  | return false;  // Reject inputs like "foo:" | 
|  |  | 
|  | // Pass results back to caller. | 
|  | host->assign(auth_begin + hostname_component.begin, hostname_component.len); | 
|  | *port = parsed_port_number; | 
|  |  | 
|  | return true;  // Success. | 
|  | } | 
|  |  | 
|  | bool ParseHostAndPort(const std::string& host_and_port, | 
|  | std::string* host, | 
|  | int* port) { | 
|  | return ParseHostAndPort( | 
|  | host_and_port.begin(), host_and_port.end(), host, port); | 
|  | } | 
|  |  | 
|  | std::string GetHostAndPort(const GURL& url) { | 
|  | // For IPv6 literals, GURL::host() already includes the brackets so it is | 
|  | // safe to just append a colon. | 
|  | return base::StringPrintf("%s:%d", url.host().c_str(), | 
|  | url.EffectiveIntPort()); | 
|  | } | 
|  |  | 
|  | std::string GetHostAndOptionalPort(const GURL& url) { | 
|  | // For IPv6 literals, GURL::host() already includes the brackets | 
|  | // so it is safe to just append a colon. | 
|  | if (url.has_port()) | 
|  | return base::StringPrintf("%s:%s", url.host().c_str(), url.port().c_str()); | 
|  | return url.host(); | 
|  | } | 
|  |  | 
|  | #if defined(OS_STARBOARD) | 
|  | bool GetIPAddressFromSbSocketAddress(const SbSocketAddress* address, | 
|  | const unsigned char** out_address_data, | 
|  | size_t* out_address_len, | 
|  | uint16* out_port) { | 
|  | DCHECK(address); | 
|  | DCHECK(out_address_data); | 
|  | DCHECK(out_address_len); | 
|  | if (out_port) { | 
|  | *out_port = address->port; | 
|  | } | 
|  |  | 
|  | *out_address_data = address->address; | 
|  | switch (address->type) { | 
|  | case kSbSocketAddressTypeIpv4: | 
|  | *out_address_len = kIPv4AddressSize; | 
|  | break; | 
|  | case kSbSocketAddressTypeIpv6: | 
|  | *out_address_len = kIPv6AddressSize; | 
|  | break; | 
|  |  | 
|  | default: | 
|  | NOTREACHED(); | 
|  | break; | 
|  | } | 
|  |  | 
|  | return true; | 
|  | } | 
|  | #else  // defined(OS_STARBOARD) | 
|  | // Extracts the address and port portions of a sockaddr. | 
|  | bool GetIPAddressFromSockAddr(const struct sockaddr* sock_addr, | 
|  | socklen_t sock_addr_len, | 
|  | const uint8** address, | 
|  | size_t* address_len, | 
|  | uint16* port) { | 
|  | if (sock_addr->sa_family == AF_INET) { | 
|  | if (sock_addr_len < static_cast<socklen_t>(sizeof(struct sockaddr_in))) | 
|  | return false; | 
|  | const struct sockaddr_in* addr = | 
|  | reinterpret_cast<const struct sockaddr_in*>(sock_addr); | 
|  | *address = reinterpret_cast<const uint8*>(&addr->sin_addr); | 
|  | *address_len = kIPv4AddressSize; | 
|  | if (port) | 
|  | *port = base::NetToHost16(addr->sin_port); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | #if defined(IN6ADDR_ANY_INIT) | 
|  | if (sock_addr->sa_family == AF_INET6) { | 
|  | if (sock_addr_len < static_cast<socklen_t>(sizeof(struct sockaddr_in6))) | 
|  | return false; | 
|  | const struct sockaddr_in6* addr = | 
|  | reinterpret_cast<const struct sockaddr_in6*>(sock_addr); | 
|  | *address = reinterpret_cast<const unsigned char*>(&addr->sin6_addr); | 
|  | *address_len = kIPv6AddressSize; | 
|  | if (port) | 
|  | *port = base::NetToHost16(addr->sin6_port); | 
|  | return true; | 
|  | } | 
|  | #endif | 
|  |  | 
|  | return false;  // Unrecognized |sa_family|. | 
|  | } | 
|  | #endif  // defined(OS_STARBOARD) | 
|  |  | 
|  | std::string IPAddressToString(const uint8* address, | 
|  | size_t address_len) { | 
|  | std::string str; | 
|  | url_canon::StdStringCanonOutput output(&str); | 
|  |  | 
|  | if (address_len == kIPv4AddressSize) { | 
|  | url_canon::AppendIPv4Address(address, &output); | 
|  | } else if (address_len == kIPv6AddressSize) { | 
|  | url_canon::AppendIPv6Address(address, &output); | 
|  | } else { | 
|  | CHECK(false) << "Invalid IP address with length: " << address_len; | 
|  | } | 
|  |  | 
|  | output.Complete(); | 
|  | return str; | 
|  | } | 
|  |  | 
|  | std::string IPAddressToStringWithPort(const uint8* address, | 
|  | size_t address_len, | 
|  | uint16 port) { | 
|  | std::string address_str = IPAddressToString(address, address_len); | 
|  |  | 
|  | if (address_len == kIPv6AddressSize) { | 
|  | // Need to bracket IPv6 addresses since they contain colons. | 
|  | return base::StringPrintf("[%s]:%d", address_str.c_str(), port); | 
|  | } | 
|  | return base::StringPrintf("%s:%d", address_str.c_str(), port); | 
|  | } | 
|  |  | 
|  | #if defined(OS_STARBOARD) | 
|  | std::string NetAddressToString(const SbSocketAddress* address) { | 
|  | const uint8* address_data; | 
|  | size_t address_len; | 
|  | if (!GetIPAddressFromSbSocketAddress(address, &address_data, &address_len, | 
|  | NULL)) { | 
|  | NOTREACHED(); | 
|  | return ""; | 
|  | } | 
|  |  | 
|  | return IPAddressToString(address_data, address_len); | 
|  | } | 
|  |  | 
|  | std::string NetAddressToStringWithPort(const SbSocketAddress* address) { | 
|  | const uint8* address_data; | 
|  | size_t address_len; | 
|  | uint16 port; | 
|  | if (!GetIPAddressFromSbSocketAddress(address, &address_data, &address_len, | 
|  | &port)) { | 
|  | NOTREACHED(); | 
|  | return ""; | 
|  | } | 
|  |  | 
|  | return IPAddressToStringWithPort(address_data, address_len, port); | 
|  | } | 
|  |  | 
|  | #else   // defined(OS_STARBOARD) | 
|  | std::string NetAddressToString(const struct sockaddr* sa, | 
|  | socklen_t sock_addr_len) { | 
|  | const uint8* address; | 
|  | size_t address_len; | 
|  | if (!GetIPAddressFromSockAddr(sa, sock_addr_len, &address, | 
|  | &address_len, NULL)) { | 
|  | NOTREACHED(); | 
|  | return ""; | 
|  | } | 
|  | return IPAddressToString(address, address_len); | 
|  | } | 
|  |  | 
|  | std::string NetAddressToStringWithPort(const struct sockaddr* sa, | 
|  | socklen_t sock_addr_len) { | 
|  | const uint8* address; | 
|  | size_t address_len; | 
|  | uint16 port; | 
|  | if (!GetIPAddressFromSockAddr(sa, sock_addr_len, &address, | 
|  | &address_len, &port)) { | 
|  | NOTREACHED(); | 
|  | return ""; | 
|  | } | 
|  | return IPAddressToStringWithPort(address, address_len, port); | 
|  | } | 
|  | #endif  // defined(OS_STARBOARD) | 
|  |  | 
|  | std::string IPAddressToString(const IPAddressNumber& addr) { | 
|  | return IPAddressToString(&addr.front(), addr.size()); | 
|  | } | 
|  |  | 
|  | std::string IPAddressToStringWithPort(const IPAddressNumber& addr, | 
|  | uint16 port) { | 
|  | return IPAddressToStringWithPort(&addr.front(), addr.size(), port); | 
|  | } | 
|  |  | 
|  | std::string GetHostName() { | 
|  | #if defined(OS_STARBOARD) | 
|  | NOTIMPLEMENTED(); | 
|  | return ""; | 
|  | #else | 
|  | #if defined(OS_WIN) | 
|  | EnsureWinsockInit(); | 
|  | #endif | 
|  |  | 
|  | // Host names are limited to 255 bytes. | 
|  | char buffer[256]; | 
|  | int result = gethostname(buffer, sizeof(buffer)); | 
|  | if (result != 0) { | 
|  | DVLOG(1) << "gethostname() failed with " << result; | 
|  | buffer[0] = '\0'; | 
|  | } | 
|  | return std::string(buffer); | 
|  | #endif | 
|  | } | 
|  |  | 
|  | void GetIdentityFromURL(const GURL& url, | 
|  | string16* username, | 
|  | string16* password) { | 
|  | UnescapeRule::Type flags = | 
|  | UnescapeRule::SPACES | UnescapeRule::URL_SPECIAL_CHARS; | 
|  | *username = UnescapeAndDecodeUTF8URLComponent(url.username(), flags, NULL); | 
|  | *password = UnescapeAndDecodeUTF8URLComponent(url.password(), flags, NULL); | 
|  | } | 
|  |  | 
|  | std::string GetHostOrSpecFromURL(const GURL& url) { | 
|  | return url.has_host() ? TrimEndingDot(url.host()) : url.spec(); | 
|  | } | 
|  |  | 
|  | void AppendFormattedHost(const GURL& url, | 
|  | const std::string& languages, | 
|  | string16* output) { | 
|  | std::vector<size_t> offsets; | 
|  | AppendFormattedComponent(url.possibly_invalid_spec(), | 
|  | url.parsed_for_possibly_invalid_spec().host, offsets, | 
|  | HostComponentTransform(languages), output, NULL, NULL); | 
|  | } | 
|  |  | 
|  | string16 FormatUrlWithOffsets(const GURL& url, | 
|  | const std::string& languages, | 
|  | FormatUrlTypes format_types, | 
|  | UnescapeRule::Type unescape_rules, | 
|  | url_parse::Parsed* new_parsed, | 
|  | size_t* prefix_end, | 
|  | std::vector<size_t>* offsets_for_adjustment) { | 
|  | url_parse::Parsed parsed_temp; | 
|  | if (!new_parsed) | 
|  | new_parsed = &parsed_temp; | 
|  | else | 
|  | *new_parsed = url_parse::Parsed(); | 
|  | std::vector<size_t> original_offsets; | 
|  | if (offsets_for_adjustment) | 
|  | original_offsets = *offsets_for_adjustment; | 
|  |  | 
|  | // Special handling for view-source:.  Don't use chrome::kViewSourceScheme | 
|  | // because this library shouldn't depend on chrome. | 
|  | const char* const kViewSource = "view-source"; | 
|  | // Reject "view-source:view-source:..." to avoid deep recursion. | 
|  | const char* const kViewSourceTwice = "view-source:view-source:"; | 
|  | if (url.SchemeIs(kViewSource) && | 
|  | !StartsWithASCII(url.possibly_invalid_spec(), kViewSourceTwice, false)) { | 
|  | return FormatViewSourceUrl(url, original_offsets, languages, format_types, | 
|  | unescape_rules, new_parsed, prefix_end, offsets_for_adjustment); | 
|  | } | 
|  |  | 
|  | // We handle both valid and invalid URLs (this will give us the spec | 
|  | // regardless of validity). | 
|  | const std::string& spec = url.possibly_invalid_spec(); | 
|  | const url_parse::Parsed& parsed = url.parsed_for_possibly_invalid_spec(); | 
|  |  | 
|  | // Scheme & separators.  These are ASCII. | 
|  | string16 url_string; | 
|  | url_string.insert(url_string.end(), spec.begin(), | 
|  | spec.begin() + parsed.CountCharactersBefore(url_parse::Parsed::USERNAME, | 
|  | true)); | 
|  | const char kHTTP[] = "http://"; | 
|  | const char kFTP[] = "ftp."; | 
|  | // URLFixerUpper::FixupURL() treats "ftp.foo.com" as ftp://ftp.foo.com.  This | 
|  | // means that if we trim "http://" off a URL whose host starts with "ftp." and | 
|  | // the user inputs this into any field subject to fixup (which is basically | 
|  | // all input fields), the meaning would be changed.  (In fact, often the | 
|  | // formatted URL is directly pre-filled into an input field.)  For this reason | 
|  | // we avoid stripping "http://" in this case. | 
|  | bool omit_http = (format_types & kFormatUrlOmitHTTP) && | 
|  | EqualsASCII(url_string, kHTTP) && | 
|  | !StartsWithASCII(url.host(), kFTP, true); | 
|  | new_parsed->scheme = parsed.scheme; | 
|  |  | 
|  | // Username & password. | 
|  | if ((format_types & kFormatUrlOmitUsernamePassword) != 0) { | 
|  | // Remove the username and password fields. We don't want to display those | 
|  | // to the user since they can be used for attacks, | 
|  | // e.g. "http://google.com:search@evil.ru/" | 
|  | new_parsed->username.reset(); | 
|  | new_parsed->password.reset(); | 
|  | // Update the offsets based on removed username and/or password. | 
|  | if (offsets_for_adjustment && !offsets_for_adjustment->empty() && | 
|  | (parsed.username.is_nonempty() || parsed.password.is_nonempty())) { | 
|  | OffsetAdjuster offset_adjuster(offsets_for_adjustment); | 
|  | if (parsed.username.is_nonempty() && parsed.password.is_nonempty()) { | 
|  | // The seeming off-by-one and off-by-two in these first two lines are to | 
|  | // account for the ':' after the username and '@' after the password. | 
|  | offset_adjuster.Add(OffsetAdjuster::Adjustment( | 
|  | static_cast<size_t>(parsed.username.begin), | 
|  | static_cast<size_t>(parsed.username.len + parsed.password.len + 2), | 
|  | 0)); | 
|  | } else { | 
|  | const url_parse::Component* nonempty_component = | 
|  | parsed.username.is_nonempty() ? &parsed.username : &parsed.password; | 
|  | // The seeming off-by-one in below is to account for the '@' after the | 
|  | // username/password. | 
|  | offset_adjuster.Add(OffsetAdjuster::Adjustment( | 
|  | static_cast<size_t>(nonempty_component->begin), | 
|  | static_cast<size_t>(nonempty_component->len + 1), 0)); | 
|  | } | 
|  | } | 
|  | } else { | 
|  | AppendFormattedComponent(spec, parsed.username, original_offsets, | 
|  | NonHostComponentTransform(unescape_rules), &url_string, | 
|  | &new_parsed->username, offsets_for_adjustment); | 
|  | if (parsed.password.is_valid()) { | 
|  | size_t colon = parsed.username.end(); | 
|  | DCHECK_EQ(static_cast<size_t>(parsed.password.begin - 1), colon); | 
|  | std::vector<size_t>::const_iterator colon_iter = | 
|  | std::find(original_offsets.begin(), original_offsets.end(), colon); | 
|  | if (colon_iter != original_offsets.end()) { | 
|  | (*offsets_for_adjustment)[colon_iter - original_offsets.begin()] = | 
|  | url_string.length(); | 
|  | } | 
|  | url_string.push_back(':'); | 
|  | } | 
|  | AppendFormattedComponent(spec, parsed.password, original_offsets, | 
|  | NonHostComponentTransform(unescape_rules), &url_string, | 
|  | &new_parsed->password, offsets_for_adjustment); | 
|  | if (parsed.username.is_valid() || parsed.password.is_valid()) { | 
|  | size_t at_sign = (parsed.password.is_valid() ? | 
|  | parsed.password : parsed.username).end(); | 
|  | DCHECK_EQ(static_cast<size_t>(parsed.host.begin - 1), at_sign); | 
|  | std::vector<size_t>::const_iterator at_sign_iter = | 
|  | std::find(original_offsets.begin(), original_offsets.end(), at_sign); | 
|  | if (at_sign_iter != original_offsets.end()) { | 
|  | (*offsets_for_adjustment)[at_sign_iter - original_offsets.begin()] = | 
|  | url_string.length(); | 
|  | } | 
|  | url_string.push_back('@'); | 
|  | } | 
|  | } | 
|  | if (prefix_end) | 
|  | *prefix_end = static_cast<size_t>(url_string.length()); | 
|  |  | 
|  | // Host. | 
|  | AppendFormattedComponent(spec, parsed.host, original_offsets, | 
|  | HostComponentTransform(languages), &url_string, &new_parsed->host, | 
|  | offsets_for_adjustment); | 
|  |  | 
|  | // Port. | 
|  | if (parsed.port.is_nonempty()) { | 
|  | url_string.push_back(':'); | 
|  | new_parsed->port.begin = url_string.length(); | 
|  | url_string.insert(url_string.end(), | 
|  | spec.begin() + parsed.port.begin, | 
|  | spec.begin() + parsed.port.end()); | 
|  | new_parsed->port.len = url_string.length() - new_parsed->port.begin; | 
|  | } else { | 
|  | new_parsed->port.reset(); | 
|  | } | 
|  |  | 
|  | // Path & query.  Both get the same general unescape & convert treatment. | 
|  | if (!(format_types & kFormatUrlOmitTrailingSlashOnBareHostname) || | 
|  | !CanStripTrailingSlash(url)) { | 
|  | AppendFormattedComponent(spec, parsed.path, original_offsets, | 
|  | NonHostComponentTransform(unescape_rules), &url_string, | 
|  | &new_parsed->path, offsets_for_adjustment); | 
|  | } | 
|  | if (parsed.query.is_valid()) | 
|  | url_string.push_back('?'); | 
|  | AppendFormattedComponent(spec, parsed.query, original_offsets, | 
|  | NonHostComponentTransform(unescape_rules), &url_string, | 
|  | &new_parsed->query, offsets_for_adjustment); | 
|  |  | 
|  | // Ref.  This is valid, unescaped UTF-8, so we can just convert. | 
|  | if (parsed.ref.is_valid()) { | 
|  | url_string.push_back('#'); | 
|  | size_t original_ref_begin = static_cast<size_t>(parsed.ref.begin); | 
|  | size_t output_ref_begin = url_string.length(); | 
|  | new_parsed->ref.begin = static_cast<int>(output_ref_begin); | 
|  |  | 
|  | std::vector<size_t> offsets_into_ref( | 
|  | OffsetsIntoComponent(original_offsets, original_ref_begin)); | 
|  | if (parsed.ref.len > 0) { | 
|  | url_string.append(UTF8ToUTF16AndAdjustOffsets( | 
|  | spec.substr(original_ref_begin, static_cast<size_t>(parsed.ref.len)), | 
|  | &offsets_into_ref)); | 
|  | } | 
|  |  | 
|  | new_parsed->ref.len = | 
|  | static_cast<int>(url_string.length() - new_parsed->ref.begin); | 
|  | AdjustForComponentTransform(original_offsets, original_ref_begin, | 
|  | static_cast<size_t>(parsed.ref.end()), offsets_into_ref, | 
|  | output_ref_begin, offsets_for_adjustment); | 
|  | } | 
|  |  | 
|  | // If we need to strip out http do it after the fact. This way we don't need | 
|  | // to worry about how offset_for_adjustment is interpreted. | 
|  | if (omit_http && StartsWith(url_string, ASCIIToUTF16(kHTTP), true)) { | 
|  | const size_t kHTTPSize = arraysize(kHTTP) - 1; | 
|  | url_string = url_string.substr(kHTTPSize); | 
|  | if (offsets_for_adjustment && !offsets_for_adjustment->empty()) { | 
|  | OffsetAdjuster offset_adjuster(offsets_for_adjustment); | 
|  | offset_adjuster.Add(OffsetAdjuster::Adjustment(0, kHTTPSize, 0)); | 
|  | } | 
|  | if (prefix_end) | 
|  | *prefix_end -= kHTTPSize; | 
|  |  | 
|  | // Adjust new_parsed. | 
|  | DCHECK(new_parsed->scheme.is_valid()); | 
|  | int delta = -(new_parsed->scheme.len + 3);  // +3 for ://. | 
|  | new_parsed->scheme.reset(); | 
|  | AdjustComponents(delta, new_parsed); | 
|  | } | 
|  |  | 
|  | LimitOffsets(url_string, offsets_for_adjustment); | 
|  | return url_string; | 
|  | } | 
|  |  | 
|  | string16 FormatUrl(const GURL& url, | 
|  | const std::string& languages, | 
|  | FormatUrlTypes format_types, | 
|  | UnescapeRule::Type unescape_rules, | 
|  | url_parse::Parsed* new_parsed, | 
|  | size_t* prefix_end, | 
|  | size_t* offset_for_adjustment) { | 
|  | std::vector<size_t> offsets; | 
|  | if (offset_for_adjustment) | 
|  | offsets.push_back(*offset_for_adjustment); | 
|  | string16 result = FormatUrlWithOffsets(url, languages, format_types, | 
|  | unescape_rules, new_parsed, prefix_end, &offsets); | 
|  | if (offset_for_adjustment) | 
|  | *offset_for_adjustment = offsets[0]; | 
|  | return result; | 
|  | } | 
|  |  | 
|  | bool CanStripTrailingSlash(const GURL& url) { | 
|  | // Omit the path only for standard, non-file URLs with nothing but "/" after | 
|  | // the hostname. | 
|  | return url.IsStandard() && !url.SchemeIsFile() && | 
|  | !url.SchemeIsFileSystem() && !url.has_query() && !url.has_ref() | 
|  | && url.path() == "/"; | 
|  | } | 
|  |  | 
|  | GURL SimplifyUrlForRequest(const GURL& url) { | 
|  | DCHECK(url.is_valid()); | 
|  | GURL::Replacements replacements; | 
|  | replacements.ClearUsername(); | 
|  | replacements.ClearPassword(); | 
|  | replacements.ClearRef(); | 
|  | return url.ReplaceComponents(replacements); | 
|  | } | 
|  |  | 
|  | // Specifies a comma separated list of port numbers that should be accepted | 
|  | // despite bans. If the string is invalid no allowed ports are stored. | 
|  | void SetExplicitlyAllowedPorts(const std::string& allowed_ports) { | 
|  | if (allowed_ports.empty()) | 
|  | return; | 
|  |  | 
|  | std::multiset<int> ports; | 
|  | size_t last = 0; | 
|  | size_t size = allowed_ports.size(); | 
|  | // The comma delimiter. | 
|  | const std::string::value_type kComma = ','; | 
|  |  | 
|  | // Overflow is still possible for evil user inputs. | 
|  | for (size_t i = 0; i <= size; ++i) { | 
|  | // The string should be composed of only digits and commas. | 
|  | if (i != size && !IsAsciiDigit(allowed_ports[i]) && | 
|  | (allowed_ports[i] != kComma)) | 
|  | return; | 
|  | if (i == size || allowed_ports[i] == kComma) { | 
|  | if (i > last) { | 
|  | int port; | 
|  | base::StringToInt(base::StringPiece(allowed_ports.begin() + last, | 
|  | allowed_ports.begin() + i), | 
|  | &port); | 
|  | ports.insert(port); | 
|  | } | 
|  | last = i + 1; | 
|  | } | 
|  | } | 
|  | g_explicitly_allowed_ports.Get() = ports; | 
|  | } | 
|  |  | 
|  | ScopedPortException::ScopedPortException(int port) : port_(port) { | 
|  | g_explicitly_allowed_ports.Get().insert(port); | 
|  | } | 
|  |  | 
|  | ScopedPortException::~ScopedPortException() { | 
|  | std::multiset<int>::iterator it = | 
|  | g_explicitly_allowed_ports.Get().find(port_); | 
|  | if (it != g_explicitly_allowed_ports.Get().end()) | 
|  | g_explicitly_allowed_ports.Get().erase(it); | 
|  | else | 
|  | NOTREACHED(); | 
|  | } | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | const char* kFinalStatusNames[] = { | 
|  | "Cannot create sockets", | 
|  | "Can create sockets", | 
|  | "Can't get addresses", | 
|  | "Global ipv6 address missing", | 
|  | "Global ipv6 address present", | 
|  | "Interface array too short", | 
|  | "Probing not supported",  // IPV6_SUPPORT_MAX | 
|  | }; | 
|  | COMPILE_ASSERT(arraysize(kFinalStatusNames) == IPV6_SUPPORT_MAX + 1, | 
|  | IPv6SupportStatus_name_count_mismatch); | 
|  |  | 
|  | // TODO(jar): The following is a simple estimate of IPv6 support.  We may need | 
|  | // to do a test resolution, and a test connection, to REALLY verify support. | 
|  | IPv6SupportResult TestIPv6SupportInternal() { | 
|  | #if defined(OS_STARBOARD) | 
|  | SbSocket test_socket = | 
|  | SbSocketCreate(kSbSocketAddressTypeIpv6, kSbSocketProtocolTcp); | 
|  | if (!SbSocketIsValid(test_socket)) { | 
|  | return IPv6SupportResult(false, IPV6_CANNOT_CREATE_SOCKETS, | 
|  | SbSystemGetLastError()); | 
|  | } | 
|  | SbSocketDestroy(test_socket); | 
|  | return IPv6SupportResult(true, IPV6_SUPPORT_MAX, 0); | 
|  | #elif defined(OS_ANDROID) || defined(__LB_ANDROID__) | 
|  | // TODO: We should fully implement IPv6 probe once 'getifaddrs' API available; | 
|  | // Another approach is implementing the similar feature by | 
|  | // java.net.NetworkInterface through JNI. | 
|  | NOTIMPLEMENTED(); | 
|  | return IPv6SupportResult(true, IPV6_SUPPORT_MAX, 0); | 
|  | #elif !defined(IN6ADDR_ANY_INIT) | 
|  | return IPv6SupportResult(false, IPV6_CANNOT_CREATE_SOCKETS, EAFNOSUPPORT); | 
|  | #elif defined(OS_POSIX) | 
|  | int test_socket = socket(AF_INET6, SOCK_STREAM, 0); | 
|  | if (test_socket == -1) | 
|  | return IPv6SupportResult(false, IPV6_CANNOT_CREATE_SOCKETS, errno); | 
|  | close(test_socket); | 
|  |  | 
|  | // Check to see if any interface has a IPv6 address. | 
|  | struct ifaddrs* interface_addr = NULL; | 
|  | int rv = getifaddrs(&interface_addr); | 
|  | if (rv != 0) { | 
|  | // Don't yet block IPv6. | 
|  | return IPv6SupportResult(true, IPV6_GETIFADDRS_FAILED, errno); | 
|  | } | 
|  |  | 
|  | bool found_ipv6 = false; | 
|  | for (struct ifaddrs* interface = interface_addr; | 
|  | interface != NULL; | 
|  | interface = interface->ifa_next) { | 
|  | if (!(IFF_UP & interface->ifa_flags)) | 
|  | continue; | 
|  | if (IFF_LOOPBACK & interface->ifa_flags) | 
|  | continue; | 
|  | struct sockaddr* addr = interface->ifa_addr; | 
|  | if (!addr) | 
|  | continue; | 
|  | if (addr->sa_family != AF_INET6) | 
|  | continue; | 
|  | // Safe cast since this is AF_INET6. | 
|  | struct sockaddr_in6* addr_in6 = | 
|  | reinterpret_cast<struct sockaddr_in6*>(addr); | 
|  | struct in6_addr* sin6_addr = &addr_in6->sin6_addr; | 
|  | if (IN6_IS_ADDR_LOOPBACK(sin6_addr) || IN6_IS_ADDR_LINKLOCAL(sin6_addr)) | 
|  | continue; | 
|  | found_ipv6 = true; | 
|  | break; | 
|  | } | 
|  | freeifaddrs(interface_addr); | 
|  | if (!found_ipv6) | 
|  | return IPv6SupportResult(false, IPV6_GLOBAL_ADDRESS_MISSING, 0); | 
|  |  | 
|  | return IPv6SupportResult(true, IPV6_GLOBAL_ADDRESS_PRESENT, 0); | 
|  | #elif defined(OS_WIN) | 
|  | EnsureWinsockInit(); | 
|  | SOCKET test_socket = socket(AF_INET6, SOCK_STREAM, 0); | 
|  | if (test_socket == INVALID_SOCKET) { | 
|  | return IPv6SupportResult(false, | 
|  | IPV6_CANNOT_CREATE_SOCKETS, | 
|  | WSAGetLastError()); | 
|  | } | 
|  | closesocket(test_socket); | 
|  |  | 
|  | // Check to see if any interface has a IPv6 address. | 
|  | // The GetAdaptersAddresses MSDN page recommends using a size of 15000 to | 
|  | // avoid reallocation. | 
|  | ULONG adapters_size = 15000; | 
|  | scoped_ptr_malloc<IP_ADAPTER_ADDRESSES> adapters; | 
|  | ULONG error; | 
|  | int num_tries = 0; | 
|  | do { | 
|  | adapters.reset( | 
|  | reinterpret_cast<PIP_ADAPTER_ADDRESSES>(malloc(adapters_size))); | 
|  | // Return only unicast addresses. | 
|  | error = GetAdaptersAddresses(AF_UNSPEC, | 
|  | GAA_FLAG_SKIP_ANYCAST | | 
|  | GAA_FLAG_SKIP_MULTICAST | | 
|  | GAA_FLAG_SKIP_DNS_SERVER | | 
|  | GAA_FLAG_SKIP_FRIENDLY_NAME, | 
|  | NULL, adapters.get(), &adapters_size); | 
|  | num_tries++; | 
|  | } while (error == ERROR_BUFFER_OVERFLOW && num_tries <= 3); | 
|  | if (error == ERROR_NO_DATA) | 
|  | return IPv6SupportResult(false, IPV6_GLOBAL_ADDRESS_MISSING, error); | 
|  | if (error != ERROR_SUCCESS) { | 
|  | // Don't yet block IPv6. | 
|  | return IPv6SupportResult(true, IPV6_GETIFADDRS_FAILED, error); | 
|  | } | 
|  |  | 
|  | PIP_ADAPTER_ADDRESSES adapter; | 
|  | for (adapter = adapters.get(); adapter; adapter = adapter->Next) { | 
|  | if (adapter->OperStatus != IfOperStatusUp) | 
|  | continue; | 
|  | if (adapter->IfType == IF_TYPE_SOFTWARE_LOOPBACK) | 
|  | continue; | 
|  | PIP_ADAPTER_UNICAST_ADDRESS unicast_address; | 
|  | for (unicast_address = adapter->FirstUnicastAddress; | 
|  | unicast_address; | 
|  | unicast_address = unicast_address->Next) { | 
|  | if (unicast_address->Address.lpSockaddr->sa_family != AF_INET6) | 
|  | continue; | 
|  | // Safe cast since this is AF_INET6. | 
|  | struct sockaddr_in6* addr_in6 = reinterpret_cast<struct sockaddr_in6*>( | 
|  | unicast_address->Address.lpSockaddr); | 
|  | struct in6_addr* sin6_addr = &addr_in6->sin6_addr; | 
|  | if (IN6_IS_ADDR_LOOPBACK(sin6_addr) || IN6_IS_ADDR_LINKLOCAL(sin6_addr)) | 
|  | continue; | 
|  | return IPv6SupportResult(true, IPV6_GLOBAL_ADDRESS_PRESENT, 0); | 
|  | } | 
|  | } | 
|  |  | 
|  | return IPv6SupportResult(false, IPV6_GLOBAL_ADDRESS_MISSING, 0); | 
|  | #else | 
|  | NOTIMPLEMENTED(); | 
|  | return IPv6SupportResult(true, IPV6_SUPPORT_MAX, 0); | 
|  | #endif  // defined(various platforms) | 
|  | } | 
|  |  | 
|  | }  // namespace | 
|  |  | 
|  | IPv6SupportResult::IPv6SupportResult(bool ipv6_supported, | 
|  | IPv6SupportStatus ipv6_support_status, | 
|  | int os_error) | 
|  | : ipv6_supported(ipv6_supported), | 
|  | ipv6_support_status(ipv6_support_status), | 
|  | os_error(os_error) { | 
|  | } | 
|  |  | 
|  | base::Value* IPv6SupportResult::ToNetLogValue( | 
|  | NetLog::LogLevel /* log_level */) const { | 
|  | base::DictionaryValue* dict = new DictionaryValue(); | 
|  | dict->SetBoolean("ipv6_supported", ipv6_supported); | 
|  | dict->SetString("ipv6_support_status", | 
|  | kFinalStatusNames[ipv6_support_status]); | 
|  | if (os_error) | 
|  | dict->SetInteger("os_error", os_error); | 
|  | return dict; | 
|  | } | 
|  |  | 
|  | IPv6SupportResult TestIPv6Support() { | 
|  | IPv6SupportResult result = TestIPv6SupportInternal(); | 
|  |  | 
|  | // Record UMA. | 
|  | if (result.ipv6_support_status != IPV6_SUPPORT_MAX) { | 
|  | static bool run_once = false; | 
|  | if (!run_once) { | 
|  | run_once = true; | 
|  | UMA_HISTOGRAM_ENUMERATION("Net.IPv6Status", | 
|  | result.ipv6_support_status, | 
|  | IPV6_SUPPORT_MAX); | 
|  | } else { | 
|  | UMA_HISTOGRAM_ENUMERATION("Net.IPv6Status_retest", | 
|  | result.ipv6_support_status, | 
|  | IPV6_SUPPORT_MAX); | 
|  | } | 
|  | } | 
|  | return result; | 
|  | } | 
|  |  | 
|  | bool HaveOnlyLoopbackAddresses() { | 
|  | #if defined(OS_ANDROID) | 
|  | return android::HaveOnlyLoopbackAddresses(); | 
|  | #elif defined(OS_POSIX) && !defined(__LB_SHELL__) | 
|  | struct ifaddrs* interface_addr = NULL; | 
|  | int rv = getifaddrs(&interface_addr); | 
|  | if (rv != 0) { | 
|  | DVLOG(1) << "getifaddrs() failed with errno = " << errno; | 
|  | return false; | 
|  | } | 
|  |  | 
|  | bool result = true; | 
|  | for (struct ifaddrs* interface = interface_addr; | 
|  | interface != NULL; | 
|  | interface = interface->ifa_next) { | 
|  | if (!(IFF_UP & interface->ifa_flags)) | 
|  | continue; | 
|  | if (IFF_LOOPBACK & interface->ifa_flags) | 
|  | continue; | 
|  | const struct sockaddr* addr = interface->ifa_addr; | 
|  | if (!addr) | 
|  | continue; | 
|  | if (addr->sa_family == AF_INET6) { | 
|  | // Safe cast since this is AF_INET6. | 
|  | const struct sockaddr_in6* addr_in6 = | 
|  | reinterpret_cast<const struct sockaddr_in6*>(addr); | 
|  | const struct in6_addr* sin6_addr = &addr_in6->sin6_addr; | 
|  | if (IN6_IS_ADDR_LOOPBACK(sin6_addr) || IN6_IS_ADDR_LINKLOCAL(sin6_addr)) | 
|  | continue; | 
|  | } | 
|  | if (addr->sa_family != AF_INET6 && addr->sa_family != AF_INET) | 
|  | continue; | 
|  |  | 
|  | result = false; | 
|  | break; | 
|  | } | 
|  | freeifaddrs(interface_addr); | 
|  | return result; | 
|  | #elif defined(OS_WIN) | 
|  | // TODO(wtc): implement with the GetAdaptersAddresses function. | 
|  | NOTIMPLEMENTED(); | 
|  | return false; | 
|  | #elif defined(__LB_SHELL__) || defined(OS_STARBOARD) | 
|  | return false; | 
|  | #else | 
|  | NOTIMPLEMENTED(); | 
|  | return false; | 
|  | #endif  // defined(various platforms) | 
|  | } | 
|  |  | 
|  | bool ParseIPLiteralToNumber(const std::string& ip_literal, | 
|  | IPAddressNumber* ip_number) { | 
|  | // |ip_literal| could be either a IPv4 or an IPv6 literal. If it contains | 
|  | // a colon however, it must be an IPv6 address. | 
|  | if (ip_literal.find(':') != std::string::npos) { | 
|  | // GURL expects IPv6 hostnames to be surrounded with brackets. | 
|  | std::string host_brackets = "[" + ip_literal + "]"; | 
|  | url_parse::Component host_comp(0, host_brackets.size()); | 
|  |  | 
|  | // Try parsing the hostname as an IPv6 literal. | 
|  | ip_number->resize(16);  // 128 bits. | 
|  | return url_canon::IPv6AddressToNumber(host_brackets.data(), | 
|  | host_comp, | 
|  | &(*ip_number)[0]); | 
|  | } | 
|  |  | 
|  | // Otherwise the string is an IPv4 address. | 
|  | ip_number->resize(4);  // 32 bits. | 
|  | url_parse::Component host_comp(0, ip_literal.size()); | 
|  | int num_components; | 
|  | url_canon::CanonHostInfo::Family family = url_canon::IPv4AddressToNumber( | 
|  | ip_literal.data(), host_comp, &(*ip_number)[0], &num_components); | 
|  | return family == url_canon::CanonHostInfo::IPV4; | 
|  | } | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | const unsigned char kIPv4MappedPrefix[] = | 
|  | { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF }; | 
|  | } | 
|  |  | 
|  | #if SB_HAS(IPV6) | 
|  | const unsigned char kIPv6Localhost[] = {0, 0, 0, 0, 0, 0, 0, 0, | 
|  | 0, 0, 0, 0, 0, 0, 0, 1}; | 
|  | #endif | 
|  |  | 
|  | IPAddressNumber ConvertIPv4NumberToIPv6Number( | 
|  | const IPAddressNumber& ipv4_number) { | 
|  | DCHECK(ipv4_number.size() == 4); | 
|  |  | 
|  | // IPv4-mapped addresses are formed by: | 
|  | // <80 bits of zeros>  + <16 bits of ones> + <32-bit IPv4 address>. | 
|  | IPAddressNumber ipv6_number; | 
|  | ipv6_number.reserve(16); | 
|  | ipv6_number.insert(ipv6_number.end(), | 
|  | kIPv4MappedPrefix, | 
|  | kIPv4MappedPrefix + arraysize(kIPv4MappedPrefix)); | 
|  | ipv6_number.insert(ipv6_number.end(), ipv4_number.begin(), ipv4_number.end()); | 
|  | return ipv6_number; | 
|  | } | 
|  |  | 
|  | bool IsIPv4Mapped(const IPAddressNumber& address) { | 
|  | if (address.size() != kIPv6AddressSize) | 
|  | return false; | 
|  | return std::equal(address.begin(), | 
|  | address.begin() + arraysize(kIPv4MappedPrefix), | 
|  | kIPv4MappedPrefix); | 
|  | } | 
|  |  | 
|  | IPAddressNumber ConvertIPv4MappedToIPv4(const IPAddressNumber& address) { | 
|  | DCHECK(IsIPv4Mapped(address)); | 
|  | return IPAddressNumber(address.begin() + arraysize(kIPv4MappedPrefix), | 
|  | address.end()); | 
|  | } | 
|  |  | 
|  | bool ParseCIDRBlock(const std::string& cidr_literal, | 
|  | IPAddressNumber* ip_number, | 
|  | size_t* prefix_length_in_bits) { | 
|  | // We expect CIDR notation to match one of these two templates: | 
|  | //   <IPv4-literal> "/" <number of bits> | 
|  | //   <IPv6-literal> "/" <number of bits> | 
|  |  | 
|  | std::vector<std::string> parts; | 
|  | base::SplitString(cidr_literal, '/', &parts); | 
|  | if (parts.size() != 2) | 
|  | return false; | 
|  |  | 
|  | // Parse the IP address. | 
|  | if (!ParseIPLiteralToNumber(parts[0], ip_number)) | 
|  | return false; | 
|  |  | 
|  | // Parse the prefix length. | 
|  | int number_of_bits = -1; | 
|  | if (!base::StringToInt(parts[1], &number_of_bits)) | 
|  | return false; | 
|  |  | 
|  | // Make sure the prefix length is in a valid range. | 
|  | if (number_of_bits < 0 || | 
|  | number_of_bits > static_cast<int>(ip_number->size() * 8)) | 
|  | return false; | 
|  |  | 
|  | *prefix_length_in_bits = static_cast<size_t>(number_of_bits); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool IPNumberMatchesPrefix(const IPAddressNumber& ip_number, | 
|  | const IPAddressNumber& ip_prefix, | 
|  | size_t prefix_length_in_bits) { | 
|  | // Both the input IP address and the prefix IP address should be | 
|  | // either IPv4 or IPv6. | 
|  | DCHECK(ip_number.size() == 4 || ip_number.size() == 16); | 
|  | DCHECK(ip_prefix.size() == 4 || ip_prefix.size() == 16); | 
|  |  | 
|  | DCHECK_LE(prefix_length_in_bits, ip_prefix.size() * 8); | 
|  |  | 
|  | // In case we have an IPv6 / IPv4 mismatch, convert the IPv4 addresses to | 
|  | // IPv6 addresses in order to do the comparison. | 
|  | if (ip_number.size() != ip_prefix.size()) { | 
|  | if (ip_number.size() == 4) { | 
|  | return IPNumberMatchesPrefix(ConvertIPv4NumberToIPv6Number(ip_number), | 
|  | ip_prefix, prefix_length_in_bits); | 
|  | } | 
|  | return IPNumberMatchesPrefix(ip_number, | 
|  | ConvertIPv4NumberToIPv6Number(ip_prefix), | 
|  | 96 + prefix_length_in_bits); | 
|  | } | 
|  |  | 
|  | // Otherwise we are comparing two IPv4 addresses, or two IPv6 addresses. | 
|  | // Compare all the bytes that fall entirely within the prefix. | 
|  | int num_entire_bytes_in_prefix = prefix_length_in_bits / 8; | 
|  | for (int i = 0; i < num_entire_bytes_in_prefix; ++i) { | 
|  | if (ip_number[i] != ip_prefix[i]) | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // In case the prefix was not a multiple of 8, there will be 1 byte | 
|  | // which is only partially masked. | 
|  | int remaining_bits = prefix_length_in_bits % 8; | 
|  | if (remaining_bits != 0) { | 
|  | unsigned char mask = 0xFF << (8 - remaining_bits); | 
|  | int i = num_entire_bytes_in_prefix; | 
|  | if ((ip_number[i] & mask) != (ip_prefix[i] & mask)) | 
|  | return false; | 
|  | } | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | #if !defined(OS_STARBOARD) | 
|  | const uint16* GetPortFieldFromSockaddr(const struct sockaddr* address, | 
|  | socklen_t address_len) { | 
|  | if (address->sa_family == AF_INET) { | 
|  | DCHECK_LE(sizeof(sockaddr_in), static_cast<size_t>(address_len)); | 
|  | const struct sockaddr_in* sockaddr = | 
|  | reinterpret_cast<const struct sockaddr_in*>(address); | 
|  | return &sockaddr->sin_port; | 
|  | #if defined(IN6ADDR_ANY_INIT) | 
|  | } else if (address->sa_family == AF_INET6) { | 
|  | DCHECK_LE(sizeof(sockaddr_in6), static_cast<size_t>(address_len)); | 
|  | const struct sockaddr_in6* sockaddr = | 
|  | reinterpret_cast<const struct sockaddr_in6*>(address); | 
|  | return &sockaddr->sin6_port; | 
|  | #endif | 
|  | } else { | 
|  | NOTREACHED(); | 
|  | return NULL; | 
|  | } | 
|  | } | 
|  |  | 
|  | int GetPortFromSockaddr(const struct sockaddr* address, socklen_t address_len) { | 
|  | const uint16* port_field = GetPortFieldFromSockaddr(address, address_len); | 
|  | if (!port_field) | 
|  | return -1; | 
|  | return base::NetToHost16(*port_field); | 
|  | } | 
|  | #endif | 
|  |  | 
|  | bool IsLocalhost(const std::string& host) { | 
|  | if (host == "localhost" || | 
|  | host == "localhost.localdomain" || | 
|  | host == "localhost6" || | 
|  | host == "localhost6.localdomain6") | 
|  | return true; | 
|  |  | 
|  | #if SB_HAS(IPV6) | 
|  | IPAddressNumber ipv6_localhost; | 
|  | ipv6_localhost.reserve(16); | 
|  | ipv6_localhost.insert(ipv6_localhost.end(), kIPv6Localhost, | 
|  | kIPv6Localhost + arraysize(kIPv6Localhost)); | 
|  | #endif | 
|  |  | 
|  | IPAddressNumber ip_number; | 
|  | if (ParseIPLiteralToNumber(host, &ip_number)) { | 
|  | size_t size = ip_number.size(); | 
|  | switch (size) { | 
|  | case kIPv4AddressSize: { | 
|  | IPAddressNumber localhost_prefix; | 
|  | localhost_prefix.push_back(127); | 
|  | for (int i = 0; i < 3; ++i) { | 
|  | localhost_prefix.push_back(0); | 
|  | } | 
|  | return IPNumberMatchesPrefix(ip_number, localhost_prefix, 8); | 
|  | } | 
|  |  | 
|  | #if SB_HAS(IPV6) | 
|  | case kIPv6AddressSize: { | 
|  | return ip_number == ipv6_localhost; | 
|  | } | 
|  | #endif | 
|  |  | 
|  | default: | 
|  | NOTREACHED(); | 
|  | } | 
|  | } | 
|  |  | 
|  | return false; | 
|  | } | 
|  |  | 
|  | NetworkInterface::NetworkInterface() { | 
|  | } | 
|  |  | 
|  | NetworkInterface::NetworkInterface(const std::string& name, | 
|  | const IPAddressNumber& address) | 
|  | : name(name), address(address) { | 
|  | } | 
|  |  | 
|  | NetworkInterface::~NetworkInterface() { | 
|  | } | 
|  |  | 
|  | }  // namespace net |