Skip to content
This repository was archived by the owner on Jan 6, 2024. It is now read-only.

Commit 9a04a72

Browse files
committed
Make zend http adapter work with socket and curl adapter
1 parent 5c42339 commit 9a04a72

File tree

4 files changed

+143
-3
lines changed

4 files changed

+143
-3
lines changed

src/Client.php

Lines changed: 90 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ public function __construct(ZendClient $client = null, ResponseFactory $response
3535
*/
3636
public function sendRequest(RequestInterface $request)
3737
{
38+
$request = $this->sanitizeRequest($request);
3839
$headers = new Headers();
3940

4041
foreach ($request->getHeaders() as $key => $value) {
@@ -44,10 +45,25 @@ public function sendRequest(RequestInterface $request)
4445
$zendRequest = new Request();
4546
$zendRequest->setMethod($request->getMethod());
4647
$zendRequest->setUri((string) $request->getUri());
47-
$zendRequest->setVersion($request->getProtocolVersion());
4848
$zendRequest->setHeaders($headers);
4949
$zendRequest->setContent($request->getBody()->getContents());
5050

51+
$options = [
52+
'httpversion' => $request->getProtocolVersion(),
53+
];
54+
55+
if (extension_loaded('curl')) {
56+
$options['curloptions'] = [
57+
CURLOPT_HTTP_VERSION => $this->getProtocolVersion($request->getProtocolVersion()),
58+
];
59+
}
60+
61+
$this->client->setOptions($options);
62+
63+
if ($this->client->getAdapter() instanceof ZendClient\Adapter\Curl && $request->getMethod()) {
64+
$request = $request->withHeader('Content-Length', '0');
65+
}
66+
5167
try {
5268
$zendResponse = $this->client->send($zendRequest);
5369
} catch (RuntimeException $exception) {
@@ -62,4 +78,77 @@ public function sendRequest(RequestInterface $request)
6278
$zendResponse->getVersion()
6379
);
6480
}
81+
82+
private function sanitizeRequest(RequestInterface $request)
83+
{
84+
$request = $this->sanitizeWithTrace($request);
85+
$request = $this->sanitizeWithCurl($request);
86+
87+
return $request;
88+
}
89+
90+
/**
91+
* Zend request remove the body if it's a trace but does not rewrite the content length header,
92+
* This can lead to error from the server has it can expect a specific content length, but don't have
93+
* a body, so we set content-length to 0 to avoid bad reading from the server.
94+
*
95+
* @param RequestInterface $request
96+
*
97+
* @return RequestInterface|static
98+
*/
99+
private function sanitizeWithTrace(RequestInterface $request)
100+
{
101+
if ($request->getMethod() === 'TRACE') {
102+
$request = $request->withHeader('Content-Length', '0');
103+
}
104+
105+
return $request;
106+
}
107+
108+
/**
109+
* Get specific curl options for Zend Curl Adapter
110+
*
111+
* @param RequestInterface $request
112+
*
113+
* @return RequestInterface|static
114+
*/
115+
private function sanitizeWithCurl(RequestInterface $request)
116+
{
117+
if ($this->client->getAdapter() instanceof ZendClient\Adapter\Curl && !in_array($request->getMethod(), [
118+
'POST',
119+
'PUT',
120+
'PATCH'
121+
], true)) {
122+
123+
$request = $request->withHeader('Content-Length', '0');
124+
}
125+
126+
return $request;
127+
}
128+
129+
/**
130+
* Return cURL constant for specified HTTP version
131+
*
132+
* @param string $requestVersion
133+
*
134+
* @throws \UnexpectedValueException if unsupported version requested
135+
*
136+
* @return int
137+
*/
138+
private function getProtocolVersion($requestVersion)
139+
{
140+
switch ($requestVersion) {
141+
case '1.0':
142+
return CURL_HTTP_VERSION_1_0;
143+
case '1.1':
144+
return CURL_HTTP_VERSION_1_1;
145+
case '2.0':
146+
if (defined('CURL_HTTP_VERSION_2_0')) {
147+
return CURL_HTTP_VERSION_2_0;
148+
}
149+
throw new \UnexpectedValueException('libcurl 7.33 needed for HTTP 2.0 support');
150+
}
151+
152+
return CURL_HTTP_VERSION_NONE;
153+
}
65154
}

tests/ClientTest.php

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,27 @@
44

55
use Http\Adapter\Zend\Client;
66
use Http\Client\Tests\HttpClientTest;
7+
use Zend\Http\Client as ZendClient;
78

8-
class ClientTest extends HttpClientTest
9+
abstract class ClientTest extends HttpClientTest
910
{
1011
protected function createHttpAdapter()
1112
{
12-
return new Client();
13+
return new Client(new ZendClient(null, [
14+
'adapter' => $this->getZendAdapter(),
15+
'maxredirects' => 0,
16+
'storeresponse' => false,
17+
]));
18+
}
19+
20+
abstract protected function getZendAdapter();
21+
22+
protected function shouldBeSkip($method, $uri, array $headers, $body)
23+
{
24+
if ($method === 'TRACE' && strlen($body) > 0) {
25+
return "Zend Http Adapter does not work well with TRACE method and a BODY";
26+
}
27+
28+
return false;
1329
}
1430
}

tests/CurlClientTest.php

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?php
2+
3+
namespace Http\Adapter\Zend\Tests;
4+
5+
use Zend\Http\Client\Adapter\Curl;
6+
7+
class CurlClientTest extends ClientTest
8+
{
9+
protected function getZendAdapter()
10+
{
11+
return Curl::class;
12+
}
13+
14+
protected function shouldBeSkip($method, $uri, array $headers, $body)
15+
{
16+
if (strlen($body) !== 0 && !in_array($method, ['POST', 'PUT', 'PATCH'], true)) {
17+
return "Zend Curl Adapter does not support body in other method than POST, PUT or PATCH";
18+
}
19+
20+
return parent::shouldBeSkip($method, $uri, $headers, $body);
21+
}
22+
}

tests/SocketClientTest.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?php
2+
3+
namespace Http\Adapter\Zend\Tests;
4+
5+
use Zend\Http\Client\Adapter\Socket;
6+
7+
class SocketClientTest extends ClientTest
8+
{
9+
protected function getZendAdapter()
10+
{
11+
return Socket::class;
12+
}
13+
}

0 commit comments

Comments
 (0)