bug 751465 - websockets dns and proxies r=jduell r=bsmedberg

--HG--
extra : rebase_source : ad2046a95f1ec9000577cc0f67aedc0766a51ed2
This commit is contained in:
Patrick McManus 2014-01-06 13:52:42 -05:00
parent ab53c3e13d
commit e3e7849089
3 changed files with 110 additions and 25 deletions

View File

@ -69,7 +69,7 @@ using namespace mozilla;
namespace mozilla { namespace mozilla {
namespace net { namespace net {
NS_IMPL_ISUPPORTS11(WebSocketChannel, NS_IMPL_ISUPPORTS12(WebSocketChannel,
nsIWebSocketChannel, nsIWebSocketChannel,
nsIHttpUpgradeListener, nsIHttpUpgradeListener,
nsIRequestObserver, nsIRequestObserver,
@ -79,6 +79,7 @@ NS_IMPL_ISUPPORTS11(WebSocketChannel,
nsIOutputStreamCallback, nsIOutputStreamCallback,
nsITimerCallback, nsITimerCallback,
nsIDNSListener, nsIDNSListener,
nsIProtocolProxyCallback,
nsIInterfaceRequestor, nsIInterfaceRequestor,
nsIChannelEventSink) nsIChannelEventSink)
@ -994,7 +995,7 @@ WebSocketChannel::~WebSocketChannel()
MOZ_ASSERT(mCalledOnStop, "WebSocket was opened but OnStop was not called"); MOZ_ASSERT(mCalledOnStop, "WebSocket was opened but OnStop was not called");
MOZ_ASSERT(mStopped, "WebSocket was opened but never stopped"); MOZ_ASSERT(mStopped, "WebSocket was opened but never stopped");
} }
MOZ_ASSERT(!mDNSRequest, "DNS Request still alive at destruction"); MOZ_ASSERT(!mCancelable, "DNS/Proxy Request still alive at destruction");
MOZ_ASSERT(!mConnecting, "Should not be connecting in destructor"); MOZ_ASSERT(!mConnecting, "Should not be connecting in destructor");
moz_free(mBuffer); moz_free(mBuffer);
@ -1959,9 +1960,9 @@ WebSocketChannel::StopSession(nsresult reason)
CleanupConnection(); CleanupConnection();
} }
if (mDNSRequest) { if (mCancelable) {
mDNSRequest->Cancel(NS_ERROR_UNEXPECTED); mCancelable->Cancel(NS_ERROR_UNEXPECTED);
mDNSRequest = nullptr; mCancelable = nullptr;
} }
mInflateReader = nullptr; mInflateReader = nullptr;
@ -2198,16 +2199,9 @@ WebSocketChannel::SetupRequest()
} }
nsresult nsresult
WebSocketChannel::ApplyForAdmission() WebSocketChannel::DoAdmissionDNS()
{ {
LOG(("WebSocketChannel::ApplyForAdmission() %p\n", this));
// Websockets has a policy of 1 session at a time being allowed in the
// CONNECTING state per server IP address (not hostname)
nsresult rv; nsresult rv;
nsCOMPtr<nsIDNSService> dns = do_GetService(NS_DNSSERVICE_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
nsCString hostName; nsCString hostName;
rv = mURI->GetHost(hostName); rv = mURI->GetHost(hostName);
@ -2217,15 +2211,39 @@ WebSocketChannel::ApplyForAdmission()
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
if (mPort == -1) if (mPort == -1)
mPort = (mEncrypted ? kDefaultWSSPort : kDefaultWSPort); mPort = (mEncrypted ? kDefaultWSSPort : kDefaultWSPort);
nsCOMPtr<nsIDNSService> dns = do_GetService(NS_DNSSERVICE_CONTRACTID, &rv);
// expect the callback in ::OnLookupComplete NS_ENSURE_SUCCESS(rv, rv);
LOG(("WebSocketChannel::ApplyForAdmission: checking for concurrent open\n"));
nsCOMPtr<nsIThread> mainThread; nsCOMPtr<nsIThread> mainThread;
NS_GetMainThread(getter_AddRefs(mainThread)); NS_GetMainThread(getter_AddRefs(mainThread));
dns->AsyncResolve(hostName, 0, this, mainThread, getter_AddRefs(mDNSRequest)); MOZ_ASSERT(!mCancelable);
NS_ENSURE_SUCCESS(rv, rv); return dns->AsyncResolve(hostName, 0, this, mainThread, getter_AddRefs(mCancelable));
}
return NS_OK; nsresult
WebSocketChannel::ApplyForAdmission()
{
LOG(("WebSocketChannel::ApplyForAdmission() %p\n", this));
// Websockets has a policy of 1 session at a time being allowed in the
// CONNECTING state per server IP address (not hostname)
// Check to see if a proxy is being used before making DNS call
nsCOMPtr<nsIProtocolProxyService> pps =
do_GetService(NS_PROTOCOLPROXYSERVICE_CONTRACTID);
if (!pps) {
// go straight to DNS
// expect the callback in ::OnLookupComplete
LOG(("WebSocketChannel::ApplyForAdmission: checking for concurrent open\n"));
return DoAdmissionDNS();
}
MOZ_ASSERT(!mCancelable);
return pps->AsyncResolve(mURI,
nsIProtocolProxyService::RESOLVE_PREFER_HTTPS_PROXY |
nsIProtocolProxyService::RESOLVE_ALWAYS_TUNNEL,
this, getter_AddRefs(mCancelable));
} }
// Called after both OnStartRequest and OnTransportAvailable have // Called after both OnStartRequest and OnTransportAvailable have
@ -2300,26 +2318,28 @@ WebSocketChannel::ReportConnectionTelemetry()
NS_IMETHODIMP NS_IMETHODIMP
WebSocketChannel::OnLookupComplete(nsICancelable *aRequest, WebSocketChannel::OnLookupComplete(nsICancelable *aRequest,
nsIDNSRecord *aRecord, nsIDNSRecord *aRecord,
nsresult aStatus) nsresult aStatus)
{ {
LOG(("WebSocketChannel::OnLookupComplete() %p [%p %p %x]\n", LOG(("WebSocketChannel::OnLookupComplete() %p [%p %p %x]\n",
this, aRequest, aRecord, aStatus)); this, aRequest, aRecord, aStatus));
NS_ABORT_IF_FALSE(NS_IsMainThread(), "not main thread"); NS_ABORT_IF_FALSE(NS_IsMainThread(), "not main thread");
NS_ABORT_IF_FALSE(aRequest == mDNSRequest || mStopped,
"wrong dns request");
if (mStopped) { if (mStopped) {
LOG(("WebSocketChannel::OnLookupComplete: Request Already Stopped\n")); LOG(("WebSocketChannel::OnLookupComplete: Request Already Stopped\n"));
mCancelable = nullptr;
return NS_OK; return NS_OK;
} }
mDNSRequest = nullptr; mCancelable = nullptr;
// These failures are not fatal - we just use the hostname as the key // These failures are not fatal - we just use the hostname as the key
if (NS_FAILED(aStatus)) { if (NS_FAILED(aStatus)) {
LOG(("WebSocketChannel::OnLookupComplete: No DNS Response\n")); LOG(("WebSocketChannel::OnLookupComplete: No DNS Response\n"));
// set host in case we got here without calling DoAdmissionDNS()
mURI->GetHost(mAddress);
} else { } else {
nsresult rv = aRecord->GetNextAddrAsString(mAddress); nsresult rv = aRecord->GetNextAddrAsString(mAddress);
if (NS_FAILED(rv)) if (NS_FAILED(rv))
@ -2332,6 +2352,35 @@ WebSocketChannel::OnLookupComplete(nsICancelable *aRequest,
return NS_OK; return NS_OK;
} }
// nsIProtocolProxyCallback
NS_IMETHODIMP
WebSocketChannel::OnProxyAvailable(nsICancelable *aRequest, nsIURI *aURI,
nsIProxyInfo *pi, nsresult status)
{
if (mStopped) {
LOG(("WebSocketChannel::OnProxyAvailable: [%p] Request Already Stopped\n", this));
mCancelable = nullptr;
return NS_OK;
}
MOZ_ASSERT(aRequest == mCancelable);
mCancelable = nullptr;
nsAutoCString type;
if (NS_SUCCEEDED(status) && pi &&
NS_SUCCEEDED(pi->GetType(type)) &&
!type.EqualsLiteral("direct")) {
LOG(("WebSocket OnProxyAvailable [%p] Proxy found skip DNS lookup\n", this));
// call DNS callback directly without DNS resolver
OnLookupComplete(nullptr, nullptr, NS_ERROR_FAILURE);
return NS_OK;
}
LOG(("WebSocketChannel::OnProxyAvailable[%] checking DNS resolution\n", this));
DoAdmissionDNS();
return NS_OK;
}
// nsIInterfaceRequestor // nsIInterfaceRequestor
NS_IMETHODIMP NS_IMETHODIMP

View File

@ -14,6 +14,7 @@
#include "nsIAsyncOutputStream.h" #include "nsIAsyncOutputStream.h"
#include "nsITimer.h" #include "nsITimer.h"
#include "nsIDNSListener.h" #include "nsIDNSListener.h"
#include "nsIProtocolProxyCallback.h"
#include "nsIChannelEventSink.h" #include "nsIChannelEventSink.h"
#include "nsIHttpChannelInternal.h" #include "nsIHttpChannelInternal.h"
#include "BaseWebSocketChannel.h" #include "BaseWebSocketChannel.h"
@ -61,6 +62,7 @@ class WebSocketChannel : public BaseWebSocketChannel,
public nsIOutputStreamCallback, public nsIOutputStreamCallback,
public nsITimerCallback, public nsITimerCallback,
public nsIDNSListener, public nsIDNSListener,
public nsIProtocolProxyCallback,
public nsIInterfaceRequestor, public nsIInterfaceRequestor,
public nsIChannelEventSink public nsIChannelEventSink
{ {
@ -73,6 +75,7 @@ public:
NS_DECL_NSIOUTPUTSTREAMCALLBACK NS_DECL_NSIOUTPUTSTREAMCALLBACK
NS_DECL_NSITIMERCALLBACK NS_DECL_NSITIMERCALLBACK
NS_DECL_NSIDNSLISTENER NS_DECL_NSIDNSLISTENER
NS_DECL_NSIPROTOCOLPROXYCALLBACK
NS_DECL_NSIINTERFACEREQUESTOR NS_DECL_NSIINTERFACEREQUESTOR
NS_DECL_NSICHANNELEVENTSINK NS_DECL_NSICHANNELEVENTSINK
@ -134,6 +137,7 @@ private:
nsresult HandleExtensions(); nsresult HandleExtensions();
nsresult SetupRequest(); nsresult SetupRequest();
nsresult ApplyForAdmission(); nsresult ApplyForAdmission();
nsresult DoAdmissionDNS();
nsresult StartWebsocketData(); nsresult StartWebsocketData();
uint16_t ResultToCloseCode(nsresult resultCode); uint16_t ResultToCloseCode(nsresult resultCode);
void ReportConnectionTelemetry(); void ReportConnectionTelemetry();
@ -165,7 +169,7 @@ private:
nsCOMPtr<nsIEventTarget> mSocketThread; nsCOMPtr<nsIEventTarget> mSocketThread;
nsCOMPtr<nsIHttpChannelInternal> mChannel; nsCOMPtr<nsIHttpChannelInternal> mChannel;
nsCOMPtr<nsIHttpChannel> mHttpChannel; nsCOMPtr<nsIHttpChannel> mHttpChannel;
nsCOMPtr<nsICancelable> mDNSRequest; nsCOMPtr<nsICancelable> mCancelable;
nsCOMPtr<nsIAsyncVerifyRedirectCallback> mRedirectCallback; nsCOMPtr<nsIAsyncVerifyRedirectCallback> mRedirectCallback;
nsCOMPtr<nsIRandomGenerator> mRandomGenerator; nsCOMPtr<nsIRandomGenerator> mRandomGenerator;

View File

@ -899,6 +899,24 @@ NS_IMETHODIMP _class::QueryInterface(REFNSIID aIID, void** aInstancePtr) \
NS_INTERFACE_TABLE_ENTRY_AMBIGUOUS(_class, nsISupports, _i1) \ NS_INTERFACE_TABLE_ENTRY_AMBIGUOUS(_class, nsISupports, _i1) \
NS_INTERFACE_TABLE_END NS_INTERFACE_TABLE_END
#define NS_INTERFACE_TABLE12(_class, _i1, _i2, _i3, _i4, _i5, _i6, _i7, \
_i8, _i9, _i10, _i11, _i12) \
NS_INTERFACE_TABLE_BEGIN \
NS_INTERFACE_TABLE_ENTRY(_class, _i1) \
NS_INTERFACE_TABLE_ENTRY(_class, _i2) \
NS_INTERFACE_TABLE_ENTRY(_class, _i3) \
NS_INTERFACE_TABLE_ENTRY(_class, _i4) \
NS_INTERFACE_TABLE_ENTRY(_class, _i5) \
NS_INTERFACE_TABLE_ENTRY(_class, _i6) \
NS_INTERFACE_TABLE_ENTRY(_class, _i7) \
NS_INTERFACE_TABLE_ENTRY(_class, _i8) \
NS_INTERFACE_TABLE_ENTRY(_class, _i9) \
NS_INTERFACE_TABLE_ENTRY(_class, _i10) \
NS_INTERFACE_TABLE_ENTRY(_class, _i11) \
NS_INTERFACE_TABLE_ENTRY(_class, _i12) \
NS_INTERFACE_TABLE_ENTRY_AMBIGUOUS(_class, nsISupports, _i1) \
NS_INTERFACE_TABLE_END
#define NS_IMPL_QUERY_INTERFACE0(_class) \ #define NS_IMPL_QUERY_INTERFACE0(_class) \
NS_INTERFACE_TABLE_HEAD(_class) \ NS_INTERFACE_TABLE_HEAD(_class) \
NS_INTERFACE_TABLE0(_class) \ NS_INTERFACE_TABLE0(_class) \
@ -965,6 +983,13 @@ NS_IMETHODIMP _class::QueryInterface(REFNSIID aIID, void** aInstancePtr) \
_i9, _i10, _i11) \ _i9, _i10, _i11) \
NS_INTERFACE_TABLE_TAIL NS_INTERFACE_TABLE_TAIL
#define NS_IMPL_QUERY_INTERFACE12(_class, _i1, _i2, _i3, _i4, _i5, _i6, \
_i7, _i8, _i9, _i10, _i11, _i12) \
NS_INTERFACE_TABLE_HEAD(_class) \
NS_INTERFACE_TABLE12(_class, _i1, _i2, _i3, _i4, _i5, _i6, _i7, _i8, \
_i9, _i10, _i11, _i12) \
NS_INTERFACE_TABLE_TAIL
/** /**
* Declare that you're going to inherit from something that already * Declare that you're going to inherit from something that already
@ -1288,6 +1313,13 @@ NS_IMETHODIMP_(nsrefcnt) Class::Release(void) \
NS_IMPL_QUERY_INTERFACE11(_class, _i1, _i2, _i3, _i4, _i5, _i6, _i7, _i8, \ NS_IMPL_QUERY_INTERFACE11(_class, _i1, _i2, _i3, _i4, _i5, _i6, _i7, _i8, \
_i9, _i10, _i11) _i9, _i10, _i11)
#define NS_IMPL_ISUPPORTS12(_class, _i1, _i2, _i3, _i4, _i5, _i6, _i7, _i8, \
_i9, _i10, _i11, _i12) \
NS_IMPL_ADDREF(_class) \
NS_IMPL_RELEASE(_class) \
NS_IMPL_QUERY_INTERFACE12(_class, _i1, _i2, _i3, _i4, _i5, _i6, _i7, _i8, \
_i9, _i10, _i11, _i12)
#define NS_IMPL_ISUPPORTS_INHERITED0(Class, Super) \ #define NS_IMPL_ISUPPORTS_INHERITED0(Class, Super) \
NS_IMPL_QUERY_INTERFACE_INHERITED0(Class, Super) \ NS_IMPL_QUERY_INTERFACE_INHERITED0(Class, Super) \
NS_IMPL_ADDREF_INHERITED(Class, Super) \ NS_IMPL_ADDREF_INHERITED(Class, Super) \