Amp\Artax\Parser::parse PHP Method

parse() public method

public parse ( $data = null )
    public function parse($data = null)
    {
        if ($data !== null) {
            $this->buffer .= $data;
        }
        if ($this->buffer == '') {
            goto more_data_needed;
        }
        switch ($this->state) {
            case self::AWAITING_HEADERS:
                goto awaiting_headers;
            case self::BODY_IDENTITY:
                goto body_identity;
            case self::BODY_IDENTITY_EOF:
                goto body_identity_eof;
            case self::BODY_CHUNKS:
                goto body_chunks;
            case self::TRAILERS_START:
                goto trailers_start;
            case self::TRAILERS:
                goto trailers;
        }
        awaiting_headers:
        if (!($startLineAndHeaders = $this->shiftHeadersFromMessageBuffer())) {
            goto more_data_needed;
        } else {
            goto start_line;
        }
        start_line:
        $startLineEndPos = strpos($startLineAndHeaders, "\n");
        $startLine = substr($startLineAndHeaders, 0, $startLineEndPos);
        $rawHeaders = substr($startLineAndHeaders, $startLineEndPos + 1);
        $this->traceBuffer = $startLineAndHeaders;
        if ($this->mode === self::MODE_REQUEST) {
            goto request_line_and_headers;
        } else {
            goto status_line_and_headers;
        }
        request_line_and_headers:
        $parts = explode(' ', trim($startLine));
        if (isset($parts[0]) && ($method = trim($parts[0]))) {
            $this->requestMethod = $method;
        } else {
            throw new ParseException($this->getParsedMessageArray(), $msg = 'Invalid request line', $code = 400, $previousException = null);
        }
        if (isset($parts[1]) && ($uri = trim($parts[1]))) {
            $this->requestUri = $uri;
        } else {
            throw new ParseException($this->getParsedMessageArray(), $msg = 'Invalid request line', $code = 400, $previousException = null);
        }
        if (isset($parts[2]) && ($protocol = str_ireplace('HTTP/', '', trim($parts[2])))) {
            $this->protocol = $protocol;
        } else {
            throw new ParseException($this->getParsedMessageArray(), $msg = 'Invalid request line', $code = 400, $previousException = null);
        }
        if (!($protocol === '1.0' || '1.1' === $protocol)) {
            throw new ParseException($this->getParsedMessageArray(), $msg = 'Protocol not supported: {$protocol}', $code = 505, $previousException = null);
        }
        if ($rawHeaders) {
            $this->headers = $this->parseHeadersFromRaw($rawHeaders);
        }
        goto transition_from_request_headers_to_body;
        status_line_and_headers:
        if (preg_match(self::STATUS_LINE_PATTERN, $startLine, $m)) {
            $this->protocol = $m['protocol'];
            $this->responseCode = $m['status'];
            $this->responseReason = trim($m['reason']);
        } else {
            throw new ParseException($this->getParsedMessageArray(), $msg = 'Invalid status line', $code = 400, $previousException = null);
        }
        if ($rawHeaders) {
            $this->headers = $this->parseHeadersFromRaw($rawHeaders);
        }
        goto transition_from_response_headers_to_body;
        transition_from_request_headers_to_body:
        if ($this->requestMethod == 'HEAD' || $this->requestMethod == 'TRACE' || $this->requestMethod == 'OPTIONS') {
            goto complete;
        } elseif ($this->parseFlowHeaders['TRANSFER-ENCODING']) {
            $this->state = self::BODY_CHUNKS;
            goto before_body;
        } elseif ($this->parseFlowHeaders['CONTENT-LENGTH']) {
            $this->remainingBodyBytes = $this->parseFlowHeaders['CONTENT-LENGTH'];
            $this->state = self::BODY_IDENTITY;
            goto before_body;
        } else {
            goto complete;
        }
        transition_from_response_headers_to_body:
        $requestMethod = array_shift($this->responseMethodMatch);
        if ($this->responseCode == 204 || $this->responseCode == 304 || $this->responseCode < 200 || $requestMethod === 'HEAD' || $requestMethod === 'CONNECT') {
            goto complete;
        } elseif ($this->parseFlowHeaders['TRANSFER-ENCODING']) {
            $this->state = self::BODY_CHUNKS;
            goto before_body;
        } elseif ($this->parseFlowHeaders['CONTENT-LENGTH'] === null) {
            $this->state = self::BODY_IDENTITY_EOF;
            goto before_body;
        } elseif ($this->parseFlowHeaders['CONTENT-LENGTH'] > 0) {
            $this->remainingBodyBytes = $this->parseFlowHeaders['CONTENT-LENGTH'];
            $this->state = self::BODY_IDENTITY;
            goto before_body;
        } else {
            goto complete;
        }
        before_body:
        if ($this->remainingBodyBytes === 0) {
            goto complete;
        }
        $uri = 'php://temp/maxmemory:' . $this->bodySwapSize;
        $this->body = fopen($uri, 'r+');
        if ($this->returnBeforeEntity) {
            $parsedMsgArr = $this->getParsedMessageArray();
            $parsedMsgArr['headersOnly'] = true;
            return $parsedMsgArr;
        }
        switch ($this->state) {
            case self::BODY_IDENTITY:
                goto body_identity;
            case self::BODY_IDENTITY_EOF:
                goto body_identity_eof;
            case self::BODY_CHUNKS:
                goto body_chunks;
            default:
                throw new \RuntimeException('Unexpected parse state encountered');
        }
        body_identity:
        $bufferDataSize = strlen($this->buffer);
        if ($bufferDataSize < $this->remainingBodyBytes) {
            $this->addToBody($this->buffer);
            $this->buffer = null;
            $this->remainingBodyBytes -= $bufferDataSize;
            goto more_data_needed;
        } elseif ($bufferDataSize == $this->remainingBodyBytes) {
            $this->addToBody($this->buffer);
            $this->buffer = null;
            $this->remainingBodyBytes = 0;
            goto complete;
        } else {
            $bodyData = substr($this->buffer, 0, $this->remainingBodyBytes);
            $this->addToBody($bodyData);
            $this->buffer = substr($this->buffer, $this->remainingBodyBytes);
            $this->remainingBodyBytes = 0;
            goto complete;
        }
        body_identity_eof:
        $this->addToBody($this->buffer);
        $this->buffer = '';
        goto more_data_needed;
        body_chunks:
        if ($this->dechunk()) {
            $this->state = self::TRAILERS_START;
            goto trailers_start;
        } else {
            goto more_data_needed;
        }
        trailers_start:
        $firstTwoBytes = substr($this->buffer, 0, 2);
        if ($firstTwoBytes == "" || $firstTwoBytes === "\r") {
            goto more_data_needed;
        } elseif ($firstTwoBytes === "\r\n") {
            $this->buffer = substr($this->buffer, 2);
            goto complete;
        } else {
            $this->state = self::TRAILERS;
            goto trailers;
        }
        trailers:
        if ($trailers = $this->shiftHeadersFromMessageBuffer()) {
            $this->parseTrailers($trailers);
            goto complete;
        } else {
            goto more_data_needed;
        }
        complete:
        $parsedMsgArr = $this->getParsedMessageArray();
        $parsedMsgArr['headersOnly'] = false;
        $this->state = self::AWAITING_HEADERS;
        $this->traceBuffer = null;
        $this->headers = [];
        $this->body = null;
        $this->bodyBytesConsumed = 0;
        $this->remainingBodyBytes = null;
        $this->chunkLenRemaining = null;
        $this->protocol = null;
        $this->requestUri = null;
        $this->requestMethod = null;
        $this->responseCode = null;
        $this->responseReason = null;
        $this->parseFlowHeaders = ['TRANSFER-ENCODING' => null, 'CONTENT-LENGTH' => null];
        return $parsedMsgArr;
        more_data_needed:
        return null;
    }

Usage Example

Example #1
0
 /**
  * @dataProvider provideParseExpectations
  */
 public function testIncrementalParse($msg, $method, $uri, $protocol, $headers, $body)
 {
     $msgParser = new Parser();
     $byteIncrement = 1;
     $msgLen = strlen($msg);
     for ($i = 0; $i < $msgLen; $i += $byteIncrement) {
         $msgPart = $msg[$i];
         $parsedRequestArr = $msgParser->parse($msgPart);
         if (NULL !== $parsedRequestArr) {
             break;
         }
     }
     $actualBody = $parsedRequestArr['body'] ? stream_get_contents($parsedRequestArr['body']) : $parsedRequestArr['body'];
     $this->assertEquals($method, $parsedRequestArr['method']);
     $this->assertEquals($uri, $parsedRequestArr['uri']);
     $this->assertEquals($protocol, $parsedRequestArr['protocol']);
     $this->assertEquals($headers, $parsedRequestArr['headers']);
     $this->assertEquals($body, $actualBody);
 }