Bug 784816 - Adding upgradeToSecure() to support startTLS in MozTCPSocket. r=mayhemer sr=sicking

This commit is contained in:
Patrick Wang 2013-09-01 03:09:17 +08:00
parent 249cbee5b4
commit e67df35def
8 changed files with 91 additions and 14 deletions

View File

@ -32,7 +32,7 @@ interface nsISocketTransport;
// Bug 797561 - Expose a server tcp socket API to web applications // Bug 797561 - Expose a server tcp socket API to web applications
[scriptable, uuid(b7803a0b-4492-45ec-ac7a-3e29f6445fa4)] [scriptable, uuid(65f6d2c8-4be6-4695-958d-0735e8935289)]
interface nsIDOMTCPSocket : nsISupports interface nsIDOMTCPSocket : nsISupports
{ {
/** /**
@ -44,7 +44,7 @@ interface nsIDOMTCPSocket : nsISupports
* @param options An object specifying one or more parameters which * @param options An object specifying one or more parameters which
* determine the details of the socket. * determine the details of the socket.
* *
* useSSL: true to create an SSL socket. Defaults to false. * useSecureTransport: true to create an SSL socket. Defaults to false.
* *
* binaryType: "arraybuffer" to use ArrayBuffer * binaryType: "arraybuffer" to use ArrayBuffer
* instances in the ondata callback and as the argument * instances in the ondata callback and as the argument
@ -74,6 +74,11 @@ interface nsIDOMTCPSocket : nsISupports
nsIDOMTCPServerSocket listen(in unsigned short localPort, [optional] in jsval options, nsIDOMTCPServerSocket listen(in unsigned short localPort, [optional] in jsval options,
[optional] in unsigned short backlog); [optional] in unsigned short backlog);
/**
* Enable secure on channel.
*/
void upgradeToSecure();
/** /**
* The host of this socket object. * The host of this socket object.
*/ */

View File

@ -8,7 +8,7 @@ interface nsITCPSocketInternal;
interface nsIDOMWindow; interface nsIDOMWindow;
// Interface to allow the content process socket to reach the IPC bridge. // Interface to allow the content process socket to reach the IPC bridge.
[scriptable, uuid(edf07a93-36a6-4574-8e23-40f64ab5f596)] [scriptable, uuid(ada5342d-6d45-4ff1-a7d3-6a4b150d0385)]
interface nsITCPSocketChild : nsISupports interface nsITCPSocketChild : nsISupports
{ {
// Tell the chrome process to open a corresponding connection with the given parameters // Tell the chrome process to open a corresponding connection with the given parameters
@ -23,6 +23,7 @@ interface nsITCPSocketChild : nsISupports
void resume(); void resume();
void suspend(); void suspend();
void close(); void close();
void startTLS();
/** /**
* Initialize the TCP socket on the child side for IPC. It is called from the child side, * Initialize the TCP socket on the child side for IPC. It is called from the child side,

View File

@ -37,6 +37,7 @@ protocol PTCPSocket
parent: parent:
Open(nsString host, uint16_t port, bool useSSL, nsString binaryType); Open(nsString host, uint16_t port, bool useSSL, nsString binaryType);
Data(SendableData data); Data(SendableData data);
StartTLS();
Suspend(); Suspend();
Resume(); Resume();
Close(); Close();

View File

@ -157,6 +157,10 @@ TCPSocket.prototype = {
// IPC socket actor // IPC socket actor
_socketBridge: null, _socketBridge: null,
// StartTLS
_waitingForStartTLS: false,
_pendingDataAfterStartTLS: [],
// Public accessors. // Public accessors.
get readyState() { get readyState() {
return this._readyState; return this._readyState;
@ -210,19 +214,23 @@ TCPSocket.prototype = {
this._onclose = f; this._onclose = f;
}, },
_activateTLS: function() {
let securityInfo = this._transport.securityInfo
.QueryInterface(Ci.nsISSLSocketControl);
securityInfo.StartTLS();
},
// Helper methods. // Helper methods.
_createTransport: function ts_createTransport(host, port, sslMode) { _createTransport: function ts_createTransport(host, port, sslMode) {
let options, optlen; let options;
if (sslMode) { if (sslMode === 'ssl') {
options = [sslMode]; options = ['ssl'];
optlen = 1;
} else { } else {
options = null; options = ['starttls'];
optlen = 0;
} }
return Cc["@mozilla.org/network/socket-transport-service;1"] return Cc["@mozilla.org/network/socket-transport-service;1"]
.getService(Ci.nsISocketTransportService) .getService(Ci.nsISocketTransportService)
.createTransport(options, optlen, host, port, null); .createTransport(options, 1, host, port, null);
}, },
_ensureCopying: function ts_ensureCopying() { _ensureCopying: function ts_ensureCopying() {
@ -248,6 +256,21 @@ TCPSocket.prototype = {
if (self._multiplexStream.count) { if (self._multiplexStream.count) {
self._ensureCopying(); self._ensureCopying();
} else { } else {
// If we are waiting for initiating starttls, we can begin to
// activate tls now.
if (self._waitingForStartTLS && self._readyState == kOPEN) {
self._activateTLS();
self._waitingForStartTLS = false;
// If we have pending data, we should send them, or fire
// a drain event if we are waiting for it.
if (self._pendingDataAfterStartTLS.length > 0) {
while (self._pendingDataAfterStartTLS.length)
self._multiplexStream.appendStream(self._pendingDataAfterStartTLS.shift());
self._ensureCopying();
return;
}
}
if (self._waitingForDrain) { if (self._waitingForDrain) {
self._waitingForDrain = false; self._waitingForDrain = false;
self.callListener("drain"); self.callListener("drain");
@ -435,7 +458,7 @@ TCPSocket.prototype = {
that._host = host; that._host = host;
that._port = port; that._port = port;
if (options !== undefined) { if (options !== undefined) {
if (options.useSSL) { if (options.useSecureTransport) {
that._ssl = 'ssl'; that._ssl = 'ssl';
} else { } else {
that._ssl = false; that._ssl = false;
@ -458,7 +481,30 @@ TCPSocket.prototype = {
that._initStream(that._binaryType); that._initStream(that._binaryType);
return that; return that;
}, },
upgradeToSecure: function ts_upgradeToSecure() {
if (this._readyState !== kOPEN) {
throw new Error("Socket not open.");
}
if (this._ssl == 'ssl') {
// Already SSL
return;
}
this._ssl = 'ssl';
if (this._inChild) {
this._socketBridge.startTLS();
return;
}
if (this._multiplexStream.count == 0) {
this._activateTLS();
} else {
this._waitingForStartTLS = true;
}
},
listen: function ts_listen(localPort, options, backlog) { listen: function ts_listen(localPort, options, backlog) {
if (!this.initWindowless()) if (!this.initWindowless())
return null; return null;
@ -524,7 +570,14 @@ TCPSocket.prototype = {
new_stream = new StringInputStream(); new_stream = new StringInputStream();
new_stream.setData(data, length); new_stream.setData(data, length);
} }
this._multiplexStream.appendStream(new_stream);
if (this._waitingForStartTLS) {
// When we are waiting for starttls, new_stream is added to pendingData
// and will be appended to multiplexStream after tls had been set up.
this._pendingDataAfterStartTLS.push(new_stream);
} else {
this._multiplexStream.appendStream(new_stream);
}
if (newBufferedAmount >= BUFFER_SIZE) { if (newBufferedAmount >= BUFFER_SIZE) {
// If we buffered more than some arbitrary amount of data, // If we buffered more than some arbitrary amount of data,

View File

@ -158,6 +158,13 @@ TCPSocketChild::RecvCallback(const nsString& aType,
return true; return true;
} }
NS_IMETHODIMP
TCPSocketChild::StartTLS()
{
SendStartTLS();
return NS_OK;
}
NS_IMETHODIMP NS_IMETHODIMP
TCPSocketChild::Suspend() TCPSocketChild::Suspend()
{ {

View File

@ -115,6 +115,15 @@ TCPSocketParent::InitJS(const JS::Value& aIntermediary, JSContext* aCx)
return NS_OK; return NS_OK;
} }
bool
TCPSocketParent::RecvStartTLS()
{
NS_ENSURE_TRUE(mSocket, true);
nsresult rv = mSocket->UpgradeToSecure();
NS_ENSURE_SUCCESS(rv, true);
return true;
}
bool bool
TCPSocketParent::RecvSuspend() TCPSocketParent::RecvSuspend()
{ {

View File

@ -47,6 +47,7 @@ public:
virtual bool RecvOpen(const nsString& aHost, const uint16_t& aPort, virtual bool RecvOpen(const nsString& aHost, const uint16_t& aPort,
const bool& useSSL, const nsString& aBinaryType); const bool& useSSL, const nsString& aBinaryType);
virtual bool RecvStartTLS() MOZ_OVERRIDE;
virtual bool RecvSuspend() MOZ_OVERRIDE; virtual bool RecvSuspend() MOZ_OVERRIDE;
virtual bool RecvResume() MOZ_OVERRIDE; virtual bool RecvResume() MOZ_OVERRIDE;
virtual bool RecvClose() MOZ_OVERRIDE; virtual bool RecvClose() MOZ_OVERRIDE;

View File

@ -32,7 +32,7 @@ TCPSocketParentIntermediary.prototype = {
open: function(aParentSide, aHost, aPort, aUseSSL, aBinaryType) { open: function(aParentSide, aHost, aPort, aUseSSL, aBinaryType) {
let baseSocket = Cc["@mozilla.org/tcp-socket;1"].createInstance(Ci.nsIDOMTCPSocket); let baseSocket = Cc["@mozilla.org/tcp-socket;1"].createInstance(Ci.nsIDOMTCPSocket);
let socket = baseSocket.open(aHost, aPort, {useSSL: aUseSSL, binaryType: aBinaryType}); let socket = baseSocket.open(aHost, aPort, {useSecureTransport: aUseSSL, binaryType: aBinaryType});
if (!socket) if (!socket)
return null; return null;