зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
654a1342d7
Коммит
7de75430e6
|
@ -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>
|
Загрузка…
Ссылка в новой задаче