Added HostResolverImpl::fallback_to_proctask_ to vary according to AsyncDnsNoFallback group in AsynDns finch trial. Fixed use-after-delete issue.

patch from issue 16881005

BUG=224248
TEST=net_unittests --gtest_filter=HostResolverImplDnsTest.NoFallbackToProcTask
TEST=net_unittests --gtest_filter=HostResolverImplDnsTest.OnDnsTaskFailureAbortedJob

Review URL: https://chromiumcodereview.appspot.com/18136002

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@209054 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/net/dns/host_resolver_impl.cc b/net/dns/host_resolver_impl.cc
index 6c41181..25e5ded 100644
--- a/net/dns/host_resolver_impl.cc
+++ b/net/dns/host_resolver_impl.cc
@@ -243,6 +243,20 @@
                              base::TimeDelta::FromDays(1), 100);
 }
 
+bool ConfigureAsyncDnsNoFallbackFieldTrial() {
+  const bool kDefault = false;
+
+  // Configure the AsyncDns field trial as follows:
+  // groups AsyncDnsNoFallbackA and AsyncDnsNoFallbackB: return true,
+  // groups AsyncDnsA and AsyncDnsB: return false,
+  // groups SystemDnsA and SystemDnsB: return false,
+  // otherwise (trial absent): return default.
+  std::string group_name = base::FieldTrialList::FindFullName("AsyncDns");
+  if (!group_name.empty())
+    return StartsWithASCII(group_name, "AsyncDnsNoFallback", false);
+  return kDefault;
+}
+
 //-----------------------------------------------------------------------------
 
 AddressList EnsurePortOnAddressList(const AddressList& list, uint16 port) {
@@ -1475,19 +1489,60 @@
 
   void StartDnsTask() {
     DCHECK(resolver_->HaveDnsConfig());
+    base::TimeTicks start_time = base::TimeTicks::Now();
     dns_task_.reset(new DnsTask(
         resolver_->dns_client_.get(),
         key_,
-        base::Bind(&Job::OnDnsTaskComplete, base::Unretained(this),
-                   base::TimeTicks::Now()),
+        base::Bind(&Job::OnDnsTaskComplete, base::Unretained(this), start_time),
         net_log_));
 
     int rv = dns_task_->Start();
-    if (rv != ERR_IO_PENDING) {
-      DCHECK_NE(OK, rv);
+    if (rv == ERR_IO_PENDING)
+      return;  // Complete asynchronously.
+    DCHECK_NE(OK, rv);
+    base::TimeDelta duration = base::TimeTicks::Now() - start_time;
+    if (resolver_->fallback_to_proctask_) {
+      DNS_HISTOGRAM("AsyncDNS.ResolveFail", duration);
       dns_task_error_ = rv;
       dns_task_.reset();
       StartProcTask();
+    } else {
+      // We could be running within Resolve(), so make sure to complete
+      // asynchronously.
+      base::MessageLoopProxy::current()->PostTask(
+          FROM_HERE,
+          base::Bind(&Job::OnDnsTaskFailure,
+                     base::Unretained(this),
+                     dns_task_->AsWeakPtr(),
+                     duration,
+                     rv));
+    }
+  }
+
+  // Called if DnsTask fails. It is posted from StartDnsTask, so Job may be
+  // deleted before this callback. In this case dns_task is deleted as well,
+  // so we use it as indicator whether Job is still valid.
+  void OnDnsTaskFailure(const base::WeakPtr<DnsTask>& dns_task,
+                        base::TimeDelta duration,
+                        int net_error) {
+    DNS_HISTOGRAM("AsyncDNS.ResolveFail", duration);
+
+    if (dns_task == NULL)
+      return;
+
+    dns_task_error_ = net_error;
+
+    // TODO(szym): Run ServeFromHosts now if nsswitch.conf says so.
+    // http://crbug.com/117655
+
+    // TODO(szym): Some net errors indicate lack of connectivity. Starting
+    // ProcTask in that case is a waste of time.
+    if (resolver_->fallback_to_proctask_) {
+      dns_task_.reset();
+      StartProcTask();
+    } else {
+      UmaAsyncDnsResolveStatus(RESOLVE_STATUS_FAIL);
+      CompleteRequestsWithError(net_error);
     }
   }
 
@@ -1500,17 +1555,7 @@
 
     base::TimeDelta duration = base::TimeTicks::Now() - start_time;
     if (net_error != OK) {
-      DNS_HISTOGRAM("AsyncDNS.ResolveFail", duration);
-
-      dns_task_error_ = net_error;
-      dns_task_.reset();
-
-      // TODO(szym): Run ServeFromHosts now if nsswitch.conf says so.
-      // http://crbug.com/117655
-
-      // TODO(szym): Some net errors indicate lack of connectivity. Starting
-      // ProcTask in that case is a waste of time.
-      StartProcTask();
+      OnDnsTaskFailure(dns_task_->AsWeakPtr(), duration, net_error);
       return;
     }
     DNS_HISTOGRAM("AsyncDNS.ResolveSuccess", duration);
@@ -1704,7 +1749,8 @@
       num_dns_failures_(0),
       ipv6_probe_monitoring_(false),
       resolved_known_ipv6_hostname_(false),
-      additional_resolver_flags_(0) {
+      additional_resolver_flags_(0),
+      fallback_to_proctask_(true) {
 
   DCHECK_GE(dispatcher_.num_priorities(), static_cast<size_t>(NUM_PRIORITIES));
 
@@ -1734,6 +1780,8 @@
     NetworkChangeNotifier::GetDnsConfig(&dns_config);
     received_dns_config_ = dns_config.IsValid();
   }
+
+  fallback_to_proctask_ = !ConfigureAsyncDnsNoFallbackFieldTrial();
 }
 
 HostResolverImpl::~HostResolverImpl() {