<commit_before><?php

namespace PHPFastCGI\FastCGIDaemon\ConnectionHandler;

use PHPFastCGI\FastCGIDaemon\DaemonInterface;
use PHPFastCGI\FastCGIDaemon\Connection\ConnectionInterface;
use PHPFastCGI\FastCGIDaemon\Exception\AbstractRequestException;
use PHPFastCGI\FastCGIDaemon\Exception\ConnectionException;
use PHPFastCGI\FastCGIDaemon\Exception\MultiplexingUnsupportedException;
use PHPFastCGI\FastCGIDaemon\Exception\ProtocolException;
use PHPFastCGI\FastCGIDaemon\Exception\UnknownRoleException;
use PHPFastCGI\FastCGIDaemon\Http\Request;

class SingleplexedResponderConnectionHandler implements
    SingleplexedConnectionHandlerInterface
{
    const STATE_READY_FOR_REQUEST  = 0;
    const STATE_READY_FOR_RESPONSE = 1;
    const STATE_DEAD               = 2;

    protected $connection;
    protected $state              = self::STATE_READY_FOR_REQUEST;
    protected $requestId          = null;
    protected $stdin              = '';
    protected $params             = array();
    protected $gotLastStdinRecord = false;
    protected $gotLastParamRecord = false;

    public function __construct(ConnectionInterface $connection)
    {
        $this->connection = $connection;
    }

    protected function ready()
    {
        return $this->gotLastStdinRecord && $this->gotLastParamRecord;
    }

    protected function createRequest()
    {
        $this->state = self::STATE_READY_FOR_RESPONSE;

        return new Request($this, $this->requestId, $this->params, $this->stdin);
    }

    protected function readRecord()
    {
        $headerData = $this->connection->read(8);

        $headerFormat = 'Cversion/Ctype/nrequestId/ncontentLength/' .
            'CpaddingLength/x';

        $record = unpack($headerFormat, $headerData);

        $record['contentData'] = $this->connection->read($record['contentLength']);
        $this->connection->read($record['paddingLength']);

        return $record;
    }

    protected function readBeginRequestRecord()
    {
        $record = $this->readRecord();

        if (DaemonInterface::FCGI_BEGIN_REQUEST !== $record['type']) {
            throw new ProtocolException('Expected begin request record');
        }

        $this->requestId = $record['requestId'];

        $contentFormat = 'nrole/Cflags/x5';

        $content = unpack($contentFormat, $record['contentData']);

        if (DaemonInterface::FCGI_KEEP_CONNECTION & $content['flags']) {
            throw new MultiplexingUnsupportedException;
        }

        if (DaemonInterface::FCGI_RESPONDER !== $content['role']) {
            throw new UnknownRoleException;
        }
    }

    protected function readNextRecord()
    {
        $record = $this->readRecord();

        if ($this->requestId !== $record['requestId']) {
            throw new ProtocolException('Received invalid request id');
        }

        switch ($record['type']) {
            case DaemonInterface::FCGI_PARAMS:
                if (0 === $record['contentLength']) {
                    $this->gotLastParamRecord = true;
                } else {
                    $initialBytes = unpack('C5', $record['contentData']);

                    $extendedLengthName  = $initialBytes[1] & 0x80;
                    $extendedLengthValue = $extendedLengthName ?
                        $initialBytes[2] & 0x80 : $initialBytes[5] & 0x80;

                    $structureFormat = (
                        ($extendedLengthName  ? 'N' : 'C') . 'nameLength/' .
                        ($extendedLengthValue ? 'N' : 'C') . 'valueLength'
                    );

                    $structure = unpack($structureFormat, $record['contentData']);

                    $skipLength = ($extendedLengthName ? 4 : 1) +
                        ($extendedLengthValue ? 4 : 1);

                    $contentFormat = (
                        'x' . $skipLength               . '/'     .<commit_msg>Fixed bug in handling of long length name & value pairs in param records<commit_after><?php

namespace PHPFastCGI\FastCGIDaemon\ConnectionHandler;

use PHPFastCGI\FastCGIDaemon\DaemonInterface;
use PHPFastCGI\FastCGIDaemon\Connection\ConnectionInterface;
use PHPFastCGI\FastCGIDaemon\Exception\AbstractRequestException;
use PHPFastCGI\FastCGIDaemon\Exception\ConnectionException;
use PHPFastCGI\FastCGIDaemon\Exception\MultiplexingUnsupportedException;
use PHPFastCGI\FastCGIDaemon\Exception\ProtocolException;
use PHPFastCGI\FastCGIDaemon\Exception\UnknownRoleException;
use PHPFastCGI\FastCGIDaemon\Http\Request;

class SingleplexedResponderConnectionHandler implements
    SingleplexedConnectionHandlerInterface
{
    const STATE_READY_FOR_REQUEST  = 0;
    const STATE_READY_FOR_RESPONSE = 1;
    const STATE_DEAD               = 2;

    protected $connection;
    protected $state              = self::STATE_READY_FOR_REQUEST;
    protected $requestId          = null;
    protected $stdin              = '';
    protected $params             = array();
    protected $gotLastStdinRecord = false;
    protected $gotLastParamRecord = false;

    public function __construct(ConnectionInterface $connection)
    {
        $this->connection = $connection;
    }

    protected function ready()
    {
        return $this->gotLastStdinRecord && $this->gotLastParamRecord;
    }

    protected function createRequest()
    {
        $this->state = self::STATE_READY_FOR_RESPONSE;

        return new Request($this, $this->requestId, $this->params, $this->stdin);
    }

    protected function readRecord()
    {
        $headerData = $this->connection->read(8);

        $headerFormat = 'Cversion/Ctype/nrequestId/ncontentLength/' .
            'CpaddingLength/x';

        $record = unpack($headerFormat, $headerData);

        $record['contentData'] = $this->connection->read($record['contentLength']);
        $this->connection->read($record['paddingLength']);

        return $record;
    }

    protected function readBeginRequestRecord()
    {
        $record = $this->readRecord();

        if (DaemonInterface::FCGI_BEGIN_REQUEST !== $record['type']) {
            throw new ProtocolException('Expected begin request record');
        }

        $this->requestId = $record['requestId'];

        $contentFormat = 'nrole/Cflags/x5';

        $content = unpack($contentFormat, $record['contentData']);

        if (DaemonInterface::FCGI_KEEP_CONNECTION & $content['flags']) {
            throw new MultiplexingUnsupportedException;
        }

        if (DaemonInterface::FCGI_RESPONDER !== $content['role']) {
            throw new UnknownRoleException;
        }
    }

    protected function readNextRecord()
    {
        $record = $this->readRecord();

        if ($this->requestId !== $record['requestId']) {
            throw new ProtocolException('Received invalid request id');
        }

        switch ($record['type']) {
            case DaemonInterface::FCGI_PARAMS:
                if (0 === $record['contentLength']) {
                    $this->gotLastParamRecord = true;
                } else {
                    $initialBytes = unpack('C5', $record['contentData']);

                    $extendedLengthName  = $initialBytes[1] & 0x80;
                    $extendedLengthValue = $extendedLengthName ?
                        $initialBytes[5] & 0x80 : $initialBytes[2] & 0x80;

                    $structureFormat = (
                        ($extendedLengthName  ? 'N' : 'C') . 'nameLength/' .
                        ($extendedLengthValue ? 'N' : 'C') . 'valueLength'
                    );

                    $structure = unpack($structureFormat, $record['contentData']);

                    if ($extendedLengthName) {
                        $structure['nameLength'] &= 0x7FFFFFFF;
                    }

                    if ($extendedLengthValue) {
                        $structure['valueLength'] &= 0x7FFFFFFF;
                    }

                    $skipLength = ($extendedLengthName ? 4 : 1) +
                        ($extendedLengthValue ? 4 : 1);

                    $contentFormat = (
                        'x' . $skipLength               . '/'     .
{'fraction_non_alphanumeric': 0.11303701869506004, 'fraction_numerical': 0.00619041723412158, 'mean_word_length': 2.310655737704918, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 39, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 2, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '937215', 'n_tokens_mistral': 2280, 'n_tokens_neox': 2106, 'n_words': 382}