зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1619584 - P2: Implement redirection r=valentin,dragana
Differential Revision: https://phabricator.services.mozilla.com/D66773 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
4a22dca83d
Коммит
1a69c8800a
|
@ -7,7 +7,6 @@
|
|||
#include "DNS.h"
|
||||
#include "nsCharSeparatedTokenizer.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsHostResolver.h"
|
||||
#include "nsHttpHandler.h"
|
||||
#include "nsIHttpChannel.h"
|
||||
#include "nsIHttpChannelInternal.h"
|
||||
|
@ -24,6 +23,7 @@
|
|||
#include "nsURLHelper.h"
|
||||
#include "TRR.h"
|
||||
#include "TRRService.h"
|
||||
#include "TRRLoadInfo.h"
|
||||
|
||||
#include "mozilla/Base64.h"
|
||||
#include "mozilla/DebugOnly.h"
|
||||
|
@ -219,11 +219,13 @@ nsresult TRR::CreateChannelHelper(nsIURI* aUri, nsIChannel** aResult) {
|
|||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
RefPtr<TRRLoadInfo> loadInfo =
|
||||
new TRRLoadInfo(aUri, nsIContentPolicy::TYPE_OTHER);
|
||||
return gHttpHandler->CreateTRRServiceChannel(aUri,
|
||||
nullptr, // givenProxyInfo
|
||||
0, // proxyResolveFlags
|
||||
nullptr, // proxyURI
|
||||
nullptr, // aLoadInfo
|
||||
nullptr, // givenProxyInfo
|
||||
0, // proxyResolveFlags
|
||||
nullptr, // proxyURI
|
||||
loadInfo, // aLoadInfo
|
||||
aResult);
|
||||
}
|
||||
|
||||
|
@ -299,7 +301,7 @@ nsresult TRR::SendHTTPRequest() {
|
|||
|
||||
if (query.IsEmpty()) {
|
||||
query.Assign(NS_LITERAL_CSTRING("?dns="));
|
||||
} else {
|
||||
} else {
|
||||
query.Append(NS_LITERAL_CSTRING("&dns="));
|
||||
}
|
||||
query.Append(body);
|
||||
|
@ -323,21 +325,22 @@ nsresult TRR::SendHTTPRequest() {
|
|||
return rv;
|
||||
}
|
||||
|
||||
rv = CreateChannelHelper(dnsURI, getter_AddRefs(mChannel));
|
||||
if (NS_FAILED(rv)) {
|
||||
nsCOMPtr<nsIChannel> channel;
|
||||
rv = CreateChannelHelper(dnsURI, getter_AddRefs(channel));
|
||||
if (NS_FAILED(rv) || !channel) {
|
||||
LOG(("TRR:SendHTTPRequest: NewChannel failed!\n"));
|
||||
return rv;
|
||||
}
|
||||
|
||||
mChannel->SetLoadFlags(
|
||||
channel->SetLoadFlags(
|
||||
nsIRequest::LOAD_ANONYMOUS | nsIRequest::INHIBIT_CACHING |
|
||||
nsIRequest::LOAD_BYPASS_CACHE | nsIChannel::LOAD_BYPASS_URL_CLASSIFIER);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = mChannel->SetNotificationCallbacks(this);
|
||||
rv = channel->SetNotificationCallbacks(this);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(mChannel);
|
||||
nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(channel);
|
||||
if (!httpChannel) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
@ -361,8 +364,7 @@ nsresult TRR::SendHTTPRequest() {
|
|||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIHttpChannelInternal> internalChannel =
|
||||
do_QueryInterface(mChannel);
|
||||
nsCOMPtr<nsIHttpChannelInternal> internalChannel = do_QueryInterface(channel);
|
||||
if (!internalChannel) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
@ -380,9 +382,6 @@ nsresult TRR::SendHTTPRequest() {
|
|||
rv = httpChannel->SetRequestMethod(NS_LITERAL_CSTRING("GET"));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
} else {
|
||||
rv = httpChannel->SetRequestHeader(NS_LITERAL_CSTRING("Cache-Control"),
|
||||
NS_LITERAL_CSTRING("no-store"), false);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nsCOMPtr<nsIUploadChannel2> uploadChannel = do_QueryInterface(httpChannel);
|
||||
if (!uploadChannel) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
|
@ -399,6 +398,37 @@ nsresult TRR::SendHTTPRequest() {
|
|||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
rv = SetupTRRServiceChannelInternal(httpChannel, useGet);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = httpChannel->AsyncOpen(this);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_NewTimerWithCallback(getter_AddRefs(mTimeout), this,
|
||||
gTRRService->GetRequestTimeout(),
|
||||
nsITimer::TYPE_ONE_SHOT);
|
||||
|
||||
mChannel = channel;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// static
|
||||
nsresult TRR::SetupTRRServiceChannelInternal(nsIHttpChannel* aChannel,
|
||||
bool aUseGet) {
|
||||
nsCOMPtr<nsIHttpChannel> httpChannel = aChannel;
|
||||
MOZ_ASSERT(httpChannel);
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
if (!aUseGet) {
|
||||
rv = httpChannel->SetRequestHeader(NS_LITERAL_CSTRING("Cache-Control"),
|
||||
NS_LITERAL_CSTRING("no-store"), false);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
// Sanitize the request by removing the Accept-Language header so we minimize
|
||||
// the amount of fingerprintable information we send to the server.
|
||||
if (!StaticPrefs::network_trr_send_accept_language_headers()) {
|
||||
|
@ -423,20 +453,15 @@ nsresult TRR::SendHTTPRequest() {
|
|||
// set the *default* response content type
|
||||
if (NS_FAILED(httpChannel->SetContentType(
|
||||
NS_LITERAL_CSTRING("application/dns-message")))) {
|
||||
LOG(("TRR::SendHTTPRequest: couldn't set content-type!\n"));
|
||||
LOG(("TRR::SetupTRRServiceChannelInternal: couldn't set content-type!\n"));
|
||||
}
|
||||
|
||||
nsCOMPtr<nsITimedChannel> timedChan(do_QueryInterface(httpChannel));
|
||||
timedChan->SetTimingEnabled(true);
|
||||
|
||||
if (NS_SUCCEEDED(httpChannel->AsyncOpen(this))) {
|
||||
NS_NewTimerWithCallback(getter_AddRefs(mTimeout), this,
|
||||
gTRRService->GetRequestTimeout(),
|
||||
nsITimer::TYPE_ONE_SHOT);
|
||||
return NS_OK;
|
||||
if (timedChan) {
|
||||
timedChan->SetTimingEnabled(true);
|
||||
}
|
||||
mChannel = nullptr;
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include "nsIHttpPushListener.h"
|
||||
#include "nsIInterfaceRequestor.h"
|
||||
#include "nsIStreamListener.h"
|
||||
#include "nsHostResolver.h"
|
||||
#include "nsXULAppAPI.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
@ -33,6 +34,7 @@ class DOHaddr : public LinkedListElement<DOHaddr> {
|
|||
};
|
||||
|
||||
class TRRService;
|
||||
class TRRServiceChannel;
|
||||
extern TRRService* gTRRService;
|
||||
|
||||
class DOHresp {
|
||||
|
@ -167,6 +169,10 @@ class TRR : public Runnable,
|
|||
|
||||
nsresult CreateChannelHelper(nsIURI* aUri, nsIChannel** aResult);
|
||||
|
||||
friend class TRRServiceChannel;
|
||||
static nsresult SetupTRRServiceChannelInternal(nsIHttpChannel* aChannel,
|
||||
bool aUseGet);
|
||||
|
||||
nsCOMPtr<nsIChannel> mChannel;
|
||||
enum TrrType mType;
|
||||
TimeStamp mStartTime;
|
||||
|
|
|
@ -18,7 +18,9 @@
|
|||
#include "nsIOService.h"
|
||||
#include "nsISeekableStream.h"
|
||||
#include "nsURLHelper.h"
|
||||
#include "TRRLoadInfo.h"
|
||||
#include "ReferrerInfo.h"
|
||||
#include "TRR.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace net {
|
||||
|
@ -675,9 +677,11 @@ nsresult TRRServiceChannel::OnPush(uint32_t aPushedStreamId,
|
|||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsILoadInfo> loadInfo =
|
||||
static_cast<TRRLoadInfo*>(mLoadInfo.get())->Clone();
|
||||
nsCOMPtr<nsIChannel> pushHttpChannel;
|
||||
rv = gHttpHandler->CreateTRRServiceChannel(pushResource, nullptr, 0, nullptr,
|
||||
nullptr,
|
||||
loadInfo,
|
||||
getter_AddRefs(pushHttpChannel));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
|
@ -945,6 +949,18 @@ TRRServiceChannel::OnStartRequest(nsIRequest* request) {
|
|||
if ((httpStatus < 500) && (httpStatus != 421) && (httpStatus != 407)) {
|
||||
ProcessAltService();
|
||||
}
|
||||
|
||||
if (httpStatus == 300 || httpStatus == 301 || httpStatus == 302 ||
|
||||
httpStatus == 303 || httpStatus == 307 || httpStatus == 308) {
|
||||
nsresult rv = SyncProcessRedirection(httpStatus);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
mStatus = rv;
|
||||
DoNotifyListener();
|
||||
return rv;
|
||||
}
|
||||
} else {
|
||||
NS_WARNING("No response head in OnStartRequest");
|
||||
}
|
||||
|
@ -959,6 +975,124 @@ TRRServiceChannel::OnStartRequest(nsIRequest* request) {
|
|||
return CallOnStartRequest();
|
||||
}
|
||||
|
||||
nsresult TRRServiceChannel::SyncProcessRedirection(uint32_t aHttpStatus) {
|
||||
nsAutoCString location;
|
||||
|
||||
// if a location header was not given, then we can't perform the redirect,
|
||||
// so just carry on as though this were a normal response.
|
||||
if (NS_FAILED(mResponseHead->GetHeader(nsHttp::Location, location))) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// make sure non-ASCII characters in the location header are escaped.
|
||||
nsAutoCString locationBuf;
|
||||
if (NS_EscapeURL(location.get(), -1, esc_OnlyNonASCII | esc_Spaces,
|
||||
locationBuf)) {
|
||||
location = locationBuf;
|
||||
}
|
||||
|
||||
LOG(("redirecting to: %s [redirection-limit=%u]\n", location.get(),
|
||||
uint32_t(mRedirectionLimit)));
|
||||
|
||||
nsCOMPtr<nsIURI> redirectURI;
|
||||
nsresult rv = NS_NewURI(getter_AddRefs(redirectURI), location);
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
LOG(("Invalid URI for redirect: Location: %s\n", location.get()));
|
||||
return NS_ERROR_CORRUPTED_CONTENT;
|
||||
}
|
||||
|
||||
// move the reference of the old location to the new one if the new
|
||||
// one has none.
|
||||
PropagateReferenceIfNeeded(mURI, redirectURI);
|
||||
|
||||
bool rewriteToGET =
|
||||
ShouldRewriteRedirectToGET(aHttpStatus, mRequestHead.ParsedMethod());
|
||||
|
||||
// Let's not rewrite the method to GET for TRR requests.
|
||||
if (rewriteToGET) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// If the method is not safe (such as POST, PUT, DELETE, ...)
|
||||
if (!mRequestHead.IsSafeMethod()) {
|
||||
LOG(("TRRServiceChannel: unsafe redirect to:%s\n", location.get()));
|
||||
}
|
||||
|
||||
uint32_t redirectFlags;
|
||||
if (nsHttp::IsPermanentRedirect(aHttpStatus)) {
|
||||
redirectFlags = nsIChannelEventSink::REDIRECT_PERMANENT;
|
||||
} else {
|
||||
redirectFlags = nsIChannelEventSink::REDIRECT_TEMPORARY;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIChannel> newChannel;
|
||||
nsCOMPtr<nsILoadInfo> redirectLoadInfo =
|
||||
static_cast<TRRLoadInfo*>(mLoadInfo.get())->Clone();
|
||||
rv = gHttpHandler->CreateTRRServiceChannel(redirectURI, nullptr, 0, nullptr,
|
||||
redirectLoadInfo,
|
||||
getter_AddRefs(newChannel));
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = SetupReplacementChannel(redirectURI, newChannel, !rewriteToGET,
|
||||
redirectFlags);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
// Make sure to do this after we received redirect veto answer,
|
||||
// i.e. after all sinks had been notified
|
||||
newChannel->SetOriginalURI(mOriginalURI);
|
||||
|
||||
rv = newChannel->AsyncOpen(mListener);
|
||||
LOG((" new channel AsyncOpen returned %" PRIX32, static_cast<uint32_t>(rv)));
|
||||
|
||||
// close down this channel
|
||||
Cancel(NS_BINDING_REDIRECTED);
|
||||
|
||||
ReleaseListeners();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult TRRServiceChannel::SetupReplacementChannel(nsIURI* aNewURI,
|
||||
nsIChannel* aNewChannel,
|
||||
bool aPreserveMethod,
|
||||
uint32_t aRedirectFlags) {
|
||||
LOG(
|
||||
("TRRServiceChannel::SetupReplacementChannel "
|
||||
"[this=%p newChannel=%p preserveMethod=%d]",
|
||||
this, aNewChannel, aPreserveMethod));
|
||||
|
||||
nsresult rv = HttpBaseChannel::SetupReplacementChannel(
|
||||
aNewURI, aNewChannel, aPreserveMethod, aRedirectFlags);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = CheckRedirectLimit(aRedirectFlags);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aNewChannel);
|
||||
if (!httpChannel) {
|
||||
MOZ_ASSERT(false);
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// convey the mApplyConversion flag (bug 91862)
|
||||
nsCOMPtr<nsIEncodedChannel> encodedChannel = do_QueryInterface(httpChannel);
|
||||
if (encodedChannel) {
|
||||
encodedChannel->SetApplyConversion(mApplyConversion);
|
||||
}
|
||||
|
||||
// Apply TRR specific settings.
|
||||
return TRR::SetupTRRServiceChannelInternal(
|
||||
httpChannel,
|
||||
mRequestHead.ParsedMethod() == nsHttpRequestHead::kMethod_Get);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
TRRServiceChannel::OnDataAvailable(nsIRequest* request, nsIInputStream* input,
|
||||
uint64_t offset, uint32_t count) {
|
||||
|
@ -1306,5 +1440,16 @@ TRRServiceChannel::GetResponseEnd(TimeStamp* _retval) {
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP TRRServiceChannel::SetLoadGroup(nsILoadGroup* aLoadGroup) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
TRRServiceChannel::TimingAllowCheck(nsIPrincipal* aOrigin, bool* aResult) {
|
||||
NS_ENSURE_ARG_POINTER(aResult);
|
||||
*aResult = true;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -101,6 +101,8 @@ class TRRServiceChannel : public HttpBaseChannel,
|
|||
NS_IMETHOD GetRequestStart(mozilla::TimeStamp* aRequestStart) override;
|
||||
NS_IMETHOD GetResponseStart(mozilla::TimeStamp* aResponseStart) override;
|
||||
NS_IMETHOD GetResponseEnd(mozilla::TimeStamp* aResponseEnd) override;
|
||||
NS_IMETHOD SetLoadGroup(nsILoadGroup* aLoadGroup) override;
|
||||
NS_IMETHOD TimingAllowCheck(nsIPrincipal* aOrigin, bool* aResult) override;
|
||||
|
||||
protected:
|
||||
TRRServiceChannel();
|
||||
|
@ -125,6 +127,10 @@ class TRRServiceChannel : public HttpBaseChannel,
|
|||
nsresult ResolveProxy();
|
||||
void AfterApplyContentConversions(nsresult aResult,
|
||||
nsIStreamListener* aListener);
|
||||
nsresult SyncProcessRedirection(uint32_t aHttpStatus);
|
||||
virtual MOZ_MUST_USE nsresult SetupReplacementChannel(
|
||||
nsIURI* aNewURI, nsIChannel* aNewChannel, bool aPreserveMethod,
|
||||
uint32_t aRedirectFlags) override;
|
||||
|
||||
// True only when we have computed the value of the top window origin.
|
||||
bool mTopWindowOriginComputed;
|
||||
|
|
|
@ -154,6 +154,7 @@ LOCAL_INCLUDES += [
|
|||
'/extensions/auth',
|
||||
'/netwerk/base',
|
||||
'/netwerk/cookie',
|
||||
'/netwerk/dns',
|
||||
'/netwerk/ipc',
|
||||
'/netwerk/socket/neqo_glue',
|
||||
'/netwerk/url-classifier',
|
||||
|
|
|
@ -1686,6 +1686,32 @@ add_task(async function test_content_encoding_gzip() {
|
|||
await new DNSListener("bar.example.com", "2.2.2.2");
|
||||
});
|
||||
|
||||
add_task(async function test_redirect_get() {
|
||||
dns.clearCache(true);
|
||||
Services.prefs.setIntPref("network.trr.mode", 3); // TRR-only
|
||||
Services.prefs.setCharPref(
|
||||
"network.trr.uri",
|
||||
`https://foo.example.com:${h2Port}/doh?redirect=4.4.4.4{&dns}`
|
||||
);
|
||||
Services.prefs.clearUserPref("network.trr.allow-rfc1918");
|
||||
Services.prefs.setBoolPref("network.trr.useGET", true);
|
||||
Services.prefs.setBoolPref("network.trr.disable-ECS", true);
|
||||
await new DNSListener("ecs.example.com", "4.4.4.4");
|
||||
});
|
||||
|
||||
// test redirect
|
||||
add_task(async function test_redirect_post() {
|
||||
dns.clearCache(true);
|
||||
Services.prefs.setIntPref("network.trr.mode", 3);
|
||||
Services.prefs.setBoolPref("network.trr.useGET", false);
|
||||
Services.prefs.setCharPref(
|
||||
"network.trr.uri",
|
||||
`https://foo.example.com:${h2Port}/doh?redirect=4.4.4.4`
|
||||
);
|
||||
|
||||
await new DNSListener("bar.example.com", "4.4.4.4");
|
||||
});
|
||||
|
||||
// confirmationNS set without confirmed NS yet
|
||||
// checks that we properly fall back to DNS is confirmation is not ready yet
|
||||
add_task(async function test_resolve_not_confirmed() {
|
||||
|
|
|
@ -580,6 +580,30 @@ function handleRequest(req, res) {
|
|||
responseIP = "5.5.5.5";
|
||||
}
|
||||
|
||||
let redirect = u.query.redirect;
|
||||
if (redirect) {
|
||||
responseIP = redirect;
|
||||
if (u.query.dns) {
|
||||
res.setHeader(
|
||||
"Location",
|
||||
"https://localhost:" +
|
||||
serverPort +
|
||||
"/doh?responseIP=" +
|
||||
responseIP +
|
||||
"&dns=" +
|
||||
u.query.dns
|
||||
);
|
||||
} else {
|
||||
res.setHeader(
|
||||
"Location",
|
||||
"https://localhost:" + serverPort + "/doh?responseIP=" + responseIP
|
||||
);
|
||||
}
|
||||
res.writeHead(307);
|
||||
res.end("");
|
||||
return;
|
||||
}
|
||||
|
||||
if (u.query.auth) {
|
||||
// There's a Set-Cookie: header in the response for "/dns" , which this
|
||||
// request subsequently would include if the http channel wasn't
|
||||
|
@ -758,7 +782,10 @@ function handleRequest(req, res) {
|
|||
payload = Buffer.concat([payload, chunk]);
|
||||
});
|
||||
req.on("end", function finishedData() {
|
||||
emitResponse(res, payload);
|
||||
// parload is empty when we send redirect response.
|
||||
if (payload.length) {
|
||||
emitResponse(res, payload);
|
||||
}
|
||||
});
|
||||
return;
|
||||
} else if (u.pathname === "/dns-cname-a") {
|
||||
|
|
Загрузка…
Ссылка в новой задаче