1 // Copyright 2019 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 package org.chromium.content_public.browser;
6 
7 import androidx.annotation.NonNull;
8 
9 import org.chromium.base.annotations.CalledByNative;
10 import org.chromium.base.annotations.JNINamespace;
11 import org.chromium.base.annotations.NativeMethods;
12 import org.chromium.net.NetError;
13 import org.chromium.url.GURL;
14 
15 /**
16  * JNI bridge with content::NavigationHandle
17  */
18 @JNINamespace("content")
19 public class NavigationHandle {
20     private long mNativeNavigationHandleProxy;
21     private final boolean mIsInMainFrame;
22     private final boolean mIsRendererInitiated;
23     private final boolean mIsSameDocument;
24     private Integer mPageTransition;
25     private GURL mUrl;
26     private boolean mHasCommitted;
27     private boolean mIsDownload;
28     private boolean mIsErrorPage;
29     private boolean mIsFragmentNavigation;
30     private boolean mIsValidSearchFormUrl;
31     private @NetError int mErrorCode;
32     private int mHttpStatusCode;
33 
34     @CalledByNative
NavigationHandle(long nativeNavigationHandleProxy, GURL url, boolean isInMainFrame, boolean isSameDocument, boolean isRendererInitiated)35     public NavigationHandle(long nativeNavigationHandleProxy, GURL url, boolean isInMainFrame,
36             boolean isSameDocument, boolean isRendererInitiated) {
37         mNativeNavigationHandleProxy = nativeNavigationHandleProxy;
38         mUrl = url;
39         mIsInMainFrame = isInMainFrame;
40         mIsSameDocument = isSameDocument;
41         mIsRendererInitiated = isRendererInitiated;
42     }
43 
44     /**
45      * The navigation received a redirect. Called once per redirect.
46      * @param url The new URL.
47      */
48     @CalledByNative
didRedirect(GURL url)49     private void didRedirect(GURL url) {
50         mUrl = url;
51     }
52 
53     /**
54      * The navigation finished. Called once per navigation.
55      */
56     @CalledByNative
didFinish(@onNull GURL url, boolean isErrorPage, boolean hasCommitted, boolean isFragmentNavigation, boolean isDownload, boolean isValidSearchFormUrl, int transition, @NetError int errorCode, int httpStatuscode)57     public void didFinish(@NonNull GURL url, boolean isErrorPage, boolean hasCommitted,
58             boolean isFragmentNavigation, boolean isDownload, boolean isValidSearchFormUrl,
59             int transition, @NetError int errorCode, int httpStatuscode) {
60         mUrl = url;
61         mIsErrorPage = isErrorPage;
62         mHasCommitted = hasCommitted;
63         mIsFragmentNavigation = isFragmentNavigation;
64         mIsDownload = isDownload;
65         mIsValidSearchFormUrl = isValidSearchFormUrl;
66         mPageTransition = transition == -1 ? null : transition;
67         mErrorCode = errorCode;
68         mHttpStatusCode = httpStatuscode;
69     }
70 
71     /**
72      * Release the C++ pointer.
73      */
74     @CalledByNative
release()75     private void release() {
76         mNativeNavigationHandleProxy = 0;
77     }
78 
nativePtr()79     public long nativePtr() {
80         return mNativeNavigationHandleProxy;
81     }
82 
83     /**
84      * The URL the frame is navigating to.  This may change during the navigation when encountering
85      * a server redirect.
86      *
87      * @deprecated Please use {@link #getUrl} instead.
88      */
89     @Deprecated
getUrlString()90     public String getUrlString() {
91         return mUrl.getPossiblyInvalidSpec();
92     }
93 
94     /**
95      * The URL the frame is navigating to.  This may change during the navigation when encountering
96      * a server redirect.
97      */
getUrl()98     public GURL getUrl() {
99         return mUrl;
100     }
101 
102     /**
103      * Whether the navigation is taking place in the main frame or in a subframe.
104      */
isInMainFrame()105     public boolean isInMainFrame() {
106         return mIsInMainFrame;
107     }
108 
109     /**
110      * Whether the navigation was initiated by the renderer process. Examples of renderer-initiated
111      * navigations include:
112      *  - <a> link click
113      *  - changing window.location.href
114      *  - redirect via the <meta http-equiv="refresh"> tag
115      *  - using window.history.pushState
116      *
117      * This method returns false for browser-initiated navigations, including:
118      *  - any navigation initiated from the omnibox
119      *  - navigations via suggestions in browser UI
120      *  - navigations via browser UI: Ctrl-R, refresh/forward/back/home buttons
121      *  - using window.history.forward() or window.history.back()
122      *  - any other "explicit" URL navigations, e.g. bookmarks
123      */
isRendererInitiated()124     public boolean isRendererInitiated() {
125         return mIsRendererInitiated;
126     }
127 
128     /**
129      * Whether the navigation happened without changing document.
130      * Examples of same document navigations are:
131      * - reference fragment navigations
132      * - pushState/replaceState
133      * - same page history navigation
134      */
isSameDocument()135     public boolean isSameDocument() {
136         return mIsSameDocument;
137     }
138 
errorDescription()139     public String errorDescription() {
140         // TODO(shaktisahu): Provide appropriate error description (crbug/690784).
141         return "";
142     }
143 
errorCode()144     public @NetError int errorCode() {
145         return mErrorCode;
146     }
147 
148     /**
149      * Whether the navigation has committed. Navigations that end up being downloads or return
150      * 204/205 response codes do not commit (i.e. the WebContents stays at the existing URL). This
151      * returns true for either successful commits or error pages that replace the previous page
152      * (distinguished by |IsErrorPage|), and false for errors that leave the user on the previous
153      * page.
154      */
hasCommitted()155     public boolean hasCommitted() {
156         return mHasCommitted;
157     }
158 
159     /**
160      * Return the HTTP status code. This can be used after the response is received in
161      * didFinishNavigation()
162      */
httpStatusCode()163     public int httpStatusCode() {
164         return mHttpStatusCode;
165     }
166 
167     /**
168      * Returns the page transition type.
169      */
pageTransition()170     public Integer pageTransition() {
171         return mPageTransition;
172     }
173 
174     /**
175      * Returns true on same-document navigation with fragment change.
176      */
isFragmentNavigation()177     public boolean isFragmentNavigation() {
178         return mIsFragmentNavigation;
179     }
180 
181     /**
182      * Whether the navigation resulted in an error page.
183      * Note that if an error page reloads, this will return true even though GetNetErrorCode will be
184      * net::OK.
185      */
isErrorPage()186     public boolean isErrorPage() {
187         return mIsErrorPage;
188     }
189 
190     /**
191      * Returns true if this navigation resulted in a download. Returns false if this navigation did
192      * not result in a download, or if download status is not yet known for this navigation.
193      * Download status is determined for a navigation when processing final (post redirect) HTTP
194      * response headers.
195      */
isDownload()196     public boolean isDownload() {
197         return mIsDownload;
198     }
199 
200     /**
201      * Returns true if the navigation is a search.
202      */
isValidSearchFormUrl()203     public boolean isValidSearchFormUrl() {
204         return mIsValidSearchFormUrl;
205     }
206 
207     /**
208      * Set request's header. If the header is already present, its value is overwritten. When
209      * modified during a navigation start, the headers will be applied to the initial network
210      * request. When modified during a redirect, the headers will be applied to the redirected
211      * request.
212      */
setRequestHeader(String headerName, String headerValue)213     public void setRequestHeader(String headerName, String headerValue) {
214         NavigationHandleJni.get().setRequestHeader(
215                 mNativeNavigationHandleProxy, headerName, headerValue);
216     }
217 
218     /**
219      * Remove a request's header. If the header is not present, it has no effect. Must be called
220      * during a redirect.
221      */
removeRequestHeader(String headerName)222     public void removeRequestHeader(String headerName) {
223         NavigationHandleJni.get().removeRequestHeader(mNativeNavigationHandleProxy, headerName);
224     }
225 
226     @NativeMethods
227     interface Natives {
setRequestHeader( long nativeNavigationHandleProxy, String headerName, String headerValue)228         void setRequestHeader(
229                 long nativeNavigationHandleProxy, String headerName, String headerValue);
removeRequestHeader(long nativeNavigationHandleProxy, String headerName)230         void removeRequestHeader(long nativeNavigationHandleProxy, String headerName);
231     }
232 }
233