Skip to content

Commit f0b7e93

Browse files
committed
Use egeloen/http-adapter for HTTP lib abstraction
1 parent 9073dc9 commit f0b7e93

File tree

7 files changed

+446
-382
lines changed

7 files changed

+446
-382
lines changed

composer.json

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,17 @@
2121
}
2222
],
2323
"require": {
24-
"php": ">=5.3.3",
25-
"guzzle/http": "3.*",
26-
"symfony/event-dispatcher": "~2.3"
24+
"php": ">=5.4.8",
25+
"symfony/event-dispatcher": "~2.3",
26+
"symfony/options-resolver": "~2.3",
27+
"egeloen/http-adapter": "0.7.x-dev"
2728
},
2829
"require-dev": {
2930
"guzzle/plugin-mock": "*",
3031
"mockery/mockery": "*",
3132
"monolog/monolog": "*",
32-
"symfony/process": "~2.3"
33+
"symfony/process": "~2.3",
34+
"symfony/http-kernel": "~2.3"
3335
},
3436
"suggest": {
3537
"monolog/monolog": "For logging issues while invalidating"
@@ -42,7 +44,7 @@
4244
},
4345
"extra": {
4446
"branch-alias": {
45-
"dev-master": "1.1.x-dev"
47+
"dev-master": "1.3.x-dev"
4648
}
4749
}
4850
}

src/Exception/ExceptionCollection.php

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,16 @@
1515
* A collection of exceptions that might occur during the flush operation of a
1616
* ProxyClientInterface implementation
1717
*/
18-
class ExceptionCollection extends \Exception implements \IteratorAggregate, \Countable, HttpCacheExceptionInterface
18+
class ExceptionCollection extends \Exception implements \IteratorAggregate, \Countable, HttpCacheExceptionInterface
1919
{
2020
private $exceptions = array();
21+
22+
public function __construct(array $exceptions = array())
23+
{
24+
foreach ($exceptions as $exception) {
25+
$this->add($exception);
26+
}
27+
}
2128

2229
/**
2330
* Add an exception to the collection

src/ProxyClient/AbstractProxyClient.php

Lines changed: 43 additions & 232 deletions
Original file line numberDiff line numberDiff line change
@@ -12,43 +12,33 @@
1212
namespace FOS\HttpCache\ProxyClient;
1313

1414
use FOS\HttpCache\Exception\ExceptionCollection;
15-
use FOS\HttpCache\Exception\InvalidUrlException;
16-
use FOS\HttpCache\Exception\ProxyResponseException;
1715
use FOS\HttpCache\Exception\ProxyUnreachableException;
18-
use Guzzle\Http\Client;
19-
use Guzzle\Http\ClientInterface;
20-
use Guzzle\Http\Exception\CurlException;
21-
use Guzzle\Common\Exception\ExceptionCollection as GuzzleExceptionCollection;
22-
use Guzzle\Http\Exception\RequestException;
23-
use Guzzle\Http\Message\RequestInterface;
16+
use FOS\HttpCache\ProxyClient\Request\InvalidationRequest;
17+
use FOS\HttpCache\ProxyClient\Request\RequestQueue;
18+
use Ivory\HttpAdapter\HttpAdapterFactory;
19+
use Ivory\HttpAdapter\HttpAdapterInterface;
20+
use Ivory\HttpAdapter\MultiHttpAdapterException;
2421

2522
/**
26-
* Guzzle-based abstract caching proxy client
23+
* Abstract caching proxy client
2724
*
2825
* @author David de Boer <[email protected]>
2926
*/
3027
abstract class AbstractProxyClient implements ProxyClientInterface
3128
{
32-
/**
33-
* IP addresses/hostnames of all caching proxy servers
34-
*
35-
* @var array
36-
*/
37-
private $servers;
38-
3929
/**
4030
* HTTP client
4131
*
42-
* @var ClientInterface
32+
* @var HttpAdapterInterface
4333
*/
44-
private $client;
34+
private $httpAdapter;
4535

4636
/**
4737
* Request queue
4838
*
49-
* @var array|RequestInterface[]
39+
* @var RequestQueue
5040
*/
51-
private $queue;
41+
protected $queue;
5242

5343
/**
5444
* Constructor
@@ -61,238 +51,59 @@ abstract class AbstractProxyClient implements ProxyClientInterface
6151
* requests (optional). This is required if
6252
* you purge and refresh paths instead of
6353
* absolute URLs.
64-
* @param ClientInterface $client HTTP client (optional). If no HTTP client
65-
* is supplied, a default one will be
66-
* created.
54+
* @param HttpAdapterInterface $httpAdapter If no HTTP client is supplied, a
55+
* default one will be created.
6756
*/
68-
public function __construct(array $servers, $baseUrl = null, ClientInterface $client = null)
69-
{
70-
$this->client = $client ?: new Client();
71-
$this->setServers($servers);
72-
$this->setBaseUrl($baseUrl);
73-
}
74-
75-
/**
76-
* Set caching proxy servers
77-
*
78-
* @param array $servers Caching proxy proxy server hostnames or IP
79-
* addresses, including port if not port 80.
80-
* E.g. array('127.0.0.1:6081')
81-
*
82-
* @throws InvalidUrlException If server is invalid or contains URL
83-
* parts other than scheme, host, port
84-
*/
85-
public function setServers(array $servers)
86-
{
87-
$this->servers = array();
88-
foreach ($servers as $server) {
89-
$this->servers[] = $this->filterUrl($server, array('scheme', 'host', 'port'));
90-
}
91-
}
92-
93-
/**
94-
* Set application hostname, optionally including a base URL, for purge and
95-
* refresh requests
96-
*
97-
* @param string $url Your application’s base URL or hostname
98-
*/
99-
public function setBaseUrl($url)
100-
{
101-
if ($url) {
102-
$url = $this->filterUrl($url);
103-
}
104-
105-
$this->client->setBaseUrl($url);
57+
public function __construct(
58+
array $servers,
59+
$baseUrl = null,
60+
HttpAdapterInterface $httpAdapter = null
61+
) {
62+
$this->httpAdapter = $httpAdapter ?: HttpAdapterFactory::guess();
63+
$this->initQueue($servers, $baseUrl);
10664
}
10765

10866
/**
10967
* {@inheritdoc}
11068
*/
11169
public function flush()
11270
{
113-
$queue = $this->queue;
114-
if (0 === count($queue)) {
71+
if (0 === $this->queue->count()) {
11572
return 0;
11673
}
117-
118-
$this->queue = array();
119-
$this->sendRequests($queue);
120-
121-
return count($queue);
122-
}
123-
124-
/**
125-
* Add a request to the queue
126-
*
127-
* @param string $method HTTP method
128-
* @param string $url URL
129-
* @param array $headers HTTP headers
130-
*/
131-
protected function queueRequest($method, $url, array $headers = array())
132-
{
133-
$signature = $this->getSignature($method, $url, $headers);
134-
if (!isset($this->queue[$signature])) {
135-
$this->queue[$signature] = $this->createRequest($method, $url, $headers);
136-
}
137-
}
138-
139-
/**
140-
* Calculate a unique hash for the request, based on all significant information.
141-
*
142-
* @param string $method HTTP method
143-
* @param string $url URL
144-
* @param array $headers HTTP headers
145-
*
146-
* @return string A hash value for this request.
147-
*/
148-
private function getSignature($method, $url, array $headers)
149-
{
150-
ksort($headers);
151-
152-
return md5($method . "\n" . $url . "\n" . var_export($headers, true));
153-
}
154-
155-
/**
156-
* Create request
157-
*
158-
* @param string $method HTTP method
159-
* @param string $url URL
160-
* @param array $headers HTTP headers
161-
*
162-
* @return RequestInterface
163-
*/
164-
protected function createRequest($method, $url, array $headers = array())
165-
{
166-
return $this->client->createRequest($method, $url, $headers);
167-
}
168-
169-
/**
170-
* Sends all requests to each caching proxy server
171-
*
172-
* Requests are sent in parallel to minimise impact on performance.
173-
*
174-
* @param RequestInterface[] $requests Requests
175-
*
176-
* @throws ExceptionCollection
177-
*/
178-
private function sendRequests(array $requests)
179-
{
180-
$allRequests = array();
181-
182-
foreach ($requests as $request) {
183-
$headers = $request->getHeaders()->toArray();
184-
// Force to re-create Host header if empty, as Apache chokes on this. See #128 for discussion.
185-
if (empty($headers['Host'])) {
186-
unset( $headers['Host'] );
187-
}
188-
foreach ($this->servers as $server) {
189-
$proxyRequest = $this->client->createRequest(
190-
$request->getMethod(),
191-
$server . $request->getResource(),
192-
$headers
193-
);
194-
$allRequests[] = $proxyRequest;
195-
}
196-
}
74+
75+
$queue = clone $this->queue;
76+
$this->queue->clear();
19777

19878
try {
199-
$this->client->send($allRequests);
200-
} catch (GuzzleExceptionCollection $e) {
201-
$this->handleException($e);
202-
}
203-
}
204-
205-
/**
206-
* Handle request exception
207-
*
208-
* @param GuzzleExceptionCollection $exceptions
209-
*
210-
* @throws ExceptionCollection
211-
*/
212-
protected function handleException(GuzzleExceptionCollection $exceptions)
213-
{
214-
$collection = new ExceptionCollection();
215-
216-
foreach ($exceptions as $exception) {
217-
if ($exception instanceof CurlException) {
218-
// Caching proxy unreachable
219-
$e = ProxyUnreachableException::proxyUnreachable(
220-
$exception->getRequest()->getHost(),
221-
$exception->getMessage(),
222-
$exception->getRequest()->getRawHeaders(),
223-
$exception
224-
);
225-
} elseif ($exception instanceof RequestException) {
226-
// Other error
227-
$e = ProxyResponseException::proxyResponse(
228-
$exception->getRequest()->getHost(),
229-
$exception->getCode(),
230-
$exception->getMessage(),
231-
$exception->getRequest()->getRawHeaders(),
232-
$exception
79+
$responses = $this->httpAdapter->sendRequests($queue->all());
80+
} catch (MultiHttpAdapterException $e) {
81+
$collection = new ExceptionCollection();
82+
foreach ($e->getExceptions() as $exception) {
83+
$collection->add(
84+
ProxyUnreachableException::proxyUnreachable(
85+
$exception->getRequest()->getHeader('Host'),
86+
$exception->getMessage(),
87+
null,
88+
$exception
89+
)
23390
);
234-
} else {
235-
// Unexpected exception type
236-
$e = $exception;
23791
}
23892

239-
$collection->add($e);
93+
throw $collection;
24094
}
241-
242-
throw $collection;
95+
96+
return count($responses);
24397
}
244-
245-
/**
246-
* Filter a URL
247-
*
248-
* Prefix the URL with "http://" if it has no scheme, then check the URL
249-
* for validity. You can specify what parts of the URL are allowed.
250-
*
251-
* @param string $url
252-
* @param string[] $allowedParts Array of allowed URL parts (optional)
253-
*
254-
* @throws InvalidUrlException If URL is invalid, the scheme is not http or
255-
* contains parts that are not expected.
256-
*
257-
* @return string The URL (with default scheme if there was no scheme)
258-
*/
259-
protected function filterUrl($url, array $allowedParts = array())
98+
99+
protected function queueRequest($method, $url, array $headers = array())
260100
{
261-
// parse_url doesn’t work properly when no scheme is supplied, so
262-
// prefix URL with HTTP scheme if necessary.
263-
if (false === strpos($url, '://')) {
264-
$url = sprintf('%s://%s', $this->getDefaultScheme(), $url);
265-
}
266-
267-
if (!$parts = parse_url($url)) {
268-
throw InvalidUrlException::invalidUrl($url);
269-
}
270-
if (empty($parts['scheme'])) {
271-
throw InvalidUrlException::invalidUrl($url, 'empty scheme');
272-
}
273-
274-
if (!in_array(strtolower($parts['scheme']), $this->getAllowedSchemes())) {
275-
throw InvalidUrlException::invalidUrlScheme($url, $parts['scheme'], $this->getAllowedSchemes());
276-
}
277-
278-
if (count($allowedParts) > 0) {
279-
$diff = array_diff(array_keys($parts), $allowedParts);
280-
if (count($diff) > 0) {
281-
throw InvalidUrlException::invalidUrlParts($url, $allowedParts);
282-
}
283-
}
284-
285-
return $url;
101+
$this->queue->add(new InvalidationRequest($method, $url, $headers));
286102
}
287-
288-
/**
289-
* Get default scheme
290-
*
291-
* @return string
292-
*/
293-
protected function getDefaultScheme()
103+
104+
protected function initQueue(array $servers, $baseUrl)
294105
{
295-
return 'http';
106+
$this->queue = new RequestQueue($servers, $baseUrl);
296107
}
297108

298109
/**

0 commit comments

Comments
 (0)