Bug 1526327 - Add GeckoWebExecutor.FETCH_FLAGS_NO_REDIRECT r=geckoview-reviewers,droeh,esawin

Using this flag will cause GeckoWebExecutor.fetch() to not automatically
follow redirects, which is the default behavior if no flag is specified.

Differential Revision: https://phabricator.services.mozilla.com/D19523

--HG--
extra : moz-landing-system : lando
This commit is contained in:
James Willcox 2019-02-21 18:15:42 +00:00
Родитель f4c323650d
Коммит 0809c64d52
5 изменённых файлов: 63 добавлений и 6 удалений

Просмотреть файл

@ -753,6 +753,7 @@ package org.mozilla.geckoview {
method public void speculativeConnect(@android.support.annotation.NonNull java.lang.String); method public void speculativeConnect(@android.support.annotation.NonNull java.lang.String);
field public static final int FETCH_FLAGS_ANONYMOUS = 1; field public static final int FETCH_FLAGS_ANONYMOUS = 1;
field public static final int FETCH_FLAGS_NONE = 0; field public static final int FETCH_FLAGS_NONE = 0;
field public static final int FETCH_FLAGS_NO_REDIRECTS = 2;
} }
public static interface GeckoWebExecutor.FetchFlags implements java.lang.annotation.Annotation { public static interface GeckoWebExecutor.FetchFlags implements java.lang.annotation.Annotation {

Просмотреть файл

@ -147,6 +147,15 @@ class WebExecutorTest {
assertThat("Status code should match", response.statusCode, equalTo(200)) assertThat("Status code should match", response.statusCode, equalTo(200))
} }
@Test
fun testDisallowRedirect() {
val response = fetch(WebRequest("$TEST_ENDPOINT/redirect-to?url=/status/200"), GeckoWebExecutor.FETCH_FLAGS_NO_REDIRECTS)
assertThat("URI should match", response.uri, equalTo("$TEST_ENDPOINT/redirect-to?url=/status/200"))
assertThat("Redirected should match", response.redirected, equalTo(false))
assertThat("Status code should match", response.statusCode, equalTo(302))
}
@Test @Test
fun testRedirectLoop() { fun testRedirectLoop() {
thrown.expect(equalTo(WebRequestError(WebRequestError.ERROR_REDIRECT_LOOP, WebRequestError.ERROR_CATEGORY_NETWORK))) thrown.expect(equalTo(WebRequestError(WebRequestError.ERROR_REDIRECT_LOOP, WebRequestError.ERROR_CATEGORY_NETWORK)))

Просмотреть файл

@ -54,7 +54,7 @@ public class GeckoWebExecutor {
} }
@Retention(RetentionPolicy.SOURCE) @Retention(RetentionPolicy.SOURCE)
@IntDef({FETCH_FLAGS_NONE, FETCH_FLAGS_ANONYMOUS}) @IntDef({FETCH_FLAGS_NONE, FETCH_FLAGS_ANONYMOUS, FETCH_FLAGS_NO_REDIRECTS})
public @interface FetchFlags {}; public @interface FetchFlags {};
/** /**
@ -68,6 +68,12 @@ public class GeckoWebExecutor {
@WrapForJNI @WrapForJNI
public static final int FETCH_FLAGS_ANONYMOUS = 1; public static final int FETCH_FLAGS_ANONYMOUS = 1;
/**
* Don't automatically follow redirects.
*/
@WrapForJNI
public static final int FETCH_FLAGS_NO_REDIRECTS = 1 << 1;
/** /**
* Create a new GeckoWebExecutor instance. * Create a new GeckoWebExecutor instance.
* *

Просмотреть файл

@ -37,6 +37,9 @@ exclude: true
- Changed `WebResponse.body` from a `ByteBuffer` to an `InputStream`. Apps that want access - Changed `WebResponse.body` from a `ByteBuffer` to an `InputStream`. Apps that want access
to the entire response body will now need to read the stream themselves. to the entire response body will now need to read the stream themselves.
- Added `GeckoWebExecutor.FETCH_FLAGS_NO_REDIRECTS`, which will cause `GeckoWebExecutor.fetch()` to not
automatically follow HTTP redirects (e.g., 302).
[67.1]: ../GeckoSession.html#getDefaultUserAgent-- [67.1]: ../GeckoSession.html#getDefaultUserAgent--
## v66 ## v66
@ -148,4 +151,4 @@ exclude: true
[65.24]: ../CrashReporter.html#sendCrashReport-android.content.Context-android.os.Bundle-java.lang.String- [65.24]: ../CrashReporter.html#sendCrashReport-android.content.Context-android.os.Bundle-java.lang.String-
[65.25]: ../GeckoResult.html [65.25]: ../GeckoResult.html
[api-version]: 5655c3f6a74c860809e57a2d66499633ac23cfcc [api-version]: a1740e5cb61e34b3180b80f33b0b33243a34d588

Просмотреть файл

@ -7,10 +7,12 @@
#include "WebExecutorSupport.h" #include "WebExecutorSupport.h"
#include "nsIChannelEventSink.h"
#include "nsIHttpChannel.h" #include "nsIHttpChannel.h"
#include "nsIHttpChannelInternal.h" #include "nsIHttpChannelInternal.h"
#include "nsIHttpHeaderVisitor.h" #include "nsIHttpHeaderVisitor.h"
#include "nsIInputStream.h" #include "nsIInputStream.h"
#include "nsIInterfaceRequestor.h"
#include "nsIStreamLoader.h" #include "nsIStreamLoader.h"
#include "nsINSSErrorsService.h" #include "nsINSSErrorsService.h"
#include "nsIUploadChannel2.h" #include "nsIUploadChannel2.h"
@ -150,11 +152,15 @@ class StreamSupport final
nsCOMPtr<nsIRequest> mRequest; nsCOMPtr<nsIRequest> mRequest;
}; };
class LoaderListener final : public nsIStreamListener { class LoaderListener final : public nsIStreamListener,
public nsIInterfaceRequestor,
public nsIChannelEventSink {
public: public:
NS_DECL_THREADSAFE_ISUPPORTS NS_DECL_THREADSAFE_ISUPPORTS
explicit LoaderListener(java::GeckoResult::Param aResult) : mResult(aResult) { explicit LoaderListener(java::GeckoResult::Param aResult,
bool aAllowRedirects)
: mResult(aResult), mAllowRedirects(aAllowRedirects) {
MOZ_ASSERT(mResult); MOZ_ASSERT(mResult);
} }
@ -211,6 +217,29 @@ class LoaderListener final : public nsIStreamListener {
return aInputStream->ReadSegments(WriteSegment, this, aCount, &countRead); return aInputStream->ReadSegments(WriteSegment, this, aCount, &countRead);
} }
NS_IMETHOD
GetInterface(const nsIID& aIID, void** aResultOut) override {
if (aIID.Equals(NS_GET_IID(nsIChannelEventSink))) {
*aResultOut = static_cast<nsIChannelEventSink*>(this);
NS_ADDREF_THIS();
return NS_OK;
}
return NS_ERROR_NO_INTERFACE;
}
NS_IMETHOD
AsyncOnChannelRedirect(nsIChannel* aOldChannel, nsIChannel* aNewChannel,
uint32_t flags,
nsIAsyncVerifyRedirectCallback* callback) override {
if (!mAllowRedirects) {
return NS_ERROR_ABORT;
}
callback->OnRedirectVerifyCallback(NS_OK);
return NS_OK;
}
private: private:
static nsresult WriteSegment(nsIInputStream* aInputStream, void* aClosure, static nsresult WriteSegment(nsIInputStream* aInputStream, void* aClosure,
const char* aFromSegment, uint32_t aToOffset, const char* aFromSegment, uint32_t aToOffset,
@ -284,9 +313,12 @@ class LoaderListener final : public nsIStreamListener {
const java::GeckoResult::GlobalRef mResult; const java::GeckoResult::GlobalRef mResult;
java::GeckoInputStream::GlobalRef mStream; java::GeckoInputStream::GlobalRef mStream;
java::GeckoInputStream::Support::GlobalRef mSupport; java::GeckoInputStream::Support::GlobalRef mSupport;
bool mAllowRedirects;
}; };
NS_IMPL_ISUPPORTS(LoaderListener, nsIStreamListener) NS_IMPL_ISUPPORTS(LoaderListener, nsIStreamListener, nsIInterfaceRequestor,
nsIChannelEventSink)
class DNSListener final : public nsIDNSListener { class DNSListener final : public nsIDNSListener {
public: public:
@ -471,8 +503,14 @@ nsresult WebExecutorSupport::CreateStreamLoader(
rv = internalChannel->SetBlockAuthPrompt(true); rv = internalChannel->SetBlockAuthPrompt(true);
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
const bool allowRedirects =
!(aFlags & java::GeckoWebExecutor::FETCH_FLAGS_NO_REDIRECTS);
// All done, set up the listener // All done, set up the listener
RefPtr<LoaderListener> listener = new LoaderListener(aResult); RefPtr<LoaderListener> listener = new LoaderListener(aResult, allowRedirects);
rv = channel->SetNotificationCallbacks(listener);
NS_ENSURE_SUCCESS(rv, rv);
// Finally, open the channel // Finally, open the channel
rv = httpChannel->AsyncOpen(listener); rv = httpChannel->AsyncOpen(listener);