void WebSocketWorker::doRead() { if (!m_isRunning) return; if (!m_webSocketServer.IsRunning() || !m_socket->isOpen()) { CloseConnection(); return; } if (m_webSocketMode) { ProcessFrames(m_socket); } else { if (!ProcessHandshake(m_socket)) SendClose(kCloseProtocolError); } if (!m_webSocketMode) { LOG(VB_HTTP, LOG_WARNING, "WebSocketServer: Timed out waiting for connection upgrade"); CloseConnection(); } }
void IPCBlobInputStreamChild::Migrated() { MutexAutoLock lock(mMutex); MOZ_ASSERT(mState == eInactiveMigrating); mWorkerRef = nullptr; mOwningEventTarget = GetCurrentThreadSerialEventTarget(); MOZ_ASSERT(IPCBlobInputStreamThread::IsOnFileEventTarget(mOwningEventTarget)); // Maybe we have no reasons to keep this actor alive. if (mStreams.IsEmpty()) { mState = eInactive; SendClose(); return; } mState = eActive; // Let's processing the pending operations. We need a stream for each pending // operation. for (uint32_t i = 0; i < mPendingOperations.Length(); ++i) { if (mPendingOperations[i].mOp == PendingOperation::eStreamNeeded) { SendStreamNeeded(); } else { MOZ_ASSERT(mPendingOperations[i].mOp == PendingOperation::eLengthNeeded); SendLengthNeeded(); } } }
NS_IMETHODIMP PresentationBuilderChild::Close(nsresult reason) { if (NS_WARN_IF(mActorDestroyed || !SendClose(reason))) { return NS_ERROR_FAILURE; } return NS_OK; }
void WebSocketWorker::HandleCloseConnection(const QByteArray &payload) { uint16_t code = kCloseNormal; if (payload.length() == 1) { LOG(VB_GENERAL, LOG_ERR, "WebSocketWorker - Invalid close payload"); SendClose(kCloseProtocolError, "Invalid close payload"); return; } if (payload.length() >= 2) { code = (payload[0] << 8); code |= payload[1] & 0xFF; } if ((code < 1000) || ((code > 1003) && (code < 1007)) || ((code > 1011) && (code < 3000)) || (code > 4999)) { LOG(VB_GENERAL, LOG_ERR, "WebSocketWorker - Invalid close code received"); SendClose(kCloseProtocolError, "Invalid close code"); return; } QString closeMessage; if (payload.length() > 2) { QByteArray messageBytes = payload.mid(2); if (!CodecUtil::isValidUTF8(messageBytes)) { LOG(VB_GENERAL, LOG_ERR, "WebSocketWorker - Message is not valid UTF-8"); SendClose(kCloseBadData, "Message is not valid UTF-8"); return; } closeMessage = QString(messageBytes); } LOG(VB_HTTP, LOG_INFO, QString("WebSocketWorker - Received CLOSE frame - [%1] %2") .arg(QString::number(code)).arg(closeMessage)); SendClose((ErrorCode)code); }
NS_IMETHODIMP AltDataOutputStreamChild::Close() { if (!mIPCOpen) { return NS_ERROR_NOT_AVAILABLE; } if (NS_FAILED(mError)) { return mError; } Unused << SendClose(); return NS_OK; }
void WebSocketWorker::HandleDataFrame(const WebSocketFrame &frame) { if (frame.finalFrame) { QList<WebSocketExtension*>::iterator it; switch (frame.opCode) { case WebSocketFrame::kOpTextFrame : if (!CodecUtil::isValidUTF8(frame.payload)) { LOG(VB_GENERAL, LOG_ERR, "WebSocketWorker - Message is not valid UTF-8"); SendClose(kCloseBadData, "Message is not valid UTF-8"); return; } // For Debugging and fuzz testing if (m_fuzzTesting) SendText(frame.payload); it = m_extensions.begin(); for (; it != m_extensions.end(); ++it) { if ((*it)->HandleTextFrame(frame)) break; } break; case WebSocketFrame::kOpBinaryFrame : if (m_fuzzTesting) SendBinary(frame.payload); it = m_extensions.begin(); for (; it != m_extensions.end(); ++it) { if ((*it)->HandleBinaryFrame(frame)) break; } break; default: break; } m_readFrame.reset(); } else { // Start of new fragmented frame m_readFrame.reset(); m_readFrame.opCode = frame.opCode; m_readFrame.payloadSize = frame.payloadSize; m_readFrame.payload = frame.payload; m_readFrame.fragmented = true; m_readFrame.finalFrame = false; } }
void IPCBlobInputStreamChild::Shutdown() { MutexAutoLock lock(mMutex); RefPtr<IPCBlobInputStreamChild> kungFuDeathGrip = this; mWorkerRef = nullptr; mPendingOperations.Clear(); if (mState == eActive) { SendClose(); mState = eInactive; } }
void CachePushStreamChild::OnEnd(nsresult aRv) { NS_ASSERT_OWNINGTHREAD(CachePushStreamChild); MOZ_ASSERT(aRv != NS_BASE_STREAM_WOULD_BLOCK); if (mClosed) { return; } mClosed = true; mStream->CloseWithStatus(aRv); if (aRv == NS_BASE_STREAM_CLOSED) { aRv = NS_OK; } // This will trigger an ActorDestroy() from the parent side Unused << SendClose(aRv); }
GMPErr GMPStorageChild::Close(GMPRecordImpl* aRecord) { if (mPlugin->GMPMessageLoop() != MessageLoop::current()) { NS_WARNING("GMP used GMPStorage on non-main thread."); return GMPGenericErr; } if (!mRecords.Contains(aRecord->Name())) { // Already closed. return GMPClosedErr; } GMPErr rv = GMPNoErr; if (!mShutdown && !SendClose(aRecord->Name())) { rv = GMPGenericErr; } aRecord->MarkClosed(); mRecords.Remove(aRecord->Name()); return rv; }
void WebSocketWorker::ProcessFrames(QTcpSocket *socket) { while (m_isRunning && socket && socket->bytesAvailable() >= 2) // No header? Return and wait for more { uint8_t headerSize = 2; // Smallest possible header size is 2 bytes, greatest is 14 bytes QByteArray header = socket->peek(headerSize); // Read header to establish validity and size of frame WebSocketFrame frame; // FIN frame.finalFrame = (bool)(header[0] & 0x80); // Reserved bits if (header.at(0) & 0x70) { LOG(VB_GENERAL, LOG_ERR, "WebSocketWorker::ProcessFrames() " "- Invalid data in reserved fields"); SendClose(kCloseProtocolError, "Invalid data in reserved fields"); return; } // Operation code uint8_t opCode = (header.at(0) & 0xF); if ((opCode > WebSocketFrame::kOpBinaryFrame && opCode < WebSocketFrame::kOpClose) || (opCode > WebSocketFrame::kOpPong)) { LOG(VB_GENERAL, LOG_ERR, QString("WebSocketWorker::ProcessFrames() " "- Invalid OpCode (%1)") .arg(QString::number(opCode, 16))); SendClose(kCloseProtocolError, "Invalid OpCode"); return; } frame.opCode = (WebSocketFrame::OpCode)opCode; frame.isMasked = (header.at(1) >> 7) & 0xFE; if (frame.isMasked) headerSize += 4; // Add 4 bytes for the mask frame.payloadSize = (header.at(1) & 0x7F); // Handle 16 or 64bit payload size headers if (frame.payloadSize >= 126) { uint8_t payloadHeaderSize = 2; // 16bit payload size if (frame.payloadSize == 127) payloadHeaderSize = 8; // 64bit payload size headerSize += payloadHeaderSize; // Add bytes for extended payload size if (socket->bytesAvailable() < headerSize) return; // Return and wait for more header = socket->peek(headerSize); // Peek the entire header QByteArray payloadHeader = header.mid(2,payloadHeaderSize); frame.payloadSize = 0; for (int i = 0; i < payloadHeaderSize; i++) { frame.payloadSize |= ((uint8_t)payloadHeader.at(i) << ((payloadHeaderSize - (i + 1)) * 8)); } } else { if (socket->bytesAvailable() < headerSize) return; // Return and wait for more header = socket->peek(headerSize); // Peek the entire header including mask } while ((uint64_t)socket->bytesAvailable() < (frame.payloadSize + header.length())) { if (!socket->waitForReadyRead(2000)) // Wait 2 seconds for the next chunk of the frame { m_errorCount++; if (m_errorCount == 5) { LOG(VB_GENERAL, LOG_ERR, "WebSocketWorker::ProcessFrames() - Timed out waiting for rest of frame to arrive."); SendClose(kCloseBadData); } return; } } if (frame.opCode == WebSocketFrame::kOpContinuation) m_readFrame.payloadSize += frame.payloadSize; LOG(VB_HTTP, LOG_DEBUG, QString("Read Header: %1").arg(QString(header.toHex()))); LOG(VB_HTTP, LOG_DEBUG, QString("Final Frame: %1").arg(frame.finalFrame ? "Yes" : "No")); LOG(VB_HTTP, LOG_DEBUG, QString("Op Code: %1").arg(QString::number(frame.opCode))); LOG(VB_HTTP, LOG_DEBUG, QString("Payload Size: %1 Bytes").arg(QString::number(frame.payloadSize))); LOG(VB_HTTP, LOG_DEBUG, QString("Total Payload Size: %1 Bytes").arg(QString::number( m_readFrame.payloadSize))); if (!m_fuzzTesting && frame.payloadSize > qPow(2,20)) // Set 1MB limit on payload per frame { LOG(VB_GENERAL, LOG_ERR, "WebSocketWorker::ProcessFrames() - Frame payload larger than limit of 1MB"); SendClose(kCloseTooLarge, "Frame payload larger than limit of 1MB"); return; } if (!m_fuzzTesting && m_readFrame.payloadSize > qPow(2,22)) // Set 4MB limit on total payload { LOG(VB_GENERAL, LOG_ERR, "WebSocketWorker::ProcessFrames() - Total payload larger than limit of 4MB"); SendClose(kCloseTooLarge, "Total payload larger than limit of 4MB"); return; } socket->read(headerSize); // Discard header from read buffer frame.payload = socket->read(frame.payloadSize); // Unmask payload if (frame.isMasked) { frame.mask = header.right(4); for (uint i = 0; i < frame.payloadSize; i++) frame.payload[i] = frame.payload.at(i) ^ frame.mask[i % 4]; } if (m_readFrame.fragmented && frame.opCode > WebSocketFrame::kOpContinuation && frame.opCode < WebSocketFrame::kOpClose) { LOG(VB_GENERAL, LOG_ERR, "WebSocketWorker - Incomplete multi-part frame? Expected continuation."); SendClose(kCloseProtocolError, "Incomplete multi-part frame? Expected continuation."); return; } // Check control frame validity if (frame.opCode >= 0x08) { if (!frame.finalFrame) { SendClose(kCloseProtocolError, "Control frames MUST NOT be fragmented"); return; } else if (frame.payloadSize > 125) { SendClose(kCloseProtocolError, "Control frames MUST NOT have payload greater than 125 bytes"); return; } } switch (frame.opCode) { case WebSocketFrame::kOpContinuation: if (!m_readFrame.fragmented) { LOG(VB_GENERAL, LOG_ERR, "WebSocketWorker - Received Continuation Frame out of sequence"); SendClose(kCloseProtocolError, "Received Continuation Frame out of sequence"); return; } m_readFrame.payload.append(frame.payload); if (m_readFrame.fragmented && frame.finalFrame) { m_readFrame.finalFrame = true; frame = m_readFrame; // Fall through to appropriate handler for complete payload } else break; [[clang::fallthrough]]; case WebSocketFrame::kOpTextFrame: case WebSocketFrame::kOpBinaryFrame: HandleDataFrame(frame); break; case WebSocketFrame::kOpPing: SendPong(frame.payload); break; case WebSocketFrame::kOpPong: break; case WebSocketFrame::kOpClose: if (!frame.finalFrame) SendClose(kCloseProtocolError, "Control frames MUST NOT be fragmented"); else HandleCloseConnection(frame.payload); break; default: LOG(VB_GENERAL, LOG_ERR, "WebSocketWorker - Received Unknown Frame Type"); break; } frame.reset(); } }
void WebSocketFrameListenerChild::Close() { mService = nullptr; SendClose(); }