зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1444539: Disconnect StreamFilters on redirect. r=mixedpuppy
MozReview-Commit-ID: AuCjXTlsFSC --HG-- extra : rebase_source : 40b0836c3efd739020dc59f1ed3f63020e187b47
This commit is contained in:
Родитель
f8ae1c0643
Коммит
73efc480a8
|
@ -0,0 +1,131 @@
|
|||
"use strict";
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "proxyService",
|
||||
"@mozilla.org/network/protocol-proxy-service;1",
|
||||
"nsIProtocolProxyService");
|
||||
|
||||
const server = createHttpServer();
|
||||
const gHost = "localhost";
|
||||
const gPort = server.identity.primaryPort;
|
||||
|
||||
const HOSTS = new Set([
|
||||
"example.com",
|
||||
"example.org",
|
||||
"example.net",
|
||||
]);
|
||||
|
||||
for (let host of HOSTS) {
|
||||
server.identity.add("http", host, 80);
|
||||
}
|
||||
|
||||
const proxyFilter = {
|
||||
proxyInfo: proxyService.newProxyInfo("http", gHost, gPort, 0, 4096, null),
|
||||
|
||||
applyFilter(service, channel, defaultProxyInfo, callback) {
|
||||
if (HOSTS.has(channel.URI.host)) {
|
||||
callback.onProxyFilterResult(this.proxyInfo);
|
||||
} else {
|
||||
callback.onProxyFilterResult(defaultProxyInfo);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
proxyService.registerChannelFilter(proxyFilter, 0);
|
||||
registerCleanupFunction(() => {
|
||||
proxyService.unregisterChannelFilter(proxyFilter);
|
||||
});
|
||||
|
||||
server.registerPathHandler("/redirect", (request, response) => {
|
||||
let params = new URLSearchParams(request.queryString);
|
||||
response.setStatusLine(request.httpVersion, 302, "Moved Temporarily");
|
||||
response.setHeader("Location", params.get("redirect_uri"));
|
||||
response.setHeader("Access-Control-Allow-Origin", "*");
|
||||
});
|
||||
|
||||
server.registerPathHandler("/dummy", (request, response) => {
|
||||
response.setStatusLine(request.httpVersion, 200, "OK");
|
||||
response.setHeader("Access-Control-Allow-Origin", "*");
|
||||
response.write("ok");
|
||||
});
|
||||
|
||||
Cu.importGlobalProperties(["fetch"]);
|
||||
|
||||
add_task(async function() {
|
||||
const {fetch} = Cu.Sandbox("http://example.com/", {wantGlobalProperties: ["fetch"]});
|
||||
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
background() {
|
||||
let pending = [];
|
||||
|
||||
browser.webRequest.onBeforeRequest.addListener(
|
||||
data => {
|
||||
let filter = browser.webRequest.filterResponseData(data.requestId);
|
||||
|
||||
let url = new URL(data.url);
|
||||
|
||||
if (url.searchParams.get("redirect_uri")) {
|
||||
pending.push(
|
||||
new Promise(resolve => { filter.onerror = resolve; }).then(() => {
|
||||
browser.test.assertEq("Channel redirected", filter.error,
|
||||
"Got correct error for redirected filter");
|
||||
}));
|
||||
}
|
||||
|
||||
filter.onstart = () => {
|
||||
filter.write(new TextEncoder().encode(data.url));
|
||||
};
|
||||
filter.ondata = event => {
|
||||
let str = new TextDecoder().decode(event.data);
|
||||
browser.test.assertEq("ok", str, `Got unfiltered data for ${data.url}`);
|
||||
};
|
||||
filter.onstop = () => {
|
||||
filter.close();
|
||||
};
|
||||
}, {
|
||||
urls: ["<all_urls>"],
|
||||
},
|
||||
["blocking"]);
|
||||
|
||||
browser.test.onMessage.addListener(async msg => {
|
||||
if (msg === "done") {
|
||||
await Promise.all(pending);
|
||||
browser.test.notifyPass("stream-filter");
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
manifest: {
|
||||
permissions: [
|
||||
"webRequest",
|
||||
"webRequestBlocking",
|
||||
"http://example.com/",
|
||||
"http://example.org/",
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
await extension.startup();
|
||||
|
||||
let results = [
|
||||
["http://example.com/dummy", "http://example.com/dummy"],
|
||||
["http://example.org/dummy", "http://example.org/dummy"],
|
||||
["http://example.net/dummy", "ok"],
|
||||
["http://example.com/redirect?redirect_uri=http://example.com/dummy", "http://example.com/dummy"],
|
||||
["http://example.com/redirect?redirect_uri=http://example.org/dummy", "http://example.org/dummy"],
|
||||
["http://example.com/redirect?redirect_uri=http://example.net/dummy", "ok"],
|
||||
["http://example.net/redirect?redirect_uri=http://example.com/dummy", "http://example.com/dummy"],
|
||||
].map(async ([url, expectedResponse]) => {
|
||||
let resp = await fetch(url);
|
||||
let text = await resp.text();
|
||||
equal(text, expectedResponse, `Expected response for ${url}`);
|
||||
});
|
||||
|
||||
await Promise.all(results);
|
||||
|
||||
extension.sendMessage("done");
|
||||
await extension.awaitFinish("stream-filter");
|
||||
await extension.unload();
|
||||
|
||||
ChromeUtils.import("resource://gre/modules/Timer.jsm");
|
||||
await new Promise(resolve => setTimeout(resolve, 100));
|
||||
});
|
|
@ -81,6 +81,7 @@ skip-if = os == "android" # checking for telemetry needs to be updated: 1384923
|
|||
[test_ext_trustworthy_origin.js]
|
||||
[test_ext_topSites.js]
|
||||
skip-if = os == "android"
|
||||
[test_ext_webRequest_filterResponseData.js]
|
||||
[test_native_manifests.js]
|
||||
subprocess = true
|
||||
skip-if = os == "android"
|
||||
|
|
|
@ -18,11 +18,13 @@ parent:
|
|||
async Resume();
|
||||
async Close();
|
||||
async Disconnect();
|
||||
async Destroy();
|
||||
|
||||
child:
|
||||
async Resumed();
|
||||
async Suspended();
|
||||
async Closed();
|
||||
async Error(nsCString error);
|
||||
|
||||
async FlushData();
|
||||
|
||||
|
|
|
@ -304,6 +304,18 @@ StreamFilterChild::RecvInitialized(bool aSuccess)
|
|||
}
|
||||
}
|
||||
|
||||
IPCResult
|
||||
StreamFilterChild::RecvError(const nsCString& aError)
|
||||
{
|
||||
mState = State::Error;
|
||||
if (mStreamFilter) {
|
||||
mStreamFilter->FireErrorEvent(NS_ConvertUTF8toUTF16(aError));
|
||||
mStreamFilter = nullptr;
|
||||
}
|
||||
SendDestroy();
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
IPCResult
|
||||
StreamFilterChild::RecvClosed() {
|
||||
MOZ_DIAGNOSTIC_ASSERT(mState == State::Closing);
|
||||
|
|
|
@ -99,6 +99,7 @@ protected:
|
|||
virtual IPCResult RecvStartRequest() override;
|
||||
virtual IPCResult RecvData(Data&& data) override;
|
||||
virtual IPCResult RecvStopRequest(const nsresult& aStatus) override;
|
||||
virtual IPCResult RecvError(const nsCString& aError) override;
|
||||
|
||||
virtual IPCResult RecvClosed() override;
|
||||
virtual IPCResult RecvSuspended() override;
|
||||
|
|
|
@ -225,6 +225,7 @@ StreamFilterParent::Broken()
|
|||
|
||||
RunOnActorThread(FUNC, [=] {
|
||||
if (self->IPCActive()) {
|
||||
self->mDisconnected = true;
|
||||
self->mState = State::Disconnected;
|
||||
}
|
||||
});
|
||||
|
@ -267,6 +268,15 @@ StreamFilterParent::Destroy()
|
|||
NS_DISPATCH_NORMAL);
|
||||
}
|
||||
|
||||
IPCResult
|
||||
StreamFilterParent::RecvDestroy()
|
||||
{
|
||||
AssertIsActorThread();
|
||||
Destroy();
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
|
||||
IPCResult
|
||||
StreamFilterParent::RecvSuspend()
|
||||
{
|
||||
|
@ -311,7 +321,6 @@ StreamFilterParent::RecvResume()
|
|||
}
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
IPCResult
|
||||
StreamFilterParent::RecvDisconnect()
|
||||
{
|
||||
|
@ -346,6 +355,7 @@ StreamFilterParent::RecvFlushedData()
|
|||
|
||||
RunOnActorThread(FUNC, [=] {
|
||||
self->mState = State::Disconnected;
|
||||
self->mDisconnected = true;
|
||||
});
|
||||
});
|
||||
return IPC_OK();
|
||||
|
@ -406,7 +416,19 @@ StreamFilterParent::OnStartRequest(nsIRequest* aRequest, nsISupports* aContext)
|
|||
|
||||
mContext = aContext;
|
||||
|
||||
if (mState != State::Disconnected) {
|
||||
if (aRequest != mChannel) {
|
||||
mDisconnected = true;
|
||||
|
||||
RefPtr<StreamFilterParent> self(this);
|
||||
RunOnActorThread(FUNC, [=] {
|
||||
if (self->IPCActive()) {
|
||||
self->mState = State::Disconnected;
|
||||
CheckResult(self->SendError(NS_LITERAL_CSTRING("Channel redirected")));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (!mDisconnected) {
|
||||
RefPtr<StreamFilterParent> self(this);
|
||||
RunOnActorThread(FUNC, [=] {
|
||||
if (self->IPCActive()) {
|
||||
|
@ -439,7 +461,7 @@ StreamFilterParent::OnStopRequest(nsIRequest* aRequest,
|
|||
AssertIsMainThread();
|
||||
|
||||
mReceivedStop = true;
|
||||
if (mState == State::Disconnected) {
|
||||
if (mDisconnected) {
|
||||
return EmitStopRequest(aStatusCode);
|
||||
}
|
||||
|
||||
|
@ -485,7 +507,7 @@ StreamFilterParent::OnDataAvailable(nsIRequest* aRequest,
|
|||
{
|
||||
AssertIsIOThread();
|
||||
|
||||
if (mState == State::Disconnected) {
|
||||
if (mDisconnected) {
|
||||
// If we're offloading data in a thread pool, it's possible that we'll
|
||||
// have buffered some additional data while waiting for the buffer to
|
||||
// flush. So, if there's any buffered data left, flush that before we
|
||||
|
|
|
@ -93,6 +93,7 @@ protected:
|
|||
virtual IPCResult RecvResume() override;
|
||||
virtual IPCResult RecvClose() override;
|
||||
virtual IPCResult RecvDisconnect() override;
|
||||
virtual IPCResult RecvDestroy() override;
|
||||
|
||||
virtual void DeallocPStreamFilterParent() override;
|
||||
|
||||
|
@ -175,6 +176,7 @@ private:
|
|||
|
||||
bool mReceivedStop;
|
||||
bool mSentStop;
|
||||
bool mDisconnected = false;
|
||||
|
||||
nsCOMPtr<nsISupports> mContext;
|
||||
uint64_t mOffset;
|
||||
|
|
Загрузка…
Ссылка в новой задаче