зеркало из https://github.com/mozilla/pjs.git
bug 723628 - speculative connect hint interface r=honzab sr=biesi
This commit is contained in:
Родитель
f7da014875
Коммит
ecdfa8e875
|
@ -103,6 +103,7 @@ XPIDLSRCS = \
|
|||
nsITransport.idl \
|
||||
nsISocketTransport.idl \
|
||||
nsISocketTransportService.idl \
|
||||
nsISpeculativeConnect.idl \
|
||||
nsIServerSocket.idl \
|
||||
nsIResumableChannel.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;
|
||||
}
|
||||
|
||||
NS_IMPL_THREADSAFE_ISUPPORTS5(nsIOService,
|
||||
NS_IMPL_THREADSAFE_ISUPPORTS6(nsIOService,
|
||||
nsIIOService,
|
||||
nsIIOService2,
|
||||
nsINetUtil,
|
||||
nsISpeculativeConnect,
|
||||
nsIObserver,
|
||||
nsISupportsWeakReference)
|
||||
|
||||
|
@ -608,10 +609,47 @@ nsIOService::NewChannelFromURI(nsIURI *aURI, nsIChannel **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
|
||||
nsIOService::NewChannelFromURIWithProxyFlags(nsIURI *aURI,
|
||||
nsIURI *aProxyURI,
|
||||
PRUint32 proxyFlags,
|
||||
PRUint32 aProxyFlags,
|
||||
nsIChannel **result)
|
||||
{
|
||||
nsresult rv;
|
||||
|
@ -636,27 +674,7 @@ nsIOService::NewChannelFromURIWithProxyFlags(nsIURI *aURI,
|
|||
// skip this step. This allows us to lazily load the PPS at startup.
|
||||
if (protoFlags & nsIProtocolHandler::ALLOWS_PROXY) {
|
||||
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 (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;
|
||||
}
|
||||
LookupProxyInfo(aURI, aProxyURI, aProxyFlags, &scheme, getter_AddRefs(pi));
|
||||
if (pi) {
|
||||
nsCAutoString type;
|
||||
if (NS_SUCCEEDED(pi->GetType(type)) && type.EqualsLiteral("http")) {
|
||||
|
@ -1236,3 +1254,37 @@ nsIOService::ExtractCharsetFromContentType(const nsACString &aTypeHeader,
|
|||
}
|
||||
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 "nsINetworkLinkService.h"
|
||||
#include "nsAsyncRedirectVerifyHelper.h"
|
||||
#include "nsISpeculativeConnect.h"
|
||||
|
||||
#define NS_N(x) (sizeof(x)/sizeof(*x))
|
||||
|
||||
|
@ -74,6 +75,7 @@ class nsIPrefBranch;
|
|||
class nsIOService : public nsIIOService2
|
||||
, public nsIObserver
|
||||
, public nsINetUtil
|
||||
, public nsISpeculativeConnect
|
||||
, public nsSupportsWeakReference
|
||||
{
|
||||
public:
|
||||
|
@ -82,6 +84,7 @@ public:
|
|||
NS_DECL_NSIIOSERVICE2
|
||||
NS_DECL_NSIOBSERVER
|
||||
NS_DECL_NSINETUTIL
|
||||
NS_DECL_NSISPECULATIVECONNECT
|
||||
|
||||
// Gets the singleton instance of the IO Service, creating it as needed
|
||||
// Returns nsnull on out of memory or failure to initialize.
|
||||
|
@ -135,6 +138,10 @@ private:
|
|||
nsresult InitializeSocketTransportService();
|
||||
nsresult InitializeNetworkLinkService();
|
||||
|
||||
// consolidated helper function
|
||||
void LookupProxyInfo(nsIURI *aURI, nsIURI *aProxyURI, PRUint32 aProxyFlags,
|
||||
nsCString *aScheme, nsIProxyInfo **outPI);
|
||||
|
||||
private:
|
||||
bool mOffline;
|
||||
bool mOfflineForProfileChange;
|
||||
|
|
|
@ -1417,12 +1417,13 @@ nsHttpHandler::SetAcceptEncodings(const char *aAcceptEncodings)
|
|||
// nsHttpHandler::nsISupports
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
NS_IMPL_THREADSAFE_ISUPPORTS5(nsHttpHandler,
|
||||
NS_IMPL_THREADSAFE_ISUPPORTS6(nsHttpHandler,
|
||||
nsIHttpProtocolHandler,
|
||||
nsIProxiedProtocolHandler,
|
||||
nsIProtocolHandler,
|
||||
nsIObserver,
|
||||
nsISupportsWeakReference)
|
||||
nsISupportsWeakReference,
|
||||
nsISpeculativeConnect)
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// nsHttpHandler::nsIProtocolHandler
|
||||
|
@ -1669,15 +1670,75 @@ nsHttpHandler::Observe(nsISupports *subject,
|
|||
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
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
NS_IMPL_THREADSAFE_ISUPPORTS4(nsHttpsHandler,
|
||||
NS_IMPL_THREADSAFE_ISUPPORTS5(nsHttpsHandler,
|
||||
nsIHttpProtocolHandler,
|
||||
nsIProxiedProtocolHandler,
|
||||
nsIProtocolHandler,
|
||||
nsISupportsWeakReference)
|
||||
nsISupportsWeakReference,
|
||||
nsISpeculativeConnect)
|
||||
|
||||
nsresult
|
||||
nsHttpsHandler::Init()
|
||||
|
|
|
@ -61,6 +61,7 @@
|
|||
#include "nsIIDNService.h"
|
||||
#include "nsITimer.h"
|
||||
#include "nsIStrictTransportSecurityService.h"
|
||||
#include "nsISpeculativeConnect.h"
|
||||
|
||||
class nsHttpConnectionInfo;
|
||||
class nsHttpHeaderArray;
|
||||
|
@ -76,6 +77,7 @@ class nsIPrefBranch;
|
|||
class nsHttpHandler : public nsIHttpProtocolHandler
|
||||
, public nsIObserver
|
||||
, public nsSupportsWeakReference
|
||||
, public nsISpeculativeConnect
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
@ -83,6 +85,7 @@ public:
|
|||
NS_DECL_NSIPROXIEDPROTOCOLHANDLER
|
||||
NS_DECL_NSIHTTPPROTOCOLHANDLER
|
||||
NS_DECL_NSIOBSERVER
|
||||
NS_DECL_NSISPECULATIVECONNECT
|
||||
|
||||
nsHttpHandler();
|
||||
virtual ~nsHttpHandler();
|
||||
|
@ -412,6 +415,7 @@ extern nsHttpHandler *gHttpHandler;
|
|||
|
||||
class nsHttpsHandler : public nsIHttpProtocolHandler
|
||||
, public nsSupportsWeakReference
|
||||
, public nsISpeculativeConnect
|
||||
{
|
||||
public:
|
||||
// we basically just want to override GetScheme and GetDefaultPort...
|
||||
|
@ -421,6 +425,7 @@ public:
|
|||
NS_DECL_NSIPROTOCOLHANDLER
|
||||
NS_FORWARD_NSIPROXIEDPROTOCOLHANDLER (gHttpHandler->)
|
||||
NS_FORWARD_NSIHTTPPROTOCOLHANDLER (gHttpHandler->)
|
||||
NS_FORWARD_NSISPECULATIVECONNECT (gHttpHandler->)
|
||||
|
||||
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]
|
||||
# Bug 675039: test hangs consistently on Android
|
||||
skip-if = os == "android"
|
||||
[test_speculative_connect.js]
|
||||
[test_standardurl.js]
|
||||
[test_standardurl_port.js]
|
||||
[test_streamcopier.js]
|
||||
|
|
Загрузка…
Ссылка в новой задаче