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
[scriptable, uuid(b7803a0b-4492-45ec-ac7a-3e29f6445fa4)]
[scriptable, uuid(65f6d2c8-4be6-4695-958d-0735e8935289)]
interface nsIDOMTCPSocket : nsISupports
{
/**
@ -44,7 +44,7 @@ interface nsIDOMTCPSocket : nsISupports
* @param options An object specifying one or more parameters which
* 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
* 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,
[optional] in unsigned short backlog);
/**
* Enable secure on channel.
*/
void upgradeToSecure();
/**
* The host of this socket object.
*/

View File

@ -8,7 +8,7 @@ interface nsITCPSocketInternal;
interface nsIDOMWindow;
// 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
{
// Tell the chrome process to open a corresponding connection with the given parameters
@ -23,6 +23,7 @@ interface nsITCPSocketChild : nsISupports
void resume();
void suspend();
void close();
void startTLS();
/**
* 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:
Open(nsString host, uint16_t port, bool useSSL, nsString binaryType);
Data(SendableData data);
StartTLS();
Suspend();
Resume();
Close();

View File

@ -157,6 +157,10 @@ TCPSocket.prototype = {
// IPC socket actor
_socketBridge: null,
// StartTLS
_waitingForStartTLS: false,
_pendingDataAfterStartTLS: [],
// Public accessors.
get readyState() {
return this._readyState;
@ -210,19 +214,23 @@ TCPSocket.prototype = {
this._onclose = f;
},
_activateTLS: function() {
let securityInfo = this._transport.securityInfo
.QueryInterface(Ci.nsISSLSocketControl);
securityInfo.StartTLS();
},
// Helper methods.
_createTransport: function ts_createTransport(host, port, sslMode) {
let options, optlen;
if (sslMode) {
options = [sslMode];
optlen = 1;
let options;
if (sslMode === 'ssl') {
options = ['ssl'];
} else {
options = null;
optlen = 0;
options = ['starttls'];
}
return Cc["@mozilla.org/network/socket-transport-service;1"]
.getService(Ci.nsISocketTransportService)
.createTransport(options, optlen, host, port, null);
.createTransport(options, 1, host, port, null);
},
_ensureCopying: function ts_ensureCopying() {
@ -248,6 +256,21 @@ TCPSocket.prototype = {
if (self._multiplexStream.count) {
self._ensureCopying();
} 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) {
self._waitingForDrain = false;
self.callListener("drain");
@ -435,7 +458,7 @@ TCPSocket.prototype = {
that._host = host;
that._port = port;
if (options !== undefined) {
if (options.useSSL) {
if (options.useSecureTransport) {
that._ssl = 'ssl';
} else {
that._ssl = false;
@ -458,7 +481,30 @@ TCPSocket.prototype = {
that._initStream(that._binaryType);
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) {
if (!this.initWindowless())
return null;
@ -524,7 +570,14 @@ TCPSocket.prototype = {
new_stream = new StringInputStream();
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 we buffered more than some arbitrary amount of data,

View File

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

View File

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

View File

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

View File

@ -32,7 +32,7 @@ TCPSocketParentIntermediary.prototype = {
open: function(aParentSide, aHost, aPort, aUseSSL, aBinaryType) {
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)
return null;