Skip to content

Commit b22d695

Browse files
committed
1 parent 4c0bd4b commit b22d695

File tree

3 files changed

+163
-0
lines changed

3 files changed

+163
-0
lines changed

src/Psr18/StreamClient.php

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
<?php
2+
/**
3+
* Class StreamClient
4+
*
5+
* @filesource StreamClient.php
6+
* @created 23.02.2019
7+
* @package chillerlan\HTTP\Psr18
8+
* @author smiley <smiley@chillerlan.net>
9+
* @copyright 2019 smiley
10+
* @license MIT
11+
*/
12+
13+
namespace chillerlan\HTTP\Psr18;
14+
15+
use Psr\Http\Message\{RequestInterface, ResponseInterface};
16+
17+
class StreamClient extends HTTPClientAbstract{
18+
19+
/**
20+
* @todo
21+
*
22+
* @inheritdoc
23+
*/
24+
public function sendRequest(RequestInterface $request):ResponseInterface{
25+
$uri = $request->getUri();
26+
$method = $request->getMethod();
27+
$headers = $this->getRequestHeaders($request);
28+
29+
$body = in_array($method, ['DELETE', 'PATCH', 'POST', 'PUT'], true)
30+
? $request->getBody()->getContents()
31+
: null;
32+
33+
$context = stream_context_create([
34+
'http' => [
35+
'method' => $method,
36+
'header' => $headers,
37+
'content' => $body,
38+
'protocol_version' => '1.1',
39+
'user_agent' => $this->options->user_agent,
40+
'max_redirects' => 0,
41+
'timeout' => 5,
42+
],
43+
'ssl' => [
44+
'cafile' => $this->options->ca_info,
45+
'verify_peer' => $this->options->ssl_verifypeer,
46+
'verify_depth' => 3,
47+
'peer_name' => $uri->getHost(),
48+
'ciphers' => 'HIGH:!SSLv2:!SSLv3',
49+
'disable_compression' => true,
50+
],
51+
]);
52+
53+
$requestUri = (string)$uri->withFragment('');
54+
55+
set_error_handler(function ($severity, $msg, $file, $line){
56+
throw new \ErrorException($msg, 0, $severity, $file, $line);
57+
});
58+
59+
try{
60+
$responseBody = file_get_contents($requestUri, false, $context);
61+
$responseHeaders = $this->parseResponseHeaders(get_headers($requestUri, 1, $context));
62+
}catch(\Exception $e){
63+
throw new ClientException($e->getMessage(), $e->getCode());
64+
}
65+
66+
restore_error_handler();
67+
68+
$response = $this->responseFactory
69+
->createResponse($responseHeaders['statuscode'], $responseHeaders['statustext'])
70+
->withProtocolVersion($responseHeaders['httpversion'])
71+
;
72+
73+
$response->getBody()->write($responseBody);
74+
$response->getBody()->rewind();
75+
76+
return $response;
77+
}
78+
79+
/**
80+
* @param \Psr\Http\Message\RequestInterface $request
81+
*
82+
* @return array
83+
*/
84+
protected function getRequestHeaders(RequestInterface $request):array{
85+
$headers = [];
86+
87+
foreach($request->getHeaders() as $name => $values){
88+
$name = strtolower($name);
89+
90+
foreach($values as $value){
91+
$value = (string)$value;
92+
93+
// cURL requires a special format for empty headers.
94+
// See https://github.com/guzzle/guzzle/issues/1882 for more details.
95+
$headers[] = $value === '' ? $name.';' : $name.': '.$value;
96+
}
97+
}
98+
99+
return $headers;
100+
}
101+
102+
/**
103+
* @param array $headers
104+
*
105+
* @return array
106+
*/
107+
protected function parseResponseHeaders(array $headers):array{
108+
$h = [];
109+
110+
foreach($headers as $k => $v){
111+
112+
if($k === 0 && substr($v, 0, 4) === 'HTTP'){
113+
$status = explode(' ', $v, 3);
114+
115+
$h['httpversion'] = explode('/', $status[0], 2)[1];
116+
$h['statuscode'] = intval($status[1]);
117+
$h['statustext'] = trim($status[2]);
118+
119+
continue;
120+
}
121+
122+
$h[strtolower($k)] = $v;
123+
124+
}
125+
126+
return $h;
127+
}
128+
129+
}

tests/Psr18/HTTPClientTestAbstract.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,5 +103,11 @@ public function testRequest(string $method, array $extra_headers){
103103

104104
}
105105

106+
/**
107+
* @expectedException \Psr\Http\Client\ClientExceptionInterface
108+
*/
109+
public function testNetworkError(){
110+
$this->http->sendRequest(new Request(Request::METHOD_GET, 'http://foo'));
111+
}
106112

107113
}

tests/Psr18/StreamClientTest.php

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php
2+
/**
3+
* Class StreamClientTest
4+
*
5+
* @filesource StreamClientTest.php
6+
* @created 23.02.2019
7+
* @package chillerlan\HTTPTest\Psr18
8+
* @author smiley <smiley@chillerlan.net>
9+
* @copyright 2019 smiley
10+
* @license MIT
11+
*/
12+
13+
namespace chillerlan\HTTPTest\Psr18;
14+
15+
use chillerlan\HTTP\{HTTPOptions, Psr18\StreamClient};
16+
17+
class StreamClientTest extends HTTPClientTestAbstract{
18+
19+
protected function setUp(){
20+
$options = new HTTPOptions([
21+
'ca_info' => __DIR__.'/../cacert.pem',
22+
'user_agent' => $this::USER_AGENT,
23+
]);
24+
25+
$this->http = new StreamClient($options);
26+
}
27+
28+
}

0 commit comments

Comments
 (0)