Backed out 4 changesets (bug 1533840, bug 1522451) for failing dom/manifest/test/test_ManifestProcessor_background_color.html on a CLOSED TREE
authorAndreea Pavel <apavel@mozilla.com>
Thu, 14 Mar 2019 23:02:15 +0200
changeset 521959 0ec36abbdb31
parent 521958 e6e7b9953ede
child 521960 210d55a03877
push id10870
push usernbeleuzu@mozilla.com
push dateFri, 15 Mar 2019 20:00:07 +0000
treeherdermozilla-beta@c594aee5b7a4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1533840, 1522451
milestone67.0a1
backs out4fd7ce83efe1
5a892aa56e37
2ddf151f9535
49ebb69e8893
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
Backed out 4 changesets (bug 1533840, bug 1522451) for failing dom/manifest/test/test_ManifestProcessor_background_color.html on a CLOSED TREE Backed out changeset 4fd7ce83efe1 (bug 1533840) Backed out changeset 5a892aa56e37 (bug 1522451) Backed out changeset 2ddf151f9535 (bug 1522451) Backed out changeset 49ebb69e8893 (bug 1522451)
dom/manifest/ValueExtractor.jsm
mobile/android/base/java/org/mozilla/gecko/customtabs/CustomTabsActivity.java
mobile/android/base/java/org/mozilla/gecko/webapps/WebAppActivity.java
mobile/android/chrome/geckoview/GeckoViewContentChild.js
mobile/android/geckoview/api.txt
mobile/android/geckoview/src/androidTest/assets/www/hello.html
mobile/android/geckoview/src/androidTest/assets/www/manifest.webmanifest
mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/ContentDelegateTest.kt
mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/TestRunnerActivity.java
mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/WebExecutorTest.kt
mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/util/Callbacks.kt
mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/util/HttpBin.java
mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/util/HttpBinHandler.java
mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoSession.java
mobile/android/geckoview/src/main/java/org/mozilla/geckoview/WebRequest.java
mobile/android/geckoview/src/main/java/org/mozilla/geckoview/WebResponse.java
mobile/android/geckoview/src/main/java/org/mozilla/geckoview/doc-files/CHANGELOG.md
mobile/android/geckoview_example/src/main/java/org/mozilla/geckoview_example/GeckoViewActivity.java
--- a/dom/manifest/ValueExtractor.jsm
+++ b/dom/manifest/ValueExtractor.jsm
@@ -45,20 +45,17 @@ ValueExtractor.prototype = {
       return value.trim() || undefined;
     }
     return value;
   },
   extractColorValue(spec) {
     const value = this.extractValue(spec);
     let color;
     if (InspectorUtils.isValidCSSColor(value)) {
-      const rgba = InspectorUtils.colorToRGBA(value);
-      color = "#" + ((rgba.r << 16) |
-        (rgba.g << 8) |
-        rgba.b).toString(16);
+      color = value;
     } else if (value) {
       this.console.warn(this.domBundle.formatStringFromName("ManifestInvalidCSSColor",
                                                             [spec.property, value],
                                                             2));
     }
     return color;
   },
 };
--- a/mobile/android/base/java/org/mozilla/gecko/customtabs/CustomTabsActivity.java
+++ b/mobile/android/base/java/org/mozilla/gecko/customtabs/CustomTabsActivity.java
@@ -26,17 +26,16 @@ import android.support.v7.widget.Toolbar
 import android.text.TextUtils;
 import android.util.Log;
 import android.view.Menu;
 import android.view.MenuInflater;
 import android.view.MenuItem;
 import android.view.View;
 import android.widget.ProgressBar;
 
-import org.json.JSONObject;
 import org.mozilla.gecko.ActivityHandlerHelper;
 import org.mozilla.gecko.BrowserApp;
 import org.mozilla.gecko.Clipboard;
 import org.mozilla.gecko.DoorHangerPopup;
 import org.mozilla.gecko.EventDispatcher;
 import org.mozilla.gecko.FormAssistPopup;
 import org.mozilla.gecko.GeckoApplication;
 import org.mozilla.gecko.R;
--- a/mobile/android/base/java/org/mozilla/gecko/webapps/WebAppActivity.java
+++ b/mobile/android/base/java/org/mozilla/gecko/webapps/WebAppActivity.java
@@ -16,17 +16,16 @@ import android.os.Bundle;
 import android.support.customtabs.CustomTabsIntent;
 import android.support.v7.app.AppCompatActivity;
 import android.support.v7.view.ActionMode;
 import android.util.Log;
 import android.view.Window;
 import android.view.WindowManager;
 import android.widget.Toast;
 
-import org.json.JSONObject;
 import org.mozilla.gecko.ActivityHandlerHelper;
 import org.mozilla.gecko.AppConstants;
 import org.mozilla.gecko.BrowserApp;
 import org.mozilla.gecko.DoorHangerPopup;
 import org.mozilla.gecko.FormAssistPopup;
 import org.mozilla.gecko.GeckoApplication;
 import org.mozilla.gecko.GeckoScreenOrientation;
 import org.mozilla.gecko.R;
--- a/mobile/android/chrome/geckoview/GeckoViewContentChild.js
+++ b/mobile/android/chrome/geckoview/GeckoViewContentChild.js
@@ -16,17 +16,16 @@ const SCREEN_LENGTH_DOCUMENT_HEIGHT = 4;
 
 // This need to match PanZoomController.java
 const SCROLL_BEHAVIOR_SMOOTH = 0;
 const SCROLL_BEHAVIOR_AUTO = 1;
 
 XPCOMUtils.defineLazyModuleGetters(this, {
   FormLikeFactory: "resource://gre/modules/FormLikeFactory.jsm",
   GeckoViewAutoFill: "resource://gre/modules/GeckoViewAutoFill.jsm",
-  ManifestObtainer: "resource://gre/modules/ManifestObtainer.jsm",
   PrivacyFilter: "resource://gre/modules/sessionstore/PrivacyFilter.jsm",
   SessionHistory: "resource://gre/modules/sessionstore/SessionHistory.jsm",
 });
 
 class GeckoViewContentChild extends GeckoViewChildModule {
   onInit() {
     debug `onInit`;
 
@@ -73,31 +72,29 @@ class GeckoViewContentChild extends Geck
     addEventListener("DOMTitleChanged", this, false);
     addEventListener("DOMWindowFocus", this, false);
     addEventListener("DOMWindowClose", this, false);
     addEventListener("MozDOMFullscreen:Entered", this, false);
     addEventListener("MozDOMFullscreen:Exit", this, false);
     addEventListener("MozDOMFullscreen:Exited", this, false);
     addEventListener("MozDOMFullscreen:Request", this, false);
     addEventListener("contextmenu", this, { capture: true });
-    addEventListener("DOMContentLoaded", this, false);
   }
 
   onDisable() {
     debug `onDisable`;
 
     removeEventListener("DOMTitleChanged", this);
     removeEventListener("DOMWindowFocus", this);
     removeEventListener("DOMWindowClose", this);
     removeEventListener("MozDOMFullscreen:Entered", this);
     removeEventListener("MozDOMFullscreen:Exit", this);
     removeEventListener("MozDOMFullscreen:Exited", this);
     removeEventListener("MozDOMFullscreen:Request", this);
     removeEventListener("contextmenu", this, { capture: true });
-    removeEventListener("DOMContentLoaded", this);
   }
 
   collectSessionState() {
     let history = SessionHistory.collect(docShell);
     let formdata = SessionStoreUtils.collectFormData(content);
     let scrolldata = SessionStoreUtils.collectScrollPosition(content);
 
     // Save the current document resolution.
@@ -423,34 +420,16 @@ class GeckoViewContentChild extends Geck
       case "mozcaretstatechanged":
         if (aEvent.reason === "presscaret" || aEvent.reason === "releasecaret") {
           this.eventDispatcher.sendRequest({
             type: "GeckoView:PinOnScreen",
             pinned: aEvent.reason === "presscaret",
           });
         }
         break;
-      case "DOMContentLoaded": {
-        content.requestIdleCallback(async () => {
-          let manifest = null;
-          try {
-            manifest = await ManifestObtainer.contentObtainManifest(content);
-          } catch (e) {
-            // Unfortunately, this throws if there is no manifest present, so we
-            // probably don't want to log anything here. Bug 1534756.
-          }
-
-          if (manifest) {
-            this.eventDispatcher.sendRequest({
-              type: "GeckoView:WebAppManifest",
-              manifest,
-            });
-          }
-        });
-      }
     }
   }
 
   // WebProgress event handler.
   onLocationChange(aWebProgress, aRequest, aLocationURI, aFlags) {
     debug `onLocationChange`;
 
     if (this._savedState) {
--- a/mobile/android/geckoview/api.txt
+++ b/mobile/android/geckoview/api.txt
@@ -348,17 +348,16 @@ package org.mozilla.geckoview {
     method @android.support.annotation.UiThread default public void onCloseRequest(@android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession);
     method @android.support.annotation.UiThread default public void onContextMenu(@android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession, int, int, @android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession.ContentDelegate.ContextElement);
     method @android.support.annotation.UiThread default public void onCrash(@android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession);
     method @android.support.annotation.UiThread default public void onExternalResponse(@android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession, @android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession.WebResponseInfo);
     method @android.support.annotation.UiThread default public void onFirstComposite(@android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession);
     method @android.support.annotation.UiThread default public void onFocusRequest(@android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession);
     method @android.support.annotation.UiThread default public void onFullScreen(@android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession, boolean);
     method @android.support.annotation.UiThread default public void onTitleChange(@android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession, @android.support.annotation.Nullable java.lang.String);
-    method @android.support.annotation.UiThread default public void onWebAppManifest(@android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession, @android.support.annotation.NonNull org.json.JSONObject);
   }
 
   public static class GeckoSession.ContentDelegate.ContextElement {
     ctor protected ContextElement(@android.support.annotation.Nullable java.lang.String, @android.support.annotation.Nullable java.lang.String, @android.support.annotation.Nullable java.lang.String, @android.support.annotation.Nullable java.lang.String, @android.support.annotation.NonNull java.lang.String, @android.support.annotation.Nullable java.lang.String);
     field public static final int TYPE_AUDIO = 3;
     field public static final int TYPE_IMAGE = 1;
     field public static final int TYPE_NONE = 0;
     field public static final int TYPE_VIDEO = 2;
@@ -952,19 +951,16 @@ package org.mozilla.geckoview {
     field public final int cacheMode;
     field @android.support.annotation.NonNull public final java.lang.String method;
     field @android.support.annotation.Nullable public final java.lang.String referrer;
   }
 
   @android.support.annotation.AnyThread public static class WebRequest.Builder extends org.mozilla.geckoview.WebMessage.Builder {
     ctor public Builder(@android.support.annotation.NonNull java.lang.String);
     method @android.support.annotation.NonNull public org.mozilla.geckoview.WebRequest.Builder body(@android.support.annotation.Nullable java.nio.ByteBuffer);
-    method @android.support.annotation.NonNull public org.mozilla.geckoview.WebRequest.Builder body(@android.support.annotation.NonNull byte[]);
-    method @android.support.annotation.NonNull public org.mozilla.geckoview.WebRequest.Builder body(@android.support.annotation.NonNull java.lang.String);
-    method @android.support.annotation.NonNull public org.mozilla.geckoview.WebRequest.Builder body(@android.support.annotation.NonNull org.json.JSONObject);
     method @android.support.annotation.NonNull public org.mozilla.geckoview.WebRequest build();
     method @android.support.annotation.NonNull public org.mozilla.geckoview.WebRequest.Builder cacheMode(int);
     method @android.support.annotation.NonNull public org.mozilla.geckoview.WebRequest.Builder method(@android.support.annotation.NonNull java.lang.String);
     method @android.support.annotation.NonNull public org.mozilla.geckoview.WebRequest.Builder referrer(@android.support.annotation.Nullable java.lang.String);
   }
 
   public static interface WebRequest.CacheMode implements java.lang.annotation.Annotation {
   }
@@ -1011,19 +1007,16 @@ package org.mozilla.geckoview {
   public static interface WebRequestError.Error implements java.lang.annotation.Annotation {
   }
 
   public static interface WebRequestError.ErrorCategory implements java.lang.annotation.Annotation {
   }
 
   @android.support.annotation.AnyThread public class WebResponse extends org.mozilla.geckoview.WebMessage {
     ctor protected WebResponse(@android.support.annotation.NonNull org.mozilla.geckoview.WebResponse.Builder);
-    method @android.support.annotation.NonNull public org.mozilla.geckoview.GeckoResult<byte[]> byteArray();
-    method @android.support.annotation.NonNull public org.mozilla.geckoview.GeckoResult<org.json.JSONObject> json();
-    method @android.support.annotation.NonNull public org.mozilla.geckoview.GeckoResult<java.lang.String> text();
     field @android.support.annotation.Nullable public final java.io.InputStream body;
     field public final boolean redirected;
     field public final int statusCode;
   }
 
   @android.support.annotation.AnyThread public static class WebResponse.Builder extends org.mozilla.geckoview.WebMessage.Builder {
     ctor public Builder(@android.support.annotation.NonNull java.lang.String);
     method @android.support.annotation.NonNull public org.mozilla.geckoview.WebResponse.Builder body(@android.support.annotation.NonNull java.io.InputStream);
--- a/mobile/android/geckoview/src/androidTest/assets/www/hello.html
+++ b/mobile/android/geckoview/src/androidTest/assets/www/hello.html
@@ -1,9 +1,6 @@
 <html>
-    <head>
-        <title>Hello, world!</title>
-        <link rel="manifest" href="manifest.webmanifest">
-    </head>
+    <head><title>Hello, world!</title></head>
     <body>
         <p>Hello, world!</p>
     </body>
 </html>
\ No newline at end of file
deleted file mode 100644
--- a/mobile/android/geckoview/src/androidTest/assets/www/manifest.webmanifest
+++ /dev/null
@@ -1,17 +0,0 @@
-{
-  "name": "App",
-  "short_name": "app",
-  "start_url": "./start/index.html",
-  "display": "standalone",
-  "background_color": "#c0feee",
-  "theme_color": "cadetblue",
-  "icons": [{
-    "src": "images/test.gif",
-    "sizes": "192x192",
-    "type": "image/gif"
-  }],
-  "related_applications": [{
-    "platform": "play",
-    "url": "https://play.google.com/store/apps/details?id=my.first.webapp"
-  }]
-}
\ No newline at end of file
--- a/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/ContentDelegateTest.kt
+++ b/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/ContentDelegateTest.kt
@@ -1,58 +1,50 @@
 /* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*-
  * Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 package org.mozilla.geckoview.test
 
 import android.app.assist.AssistStructure
 import android.graphics.SurfaceTexture
-import android.net.Uri
 import android.os.Build
 import org.mozilla.geckoview.AllowOrDeny
+import org.mozilla.geckoview.GeckoDisplay
 import org.mozilla.geckoview.GeckoResult
 import org.mozilla.geckoview.GeckoSession
 import org.mozilla.geckoview.GeckoSession.NavigationDelegate.LoadRequest
 import org.mozilla.geckoview.test.rule.GeckoSessionTestRule.AssertCalled
 import org.mozilla.geckoview.test.rule.GeckoSessionTestRule.IgnoreCrash
 import org.mozilla.geckoview.test.rule.GeckoSessionTestRule.ReuseSession
 import org.mozilla.geckoview.test.rule.GeckoSessionTestRule.WithDevToolsAPI
 import org.mozilla.geckoview.test.rule.GeckoSessionTestRule.WithDisplay
 import org.mozilla.geckoview.test.util.Callbacks
 import org.mozilla.geckoview.test.util.UiThreadUtils
 
 import android.os.Looper
-import android.support.test.InstrumentationRegistry
 import android.support.test.filters.MediumTest
 import android.support.test.filters.SdkSuppress
 import android.support.test.runner.AndroidJUnit4
 import android.text.InputType
 import android.util.SparseArray
 import android.view.Surface
 import android.view.View
 import android.view.ViewStructure
 import android.widget.EditText
 import org.hamcrest.Matchers.*
-import org.json.JSONObject
 import org.junit.Assume.assumeThat
 import org.junit.Test
 import org.junit.runner.RunWith
-import org.mozilla.geckoview.test.util.HttpBin
-
-import java.net.URI
 
 import kotlin.concurrent.thread
 
 @RunWith(AndroidJUnit4::class)
 @MediumTest
 class ContentDelegateTest : BaseSessionTest() {
-    companion object {
-        val TEST_ENDPOINT: String = "http://localhost:4243"
-    }
 
     @Test fun titleChange() {
         sessionRule.session.loadTestPath(TITLE_CHANGE_HTML_PATH)
 
         sessionRule.waitUntilCalled(object : Callbacks.ContentDelegate {
             @AssertCalled(count = 2)
             override fun onTitleChange(session: GeckoSession, title: String?) {
                 assertThat("Title should match", title,
@@ -583,49 +575,9 @@ class ContentDelegateTest : BaseSessionT
         sessionRule.waitUntilCalled(object : Callbacks.ContentDelegate {
             @AssertCalled(count = 1)
             override fun onFirstComposite(session: GeckoSession) {
             }
         })
         display.surfaceDestroyed()
         mainSession.releaseDisplay(display)
     }
-
-    @Test fun webAppManifest() {
-        val httpBin = HttpBin(InstrumentationRegistry.getTargetContext(), URI.create(TEST_ENDPOINT))
-
-        try {
-            httpBin.start()
-
-            mainSession.loadUri("$TEST_ENDPOINT$HELLO_HTML_PATH")
-            mainSession.waitUntilCalled(object : Callbacks.All {
-
-                @AssertCalled(count = 1)
-                override fun onPageStop(session: GeckoSession, success: Boolean) {
-                    assertThat("Page load should succeed", success, equalTo(true))
-                }
-
-                @AssertCalled(count = 1)
-                override fun onWebAppManifest(session: GeckoSession, manifest: JSONObject) {
-                    // These values come from the manifest at assets/www/manifest.webmanifest
-                    assertThat("name should match", manifest.getString("name"), equalTo("App"))
-                    assertThat("short_name should match", manifest.getString("short_name"), equalTo("app"))
-                    assertThat("display should match", manifest.getString("display"), equalTo("standalone"))
-
-                    // The color here is "cadetblue" converted to hex.
-                    assertThat("theme_color should match", manifest.getString("theme_color"), equalTo("#5f9ea0"))
-                    assertThat("background_color should match", manifest.getString("background_color"), equalTo("#c0feee"))
-                    assertThat("start_url should match", manifest.getString("start_url"), equalTo("$TEST_ENDPOINT/assets/www/start/index.html"))
-
-                    val icon = manifest.getJSONArray("icons").getJSONObject(0);
-
-                    val iconSrc = Uri.parse(icon.getString("src"))
-                    assertThat("icon should have a valid src", iconSrc, notNullValue())
-                    assertThat("icon src should be absolute", iconSrc.isAbsolute, equalTo(true))
-                    assertThat("icon should have sizes", icon.getString("sizes"),  not(isEmptyOrNullString()))
-                    assertThat("icon type should match", icon.getString("type"), equalTo("image/gif"))
-                }
-            })
-        } finally {
-            httpBin.stop()
-        }
-    }
 }
--- a/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/TestRunnerActivity.java
+++ b/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/TestRunnerActivity.java
@@ -1,16 +1,15 @@
 /* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*-
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.geckoview.test;
 
-import org.json.JSONObject;
 import org.mozilla.geckoview.AllowOrDeny;
 import org.mozilla.geckoview.GeckoDisplay;
 import org.mozilla.geckoview.GeckoResult;
 import org.mozilla.geckoview.GeckoSession;
 import org.mozilla.geckoview.GeckoSessionSettings;
 import org.mozilla.geckoview.GeckoView;
 import org.mozilla.geckoview.GeckoRuntime;
 import org.mozilla.geckoview.GeckoRuntimeSettings;
@@ -109,20 +108,16 @@ public class TestRunnerActivity extends 
             if (System.getenv("MOZ_CRASHREPORTER_SHUTDOWN") != null) {
                 sRuntime.shutdown();
             }
         }
 
         @Override
         public void onFirstComposite(final GeckoSession session) {
         }
-
-        @Override
-        public void onWebAppManifest(final GeckoSession session, final JSONObject manifest) {
-        }
     };
 
     private GeckoSession createSession() {
         return createSession(null);
     }
 
     private GeckoSession createSession(GeckoSessionSettings settings) {
         if (settings == null) {
--- 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
@@ -3,26 +3,29 @@
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 package org.mozilla.geckoview.test
 
 import android.os.Build
 import android.os.Handler
 import android.os.Looper
 import android.os.SystemClock
-import android.support.test.InstrumentationRegistry
 
 import android.support.test.filters.MediumTest
 import android.support.test.filters.SdkSuppress
 import android.support.test.runner.AndroidJUnit4
 
 import java.math.BigInteger
 
 import java.net.URI
 
+import java.nio.ByteBuffer
+import java.nio.CharBuffer
+import java.nio.charset.Charset
+
 import java.security.MessageDigest
 
 import java.util.concurrent.CountDownLatch
 
 import org.hamcrest.MatcherAssert.assertThat
 import org.hamcrest.Matchers.*
 
 import org.json.JSONObject
@@ -35,17 +38,16 @@ import org.mozilla.geckoview.GeckoWebExe
 import org.mozilla.geckoview.WebRequest
 import org.mozilla.geckoview.WebRequestError
 import org.mozilla.geckoview.WebResponse
 
 import org.mozilla.geckoview.test.util.Environment
 import org.mozilla.geckoview.test.util.HttpBin
 import org.mozilla.geckoview.test.util.RuntimeCreator
 import java.net.UnknownHostException
-import java.nio.ByteBuffer
 
 @MediumTest
 @RunWith(AndroidJUnit4::class)
 class WebExecutorTest {
     companion object {
         val TEST_ENDPOINT: String = "http://localhost:4242"
     }
 
@@ -59,17 +61,17 @@ class WebExecutorTest {
     fun setup() {
         // Using @UiThreadTest here does not seem to block
         // the tests which are not using @UiThreadTest, so we do that
         // ourselves here as GeckoRuntime needs to be initialized
         // on the UI thread.
         val latch = CountDownLatch(1)
         Handler(Looper.getMainLooper()).post {
             executor = GeckoWebExecutor(RuntimeCreator.getRuntime())
-            server = HttpBin(InstrumentationRegistry.getTargetContext(), URI.create(TEST_ENDPOINT))
+            server = HttpBin(URI.create(TEST_ENDPOINT))
             server.start()
             latch.countDown()
         }
 
         latch.await()
     }
 
     @After
@@ -80,62 +82,60 @@ class WebExecutorTest {
     private fun fetch(request: WebRequest): WebResponse {
         return fetch(request, GeckoWebExecutor.FETCH_FLAGS_NONE)
     }
 
     private fun fetch(request: WebRequest, @GeckoWebExecutor.FetchFlags flags: Int): WebResponse {
         return executor.fetch(request, flags).poll(env.defaultTimeoutMillis)!!
     }
 
-    fun WebResponse.getBodyBytes(): ByteBuffer {
-        return ByteBuffer.wrap(byteArray().poll()!!);
+    fun String.toDirectByteBuffer(): ByteBuffer {
+        val chars = CharBuffer.wrap(this)
+        val buffer = ByteBuffer.allocateDirect(this.length)
+        Charset.forName("UTF-8").newEncoder().encode(chars, buffer, true)
+
+        return buffer
     }
 
     fun WebResponse.getJSONBody(): JSONObject {
-        return json().poll()!!
+        val bytes = ByteBuffer.wrap(body!!.readBytes())
+        return JSONObject(Charset.forName("UTF-8").decode(bytes).toString())
     }
 
     @Test
     fun smoke() {
         val uri = "$TEST_ENDPOINT/anything"
-        val requestBody = JSONObject("{ \"foo\": 42 }")
+        val bodyString = "This is the POST data"
         val referrer = "http://foo/bar"
 
         val request = WebRequest.Builder(uri)
                 .method("POST")
                 .header("Header1", "Clobbered")
                 .header("Header1", "Value")
                 .addHeader("Header2", "Value1")
                 .addHeader("Header2", "Value2")
                 .referrer(referrer)
                 .header("Content-Type", "text/plain")
-                .body(requestBody)
+                .body(bodyString.toDirectByteBuffer())
                 .build()
 
         val response = fetch(request)
 
         assertThat("URI should match", response.uri, equalTo(uri))
         assertThat("Status could should match", response.statusCode, equalTo(200))
         assertThat("Content type should match", response.headers["Content-Type"], equalTo("application/json"))
         assertThat("Redirected should match", response.redirected, equalTo(false))
 
         val body = response.getJSONBody()
         assertThat("Method should match", body.getString("method"), equalTo("POST"))
         assertThat("Headers should match", body.getJSONObject("headers").getString("Header1"), equalTo("Value"))
         assertThat("Headers should match", body.getJSONObject("headers").getString("Header2"), equalTo("Value1, Value2"))
         assertThat("Headers should match", body.getJSONObject("headers").getString("Content-Type"), equalTo("text/plain"))
         assertThat("Referrer should match", body.getJSONObject("headers").getString("Referer"), equalTo(referrer))
-        assertThat("Data should match", body.getString("data"), equalTo(requestBody.toString()));
-    }
-
-    @Test
-    fun testFetchAsset() {
-        val response = fetch(WebRequest("$TEST_ENDPOINT/assets/www/hello.html"))
-        assertThat("Status should match", response.statusCode, equalTo(200))
-        assertThat("Body should have bytes", response.getBodyBytes().remaining(), greaterThan(0))
+        assertThat("Data should match", body.getString("data"), equalTo(bodyString));
     }
 
     @Test
     fun test404() {
         val response = fetch(WebRequest("$TEST_ENDPOINT/status/404"))
         assertThat("Status code should match", response.statusCode, equalTo(404))
     }
 
--- a/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/util/Callbacks.kt
+++ b/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/util/Callbacks.kt
@@ -13,17 +13,16 @@ import org.mozilla.geckoview.GeckoSessio
 import org.mozilla.geckoview.GeckoSession.ContentDelegate.ContextElement
 import org.mozilla.geckoview.GeckoSession.NavigationDelegate.LoadRequest
 import org.mozilla.geckoview.MediaElement
 import org.mozilla.geckoview.WebRequestError
 
 import android.view.inputmethod.CursorAnchorInfo
 import android.view.inputmethod.ExtractedText
 import android.view.inputmethod.ExtractedTextRequest
-import org.json.JSONObject
 
 class Callbacks private constructor() {
     object Default : All
 
     interface All : ContentBlockingDelegate, ContentDelegate,
                     HistoryDelegate, MediaDelegate,
                     NavigationDelegate, PermissionDelegate, ProgressDelegate,
                     PromptDelegate, ScrollDelegate, SelectionActionDelegate,
--- a/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/util/HttpBin.java
+++ b/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/util/HttpBin.java
@@ -11,17 +11,16 @@
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
 package org.mozilla.geckoview.test.util;
 
-import android.content.Context;
 import android.os.StrictMode;
 
 import android.support.annotation.NonNull;
 
 import android.util.Log;
 
 import java.net.URI;
 
@@ -38,18 +37,18 @@ import org.eclipse.jetty.util.thread.Exe
 public final class HttpBin {
     private static final String LOGTAG = "HttpBin";
     private final Server mServer;
 
     static {
         org.eclipse.jetty.util.log.Log.setLog(new AndroidLogger());
     }
 
-    public HttpBin(@NonNull Context context, @NonNull URI endpoint) {
-        this(endpoint, new HttpBinHandler(context));
+    public HttpBin(@NonNull URI endpoint) {
+        this(endpoint, new HttpBinHandler());
     }
 
     public HttpBin(@NonNull URI endpoint, @NonNull HttpBinHandler handler) {
         StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder(
                 StrictMode.getThreadPolicy())
                 .permitNetwork()
                 .build());
 
--- a/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/util/HttpBinHandler.java
+++ b/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/util/HttpBinHandler.java
@@ -11,18 +11,16 @@
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
 package org.mozilla.geckoview.test.util;
 
-import android.content.Context;
-import android.content.res.AssetManager;
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
 
 import android.util.Log;
 
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
@@ -43,24 +41,16 @@ import org.eclipse.jetty.server.handler.
 
 import org.json.JSONException;
 import org.json.JSONObject;
 
 class HttpBinHandler extends AbstractHandler {
     private static final String LOGTAG = "HttpBinHandler";
     private static final int BUFSIZE = 4096;
 
-    private AssetManager mAssets;
-
-    public HttpBinHandler(@NonNull Context context) {
-        super();
-
-        mAssets = context.getResources().getAssets();
-    }
-
     private static void pipe(final @NonNull InputStream is) throws IOException {
         pipe(is, null);
     }
 
     private static void pipe(final @NonNull InputStream is, final @Nullable OutputStream os)
         throws IOException {
         final byte[] buf = new byte[BUFSIZE];
         int count = 0;
@@ -193,34 +183,25 @@ class HttpBinHandler extends AbstractHan
                 final byte[] digest = MessageDigest.getInstance("SHA-256").digest(payload);
                 servletResponse.addHeader("X-SHA-256",
                         String.format("%064x", new BigInteger(1, digest)));
 
                 os.write(payload);
                 os.flush();
 
                 baseRequest.setHandled(true);
-            } else if (uri.startsWith("/assets")) {
-                pipe(is);
-                pipe(mAssets.open(uri.substring("/assets/".length())), os);
-                os.flush();
-                baseRequest.setHandled(true);
             }
 
             if (!baseRequest.isHandled()) {
                 servletResponse.setStatus(501);
                 baseRequest.setHandled(true);
             }
         } catch (JSONException e) {
             Log.e(LOGTAG, "JSON error while handling response", e);
             servletResponse.setStatus(500);
             baseRequest.setHandled(true);
         } catch (NoSuchAlgorithmException e) {
             Log.e(LOGTAG, "Failed to generate digest", e);
             servletResponse.setStatus(500);
             baseRequest.setHandled(true);
-        } catch (IOException e) {
-            Log.e(LOGTAG, "Failed to respond", e);
-            servletResponse.setStatus(500);
-            baseRequest.setHandled(true);
         }
     }
 }
--- a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoSession.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoSession.java
@@ -6,18 +6,16 @@
 
 package org.mozilla.geckoview;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.ref.WeakReference;
 import java.util.UUID;
 
-import org.json.JSONException;
-import org.json.JSONObject;
 import org.mozilla.gecko.annotation.WrapForJNI;
 import org.mozilla.gecko.EventDispatcher;
 import org.mozilla.gecko.GeckoAppShell;
 import org.mozilla.gecko.GeckoThread;
 import org.mozilla.gecko.IGeckoEditableParent;
 import org.mozilla.gecko.mozglue.JNIObject;
 import org.mozilla.gecko.NativeQueue;
 import org.mozilla.gecko.util.BundleEventListener;
@@ -340,17 +338,16 @@ public class GeckoSession implements Par
                 "GeckoView:ContentCrash",
                 "GeckoView:ContextMenu",
                 "GeckoView:DOMTitleChanged",
                 "GeckoView:DOMWindowFocus",
                 "GeckoView:DOMWindowClose",
                 "GeckoView:ExternalResponse",
                 "GeckoView:FullScreenEnter",
                 "GeckoView:FullScreenExit",
-                "GeckoView:WebAppManifest",
             }
         ) {
             @Override
             public void handleMessage(final ContentDelegate delegate,
                                       final String event,
                                       final GeckoBundle message,
                                       final EventCallback callback) {
 
@@ -380,27 +377,16 @@ public class GeckoSession implements Par
                 } else if ("GeckoView:DOMWindowClose".equals(event)) {
                     delegate.onCloseRequest(GeckoSession.this);
                 } else if ("GeckoView:FullScreenEnter".equals(event)) {
                     delegate.onFullScreen(GeckoSession.this, true);
                 } else if ("GeckoView:FullScreenExit".equals(event)) {
                     delegate.onFullScreen(GeckoSession.this, false);
                 } else if ("GeckoView:ExternalResponse".equals(event)) {
                     delegate.onExternalResponse(GeckoSession.this, new WebResponseInfo(message));
-                } else if ("GeckoView:WebAppManifest".equals(event)) {
-                    final GeckoBundle manifest = message.getBundle("manifest");
-                    if (manifest == null) {
-                        return;
-                    }
-
-                    try {
-                        delegate.onWebAppManifest(GeckoSession.this, manifest.toJSONObject());
-                    } catch (JSONException e) {
-                        Log.e(LOGTAG, "Failed to convert web app manifest to JSON", e);
-                    }
                 }
             }
         };
 
     private final GeckoSessionHandler<NavigationDelegate> mNavigationHandler =
         new GeckoSessionHandler<NavigationDelegate>(
             "GeckoViewNavigation", this,
             new String[]{
@@ -2766,26 +2752,16 @@ public class GeckoSession implements Par
         /**
          * Notification that the first content composition has occurred.
          * This callback is invoked for the first content composite after either
          * a start or a restart of the compositor.
          * @param session The GeckoSession that had a first paint event.
          */
         @UiThread
         default void onFirstComposite(@NonNull GeckoSession session) {}
-
-        /**
-         * This is fired when the loaded document has a valid Web App Manifest present.
-         *
-         * @param session The GeckoSession that contains the Web App Manifest
-         * @param manifest A parsed and validated {@link JSONObject} containing the manifest contents.
-         * @see <a href="https://www.w3.org/TR/appmanifest/">Web App Manifest specification</a>
-         */
-        @UiThread
-        default void onWebAppManifest(@NonNull GeckoSession session, @NonNull JSONObject manifest) {}
     }
 
     public interface SelectionActionDelegate {
         @Retention(RetentionPolicy.SOURCE)
         @IntDef(flag = true, value = {FLAG_IS_COLLAPSED,
                                       FLAG_IS_EDITABLE})
         /* package */ @interface Flag {}
 
--- a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/WebRequest.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/WebRequest.java
@@ -1,30 +1,27 @@
 /* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
  * vim: ts=4 sw=4 expandtab:
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.geckoview;
 
-import org.json.JSONObject;
-
 import org.mozilla.gecko.annotation.WrapForJNI;
 
 import android.support.annotation.AnyThread;
 import android.support.annotation.IntDef;
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 
 import java.nio.ByteBuffer;
-import java.nio.charset.Charset;
 
 /**
  * WebRequest represents an HTTP[S] request. The typical pattern is to create instances of this
  * class via {@link WebRequest.Builder}, and fetch responses via {@link GeckoWebExecutor#fetch(WebRequest)}.
  */
 @WrapForJNI
 @AnyThread
 public class WebRequest extends WebMessage {
@@ -168,52 +165,16 @@ public class WebRequest extends WebMessa
             if (buffer != null && !buffer.isDirect()) {
                 throw new IllegalArgumentException("body must be directly allocated");
             }
             mBody = buffer;
             return this;
         }
 
         /**
-         * Set the body.
-         *
-         * @param bytes A non-null byte array.
-         * @return This Builder instance.
-         */
-        public @NonNull Builder body(final @NonNull byte[] bytes) {
-            final ByteBuffer buffer = ByteBuffer.allocateDirect(bytes.length);
-            buffer.put(bytes);
-
-            body(buffer);
-            return this;
-        }
-
-        /**
-         * Set the body.
-         *
-         * @param bodyString A non-null {@link String}.
-         * @return This Builder instance.
-         */
-        public @NonNull Builder body(final @NonNull String bodyString) {
-            body(bodyString.getBytes(Charset.forName("UTF-8")));
-            return this;
-        }
-
-        /**
-         * Set the body.
-         *
-         * @param object A non-null {@link JSONObject}.
-         * @return This Builder instance.
-         */
-        public @NonNull Builder body(final @NonNull JSONObject object) {
-            body(object.toString());
-            return this;
-        }
-
-        /**
          * Set the HTTP method.
          *
          * @param method The HTTP method String.
          * @return This Builder instance.
          */
         public @NonNull Builder method(final @NonNull String method) {
             mMethod = method;
             return this;
--- a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/WebResponse.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/WebResponse.java
@@ -1,40 +1,32 @@
 /* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
  * vim: ts=4 sw=4 expandtab:
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.geckoview;
 
-import org.json.JSONObject;
 import org.mozilla.gecko.annotation.WrapForJNI;
 
 import android.support.annotation.AnyThread;
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
 
-import java.io.ByteArrayOutputStream;
 import java.io.InputStream;
 import java.nio.ByteBuffer;
-import java.nio.charset.Charset;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
 
 /**
  * WebResponse represents an HTTP[S] response. It is normally created
  * by {@link GeckoWebExecutor#fetch(WebRequest)}.
  */
 @WrapForJNI
 @AnyThread
 public class WebResponse extends WebMessage {
-    private static final ExecutorService sExecutorService = Executors.newCachedThreadPool();
-    private static final int BUFSIZE = 8192;
-
     /**
      * The HTTP status code for the response, e.g. 200.
      */
     public final int statusCode;
 
     /**
      * A boolean indicating whether or not this response is
      * the result of a redirection.
@@ -49,87 +41,16 @@ public class WebResponse extends WebMess
     protected WebResponse(final @NonNull Builder builder) {
         super(builder);
         this.statusCode = builder.mStatusCode;
         this.redirected = builder.mRedirected;
         this.body = builder.mBody;
     }
 
     /**
-     * Reads the {@link #body} stream into a byte array.
-     *
-     * @return A {@link GeckoResult} which resolves to a byte array containing the response body.
-     */
-    public @NonNull GeckoResult<byte[]> byteArray() {
-        if (body == null) {
-            return GeckoResult.fromValue(new byte[0]);
-        }
-
-        final GeckoResult<byte[]> result = new GeckoResult<>();
-        sExecutorService.submit(() -> {
-            final ByteArrayOutputStream os = new ByteArrayOutputStream();
-            final byte buf[] = new byte[BUFSIZE];
-            int count;
-
-            try {
-                while ((count = body.read(buf)) > 0) {
-                    os.write(buf, 0, count);
-                }
-
-                os.flush();
-
-                result.complete(os.toByteArray());
-            } catch (Exception e) {
-                result.completeExceptionally(e);
-            }
-        });
-
-        return result;
-    }
-
-    /**
-     * Reads the {@link #body} stream into a {@link String}.
-     *
-     * @return A {@link GeckoResult} which resolves to a {@link String} containing the response body.
-     */
-    public @NonNull GeckoResult<String> text() {
-        final GeckoResult<String> result = new GeckoResult<>();
-
-        sExecutorService.submit(() -> {
-            try {
-                final ByteBuffer bytes = ByteBuffer.wrap(byteArray().poll());
-                result.complete(Charset.forName("UTF-8").decode(bytes).toString());
-            } catch (Throwable t) {
-                result.completeExceptionally(t);
-            }
-        });
-
-        return result;
-    }
-
-    /**
-     * Reads the {@link #body} stream into a {@link JSONObject}.
-     *
-     * @return A {@link GeckoResult} which resolves to a {@link JSONObject} containing the response body.
-     */
-    public @NonNull GeckoResult<JSONObject> json() {
-        final GeckoResult<JSONObject> result = new GeckoResult<>();
-
-        sExecutorService.submit(() -> {
-            try {
-                result.complete(new JSONObject(text().poll()));
-            } catch (Throwable t) {
-                result.completeExceptionally(t);
-            }
-        });
-
-        return result;
-    }
-
-    /**
      * Builder offers a convenient way to create WebResponse instances.
      */
     @WrapForJNI
     @AnyThread
     public static class Builder extends WebMessage.Builder {
         /* package */ int mStatusCode;
         /* package */ boolean mRedirected;
         /* package */ InputStream mBody;
--- 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
@@ -85,35 +85,16 @@ exclude: true
 [67.20]: ../GeckoDisplay.html
 [67.21]: ../GeckoDisplay.html#capturePixels
 
 - Add missing `@Nullable` annotation to return value for
   `GeckoSession.PromptDelegate.ChoiceCallback.onPopupResult()`
 
 - Added `default` implementations for all non-functional `interface`s.
 
-- Added [`ContentDelegate.onWebAppManifest`][67.22], which will deliver the contents of a parsed
-  and validated Web App Manifest on pages that contain one.
-
-[67.22]: ../GeckoSession.ContentDelegate.html#onWebAppManifest-org.mozilla.geckoview.GeckoSession-org.json.JSONObject
-
-- Added [`WebResponse.byteArray()`][67.22], [`WebResponse.text()`][67.23], and
-  [`WebResponse.json()`][67.24] as convenience methods for accessing the response body.
-
-[67.23]: ../WebResponse.html#byteArray--
-[67.24]: ../WebResponse.html#text--
-[67.25]: ../WebResponse.html#json--
-
-- Added [`byte[]`][67.25], [`String`][67.26], and [`JSONObject`][67.27] overloads of
-  `WebRequest.Body.Builder.body()` as convenience methods for setting the request body.
-
-[67.26]: ../WebRequest.Builder.html#body-byte:A-
-[67.27]: ../WebRequest.Builder.html#body-java.lang.String-
-[67.28]: ../WebRequest.Builder.html#body-org.json.JSONObject-
-
 ## v66
 - Removed redundant field `trackingMode` from [`SecurityInformation`][66.6].
   Use `TrackingProtectionDelegate.onTrackerBlocked` for notification of blocked
   elements during page load.
 
 [66.6]: ../GeckoSession.ProgressDelegate.SecurityInformation.html
 
 - Added [`@NonNull`][66.1] or [`@Nullable`][66.2] to all APIs.
@@ -223,9 +204,9 @@ exclude: true
 [65.23]: ../GeckoSession.FinderResult.html
 
 - Update [`CrashReporter#sendCrashReport`][65.24] to return the crash ID as a
   [`GeckoResult<String>`][65.25].
 
 [65.24]: ../CrashReporter.html#sendCrashReport-android.content.Context-android.os.Bundle-java.lang.String-
 [65.25]: ../GeckoResult.html
 
-[api-version]: bf7527ba15aeda260dbfb8dd134e963ab062fba8
+[api-version]: 09c473360eb5e17aa801fa0f966cd8671cf2f3d2
--- a/mobile/android/geckoview_example/src/main/java/org/mozilla/geckoview_example/GeckoViewActivity.java
+++ b/mobile/android/geckoview_example/src/main/java/org/mozilla/geckoview_example/GeckoViewActivity.java
@@ -1,16 +1,15 @@
 /* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.geckoview_example;
 
-import org.json.JSONObject;
 import org.mozilla.geckoview.AllowOrDeny;
 import org.mozilla.geckoview.BasicSelectionActionDelegate;
 import org.mozilla.geckoview.ContentBlocking;
 import org.mozilla.geckoview.GeckoResult;
 import org.mozilla.geckoview.GeckoRuntime;
 import org.mozilla.geckoview.GeckoRuntimeSettings;
 import org.mozilla.geckoview.GeckoSession;
 import org.mozilla.geckoview.GeckoSessionSettings;
@@ -529,21 +528,16 @@ public class GeckoViewActivity extends A
             session.open(sGeckoRuntime);
             session.loadUri(DEFAULT_URL);
         }
 
         @Override
         public void onFirstComposite(final GeckoSession session) {
             Log.d(LOGTAG, "onFirstComposite");
         }
-
-        @Override
-        public void onWebAppManifest(final GeckoSession session, JSONObject manifest) {
-            Log.d(LOGTAG, "onWebAppManifest: " + manifest);
-        }
     }
 
     private class ExampleProgressDelegate implements GeckoSession.ProgressDelegate {
         private ExampleContentBlockingDelegate mCb;
 
         private ExampleProgressDelegate(final ExampleContentBlockingDelegate cb) {
             mCb = cb;
         }