This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | |||
3 | namespace Http\Client\Socket; |
||
4 | |||
5 | use Http\Client\HttpClient; |
||
6 | use Http\Client\Socket\Exception\ConnectionException; |
||
7 | use Http\Client\Socket\Exception\InvalidRequestException; |
||
8 | use Http\Client\Socket\Exception\SSLConnectionException; |
||
9 | use Http\Client\Socket\Exception\TimeoutException; |
||
10 | use Psr\Http\Message\RequestInterface; |
||
11 | use Psr\Http\Message\ResponseInterface; |
||
12 | use Symfony\Component\OptionsResolver\Options; |
||
13 | use Symfony\Component\OptionsResolver\OptionsResolver; |
||
14 | |||
15 | /** |
||
16 | * Socket Http Client. |
||
17 | * |
||
18 | * Use stream and socket capabilities of the core of PHP to send HTTP requests |
||
19 | * |
||
20 | * @author Joel Wurtz <[email protected]> |
||
21 | */ |
||
22 | class Client implements HttpClient |
||
23 | { |
||
24 | use RequestWriter; |
||
25 | use ResponseReader; |
||
26 | |||
27 | private $config = [ |
||
28 | 'remote_socket' => null, |
||
29 | 'timeout' => null, |
||
30 | 'stream_context_options' => [], |
||
31 | 'stream_context_param' => [], |
||
32 | 'ssl' => null, |
||
33 | 'write_buffer_size' => 8192, |
||
34 | 'ssl_method' => STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT, |
||
35 | ]; |
||
36 | |||
37 | /** |
||
38 | * Constructor. |
||
39 | * |
||
40 | * @param array $config { |
||
41 | * |
||
42 | * @var string $remote_socket Remote entrypoint (can be a tcp or unix domain address) |
||
43 | * @var int $timeout Timeout before canceling request |
||
44 | * @var array $stream_context_options Context options as defined in the PHP documentation |
||
45 | * @var array $stream_context_param Context params as defined in the PHP documentation |
||
46 | * @var bool $ssl Use ssl, default to scheme from request, false if not present |
||
47 | * @var int $write_buffer_size Buffer when writing the request body, defaults to 8192 |
||
48 | * @var int $ssl_method Crypto method for ssl/tls, see PHP doc, defaults to STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT |
||
49 | * } |
||
50 | */ |
||
51 | 64 | public function __construct($config1 = [], $config2 = null, array $config = []) |
|
0 ignored issues
–
show
|
|||
52 | { |
||
53 | 64 | if (\is_array($config1)) { |
|
54 | 64 | $this->config = $this->configure($config1); |
|
55 | |||
56 | 64 | return; |
|
57 | } |
||
58 | |||
59 | @trigger_error('Passing a Psr\Http\Message\ResponseFactoryInterface and a Psr\Http\Message\StreamFactoryInterface to SocketClient is deprecated, and will be removed in 3.0, you should only pass config options.', E_USER_DEPRECATED); |
||
0 ignored issues
–
show
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.
If you suppress an error, we recommend checking for the error condition explicitly: // For example instead of
@mkdir($dir);
// Better use
if (@mkdir($dir) === false) {
throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
![]() |
|||
60 | |||
61 | $this->config = $this->configure($config); |
||
62 | } |
||
63 | |||
64 | /** |
||
65 | * {@inheritdoc} |
||
66 | */ |
||
67 | 64 | public function sendRequest(RequestInterface $request): ResponseInterface |
|
68 | { |
||
69 | 64 | $remote = $this->config['remote_socket']; |
|
70 | 64 | $useSsl = $this->config['ssl']; |
|
71 | |||
72 | 64 | if (!$request->hasHeader('Connection')) { |
|
73 | 13 | $request = $request->withHeader('Connection', 'close'); |
|
74 | } |
||
75 | |||
76 | 64 | if (null === $remote) { |
|
77 | 55 | $remote = $this->determineRemoteFromRequest($request); |
|
78 | } |
||
79 | |||
80 | 63 | if (null === $useSsl) { |
|
81 | 58 | $useSsl = ('https' === $request->getUri()->getScheme()); |
|
82 | } |
||
83 | |||
84 | 63 | $socket = $this->createSocket($request, $remote, $useSsl); |
|
85 | |||
86 | try { |
||
87 | 59 | $this->writeRequest($socket, $request, $this->config['write_buffer_size']); |
|
88 | 59 | $response = $this->readResponse($request, $socket); |
|
89 | 1 | } catch (\Exception $e) { |
|
90 | 1 | $this->closeSocket($socket); |
|
91 | |||
92 | 1 | throw $e; |
|
93 | } |
||
94 | |||
95 | 58 | return $response; |
|
96 | } |
||
97 | |||
98 | /** |
||
99 | * Create the socket to write request and read response on it. |
||
100 | * |
||
101 | * @param RequestInterface $request Request for |
||
102 | * @param string $remote Entrypoint for the connection |
||
103 | * @param bool $useSsl Whether to use ssl or not |
||
104 | * |
||
105 | * @throws ConnectionException|SSLConnectionException When the connection fail |
||
106 | * |
||
107 | * @return resource Socket resource |
||
108 | */ |
||
109 | 63 | protected function createSocket(RequestInterface $request, string $remote, bool $useSsl) |
|
110 | { |
||
111 | 63 | $errNo = null; |
|
112 | 63 | $errMsg = null; |
|
113 | 63 | $socket = @stream_socket_client($remote, $errNo, $errMsg, floor($this->config['timeout'] / 1000), STREAM_CLIENT_CONNECT, $this->config['stream_context']); |
|
114 | |||
115 | 63 | if (false === $socket) { |
|
116 | 3 | if (110 === $errNo) { |
|
117 | 1 | throw new TimeoutException($errMsg, $request); |
|
118 | } |
||
119 | |||
120 | 2 | throw new ConnectionException($errMsg, $request); |
|
121 | } |
||
122 | |||
123 | 60 | stream_set_timeout($socket, floor($this->config['timeout'] / 1000), $this->config['timeout'] % 1000); |
|
124 | |||
125 | 60 | if ($useSsl && false === @stream_socket_enable_crypto($socket, true, $this->config['ssl_method'])) { |
|
126 | 1 | throw new SSLConnectionException(sprintf('Cannot enable tls: %s', error_get_last()['message']), $request); |
|
127 | } |
||
128 | |||
129 | 59 | return $socket; |
|
130 | } |
||
131 | |||
132 | /** |
||
133 | * Close the socket, used when having an error. |
||
134 | * |
||
135 | * @param resource $socket |
||
136 | */ |
||
137 | 1 | protected function closeSocket($socket) |
|
138 | { |
||
139 | 1 | fclose($socket); |
|
140 | 1 | } |
|
141 | |||
142 | /** |
||
143 | * Return configuration for the socket client. |
||
144 | * |
||
145 | * @param array $config Configuration from user |
||
146 | * |
||
147 | * @return array Configuration resolved |
||
148 | */ |
||
149 | 64 | protected function configure(array $config = []) |
|
150 | { |
||
151 | 64 | $resolver = new OptionsResolver(); |
|
152 | 64 | $resolver->setDefaults($this->config); |
|
153 | $resolver->setDefault('stream_context', function (Options $options) { |
||
154 | 64 | return stream_context_create($options['stream_context_options'], $options['stream_context_param']); |
|
155 | 64 | }); |
|
156 | |||
157 | 64 | $resolver->setDefault('timeout', ini_get('default_socket_timeout') * 1000); |
|
158 | |||
159 | 64 | $resolver->setAllowedTypes('stream_context_options', 'array'); |
|
160 | 64 | $resolver->setAllowedTypes('stream_context_param', 'array'); |
|
161 | 64 | $resolver->setAllowedTypes('stream_context', 'resource'); |
|
162 | 64 | $resolver->setAllowedTypes('ssl', ['bool', 'null']); |
|
163 | |||
164 | 64 | return $resolver->resolve($config); |
|
165 | } |
||
166 | |||
167 | /** |
||
168 | * Return remote socket from the request. |
||
169 | * |
||
170 | * @throws InvalidRequestException When no remote can be determined from the request |
||
171 | * |
||
172 | * @return string |
||
173 | */ |
||
174 | 55 | private function determineRemoteFromRequest(RequestInterface $request) |
|
175 | { |
||
176 | 55 | if (!$request->hasHeader('Host') && '' === $request->getUri()->getHost()) { |
|
177 | 1 | throw new InvalidRequestException('Remote is not defined and we cannot determine a connection endpoint for this request (no Host header)', $request); |
|
178 | } |
||
179 | |||
180 | 54 | $host = $request->getUri()->getHost(); |
|
181 | 54 | $port = $request->getUri()->getPort() ?: ('https' === $request->getUri()->getScheme() ? 443 : 80); |
|
182 | 54 | $endpoint = sprintf('%s:%s', $host, $port); |
|
183 | |||
184 | // If use the host header if present for the endpoint |
||
185 | 54 | if (empty($host) && $request->hasHeader('Host')) { |
|
186 | 1 | $endpoint = $request->getHeaderLine('Host'); |
|
187 | } |
||
188 | |||
189 | 54 | return sprintf('tcp://%s', $endpoint); |
|
190 | } |
||
191 | } |
||
192 |
This check looks from parameters that have been defined for a function or method, but which are not used in the method body.