1<?php
2namespace GuzzleHttp\Handler;
3
4use GuzzleHttp\Psr7\Response;
5use Psr\Http\Message\RequestInterface;
6use Psr\Http\Message\ResponseInterface;
7use Psr\Http\Message\StreamInterface;
8
9/**
10 * Represents a cURL easy handle and the data it populates.
11 *
12 * @internal
13 */
14final class EasyHandle
15{
16    /** @var resource cURL resource */
17    public $handle;
18
19    /** @var StreamInterface Where data is being written */
20    public $sink;
21
22    /** @var array Received HTTP headers so far */
23    public $headers = [];
24
25    /** @var ResponseInterface Received response (if any) */
26    public $response;
27
28    /** @var RequestInterface Request being sent */
29    public $request;
30
31    /** @var array Request options */
32    public $options = [];
33
34    /** @var int cURL error number (if any) */
35    public $errno = 0;
36
37    /** @var \Exception Exception during on_headers (if any) */
38    public $onHeadersException;
39
40    /**
41     * Attach a response to the easy handle based on the received headers.
42     *
43     * @throws \RuntimeException if no headers have been received.
44     */
45    public function createResponse()
46    {
47        if (empty($this->headers)) {
48            throw new \RuntimeException('No headers have been received');
49        }
50
51        // HTTP-version SP status-code SP reason-phrase
52        $startLine = explode(' ', array_shift($this->headers), 3);
53        $headers = \GuzzleHttp\headers_from_lines($this->headers);
54        $normalizedKeys = \GuzzleHttp\normalize_header_keys($headers);
55
56        if (!empty($this->options['decode_content'])
57            && isset($normalizedKeys['content-encoding'])
58        ) {
59            $headers['x-encoded-content-encoding']
60                = $headers[$normalizedKeys['content-encoding']];
61            unset($headers[$normalizedKeys['content-encoding']]);
62            if (isset($normalizedKeys['content-length'])) {
63                $headers['x-encoded-content-length']
64                    = $headers[$normalizedKeys['content-length']];
65
66                $bodyLength = (int) $this->sink->getSize();
67                if ($bodyLength) {
68                    $headers[$normalizedKeys['content-length']] = $bodyLength;
69                } else {
70                    unset($headers[$normalizedKeys['content-length']]);
71                }
72            }
73        }
74
75        // Attach a response to the easy handle with the parsed headers.
76        $this->response = new Response(
77            $startLine[1],
78            $headers,
79            $this->sink,
80            substr($startLine[0], 5),
81            isset($startLine[2]) ? (string) $startLine[2] : null
82        );
83    }
84
85    public function __get($name)
86    {
87        $msg = $name === 'handle'
88            ? 'The EasyHandle has been released'
89            : 'Invalid property: ' . $name;
90        throw new \BadMethodCallException($msg);
91    }
92}
93