Commit 10311d71 authored by John Abd-El-Malek's avatar John Abd-El-Malek Committed by Commit Bot

Add a way for embedders to know if a navigation failed because it became a download.

Bug: 1025603
Change-Id: I48762b17e485ba636e880525dfda63324955330c
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2202963
Commit-Queue: John Abd-El-Malek <jam@chromium.org>
Auto-Submit: John Abd-El-Malek <jam@chromium.org>
Reviewed-by: default avatarScott Violet <sky@chromium.org>
Cr-Commit-Position: refs/heads/master@{#769046}
parent f7c5c6d8
......@@ -133,6 +133,13 @@ public final class NavigationImpl extends INavigation.Stub {
}
}
@Override
public boolean isDownload() {
StrictModeWorkaround.apply();
throwIfNativeDestroyed();
return NavigationImplJni.get().isDownload(mNativeNavigationImpl);
}
private void throwIfNativeDestroyed() {
if (mNativeNavigationImpl == 0) {
throw new IllegalStateException("Using Navigation after native destroyed");
......@@ -174,6 +181,7 @@ public final class NavigationImpl extends INavigation.Stub {
int getHttpStatusCode(long nativeNavigationImpl);
boolean isSameDocument(long nativeNavigationImpl);
boolean isErrorPage(long nativeNavigationImpl);
boolean isDownload(long nativeNavigationImpl);
int getLoadError(long nativeNavigationImpl);
boolean setRequestHeader(long nativeNavigationImpl, String name, String value);
boolean isValidRequestHeaderName(String name);
......
......@@ -25,4 +25,6 @@ interface INavigation {
void setRequestHeader(in String name, in String value) = 7;
void setUserAgentString(in String value) = 8;
boolean isDownload() = 9;
}
......@@ -94,6 +94,7 @@ class OneShotNavigationObserver : public NavigationObserver {
bool completed() { return completed_; }
bool is_error_page() { return is_error_page_; }
bool is_download() { return is_download_; }
Navigation::LoadError load_error() { return load_error_; }
int http_status_code() { return http_status_code_; }
NavigationState navigation_state() { return navigation_state_; }
......@@ -109,6 +110,7 @@ class OneShotNavigationObserver : public NavigationObserver {
void Finish(Navigation* navigation) {
is_error_page_ = navigation->IsErrorPage();
is_download_ = navigation->IsDownload();
load_error_ = navigation->GetLoadError();
http_status_code_ = navigation->GetHttpStatusCode();
navigation_state_ = navigation->GetState();
......@@ -119,6 +121,7 @@ class OneShotNavigationObserver : public NavigationObserver {
Tab* tab_;
bool completed_ = false;
bool is_error_page_ = false;
bool is_download_ = false;
Navigation::LoadError load_error_ = Navigation::kNoError;
int http_status_code_ = 0;
NavigationState navigation_state_ = NavigationState::kWaitingResponse;
......@@ -214,6 +217,21 @@ IN_PROC_BROWSER_TEST_F(NavigationBrowserTest, HttpConnectivityError) {
EXPECT_EQ(observer.navigation_state(), NavigationState::kFailed);
}
IN_PROC_BROWSER_TEST_F(NavigationBrowserTest, Download) {
EXPECT_TRUE(embedded_test_server()->Start());
GURL url(embedded_test_server()->GetURL("/content-disposition.html"));
OneShotNavigationObserver observer(shell());
GetNavigationController()->Navigate(url);
observer.WaitForNavigation();
EXPECT_FALSE(observer.completed());
EXPECT_FALSE(observer.is_error_page());
EXPECT_TRUE(observer.is_download());
EXPECT_EQ(observer.load_error(), Navigation::kOtherError);
EXPECT_EQ(observer.navigation_state(), NavigationState::kFailed);
}
IN_PROC_BROWSER_TEST_F(NavigationBrowserTest, StopInOnStart) {
ASSERT_TRUE(embedded_test_server()->Start());
base::RunLoop run_loop;
......
......@@ -96,7 +96,7 @@ const std::vector<GURL>& NavigationImpl::GetRedirectChain() {
}
NavigationState NavigationImpl::GetState() {
if (navigation_handle_->IsErrorPage())
if (navigation_handle_->IsErrorPage() || navigation_handle_->IsDownload())
return NavigationState::kFailed;
if (navigation_handle_->HasCommitted())
return NavigationState::kComplete;
......@@ -118,6 +118,10 @@ bool NavigationImpl::IsErrorPage() {
return navigation_handle_->IsErrorPage();
}
bool NavigationImpl::IsDownload() {
return navigation_handle_->IsDownload();
}
Navigation::LoadError NavigationImpl::GetLoadError() {
auto error_code = navigation_handle_->GetNetErrorCode();
if (auto* response_headers = navigation_handle_->GetResponseHeaders()) {
......
......@@ -58,6 +58,7 @@ class NavigationImpl : public Navigation {
int GetHttpStatusCode(JNIEnv* env) { return GetHttpStatusCode(); }
bool IsSameDocument(JNIEnv* env) { return IsSameDocument(); }
bool IsErrorPage(JNIEnv* env) { return IsErrorPage(); }
bool IsDownload(JNIEnv* env) { return IsDownload(); }
int GetLoadError(JNIEnv* env) { return static_cast<int>(GetLoadError()); }
jboolean SetRequestHeader(JNIEnv* env,
const base::android::JavaParamRef<jstring>& name,
......@@ -79,6 +80,7 @@ class NavigationImpl : public Navigation {
int GetHttpStatusCode() override;
bool IsSameDocument() override;
bool IsErrorPage() override;
bool IsDownload() override;
LoadError GetLoadError() override;
void SetRequestHeader(const std::string& name,
const std::string& value) override;
......
......@@ -126,6 +126,27 @@ public class Navigation extends IClientNavigation.Stub {
}
}
/**
* Whether this navigation resulted in a download. Returns false if this navigation did not
* result in a download, or if download status is not yet known for this navigation. Download
* status is determined for a navigation when processing final (post redirect) HTTP response
* headers. This means the only time the embedder can know if it's a download is in
* NavigationCallback.onNavigationFailed.
*
* @since 84
*/
public boolean isDownload() {
ThreadCheck.ensureOnUiThread();
if (WebLayer.getSupportedMajorVersionInternal() < 84) {
throw new UnsupportedOperationException();
}
try {
return mNavigationImpl.isDownload();
} catch (RemoteException e) {
throw new APICallException(e);
}
}
/**
* Sets a header for a network request. If a header with the specified name exists it is
* overwritten. This method can only be called at two times, from
......
......@@ -24,7 +24,9 @@ enum class NavigationState {
// The navigation succeeded. Any NavigationObservers would have had
// NavigationCompleted() called.
kComplete = 2,
// The navigation failed. IsErrorPage() will return true, and any
// The navigation failed. This could be because of an error (in which case
// IsErrorPage() will return true) or the navigation got turned into a
// download (in which case IsDownload() will return true).
// NavigationObservers would have had NavigationFailed() called.
kFailed = 3,
};
......@@ -60,6 +62,14 @@ class Navigation {
// GetNetErrorCode will be kNoError.
virtual bool IsErrorPage() = 0;
// Returns true if this navigation resulted in a download. Returns false if
// this navigation did not result in a download, or if download status is not
// yet known for this navigation. Download status is determined for a
// navigation when processing final (post redirect) HTTP response headers.
// This means the only time the embedder can know if it's a download is in
// NavigationObserver::NavigationFailed.
virtual bool IsDownload() = 0;
// GENERATED_JAVA_ENUM_PACKAGE: org.chromium.weblayer_private
// GENERATED_JAVA_CLASS_NAME_OVERRIDE: ImplLoadError
enum LoadError {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment