[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,25 +1702,28 @@ 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) {
bool isDeflated = mPMCECompressor && mPMCECompressor->IsMessageDeflated();
LOG(("WebSocketChannel:: %stext frame received\n",
isDeflated ? "deflated " : ""));
if (mListenerMT) { if (mListenerMT) {
nsCString utf8Data; nsCString utf8Data;
if (isDeflated) { { // lockscope
rv = mPMCECompressor->Inflate(payload, payloadLength, utf8Data); MutexAutoLock lock(mCompressorMutex);
if (NS_FAILED(rv)) { bool isDeflated = mPMCECompressor && mPMCECompressor->IsMessageDeflated();
return rv; LOG(("WebSocketChannel:: %stext frame received\n",
} isDeflated ? "deflated " : ""));
LOG(("WebSocketChannel:: message successfully inflated "
"[origLength=%d, newLength=%d]\n", payloadLength, if (isDeflated) {
utf8Data.Length())); rv = mPMCECompressor->Inflate(payload, payloadLength, utf8Data);
} else { if (NS_FAILED(rv)) {
if (!utf8Data.Assign((const char *)payload, payloadLength, return rv;
mozilla::fallible)) { }
return NS_ERROR_OUT_OF_MEMORY; LOG(("WebSocketChannel:: message successfully inflated "
"[origLength=%d, newLength=%d]\n", payloadLength,
utf8Data.Length()));
} else {
if (!utf8Data.Assign((const char *)payload, payloadLength,
mozilla::fallible)) {
return NS_ERROR_OUT_OF_MEMORY;
}
} }
} }
@ -1835,25 +1840,28 @@ 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) {
bool isDeflated = mPMCECompressor && mPMCECompressor->IsMessageDeflated();
LOG(("WebSocketChannel:: %sbinary frame received\n",
isDeflated ? "deflated " : ""));
if (mListenerMT) { if (mListenerMT) {
nsCString binaryData; nsCString binaryData;
if (isDeflated) { { //lockscope
rv = mPMCECompressor->Inflate(payload, payloadLength, binaryData); MutexAutoLock lock(mCompressorMutex);
if (NS_FAILED(rv)) { bool isDeflated = mPMCECompressor && mPMCECompressor->IsMessageDeflated();
return rv; LOG(("WebSocketChannel:: %sbinary frame received\n",
} isDeflated ? "deflated " : ""));
LOG(("WebSocketChannel:: message successfully inflated "
"[origLength=%d, newLength=%d]\n", payloadLength, if (isDeflated) {
binaryData.Length())); rv = mPMCECompressor->Inflate(payload, payloadLength, binaryData);
} else { if (NS_FAILED(rv)) {
if (!binaryData.Assign((const char *)payload, payloadLength, return rv;
mozilla::fallible)) { }
return NS_ERROR_OUT_OF_MEMORY; LOG(("WebSocketChannel:: message successfully inflated "
"[origLength=%d, newLength=%d]\n", payloadLength,
binaryData.Length()));
} else {
if (!binaryData.Assign((const char *)payload, payloadLength,
mozilla::fallible)) {
return NS_ERROR_OUT_OF_MEMORY;
}
} }
} }
@ -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;
} }
mPMCECompressor = nullptr; {
MutexAutoLock lock(mCompressorMutex);
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;