[CDP] Detect `Page.navigate` download

Before this CL, navigating to a download URL yields "net::ERR_ABORTED",
and is impossible to distinguish from any other error.
To determine whether the error stems from a download,
one needs to wait for the `Browser.downloadWillBegin` event.
But since that can be emitted *after* `Page.navigate` returns,
this introduces unnecessary waiting.

To prevent this waiting, this CL adds a flag that
shows whether the navigation turned into a download.

Change-Id: I90d81d289df6621d0cdb977ba6ed7e7d74ee475e
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6696011
Commit-Queue: Yury Semikhatsky <yurys@chromium.org>
Reviewed-by: Maksim Sadym <sadym@chromium.org>
Reviewed-by: Andrey Kosyakov <caseq@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1487924}
diff --git a/AUTHORS b/AUTHORS
index 44d0bd6..2625532 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -1400,6 +1400,7 @@
 Simon Arlott <simon.arlott@gmail.com>
 Simon Cadman <simon@cadman.uk>
 Simon Jackson <simon.jackson@sonocent.com>
+Simon Knott <info@simonknott.de>
 Simon La Macchia <smacchia@amazon.com>
 Siva Kumar Gunturi <siva.gunturi@samsung.com>
 Slava Aseev <nullptrnine@gmail.com>
diff --git a/content/browser/devtools/protocol/page_handler.cc b/content/browser/devtools/protocol/page_handler.cc
index b95ac954..aa4e2dd 100644
--- a/content/browser/devtools/protocol/page_handler.cc
+++ b/content/browser/devtools/protocol/page_handler.cc
@@ -815,7 +815,8 @@
   // abort to DevTools anyway.
   if (!request->IsNavigationStarted()) {
     callback->sendSuccess(frame_id, std::nullopt,
-                          net::ErrorToString(net::ERR_ABORTED));
+                          net::ErrorToString(net::ERR_ABORTED),
+                          request->IsDownload());
     return;
   }
   std::optional<std::string> opt_error;
@@ -825,7 +826,8 @@
       request->IsSameDocument()
           ? std::optional<std::string>()
           : request->devtools_navigation_token().ToString();
-  callback->sendSuccess(frame_id, std::move(loader_id), std::move(opt_error));
+  callback->sendSuccess(frame_id, std::move(loader_id), std::move(opt_error),
+                        request->IsDownload());
 }
 
 }  // namespace
@@ -938,7 +940,7 @@
     return;
   if (!navigation_handle) {
     callback->sendSuccess(out_frame_id, std::nullopt,
-                          net::ErrorToString(net::ERR_ABORTED));
+                          net::ErrorToString(net::ERR_ABORTED), std::nullopt);
     return;
   }
   auto* navigation_request =
diff --git a/third_party/blink/public/devtools_protocol/browser_protocol.pdl b/third_party/blink/public/devtools_protocol/browser_protocol.pdl
index b36951d5..00c4263f 100644
--- a/third_party/blink/public/devtools_protocol/browser_protocol.pdl
+++ b/third_party/blink/public/devtools_protocol/browser_protocol.pdl
@@ -9452,6 +9452,8 @@
       optional Network.LoaderId loaderId
       # User friendly error message, present if and only if navigation has failed.
       optional string errorText
+      # Whether the navigation resulted in a download.
+      experimental optional boolean isDownload
 
   # Navigates current page to the given history entry.
   command navigateToHistoryEntry
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/page/navigate-204-expected.txt b/third_party/blink/web_tests/http/tests/inspector-protocol/page/navigate-204-expected.txt
index 80c99ba..de1012d 100644
--- a/third_party/blink/web_tests/http/tests/inspector-protocol/page/navigate-204-expected.txt
+++ b/third_party/blink/web_tests/http/tests/inspector-protocol/page/navigate-204-expected.txt
@@ -4,6 +4,7 @@
     result : {
         errorText : net::ERR_ABORTED
         frameId : <string>
+        isDownload : false
         loaderId : <string>
     }
     sessionId : <string>
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/page/navigate-attachment-expected.txt b/third_party/blink/web_tests/http/tests/inspector-protocol/page/navigate-attachment-expected.txt
new file mode 100644
index 0000000..6a010824
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/inspector-protocol/page/navigate-attachment-expected.txt
@@ -0,0 +1,12 @@
+Tests that Page.navigate returns isDownload when server responds with Content-Disposition: attachment.
+{
+    id : <number>
+    result : {
+        errorText : net::ERR_ABORTED
+        frameId : <string>
+        isDownload : true
+        loaderId : <string>
+    }
+    sessionId : <string>
+}
+
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/page/navigate-attachment.js b/third_party/blink/web_tests/http/tests/inspector-protocol/page/navigate-attachment.js
new file mode 100644
index 0000000..7024511
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/inspector-protocol/page/navigate-attachment.js
@@ -0,0 +1,9 @@
+(async function(/** @type {import('test_runner').TestRunner} */ testRunner) {
+  var {page, session, dp} = await testRunner.startBlank(
+      `Tests that Page.navigate returns isDownload when server responds with Content-Disposition: attachment.`);
+
+  await dp.Page.enable();
+  const response = await dp.Page.navigate({ url: testRunner.url('./resources/httpAttachment.php')});
+  testRunner.log(response);
+  testRunner.completeTest();
+})
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/page/resources/httpAttachment.php b/third_party/blink/web_tests/http/tests/inspector-protocol/page/resources/httpAttachment.php
new file mode 100644
index 0000000..7634d08
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/inspector-protocol/page/resources/httpAttachment.php
@@ -0,0 +1,5 @@
+<?php
+ob_start();
+header('Content-Disposition: attachment; filename="downloaded.txt"');
+?>
+foo bar baz
diff --git a/third_party/blink/web_tests/inspector-protocol/page/pageNavigateToFragment-expected.txt b/third_party/blink/web_tests/inspector-protocol/page/pageNavigateToFragment-expected.txt
index 138fe2a..f197826 100644
--- a/third_party/blink/web_tests/inspector-protocol/page/pageNavigateToFragment-expected.txt
+++ b/third_party/blink/web_tests/inspector-protocol/page/pageNavigateToFragment-expected.txt
@@ -3,6 +3,7 @@
     id : <number>
     result : {
         frameId : <string>
+        isDownload : false
         loaderId : <string>
     }
     sessionId : <string>
@@ -11,6 +12,7 @@
     id : <number>
     result : {
         frameId : <string>
+        isDownload : false
     }
     sessionId : <string>
 }