Bug 1081686 - WebSocket can be still accessible once it is disconnected, r=smaug

--HG--
rename : content/base/test/test_websocket_hello.html => content/base/test/test_bug1081686.html
This commit is contained in:
Andrea Marchesini 2014-10-13 18:22:09 +01:00
Родитель 654a1342d7
Коммит 7de75430e6
4 изменённых файлов: 204 добавлений и 165 удалений

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

@ -83,13 +83,9 @@ public:
, mDisconnected(false)
, mCloseEventWasClean(false)
, mCloseEventCode(nsIWebSocketChannel::CLOSE_ABNORMAL)
, mOutgoingBufferedAmount(0)
, mBinaryType(dom::BinaryType::Blob)
, mScriptLine(0)
, mInnerWindowID(0)
, mMutex("WebSocketImpl::mMutex")
, mWorkerPrivate(nullptr)
, mReadyState(WebSocket::CONNECTING)
{
if (!NS_IsMainThread()) {
mWorkerPrivate = GetCurrentThreadWorkerPrivate();
@ -104,51 +100,6 @@ public:
bool IsTargetThread() const;
uint16_t ReadyState()
{
MutexAutoLock lock(mMutex);
return mReadyState;
}
void SetReadyState(uint16_t aReadyState)
{
MutexAutoLock lock(mMutex);
mReadyState = aReadyState;
}
uint32_t BufferedAmount() const
{
AssertIsOnTargetThread();
return mOutgoingBufferedAmount;
}
dom::BinaryType BinaryType() const
{
AssertIsOnTargetThread();
return mBinaryType;
}
void SetBinaryType(dom::BinaryType aData)
{
AssertIsOnTargetThread();
mBinaryType = aData;
}
void GetUrl(nsAString& aURL) const
{
AssertIsOnTargetThread();
if (mEffectiveURL.IsEmpty()) {
aURL = mOriginalURL;
} else {
aURL = mEffectiveURL;
}
}
void Close(const Optional<uint16_t>& aCode,
const Optional<nsAString>& aReason,
ErrorResult& aRv);
void Init(JSContext* aCx,
nsIPrincipal* aPrincipal,
const nsAString& aURL,
@ -160,12 +111,6 @@ public:
void AsyncOpen(ErrorResult& aRv);
void Send(nsIInputStream* aMsgStream,
const nsACString& aMsgString,
uint32_t aMsgLength,
bool aIsBinary,
ErrorResult& aRv);
nsresult ParseURL(const nsAString& aURL);
nsresult InitializeConnection();
@ -212,9 +157,6 @@ public:
nsCOMPtr<nsIWebSocketChannel> mChannel;
// related to the WebSocket constructor steps
nsString mOriginalURL;
nsString mEffectiveURL; // after redirects
bool mSecure; // if true it is using SSL and the wss scheme,
// otherwise it is using the ws scheme with no SSL
@ -234,16 +176,10 @@ public:
nsCString mURI;
nsCString mRequestedProtocolList;
nsCString mEstablishedProtocol;
nsCString mEstablishedExtensions;
nsCOMPtr<nsIPrincipal> mPrincipal;
nsWeakPtr mOriginDocument;
uint32_t mOutgoingBufferedAmount;
dom::BinaryType mBinaryType;
// Web Socket owner information:
// - the script file name, UTF8 encoded.
// - source code line number where the Web Socket object was constructed.
@ -254,10 +190,6 @@ public:
uint32_t mScriptLine;
uint64_t mInnerWindowID;
// This mutex protects mReadyState that is the only variable that is used in
// different threads.
mozilla::Mutex mMutex;
WorkerPrivate* mWorkerPrivate;
nsAutoPtr<WorkerFeature> mWorkerFeature;
@ -269,9 +201,6 @@ private:
Disconnect();
}
}
// This value should not be used directly but use ReadyState() instead.
uint16_t mReadyState;
};
NS_IMPL_ISUPPORTS(WebSocketImpl,
@ -450,7 +379,7 @@ WebSocketImpl::CloseConnection(uint16_t aReasonCode,
{
AssertIsOnTargetThread();
uint16_t readyState = ReadyState();
uint16_t readyState = mWebSocket->ReadyState();
if (readyState == WebSocket::CLOSING ||
readyState == WebSocket::CLOSED) {
return NS_OK;
@ -458,7 +387,7 @@ WebSocketImpl::CloseConnection(uint16_t aReasonCode,
// The common case...
if (mChannel) {
SetReadyState(WebSocket::CLOSING);
mWebSocket->SetReadyState(WebSocket::CLOSING);
// The channel has to be closed on the main-thread.
@ -481,7 +410,7 @@ WebSocketImpl::CloseConnection(uint16_t aReasonCode,
mCloseEventCode = aReasonCode;
CopyUTF8toUTF16(aReasonString, mCloseEventReason);
SetReadyState(WebSocket::CLOSING);
mWebSocket->SetReadyState(WebSocket::CLOSING);
// Can be called from Cancel() or Init() codepaths, so need to dispatch
// onerror/onclose asynchronously
@ -503,7 +432,7 @@ WebSocketImpl::ConsoleError()
NS_ConvertUTF8toUTF16 specUTF16(mURI);
const char16_t* formatStrings[] = { specUTF16.get() };
if (ReadyState() < WebSocket::OPEN) {
if (mWebSocket->ReadyState() < WebSocket::OPEN) {
PrintErrorOnConsole("chrome://global/locale/appstrings.properties",
MOZ_UTF16("connectionFailure"),
formatStrings, ArrayLength(formatStrings));
@ -621,7 +550,7 @@ WebSocketImpl::DoOnMessageAvailable(const nsACString& aMsg, bool isBinary)
{
AssertIsOnTargetThread();
int16_t readyState = ReadyState();
int16_t readyState = mWebSocket->ReadyState();
if (readyState == WebSocket::CLOSED) {
NS_ERROR("Received message after CLOSED");
return NS_ERROR_UNEXPECTED;
@ -664,7 +593,7 @@ WebSocketImpl::OnStart(nsISupports* aContext)
{
AssertIsOnTargetThread();
int16_t readyState = ReadyState();
int16_t readyState = mWebSocket->ReadyState();
// This is the only function that sets OPEN, and should be called only once
MOZ_ASSERT(readyState != WebSocket::OPEN,
@ -683,13 +612,13 @@ WebSocketImpl::OnStart(nsISupports* aContext)
}
if (!mRequestedProtocolList.IsEmpty()) {
mChannel->GetProtocol(mEstablishedProtocol);
mChannel->GetProtocol(mWebSocket->mEstablishedProtocol);
}
mChannel->GetExtensions(mEstablishedExtensions);
mChannel->GetExtensions(mWebSocket->mEstablishedExtensions);
UpdateURI();
SetReadyState(WebSocket::OPEN);
mWebSocket->SetReadyState(WebSocket::OPEN);
// Call 'onopen'
rv = mWebSocket->CreateAndDispatchSimpleEvent(NS_LITERAL_STRING("open"));
@ -710,7 +639,7 @@ WebSocketImpl::OnStop(nsISupports* aContext, nsresult aStatusCode)
// We can be CONNECTING here if connection failed.
// We can be OPEN if we have encountered a fatal protocol error
// We can be CLOSING if close() was called and/or server initiated close.
MOZ_ASSERT(ReadyState() != WebSocket::CLOSED,
MOZ_ASSERT(mWebSocket->ReadyState() != WebSocket::CLOSED,
"Shouldn't already be CLOSED when OnStop called");
// called by network stack, not JS, so can dispatch JS events synchronously
@ -755,11 +684,11 @@ WebSocketImpl::OnAcknowledge(nsISupports *aContext, uint32_t aSize)
{
AssertIsOnTargetThread();
if (aSize > mOutgoingBufferedAmount) {
if (aSize > mWebSocket->mOutgoingBufferedAmount) {
return NS_ERROR_UNEXPECTED;
}
mOutgoingBufferedAmount -= aSize;
mWebSocket->mOutgoingBufferedAmount -= aSize;
return NS_OK;
}
@ -769,7 +698,7 @@ WebSocketImpl::OnServerClose(nsISupports *aContext, uint16_t aCode,
{
AssertIsOnTargetThread();
int16_t readyState = ReadyState();
int16_t readyState = mWebSocket->ReadyState();
MOZ_ASSERT(readyState != WebSocket::CONNECTING,
"Received server close before connected?");
@ -807,7 +736,7 @@ WebSocketImpl::GetInterface(const nsIID& aIID, void** aResult)
{
AssertIsOnMainThread();
if (ReadyState() == WebSocket::CLOSED) {
if (!mWebSocket || mWebSocket->ReadyState() == WebSocket::CLOSED) {
return NS_ERROR_FAILURE;
}
@ -841,6 +770,10 @@ WebSocket::WebSocket(nsPIDOMWindow* aOwnerWindow)
, mWorkerPrivate(nullptr)
, mKeepingAlive(false)
, mCheckMustKeepAlive(true)
, mOutgoingBufferedAmount(0)
, mBinaryType(dom::BinaryType::Blob)
, mMutex("WebSocketImpl::mMutex")
, mReadyState(CONNECTING)
{
mImpl = new WebSocketImpl(this);
mWorkerPrivate = mImpl->mWorkerPrivate;
@ -1490,7 +1423,7 @@ void
WebSocketImpl::DispatchConnectionCloseEvents()
{
AssertIsOnTargetThread();
SetReadyState(WebSocket::CLOSED);
mWebSocket->SetReadyState(WebSocket::CLOSED);
// Call 'onerror' if needed
if (mFailed) {
@ -1516,7 +1449,7 @@ nsresult
WebSocket::CreateAndDispatchSimpleEvent(const nsAString& aName)
{
MOZ_ASSERT(mImpl);
mImpl->AssertIsOnTargetThread();
AssertIsOnTargetThread();
nsresult rv = CheckInnerWindowCorrectness();
if (NS_FAILED(rv)) {
@ -1541,7 +1474,7 @@ WebSocket::CreateAndDispatchMessageEvent(const nsACString& aData,
bool aIsBinary)
{
MOZ_ASSERT(mImpl);
mImpl->AssertIsOnTargetThread();
AssertIsOnTargetThread();
AutoJSAPI jsapi;
@ -1565,7 +1498,7 @@ WebSocket::CreateAndDispatchMessageEvent(JSContext* aCx,
bool aIsBinary)
{
MOZ_ASSERT(mImpl);
mImpl->AssertIsOnTargetThread();
AssertIsOnTargetThread();
nsresult rv = CheckInnerWindowCorrectness();
if (NS_FAILED(rv)) {
@ -1575,11 +1508,11 @@ WebSocket::CreateAndDispatchMessageEvent(JSContext* aCx,
// Create appropriate JS object for message
JS::Rooted<JS::Value> jsData(aCx);
if (aIsBinary) {
if (mImpl->mBinaryType == dom::BinaryType::Blob) {
if (mBinaryType == dom::BinaryType::Blob) {
nsresult rv = nsContentUtils::CreateBlobBuffer(aCx, GetOwner(), aData,
&jsData);
NS_ENSURE_SUCCESS(rv, rv);
} else if (mImpl->mBinaryType == dom::BinaryType::Arraybuffer) {
} else if (mBinaryType == dom::BinaryType::Arraybuffer) {
JS::Rooted<JSObject*> arrayBuf(aCx);
nsresult rv = nsContentUtils::CreateArrayBuffer(aCx, aData,
arrayBuf.address());
@ -1625,7 +1558,7 @@ WebSocket::CreateAndDispatchCloseEvent(bool aWasClean,
const nsAString &aReason)
{
MOZ_ASSERT(mImpl);
mImpl->AssertIsOnTargetThread();
AssertIsOnTargetThread();
nsresult rv = CheckInnerWindowCorrectness();
if (NS_FAILED(rv)) {
@ -1767,7 +1700,7 @@ WebSocketImpl::ParseURL(const nsAString& aURL)
}
}
mOriginalURL = aURL;
mWebSocket->mOriginalURL = aURL;
rv = parsedURL->GetSpec(mURI);
MOZ_ASSERT(NS_SUCCEEDED(rv));
@ -1795,9 +1728,9 @@ WebSocket::UpdateMustKeepAlive()
bool shouldKeepAlive = false;
if (mListenerManager) {
switch (mImpl->ReadyState())
switch (ReadyState())
{
case WebSocket::CONNECTING:
case CONNECTING:
{
if (mListenerManager->HasListenersFor(nsGkAtoms::onopen) ||
mListenerManager->HasListenersFor(nsGkAtoms::onmessage) ||
@ -1808,19 +1741,19 @@ WebSocket::UpdateMustKeepAlive()
}
break;
case WebSocket::OPEN:
case WebSocket::CLOSING:
case OPEN:
case CLOSING:
{
if (mListenerManager->HasListenersFor(nsGkAtoms::onmessage) ||
mListenerManager->HasListenersFor(nsGkAtoms::onerror) ||
mListenerManager->HasListenersFor(nsGkAtoms::onclose) ||
mImpl->mOutgoingBufferedAmount != 0) {
mOutgoingBufferedAmount != 0) {
shouldKeepAlive = true;
}
}
break;
case WebSocket::CLOSED:
case CLOSED:
{
shouldKeepAlive = false;
}
@ -1940,7 +1873,7 @@ WebSocketImpl::UpdateURI()
channel = static_cast<BaseWebSocketChannel*>(mChannel.get());
MOZ_ASSERT(channel);
channel->GetEffectiveURL(mEffectiveURL);
channel->GetEffectiveURL(mWebSocket->mEffectiveURL);
mSecure = channel->IsEncrypted();
return NS_OK;
@ -1966,62 +1899,70 @@ WebSocket::EventListenerRemoved(nsIAtom* aType)
// webIDL: readonly attribute unsigned short readyState;
uint16_t
WebSocket::ReadyState() const
WebSocket::ReadyState()
{
MOZ_ASSERT(mImpl);
return mImpl->ReadyState();
MutexAutoLock lock(mMutex);
return mReadyState;
}
void
WebSocket::SetReadyState(uint16_t aReadyState)
{
MutexAutoLock lock(mMutex);
mReadyState = aReadyState;
}
// webIDL: readonly attribute unsigned long bufferedAmount;
uint32_t
WebSocket::BufferedAmount() const
{
MOZ_ASSERT(mImpl);
return mImpl->BufferedAmount();
AssertIsOnTargetThread();
return mOutgoingBufferedAmount;
}
// webIDL: attribute BinaryType binaryType;
dom::BinaryType
WebSocket::BinaryType() const
{
MOZ_ASSERT(mImpl);
return mImpl->BinaryType();
AssertIsOnTargetThread();
return mBinaryType;
}
// webIDL: attribute BinaryType binaryType;
void
WebSocket::SetBinaryType(dom::BinaryType aData)
{
MOZ_ASSERT(mImpl);
mImpl->SetBinaryType(aData);
AssertIsOnTargetThread();
mBinaryType = aData;
}
// webIDL: readonly attribute DOMString url
void
WebSocket::GetUrl(nsAString& aURL)
{
MOZ_ASSERT(mImpl);
mImpl->GetUrl(aURL);
AssertIsOnTargetThread();
if (mEffectiveURL.IsEmpty()) {
aURL = mOriginalURL;
} else {
aURL = mEffectiveURL;
}
}
// webIDL: readonly attribute DOMString extensions;
void
WebSocket::GetExtensions(nsAString& aExtensions)
{
MOZ_ASSERT(mImpl);
mImpl->AssertIsOnTargetThread();
CopyUTF8toUTF16(mImpl->mEstablishedExtensions, aExtensions);
AssertIsOnTargetThread();
CopyUTF8toUTF16(mEstablishedExtensions, aExtensions);
}
// webIDL: readonly attribute DOMString protocol;
void
WebSocket::GetProtocol(nsAString& aProtocol)
{
MOZ_ASSERT(mImpl);
mImpl->AssertIsOnTargetThread();
CopyUTF8toUTF16(mImpl->mEstablishedProtocol, aProtocol);
AssertIsOnTargetThread();
CopyUTF8toUTF16(mEstablishedProtocol, aProtocol);
}
// webIDL: void send(DOMString data);
@ -2029,16 +1970,17 @@ void
WebSocket::Send(const nsAString& aData,
ErrorResult& aRv)
{
MOZ_ASSERT(mImpl);
mImpl->AssertIsOnTargetThread();
AssertIsOnTargetThread();
NS_ConvertUTF16toUTF8 msgString(aData);
mImpl->Send(nullptr, msgString, msgString.Length(), false, aRv);
Send(nullptr, msgString, msgString.Length(), false, aRv);
}
void
WebSocket::Send(File& aData, ErrorResult& aRv)
{
AssertIsOnTargetThread();
nsCOMPtr<nsIInputStream> msgStream;
nsresult rv = aData.GetInternalStream(getter_AddRefs(msgStream));
if (NS_FAILED(rv)) {
@ -2058,15 +2000,14 @@ WebSocket::Send(File& aData, ErrorResult& aRv)
return;
}
mImpl->Send(msgStream, EmptyCString(), msgLength, true, aRv);
Send(msgStream, EmptyCString(), msgLength, true, aRv);
}
void
WebSocket::Send(const ArrayBuffer& aData,
ErrorResult& aRv)
{
MOZ_ASSERT(mImpl);
mImpl->AssertIsOnTargetThread();
AssertIsOnTargetThread();
aData.ComputeLengthAndData();
@ -2076,15 +2017,14 @@ WebSocket::Send(const ArrayBuffer& aData,
char* data = reinterpret_cast<char*>(aData.Data());
nsDependentCSubstring msgString(data, len);
mImpl->Send(nullptr, msgString, len, true, aRv);
Send(nullptr, msgString, len, true, aRv);
}
void
WebSocket::Send(const ArrayBufferView& aData,
ErrorResult& aRv)
{
MOZ_ASSERT(mImpl);
mImpl->AssertIsOnTargetThread();
AssertIsOnTargetThread();
aData.ComputeLengthAndData();
@ -2094,20 +2034,20 @@ WebSocket::Send(const ArrayBufferView& aData,
char* data = reinterpret_cast<char*>(aData.Data());
nsDependentCSubstring msgString(data, len);
mImpl->Send(nullptr, msgString, len, true, aRv);
Send(nullptr, msgString, len, true, aRv);
}
void
WebSocketImpl::Send(nsIInputStream* aMsgStream,
const nsACString& aMsgString,
uint32_t aMsgLength,
bool aIsBinary,
ErrorResult& aRv)
WebSocket::Send(nsIInputStream* aMsgStream,
const nsACString& aMsgString,
uint32_t aMsgLength,
bool aIsBinary,
ErrorResult& aRv)
{
AssertIsOnTargetThread();
int64_t readyState = ReadyState();
if (readyState == WebSocket::CONNECTING) {
if (readyState == CONNECTING) {
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
return;
}
@ -2115,22 +2055,23 @@ WebSocketImpl::Send(nsIInputStream* aMsgStream,
// Always increment outgoing buffer len, even if closed
mOutgoingBufferedAmount += aMsgLength;
if (readyState == WebSocket::CLOSING ||
readyState == WebSocket::CLOSED) {
if (readyState == CLOSING ||
readyState == CLOSED) {
return;
}
MOZ_ASSERT(readyState == WebSocket::OPEN,
"Unknown state in WebSocket::Send");
// We must have mImpl when connected.
MOZ_ASSERT(mImpl);
MOZ_ASSERT(readyState == OPEN, "Unknown state in WebSocket::Send");
nsresult rv;
if (aMsgStream) {
rv = mChannel->SendBinaryStream(aMsgStream, aMsgLength);
rv = mImpl->mChannel->SendBinaryStream(aMsgStream, aMsgLength);
} else {
if (aIsBinary) {
rv = mChannel->SendBinaryMsg(aMsgString);
rv = mImpl->mChannel->SendBinaryMsg(aMsgString);
} else {
rv = mChannel->SendMsg(aMsgString);
rv = mImpl->mChannel->SendMsg(aMsgString);
}
}
@ -2139,7 +2080,7 @@ WebSocketImpl::Send(nsIInputStream* aMsgStream,
return;
}
mWebSocket->UpdateMustKeepAlive();
UpdateMustKeepAlive();
}
// webIDL: void close(optional unsigned short code, optional DOMString reason):
@ -2147,15 +2088,6 @@ void
WebSocket::Close(const Optional<uint16_t>& aCode,
const Optional<nsAString>& aReason,
ErrorResult& aRv)
{
MOZ_ASSERT(mImpl);
mImpl->Close(aCode, aReason, aRv);
}
void
WebSocketImpl::Close(const Optional<uint16_t>& aCode,
const Optional<nsAString>& aReason,
ErrorResult& aRv)
{
AssertIsOnTargetThread();
@ -2181,18 +2113,21 @@ WebSocketImpl::Close(const Optional<uint16_t>& aCode,
}
int64_t readyState = ReadyState();
if (readyState == WebSocket::CLOSING ||
readyState == WebSocket::CLOSED) {
if (readyState == CLOSING ||
readyState == CLOSED) {
return;
}
if (readyState == WebSocket::CONNECTING) {
FailConnection(closeCode, closeReason);
// If the webSocket is not closed we MUST have a mImpl.
MOZ_ASSERT(mImpl);
if (readyState == CONNECTING) {
mImpl->FailConnection(closeCode, closeReason);
return;
}
MOZ_ASSERT(readyState == WebSocket::OPEN);
CloseConnection(closeCode, closeReason);
MOZ_ASSERT(readyState == OPEN);
mImpl->CloseConnection(closeCode, closeReason);
}
//-----------------------------------------------------------------------------
@ -2206,7 +2141,7 @@ WebSocketImpl::Observe(nsISupports* aSubject,
{
AssertIsOnMainThread();
int64_t readyState = ReadyState();
int64_t readyState = mWebSocket->ReadyState();
if ((readyState == WebSocket::CLOSING) ||
(readyState == WebSocket::CLOSED)) {
return NS_OK;
@ -2235,7 +2170,7 @@ WebSocketImpl::GetName(nsACString& aName)
{
AssertIsOnMainThread();
CopyUTF16toUTF8(mOriginalURL, aName);
CopyUTF16toUTF8(mWebSocket->mOriginalURL, aName);
return NS_OK;
}
@ -2244,7 +2179,7 @@ WebSocketImpl::IsPending(bool* aValue)
{
AssertIsOnTargetThread();
int64_t readyState = ReadyState();
int64_t readyState = mWebSocket->ReadyState();
*aValue = (readyState != WebSocket::CLOSED);
return NS_OK;
}
@ -2323,7 +2258,7 @@ WebSocketImpl::CancelInternal()
{
AssertIsOnTargetThread();
int64_t readyState = ReadyState();
int64_t readyState = mWebSocket->ReadyState();
if (readyState == WebSocket::CLOSING || readyState == WebSocket::CLOSED) {
return NS_OK;
}
@ -2484,5 +2419,11 @@ WebSocketImpl::IsTargetThread() const
return NS_IsMainThread() == !mWorkerPrivate;
}
void
WebSocket::AssertIsOnTargetThread() const
{
MOZ_ASSERT(NS_IsMainThread() == !mWorkerPrivate);
}
} // dom namespace
} // mozilla namespace

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

@ -23,6 +23,8 @@
#define DEFAULT_WS_SCHEME_PORT 80
#define DEFAULT_WSS_SCHEME_PORT 443
class nsIInputStream;
namespace mozilla {
namespace dom {
@ -88,7 +90,7 @@ public: // WebIDL interface:
void GetUrl(nsAString& aResult);
// webIDL: readonly attribute unsigned short readyState;
uint16_t ReadyState() const;
uint16_t ReadyState();
// webIDL: readonly attribute unsigned long bufferedAmount;
uint32_t BufferedAmount() const;
@ -134,6 +136,8 @@ private: // constructor && distructor
explicit WebSocket(nsPIDOMWindow* aOwnerWindow);
virtual ~WebSocket();
void SetReadyState(uint16_t aReadyState);
// These methods actually do the dispatch for various events.
nsresult CreateAndDispatchSimpleEvent(const nsAString& aName);
nsresult CreateAndDispatchMessageEvent(const nsACString& aData,
@ -157,16 +161,39 @@ private:
WebSocket(const WebSocket& x) MOZ_DELETE; // prevent bad usage
WebSocket& operator=(const WebSocket& x) MOZ_DELETE;
void Send(nsIInputStream* aMsgStream,
const nsACString& aMsgString,
uint32_t aMsgLength,
bool aIsBinary,
ErrorResult& aRv);
void AssertIsOnTargetThread() const;
// Raw pointer because this WebSocketImpl is created, managed and destroyed by
// WebSocket.
WebSocketImpl* mImpl;
// This is used just to check in which thread this object is used when mImpl
// is null.
workers::WorkerPrivate* mWorkerPrivate;
bool mKeepingAlive;
bool mCheckMustKeepAlive;
uint32_t mOutgoingBufferedAmount;
// related to the WebSocket constructor steps
nsString mOriginalURL;
nsString mEffectiveURL; // after redirects
nsCString mEstablishedExtensions;
nsCString mEstablishedProtocol;
dom::BinaryType mBinaryType;
// This mutex protects mReadyState that is the only variable that is used in
// different threads.
mozilla::Mutex mMutex;
// This value should not be used directly but use ReadyState() instead.
uint16_t mReadyState;
};
} //namespace dom

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

@ -659,3 +659,4 @@ support-files = file_bug1011748_redirect.sjs file_bug1011748_OK.sjs
[test_element.matches.html]
[test_user_select.html]
skip-if = buildapp == 'mulet' || buildapp == 'b2g'
[test_bug1081686.html]

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

@ -0,0 +1,70 @@
<!DOCTYPE HTML>
<html>
<!--
-->
<head>
<title>bug 1081686</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body onload="testWebSocket()">
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
var ws;
function forcegc()
{
SpecialPowers.forceGC();
SpecialPowers.gc();
setTimeout(function()
{
SpecialPowers.gc();
}, 0);
}
function testWebSocket () {
ws = new WebSocket("ws://mochi.test:8888/tests/content/base/test/file_websocket_hello");
ws.onopen = function(e) {
ws.send("data");
}
ws.onclose = function(e) {
forcegc();
setTimeout(function() {
is(ws.readyState, 3, 'WebSocket is closed');
is(ws.bufferedAmount, 0, 'WebSocket.bufferedAmount should be empty.');
is(ws.binaryType, 'blob', 'WebSocket.binaryType is blob');
ws.binaryType = 'arraybuffer';
is(ws.binaryType, 'arraybuffer', 'WebSocket.binaryType is arraybuffer');
is(ws.url, 'ws://mochi.test:8888/tests/content/base/test/file_websocket_hello', 'WebSocket.url is correct');
ws.close();
ws.send('foobar');
SimpleTest.finish();
}, 1000);
}
ws.onerror = function(e) {
ok(false, "onerror called!");
SimpleTest.finish();
}
ws.onmessage = function(e) {
is(e.data, "Hello world!", "Wrong data");
ws.close();
}
}
SimpleTest.waitForExplicitFinish();
</script>
</pre>
<div>
</div>
</body>
</html>