Bug 1665426 - Implement fetch flag for private browsing downloads in WebExecutor r=geckoview-reviewers,agi,snorp
authorowlishDeveloper <bugzeeeeee@gmail.com>
Tue, 13 Oct 2020 17:59:49 +0000
changeset 552885 6f0c7cf92ea027280489141e51ff5295d5ee028c
parent 552884 921640803dd55c5ebd50f8ad2c639a28dc9b2de4
child 552886 bf878ce3529bc093b2467eb3ff7880886a91c610
push id128566
push useristorozhko@mozilla.com
push dateTue, 13 Oct 2020 22:01:43 +0000
treeherderautoland@6f0c7cf92ea0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgeckoview-reviewers, agi, snorp
bugs1665426
milestone83.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1665426 - Implement fetch flag for private browsing downloads in WebExecutor r=geckoview-reviewers,agi,snorp Differential Revision: https://phabricator.services.mozilla.com/D93044
mobile/android/geckoview/api.txt
mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/WebExecutorTest.kt
mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoWebExecutor.java
mobile/android/geckoview/src/main/java/org/mozilla/geckoview/doc-files/CHANGELOG.md
widget/android/WebExecutorSupport.cpp
--- a/mobile/android/geckoview/api.txt
+++ b/mobile/android/geckoview/api.txt
@@ -1319,16 +1319,17 @@ package org.mozilla.geckoview {
     ctor public GeckoWebExecutor(@NonNull GeckoRuntime);
     method @NonNull public GeckoResult<WebResponse> fetch(@NonNull WebRequest);
     method @NonNull public GeckoResult<WebResponse> fetch(@NonNull WebRequest, int);
     method @NonNull public GeckoResult<InetAddress[]> resolve(@NonNull String);
     method public void speculativeConnect(@NonNull String);
     field public static final int FETCH_FLAGS_ANONYMOUS = 1;
     field public static final int FETCH_FLAGS_NONE = 0;
     field public static final int FETCH_FLAGS_NO_REDIRECTS = 2;
+    field public static final int FETCH_FLAGS_PRIVATE = 8;
     field public static final int FETCH_FLAGS_STREAM_FAILURE_TEST = 1024;
   }
 
   @AnyThread public class Image {
     method @NonNull public GeckoResult<Bitmap> getBitmap(int);
   }
 
   @AnyThread public class MediaElement {
--- a/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/WebExecutorTest.kt
+++ b/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/WebExecutorTest.kt
@@ -247,29 +247,69 @@ class WebExecutorTest {
 
         val anotherBody = fetch(WebRequest("$TEST_ENDPOINT/cookies")).getJSONBody()
         assertThat("Body should match",
                 anotherBody.getJSONObject("cookies").getString("uptimeMillis"),
                 equalTo(uptimeMillis.toString()))
     }
 
     @Test
-    fun testAnonymous() {
+    fun testAnonymousSendCookies() {
+        val uptimeMillis = SystemClock.uptimeMillis()
+        val response = fetch(WebRequest("$TEST_ENDPOINT/cookies/set/uptimeMillis/$uptimeMillis"), GeckoWebExecutor.FETCH_FLAGS_ANONYMOUS)
+
+        // We get redirected to /cookies which returns the cookies that were sent in the request
+        assertThat("URI should match", response.uri, equalTo("$TEST_ENDPOINT/cookies"))
+        assertThat("Status code should match", response.statusCode, equalTo(200))
+
+        val body = response.getJSONBody()
+        assertThat("Cookies should not be set for the test server",
+                body.getJSONObject("cookies").length(),
+                equalTo(0))
+    }
+
+    @Test
+    fun testAnonymousGetCookies() {
         // Ensure a cookie is set for the test server
-        testCookies();
+        testCookies()
 
         val response = fetch(WebRequest("$TEST_ENDPOINT/cookies"),
                 GeckoWebExecutor.FETCH_FLAGS_ANONYMOUS)
 
         assertThat("Status code should match", response.statusCode, equalTo(200))
         val cookies = response.getJSONBody().getJSONObject("cookies")
         assertThat("Cookies should be empty", cookies.length(), equalTo(0))
     }
 
     @Test
+    fun testPrivateCookies() {
+        val uptimeMillis = SystemClock.uptimeMillis()
+        val response = fetch(WebRequest("$TEST_ENDPOINT/cookies/set/uptimeMillis/$uptimeMillis"), GeckoWebExecutor.FETCH_FLAGS_PRIVATE)
+
+        // We get redirected to /cookies which returns the cookies that were sent in the request
+        assertThat("URI should match", response.uri, equalTo("$TEST_ENDPOINT/cookies"))
+        assertThat("Status code should match", response.statusCode, equalTo(200))
+
+        val body = response.getJSONBody()
+        assertThat("Cookies should be set for the test server",
+                body.getJSONObject("cookies").getString("uptimeMillis"),
+                equalTo(uptimeMillis.toString()))
+
+        val anotherBody = fetch(WebRequest("$TEST_ENDPOINT/cookies"), GeckoWebExecutor.FETCH_FLAGS_PRIVATE).getJSONBody()
+        assertThat("Body should match",
+                anotherBody.getJSONObject("cookies").getString("uptimeMillis"),
+                equalTo(uptimeMillis.toString()))
+
+        val yetAnotherBody = fetch(WebRequest("$TEST_ENDPOINT/cookies")).getJSONBody()
+        assertThat("Cookies set in private session are not supposed to be seen in normal download",
+                yetAnotherBody.getJSONObject("cookies").length(),
+                equalTo(0))
+    }
+
+    @Test
     fun testSpeculativeConnect() {
         // We don't have a way to know if it succeeds or not, but at least we can ensure
         // it doesn't explode.
         executor.speculativeConnect("http://localhost")
 
         // This is just a fence to ensure the above actually ran.
         fetch(WebRequest("$TEST_ENDPOINT/cookies"))
     }
--- a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoWebExecutor.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoWebExecutor.java
@@ -84,22 +84,21 @@ public class GeckoWebExecutor {
     // TODO: implement in WebExecutorSupport and make public bug 1538348
     /**
      * Enables downloads to continue even if they encounter HTTP errors.
      * Using this flag, for example, enables the download of server error pages.
      */
     @WrapForJNI
     /* package */ static final int FETCH_FLAGS_ALLOW_SOME_ERRORS = 1 << 2;
 
-    // TODO: implement in WebExecutorSupport and make public bug 1538348
     /**
-     * Associates this download with a private browsing session
+     * Associates this download with the current private browsing session
      */
     @WrapForJNI
-    /* package */ static final int FETCH_FLAGS_PRIVATE = 1 << 3;
+    public static final int FETCH_FLAGS_PRIVATE = 1 << 3;
 
     /**
      * This flag causes a read error in the {@link WebResponse} body. Useful for testing.
      */
     @WrapForJNI
     public static final int FETCH_FLAGS_STREAM_FAILURE_TEST = 1 << 10;
 
     /**
--- a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/doc-files/CHANGELOG.md
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/doc-files/CHANGELOG.md
@@ -24,21 +24,24 @@ exclude: true
 - Replaced android.util.ArrayMap with java.util.TreeMap in [`WebMessage`][65.13] to enable case-insensitive handling of the HTTP headers.
   ([bug 1666013]({{bugzilla}}1666013))
 - Added [`ContentBlocking.SafeBrowsingProvider`][83.3] to configure Safe
   Browsing providers.
   ([bug 1660241]({{bugzilla}}1660241))
 - Added [`GeckoRuntime.ActivityDelegate`][83.4] which allows applications to handle
   starting external Activities on behalf of GeckoView. Currently this is used to integrate
   FIDO support for WebAuthn.
+- Added ['GeckoWebExecutor#FETCH_FLAG_PRIVATE'][83.5]. This new flag allows for private browsing downloads using WebExecutor.
+  ([bug 1665426]({{bugzilla}}1665426))
 
 [83.1]: {{javadoc_uri}}/WebExtension.MetaData.html#temporary
 [83.2]: {{javadoc_uri}}/MediaSession.Delegate.html#onMetadata-org.mozilla.geckoview.GeckoSession-org.mozilla.geckoview.MediaSession-org.mozilla.geckoview.MediaSession.Metadata-
 [83.3]: {{javadoc_uri}}/ContentBlocking.SafeBrowsingProvider.html
 [83.4]: {{javadoc_uri}}/GeckoRuntime.ActivityDelegate.html
+[83.5]: {{javadoc_uri}}/GeckoWebExecutor.html#FETCH_FLAG_PRIVATE
 
 ## v82
 - ⚠️  [`WebNotification.source`][79.2] is now `@Nullable` to account for
   WebExtension notifications which don't have a `source` field.
 - ⚠️ Deprecated [`ContentDelegate#onExternalResponse(GeckoSession, WebResponseInfo)`][82.1] with the intention of removing
   them in GeckoView v85. 
   ([bug 1530022]({{bugzilla}}1530022))
 - Added [`ContentDelegate#onExternalResponse(GeckoSession, WebResponse)`][82.2] to eliminate the need
@@ -818,9 +821,9 @@ to allow adding gecko profiler markers.
 [65.19]: {{javadoc_uri}}/GeckoSession.NavigationDelegate.LoadRequest.html#isRedirect
 [65.20]: {{javadoc_uri}}/GeckoSession.html#LOAD_FLAGS_BYPASS_CLASSIFIER
 [65.21]: {{javadoc_uri}}/GeckoSession.ContentDelegate.ContextElement.html
 [65.22]: {{javadoc_uri}}/GeckoSession.ContentDelegate.html#onContextMenu-org.mozilla.geckoview.GeckoSession-int-int-org.mozilla.geckoview.GeckoSession.ContentDelegate.ContextElement-
 [65.23]: {{javadoc_uri}}/GeckoSession.FinderResult.html
 [65.24]: {{javadoc_uri}}/CrashReporter.html#sendCrashReport-android.content.Context-android.os.Bundle-java.lang.String-
 [65.25]: {{javadoc_uri}}/GeckoResult.html
 
-[api-version]: d3186b70503f71a6476c765f76c6d49f9a1fb282
+[api-version]: b55b29412d4d11b9a62dfd71f60568d1286b1e7b
--- a/widget/android/WebExecutorSupport.cpp
+++ b/widget/android/WebExecutorSupport.cpp
@@ -20,16 +20,17 @@
 #include "mozilla/java/GeckoWebExecutorWrappers.h"
 #include "mozilla/java/WebMessageWrappers.h"
 #include "mozilla/java/WebRequestErrorWrappers.h"
 #include "mozilla/java/WebResponseWrappers.h"
 #include "mozilla/net/DNS.h"  // for NetAddr
 #include "mozilla/net/CookieJarSettings.h"
 #include "mozilla/Preferences.h"
 #include "GeckoViewStreamListener.h"
+#include "nsIPrivateBrowsingChannel.h"
 
 #include "nsNetUtil.h"  // for NS_NewURI, NS_NewChannel, NS_NewStreamLoader
 
 #include "InetAddress.h"  // for java::sdk::InetAddress and java::sdk::UnknownHostException
 #include "ReferrerInfo.h"
 
 namespace mozilla {
 using namespace net;
@@ -373,16 +374,22 @@ nsresult WebExecutorSupport::CreateStrea
                      nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL,
                      nsIContentPolicy::TYPE_OTHER);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (aFlags & java::GeckoWebExecutor::FETCH_FLAGS_ANONYMOUS) {
     channel->SetLoadFlags(nsIRequest::LOAD_ANONYMOUS);
   }
 
+  if (aFlags & java::GeckoWebExecutor::FETCH_FLAGS_PRIVATE) {
+    nsCOMPtr<nsIPrivateBrowsingChannel> pbChannel = do_QueryInterface(channel);
+    NS_ENSURE_TRUE(pbChannel, NS_ERROR_FAILURE);
+    pbChannel->SetPrivate(true);
+  }
+
   nsCOMPtr<nsICookieJarSettings> cookieJarSettings =
       CookieJarSettings::Create();
   MOZ_ASSERT(cookieJarSettings);
 
   nsCOMPtr<nsILoadInfo> loadInfo = channel->LoadInfo();
   loadInfo->SetCookieJarSettings(cookieJarSettings);
 
   // setup http/https specific things