net_util_win.cc revision ddb351dbec246cf1fab5ec20d2d5520909041de1
14e7064fa7e344e8f87a5b8457e96dfdd252c4a9eArgyrios Kyrtzidis// Copyright (c) 2011 The Chromium Authors. All rights reserved.
24e7064fa7e344e8f87a5b8457e96dfdd252c4a9eArgyrios Kyrtzidis// Use of this source code is governed by a BSD-style license that can be
34e7064fa7e344e8f87a5b8457e96dfdd252c4a9eArgyrios Kyrtzidis// found in the LICENSE file.
44e7064fa7e344e8f87a5b8457e96dfdd252c4a9eArgyrios Kyrtzidis
54e7064fa7e344e8f87a5b8457e96dfdd252c4a9eArgyrios Kyrtzidis#include "net/base/net_util.h"
64e7064fa7e344e8f87a5b8457e96dfdd252c4a9eArgyrios Kyrtzidis
74e7064fa7e344e8f87a5b8457e96dfdd252c4a9eArgyrios Kyrtzidis#include <iphlpapi.h>
84e7064fa7e344e8f87a5b8457e96dfdd252c4a9eArgyrios Kyrtzidis
94e7064fa7e344e8f87a5b8457e96dfdd252c4a9eArgyrios Kyrtzidis#include <algorithm>
104e7064fa7e344e8f87a5b8457e96dfdd252c4a9eArgyrios Kyrtzidis
114e7064fa7e344e8f87a5b8457e96dfdd252c4a9eArgyrios Kyrtzidis#include "base/file_path.h"
124e7064fa7e344e8f87a5b8457e96dfdd252c4a9eArgyrios Kyrtzidis#include "base/memory/scoped_ptr.h"
134e7064fa7e344e8f87a5b8457e96dfdd252c4a9eArgyrios Kyrtzidis#include "base/string_piece.h"
144e7064fa7e344e8f87a5b8457e96dfdd252c4a9eArgyrios Kyrtzidis#include "base/string_util.h"
154e7064fa7e344e8f87a5b8457e96dfdd252c4a9eArgyrios Kyrtzidis#include "base/sys_string_conversions.h"
164e7064fa7e344e8f87a5b8457e96dfdd252c4a9eArgyrios Kyrtzidis#include "base/threading/thread_restrictions.h"
174e7064fa7e344e8f87a5b8457e96dfdd252c4a9eArgyrios Kyrtzidis#include "base/utf_string_conversions.h"
184e7064fa7e344e8f87a5b8457e96dfdd252c4a9eArgyrios Kyrtzidis#include "googleurl/src/gurl.h"
194e7064fa7e344e8f87a5b8457e96dfdd252c4a9eArgyrios Kyrtzidis#include "net/base/escape.h"
20dd93c596cd95e1b96031ff47efe0a5095ff3d7f1Argyrios Kyrtzidis#include "net/base/ip_endpoint.h"
214e7064fa7e344e8f87a5b8457e96dfdd252c4a9eArgyrios Kyrtzidis#include "net/base/net_errors.h"
224e7064fa7e344e8f87a5b8457e96dfdd252c4a9eArgyrios Kyrtzidis
234e7064fa7e344e8f87a5b8457e96dfdd252c4a9eArgyrios Kyrtzidisnamespace net {
244e7064fa7e344e8f87a5b8457e96dfdd252c4a9eArgyrios Kyrtzidis
25dd93c596cd95e1b96031ff47efe0a5095ff3d7f1Argyrios Kyrtzidisbool FileURLToFilePath(const GURL& url, FilePath* file_path) {
26dd93c596cd95e1b96031ff47efe0a5095ff3d7f1Argyrios Kyrtzidis  *file_path = FilePath();
27dd93c596cd95e1b96031ff47efe0a5095ff3d7f1Argyrios Kyrtzidis  std::wstring& file_path_str = const_cast<std::wstring&>(file_path->value());
28dd93c596cd95e1b96031ff47efe0a5095ff3d7f1Argyrios Kyrtzidis  file_path_str.clear();
29dd93c596cd95e1b96031ff47efe0a5095ff3d7f1Argyrios Kyrtzidis
30dd93c596cd95e1b96031ff47efe0a5095ff3d7f1Argyrios Kyrtzidis  if (!url.is_valid())
31dd93c596cd95e1b96031ff47efe0a5095ff3d7f1Argyrios Kyrtzidis    return false;
32dd93c596cd95e1b96031ff47efe0a5095ff3d7f1Argyrios Kyrtzidis
33dd93c596cd95e1b96031ff47efe0a5095ff3d7f1Argyrios Kyrtzidis  std::string path;
34dd93c596cd95e1b96031ff47efe0a5095ff3d7f1Argyrios Kyrtzidis  std::string host = url.host();
35dd93c596cd95e1b96031ff47efe0a5095ff3d7f1Argyrios Kyrtzidis  if (host.empty()) {
36dd93c596cd95e1b96031ff47efe0a5095ff3d7f1Argyrios Kyrtzidis    // URL contains no host, the path is the filename. In this case, the path
37dd93c596cd95e1b96031ff47efe0a5095ff3d7f1Argyrios Kyrtzidis    // will probably be preceeded with a slash, as in "/C:/foo.txt", so we
38dd93c596cd95e1b96031ff47efe0a5095ff3d7f1Argyrios Kyrtzidis    // trim out that here.
39dd93c596cd95e1b96031ff47efe0a5095ff3d7f1Argyrios Kyrtzidis    path = url.path();
40dd93c596cd95e1b96031ff47efe0a5095ff3d7f1Argyrios Kyrtzidis    size_t first_non_slash = path.find_first_not_of("/\\");
414e7064fa7e344e8f87a5b8457e96dfdd252c4a9eArgyrios Kyrtzidis    if (first_non_slash != std::string::npos && first_non_slash > 0)
424e7064fa7e344e8f87a5b8457e96dfdd252c4a9eArgyrios Kyrtzidis      path.erase(0, first_non_slash);
434e7064fa7e344e8f87a5b8457e96dfdd252c4a9eArgyrios Kyrtzidis  } else {
444e7064fa7e344e8f87a5b8457e96dfdd252c4a9eArgyrios Kyrtzidis    // URL contains a host: this means it's UNC. We keep the preceeding slash
454e7064fa7e344e8f87a5b8457e96dfdd252c4a9eArgyrios Kyrtzidis    // on the path.
464e7064fa7e344e8f87a5b8457e96dfdd252c4a9eArgyrios Kyrtzidis    path = "\\\\";
474e7064fa7e344e8f87a5b8457e96dfdd252c4a9eArgyrios Kyrtzidis    path.append(host);
48dd93c596cd95e1b96031ff47efe0a5095ff3d7f1Argyrios Kyrtzidis    path.append(url.path());
49dd93c596cd95e1b96031ff47efe0a5095ff3d7f1Argyrios Kyrtzidis  }
50dd93c596cd95e1b96031ff47efe0a5095ff3d7f1Argyrios Kyrtzidis
51dd93c596cd95e1b96031ff47efe0a5095ff3d7f1Argyrios Kyrtzidis  if (path.empty())
524e7064fa7e344e8f87a5b8457e96dfdd252c4a9eArgyrios Kyrtzidis    return false;
534e7064fa7e344e8f87a5b8457e96dfdd252c4a9eArgyrios Kyrtzidis  std::replace(path.begin(), path.end(), '/', '\\');
544e7064fa7e344e8f87a5b8457e96dfdd252c4a9eArgyrios Kyrtzidis
554e7064fa7e344e8f87a5b8457e96dfdd252c4a9eArgyrios Kyrtzidis  // GURL stores strings as percent-encoded UTF-8, this will undo if possible.
564e7064fa7e344e8f87a5b8457e96dfdd252c4a9eArgyrios Kyrtzidis  path = UnescapeURLComponent(path,
574e7064fa7e344e8f87a5b8457e96dfdd252c4a9eArgyrios Kyrtzidis      UnescapeRule::SPACES | UnescapeRule::URL_SPECIAL_CHARS);
584e7064fa7e344e8f87a5b8457e96dfdd252c4a9eArgyrios Kyrtzidis
594e7064fa7e344e8f87a5b8457e96dfdd252c4a9eArgyrios Kyrtzidis  if (!IsStringUTF8(path)) {
60dd93c596cd95e1b96031ff47efe0a5095ff3d7f1Argyrios Kyrtzidis    // Not UTF-8, assume encoding is native codepage and we're done. We know we
614e7064fa7e344e8f87a5b8457e96dfdd252c4a9eArgyrios Kyrtzidis    // are giving the conversion function a nonempty string, and it may fail if
624e7064fa7e344e8f87a5b8457e96dfdd252c4a9eArgyrios Kyrtzidis    // the given string is not in the current encoding and give us an empty
634e7064fa7e344e8f87a5b8457e96dfdd252c4a9eArgyrios Kyrtzidis    // string back. We detect this and report failure.
64dd93c596cd95e1b96031ff47efe0a5095ff3d7f1Argyrios Kyrtzidis    file_path_str = base::SysNativeMBToWide(path);
654e7064fa7e344e8f87a5b8457e96dfdd252c4a9eArgyrios Kyrtzidis    return !file_path_str.empty();
664e7064fa7e344e8f87a5b8457e96dfdd252c4a9eArgyrios Kyrtzidis  }
67dd93c596cd95e1b96031ff47efe0a5095ff3d7f1Argyrios Kyrtzidis  file_path_str.assign(UTF8ToWide(path));
68dd93c596cd95e1b96031ff47efe0a5095ff3d7f1Argyrios Kyrtzidis
69dd93c596cd95e1b96031ff47efe0a5095ff3d7f1Argyrios Kyrtzidis  // We used to try too hard and see if |path| made up entirely of
70dd93c596cd95e1b96031ff47efe0a5095ff3d7f1Argyrios Kyrtzidis  // the 1st 256 characters in the Unicode was a zero-extended UTF-16.
71dd93c596cd95e1b96031ff47efe0a5095ff3d7f1Argyrios Kyrtzidis  // If so, we converted it to 'Latin-1' and checked if the result was UTF-8.
72dd93c596cd95e1b96031ff47efe0a5095ff3d7f1Argyrios Kyrtzidis  // If the check passed, we converted the result to UTF-8.
73dd93c596cd95e1b96031ff47efe0a5095ff3d7f1Argyrios Kyrtzidis  // Otherwise, we treated the result as the native OS encoding.
74dd93c596cd95e1b96031ff47efe0a5095ff3d7f1Argyrios Kyrtzidis  // However, that led to http://crbug.com/4619 and http://crbug.com/14153
75dd93c596cd95e1b96031ff47efe0a5095ff3d7f1Argyrios Kyrtzidis  return true;
76dd93c596cd95e1b96031ff47efe0a5095ff3d7f1Argyrios Kyrtzidis}
774e7064fa7e344e8f87a5b8457e96dfdd252c4a9eArgyrios Kyrtzidis
784e7064fa7e344e8f87a5b8457e96dfdd252c4a9eArgyrios Kyrtzidisbool GetNetworkList(NetworkInterfaceList* networks) {
794e7064fa7e344e8f87a5b8457e96dfdd252c4a9eArgyrios Kyrtzidis  // GetAdaptersAddresses() may require IO operations.
804e7064fa7e344e8f87a5b8457e96dfdd252c4a9eArgyrios Kyrtzidis  base::ThreadRestrictions::AssertIOAllowed();
814e7064fa7e344e8f87a5b8457e96dfdd252c4a9eArgyrios Kyrtzidis
824e7064fa7e344e8f87a5b8457e96dfdd252c4a9eArgyrios Kyrtzidis  IP_ADAPTER_ADDRESSES info_temp;
834e7064fa7e344e8f87a5b8457e96dfdd252c4a9eArgyrios Kyrtzidis  ULONG len = 0;
844e7064fa7e344e8f87a5b8457e96dfdd252c4a9eArgyrios Kyrtzidis
854e7064fa7e344e8f87a5b8457e96dfdd252c4a9eArgyrios Kyrtzidis  // First get number of networks.
864e7064fa7e344e8f87a5b8457e96dfdd252c4a9eArgyrios Kyrtzidis  ULONG result = GetAdaptersAddresses(AF_UNSPEC, 0, NULL, &info_temp, &len);
874e7064fa7e344e8f87a5b8457e96dfdd252c4a9eArgyrios Kyrtzidis  if (result != ERROR_BUFFER_OVERFLOW) {
884e7064fa7e344e8f87a5b8457e96dfdd252c4a9eArgyrios Kyrtzidis    // There are 0 networks.
894e7064fa7e344e8f87a5b8457e96dfdd252c4a9eArgyrios Kyrtzidis    return true;
904e7064fa7e344e8f87a5b8457e96dfdd252c4a9eArgyrios Kyrtzidis  }
914e7064fa7e344e8f87a5b8457e96dfdd252c4a9eArgyrios Kyrtzidis
924e7064fa7e344e8f87a5b8457e96dfdd252c4a9eArgyrios Kyrtzidis  scoped_array<char> buf(new char[len]);
934e7064fa7e344e8f87a5b8457e96dfdd252c4a9eArgyrios Kyrtzidis  IP_ADAPTER_ADDRESSES *adapters =
94dd93c596cd95e1b96031ff47efe0a5095ff3d7f1Argyrios Kyrtzidis      reinterpret_cast<IP_ADAPTER_ADDRESSES *>(buf.get());
954e7064fa7e344e8f87a5b8457e96dfdd252c4a9eArgyrios Kyrtzidis  result = GetAdaptersAddresses(AF_UNSPEC, 0, NULL, adapters, &len);
964e7064fa7e344e8f87a5b8457e96dfdd252c4a9eArgyrios Kyrtzidis  if (result != NO_ERROR) {
974e7064fa7e344e8f87a5b8457e96dfdd252c4a9eArgyrios Kyrtzidis    LOG(ERROR) << "GetAdaptersAddresses failed: " << result;
984e7064fa7e344e8f87a5b8457e96dfdd252c4a9eArgyrios Kyrtzidis    return false;
994e7064fa7e344e8f87a5b8457e96dfdd252c4a9eArgyrios Kyrtzidis  }
100dd93c596cd95e1b96031ff47efe0a5095ff3d7f1Argyrios Kyrtzidis
101dd93c596cd95e1b96031ff47efe0a5095ff3d7f1Argyrios Kyrtzidis  for (IP_ADAPTER_ADDRESSES *adapter = adapters; adapter != NULL;
1024e7064fa7e344e8f87a5b8457e96dfdd252c4a9eArgyrios Kyrtzidis       adapter = adapter->Next) {
1034e7064fa7e344e8f87a5b8457e96dfdd252c4a9eArgyrios Kyrtzidis    // Ignore the loopback device.
1044e7064fa7e344e8f87a5b8457e96dfdd252c4a9eArgyrios Kyrtzidis    if (adapter->IfType == IF_TYPE_SOFTWARE_LOOPBACK) {
1054e7064fa7e344e8f87a5b8457e96dfdd252c4a9eArgyrios Kyrtzidis      continue;
1064e7064fa7e344e8f87a5b8457e96dfdd252c4a9eArgyrios Kyrtzidis    }
1074e7064fa7e344e8f87a5b8457e96dfdd252c4a9eArgyrios Kyrtzidis
1084e7064fa7e344e8f87a5b8457e96dfdd252c4a9eArgyrios Kyrtzidis    IP_ADAPTER_UNICAST_ADDRESS* address;
1094e7064fa7e344e8f87a5b8457e96dfdd252c4a9eArgyrios Kyrtzidis    for (address = adapter->FirstUnicastAddress; address != NULL;
1104e7064fa7e344e8f87a5b8457e96dfdd252c4a9eArgyrios Kyrtzidis         address = address->Next) {
1114e7064fa7e344e8f87a5b8457e96dfdd252c4a9eArgyrios Kyrtzidis      int family = address->Address.lpSockaddr->sa_family;
1124e7064fa7e344e8f87a5b8457e96dfdd252c4a9eArgyrios Kyrtzidis      if (family == AF_INET || family == AF_INET6) {
1134e7064fa7e344e8f87a5b8457e96dfdd252c4a9eArgyrios Kyrtzidis        IPEndPoint endpoint;
1144e7064fa7e344e8f87a5b8457e96dfdd252c4a9eArgyrios Kyrtzidis        if (endpoint.FromSockAddr(address->Address.lpSockaddr,
1154e7064fa7e344e8f87a5b8457e96dfdd252c4a9eArgyrios Kyrtzidis                                  address->Address.iSockaddrLength)) {
1164e7064fa7e344e8f87a5b8457e96dfdd252c4a9eArgyrios Kyrtzidis          std::string name = adapter->AdapterName;
1174e7064fa7e344e8f87a5b8457e96dfdd252c4a9eArgyrios Kyrtzidis          networks->push_back(NetworkInterface(name, endpoint.address()));
1184e7064fa7e344e8f87a5b8457e96dfdd252c4a9eArgyrios Kyrtzidis        }
1194e7064fa7e344e8f87a5b8457e96dfdd252c4a9eArgyrios Kyrtzidis      }
1204e7064fa7e344e8f87a5b8457e96dfdd252c4a9eArgyrios Kyrtzidis    }
1214e7064fa7e344e8f87a5b8457e96dfdd252c4a9eArgyrios Kyrtzidis  }
1224e7064fa7e344e8f87a5b8457e96dfdd252c4a9eArgyrios Kyrtzidis
1234e7064fa7e344e8f87a5b8457e96dfdd252c4a9eArgyrios Kyrtzidis  return true;
1244e7064fa7e344e8f87a5b8457e96dfdd252c4a9eArgyrios Kyrtzidis}
1254e7064fa7e344e8f87a5b8457e96dfdd252c4a9eArgyrios Kyrtzidis
1264e7064fa7e344e8f87a5b8457e96dfdd252c4a9eArgyrios Kyrtzidis}  // namespace net
1274e7064fa7e344e8f87a5b8457e96dfdd252c4a9eArgyrios Kyrtzidis