bug 723628 - speculative connect hint interface r=honzab sr=biesi

This commit is contained in:
Patrick McManus 2012-04-25 08:54:42 -04:00
Родитель f7da014875
Коммит ecdfa8e875
8 изменённых файлов: 265 добавлений и 27 удалений

Просмотреть файл

@ -103,6 +103,7 @@ XPIDLSRCS = \
nsITransport.idl \ nsITransport.idl \
nsISocketTransport.idl \ nsISocketTransport.idl \
nsISocketTransportService.idl \ nsISocketTransportService.idl \
nsISpeculativeConnect.idl \
nsIServerSocket.idl \ nsIServerSocket.idl \
nsIResumableChannel.idl \ nsIResumableChannel.idl \
nsIRequestObserverProxy.idl \ nsIRequestObserverProxy.idl \

Просмотреть файл

@ -0,0 +1,69 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla.
*
* The Initial Developer of the Original Code is
* Netscape Communications.
* Portions created by the Initial Developer are Copyright (C) 2012
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Patrick McManus <mcmanus@ducksong.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "nsISupports.idl"
interface nsIURI;
interface nsIInterfaceRequestor;
interface nsIEventTarget;
[scriptable, uuid(b3c53863-1313-480a-90a2-5b0da651ee5e)]
interface nsISpeculativeConnect : nsISupports
{
/**
* Called as a hint to indicate a new transaction for the URI is likely coming
* soon. The implementer may use this information to start a TCP
* and/or SSL level handshake for that resource immediately so that it is
* ready and/or progressed when the transaction is actually submitted.
*
* No obligation is taken on by the implementer, nor is the submitter obligated
* to actually open the new channel.
*
* @param aURI the URI of the hinted transaction
* @param aCallbacks any security callbacks for use with SSL for interfaces
* such as nsIBadCertListener. May be null.
* @param aTarget the thread on which the release of the callbacks will
* occur. May be null for "any thread".
*
*/
void speculativeConnect(in nsIURI aURI,
in nsIInterfaceRequestor aCallbacks,
in nsIEventTarget aTarget);
};

Просмотреть файл

@ -341,10 +341,11 @@ nsIOService::GetInstance() {
return gIOService; return gIOService;
} }
NS_IMPL_THREADSAFE_ISUPPORTS5(nsIOService, NS_IMPL_THREADSAFE_ISUPPORTS6(nsIOService,
nsIIOService, nsIIOService,
nsIIOService2, nsIIOService2,
nsINetUtil, nsINetUtil,
nsISpeculativeConnect,
nsIObserver, nsIObserver,
nsISupportsWeakReference) nsISupportsWeakReference)
@ -608,10 +609,47 @@ nsIOService::NewChannelFromURI(nsIURI *aURI, nsIChannel **result)
return NewChannelFromURIWithProxyFlags(aURI, nsnull, 0, result); return NewChannelFromURIWithProxyFlags(aURI, nsnull, 0, result);
} }
void
nsIOService::LookupProxyInfo(nsIURI *aURI,
nsIURI *aProxyURI,
PRUint32 aProxyFlags,
nsCString *aScheme,
nsIProxyInfo **outPI)
{
nsresult rv;
nsCOMPtr<nsIProxyInfo> pi;
if (!mProxyService) {
mProxyService = do_GetService(NS_PROTOCOLPROXYSERVICE_CONTRACTID);
if (!mProxyService)
NS_WARNING("failed to get protocol proxy service");
}
if (mProxyService) {
PRUint32 flags = 0;
if (aScheme->EqualsLiteral("http") || aScheme->EqualsLiteral("https"))
flags = nsIProtocolProxyService::RESOLVE_NON_BLOCKING;
rv = mProxyService->Resolve(aProxyURI ? aProxyURI : aURI, aProxyFlags,
getter_AddRefs(pi));
if (rv == NS_BASE_STREAM_WOULD_BLOCK) {
// Use an UNKNOWN proxy to defer resolution and avoid blocking.
rv = mProxyService->NewProxyInfo(NS_LITERAL_CSTRING("unknown"),
NS_LITERAL_CSTRING(""),
-1, 0, 0, nsnull,
getter_AddRefs(pi));
}
if (NS_FAILED(rv))
pi = nsnull;
}
*outPI = pi;
if (pi)
pi.forget();
}
NS_IMETHODIMP NS_IMETHODIMP
nsIOService::NewChannelFromURIWithProxyFlags(nsIURI *aURI, nsIOService::NewChannelFromURIWithProxyFlags(nsIURI *aURI,
nsIURI *aProxyURI, nsIURI *aProxyURI,
PRUint32 proxyFlags, PRUint32 aProxyFlags,
nsIChannel **result) nsIChannel **result)
{ {
nsresult rv; nsresult rv;
@ -636,27 +674,7 @@ nsIOService::NewChannelFromURIWithProxyFlags(nsIURI *aURI,
// skip this step. This allows us to lazily load the PPS at startup. // skip this step. This allows us to lazily load the PPS at startup.
if (protoFlags & nsIProtocolHandler::ALLOWS_PROXY) { if (protoFlags & nsIProtocolHandler::ALLOWS_PROXY) {
nsCOMPtr<nsIProxyInfo> pi; nsCOMPtr<nsIProxyInfo> pi;
if (!mProxyService) { LookupProxyInfo(aURI, aProxyURI, aProxyFlags, &scheme, getter_AddRefs(pi));
mProxyService = do_GetService(NS_PROTOCOLPROXYSERVICE_CONTRACTID);
if (!mProxyService)
NS_WARNING("failed to get protocol proxy service");
}
if (mProxyService) {
PRUint32 flags = 0;
if (scheme.EqualsLiteral("http") || scheme.EqualsLiteral("https"))
flags = nsIProtocolProxyService::RESOLVE_NON_BLOCKING;
rv = mProxyService->Resolve(aProxyURI ? aProxyURI : aURI, proxyFlags,
getter_AddRefs(pi));
if (rv == NS_BASE_STREAM_WOULD_BLOCK) {
// Use an UNKNOWN proxy to defer resolution and avoid blocking.
rv = mProxyService->NewProxyInfo(NS_LITERAL_CSTRING("unknown"),
NS_LITERAL_CSTRING(""),
-1, 0, 0, nsnull,
getter_AddRefs(pi));
}
if (NS_FAILED(rv))
pi = nsnull;
}
if (pi) { if (pi) {
nsCAutoString type; nsCAutoString type;
if (NS_SUCCEEDED(pi->GetType(type)) && type.EqualsLiteral("http")) { if (NS_SUCCEEDED(pi->GetType(type)) && type.EqualsLiteral("http")) {
@ -1236,3 +1254,37 @@ nsIOService::ExtractCharsetFromContentType(const nsACString &aTypeHeader,
} }
return NS_OK; return NS_OK;
} }
// nsISpeculativeConnect
NS_IMETHODIMP
nsIOService::SpeculativeConnect(nsIURI *aURI,
nsIInterfaceRequestor *aCallbacks,
nsIEventTarget *aTarget)
{
nsCAutoString scheme;
nsresult rv = aURI->GetScheme(scheme);
if (NS_FAILED(rv))
return rv;
// Check for proxy information. If there is a proxy configured then a
// speculative connect should not be performed because the potential
// reward is slim with tcp peers closely located to the browser.
nsCOMPtr<nsIProxyInfo> pi;
LookupProxyInfo(aURI, nsnull, 0, &scheme, getter_AddRefs(pi));
if (pi)
return NS_OK;
nsCOMPtr<nsIProtocolHandler> handler;
rv = GetProtocolHandler(scheme.get(), getter_AddRefs(handler));
if (NS_FAILED(rv))
return rv;
nsCOMPtr<nsISpeculativeConnect> speculativeHandler =
do_QueryInterface(handler);
if (!handler)
return NS_OK;
return speculativeHandler->SpeculativeConnect(aURI,
aCallbacks,
aTarget);
}

Просмотреть файл

@ -58,6 +58,7 @@
#include "nsCategoryCache.h" #include "nsCategoryCache.h"
#include "nsINetworkLinkService.h" #include "nsINetworkLinkService.h"
#include "nsAsyncRedirectVerifyHelper.h" #include "nsAsyncRedirectVerifyHelper.h"
#include "nsISpeculativeConnect.h"
#define NS_N(x) (sizeof(x)/sizeof(*x)) #define NS_N(x) (sizeof(x)/sizeof(*x))
@ -74,6 +75,7 @@ class nsIPrefBranch;
class nsIOService : public nsIIOService2 class nsIOService : public nsIIOService2
, public nsIObserver , public nsIObserver
, public nsINetUtil , public nsINetUtil
, public nsISpeculativeConnect
, public nsSupportsWeakReference , public nsSupportsWeakReference
{ {
public: public:
@ -82,6 +84,7 @@ public:
NS_DECL_NSIIOSERVICE2 NS_DECL_NSIIOSERVICE2
NS_DECL_NSIOBSERVER NS_DECL_NSIOBSERVER
NS_DECL_NSINETUTIL NS_DECL_NSINETUTIL
NS_DECL_NSISPECULATIVECONNECT
// Gets the singleton instance of the IO Service, creating it as needed // Gets the singleton instance of the IO Service, creating it as needed
// Returns nsnull on out of memory or failure to initialize. // Returns nsnull on out of memory or failure to initialize.
@ -135,6 +138,10 @@ private:
nsresult InitializeSocketTransportService(); nsresult InitializeSocketTransportService();
nsresult InitializeNetworkLinkService(); nsresult InitializeNetworkLinkService();
// consolidated helper function
void LookupProxyInfo(nsIURI *aURI, nsIURI *aProxyURI, PRUint32 aProxyFlags,
nsCString *aScheme, nsIProxyInfo **outPI);
private: private:
bool mOffline; bool mOffline;
bool mOfflineForProfileChange; bool mOfflineForProfileChange;

Просмотреть файл

@ -1417,12 +1417,13 @@ nsHttpHandler::SetAcceptEncodings(const char *aAcceptEncodings)
// nsHttpHandler::nsISupports // nsHttpHandler::nsISupports
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
NS_IMPL_THREADSAFE_ISUPPORTS5(nsHttpHandler, NS_IMPL_THREADSAFE_ISUPPORTS6(nsHttpHandler,
nsIHttpProtocolHandler, nsIHttpProtocolHandler,
nsIProxiedProtocolHandler, nsIProxiedProtocolHandler,
nsIProtocolHandler, nsIProtocolHandler,
nsIObserver, nsIObserver,
nsISupportsWeakReference) nsISupportsWeakReference,
nsISpeculativeConnect)
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// nsHttpHandler::nsIProtocolHandler // nsHttpHandler::nsIProtocolHandler
@ -1669,15 +1670,75 @@ nsHttpHandler::Observe(nsISupports *subject,
return NS_OK; return NS_OK;
} }
// nsISpeculativeConnect
NS_IMETHODIMP
nsHttpHandler::SpeculativeConnect(nsIURI *aURI,
nsIInterfaceRequestor *aCallbacks,
nsIEventTarget *aTarget)
{
nsIStrictTransportSecurityService* stss = gHttpHandler->GetSTSService();
bool isStsHost = false;
if (!stss)
return NS_OK;
nsCOMPtr<nsIURI> clone;
if (NS_SUCCEEDED(stss->IsStsURI(aURI, &isStsHost)) && isStsHost) {
if (NS_SUCCEEDED(aURI->Clone(getter_AddRefs(clone)))) {
clone->SetScheme(NS_LITERAL_CSTRING("https"));
aURI = clone.get();
}
}
nsCAutoString scheme;
nsresult rv = aURI->GetScheme(scheme);
if (NS_FAILED(rv))
return rv;
// If this is HTTPS, make sure PSM is initialized as the channel
// creation path may have been bypassed
if (scheme.EqualsLiteral("https")) {
if (!IsNeckoChild()) {
// make sure PSM gets initialized on the main thread.
net_EnsurePSMInit();
}
}
// Ensure that this is HTTP or HTTPS, otherwise we don't do preconnect here
else if (!scheme.EqualsLiteral("http"))
return NS_ERROR_UNEXPECTED;
// Construct connection info object
bool usingSSL = false;
rv = aURI->SchemeIs("https", &usingSSL);
if (NS_FAILED(rv))
return rv;
nsCAutoString host;
rv = aURI->GetAsciiHost(host);
if (NS_FAILED(rv))
return rv;
PRInt32 port = -1;
rv = aURI->GetPort(&port);
if (NS_FAILED(rv))
return rv;
nsHttpConnectionInfo *ci =
new nsHttpConnectionInfo(host, port, nsnull, usingSSL);
return SpeculativeConnect(ci, aCallbacks, aTarget);
}
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// nsHttpsHandler implementation // nsHttpsHandler implementation
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
NS_IMPL_THREADSAFE_ISUPPORTS4(nsHttpsHandler, NS_IMPL_THREADSAFE_ISUPPORTS5(nsHttpsHandler,
nsIHttpProtocolHandler, nsIHttpProtocolHandler,
nsIProxiedProtocolHandler, nsIProxiedProtocolHandler,
nsIProtocolHandler, nsIProtocolHandler,
nsISupportsWeakReference) nsISupportsWeakReference,
nsISpeculativeConnect)
nsresult nsresult
nsHttpsHandler::Init() nsHttpsHandler::Init()

Просмотреть файл

@ -61,6 +61,7 @@
#include "nsIIDNService.h" #include "nsIIDNService.h"
#include "nsITimer.h" #include "nsITimer.h"
#include "nsIStrictTransportSecurityService.h" #include "nsIStrictTransportSecurityService.h"
#include "nsISpeculativeConnect.h"
class nsHttpConnectionInfo; class nsHttpConnectionInfo;
class nsHttpHeaderArray; class nsHttpHeaderArray;
@ -76,6 +77,7 @@ class nsIPrefBranch;
class nsHttpHandler : public nsIHttpProtocolHandler class nsHttpHandler : public nsIHttpProtocolHandler
, public nsIObserver , public nsIObserver
, public nsSupportsWeakReference , public nsSupportsWeakReference
, public nsISpeculativeConnect
{ {
public: public:
NS_DECL_ISUPPORTS NS_DECL_ISUPPORTS
@ -83,6 +85,7 @@ public:
NS_DECL_NSIPROXIEDPROTOCOLHANDLER NS_DECL_NSIPROXIEDPROTOCOLHANDLER
NS_DECL_NSIHTTPPROTOCOLHANDLER NS_DECL_NSIHTTPPROTOCOLHANDLER
NS_DECL_NSIOBSERVER NS_DECL_NSIOBSERVER
NS_DECL_NSISPECULATIVECONNECT
nsHttpHandler(); nsHttpHandler();
virtual ~nsHttpHandler(); virtual ~nsHttpHandler();
@ -412,6 +415,7 @@ extern nsHttpHandler *gHttpHandler;
class nsHttpsHandler : public nsIHttpProtocolHandler class nsHttpsHandler : public nsIHttpProtocolHandler
, public nsSupportsWeakReference , public nsSupportsWeakReference
, public nsISpeculativeConnect
{ {
public: public:
// we basically just want to override GetScheme and GetDefaultPort... // we basically just want to override GetScheme and GetDefaultPort...
@ -421,6 +425,7 @@ public:
NS_DECL_NSIPROTOCOLHANDLER NS_DECL_NSIPROTOCOLHANDLER
NS_FORWARD_NSIPROXIEDPROTOCOLHANDLER (gHttpHandler->) NS_FORWARD_NSIPROXIEDPROTOCOLHANDLER (gHttpHandler->)
NS_FORWARD_NSIHTTPPROTOCOLHANDLER (gHttpHandler->) NS_FORWARD_NSIHTTPPROTOCOLHANDLER (gHttpHandler->)
NS_FORWARD_NSISPECULATIVECONNECT (gHttpHandler->)
nsHttpsHandler() { } nsHttpsHandler() { }
virtual ~nsHttpsHandler() { } virtual ~nsHttpsHandler() { }

Просмотреть файл

@ -0,0 +1,42 @@
const Cc = Components.classes;
const Ci = Components.interfaces;
const CC = Components.Constructor;
const ServerSocket = CC("@mozilla.org/network/server-socket;1",
"nsIServerSocket",
"init");
var serv;
function TestServer() {
this.listener = ServerSocket(4444, true, -1);
this.listener.asyncListen(this);
}
TestServer.prototype = {
QueryInterface: function(iid) {
if (iid.equals(Ci.nsIServerSocket) ||
iid.equals(Ci.nsISupports))
return this;
throw Components.results.NS_ERROR_NO_INTERFACE;
},
onSocketAccepted: function(socket, trans) {
try { this.listener.close(); } catch(e) {}
do_check_true(true);
do_test_finished();
},
onStopListening: function(socket) {}
}
function run_test() {
var ios = Cc["@mozilla.org/network/io-service;1"]
.getService(Ci.nsIIOService);
serv = new TestServer();
URI = ios.newURI("http://localhost:4444/just/a/test", null, null);
ios.QueryInterface(Components.interfaces.nsISpeculativeConnect)
.speculativeConnect(URI, null, null);
do_test_pending();
}

Просмотреть файл

@ -174,6 +174,7 @@ skip-if = os == "win"
[test_socks.js] [test_socks.js]
# Bug 675039: test hangs consistently on Android # Bug 675039: test hangs consistently on Android
skip-if = os == "android" skip-if = os == "android"
[test_speculative_connect.js]
[test_standardurl.js] [test_standardurl.js]
[test_standardurl_port.js] [test_standardurl_port.js]
[test_streamcopier.js] [test_streamcopier.js]