mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1119021 - Implement fetch() redirects correctly. r=bkelly
This commit is contained in:
parent
03579a2217
commit
86e81d17de
@ -65,6 +65,8 @@ http://127.0.0.1:8888 privileged
|
||||
http://test:80 privileged
|
||||
http://mochi.test:8888 privileged
|
||||
http://test1.mochi.test:8888
|
||||
http://sub1.test1.mochi.test:8888
|
||||
http://sub2.xn--lt-uia.mochi.test:8888
|
||||
http://test2.mochi.test:8888
|
||||
http://example.org:80 privileged
|
||||
http://test1.example.org:80 privileged
|
||||
|
@ -31,7 +31,9 @@
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
NS_IMPL_ISUPPORTS(FetchDriver, nsIStreamListener)
|
||||
NS_IMPL_ISUPPORTS(FetchDriver,
|
||||
nsIStreamListener, nsIChannelEventSink, nsIInterfaceRequestor,
|
||||
nsIAsyncVerifyRedirectCallback)
|
||||
|
||||
FetchDriver::FetchDriver(InternalRequest* aRequest, nsIPrincipal* aPrincipal,
|
||||
nsILoadGroup* aLoadGroup)
|
||||
@ -89,7 +91,6 @@ FetchDriver::ContinueFetch(bool aCORSFlag)
|
||||
nsAutoCString url;
|
||||
mRequest->GetURL(url);
|
||||
nsCOMPtr<nsIURI> requestURI;
|
||||
// FIXME(nsm): Deal with relative URLs.
|
||||
nsresult rv = NS_NewURI(getter_AddRefs(requestURI), url,
|
||||
nullptr, nullptr);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
@ -332,6 +333,11 @@ FetchDriver::HttpFetch(bool aCORSFlag, bool aCORSPreflightFlag, bool aAuthentica
|
||||
return rv;
|
||||
}
|
||||
|
||||
// Insert ourselves into the notification callbacks chain so we can handle
|
||||
// cross-origin redirects.
|
||||
chan->GetNotificationCallbacks(getter_AddRefs(mNotificationCallbacks));
|
||||
chan->SetNotificationCallbacks(this);
|
||||
|
||||
// Step 3.1 "If the CORS preflight flag is set and one of these conditions is
|
||||
// true..." is handled by the CORS proxy.
|
||||
//
|
||||
@ -688,5 +694,157 @@ FetchDriver::OnStopRequest(nsIRequest* aRequest,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// This is called when the channel is redirected.
|
||||
NS_IMETHODIMP
|
||||
FetchDriver::AsyncOnChannelRedirect(nsIChannel* aOldChannel,
|
||||
nsIChannel* aNewChannel,
|
||||
uint32_t aFlags,
|
||||
nsIAsyncVerifyRedirectCallback *aCallback)
|
||||
{
|
||||
NS_PRECONDITION(aNewChannel, "Redirect without a channel?");
|
||||
|
||||
nsresult rv;
|
||||
|
||||
// Section 4.2, Step 4.6-4.7, enforcing a redirect count is done by Necko.
|
||||
// The pref used is "network.http.redirection-limit" which is set to 20 by
|
||||
// default.
|
||||
//
|
||||
// Step 4.8. We only unset this for spec compatibility. Any actions we take
|
||||
// on mRequest here do not affect what the channel does.
|
||||
mRequest->UnsetSameOriginDataURL();
|
||||
|
||||
//
|
||||
// Requests that require preflight are not permitted to redirect.
|
||||
// Fetch spec section 4.2 "HTTP Fetch", step 4.9 just uses the manual
|
||||
// redirect flag to decide whether to execute step 4.10 or not. We do not
|
||||
// represent it in our implementation.
|
||||
// The only thing we do is to check if the request requires a preflight (part
|
||||
// of step 4.9), in which case we abort. This part cannot be done by
|
||||
// nsCORSListenerProxy since it does not have access to mRequest.
|
||||
// which case. Step 4.10.3 is handled by OnRedirectVerifyCallback(), and all
|
||||
// the other steps are handled by nsCORSListenerProxy.
|
||||
if (!NS_IsInternalSameURIRedirect(aOldChannel, aNewChannel, aFlags)) {
|
||||
rv = DoesNotRequirePreflight(aNewChannel);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("nsXMLHttpRequest::OnChannelRedirect: "
|
||||
"DoesNotRequirePreflight returned failure");
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
mRedirectCallback = aCallback;
|
||||
mOldRedirectChannel = aOldChannel;
|
||||
mNewRedirectChannel = aNewChannel;
|
||||
|
||||
nsCOMPtr<nsIChannelEventSink> outer =
|
||||
do_GetInterface(mNotificationCallbacks);
|
||||
if (outer) {
|
||||
// The callee is supposed to call OnRedirectVerifyCallback() on success,
|
||||
// and nobody has to call it on failure, so we can just return after this
|
||||
// block.
|
||||
rv = outer->AsyncOnChannelRedirect(aOldChannel, aNewChannel, aFlags, this);
|
||||
if (NS_FAILED(rv)) {
|
||||
aOldChannel->Cancel(rv);
|
||||
mRedirectCallback = nullptr;
|
||||
mOldRedirectChannel = nullptr;
|
||||
mNewRedirectChannel = nullptr;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
(void) OnRedirectVerifyCallback(NS_OK);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Returns NS_OK if no preflight is required, error otherwise.
|
||||
nsresult
|
||||
FetchDriver::DoesNotRequirePreflight(nsIChannel* aChannel)
|
||||
{
|
||||
// If this is a same-origin request or the channel's URI inherits
|
||||
// its principal, it's allowed.
|
||||
if (nsContentUtils::CheckMayLoad(mPrincipal, aChannel, true)) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Check if we need to do a preflight request.
|
||||
nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aChannel);
|
||||
NS_ENSURE_TRUE(httpChannel, NS_ERROR_DOM_BAD_URI);
|
||||
|
||||
nsAutoCString method;
|
||||
httpChannel->GetRequestMethod(method);
|
||||
if (mRequest->Mode() == RequestMode::Cors_with_forced_preflight ||
|
||||
!mRequest->Headers()->HasOnlySimpleHeaders() ||
|
||||
(!method.LowerCaseEqualsLiteral("get") &&
|
||||
!method.LowerCaseEqualsLiteral("post") &&
|
||||
!method.LowerCaseEqualsLiteral("head"))) {
|
||||
return NS_ERROR_DOM_BAD_URI;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
FetchDriver::GetInterface(const nsIID& aIID, void **aResult)
|
||||
{
|
||||
if (aIID.Equals(NS_GET_IID(nsIChannelEventSink))) {
|
||||
*aResult = static_cast<nsIChannelEventSink*>(this);
|
||||
NS_ADDREF_THIS();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult rv;
|
||||
|
||||
if (mNotificationCallbacks) {
|
||||
rv = mNotificationCallbacks->GetInterface(aIID, aResult);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
NS_ASSERTION(*aResult, "Lying nsIInterfaceRequestor implementation!");
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
else if (aIID.Equals(NS_GET_IID(nsIStreamListener))) {
|
||||
*aResult = static_cast<nsIStreamListener*>(this);
|
||||
NS_ADDREF_THIS();
|
||||
return NS_OK;
|
||||
}
|
||||
else if (aIID.Equals(NS_GET_IID(nsIRequestObserver))) {
|
||||
*aResult = static_cast<nsIRequestObserver*>(this);
|
||||
NS_ADDREF_THIS();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
return QueryInterface(aIID, aResult);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
FetchDriver::OnRedirectVerifyCallback(nsresult aResult)
|
||||
{
|
||||
// On a successful redirect we perform the following substeps of Section 4.2,
|
||||
// step 4.10.
|
||||
if (NS_SUCCEEDED(aResult)) {
|
||||
// Step 4.10.3 "Set request's url to locationURL." so that when we set the
|
||||
// Response's URL from the Request's URL in Section 4, step 6, we get the
|
||||
// final value.
|
||||
nsCOMPtr<nsIURI> newURI;
|
||||
nsresult rv = NS_GetFinalChannelURI(mNewRedirectChannel, getter_AddRefs(newURI));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
aResult = rv;
|
||||
} else {
|
||||
// We need to update our request's URL.
|
||||
nsAutoCString newUrl;
|
||||
newURI->GetSpec(newUrl);
|
||||
mRequest->SetURL(newUrl);
|
||||
}
|
||||
}
|
||||
|
||||
if (NS_FAILED(aResult)) {
|
||||
mOldRedirectChannel->Cancel(aResult);
|
||||
}
|
||||
|
||||
mOldRedirectChannel = nullptr;
|
||||
mNewRedirectChannel = nullptr;
|
||||
mRedirectCallback->OnRedirectVerifyCallback(aResult);
|
||||
mRedirectCallback = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
@ -7,6 +7,9 @@
|
||||
#define mozilla_dom_FetchDriver_h
|
||||
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsIAsyncVerifyRedirectCallback.h"
|
||||
#include "nsIChannelEventSink.h"
|
||||
#include "nsIInterfaceRequestor.h"
|
||||
#include "nsIStreamListener.h"
|
||||
#include "nsRefPtr.h"
|
||||
|
||||
@ -35,12 +38,18 @@ protected:
|
||||
{ };
|
||||
};
|
||||
|
||||
class FetchDriver MOZ_FINAL : public nsIStreamListener
|
||||
class FetchDriver MOZ_FINAL : public nsIStreamListener,
|
||||
public nsIChannelEventSink,
|
||||
public nsIInterfaceRequestor,
|
||||
public nsIAsyncVerifyRedirectCallback
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIREQUESTOBSERVER
|
||||
NS_DECL_NSISTREAMLISTENER
|
||||
NS_DECL_NSICHANNELEVENTSINK
|
||||
NS_DECL_NSIINTERFACEREQUESTOR
|
||||
NS_DECL_NSIASYNCVERIFYREDIRECTCALLBACK
|
||||
|
||||
explicit FetchDriver(InternalRequest* aRequest, nsIPrincipal* aPrincipal,
|
||||
nsILoadGroup* aLoadGroup);
|
||||
@ -53,6 +62,10 @@ private:
|
||||
nsRefPtr<InternalResponse> mResponse;
|
||||
nsCOMPtr<nsIOutputStream> mPipeOutputStream;
|
||||
nsRefPtr<FetchDriverObserver> mObserver;
|
||||
nsCOMPtr<nsIInterfaceRequestor> mNotificationCallbacks;
|
||||
nsCOMPtr<nsIAsyncVerifyRedirectCallback> mRedirectCallback;
|
||||
nsCOMPtr<nsIChannel> mOldRedirectChannel;
|
||||
nsCOMPtr<nsIChannel> mNewRedirectChannel;
|
||||
uint32_t mFetchRecursionCount;
|
||||
|
||||
DebugOnly<bool> mResponseAvailableCalled;
|
||||
@ -75,6 +88,7 @@ private:
|
||||
void BeginResponse(InternalResponse* aResponse);
|
||||
nsresult FailWithNetworkError();
|
||||
nsresult SucceedWithResponse();
|
||||
nsresult DoesNotRequirePreflight(nsIChannel* aChannel);
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
@ -62,10 +62,8 @@ public:
|
||||
, mCredentialsMode(RequestCredentials::Omit)
|
||||
, mResponseTainting(RESPONSETAINT_BASIC)
|
||||
, mCacheMode(RequestCache::Default)
|
||||
, mRedirectCount(0)
|
||||
, mAuthenticationFlag(false)
|
||||
, mForceOriginHeader(false)
|
||||
, mManualRedirect(false)
|
||||
, mPreserveContentCodings(false)
|
||||
// FIXME(nsm): This should be false by default, but will lead to the
|
||||
// algorithm never loading data: URLs right now. See Bug 1018872 about
|
||||
@ -92,10 +90,8 @@ public:
|
||||
, mCredentialsMode(aOther.mCredentialsMode)
|
||||
, mResponseTainting(aOther.mResponseTainting)
|
||||
, mCacheMode(aOther.mCacheMode)
|
||||
, mRedirectCount(aOther.mRedirectCount)
|
||||
, mAuthenticationFlag(aOther.mAuthenticationFlag)
|
||||
, mForceOriginHeader(aOther.mForceOriginHeader)
|
||||
, mManualRedirect(aOther.mManualRedirect)
|
||||
, mPreserveContentCodings(aOther.mPreserveContentCodings)
|
||||
, mSameOriginDataURL(aOther.mSameOriginDataURL)
|
||||
, mSandboxedStorageAreaURLs(aOther.mSandboxedStorageAreaURLs)
|
||||
@ -132,6 +128,12 @@ public:
|
||||
aURL.Assign(mURL);
|
||||
}
|
||||
|
||||
void
|
||||
SetURL(const nsACString& aURL)
|
||||
{
|
||||
mURL.Assign(aURL);
|
||||
}
|
||||
|
||||
bool
|
||||
ReferrerIsNone() const
|
||||
{
|
||||
@ -250,6 +252,12 @@ public:
|
||||
return mSameOriginDataURL;
|
||||
}
|
||||
|
||||
void
|
||||
UnsetSameOriginDataURL()
|
||||
{
|
||||
mSameOriginDataURL = false;
|
||||
}
|
||||
|
||||
void
|
||||
SetBody(nsIInputStream* aStream)
|
||||
{
|
||||
@ -274,12 +282,6 @@ public:
|
||||
private:
|
||||
~InternalRequest();
|
||||
|
||||
void
|
||||
SetURL(const nsACString& aURL)
|
||||
{
|
||||
mURL.Assign(aURL);
|
||||
}
|
||||
|
||||
nsCString mMethod;
|
||||
nsCString mURL;
|
||||
nsRefPtr<InternalHeaders> mHeaders;
|
||||
@ -300,11 +302,8 @@ private:
|
||||
ResponseTainting mResponseTainting;
|
||||
RequestCache mCacheMode;
|
||||
|
||||
uint32_t mRedirectCount;
|
||||
|
||||
bool mAuthenticationFlag;
|
||||
bool mForceOriginHeader;
|
||||
bool mManualRedirect;
|
||||
bool mPreserveContentCodings;
|
||||
bool mSameOriginDataURL;
|
||||
bool mSandboxedStorageAreaURLs;
|
||||
|
@ -24,7 +24,11 @@ function testURL() {
|
||||
ok(res.type !== "error", "Response should not be an error for " + entry[0]);
|
||||
is(res.status, entry[2], "Status should match expected for " + entry[0]);
|
||||
is(res.statusText, entry[3], "Status text should match expected for " + entry[0]);
|
||||
ok(res.url.endsWith(path + entry[0]), "Response url should match request for simple fetch for " + entry[0]);
|
||||
// This file redirects to pass2
|
||||
if (entry[0] != "file_XHR_pass3.txt")
|
||||
ok(res.url.endsWith(path + entry[0]), "Response url should match request for simple fetch for " + entry[0]);
|
||||
else
|
||||
ok(res.url.endsWith(path + "file_XHR_pass2.txt"), "Response url should match request for simple fetch for " + entry[0]);
|
||||
is(res.headers.get('content-type'), entry[4], "Response should have content-type for " + entry[0]);
|
||||
});
|
||||
promises.push(p);
|
||||
@ -56,7 +60,10 @@ function testRequestGET() {
|
||||
ok(res.type !== "error", "Response should not be an error for " + entry[0]);
|
||||
is(res.status, entry[2], "Status should match expected for " + entry[0]);
|
||||
is(res.statusText, entry[3], "Status text should match expected for " + entry[0]);
|
||||
ok(res.url.endsWith(path + entry[0]), "Response url should match request for simple fetch for " + entry[0]);
|
||||
if (entry[0] != "file_XHR_pass3.txt")
|
||||
ok(res.url.endsWith(path + entry[0]), "Response url should match request for simple fetch for " + entry[0]);
|
||||
else
|
||||
ok(res.url.endsWith(path + "file_XHR_pass2.txt"), "Response url should match request for simple fetch for " + entry[0]);
|
||||
is(res.headers.get('content-type'), entry[4], "Response should have content-type for " + entry[0]);
|
||||
});
|
||||
promises.push(p);
|
||||
|
@ -873,6 +873,314 @@ function testCredentials() {
|
||||
return finalPromise;
|
||||
}
|
||||
|
||||
function testRedirects() {
|
||||
var origin = "http://mochi.test:8888";
|
||||
|
||||
var tests = [
|
||||
{ pass: 1,
|
||||
method: "GET",
|
||||
hops: [{ server: "http://example.com",
|
||||
allowOrigin: origin
|
||||
},
|
||||
],
|
||||
},
|
||||
{ pass: 0,
|
||||
method: "GET",
|
||||
hops: [{ server: "http://example.com",
|
||||
allowOrigin: origin
|
||||
},
|
||||
{ server: "http://mochi.test:8888",
|
||||
allowOrigin: origin
|
||||
},
|
||||
],
|
||||
},
|
||||
{ pass: 1,
|
||||
method: "GET",
|
||||
hops: [{ server: "http://example.com",
|
||||
allowOrigin: origin
|
||||
},
|
||||
{ server: "http://mochi.test:8888",
|
||||
allowOrigin: "*"
|
||||
},
|
||||
],
|
||||
},
|
||||
{ pass: 0,
|
||||
method: "GET",
|
||||
hops: [{ server: "http://example.com",
|
||||
allowOrigin: origin
|
||||
},
|
||||
{ server: "http://mochi.test:8888",
|
||||
},
|
||||
],
|
||||
},
|
||||
{ pass: 1,
|
||||
method: "GET",
|
||||
hops: [{ server: "http://mochi.test:8888",
|
||||
},
|
||||
{ server: "http://mochi.test:8888",
|
||||
},
|
||||
{ server: "http://example.com",
|
||||
allowOrigin: origin
|
||||
},
|
||||
],
|
||||
},
|
||||
{ pass: 0,
|
||||
method: "GET",
|
||||
hops: [{ server: "http://mochi.test:8888",
|
||||
},
|
||||
{ server: "http://mochi.test:8888",
|
||||
},
|
||||
{ server: "http://example.com",
|
||||
allowOrigin: origin
|
||||
},
|
||||
{ server: "http://mochi.test:8888",
|
||||
},
|
||||
],
|
||||
},
|
||||
{ pass: 0,
|
||||
method: "GET",
|
||||
hops: [{ server: "http://example.com",
|
||||
allowOrigin: origin
|
||||
},
|
||||
{ server: "http://test2.mochi.test:8000",
|
||||
allowOrigin: origin
|
||||
},
|
||||
{ server: "http://sub2.xn--lt-uia.mochi.test:8888",
|
||||
allowOrigin: origin
|
||||
},
|
||||
{ server: "http://sub1.test1.mochi.test:8888",
|
||||
allowOrigin: origin
|
||||
},
|
||||
],
|
||||
},
|
||||
{ pass: 0,
|
||||
method: "GET",
|
||||
hops: [{ server: "http://example.com",
|
||||
allowOrigin: origin
|
||||
},
|
||||
{ server: "http://test2.mochi.test:8000",
|
||||
allowOrigin: origin
|
||||
},
|
||||
{ server: "http://sub2.xn--lt-uia.mochi.test:8888",
|
||||
allowOrigin: "*"
|
||||
},
|
||||
{ server: "http://sub1.test1.mochi.test:8888",
|
||||
allowOrigin: "*"
|
||||
},
|
||||
],
|
||||
},
|
||||
{ pass: 1,
|
||||
method: "GET",
|
||||
hops: [{ server: "http://example.com",
|
||||
allowOrigin: origin
|
||||
},
|
||||
{ server: "http://test2.mochi.test:8888",
|
||||
allowOrigin: "*"
|
||||
},
|
||||
{ server: "http://sub2.xn--lt-uia.mochi.test:8888",
|
||||
allowOrigin: "*"
|
||||
},
|
||||
{ server: "http://sub1.test1.mochi.test:8888",
|
||||
allowOrigin: "*"
|
||||
},
|
||||
],
|
||||
},
|
||||
{ pass: 0,
|
||||
method: "GET",
|
||||
hops: [{ server: "http://example.com",
|
||||
allowOrigin: origin
|
||||
},
|
||||
{ server: "http://test2.mochi.test:8000",
|
||||
allowOrigin: origin
|
||||
},
|
||||
{ server: "http://sub2.xn--lt-uia.mochi.test:8888",
|
||||
allowOrigin: "x"
|
||||
},
|
||||
{ server: "http://sub1.test1.mochi.test:8888",
|
||||
allowOrigin: origin
|
||||
},
|
||||
],
|
||||
},
|
||||
{ pass: 0,
|
||||
method: "GET",
|
||||
hops: [{ server: "http://example.com",
|
||||
allowOrigin: origin
|
||||
},
|
||||
{ server: "http://test2.mochi.test:8000",
|
||||
allowOrigin: origin
|
||||
},
|
||||
{ server: "http://sub2.xn--lt-uia.mochi.test:8888",
|
||||
allowOrigin: "*"
|
||||
},
|
||||
{ server: "http://sub1.test1.mochi.test:8888",
|
||||
allowOrigin: origin
|
||||
},
|
||||
],
|
||||
},
|
||||
{ pass: 0,
|
||||
method: "GET",
|
||||
hops: [{ server: "http://example.com",
|
||||
allowOrigin: origin
|
||||
},
|
||||
{ server: "http://test2.mochi.test:8000",
|
||||
allowOrigin: origin
|
||||
},
|
||||
{ server: "http://sub2.xn--lt-uia.mochi.test:8888",
|
||||
allowOrigin: "*"
|
||||
},
|
||||
{ server: "http://sub1.test1.mochi.test:8888",
|
||||
},
|
||||
],
|
||||
},
|
||||
{ pass: 1,
|
||||
method: "POST",
|
||||
body: "hi there",
|
||||
headers: { "Content-Type": "text/plain" },
|
||||
hops: [{ server: "http://mochi.test:8888",
|
||||
},
|
||||
{ server: "http://example.com",
|
||||
allowOrigin: origin,
|
||||
},
|
||||
],
|
||||
},
|
||||
{ pass: 0,
|
||||
method: "POST",
|
||||
body: "hi there",
|
||||
headers: { "Content-Type": "text/plain",
|
||||
"my-header": "myValue",
|
||||
},
|
||||
hops: [{ server: "http://mochi.test:8888",
|
||||
},
|
||||
{ server: "http://example.com",
|
||||
allowOrigin: origin,
|
||||
allowHeaders: "my-header",
|
||||
},
|
||||
],
|
||||
},
|
||||
{ pass: 0,
|
||||
method: "DELETE",
|
||||
hops: [{ server: "http://mochi.test:8888",
|
||||
},
|
||||
{ server: "http://example.com",
|
||||
allowOrigin: origin,
|
||||
},
|
||||
],
|
||||
},
|
||||
{ pass: 0,
|
||||
method: "POST",
|
||||
body: "hi there",
|
||||
headers: { "Content-Type": "text/plain",
|
||||
"my-header": "myValue",
|
||||
},
|
||||
hops: [{ server: "http://example.com",
|
||||
allowOrigin: origin,
|
||||
},
|
||||
{ server: "http://sub1.test1.mochi.test:8888",
|
||||
allowOrigin: origin,
|
||||
},
|
||||
],
|
||||
},
|
||||
{ pass: 0,
|
||||
method: "DELETE",
|
||||
hops: [{ server: "http://example.com",
|
||||
allowOrigin: origin,
|
||||
},
|
||||
{ server: "http://sub1.test1.mochi.test:8888",
|
||||
allowOrigin: origin,
|
||||
},
|
||||
],
|
||||
},
|
||||
{ pass: 0,
|
||||
method: "POST",
|
||||
body: "hi there",
|
||||
headers: { "Content-Type": "text/plain",
|
||||
"my-header": "myValue",
|
||||
},
|
||||
hops: [{ server: "http://example.com",
|
||||
},
|
||||
{ server: "http://sub1.test1.mochi.test:8888",
|
||||
allowOrigin: origin,
|
||||
allowHeaders: "my-header",
|
||||
},
|
||||
],
|
||||
},
|
||||
{ pass: 1,
|
||||
method: "POST",
|
||||
body: "hi there",
|
||||
headers: { "Content-Type": "text/plain" },
|
||||
hops: [{ server: "http://mochi.test:8888",
|
||||
},
|
||||
{ server: "http://example.com",
|
||||
allowOrigin: origin,
|
||||
},
|
||||
],
|
||||
},
|
||||
{ pass: 0,
|
||||
method: "POST",
|
||||
body: "hi there",
|
||||
headers: { "Content-Type": "text/plain",
|
||||
"my-header": "myValue",
|
||||
},
|
||||
hops: [{ server: "http://example.com",
|
||||
allowOrigin: origin,
|
||||
allowHeaders: "my-header",
|
||||
},
|
||||
{ server: "http://mochi.test:8888",
|
||||
allowOrigin: origin,
|
||||
allowHeaders: "my-header",
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
var fetches = [];
|
||||
for (test of tests) {
|
||||
req = {
|
||||
url: test.hops[0].server + corsServerPath + "hop=1&hops=" +
|
||||
escape(test.hops.toSource()),
|
||||
method: test.method,
|
||||
headers: test.headers,
|
||||
body: test.body,
|
||||
};
|
||||
|
||||
if (test.pass) {
|
||||
if (test.body)
|
||||
req.url += "&body=" + escape(test.body);
|
||||
}
|
||||
|
||||
var request = new Request(req.url, { method: req.method,
|
||||
headers: req.headers,
|
||||
body: req.body });
|
||||
fetches.push((function(request, test) {
|
||||
return fetch(request).then(function(res) {
|
||||
if (test.pass) {
|
||||
is(isNetworkError(res), false,
|
||||
"shouldn't have failed in test for " + test.toSource());
|
||||
is(res.status, 200, "wrong status in test for " + test.toSource());
|
||||
is(res.statusText, "OK", "wrong status text for " + test.toSource());
|
||||
is((new URL(res.url)).host, (new URL(test.hops[test.hops.length-1].server)).host, "Response URL should be redirected URL");
|
||||
return res.text().then(function(v) {
|
||||
is(v, "<res>hello pass</res>\n",
|
||||
"wrong responseText in test for " + test.toSource());
|
||||
});
|
||||
}
|
||||
else {
|
||||
is(isNetworkError(res), true,
|
||||
"should have failed in test for " + test.toSource());
|
||||
is(res.status, 0, "wrong status in test for " + test.toSource());
|
||||
is(res.statusText, "", "wrong status text for " + test.toSource());
|
||||
return res.text().then(function(v) {
|
||||
is(v, "",
|
||||
"wrong responseText in test for " + test.toSource());
|
||||
});
|
||||
}
|
||||
});
|
||||
})(request, test));
|
||||
}
|
||||
|
||||
return Promise.all(fetches);
|
||||
}
|
||||
|
||||
function runTest() {
|
||||
var done = function() {
|
||||
if (typeof SimpleTest === "object") {
|
||||
@ -889,6 +1197,7 @@ function runTest() {
|
||||
.then(testModeNoCors)
|
||||
.then(testModeCors)
|
||||
.then(testCredentials)
|
||||
.then(testRedirects)
|
||||
// Put more promise based tests here.
|
||||
.then(done)
|
||||
.catch(function(e) {
|
||||
|
Loading…
Reference in New Issue
Block a user