Exemplo n.º 1
0
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;
}
Exemplo n.º 4
0
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;
}
Exemplo n.º 6
0
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;
  }
}
Exemplo n.º 8
0
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);
}
Exemplo n.º 9
0
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;
}
Exemplo n.º 10
0
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();
}