forked from mirrors/gecko-dev
Bug 1896625 - Support creating TLS tunnel for WebrtcTCPSocket, a=dmeehan
Differential Revision: https://phabricator.services.mozilla.com/D217025
This commit is contained in:
parent
7119cc28b9
commit
8d1f864c40
14 changed files with 128 additions and 33 deletions
|
|
@ -4907,8 +4907,9 @@ std::unique_ptr<NrSocketProxyConfig> PeerConnectionImpl::GetProxyConfig()
|
|||
|
||||
TabId id = browserChild->GetTabId();
|
||||
nsCOMPtr<nsILoadInfo> loadInfo =
|
||||
new net::LoadInfo(doc->NodePrincipal(), doc->NodePrincipal(), doc, 0,
|
||||
nsIContentPolicy::TYPE_INVALID);
|
||||
new net::LoadInfo(doc->NodePrincipal(), doc->NodePrincipal(), doc,
|
||||
nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL,
|
||||
nsIContentPolicy::TYPE_PROXIED_WEBRTC_MEDIA);
|
||||
|
||||
net::LoadInfoArgs loadInfoArgs;
|
||||
MOZ_ALWAYS_SUCCEEDS(
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
#include "nsString.h"
|
||||
#include "mozilla/dom/ContentProcessManager.h"
|
||||
#include "mozilla/dom/BrowserParent.h"
|
||||
#include "mozilla/StaticPrefs_media.h"
|
||||
#include "nsISocketTransportService.h"
|
||||
#include "nsICancelable.h"
|
||||
#include "nsSocketTransportService2.h"
|
||||
|
|
@ -420,14 +421,14 @@ nsresult WebrtcTCPSocket::OpenWithHttpProxy() {
|
|||
// introduce new behavior. can't follow redirects on connect anyway.
|
||||
nsCOMPtr<nsIChannel> localChannel;
|
||||
rv = ioService->NewChannelFromURIWithProxyFlags(
|
||||
mURI, nullptr,
|
||||
// Proxy flags are overridden by SetConnectOnly()
|
||||
0, loadInfo->LoadingNode(), loadInfo->GetLoadingPrincipal(),
|
||||
mURI, mURI,
|
||||
nsIProtocolProxyService::RESOLVE_PREFER_HTTPS_PROXY |
|
||||
nsIProtocolProxyService::RESOLVE_ALWAYS_TUNNEL,
|
||||
loadInfo->LoadingNode(), loadInfo->GetLoadingPrincipal(),
|
||||
loadInfo->TriggeringPrincipal(),
|
||||
nsILoadInfo::SEC_COOKIES_OMIT |
|
||||
// We need this flag to allow loads from any origin since this channel
|
||||
// is being used to CONNECT to an HTTP proxy.
|
||||
nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL,
|
||||
// We need this flag to allow loads from any origin since this channel
|
||||
// is being used to CONNECT to an HTTP proxy.
|
||||
nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL,
|
||||
nsIContentPolicy::TYPE_PROXIED_WEBRTC_MEDIA,
|
||||
getter_AddRefs(localChannel));
|
||||
if (NS_FAILED(rv)) {
|
||||
|
|
@ -448,6 +449,9 @@ nsresult WebrtcTCPSocket::OpenWithHttpProxy() {
|
|||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
rv = localChannel->SetLoadInfo(loadInfo);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
httpChannel->SetNotificationCallbacks(this);
|
||||
|
||||
// don't block webrtc proxy setup with other requests
|
||||
|
|
@ -465,7 +469,8 @@ nsresult WebrtcTCPSocket::OpenWithHttpProxy() {
|
|||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
rv = httpChannel->SetConnectOnly();
|
||||
rv = httpChannel->SetConnectOnly(
|
||||
mozilla::StaticPrefs::media_webrtc_tls_tunnel_for_all_proxy());
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11350,6 +11350,11 @@
|
|||
#endif
|
||||
mirror: always
|
||||
|
||||
- name: media.webrtc.tls_tunnel_for_all_proxy
|
||||
type: bool
|
||||
value: true
|
||||
mirror: always
|
||||
|
||||
# If true, then we require explicit approval from the embedding app (ex. Fenix)
|
||||
# on GeckoView to know if we can allow audible, inaudible media or both kinds
|
||||
# of media to autoplay.
|
||||
|
|
|
|||
|
|
@ -3757,7 +3757,7 @@ HttpBaseChannel::GetOnlyConnect(bool* aOnlyConnect) {
|
|||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HttpBaseChannel::SetConnectOnly() {
|
||||
HttpBaseChannel::SetConnectOnly(bool aTlsTunnel) {
|
||||
ENSURE_CALLED_BEFORE_CONNECT();
|
||||
|
||||
if (!mUpgradeProtocolCallback) {
|
||||
|
|
@ -3765,6 +3765,9 @@ HttpBaseChannel::SetConnectOnly() {
|
|||
}
|
||||
|
||||
mCaps |= NS_HTTP_CONNECT_ONLY;
|
||||
if (aTlsTunnel) {
|
||||
mCaps |= NS_HTTP_TLS_TUNNEL;
|
||||
}
|
||||
mProxyResolveFlags = nsIProtocolProxyService::RESOLVE_PREFER_HTTPS_PROXY |
|
||||
nsIProtocolProxyService::RESOLVE_ALWAYS_TUNNEL;
|
||||
return SetLoadFlags(nsIRequest::INHIBIT_CACHING | nsIChannel::LOAD_ANONYMOUS |
|
||||
|
|
|
|||
|
|
@ -273,7 +273,7 @@ class HttpBaseChannel : public nsHashPropertyBag,
|
|||
NS_IMETHOD GetRemoteAddress(nsACString& addr) override;
|
||||
NS_IMETHOD GetRemotePort(int32_t* port) override;
|
||||
NS_IMETHOD GetOnlyConnect(bool* aOnlyConnect) override;
|
||||
NS_IMETHOD SetConnectOnly() override;
|
||||
NS_IMETHOD SetConnectOnly(bool aTlsTunnel) override;
|
||||
NS_IMETHOD GetAllowSpdy(bool* aAllowSpdy) override;
|
||||
NS_IMETHOD SetAllowSpdy(bool aAllowSpdy) override;
|
||||
NS_IMETHOD GetAllowHttp3(bool* aAllowHttp3) override;
|
||||
|
|
|
|||
|
|
@ -360,6 +360,7 @@ NS_INTERFACE_MAP_BEGIN(TLSTransportLayer)
|
|||
NS_INTERFACE_MAP_ENTRY(nsIInputStreamCallback)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIOutputStreamCallback)
|
||||
NS_INTERFACE_MAP_ENTRY_CONCRETE(TLSTransportLayer)
|
||||
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsITransport)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
TLSTransportLayer::TLSTransportLayer(nsISocketTransport* aTransport,
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=4 sw=2 sts=2 et cin: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
|
|
|
|||
|
|
@ -186,6 +186,10 @@ extern const nsCString kHttp3Versions[];
|
|||
// When set, disallow to connect to a HTTP/2 proxy.
|
||||
#define NS_HTTP_DISALLOW_HTTP2_PROXY (1 << 28)
|
||||
|
||||
// When set, setup TLS tunnel even when HTTP proxy is used.
|
||||
// Need to be used together with NS_HTTP_CONNECT_ONLY
|
||||
#define NS_HTTP_TLS_TUNNEL (1 << 29)
|
||||
|
||||
#define NS_HTTP_TRR_FLAGS_FROM_MODE(x) ((static_cast<uint32_t>(x) & 3) << 19)
|
||||
|
||||
#define NS_HTTP_TRR_MODE_FROM_FLAGS(x) \
|
||||
|
|
|
|||
|
|
@ -1067,25 +1067,26 @@ void nsHttpConnection::HandleTunnelResponse(uint16_t responseStatus,
|
|||
*reset = true;
|
||||
}
|
||||
nsresult rv;
|
||||
// CONNECT only flag doesn't do the tls setup. https here only
|
||||
// ensures a proxy tunnel was used not that tls is setup.
|
||||
if (isHttps) {
|
||||
if (!onlyConnect) {
|
||||
if (mConnInfo->UsingHttpsProxy()) {
|
||||
LOG(("%p new TLSFilterTransaction %s %d\n", this, mConnInfo->Origin(),
|
||||
mConnInfo->OriginPort()));
|
||||
SetupSecondaryTLS();
|
||||
}
|
||||
bool skipSSL = false;
|
||||
if (mConnInfo->UsingHttpsProxy() ||
|
||||
mTransactionCaps & NS_HTTP_TLS_TUNNEL) {
|
||||
LOG(("%p SetupSecondaryTLS %s %d\n", this, mConnInfo->Origin(),
|
||||
mConnInfo->OriginPort()));
|
||||
SetupSecondaryTLS();
|
||||
} else if (onlyConnect) {
|
||||
MOZ_ASSERT(mConnInfo->UsingOnlyHttpProxy(), "Must be a HTTP proxy");
|
||||
|
||||
// We have CONNECT only flag and a HTTP proxy is used here, so we can
|
||||
// just skip setting up SSL. We have to mark this as complete to finish
|
||||
// the transaction and be upgraded.
|
||||
mTlsHandshaker->SetNPNComplete();
|
||||
skipSSL = true;
|
||||
}
|
||||
|
||||
if (!skipSSL) {
|
||||
rv = mTlsHandshaker->InitSSLParams(false, true);
|
||||
LOG(("InitSSLParams [rv=%" PRIx32 "]\n", static_cast<uint32_t>(rv)));
|
||||
} else {
|
||||
// We have an https protocol but the CONNECT only flag was
|
||||
// specified. The consumer only wants a raw socket to the
|
||||
// proxy. We have to mark this as complete to finish the
|
||||
// transaction and be upgraded. OnSocketReadable() uses this
|
||||
// to detect an inactive tunnel and blocks completion.
|
||||
mTlsHandshaker->SetNPNComplete();
|
||||
}
|
||||
}
|
||||
rv = mSocketOut->AsyncWait(this, 0, 0, nullptr);
|
||||
|
|
@ -1612,14 +1613,15 @@ nsresult nsHttpConnection::OnSocketWritable() {
|
|||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
if (mState == HttpConnectionState::REQUEST) {
|
||||
if (mState == HttpConnectionState::REQUEST &&
|
||||
mTlsHandshaker->EnsureNPNComplete()) {
|
||||
// Don't need to check this each write attempt since it is only
|
||||
// updated after OnSocketWritable completes.
|
||||
// We've already done primary tls (if needed) and sent our CONNECT.
|
||||
// If we're doing a CONNECT only request there's no need to write
|
||||
// the http transaction or do the SSL handshake here.
|
||||
LOG(("return ok because proxy connect successful\n"));
|
||||
return NS_OK;
|
||||
// the http transaction.
|
||||
LOG(("return NS_BASE_STREAM_CLOSED to make transaction closed\n"));
|
||||
return NS_BASE_STREAM_CLOSED;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -236,6 +236,9 @@ class nsHttpConnectionInfo final : public ARefBase {
|
|||
// Returns true when proxying over HTTP or HTTPS
|
||||
bool UsingHttpProxy() const { return mUsingHttpProxy || mUsingHttpsProxy; }
|
||||
|
||||
// Returns true when only proxying over HTTP
|
||||
bool UsingOnlyHttpProxy() const { return mUsingHttpProxy; }
|
||||
|
||||
// Returns true when proxying over HTTPS
|
||||
bool UsingHttpsProxy() const { return mUsingHttpsProxy; }
|
||||
|
||||
|
|
|
|||
|
|
@ -211,8 +211,11 @@ interface nsIHttpChannelInternal : nsISupports
|
|||
*
|
||||
* Proxy resolve flags are set with RESOLVE_PREFER_HTTPS_PROXY and
|
||||
* RESOLVE_ALWAYS_TUNNEL.
|
||||
*
|
||||
* @param tlsTunnel
|
||||
* When true, always setup TLS tunnel
|
||||
*/
|
||||
[must_use] void setConnectOnly();
|
||||
[must_use] void setConnectOnly(in boolean tlsTunnel);
|
||||
|
||||
/**
|
||||
* True iff the channel is CONNECT only.
|
||||
|
|
|
|||
|
|
@ -229,7 +229,7 @@ function makeChan(url) {
|
|||
|
||||
var internal = chan.QueryInterface(Ci.nsIHttpChannelInternal);
|
||||
internal.HTTPUpgrade(ALPN, upgradeListener);
|
||||
internal.setConnectOnly();
|
||||
internal.setConnectOnly(false);
|
||||
|
||||
return chan;
|
||||
}
|
||||
|
|
|
|||
62
netwerk/test/unit/test_proxyconnect_https.js
Normal file
62
netwerk/test/unit/test_proxyconnect_https.js
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
/* 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/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
/* import-globals-from head_cache.js */
|
||||
/* import-globals-from head_cookies.js */
|
||||
/* import-globals-from head_channels.js */
|
||||
/* import-globals-from head_servers.js */
|
||||
|
||||
const { TestUtils } = ChromeUtils.importESModule(
|
||||
"resource://testing-common/TestUtils.sys.mjs"
|
||||
);
|
||||
|
||||
function makeChan(uri) {
|
||||
let chan = NetUtil.newChannel({
|
||||
uri,
|
||||
loadUsingSystemPrincipal: true,
|
||||
}).QueryInterface(Ci.nsIHttpChannel);
|
||||
chan.loadFlags = Ci.nsIChannel.LOAD_INITIAL_DOCUMENT_URI;
|
||||
return chan;
|
||||
}
|
||||
|
||||
let gotTransport = false;
|
||||
var upgradeListener = {
|
||||
onTransportAvailable: () => {
|
||||
gotTransport = true;
|
||||
},
|
||||
QueryInterface: ChromeUtils.generateQI(["nsIHttpUpgradeListener"]),
|
||||
};
|
||||
|
||||
add_task(async function test_connect_only_https() {
|
||||
let certdb = Cc["@mozilla.org/security/x509certdb;1"].getService(
|
||||
Ci.nsIX509CertDB
|
||||
);
|
||||
addCertFromFile(certdb, "http2-ca.pem", "CTu,u,u");
|
||||
addCertFromFile(certdb, "proxy-ca.pem", "CTu,u,u");
|
||||
|
||||
let proxy = new NodeHTTPSProxyServer();
|
||||
await proxy.start();
|
||||
let server = new NodeHTTPSServer();
|
||||
await server.start();
|
||||
registerCleanupFunction(async () => {
|
||||
await proxy.stop();
|
||||
await server.stop();
|
||||
});
|
||||
|
||||
let chan = makeChan(`https://localhost:${server.port()}/test`);
|
||||
var internal = chan.QueryInterface(Ci.nsIHttpChannelInternal);
|
||||
internal.HTTPUpgrade("webrtc", upgradeListener);
|
||||
internal.setConnectOnly(false);
|
||||
await new Promise(resolve => {
|
||||
chan.asyncOpen(new ChannelListener(resolve, null, CL_ALLOW_UNKNOWN_CL));
|
||||
});
|
||||
|
||||
await TestUtils.waitForCondition(() => gotTransport);
|
||||
Assert.ok(gotTransport);
|
||||
|
||||
await proxy.stop();
|
||||
await server.stop();
|
||||
});
|
||||
|
|
@ -1289,6 +1289,11 @@ skip-if = [
|
|||
["test_connection_coalescing.js"]
|
||||
|
||||
["test_default_uri_bypass.js"]
|
||||
|
||||
["test_proxyconnect_https.js"]
|
||||
skip-if = [
|
||||
"socketprocess_networking",
|
||||
]
|
||||
["test_bug1883496.js"]
|
||||
skip-if = [
|
||||
"os != 'android'",
|
||||
|
|
|
|||
Loading…
Reference in a new issue