зеркало из https://github.com/mozilla/gecko-dev.git
Backed out 3 changesets (bug 1603452, bug 1603114, bug 1577596) for causing lint failure in GeckoSession.java CLOSED TREE
Backed out changeset 1a9be6d049a7 (bug 1577596) Backed out changeset 11e1f382ea77 (bug 1603114) Backed out changeset d63c194d1c6c (bug 1603452)
This commit is contained in:
Родитель
833a7f9e2e
Коммит
00a57ab6c7
|
@ -70,6 +70,3 @@ pref("ui.android.mouse_as_touch", 2);
|
|||
|
||||
// Fenix is currently not whitelisted for Web Authentication
|
||||
pref("security.webauth.webauthn_enable_android_fido2", false);
|
||||
|
||||
// Enable autoplay permission prompts
|
||||
pref("media.geckoview.autoplay.request", true);
|
||||
|
|
|
@ -777,8 +777,6 @@ package org.mozilla.geckoview {
|
|||
method @UiThread default public void onAndroidPermissionsRequest(@NonNull GeckoSession, @Nullable String[], @NonNull GeckoSession.PermissionDelegate.Callback);
|
||||
method @UiThread default public void onContentPermissionRequest(@NonNull GeckoSession, @Nullable String, int, @NonNull GeckoSession.PermissionDelegate.Callback);
|
||||
method @UiThread default public void onMediaPermissionRequest(@NonNull GeckoSession, @NonNull String, @Nullable GeckoSession.PermissionDelegate.MediaSource[], @Nullable GeckoSession.PermissionDelegate.MediaSource[], @NonNull GeckoSession.PermissionDelegate.MediaCallback);
|
||||
field public static final int PERMISSION_AUTOPLAY_AUDIBLE = 4;
|
||||
field public static final int PERMISSION_AUTOPLAY_INAUDIBLE = 3;
|
||||
field public static final int PERMISSION_DESKTOP_NOTIFICATION = 1;
|
||||
field public static final int PERMISSION_GEOLOCATION = 0;
|
||||
field public static final int PERMISSION_PERSISTENT_STORAGE = 2;
|
||||
|
|
|
@ -223,13 +223,12 @@ dependencies {
|
|||
testImplementation 'org.mockito:mockito-core:1.10.19'
|
||||
|
||||
androidTestImplementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
|
||||
androidTestImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.2"
|
||||
androidTestImplementation 'com.android.support.test:runner:1.0.2'
|
||||
androidTestImplementation 'com.android.support.test:rules:1.0.2'
|
||||
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
|
||||
androidTestImplementation "com.android.support:support-annotations:$support_library_version"
|
||||
|
||||
androidTestImplementation 'com.koushikdutta.async:androidasync:2.+'
|
||||
androidTestImplementation 'org.eclipse.jetty:jetty-server:7.6.21.v20160908'
|
||||
}
|
||||
|
||||
apply from: "${topsrcdir}/mobile/android/gradle/with_gecko_binaries.gradle"
|
||||
|
|
|
@ -66,8 +66,6 @@ open class BaseSessionTest(noErrorCollector: Boolean = false) {
|
|||
const val PUSH_HTML_PATH = "/assets/www/push/push.html"
|
||||
const val OPEN_WINDOW_PATH = "/assets/www/worker/open_window.html"
|
||||
const val OPEN_WINDOW_TARGET_PATH = "/assets/www/worker/open_window_target.html"
|
||||
|
||||
const val TEST_ENDPOINT = GeckoSessionTestRule.TEST_ENDPOINT
|
||||
}
|
||||
|
||||
@get:Rule val sessionRule = GeckoSessionTestRule()
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
package org.mozilla.geckoview.test
|
||||
|
||||
import android.support.test.InstrumentationRegistry
|
||||
import org.mozilla.geckoview.AllowOrDeny
|
||||
import org.mozilla.geckoview.ContentBlocking
|
||||
import org.mozilla.geckoview.GeckoResult
|
||||
|
@ -23,15 +24,35 @@ import android.support.test.runner.AndroidJUnit4
|
|||
import org.hamcrest.MatcherAssert
|
||||
import org.hamcrest.Matchers.*
|
||||
import org.json.JSONObject
|
||||
import org.junit.After
|
||||
import org.junit.Before
|
||||
import org.junit.Ignore
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mozilla.geckoview.test.rule.GeckoSessionTestRule
|
||||
import org.mozilla.geckoview.test.util.HttpBin
|
||||
import org.mozilla.geckoview.test.util.UiThreadUtils
|
||||
import java.net.URI
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
@MediumTest
|
||||
class NavigationDelegateTest : BaseSessionTest() {
|
||||
companion object {
|
||||
val TEST_ENDPOINT: String = "http://localhost:4242"
|
||||
}
|
||||
|
||||
lateinit var server: HttpBin
|
||||
|
||||
@Before
|
||||
fun setup() {
|
||||
server = HttpBin(InstrumentationRegistry.getTargetContext(), URI.create(TEST_ENDPOINT))
|
||||
server.start()
|
||||
}
|
||||
|
||||
@After
|
||||
fun cleanup() {
|
||||
server.stop()
|
||||
}
|
||||
|
||||
fun testLoadErrorWithErrorPage(testUri: String, expectedCategory: Int,
|
||||
expectedError: Int,
|
||||
|
|
|
@ -16,13 +16,13 @@ import android.support.test.InstrumentationRegistry
|
|||
import android.support.test.filters.MediumTest
|
||||
import android.support.test.runner.AndroidJUnit4
|
||||
|
||||
import org.junit.Assume.assumeThat
|
||||
import org.hamcrest.Matchers.*
|
||||
import org.json.JSONArray
|
||||
import org.junit.Assert.fail
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.junit.Ignore
|
||||
import org.mozilla.geckoview.GeckoRuntimeSettings
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
@MediumTest
|
||||
|
@ -260,22 +260,6 @@ class PermissionDelegateTest : BaseSessionTest() {
|
|||
result as String, equalTo("denied"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun autoplayReject() {
|
||||
sessionRule.runtime.settings.autoplayDefault = GeckoRuntimeSettings.AUTOPLAY_DEFAULT_BLOCKED
|
||||
|
||||
mainSession.loadTestPath(AUTOPLAY_PATH)
|
||||
|
||||
mainSession.waitUntilCalled(object : Callbacks.PermissionDelegate {
|
||||
@AssertCalled(count = 2)
|
||||
override fun onContentPermissionRequest(session: GeckoSession, uri: String?, type: Int, callback: GeckoSession.PermissionDelegate.Callback) {
|
||||
val expectedType = if (sessionRule.currentCall.counter == 1) GeckoSession.PermissionDelegate.PERMISSION_AUTOPLAY_AUDIBLE else GeckoSession.PermissionDelegate.PERMISSION_AUTOPLAY_INAUDIBLE
|
||||
assertThat("Type should match", type, equalTo(expectedType))
|
||||
callback.reject()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// @Test fun persistentStorage() {
|
||||
// mainSession.loadTestPath(HELLO_HTML_PATH)
|
||||
// mainSession.waitForPageStop()
|
||||
|
|
|
@ -13,11 +13,11 @@ import android.support.test.InstrumentationRegistry
|
|||
import android.support.test.filters.MediumTest
|
||||
import android.support.test.filters.SdkSuppress
|
||||
import android.support.test.runner.AndroidJUnit4
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.runBlocking
|
||||
|
||||
import java.math.BigInteger
|
||||
|
||||
import java.net.URI
|
||||
|
||||
import java.nio.ByteBuffer
|
||||
import java.nio.CharBuffer
|
||||
import java.nio.charset.Charset
|
||||
|
@ -35,10 +35,14 @@ import org.junit.*
|
|||
import org.junit.rules.ExpectedException
|
||||
import org.junit.runner.RunWith
|
||||
import org.junit.Ignore
|
||||
import org.mozilla.geckoview.*
|
||||
|
||||
import org.mozilla.geckoview.GeckoWebExecutor
|
||||
import org.mozilla.geckoview.WebRequest
|
||||
import org.mozilla.geckoview.WebRequestError
|
||||
import org.mozilla.geckoview.WebResponse
|
||||
|
||||
import org.mozilla.geckoview.test.util.HttpBin
|
||||
import org.mozilla.geckoview.test.util.RuntimeCreator
|
||||
import org.mozilla.geckoview.test.util.TestServer
|
||||
import java.io.IOException
|
||||
import java.net.UnknownHostException
|
||||
import java.util.*
|
||||
|
@ -47,12 +51,11 @@ import java.util.*
|
|||
@RunWith(AndroidJUnit4::class)
|
||||
class WebExecutorTest {
|
||||
companion object {
|
||||
const val TEST_PORT: Int = 4242
|
||||
const val TEST_ENDPOINT: String = "http://localhost:${TEST_PORT}"
|
||||
val TEST_ENDPOINT: String = "http://localhost:4242"
|
||||
}
|
||||
|
||||
lateinit var executor: GeckoWebExecutor
|
||||
lateinit var server: TestServer
|
||||
lateinit var server: HttpBin
|
||||
|
||||
@get:Rule val thrown = ExpectedException.none()
|
||||
|
||||
|
@ -62,12 +65,15 @@ class WebExecutorTest {
|
|||
// the tests which are not using @UiThreadTest, so we do that
|
||||
// ourselves here as GeckoRuntime needs to be initialized
|
||||
// on the UI thread.
|
||||
runBlocking(Dispatchers.Main) {
|
||||
val latch = CountDownLatch(1)
|
||||
Handler(Looper.getMainLooper()).post {
|
||||
executor = GeckoWebExecutor(RuntimeCreator.getRuntime())
|
||||
server = HttpBin(InstrumentationRegistry.getTargetContext(), URI.create(TEST_ENDPOINT))
|
||||
server.start()
|
||||
latch.countDown()
|
||||
}
|
||||
|
||||
server = TestServer(InstrumentationRegistry.getTargetContext())
|
||||
server.start(TEST_PORT)
|
||||
latch.await()
|
||||
}
|
||||
|
||||
@After
|
||||
|
@ -92,9 +98,7 @@ class WebExecutorTest {
|
|||
}
|
||||
|
||||
fun WebResponse.getBodyBytes(): ByteBuffer {
|
||||
body!!.use {
|
||||
return ByteBuffer.wrap(it.readBytes())
|
||||
}
|
||||
return ByteBuffer.wrap(body!!.readBytes())
|
||||
}
|
||||
|
||||
fun WebResponse.getJSONBody(): JSONObject {
|
||||
|
@ -136,7 +140,7 @@ class WebExecutorTest {
|
|||
|
||||
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; charset=utf-8"))
|
||||
assertThat("Content type should match", response.headers["Content-Type"], equalTo("application/json"))
|
||||
assertThat("Redirected should match", response.redirected, equalTo(false))
|
||||
|
||||
val body = response.getJSONBody()
|
||||
|
@ -156,9 +160,9 @@ class WebExecutorTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
fun testStatus() {
|
||||
val response = fetch(WebRequest("$TEST_ENDPOINT/status/500"))
|
||||
assertThat("Status code should match", response.statusCode, equalTo(500))
|
||||
fun test404() {
|
||||
val response = fetch(WebRequest("$TEST_ENDPOINT/status/404"))
|
||||
assertThat("Status code should match", response.statusCode, equalTo(404))
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -318,7 +322,7 @@ class WebExecutorTest {
|
|||
|
||||
@Test(expected = IOException::class)
|
||||
fun readClosedStream() {
|
||||
val response = executor.fetch(WebRequest("$TEST_ENDPOINT/bytes/1024")).pollDefault()!!
|
||||
val response = executor.fetch(WebRequest("$TEST_ENDPOINT/anything")).pollDefault()!!
|
||||
|
||||
assertThat("Status code should match", response.statusCode, equalTo(200))
|
||||
|
||||
|
@ -327,10 +331,11 @@ class WebExecutorTest {
|
|||
stream.readBytes()
|
||||
}
|
||||
|
||||
@Ignore //bug 1596314 - disable test for frequent failures
|
||||
@Test(expected = IOException::class)
|
||||
fun readTimeout() {
|
||||
val expectedCount = 10
|
||||
val response = executor.fetch(WebRequest("$TEST_ENDPOINT/trickle/${expectedCount}")).pollDefault()!!
|
||||
val expectedCount = 1 * 1024 * 1024 // 1MB
|
||||
val response = executor.fetch(WebRequest("$TEST_ENDPOINT/bytes/$expectedCount")).pollDefault()!!
|
||||
|
||||
assertThat("Status code should match", response.statusCode, equalTo(200))
|
||||
assertThat("Content-Length should match", response.headers["Content-Length"]!!.toInt(), equalTo(expectedCount))
|
||||
|
|
|
@ -23,7 +23,7 @@ import org.mozilla.geckoview.*
|
|||
import org.mozilla.geckoview.test.rule.GeckoSessionTestRule
|
||||
import org.mozilla.geckoview.test.rule.GeckoSessionTestRule.AssertCalled
|
||||
import org.mozilla.geckoview.test.util.Callbacks
|
||||
import org.mozilla.geckoview.test.util.TestServer
|
||||
import org.mozilla.geckoview.test.util.HttpBin
|
||||
import java.net.URI
|
||||
|
||||
import java.util.UUID
|
||||
|
@ -32,8 +32,7 @@ import java.util.UUID
|
|||
@MediumTest
|
||||
class WebExtensionTest : BaseSessionTest() {
|
||||
companion object {
|
||||
val TEST_PORT: Int = 4243
|
||||
val TEST_ENDPOINT: String = "http://localhost:${TEST_PORT}"
|
||||
val TEST_ENDPOINT: String = "http://localhost:4243"
|
||||
val TABS_CREATE_BACKGROUND: String = "resource://android/assets/web_extensions/tabs-create/"
|
||||
val TABS_CREATE_REMOVE_BACKGROUND: String = "resource://android/assets/web_extensions/tabs-create-remove/"
|
||||
val TABS_REMOVE_BACKGROUND: String = "resource://android/assets/web_extensions/tabs-remove/"
|
||||
|
@ -686,16 +685,16 @@ class WebExtensionTest : BaseSessionTest() {
|
|||
|
||||
@Test
|
||||
fun iframeTopLevel() {
|
||||
val server = TestServer(InstrumentationRegistry.getTargetContext())
|
||||
val httpBin = HttpBin(InstrumentationRegistry.getTargetContext(), URI.create(TEST_ENDPOINT))
|
||||
|
||||
try {
|
||||
server.start(TEST_PORT)
|
||||
httpBin.start()
|
||||
|
||||
mainSession.loadUri("$TEST_ENDPOINT$HELLO_IFRAME_HTML_PATH")
|
||||
sessionRule.waitForPageStop()
|
||||
testIframeTopLevel()
|
||||
} finally {
|
||||
server.stop()
|
||||
httpBin.stop()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@ import org.mozilla.geckoview.GeckoSessionSettings;
|
|||
import org.mozilla.geckoview.RuntimeTelemetry;
|
||||
import org.mozilla.geckoview.SessionTextInput;
|
||||
import org.mozilla.geckoview.WebExtension;
|
||||
import org.mozilla.geckoview.test.util.TestServer;
|
||||
import org.mozilla.geckoview.test.util.HttpBin;
|
||||
import org.mozilla.geckoview.test.util.RuntimeCreator;
|
||||
import org.mozilla.geckoview.test.util.Environment;
|
||||
import org.mozilla.geckoview.test.util.UiThreadUtils;
|
||||
|
@ -64,6 +64,7 @@ import java.lang.reflect.InvocationTargetException;
|
|||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.net.URI;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
|
@ -88,9 +89,7 @@ import kotlin.reflect.KClass;
|
|||
*/
|
||||
public class GeckoSessionTestRule implements TestRule {
|
||||
private static final String LOGTAG = "GeckoSessionTestRule";
|
||||
|
||||
private static final int TEST_PORT = 4245;
|
||||
public static final String TEST_ENDPOINT = "http://localhost:" + TEST_PORT;
|
||||
public static final String TEST_ENDPOINT = "http://localhost:4245";
|
||||
|
||||
private static final Method sOnPageStart;
|
||||
private static final Method sOnPageStop;
|
||||
|
@ -1236,11 +1235,12 @@ public class GeckoSessionTestRule implements TestRule {
|
|||
public void evaluate() throws Throwable {
|
||||
final AtomicReference<Throwable> exceptionRef = new AtomicReference<>();
|
||||
|
||||
TestServer server = new TestServer(InstrumentationRegistry.getTargetContext());
|
||||
HttpBin httpBin = new HttpBin(InstrumentationRegistry.getTargetContext(),
|
||||
URI.create(TEST_ENDPOINT));
|
||||
|
||||
mInstrumentation.runOnMainSync(() -> {
|
||||
try {
|
||||
server.start(TEST_PORT);
|
||||
httpBin.start();
|
||||
|
||||
RuntimeCreator.setPortDelegate(mPortDelegate);
|
||||
|
||||
|
@ -1273,7 +1273,7 @@ public class GeckoSessionTestRule implements TestRule {
|
|||
exceptionRef.set(t);
|
||||
} finally {
|
||||
try {
|
||||
server.stop();
|
||||
httpBin.stop();
|
||||
cleanupStatement();
|
||||
} catch (Throwable t) {
|
||||
exceptionRef.compareAndSet(null, t);
|
||||
|
|
|
@ -0,0 +1,156 @@
|
|||
/*
|
||||
* Copyright 2015-2016 Bounce Storage, Inc. <info@bouncestorage.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* 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;
|
||||
|
||||
import org.eclipse.jetty.server.Server;
|
||||
|
||||
import org.eclipse.jetty.util.log.AbstractLogger;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.util.thread.ExecutorThreadPool;
|
||||
|
||||
/**
|
||||
* Reimplementation of HttpBin http://httpbin.org/ suitable for offline unit
|
||||
* tests.
|
||||
*/
|
||||
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, @NonNull HttpBinHandler handler) {
|
||||
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder(
|
||||
StrictMode.getThreadPolicy())
|
||||
.permitNetwork()
|
||||
.build());
|
||||
|
||||
mServer = new Server(endpoint.getPort());
|
||||
mServer.setHandler(handler);
|
||||
}
|
||||
|
||||
public void start() throws Exception {
|
||||
mServer.start();
|
||||
}
|
||||
|
||||
public void stop() throws Exception {
|
||||
mServer.stop();
|
||||
}
|
||||
|
||||
public int getPort() {
|
||||
return mServer.getConnectors()[0].getLocalPort();
|
||||
}
|
||||
|
||||
// We need this because the default Logger tries to use some things
|
||||
// that don't exist in older versions of Android
|
||||
private static class AndroidLogger extends AbstractLogger {
|
||||
private boolean mDebugEnabled;
|
||||
|
||||
@Override
|
||||
protected Logger newLogger(String fullname) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warn(String msg, Object... args) {
|
||||
Log.w(LOGTAG, String.format(msg, args));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warn(Throwable thrown) {
|
||||
Log.w(LOGTAG, thrown);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warn(String msg, Throwable thrown) {
|
||||
Log.w(LOGTAG, msg, thrown);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void info(String msg, Object... args) {
|
||||
Log.i(LOGTAG, String.format(msg, args));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void info(Throwable thrown) {
|
||||
Log.i(LOGTAG, thrown.getMessage(), thrown);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void info(String msg, Throwable thrown) {
|
||||
Log.i(LOGTAG, msg, thrown);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDebugEnabled() {
|
||||
return mDebugEnabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDebugEnabled(boolean enabled) {
|
||||
mDebugEnabled = enabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debug(String msg, Object... args) {
|
||||
if (mDebugEnabled) {
|
||||
Log.d(LOGTAG, String.format(msg, args));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debug(Throwable thrown) {
|
||||
if (mDebugEnabled) {
|
||||
Log.d(LOGTAG, thrown.getMessage(), thrown);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debug(String msg, Throwable thrown) {
|
||||
if (mDebugEnabled) {
|
||||
Log.d(LOGTAG, msg, thrown);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void ignore(Throwable ignored) {
|
||||
// This is pretty spammy
|
||||
if (mDebugEnabled) {
|
||||
Log.w(LOGTAG, "Ignored Exception: ", ignored);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
|
@ -0,0 +1,226 @@
|
|||
/*
|
||||
* Copyright 2015-2016 Bounce Storage, Inc. <info@bouncestorage.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* 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;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Random;
|
||||
|
||||
import javax.servlet.http.Cookie;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.server.handler.AbstractHandler;
|
||||
|
||||
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;
|
||||
while ((count = is.read(buf)) > 0) {
|
||||
if (os != null) {
|
||||
os.write(buf, 0, count);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void respondJSON(HttpServletResponse response, OutputStream os, JSONObject obj)
|
||||
throws IOException {
|
||||
final byte[] body = obj.toString().getBytes();
|
||||
|
||||
response.setContentLength(body.length);
|
||||
response.setContentType("application/json");
|
||||
response.setStatus(HttpServletResponse.SC_OK);
|
||||
os.write(body);
|
||||
os.flush();
|
||||
}
|
||||
|
||||
private void redirectTo(HttpServletResponse response, String location) {
|
||||
response.setHeader("Location", location);
|
||||
response.setStatus(HttpServletResponse.SC_MOVED_TEMPORARILY);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void handle(String target, Request baseRequest,
|
||||
HttpServletRequest request, HttpServletResponse servletResponse)
|
||||
throws IOException {
|
||||
String method = request.getMethod();
|
||||
String uri = request.getRequestURI();
|
||||
try (InputStream is = request.getInputStream();
|
||||
OutputStream os = servletResponse.getOutputStream()) {
|
||||
if (method.equals("GET") && uri.startsWith("/status/")) {
|
||||
pipe(is);
|
||||
int status = Integer.parseInt(uri.substring(
|
||||
"/status/".length()));
|
||||
servletResponse.setStatus(status);
|
||||
baseRequest.setHandled(true);
|
||||
} else if (uri.equals("/redirect-to")) {
|
||||
pipe(is);
|
||||
redirectTo(servletResponse, request.getParameter("url"));
|
||||
baseRequest.setHandled(true);
|
||||
} else if (uri.startsWith("/redirect/")) {
|
||||
pipe(is);
|
||||
|
||||
int count = Integer.parseInt(uri.substring("/redirect/".length())) - 1;
|
||||
if (count > 0) {
|
||||
redirectTo(servletResponse, "/redirect/" + count);
|
||||
} else {
|
||||
servletResponse.setStatus(HttpServletResponse.SC_OK);
|
||||
}
|
||||
|
||||
baseRequest.setHandled(true);
|
||||
} else if (uri.equals("/cookies")) {
|
||||
pipe(is);
|
||||
|
||||
final JSONObject cookies = new JSONObject();
|
||||
|
||||
if (request.getCookies() != null) {
|
||||
for (final Cookie cookie : request.getCookies()) {
|
||||
cookies.put(cookie.getName(), cookie.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
final JSONObject response = new JSONObject();
|
||||
response.put("cookies", cookies);
|
||||
|
||||
respondJSON(servletResponse, os, response);
|
||||
baseRequest.setHandled(true);
|
||||
} else if (uri.startsWith("/cookies/set/")) {
|
||||
pipe(is);
|
||||
|
||||
final String[] parts = uri.substring("/cookies/set/".length()).split("/");
|
||||
|
||||
servletResponse.addHeader("Set-Cookie",
|
||||
String.format("%s=%s; Path=/", parts[0], parts[1]));
|
||||
|
||||
servletResponse.setHeader("Location", "/cookies");
|
||||
servletResponse.setStatus(HttpServletResponse.SC_MOVED_TEMPORARILY);
|
||||
baseRequest.setHandled(true);
|
||||
} else if (uri.startsWith("/basic-auth")) {
|
||||
pipe(is);
|
||||
|
||||
// FIXME: we don't actually check the username/password here
|
||||
servletResponse.addHeader("WWW-Authenticate",
|
||||
"Basic realm=\"Fake Realm\"");
|
||||
servletResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
|
||||
baseRequest.setHandled(true);
|
||||
} else if (uri.equals("/anything")) {
|
||||
servletResponse.setStatus(HttpServletResponse.SC_OK);
|
||||
baseRequest.setHandled(true);
|
||||
|
||||
final JSONObject response = new JSONObject();
|
||||
|
||||
// Method
|
||||
response.put("method", method);
|
||||
|
||||
// Headers
|
||||
final JSONObject headers = new JSONObject();
|
||||
response.put("headers", headers);
|
||||
|
||||
for (Enumeration<String> names = request.getHeaderNames(); names.hasMoreElements();) {
|
||||
final String name = names.nextElement();
|
||||
headers.put(name, request.getHeader(name));
|
||||
}
|
||||
|
||||
// Body data
|
||||
final ByteArrayOutputStream data = new ByteArrayOutputStream();
|
||||
pipe(is, data);
|
||||
|
||||
response.put("data", data.toString("UTF-8"));
|
||||
respondJSON(servletResponse, os, response);
|
||||
baseRequest.setHandled(true);
|
||||
} else if (uri.startsWith("/bytes")) {
|
||||
pipe(is);
|
||||
|
||||
final int count = Integer.parseInt(uri.substring("/bytes/".length()));
|
||||
|
||||
final Random random = new Random(System.currentTimeMillis());
|
||||
final byte[] payload = new byte[count];
|
||||
random.nextBytes(payload);
|
||||
|
||||
servletResponse.setStatus(HttpServletResponse.SC_OK);
|
||||
servletResponse.setContentLength(count);
|
||||
servletResponse.setContentType("application/octet-stream");
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,144 +0,0 @@
|
|||
package org.mozilla.geckoview.test.util
|
||||
|
||||
import android.content.Context
|
||||
import android.content.res.AssetManager
|
||||
import android.os.SystemClock
|
||||
import android.webkit.MimeTypeMap
|
||||
import com.koushikdutta.async.ByteBufferList
|
||||
import com.koushikdutta.async.http.server.AsyncHttpServer
|
||||
import com.koushikdutta.async.http.server.AsyncHttpServerRequest
|
||||
import com.koushikdutta.async.http.server.AsyncHttpServerResponse
|
||||
import com.koushikdutta.async.util.TaggedList
|
||||
import org.json.JSONObject
|
||||
import java.io.FileNotFoundException
|
||||
import java.math.BigInteger
|
||||
import java.security.MessageDigest
|
||||
import java.util.*
|
||||
|
||||
class TestServer {
|
||||
private val server = AsyncHttpServer()
|
||||
private val assets: AssetManager
|
||||
|
||||
constructor(context: Context) {
|
||||
assets = context.resources.assets
|
||||
|
||||
val anything = { request: AsyncHttpServerRequest, response: AsyncHttpServerResponse ->
|
||||
val obj = JSONObject()
|
||||
|
||||
obj.put("method", request.method)
|
||||
|
||||
val headers = JSONObject()
|
||||
for (key in request.headers.multiMap.keys) {
|
||||
val values = request.headers.multiMap.get(key) as TaggedList<String>
|
||||
headers.put(values.tag(), values.joinToString(", "))
|
||||
}
|
||||
|
||||
obj.put("headers", headers)
|
||||
|
||||
if (request.method == "POST") {
|
||||
obj.put("data", request.body.get() as String)
|
||||
}
|
||||
|
||||
response.send(obj)
|
||||
}
|
||||
|
||||
server.post("/anything", anything)
|
||||
server.get("/anything", anything)
|
||||
|
||||
server.get("/assets/.*") { request, response ->
|
||||
try {
|
||||
val mimeType = MimeTypeMap.getSingleton()
|
||||
.getMimeTypeFromExtension(MimeTypeMap.getFileExtensionFromUrl(request.path))
|
||||
val name = request.path.substring("/assets/".count())
|
||||
val asset = assets.open(name).readBytes()
|
||||
|
||||
response.send(mimeType, asset)
|
||||
} catch (e: FileNotFoundException) {
|
||||
response.code(404)
|
||||
response.end()
|
||||
}
|
||||
}
|
||||
|
||||
server.get("/status/.*") { request, response ->
|
||||
val statusCode = request.path.substring("/status/".count()).toInt()
|
||||
response.code(statusCode)
|
||||
response.end()
|
||||
}
|
||||
|
||||
server.get("/redirect-to.*") { request, response ->
|
||||
response.redirect(request.query.getString("url"))
|
||||
}
|
||||
|
||||
server.get("/redirect/.*") { request, response ->
|
||||
val count = request.path.split('/').last().toInt() - 1
|
||||
if (count > 0) {
|
||||
response.redirect("/redirect/${count}")
|
||||
}
|
||||
|
||||
response.end()
|
||||
}
|
||||
|
||||
server.get("/basic-auth/.*") { _, response ->
|
||||
response.code(401)
|
||||
response.headers.set("WWW-Authenticate", "Basic realm=\"Fake Realm\"")
|
||||
response.end()
|
||||
}
|
||||
|
||||
server.get("/cookies") { request, response ->
|
||||
val cookiesObj = JSONObject()
|
||||
|
||||
request.headers.get("cookie")?.split(";")?.forEach {
|
||||
val parts = it.trim().split('=')
|
||||
cookiesObj.put(parts[0], parts[1])
|
||||
}
|
||||
|
||||
val obj = JSONObject()
|
||||
obj.put("cookies", cookiesObj)
|
||||
response.send(obj)
|
||||
}
|
||||
|
||||
server.get("/cookies/set/.*") { request, response ->
|
||||
val parts = request.path.substring("/cookies/set/".count()).split('/')
|
||||
|
||||
response.headers.set("Set-Cookie", "${parts[0]}=${parts[1]}; Path=/")
|
||||
response.headers.set("Location", "/cookies")
|
||||
response.code(302)
|
||||
response.end()
|
||||
}
|
||||
|
||||
server.get("/bytes/.*") { request, response ->
|
||||
val count = request.path.split("/").last().toInt()
|
||||
val random = Random(System.currentTimeMillis())
|
||||
val payload = ByteArray(count)
|
||||
random.nextBytes(payload)
|
||||
|
||||
val digest = MessageDigest.getInstance("SHA-256").digest(payload)
|
||||
response.headers.set("X-SHA-256", String.format("%064x", BigInteger(1, digest)))
|
||||
response.send("application/octet-stream", payload)
|
||||
}
|
||||
|
||||
server.get("/trickle/.*") { request, response ->
|
||||
val count = request.path.split("/").last().toInt()
|
||||
|
||||
response.setContentType("application/octet-stream")
|
||||
response.headers.set("Content-Length", "${count}")
|
||||
response.writeHead()
|
||||
|
||||
val payload = byteArrayOf(1)
|
||||
for (i in 1..count) {
|
||||
response.write(ByteBufferList(payload))
|
||||
SystemClock.sleep(250)
|
||||
}
|
||||
|
||||
response.end()
|
||||
}
|
||||
}
|
||||
|
||||
fun start(port: Int) {
|
||||
server.listen(port)
|
||||
}
|
||||
|
||||
fun stop() {
|
||||
server.stop()
|
||||
}
|
||||
}
|
|
@ -47,11 +47,6 @@ import java.util.LinkedList;
|
|||
public synchronized void close() throws IOException {
|
||||
super.close();
|
||||
mClosed = true;
|
||||
|
||||
if (mSupport != null) {
|
||||
mSupport.close();
|
||||
mSupport = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -197,9 +192,6 @@ import java.util.LinkedList;
|
|||
@WrapForJNI(dispatchTo = "gecko")
|
||||
private native void resume();
|
||||
|
||||
@WrapForJNI(dispatchTo = "gecko")
|
||||
private native void close();
|
||||
|
||||
@Override // JNIObject
|
||||
protected void disposeNative() {
|
||||
throw new UnsupportedOperationException();
|
||||
|
|
|
@ -774,6 +774,7 @@ public class GeckoSession implements Parcelable {
|
|||
final String event,
|
||||
final GeckoBundle message,
|
||||
final EventCallback callback) {
|
||||
|
||||
if (delegate == null) {
|
||||
callback.sendSuccess(/* granted */ false);
|
||||
return;
|
||||
|
@ -798,10 +799,6 @@ public class GeckoSession implements Parcelable {
|
|||
// doesn't support Web MIDI.
|
||||
callback.sendError("Unsupported");
|
||||
return;
|
||||
} else if ("autoplay-media-inaudible".equals(typeString)) {
|
||||
type = PermissionDelegate.PERMISSION_AUTOPLAY_INAUDIBLE;
|
||||
} else if ("autoplay-media-audible".equals(typeString)) {
|
||||
type = PermissionDelegate.PERMISSION_AUTOPLAY_AUDIBLE;
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unknown permission request: " + typeString);
|
||||
}
|
||||
|
@ -4970,16 +4967,6 @@ public class GeckoSession implements Parcelable {
|
|||
*/
|
||||
int PERMISSION_XR = 3;
|
||||
|
||||
/**
|
||||
* Permission for allowing autoplay of inaudible (silent) video.
|
||||
*/
|
||||
int PERMISSION_AUTOPLAY_INAUDIBLE = 3;
|
||||
|
||||
/**
|
||||
* Permission for allowing autoplay of audible video.
|
||||
*/
|
||||
int PERMISSION_AUTOPLAY_AUDIBLE = 4;
|
||||
|
||||
/**
|
||||
* Callback interface for notifying the result of a permission request.
|
||||
*/
|
||||
|
@ -5230,10 +5217,7 @@ public class GeckoSession implements Parcelable {
|
|||
@Retention(RetentionPolicy.SOURCE)
|
||||
@IntDef({PermissionDelegate.PERMISSION_GEOLOCATION,
|
||||
PermissionDelegate.PERMISSION_DESKTOP_NOTIFICATION,
|
||||
PermissionDelegate.PERMISSION_PERSISTENT_STORAGE,
|
||||
PermissionDelegate.PERMISSION_XR,
|
||||
PermissionDelegate.PERMISSION_AUTOPLAY_INAUDIBLE,
|
||||
PermissionDelegate.PERMISSION_AUTOPLAY_AUDIBLE})
|
||||
PermissionDelegate.PERMISSION_XR})
|
||||
/* package */ @interface Permission {}
|
||||
|
||||
/**
|
||||
|
|
|
@ -26,10 +26,7 @@ exclude: true
|
|||
attaching a [`LoginStorage.Delegate`][73.8] via
|
||||
[`GeckoRuntime#setLoginStorageDelegate`][73.9]
|
||||
([bug 1602881]({{bugzilla}}1602881))
|
||||
- Added [`GeckoSession.PermissionDelegate#PERMISSION_AUTOPLAY_AUDIBLE`][73.10] and
|
||||
[`GeckoSession.PermissionDelegate#PERMISSION_AUTOPLAY_INAUDIBLE`][73.11]. These control
|
||||
autoplay permissions for audible and inaudible videos.
|
||||
([bug 1577596]({{bugzilla}}1577596))
|
||||
|
||||
|
||||
[73.1]: {{javadoc_uri}}/WebExtensionController.html#install-java.lang.String-
|
||||
[73.2]: {{javadoc_uri}}/WebExtensionController.html#uninstall-org.mozilla.geckoview.WebExtension-
|
||||
|
@ -40,8 +37,6 @@ exclude: true
|
|||
[73.7]: {{javadoc_uri}}/LoginStorage.html
|
||||
[73.8]: {{javadoc_uri}}/LoginStorage.Delegate.html
|
||||
[73.9]: {{javadoc_uri}}/GeckoRuntime.html#setLoginStorageDelegate-org.mozilla.geckoview.LoginStorage.Delegate-
|
||||
[73.10]: {{javadoc_uri}}/GeckoSession.PermissionDelegate.html#PERMISSION_AUTOPLAY_AUDIBLE
|
||||
[73.11]: {{javadoc_uri}}/GeckoSession.PermissionDelegate.html#PERMISSION_AUTOPLAY_INAUDIBLE
|
||||
|
||||
## v72
|
||||
- Added [`GeckoSession.NavigationDelegate.LoadRequest#hasUserGesture`][72.1]. This indicates
|
||||
|
@ -110,10 +105,9 @@ exclude: true
|
|||
[72.20]: https://developer.android.com/reference/java/lang/String
|
||||
[72.21]: {{javadoc_uri}}/WebExtension.Icon.html
|
||||
[72.22]: {{javadoc_uri}}/GeckoWebExecutor.html#FETCH_FLAGS_STREAM_FAILURE_TEST
|
||||
[72.23]: {{javadoc_uri}}/CrashReporter.html#sendCrashReport-android.content.Context-java.io.File-org.json.JSONObject-
|
||||
[72.23]: {{javadoc_uri}}/CrashReporter#sendCrashReport-android.content.Context-java.io.File-org.json.JSONObject-
|
||||
[72.24]: {{javadoc_uri}}/GeckoSession.PermissionDelegate.html#PERMISSION_PERSISTENT_XR
|
||||
|
||||
=
|
||||
## v71
|
||||
- Added a content blocking flag for blocked social cookies to [`ContentBlocking`][70.17].
|
||||
([bug 1584479]({{bugzilla}}1584479))
|
||||
|
@ -510,4 +504,4 @@ exclude: true
|
|||
[65.24]: {{javadoc_uri}}/CrashReporter.html#sendCrashReport-android.content.Context-android.os.Bundle-java.lang.String-
|
||||
[65.25]: {{javadoc_uri}}/GeckoResult.html
|
||||
|
||||
[api-version]: 53eef399f685d92e66c3af73363522edebd3ea93
|
||||
[api-version]: 07ee732ba2eaafada09739c61c0196e427a2f0ed
|
||||
|
|
|
@ -269,7 +269,6 @@ public class GeckoViewActivity
|
|||
|
||||
private boolean mShowNotificationsRejected;
|
||||
private ArrayList<String> mAcceptedPersistentStorage = new ArrayList<String>();
|
||||
private ArrayList<String> mAcceptedAutoplay = new ArrayList<>();
|
||||
|
||||
private ToolbarLayout mToolbarView;
|
||||
private String mCurrentUri;
|
||||
|
@ -1134,26 +1133,6 @@ public class GeckoViewActivity
|
|||
}
|
||||
}
|
||||
|
||||
class ExampleAutoplayCallback implements GeckoSession.PermissionDelegate.Callback {
|
||||
private final GeckoSession.PermissionDelegate.Callback mCallback;
|
||||
private final String mUri;
|
||||
ExampleAutoplayCallback(final GeckoSession.PermissionDelegate.Callback callback, String uri) {
|
||||
mCallback = callback;
|
||||
mUri = uri;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reject() {
|
||||
mCallback.reject();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void grant() {
|
||||
mAcceptedAutoplay.add(mUri);
|
||||
mCallback.grant();
|
||||
}
|
||||
}
|
||||
|
||||
public void onRequestPermissionsResult(final String[] permissions,
|
||||
final int[] grantResults) {
|
||||
if (mCallback == null) {
|
||||
|
@ -1201,7 +1180,7 @@ public class GeckoViewActivity
|
|||
contentPermissionCallback = new ExampleNotificationCallback(callback);
|
||||
} else if (PERMISSION_PERSISTENT_STORAGE == type) {
|
||||
if (mAcceptedPersistentStorage.contains(uri)) {
|
||||
Log.w(LOGTAG, "Persistent Storage for " + uri + " already granted by user.");
|
||||
Log.w(LOGTAG, "Persistent Storage for "+ uri +" already granted by user.");
|
||||
callback.grant();
|
||||
return;
|
||||
}
|
||||
|
@ -1209,15 +1188,6 @@ public class GeckoViewActivity
|
|||
contentPermissionCallback = new ExamplePersistentStorageCallback(callback, uri);
|
||||
} else if (PERMISSION_XR == type) {
|
||||
resId = R.string.request_xr;
|
||||
} else if (PERMISSION_AUTOPLAY_AUDIBLE == type || PERMISSION_AUTOPLAY_INAUDIBLE == type) {
|
||||
if (mAcceptedAutoplay.contains(uri)) {
|
||||
Log.w(LOGTAG, "Autoplay for " + uri + " already granted by user.");
|
||||
callback.grant();
|
||||
return;
|
||||
}
|
||||
|
||||
resId = R.string.request_autoplay;
|
||||
contentPermissionCallback = new ExampleAutoplayCallback(callback, uri);
|
||||
} else {
|
||||
Log.w(LOGTAG, "Unknown permission: " + type);
|
||||
callback.reject();
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
<string name="request_audio">Share audio with "%1$s"</string>
|
||||
<string name="request_media">Share video and audio with "%1$s"</string>
|
||||
<string name="request_xr">Share WebXR displays with "%1$s"?</string>
|
||||
<string name="request_autoplay">Allow video to autoplay on "%1$s"?</string>
|
||||
<string name="media_back_camera">Back camera</string>
|
||||
<string name="media_front_camera">Front camera</string>
|
||||
<string name="media_microphone">Microphone</string>
|
||||
|
|
|
@ -143,24 +143,14 @@ class StreamSupport final
|
|||
public:
|
||||
typedef java::GeckoInputStream::Support::Natives<StreamSupport> Base;
|
||||
using Base::AttachNative;
|
||||
using Base::DisposeNative;
|
||||
using Base::GetNative;
|
||||
|
||||
explicit StreamSupport(java::GeckoInputStream::Support::Param aInstance,
|
||||
nsIRequest* aRequest)
|
||||
: mInstance(aInstance), mRequest(aRequest) {}
|
||||
|
||||
void Close() {
|
||||
mRequest->Cancel(NS_ERROR_ABORT);
|
||||
mRequest->Resume();
|
||||
|
||||
// This is basically `delete this`, so don't run anything else!
|
||||
Base::DisposeNative(mInstance);
|
||||
}
|
||||
explicit StreamSupport(nsIRequest* aRequest) : mRequest(aRequest) {}
|
||||
|
||||
void Resume() { mRequest->Resume(); }
|
||||
|
||||
private:
|
||||
java::GeckoInputStream::Support::GlobalRef mInstance;
|
||||
nsCOMPtr<nsIRequest> mRequest;
|
||||
};
|
||||
|
||||
|
@ -193,8 +183,8 @@ class LoaderListener final : public nsIStreamListener,
|
|||
|
||||
// We're expecting data later via OnDataAvailable, so create the stream now.
|
||||
mSupport = java::GeckoInputStream::Support::New();
|
||||
StreamSupport::AttachNative(
|
||||
mSupport, mozilla::MakeUnique<StreamSupport>(mSupport, aRequest));
|
||||
StreamSupport::AttachNative(mSupport,
|
||||
mozilla::MakeUnique<StreamSupport>(aRequest));
|
||||
|
||||
mStream = java::GeckoInputStream::New(mSupport);
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче