зеркало из https://github.com/mozilla/gecko-dev.git
Backed out changeset 22970015ff0c (bug 1815739) for saveAContentPdfDocument related junit failures. CLOSED TREE
This commit is contained in:
Родитель
e719890e40
Коммит
c3f330e9fb
|
@ -1,47 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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/. */
|
||||
|
||||
#include "GeckoViewContentChannel.h"
|
||||
#include "GeckoViewInputStream.h"
|
||||
#include "mozilla/java/ContentInputStreamWrappers.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
GeckoViewContentChannel::GeckoViewContentChannel(nsIURI* aURI) {
|
||||
SetURI(aURI);
|
||||
SetOriginalURI(aURI);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
GeckoViewContentChannel::OpenContentStream(bool aAsync,
|
||||
nsIInputStream** aResult,
|
||||
nsIChannel** aChannel) {
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
nsresult rv = GetURI(getter_AddRefs(uri));
|
||||
NS_ENSURE_SUCCESS(rv, NS_ERROR_MALFORMED_URI);
|
||||
|
||||
nsAutoCString spec;
|
||||
rv = uri->GetSpec(spec);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
bool isReadable = GeckoViewContentInputStream::isReadable(spec);
|
||||
if (!isReadable) {
|
||||
return NS_ERROR_FILE_NOT_FOUND;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIInputStream> inputStream;
|
||||
rv = GeckoViewContentInputStream::getInstance(spec,
|
||||
getter_AddRefs(inputStream));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (NS_WARN_IF(!inputStream)) {
|
||||
return NS_ERROR_MALFORMED_URI;
|
||||
}
|
||||
|
||||
inputStream.forget(aResult);
|
||||
|
||||
return NS_OK;
|
||||
}
|
|
@ -1,23 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cin: */
|
||||
/* 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/. */
|
||||
|
||||
#ifndef GeckoViewContentChannel_h__
|
||||
#define GeckoViewContentChannel_h__
|
||||
|
||||
#include "nsBaseChannel.h"
|
||||
|
||||
class GeckoViewContentChannel final : public nsBaseChannel {
|
||||
public:
|
||||
explicit GeckoViewContentChannel(nsIURI* aUri);
|
||||
|
||||
private:
|
||||
~GeckoViewContentChannel() = default;
|
||||
|
||||
nsresult OpenContentStream(bool async, nsIInputStream** result,
|
||||
nsIChannel** channel) override;
|
||||
};
|
||||
|
||||
#endif // !GeckoViewContentChannel_h__
|
|
@ -1,54 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
// vim:ts=4 sw=2 sts=2 et cin:
|
||||
/* 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/. */
|
||||
|
||||
#include "GeckoViewContentProtocolHandler.h"
|
||||
#include "GeckoViewContentChannel.h"
|
||||
#include "nsStandardURL.h"
|
||||
#include "nsURLHelper.h"
|
||||
#include "nsIURIMutator.h"
|
||||
|
||||
#include "nsNetUtil.h"
|
||||
|
||||
#include "mozilla/ResultExtensions.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
nsresult GeckoViewContentProtocolHandler::Init() { return NS_OK; }
|
||||
|
||||
NS_IMPL_ISUPPORTS(GeckoViewContentProtocolHandler, nsIProtocolHandler,
|
||||
nsISupportsWeakReference)
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// nsIProtocolHandler methods:
|
||||
|
||||
NS_IMETHODIMP
|
||||
GeckoViewContentProtocolHandler::GetScheme(nsACString& result) {
|
||||
result.AssignLiteral("content");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
GeckoViewContentProtocolHandler::NewChannel(nsIURI* uri, nsILoadInfo* aLoadInfo,
|
||||
nsIChannel** result) {
|
||||
nsresult rv;
|
||||
RefPtr<GeckoViewContentChannel> chan = new GeckoViewContentChannel(uri);
|
||||
|
||||
rv = chan->SetLoadInfo(aLoadInfo);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
chan.forget(result);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
GeckoViewContentProtocolHandler::AllowPort(int32_t port, const char* scheme,
|
||||
bool* result) {
|
||||
// don't override anything.
|
||||
*result = false;
|
||||
return NS_OK;
|
||||
}
|
|
@ -1,27 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* 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/. */
|
||||
|
||||
#ifndef GeckoViewContentProtocolHandler_h__
|
||||
#define GeckoViewContentProtocolHandler_h__
|
||||
|
||||
#include "nsIProtocolHandler.h"
|
||||
#include "nsWeakReference.h"
|
||||
|
||||
class nsIURIMutator;
|
||||
|
||||
class GeckoViewContentProtocolHandler : public nsIProtocolHandler,
|
||||
public nsSupportsWeakReference {
|
||||
virtual ~GeckoViewContentProtocolHandler() = default;
|
||||
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSIPROTOCOLHANDLER
|
||||
|
||||
GeckoViewContentProtocolHandler() = default;
|
||||
|
||||
[[nodiscard]] nsresult Init();
|
||||
};
|
||||
|
||||
#endif // !GeckoViewContentProtocolHandler_h__
|
|
@ -1,110 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cin: */
|
||||
/* 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/. */
|
||||
|
||||
#include "GeckoViewInputStream.h"
|
||||
#include "nsStreamUtils.h"
|
||||
|
||||
NS_IMPL_ISUPPORTS(GeckoViewInputStream, nsIInputStream);
|
||||
|
||||
NS_IMETHODIMP
|
||||
GeckoViewInputStream::Close() {
|
||||
mClosed = true;
|
||||
mInstance->Close();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
GeckoViewInputStream::Available(uint64_t* aCount) {
|
||||
if (mClosed) {
|
||||
return NS_BASE_STREAM_CLOSED;
|
||||
}
|
||||
|
||||
*aCount = static_cast<uint64_t>(mInstance->Available());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
GeckoViewInputStream::StreamStatus() {
|
||||
return mClosed ? NS_BASE_STREAM_CLOSED : NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
GeckoViewInputStream::Read(char* aBuf, uint32_t aCount, uint32_t* aReadCount) {
|
||||
return ReadSegments(NS_CopySegmentToBuffer, aBuf, aCount, aReadCount);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
GeckoViewInputStream::ReadSegments(nsWriteSegmentFun writer, void* aClosure,
|
||||
uint32_t aCount, uint32_t* result) {
|
||||
NS_ASSERTION(result, "null ptr");
|
||||
|
||||
if (mClosed) {
|
||||
return NS_BASE_STREAM_CLOSED;
|
||||
}
|
||||
|
||||
auto bufferAddress =
|
||||
static_cast<const char*>(mInstance->MBuffer()->Address());
|
||||
uint32_t segmentPos = static_cast<uint32_t>(mInstance->MPos());
|
||||
int32_t dataLength = 0;
|
||||
nsresult rv;
|
||||
|
||||
*result = 0;
|
||||
while (aCount) {
|
||||
rv = mInstance->Read(static_cast<int64_t>(aCount), &dataLength);
|
||||
if (NS_FAILED(rv)) {
|
||||
return NS_BASE_STREAM_OSERROR;
|
||||
}
|
||||
|
||||
if (dataLength == -1) {
|
||||
break;
|
||||
}
|
||||
|
||||
uint32_t uDataLength = static_cast<uint32_t>(dataLength);
|
||||
uint32_t written;
|
||||
rv = writer(this, aClosure, bufferAddress + segmentPos, *result,
|
||||
uDataLength, &written);
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
// InputStreams do not propagate errors to caller.
|
||||
break;
|
||||
}
|
||||
|
||||
NS_ASSERTION(written > 0, "Must have written something");
|
||||
|
||||
*result += written;
|
||||
aCount -= written;
|
||||
|
||||
segmentPos = static_cast<uint32_t>(mInstance->ConsumedData(written));
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
GeckoViewInputStream::IsNonBlocking(bool* aNonBlocking) {
|
||||
*aNonBlocking = true;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool GeckoViewInputStream::isClosed() const { return mInstance->IsClosed(); }
|
||||
|
||||
bool GeckoViewContentInputStream::isReadable(const nsAutoCString& aUri) {
|
||||
return mozilla::java::ContentInputStream::IsReadable(
|
||||
mozilla::jni::StringParam(aUri));
|
||||
}
|
||||
|
||||
nsresult GeckoViewContentInputStream::getInstance(const nsAutoCString& aUri,
|
||||
nsIInputStream** aInstance) {
|
||||
RefPtr<GeckoViewContentInputStream> instance =
|
||||
new GeckoViewContentInputStream(aUri);
|
||||
if (instance->isClosed()) {
|
||||
return NS_ERROR_FILE_NOT_FOUND;
|
||||
}
|
||||
*aInstance = instance.forget().take();
|
||||
|
||||
return NS_OK;
|
||||
}
|
|
@ -1,43 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cin: */
|
||||
/* 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/. */
|
||||
|
||||
#ifndef GeckoViewInputStream_h__
|
||||
#define GeckoViewInputStream_h__
|
||||
|
||||
#include "mozilla/java/GeckoViewInputStreamWrappers.h"
|
||||
#include "mozilla/java/ContentInputStreamWrappers.h"
|
||||
#include "nsIInputStream.h"
|
||||
|
||||
class GeckoViewInputStream : public nsIInputStream {
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIINPUTSTREAM
|
||||
|
||||
explicit GeckoViewInputStream(
|
||||
mozilla::java::GeckoViewInputStream::LocalRef aInstance)
|
||||
: mInstance(aInstance){};
|
||||
bool isClosed() const;
|
||||
|
||||
protected:
|
||||
virtual ~GeckoViewInputStream() = default;
|
||||
|
||||
private:
|
||||
mozilla::java::GeckoViewInputStream::LocalRef mInstance;
|
||||
bool mClosed{false};
|
||||
};
|
||||
|
||||
class GeckoViewContentInputStream final : public GeckoViewInputStream {
|
||||
public:
|
||||
static nsresult getInstance(const nsAutoCString& aUri,
|
||||
nsIInputStream** aInstance);
|
||||
static bool isReadable(const nsAutoCString& aUri);
|
||||
|
||||
private:
|
||||
explicit GeckoViewContentInputStream(const nsAutoCString& aUri)
|
||||
: GeckoViewInputStream(mozilla::java::ContentInputStream::GetInstance(
|
||||
mozilla::jni::StringParam(aUri))) {}
|
||||
};
|
||||
|
||||
#endif // !GeckoViewInputStream_h__
|
|
@ -77,20 +77,6 @@ Classes = [
|
|||
'headers': ['GeckoViewExternalAppService.h'],
|
||||
'processes': ProcessSelector.ALLOW_IN_SOCKET_PROCESS,
|
||||
},
|
||||
{
|
||||
'cid': '{a8f4582e-4b47-4e06-970d-b94b76977bf7}',
|
||||
'contract_ids': ['@mozilla.org/network/protocol;1?name=content'],
|
||||
'type': 'GeckoViewContentProtocolHandler',
|
||||
'headers': ['./GeckoViewContentProtocolHandler.h'],
|
||||
'protocol_config': {
|
||||
'scheme': 'content',
|
||||
'flags': [
|
||||
'URI_IS_POTENTIALLY_TRUSTWORTHY',
|
||||
'URI_IS_LOCAL_RESOURCE',
|
||||
'URI_DANGEROUS_TO_LOAD',
|
||||
],
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
if defined('MOZ_ANDROID_HISTORY'):
|
||||
|
|
|
@ -5,19 +5,13 @@
|
|||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
SOURCES += [
|
||||
"GeckoViewContentChannel.cpp",
|
||||
"GeckoViewContentProtocolHandler.cpp",
|
||||
"GeckoViewExternalAppService.cpp",
|
||||
"GeckoViewInputStream.cpp",
|
||||
"GeckoViewOutputStream.cpp",
|
||||
"GeckoViewStreamListener.cpp",
|
||||
]
|
||||
|
||||
EXPORTS += [
|
||||
"GeckoViewContentChannel.h",
|
||||
"GeckoViewContentProtocolHandler.h",
|
||||
"GeckoViewExternalAppService.h",
|
||||
"GeckoViewInputStream.h",
|
||||
"GeckoViewOutputStream.h",
|
||||
"GeckoViewStreamListener.h",
|
||||
]
|
||||
|
|
|
@ -158,20 +158,4 @@ class PdfCreationTest : BaseSessionTest() {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
@NullDelegate(Autofill.Delegate::class)
|
||||
@Test
|
||||
fun saveAContentPdfDocument() {
|
||||
activityRule.scenario.onActivity {
|
||||
val originalBytes = getTestBytes(HELLO_PDF_WORLD_PDF_PATH)
|
||||
TestContentProvider.setTestData(originalBytes, "application/pdf")
|
||||
mainSession.loadUri("content://org.mozilla.geckoview.test.provider/pdf")
|
||||
mainSession.waitForPageStop()
|
||||
|
||||
val response = mainSession.pdfFileSaver.save()
|
||||
sessionRule.waitForResult(response).let {
|
||||
assertThat("The PDF File must the same as the original one.", it.body?.readBytes(), equalTo(originalBytes))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,140 +0,0 @@
|
|||
/* 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 android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ProviderInfo;
|
||||
import android.content.res.AssetFileDescriptor;
|
||||
import android.net.Uri;
|
||||
import android.os.Process;
|
||||
import android.util.Log;
|
||||
import androidx.annotation.AnyThread;
|
||||
import androidx.annotation.NonNull;
|
||||
import java.io.IOException;
|
||||
import org.mozilla.gecko.GeckoAppShell;
|
||||
import org.mozilla.gecko.annotation.WrapForJNI;
|
||||
|
||||
/**
|
||||
* This class provides an {@link OutputStream} wrapper for a Gecko nsIOutputStream (or really,
|
||||
* nsIRequest).
|
||||
*/
|
||||
/* package */ class ContentInputStream extends GeckoViewInputStream {
|
||||
private static final String LOGTAG = "ContentInputStream";
|
||||
|
||||
private static final byte[][] HEADERS = {{'%', 'P', 'D', 'F', '-'}};
|
||||
|
||||
private AssetFileDescriptor mFd;
|
||||
|
||||
ContentInputStream(final @NonNull String aUri) {
|
||||
final Uri uri = Uri.parse(aUri);
|
||||
final Context context = GeckoAppShell.getApplicationContext();
|
||||
final ContentResolver cr = context.getContentResolver();
|
||||
|
||||
try {
|
||||
mFd = cr.openAssetFileDescriptor(uri, "r");
|
||||
setInputStream(mFd.createInputStream());
|
||||
|
||||
if (!checkHeaders(HEADERS)) {
|
||||
Log.e(LOGTAG, "Cannot open the uri: " + aUri + " (invalid header)");
|
||||
close();
|
||||
}
|
||||
} catch (final IOException | SecurityException e) {
|
||||
Log.e(LOGTAG, "Cannot open the uri: " + aUri, e);
|
||||
close();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
if (mFd != null) {
|
||||
try {
|
||||
mFd.close();
|
||||
} catch (final IOException e) {
|
||||
Log.e(LOGTAG, "Cannot close the file descriptor", e);
|
||||
} finally {
|
||||
mFd = null;
|
||||
}
|
||||
}
|
||||
super.close();
|
||||
}
|
||||
|
||||
private static boolean wasGrantedPermission(
|
||||
final @NonNull Context aCtx, final @NonNull Uri aUri) {
|
||||
// For reference:
|
||||
// https://developer.android.com/topic/security/risks/content-resolver#mitigations_2
|
||||
final int pid = Process.myPid();
|
||||
final int uid = Process.myUid();
|
||||
return aCtx.checkUriPermission(aUri, pid, uid, Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||
== PackageManager.PERMISSION_GRANTED;
|
||||
}
|
||||
|
||||
private static boolean isExported(final @NonNull Context aCtx, final @NonNull Uri aUri) {
|
||||
// For reference:
|
||||
// https://developer.android.com/topic/security/risks/content-resolver#mitigations_2
|
||||
final String authority = aUri.getAuthority();
|
||||
final PackageManager packageManager = aCtx.getPackageManager();
|
||||
if (authority == null || packageManager == null) {
|
||||
return false;
|
||||
}
|
||||
final ProviderInfo info = packageManager.resolveContentProvider(authority, 0);
|
||||
if (info == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// We check that the provider is exported:
|
||||
// https://developer.android.com/reference/android/content/pm/ComponentInfo?hl=en#exported
|
||||
// or is GV itself (when testing GV, the provider is GV itself).
|
||||
final String packageName = aCtx.getPackageName();
|
||||
return info.exported || (packageName != null && packageName.equals(info.packageName));
|
||||
}
|
||||
|
||||
private static boolean belongsToCurrentApplication(
|
||||
final @NonNull Context aCtx, final @NonNull Uri aUri) {
|
||||
// For reference:
|
||||
// https://developer.android.com/topic/security/risks/content-resolver#mitigations_2
|
||||
final String authority = aUri.getAuthority();
|
||||
final PackageManager packageManager = aCtx.getPackageManager();
|
||||
if (authority == null || packageManager == null) {
|
||||
return false;
|
||||
}
|
||||
final ProviderInfo info = packageManager.resolveContentProvider(authority, 0);
|
||||
if (info == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// We check that the provider is GV itself (when testing GV, the provider is GV itself).
|
||||
final String packageName = aCtx.getPackageName();
|
||||
return packageName != null && packageName.equals(info.packageName);
|
||||
}
|
||||
|
||||
@WrapForJNI
|
||||
@AnyThread
|
||||
private static boolean isReadable(final @NonNull String aUri) {
|
||||
final Uri uri = Uri.parse(aUri);
|
||||
final Context context = GeckoAppShell.getApplicationContext();
|
||||
|
||||
if ((isExported(context, uri) && wasGrantedPermission(context, uri))
|
||||
|| belongsToCurrentApplication(context, uri)) {
|
||||
try {
|
||||
final ContentResolver cr = context.getContentResolver();
|
||||
cr.openAssetFileDescriptor(uri, "r").close();
|
||||
return true;
|
||||
} catch (final IOException | SecurityException e) {
|
||||
// A SecurityException could happen if the uri is no more valid.
|
||||
Log.e(LOGTAG, "Cannot read the uri: " + uri, e);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@WrapForJNI
|
||||
@AnyThread
|
||||
private static @NonNull GeckoViewInputStream getInstance(final @NonNull String aUri) {
|
||||
return new ContentInputStream(aUri);
|
||||
}
|
||||
}
|
|
@ -1,163 +0,0 @@
|
|||
/* 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 android.util.Log;
|
||||
import androidx.annotation.AnyThread;
|
||||
import androidx.annotation.NonNull;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.Channels;
|
||||
import java.nio.channels.ReadableByteChannel;
|
||||
import org.mozilla.gecko.annotation.WrapForJNI;
|
||||
|
||||
/** This class provides a Gecko nsIInputStream wrapper for a Java {@link InputStream}. */
|
||||
@WrapForJNI
|
||||
@AnyThread
|
||||
/* package */ class GeckoViewInputStream {
|
||||
private static final String LOGTAG = "GeckoViewInputStream";
|
||||
private static final int BUFFER_SIZE = 4096;
|
||||
|
||||
protected final ByteBuffer mBuffer = ByteBuffer.allocateDirect(BUFFER_SIZE);
|
||||
private ReadableByteChannel mChannel;
|
||||
private InputStream mIs = null;
|
||||
private boolean mMustGetData = true;
|
||||
private int mPos = 0;
|
||||
private int mSize;
|
||||
|
||||
/**
|
||||
* Set an input stream.
|
||||
*
|
||||
* @param is the {@link InputStream} to set.
|
||||
*/
|
||||
protected void setInputStream(final @NonNull InputStream is) {
|
||||
mIs = is;
|
||||
mChannel = Channels.newChannel(is);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if there is a stream.
|
||||
*
|
||||
* @return true if there is no stream.
|
||||
*/
|
||||
public boolean isClosed() {
|
||||
return mIs == null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by native code to get the number of available bytes in the underlying stream.
|
||||
*
|
||||
* @return the number of available bytes.
|
||||
*/
|
||||
public int available() {
|
||||
if (mIs == null || mSize == -1) {
|
||||
return 0;
|
||||
}
|
||||
try {
|
||||
return Math.max(mIs.available(), mMustGetData ? 0 : mSize - mPos);
|
||||
} catch (final IOException e) {
|
||||
Log.e(LOGTAG, "Cannot get the number of available bytes", e);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/** Close the underlying stream. */
|
||||
public void close() {
|
||||
if (mIs == null) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
mChannel.close();
|
||||
} catch (final IOException e) {
|
||||
Log.e(LOGTAG, "Cannot close the channel", e);
|
||||
} finally {
|
||||
mChannel = null;
|
||||
}
|
||||
|
||||
try {
|
||||
mIs.close();
|
||||
} catch (final IOException e) {
|
||||
Log.e(LOGTAG, "Cannot close the stream", e);
|
||||
} finally {
|
||||
mIs = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by native code to notify that the data have been consumed.
|
||||
*
|
||||
* @param length the number of consumed bytes.
|
||||
* @return the position in the buffer.
|
||||
*/
|
||||
public long consumedData(final int length) {
|
||||
mPos += length;
|
||||
if (mPos >= mSize) {
|
||||
mPos = 0;
|
||||
mMustGetData = true;
|
||||
}
|
||||
return mPos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that the underlying stream starts with one of the given headers.
|
||||
*
|
||||
* @param headers the headers to check.
|
||||
* @return true if one of the headers is found.
|
||||
*/
|
||||
protected boolean checkHeaders(final @NonNull byte[][] headers) throws IOException {
|
||||
read(0);
|
||||
for (final byte[] header : headers) {
|
||||
final int headerLength = header.length;
|
||||
if (mSize < headerLength) {
|
||||
continue;
|
||||
}
|
||||
int i = 0;
|
||||
for (; i < headerLength; i++) {
|
||||
if (mBuffer.get(i) != header[i]) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i == headerLength) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by native code to read some bytes in the underlying stream.
|
||||
*
|
||||
* @param aCount the number of bytes to read.
|
||||
* @return the number of read bytes, -1 in case of EOF.
|
||||
* @throws IOException if an error occurs.
|
||||
*/
|
||||
@WrapForJNI(exceptionMode = "nsresult")
|
||||
public int read(final long aCount) throws IOException {
|
||||
if (mIs == null) {
|
||||
Log.e(LOGTAG, "The stream is closed.");
|
||||
throw new IllegalStateException("Stream is closed");
|
||||
}
|
||||
|
||||
if (!mMustGetData) {
|
||||
return (int) Math.min((long) (mSize - mPos), aCount);
|
||||
}
|
||||
|
||||
mMustGetData = false;
|
||||
mBuffer.clear();
|
||||
|
||||
try {
|
||||
mSize = mChannel.read(mBuffer);
|
||||
} catch (final IOException e) {
|
||||
Log.e(LOGTAG, "Cannot read some bytes", e);
|
||||
throw e;
|
||||
}
|
||||
if (mSize == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return (int) Math.min((long) mSize, aCount);
|
||||
}
|
||||
}
|
|
@ -79,8 +79,7 @@ public final class SessionPdfFileSaver {
|
|||
public GeckoResult<WebResponse> onValue(final WebResponse response) {
|
||||
final int statusCode = response.statusCode != 0 ? response.statusCode : 200;
|
||||
return GeckoResult.fromValue(
|
||||
new WebResponse.Builder(
|
||||
originalUrl.startsWith("content://") ? url : originalUrl)
|
||||
new WebResponse.Builder(originalUrl)
|
||||
.statusCode(statusCode)
|
||||
.body(response.body)
|
||||
.skipConfirmation(skipConfirmation)
|
||||
|
|
|
@ -205,7 +205,7 @@ export class GeckoViewNavigation extends GeckoViewModule {
|
|||
// a privileged principal.
|
||||
const isExternal =
|
||||
navFlags & Ci.nsIWebNavigation.LOAD_FLAGS_FROM_EXTERNAL;
|
||||
if (!isExternal || Services.io.newURI(uri).schemeIs("content")) {
|
||||
if (!isExternal) {
|
||||
// Always use the system principal as the triggering principal
|
||||
// for user-initiated (ie. no referrer session and not external)
|
||||
// loads. See discussion in bug 1573860.
|
||||
|
|
|
@ -33,7 +33,6 @@ classes_with_WrapForJNI = [
|
|||
"Clipboard",
|
||||
"CodecProxy",
|
||||
"CompositorSurfaceManager",
|
||||
"ContentInputStream",
|
||||
"EnterpriseRoots",
|
||||
"EventCallback",
|
||||
"EventDispatcher",
|
||||
|
@ -59,7 +58,6 @@ classes_with_WrapForJNI = [
|
|||
"GeckoSurfaceTexture",
|
||||
"GeckoSystemStateListener",
|
||||
"GeckoThread",
|
||||
"GeckoViewInputStream",
|
||||
"GeckoVRManager",
|
||||
"GeckoVideoInfo",
|
||||
"GeckoWebExecutor",
|
||||
|
|
Загрузка…
Ссылка в новой задаче