Add support for NetErrorDetails to Cronet's BidirectionalStream

This plumbs the quic error information through to Cronet's
BidirectionalStream::OnError

Bug: 624942
Cq-Include-Trybots: master.tryserver.chromium.android:android_cronet_tester
Change-Id: I7debf4c530cc9fba4a8fe5c62808afa582e6428e
Reviewed-on: https://chromium-review.googlesource.com/567282
Reviewed-by: Misha Efimov <[email protected]>
Commit-Queue: Brad Lassey <[email protected]>
Cr-Commit-Position: refs/heads/master@{#487690}
diff --git a/components/cronet/android/cronet_bidirectional_stream_adapter.cc b/components/cronet/android/cronet_bidirectional_stream_adapter.cc
index 104cb43..74e7d84c 100644
--- a/components/cronet/android/cronet_bidirectional_stream_adapter.cc
+++ b/components/cronet/android/cronet_bidirectional_stream_adapter.cc
@@ -322,10 +322,11 @@
   DCHECK(context_->IsOnNetworkThread());
   stream_failed_ = true;
   JNIEnv* env = base::android::AttachCurrentThread();
-  // TODO(mgersh): Add support for NetErrorDetails (http://crbug.com/624942)
+  net::NetErrorDetails net_error_details;
+  bidi_stream_->PopulateNetErrorDetails(&net_error_details);
   cronet::Java_CronetBidirectionalStream_onError(
       env, owner_.obj(), NetErrorToUrlRequestError(error), error,
-      net::QUIC_NO_ERROR,
+      net_error_details.quic_connection_error,
       ConvertUTF8ToJavaString(env, net::ErrorToString(error)).obj(),
       bidi_stream_->GetTotalReceivedBytes());
 }
diff --git a/components/cronet/android/test/javatests/src/org/chromium/net/BidirectionalStreamQuicTest.java b/components/cronet/android/test/javatests/src/org/chromium/net/BidirectionalStreamQuicTest.java
index 28f6612..5ff68b4 100644
--- a/components/cronet/android/test/javatests/src/org/chromium/net/BidirectionalStreamQuicTest.java
+++ b/components/cronet/android/test/javatests/src/org/chromium/net/BidirectionalStreamQuicTest.java
@@ -334,6 +334,11 @@
         NetworkException networkError = (NetworkException) callback.mError;
         assertTrue(NetError.ERR_QUIC_PROTOCOL_ERROR == networkError.getCronetInternalErrorCode()
                 || NetError.ERR_CONNECTION_REFUSED == networkError.getCronetInternalErrorCode());
+        if (NetError.ERR_CONNECTION_REFUSED == networkError.getCronetInternalErrorCode()) return;
+        assertTrue(callback.mError instanceof QuicException);
+        QuicException quicException = (QuicException) callback.mError;
+        // 16 is QUIC_PEER_GOING_AWAY
+        assertEquals(16, quicException.getQuicDetailedErrorCode());
     }
 
     @SmallTest
diff --git a/net/http/bidirectional_stream.cc b/net/http/bidirectional_stream.cc
index dbd25301..176f140 100644
--- a/net/http/bidirectional_stream.cc
+++ b/net/http/bidirectional_stream.cc
@@ -213,6 +213,12 @@
   *load_timing_info = load_timing_info_;
 }
 
+void BidirectionalStream::PopulateNetErrorDetails(NetErrorDetails* details) {
+  DCHECK(details);
+  if (stream_impl_)
+    stream_impl_->PopulateNetErrorDetails(details);
+}
+
 void BidirectionalStream::OnStreamReady(bool request_headers_sent) {
   request_headers_sent_ = request_headers_sent;
   if (net_log_.IsCapturing()) {
diff --git a/net/http/bidirectional_stream.h b/net/http/bidirectional_stream.h
index e72e7fe4..043ce80b 100644
--- a/net/http/bidirectional_stream.h
+++ b/net/http/bidirectional_stream.h
@@ -31,6 +31,7 @@
 class ProxyInfo;
 class SpdyHeaderBlock;
 struct BidirectionalStreamRequestInfo;
+struct NetErrorDetails;
 struct SSLConfig;
 
 // A class to do HTTP/2 bidirectional streaming. Note that at most one each of
@@ -170,6 +171,11 @@
   // Gets LoadTimingInfo of this stream.
   void GetLoadTimingInfo(LoadTimingInfo* load_timing_info) const;
 
+  // Get the network error details this stream is encountering.
+  // Fills in |details| if it is available; leaves |details| unchanged if it
+  // is unavailable.
+  void PopulateNetErrorDetails(NetErrorDetails* details);
+
  private:
   // BidirectionalStreamImpl::Delegate implementation:
   void OnStreamReady(bool request_headers_sent) override;
diff --git a/net/http/bidirectional_stream_impl.h b/net/http/bidirectional_stream_impl.h
index 9b5ffab7..b5228f25 100644
--- a/net/http/bidirectional_stream_impl.h
+++ b/net/http/bidirectional_stream_impl.h
@@ -26,6 +26,7 @@
 class NetLogWithSource;
 class SpdyHeaderBlock;
 struct BidirectionalStreamRequestInfo;
+struct NetErrorDetails;
 
 // Exposes an interface to do HTTP/2 bidirectional streaming.
 // Note that only one ReadData or SendData should be in flight until the
@@ -152,6 +153,11 @@
   // and false otherwise.
   virtual bool GetLoadTimingInfo(LoadTimingInfo* load_timing_info) const = 0;
 
+  // Get the network error details this stream is encountering.
+  // Fills in |details| if it is available; leaves |details| unchanged if it
+  // is unavailable.
+  virtual void PopulateNetErrorDetails(NetErrorDetails* details) = 0;
+
  private:
   DISALLOW_COPY_AND_ASSIGN(BidirectionalStreamImpl);
 };
diff --git a/net/quic/chromium/bidirectional_stream_quic_impl.cc b/net/quic/chromium/bidirectional_stream_quic_impl.cc
index c10720d5..648056a 100644
--- a/net/quic/chromium/bidirectional_stream_quic_impl.cc
+++ b/net/quic/chromium/bidirectional_stream_quic_impl.cc
@@ -17,6 +17,7 @@
 #include "net/socket/next_proto.h"
 #include "net/spdy/chromium/spdy_http_utils.h"
 #include "net/spdy/core/spdy_header_block.h"
+#include "quic_http_stream.h"
 
 namespace net {
 namespace {
@@ -226,6 +227,16 @@
   return true;
 }
 
+void BidirectionalStreamQuicImpl::PopulateNetErrorDetails(
+    NetErrorDetails* details) {
+  DCHECK(details);
+  details->connection_info =
+      QuicHttpStream::ConnectionInfoFromQuicVersion(session_->GetQuicVersion());
+  session_->PopulateNetErrorDetails(details);
+  if (session_->IsCryptoHandshakeConfirmed() && stream_)
+    details->quic_connection_error = stream_->connection_error();
+}
+
 void BidirectionalStreamQuicImpl::OnStreamReady(int rv) {
   DCHECK_NE(ERR_IO_PENDING, rv);
   DCHECK(!stream_);
diff --git a/net/quic/chromium/bidirectional_stream_quic_impl.h b/net/quic/chromium/bidirectional_stream_quic_impl.h
index 8ec93aee..8b63600bd 100644
--- a/net/quic/chromium/bidirectional_stream_quic_impl.h
+++ b/net/quic/chromium/bidirectional_stream_quic_impl.h
@@ -51,6 +51,7 @@
   int64_t GetTotalReceivedBytes() const override;
   int64_t GetTotalSentBytes() const override;
   bool GetLoadTimingInfo(LoadTimingInfo* load_timing_info) const override;
+  void PopulateNetErrorDetails(NetErrorDetails* details) override;
 
  private:
   int WriteHeaders();
diff --git a/net/spdy/chromium/bidirectional_stream_spdy_impl.cc b/net/spdy/chromium/bidirectional_stream_spdy_impl.cc
index fa223bb4..616f1673 100644
--- a/net/spdy/chromium/bidirectional_stream_spdy_impl.cc
+++ b/net/spdy/chromium/bidirectional_stream_spdy_impl.cc
@@ -193,6 +193,9 @@
   return stream_->GetLoadTimingInfo(load_timing_info);
 }
 
+void BidirectionalStreamSpdyImpl::PopulateNetErrorDetails(
+    NetErrorDetails* details) {}
+
 void BidirectionalStreamSpdyImpl::OnHeadersSent() {
   DCHECK(stream_);
 
diff --git a/net/spdy/chromium/bidirectional_stream_spdy_impl.h b/net/spdy/chromium/bidirectional_stream_spdy_impl.h
index 61e00e0..c4c11ed 100644
--- a/net/spdy/chromium/bidirectional_stream_spdy_impl.h
+++ b/net/spdy/chromium/bidirectional_stream_spdy_impl.h
@@ -57,6 +57,7 @@
   int64_t GetTotalReceivedBytes() const override;
   int64_t GetTotalSentBytes() const override;
   bool GetLoadTimingInfo(LoadTimingInfo* load_timing_info) const override;
+  void PopulateNetErrorDetails(NetErrorDetails* details) override;
 
   // SpdyStream::Delegate implementation:
   void OnHeadersSent() override;