Home | History | Annotate | Download | only in proxy
      1 // Copyright (c) 2010 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "net/proxy/proxy_resolver_js_bindings.h"
      6 
      7 #include "base/logging.h"
      8 #include "base/string_util.h"
      9 #include "base/values.h"
     10 #include "net/base/address_list.h"
     11 #include "net/base/host_cache.h"
     12 #include "net/base/host_resolver.h"
     13 #include "net/base/net_errors.h"
     14 #include "net/base/net_log.h"
     15 #include "net/base/net_util.h"
     16 #include "net/base/sys_addrinfo.h"
     17 #include "net/proxy/proxy_resolver_request_context.h"
     18 
     19 namespace net {
     20 
     21 namespace {
     22 
     23 // Event parameters for a PAC error message (line number + message).
     24 class ErrorNetlogParams : public NetLog::EventParameters {
     25  public:
     26   ErrorNetlogParams(int line_number,
     27                     const string16& message)
     28       : line_number_(line_number),
     29         message_(message) {
     30   }
     31 
     32   virtual Value* ToValue() const {
     33     DictionaryValue* dict = new DictionaryValue();
     34     dict->SetInteger("line_number", line_number_);
     35     dict->SetString("message", message_);
     36     return dict;
     37   }
     38 
     39  private:
     40   const int line_number_;
     41   const string16 message_;
     42 
     43   DISALLOW_COPY_AND_ASSIGN(ErrorNetlogParams);
     44 };
     45 
     46 // Event parameters for a PAC alert().
     47 class AlertNetlogParams : public NetLog::EventParameters {
     48  public:
     49   explicit AlertNetlogParams(const string16& message) : message_(message) {
     50   }
     51 
     52   virtual Value* ToValue() const {
     53     DictionaryValue* dict = new DictionaryValue();
     54     dict->SetString("message", message_);
     55     return dict;
     56   }
     57 
     58  private:
     59   const string16 message_;
     60 
     61   DISALLOW_COPY_AND_ASSIGN(AlertNetlogParams);
     62 };
     63 
     64 // ProxyResolverJSBindings implementation.
     65 class DefaultJSBindings : public ProxyResolverJSBindings {
     66  public:
     67   DefaultJSBindings(HostResolver* host_resolver, NetLog* net_log)
     68       : host_resolver_(host_resolver),
     69         net_log_(net_log) {
     70   }
     71 
     72   // Handler for "alert(message)".
     73   virtual void Alert(const string16& message) {
     74     VLOG(1) << "PAC-alert: " << message;
     75 
     76     // Send to the NetLog.
     77     LogEventToCurrentRequestAndGlobally(NetLog::TYPE_PAC_JAVASCRIPT_ALERT,
     78                                         new AlertNetlogParams(message));
     79   }
     80 
     81   // Handler for "myIpAddress()".
     82   // TODO(eroman): Perhaps enumerate the interfaces directly, using
     83   // getifaddrs().
     84   virtual bool MyIpAddress(std::string* first_ip_address) {
     85     LogEventToCurrentRequest(NetLog::PHASE_BEGIN,
     86                              NetLog::TYPE_PAC_JAVASCRIPT_MY_IP_ADDRESS,
     87                              NULL);
     88 
     89     bool ok = MyIpAddressImpl(first_ip_address);
     90 
     91     LogEventToCurrentRequest(NetLog::PHASE_END,
     92                              NetLog::TYPE_PAC_JAVASCRIPT_MY_IP_ADDRESS,
     93                              NULL);
     94     return ok;
     95   }
     96 
     97   // Handler for "myIpAddressEx()".
     98   virtual bool MyIpAddressEx(std::string* ip_address_list) {
     99     LogEventToCurrentRequest(NetLog::PHASE_BEGIN,
    100                              NetLog::TYPE_PAC_JAVASCRIPT_MY_IP_ADDRESS_EX,
    101                              NULL);
    102 
    103     bool ok = MyIpAddressExImpl(ip_address_list);
    104 
    105     LogEventToCurrentRequest(NetLog::PHASE_END,
    106                              NetLog::TYPE_PAC_JAVASCRIPT_MY_IP_ADDRESS_EX,
    107                              NULL);
    108     return ok;
    109   }
    110 
    111   // Handler for "dnsResolve(host)".
    112   virtual bool DnsResolve(const std::string& host,
    113                           std::string* first_ip_address) {
    114     LogEventToCurrentRequest(NetLog::PHASE_BEGIN,
    115                              NetLog::TYPE_PAC_JAVASCRIPT_DNS_RESOLVE,
    116                              NULL);
    117 
    118     bool ok = DnsResolveImpl(host, first_ip_address);
    119 
    120     LogEventToCurrentRequest(NetLog::PHASE_END,
    121                              NetLog::TYPE_PAC_JAVASCRIPT_DNS_RESOLVE,
    122                              NULL);
    123     return ok;
    124   }
    125 
    126   // Handler for "dnsResolveEx(host)".
    127   virtual bool DnsResolveEx(const std::string& host,
    128                             std::string* ip_address_list) {
    129     LogEventToCurrentRequest(NetLog::PHASE_BEGIN,
    130                              NetLog::TYPE_PAC_JAVASCRIPT_DNS_RESOLVE_EX,
    131                              NULL);
    132 
    133     bool ok = DnsResolveExImpl(host, ip_address_list);
    134 
    135     LogEventToCurrentRequest(NetLog::PHASE_END,
    136                              NetLog::TYPE_PAC_JAVASCRIPT_DNS_RESOLVE_EX,
    137                              NULL);
    138     return ok;
    139   }
    140 
    141   // Handler for when an error is encountered. |line_number| may be -1.
    142   virtual void OnError(int line_number, const string16& message) {
    143     // Send to the chrome log.
    144     if (line_number == -1)
    145       VLOG(1) << "PAC-error: " << message;
    146     else
    147       VLOG(1) << "PAC-error: " << "line: " << line_number << ": " << message;
    148 
    149     // Send the error to the NetLog.
    150     LogEventToCurrentRequestAndGlobally(
    151         NetLog::TYPE_PAC_JAVASCRIPT_ERROR,
    152         new ErrorNetlogParams(line_number, message));
    153   }
    154 
    155   virtual void Shutdown() {
    156     host_resolver_->Shutdown();
    157   }
    158 
    159  private:
    160   bool MyIpAddressImpl(std::string* first_ip_address) {
    161     std::string my_hostname = GetHostName();
    162     if (my_hostname.empty())
    163       return false;
    164     return DnsResolveImpl(my_hostname, first_ip_address);
    165   }
    166 
    167   bool MyIpAddressExImpl(std::string* ip_address_list) {
    168     std::string my_hostname = GetHostName();
    169     if (my_hostname.empty())
    170       return false;
    171     return DnsResolveExImpl(my_hostname, ip_address_list);
    172   }
    173 
    174   bool DnsResolveImpl(const std::string& host,
    175                       std::string* first_ip_address) {
    176     // Do a sync resolve of the hostname (port doesn't matter).
    177     // Disable IPv6 results. We do this because the PAC specification isn't
    178     // really IPv6 friendly, and Internet Explorer also restricts to IPv4.
    179     // Consequently a lot of existing PAC scripts assume they will only get
    180     // IPv4 results, and will misbehave if they get an IPv6 result.
    181     // See http://crbug.com/24641 for more details.
    182     HostResolver::RequestInfo info(HostPortPair(host, 80));
    183     info.set_address_family(ADDRESS_FAMILY_IPV4);
    184     AddressList address_list;
    185 
    186     int result = DnsResolveHelper(info, &address_list);
    187     if (result != OK)
    188       return false;
    189 
    190     // There may be multiple results; we will just use the first one.
    191     // This returns empty string on failure.
    192     *first_ip_address = net::NetAddressToString(address_list.head());
    193     if (first_ip_address->empty())
    194       return false;
    195 
    196     return true;
    197   }
    198 
    199   bool DnsResolveExImpl(const std::string& host,
    200                         std::string* ip_address_list) {
    201     // Do a sync resolve of the hostname (port doesn't matter).
    202     HostResolver::RequestInfo info(HostPortPair(host, 80));
    203     AddressList address_list;
    204     int result = DnsResolveHelper(info, &address_list);
    205 
    206     if (result != OK)
    207       return false;
    208 
    209     // Stringify all of the addresses in the address list, separated
    210     // by semicolons.
    211     std::string address_list_str;
    212     const struct addrinfo* current_address = address_list.head();
    213     while (current_address) {
    214       if (!address_list_str.empty())
    215         address_list_str += ";";
    216       const std::string address_string = NetAddressToString(current_address);
    217       if (address_string.empty())
    218         return false;
    219       address_list_str += address_string;
    220       current_address = current_address->ai_next;
    221     }
    222 
    223     *ip_address_list = address_list_str;
    224     return true;
    225   }
    226 
    227   // Helper to execute a synchronous DNS resolve, using the per-request
    228   // DNS cache if there is one.
    229   int DnsResolveHelper(const HostResolver::RequestInfo& info,
    230                        AddressList* address_list) {
    231     HostCache::Key cache_key(info.hostname(),
    232                              info.address_family(),
    233                              info.host_resolver_flags());
    234 
    235     HostCache* host_cache = current_request_context() ?
    236         current_request_context()->host_cache : NULL;
    237 
    238     // First try to service this request from the per-request DNS cache.
    239     // (we cache DNS failures much more aggressively within the context
    240     // of a FindProxyForURL() request).
    241     if (host_cache) {
    242       const HostCache::Entry* entry =
    243           host_cache->Lookup(cache_key, base::TimeTicks::Now());
    244       if (entry) {
    245         if (entry->error == OK)
    246           *address_list = entry->addrlist;
    247         return entry->error;
    248       }
    249     }
    250 
    251     // Otherwise ask the resolver.
    252     int result = host_resolver_->Resolve(info, address_list, NULL, NULL,
    253                                          BoundNetLog());
    254 
    255     // Save the result back to the per-request DNS cache.
    256     if (host_cache) {
    257       host_cache->Set(cache_key, result, *address_list,
    258                       base::TimeTicks::Now());
    259     }
    260 
    261     return result;
    262   }
    263 
    264   void LogEventToCurrentRequest(
    265       NetLog::EventPhase phase,
    266       NetLog::EventType type,
    267       scoped_refptr<NetLog::EventParameters> params) {
    268     if (current_request_context() && current_request_context()->net_log)
    269       current_request_context()->net_log->AddEntry(type, phase, params);
    270   }
    271 
    272   void LogEventToCurrentRequestAndGlobally(
    273       NetLog::EventType type,
    274       scoped_refptr<NetLog::EventParameters> params) {
    275     LogEventToCurrentRequest(NetLog::PHASE_NONE, type, params);
    276 
    277     // Emit to the global NetLog event stream.
    278     if (net_log_) {
    279       net_log_->AddEntry(
    280           type,
    281           base::TimeTicks::Now(),
    282           NetLog::Source(),
    283           NetLog::PHASE_NONE,
    284           params);
    285     }
    286   }
    287 
    288   HostResolver* const host_resolver_;
    289   NetLog* net_log_;
    290 };
    291 
    292 }  // namespace
    293 
    294 // static
    295 ProxyResolverJSBindings* ProxyResolverJSBindings::CreateDefault(
    296     HostResolver* host_resolver, NetLog* net_log) {
    297   return new DefaultJSBindings(host_resolver, net_log);
    298 }
    299 
    300 }  // namespace net
    301