Moves the connected callback invocation to before stream initialization

As suggested in crrev.com/c/3545253, moving the `connected_callback_`
invocation in HttpNetworkTransaction can happen *before* DoInitStream()
is called, enabling the URLLoader::OnConnected() behavior to execute
without having to wait for stream initialization.

This CL moves the `connected_callback_` invocation to
DoCreateStreamComplete().  In order to do this, the HttpRequestInfo
object needs to be available to get the ACCEPT_CH frame payload (if
any), and currently it was only available when
HttpStream::InitializeStream() is called.  To solve this problem, we
introduce a new method to the HttpStream interface: RegisterRequest.
This separates request registration from stream initialization so we can
move the `connected_callback_` invocation to before DoInitStream().

In addition to a (perhaps slight) performance improvement, the
advantages of this are:
 - If the HTTP/2 or HTTP/3 session has hit its max stream limit, you no
   longer wait on a slot to be available (only to not use it!) first.
 - If there's a matching HTTP/2 push stream, you don't consume and discard
   it.
 - If 0-RTT over TCP is enabled (not launched) and this is a POST request,
   you no longer wait for handshake confirmation and can resolve ACCEPT_CH
   a hair sooner.

Bug: 1313781
Change-Id: I30ccf9473ce0798a409364b2ddad5e8fee2cfa74
Fixed: 1313781
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3573185
Reviewed-by: Titouan Rigoudy <[email protected]>
Reviewed-by: Matt Menke <[email protected]>
Commit-Queue: Ali Beyad <[email protected]>
Cr-Commit-Position: refs/heads/main@{#990556}
diff --git a/net/http/http_network_transaction.cc b/net/http/http_network_transaction.cc
index 72fafbd..d1494b8 100644
--- a/net/http/http_network_transaction.cc
+++ b/net/http/http_network_transaction.cc
@@ -378,7 +378,7 @@
       // Renewed streams shouldn't carry over sent or received bytes.
       DCHECK_EQ(0, new_stream->GetTotalReceivedBytes());
       DCHECK_EQ(0, new_stream->GetTotalSentBytes());
-      next_state_ = STATE_INIT_STREAM;
+      next_state_ = STATE_CONNECTED_CALLBACK;
     }
     stream_.reset(new_stream);
   }
@@ -738,6 +738,9 @@
       case STATE_INIT_STREAM_COMPLETE:
         rv = DoInitStreamComplete(rv);
         break;
+      case STATE_CONNECTED_CALLBACK:
+        rv = DoConnectedCallback();
+        break;
       case STATE_CONNECTED_CALLBACK_COMPLETE:
         rv = DoConnectedCallbackComplete(rv);
         break;
@@ -857,7 +860,7 @@
 int HttpNetworkTransaction::DoCreateStreamComplete(int result) {
   CopyConnectionAttemptsFromStreamRequest();
   if (result == OK) {
-    next_state_ = STATE_INIT_STREAM;
+    next_state_ = STATE_CONNECTED_CALLBACK;
     DCHECK(stream_.get());
   } else if (result == ERR_HTTP_1_1_REQUIRED ||
              result == ERR_PROXY_HTTP_1_1_REQUIRED) {
@@ -877,10 +880,8 @@
   DCHECK(stream_.get());
   next_state_ = STATE_INIT_STREAM_COMPLETE;
 
-  stream_->GetRemoteEndpoint(&remote_endpoint_);
-
-  return stream_->InitializeStream(request_, can_send_early_data_, priority_,
-                                   net_log_, io_callback_);
+  return stream_->InitializeStream(can_send_early_data_, priority_, net_log_,
+                                   io_callback_);
 }
 
 int HttpNetworkTransaction::DoInitStreamComplete(int result) {
@@ -898,22 +899,33 @@
     return result;
   }
 
+  next_state_ = STATE_GENERATE_PROXY_AUTH_TOKEN;
+  return result;
+}
+
+int HttpNetworkTransaction::DoConnectedCallback() {
+  // Register the HttpRequestInfo object on the stream here so that it's
+  // available when invoking the `connected_callback_`, as
+  // HttpStream::GetAcceptChViaAlps() needs the HttpRequestInfo to retrieve
+  // the ACCEPT_CH frame payload.
+  stream_->RegisterRequest(request_);
+  stream_->GetRemoteEndpoint(&remote_endpoint_);
   next_state_ = STATE_CONNECTED_CALLBACK_COMPLETE;
 
-  // Fire off notification that we have successfully connected.
-  if (!connected_callback_.is_null()) {
-    TransportType type = TransportType::kDirect;
-    if (!proxy_info_.is_direct()) {
-      type = TransportType::kProxied;
-    }
-    result = connected_callback_.Run(
-        TransportInfo(type, remote_endpoint_,
-                      std::string(stream_->GetAcceptChViaAlps())),
-        base::BindOnce(&HttpNetworkTransaction::ResumeAfterConnected,
-                       base::Unretained(this)));
+  if (connected_callback_.is_null()) {
+    return OK;
   }
 
-  return result;
+  // Fire off notification that we have successfully connected.
+  TransportType type = TransportType::kDirect;
+  if (!proxy_info_.is_direct()) {
+    type = TransportType::kProxied;
+  }
+  return connected_callback_.Run(
+      TransportInfo(type, remote_endpoint_,
+                    std::string{stream_->GetAcceptChViaAlps()}),
+      base::BindOnce(&HttpNetworkTransaction::ResumeAfterConnected,
+                     base::Unretained(this)));
 }
 
 int HttpNetworkTransaction::DoConnectedCallbackComplete(int result) {
@@ -926,7 +938,7 @@
     return result;
   }
 
-  next_state_ = STATE_GENERATE_PROXY_AUTH_TOKEN;
+  next_state_ = STATE_INIT_STREAM;
   return OK;
 }