[network] Add locking around access to WebSocketChannel::mPMCECompressor

This commit is contained in:
Moonchild 2023-08-30 16:38:42 +02:00 • committed by roytam1
commit 058e936f62
2 changed files with 49 additions and 33 deletions

View file

@ -1191,6 +1191,7 @@ WebSocketChannel::WebSocketChannel() :
mBufferSize(kIncomingBufferInitialSize), mBufferSize(kIncomingBufferInitialSize),
mCurrentOut(nullptr), mCurrentOut(nullptr),
mCurrentOutSent(0), mCurrentOutSent(0),
mCompressorMutex("WebSocketChannel::mCompressorMutex"),
mDynamicOutputSize(0), mDynamicOutputSize(0),
mDynamicOutput(nullptr), mDynamicOutput(nullptr),
mPrivateBrowsing(false), mPrivateBrowsing(false),
@ -1627,6 +1628,7 @@ WebSocketChannel::ProcessInput(uint8_t *buffer, uint32_t count)
if (rsvBits) { if (rsvBits) {
// PMCE sets RSV1 bit in the first fragment when the non-control frame // PMCE sets RSV1 bit in the first fragment when the non-control frame
// is deflated // is deflated
MutexAutoLock lock(mCompressorMutex);
if (mPMCECompressor && rsvBits == kRsv1Bit && mFragmentAccumulator == 0 && if (mPMCECompressor && rsvBits == kRsv1Bit && mFragmentAccumulator == 0 &&
!(opcode & kControlFrameMask)) { !(opcode & kControlFrameMask)) {
mPMCECompressor->SetMessageDeflated(); mPMCECompressor->SetMessageDeflated();
@ -1700,13 +1702,15 @@ WebSocketChannel::ProcessInput(uint8_t *buffer, uint32_t count)
LOG(("WebSocketChannel:: ignoring read frame code %d after completion\n", LOG(("WebSocketChannel:: ignoring read frame code %d after completion\n",
opcode)); opcode));
} else if (opcode == nsIWebSocketFrame::OPCODE_TEXT) { } else if (opcode == nsIWebSocketFrame::OPCODE_TEXT) {
if (mListenerMT) {
nsCString utf8Data;
{ // lockscope
MutexAutoLock lock(mCompressorMutex);
bool isDeflated = mPMCECompressor && mPMCECompressor->IsMessageDeflated(); bool isDeflated = mPMCECompressor && mPMCECompressor->IsMessageDeflated();
LOG(("WebSocketChannel:: %stext frame received\n", LOG(("WebSocketChannel:: %stext frame received\n",
isDeflated ? "deflated " : "")); isDeflated ? "deflated " : ""));
if (mListenerMT) {
nsCString utf8Data;
if (isDeflated) { if (isDeflated) {
rv = mPMCECompressor->Inflate(payload, payloadLength, utf8Data); rv = mPMCECompressor->Inflate(payload, payloadLength, utf8Data);
if (NS_FAILED(rv)) { if (NS_FAILED(rv)) {
@ -1721,6 +1725,7 @@ WebSocketChannel::ProcessInput(uint8_t *buffer, uint32_t count)
return NS_ERROR_OUT_OF_MEMORY; return NS_ERROR_OUT_OF_MEMORY;
} }
} }
}
// Section 8.1 says to fail connection if invalid utf-8 in text message // Section 8.1 says to fail connection if invalid utf-8 in text message
if (!IsUTF8(utf8Data, false)) { if (!IsUTF8(utf8Data, false)) {
@ -1835,13 +1840,15 @@ WebSocketChannel::ProcessInput(uint8_t *buffer, uint32_t count)
mService->FrameReceived(mSerial, mInnerWindowID, frame.forget()); mService->FrameReceived(mSerial, mInnerWindowID, frame.forget());
} }
} else if (opcode == nsIWebSocketFrame::OPCODE_BINARY) { } else if (opcode == nsIWebSocketFrame::OPCODE_BINARY) {
if (mListenerMT) {
nsCString binaryData;
{ //lockscope
MutexAutoLock lock(mCompressorMutex);
bool isDeflated = mPMCECompressor && mPMCECompressor->IsMessageDeflated(); bool isDeflated = mPMCECompressor && mPMCECompressor->IsMessageDeflated();
LOG(("WebSocketChannel:: %sbinary frame received\n", LOG(("WebSocketChannel:: %sbinary frame received\n",
isDeflated ? "deflated " : "")); isDeflated ? "deflated " : ""));
if (mListenerMT) {
nsCString binaryData;
if (isDeflated) { if (isDeflated) {
rv = mPMCECompressor->Inflate(payload, payloadLength, binaryData); rv = mPMCECompressor->Inflate(payload, payloadLength, binaryData);
if (NS_FAILED(rv)) { if (NS_FAILED(rv)) {
@ -1856,6 +1863,7 @@ WebSocketChannel::ProcessInput(uint8_t *buffer, uint32_t count)
return NS_ERROR_OUT_OF_MEMORY; return NS_ERROR_OUT_OF_MEMORY;
} }
} }
}
RefPtr<WebSocketFrame> frame = RefPtr<WebSocketFrame> frame =
mService->CreateFrameIfNeeded(finBit, rsvBit1, rsvBit2, rsvBit3, mService->CreateFrameIfNeeded(finBit, rsvBit1, rsvBit2, rsvBit3,
@ -2156,6 +2164,7 @@ WebSocketChannel::PrimeNewOutgoingMessage()
} }
// deflate the payload if PMCE is negotiated // deflate the payload if PMCE is negotiated
MutexAutoLock lock(mCompressorMutex);
if (mPMCECompressor && if (mPMCECompressor &&
(msgType == kMsgTypeString || msgType == kMsgTypeBinaryString)) { (msgType == kMsgTypeString || msgType == kMsgTypeBinaryString)) {
if (mCurrentOut->DeflatePayload(mPMCECompressor)) { if (mCurrentOut->DeflatePayload(mPMCECompressor)) {
@ -2447,7 +2456,10 @@ WebSocketChannel::StopSession(nsresult reason)
mCancelable = nullptr; mCancelable = nullptr;
} }
{
MutexAutoLock lock(mCompressorMutex);
mPMCECompressor = nullptr; mPMCECompressor = nullptr;
}
if (!mCalledOnStop) { if (!mCalledOnStop) {
mCalledOnStop = 1; mCalledOnStop = 1;
@ -2702,6 +2714,7 @@ WebSocketChannel::HandleExtensions()
serverMaxWindowBits = 15; serverMaxWindowBits = 15;
} }
MutexAutoLock lock(mCompressorMutex);
mPMCECompressor = new PMCECompression(clientNoContextTakeover, mPMCECompressor = new PMCECompression(clientNoContextTakeover,
clientMaxWindowBits, clientMaxWindowBits,
serverMaxWindowBits); serverMaxWindowBits);
@ -3678,6 +3691,7 @@ WebSocketChannel::OnTransportAvailable(nsISocketTransport *aTransport,
serverMaxWindowBits = 15; serverMaxWindowBits = 15;
} }
MutexAutoLock lock(mCompressorMutex);
mPMCECompressor = new PMCECompression(serverNoContextTakeover, mPMCECompressor = new PMCECompression(serverNoContextTakeover,
serverMaxWindowBits, serverMaxWindowBits,
clientMaxWindowBits); clientMaxWindowBits);

View file

@ -18,6 +18,7 @@
#include "nsIChannelEventSink.h" #include "nsIChannelEventSink.h"
#include "nsIHttpChannelInternal.h" #include "nsIHttpChannelInternal.h"
#include "nsIStringStream.h" #include "nsIStringStream.h"
#include "mozilla/Mutex.h"
#include "BaseWebSocketChannel.h" #include "BaseWebSocketChannel.h"
#include "nsCOMPtr.h" #include "nsCOMPtr.h"
@ -288,6 +289,7 @@ private:
uint32_t mHdrOutToSend; uint32_t mHdrOutToSend;
uint8_t *mHdrOut; uint8_t *mHdrOut;
uint8_t mOutHeader[kCopyBreak + 16]; uint8_t mOutHeader[kCopyBreak + 16];
Mutex mCompressorMutex;
nsAutoPtr<PMCECompression> mPMCECompressor; nsAutoPtr<PMCECompression> mPMCECompressor;
uint32_t mDynamicOutputSize; uint32_t mDynamicOutputSize;
uint8_t *mDynamicOutput; uint8_t *mDynamicOutput;