Completed
Push — master ( 9bb55b...536c73 )
by David de
11s
created

FOSHttpCacheExtension::getConfiguration()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 2
crap 1
1
<?php
2
3
/*
4
 * This file is part of the FOSHttpCacheBundle package.
5
 *
6
 * (c) FriendsOfSymfony <http://friendsofsymfony.github.com/>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace FOS\HttpCacheBundle\DependencyInjection;
13
14
use FOS\HttpCacheBundle\DependencyInjection\Compiler\HashGeneratorPass;
15
use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
16
use Symfony\Component\DependencyInjection\ContainerBuilder;
17
use Symfony\Component\Config\FileLocator;
18
use Symfony\Component\DependencyInjection\DefinitionDecorator;
19
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
20
use Symfony\Component\DependencyInjection\Reference;
21
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
22
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
23
24
/**
25
 * {@inheritdoc}
26
 */
27
class FOSHttpCacheExtension extends Extension
28
{
29
    /**
30
     * {@inheritdoc}
31
     */
32 22
    public function getConfiguration(array $config, ContainerBuilder $container)
33
    {
34 22
        return new Configuration($container->getParameter('kernel.debug'));
35
    }
36
37
    /**
38
     * {@inheritdoc}
39
     */
40 22
    public function load(array $configs, ContainerBuilder $container)
41
    {
42 22
        $configuration = $this->getConfiguration($configs, $container);
43 22
        $config = $this->processConfiguration($configuration, $configs);
0 ignored issues
show
Bug introduced by
It seems like $configuration defined by $this->getConfiguration($configs, $container) on line 42 can be null; however, Symfony\Component\Depend...:processConfiguration() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
44
45 22
        $loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
46 22
        $loader->load('matcher.xml');
47
48 22
        if ($config['debug']['enabled'] || (!empty($config['cache_control']))) {
49 3
            $debugHeader = $config['debug']['enabled'] ? $config['debug']['header'] : false;
50 3
            $container->setParameter($this->getAlias().'.debug_header', $debugHeader);
51 3
            $loader->load('cache_control_listener.xml');
52
        }
53
54 22
        if (!empty($config['cache_control'])) {
55 3
            $this->loadCacheControl($container, $config['cache_control']);
56
        }
57
58 22
        if (isset($config['proxy_client'])) {
59 16
            $this->loadProxyClient($container, $loader, $config['proxy_client']);
60
        }
61
62 21
        if (isset($config['test'])) {
63 1
            $this->loadTest($container, $loader, $config['test']);
64
        }
65
66 21
        if ($config['cache_manager']['enabled']) {
67 16
            if (array_key_exists('custom_proxy_client', $config['cache_manager'])) {
68
                // overwrite the previously set alias, if a proxy client was also configured
69 1
                $container->setAlias(
70 1
                    $this->getAlias().'.default_proxy_client',
71 1
                    $config['cache_manager']['custom_proxy_client']
72
                );
73
            }
74 16
            if ('auto' === $config['cache_manager']['generate_url_type']) {
75 16
                if (array_key_exists('custom_proxy_client', $config['cache_manager'])) {
76 1
                    $generateUrlType = UrlGeneratorInterface::ABSOLUTE_URL;
77
                } else {
78 15
                    $defaultClient = $this->getDefaultProxyClient($config['proxy_client']);
79 15
                    $generateUrlType = array_key_exists('base_url', $config['proxy_client'][$defaultClient])
80 15
                        ? UrlGeneratorInterface::ABSOLUTE_PATH
81 16
                        : UrlGeneratorInterface::ABSOLUTE_URL
82
                    ;
83
                }
84
            } else {
85
                $generateUrlType = $config['cache_manager']['generate_url_type'];
86
            }
87 16
            $container->setParameter($this->getAlias().'.cache_manager.generate_url_type', $generateUrlType);
88 16
            $loader->load('cache_manager.xml');
89
        }
90
91 21
        if ($config['tags']['enabled']) {
92 16
            $this->loadCacheTagging(
93
                $container,
94
                $loader,
95 16
                $config['tags'],
96 16
                array_key_exists('proxy_client', $config)
97 15
                    ? $this->getDefaultProxyClient($config['proxy_client'])
98 16
                    : 'custom'
99
            );
100
        } else {
101 5
            $container->setParameter($this->getAlias().'.compiler_pass.tag_annotations', false);
102
        }
103
104 20
        if ($config['invalidation']['enabled']) {
105 15
            $loader->load('invalidation_listener.xml');
106
107 15
            if (!empty($config['invalidation']['expression_language'])) {
108
                $container->setAlias(
109
                    $this->getAlias().'.invalidation.expression_language',
110
                    $config['invalidation']['expression_language']
111
                );
112
            }
113
114 15
            if (!empty($config['invalidation']['rules'])) {
115 2
                $this->loadInvalidatorRules($container, $config['invalidation']['rules']);
116
            }
117
        }
118
119 20
        if ($config['user_context']['enabled']) {
120 4
            $this->loadUserContext($container, $loader, $config['user_context']);
121
        }
122
123 20
        if (!empty($config['flash_message']) && $config['flash_message']['enabled']) {
124 1
            $container->setParameter($this->getAlias().'.event_listener.flash_message.options', $config['flash_message']);
125
126 1
            $loader->load('flash_message.xml');
127
        }
128 20
    }
129
130
    /**
131
     * @param ContainerBuilder $container
132
     * @param array            $config
133
     *
134
     * @throws InvalidConfigurationException
135
     */
136 3
    private function loadCacheControl(ContainerBuilder $container, array $config)
137
    {
138 3
        $controlDefinition = $container->getDefinition($this->getAlias().'.event_listener.cache_control');
139
140 3
        foreach ($config['rules'] as $rule) {
141 3
            $ruleMatcher = $this->parseRuleMatcher($container, $rule['match']);
142
143 3
            if ('default' === $rule['headers']['overwrite']) {
144 3
                $rule['headers']['overwrite'] = $config['defaults']['overwrite'];
145
            }
146
147 3
            $controlDefinition->addMethodCall('addRule', array($ruleMatcher, $rule['headers']));
148
        }
149 3
    }
150
151 5
    private function parseRuleMatcher(ContainerBuilder $container, array $match)
152
    {
153 5
        $match['ips'] = (empty($match['ips'])) ? null : $match['ips'];
154
155 5
        $requestMatcher = $this->createRequestMatcher(
156
            $container,
157 5
            $match['path'],
158 5
            $match['host'],
159 5
            $match['methods'],
160 5
            $match['ips'],
161 5
            $match['attributes']
162
        );
163
164 5
        $extraCriteria = array();
165 5
        foreach (array('additional_cacheable_status', 'match_response') as $extra) {
166 5
            if (isset($match[$extra])) {
167 5
                $extraCriteria[$extra] = $match[$extra];
168
            }
169
        }
170
171 5
        return $this->createRuleMatcher(
172
            $container,
173
            $requestMatcher,
174
            $extraCriteria
175
        );
176
    }
177
178 5
    private function createRuleMatcher(ContainerBuilder $container, Reference $requestMatcher, array $extraCriteria)
179
    {
180 5
        $arguments = array((string) $requestMatcher, $extraCriteria);
181 5
        $serialized = serialize($arguments);
182 5
        $id = $this->getAlias().'.rule_matcher.'.md5($serialized).sha1($serialized);
183
184 5 View Code Duplication
        if (!$container->hasDefinition($id)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
185
            $container
186 5
                ->setDefinition($id, new DefinitionDecorator($this->getAlias().'.rule_matcher'))
187 5
                ->replaceArgument(0, $requestMatcher)
188 5
                ->replaceArgument(1, $extraCriteria)
189
            ;
190
        }
191
192 5
        return new Reference($id);
193
    }
194
195 4
    private function loadUserContext(ContainerBuilder $container, XmlFileLoader $loader, array $config)
196
    {
197 4
        $loader->load('user_context.xml');
198
199 4
        $container->getDefinition($this->getAlias().'.user_context.request_matcher')
200 4
            ->replaceArgument(0, $config['match']['accept'])
201 4
            ->replaceArgument(1, $config['match']['method']);
202
203 4
        $container->getDefinition($this->getAlias().'.event_listener.user_context')
204 4
            ->replaceArgument(0, new Reference($config['match']['matcher_service']))
205 4
            ->replaceArgument(2, $config['user_identifier_headers'])
206 4
            ->replaceArgument(3, $config['user_hash_header'])
207 4
            ->replaceArgument(4, $config['hash_cache_ttl'])
208 4
            ->replaceArgument(5, $config['always_vary_on_context_hash']);
209
210 4
        $container->getDefinition($this->getAlias().'.user_context.anonymous_request_matcher')
211 4
            ->replaceArgument(0, $config['user_identifier_headers']);
212
213 4
        if ($config['logout_handler']['enabled']) {
214 4
            $container->getDefinition($this->getAlias().'.user_context.logout_handler')
215 4
                ->replaceArgument(1, $config['user_identifier_headers'])
216 4
                ->replaceArgument(2, $config['match']['accept']);
217
        } else {
218
            $container->removeDefinition($this->getAlias().'.user_context.logout_handler');
219
        }
220
221 4
        if ($config['role_provider']) {
222 2
            $container->getDefinition($this->getAlias().'.user_context.role_provider')
223 2
                ->addTag(HashGeneratorPass::TAG_NAME)
224 2
                ->setAbstract(false);
225
        }
226 4
    }
227
228 5
    private function createRequestMatcher(ContainerBuilder $container, $path = null, $host = null, $methods = null, $ips = null, array $attributes = array())
229
    {
230 5
        $arguments = array($path, $host, $methods, $ips, $attributes);
231 5
        $serialized = serialize($arguments);
232 5
        $id = $this->getAlias().'.request_matcher.'.md5($serialized).sha1($serialized);
233
234 5 View Code Duplication
        if (!$container->hasDefinition($id)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
235
            $container
236 5
                ->setDefinition($id, new DefinitionDecorator($this->getAlias().'.request_matcher'))
237 5
                ->setArguments($arguments)
238
            ;
239
        }
240
241 5
        return new Reference($id);
242
    }
243
244 16
    private function loadProxyClient(ContainerBuilder $container, XmlFileLoader $loader, array $config)
245
    {
246 16
        if (isset($config['varnish'])) {
247 13
            $this->loadVarnish($container, $loader, $config['varnish']);
248
        }
249 15
        if (isset($config['nginx'])) {
250 2
            $this->loadNginx($container, $loader, $config['nginx']);
251
        }
252 15
        if (isset($config['symfony'])) {
253 1
            $this->loadSymfony($container, $loader, $config['symfony']);
254
        }
255
256 15
        $container->setAlias(
257 15
            $this->getAlias().'.default_proxy_client',
258 15
            $this->getAlias().'.proxy_client.'.$this->getDefaultProxyClient($config)
259
        );
260 15
    }
261
262 13 View Code Duplication
    private function loadVarnish(ContainerBuilder $container, XmlFileLoader $loader, array $config)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
263
    {
264 13
        $loader->load('varnish.xml');
265 13
        foreach ($config['servers'] as $url) {
266 13
            $this->validateUrl($url, 'Not a valid Varnish server address: "%s"');
267
        }
268 13
        if (!empty($config['base_url'])) {
269 13
            $baseUrl = $this->prefixSchema($config['base_url'], 'Not a valid base path: "%s"');
0 ignored issues
show
Unused Code introduced by
The call to FOSHttpCacheExtension::prefixSchema() has too many arguments starting with 'Not a valid base path: "%s"'.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
270 13
            $this->validateUrl($baseUrl, 'Not a valid base path: "%s"');
271
        } else {
272
            $baseUrl = null;
273
        }
274 12
        $container->setParameter($this->getAlias().'.proxy_client.varnish.servers', $config['servers']);
275 12
        $container->setParameter($this->getAlias().'.proxy_client.varnish.base_url', $baseUrl);
276
277 12
        if (!empty($config['guzzle_client'])) {
278 1
            $container->setAlias(
279 1
                $this->getAlias().'.proxy_client.varnish.guzzle_client',
280 1
                $config['guzzle_client']
281
            );
282
        }
283 12
    }
284
285 2 View Code Duplication
    private function loadNginx(ContainerBuilder $container, XmlFileLoader $loader, array $config)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
286
    {
287 2
        $loader->load('nginx.xml');
288 2
        foreach ($config['servers'] as $url) {
289 2
            $this->validateUrl($url, 'Not a valid Nginx server address: "%s"');
290
        }
291 2
        if (!empty($config['base_url'])) {
292 2
            $baseUrl = $this->prefixSchema($config['base_url'], 'Not a valid base path: "%s"');
0 ignored issues
show
Unused Code introduced by
The call to FOSHttpCacheExtension::prefixSchema() has too many arguments starting with 'Not a valid base path: "%s"'.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
293
        } else {
294
            $baseUrl = null;
295
        }
296 2
        $container->setParameter($this->getAlias().'.proxy_client.nginx.servers', $config['servers']);
297 2
        $container->setParameter($this->getAlias().'.proxy_client.nginx.base_url', $baseUrl);
298 2
        $container->setParameter($this->getAlias().'.proxy_client.nginx.purge_location', $config['purge_location']);
299
300 2
        if (!empty($config['guzzle_client'])) {
301
            $container->setAlias(
302
                $this->getAlias().'.proxy_client.nginx.guzzle_client',
303
                $config['guzzle_client']
304
            );
305
        }
306 2
    }
307
308 1 View Code Duplication
    private function loadSymfony(ContainerBuilder $container, XmlFileLoader $loader, array $config)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
309
    {
310 1
        $loader->load('symfony.xml');
311 1
        foreach ($config['servers'] as $url) {
312 1
            $this->validateUrl($url, 'Not a valid web server address: "%s"');
313
        }
314 1
        if (!empty($config['base_url'])) {
315 1
            $baseUrl = $this->prefixSchema($config['base_url'], 'Not a valid base path: "%s"');
0 ignored issues
show
Unused Code introduced by
The call to FOSHttpCacheExtension::prefixSchema() has too many arguments starting with 'Not a valid base path: "%s"'.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
316 1
            $this->validateUrl($baseUrl, 'Not a valid base path: "%s"');
317
        } else {
318
            $baseUrl = null;
319
        }
320 1
        $container->setParameter($this->getAlias().'.proxy_client.symfony.servers', $config['servers']);
321 1
        $container->setParameter($this->getAlias().'.proxy_client.symfony.base_url', $baseUrl);
322
323 1
        if (!empty($config['guzzle_client'])) {
324
            $container->setAlias(
325
                $this->getAlias().'.proxy_client.symfony.guzzle_client',
326
                $config['guzzle_client']
327
            );
328
        }
329 1
    }
330
331
    /**
332
     * @param ContainerBuilder $container
333
     * @param XmlFileLoader    $loader
334
     * @param array            $config    Configuration section for the tags node
335
     * @param string           $client    Name of the client used with the cache manager,
336
     *                                    "custom" when a custom client is used
337
     */
338 16
    private function loadCacheTagging(ContainerBuilder $container, XmlFileLoader $loader, array $config, $client)
339
    {
340 16
        if ('auto' === $config['enabled'] && 'varnish' !== $client) {
341 3
            $container->setParameter($this->getAlias().'.compiler_pass.tag_annotations', false);
342
343 3
            return;
344
        }
345 13
        if (!in_array($client, array('varnish', 'custom'))) {
346 1
            throw new InvalidConfigurationException(sprintf('You can not enable cache tagging with %s', $client));
347
        }
348
349 12
        $container->setParameter($this->getAlias().'.compiler_pass.tag_annotations', true);
350 12
        $container->setParameter($this->getAlias().'.tag_handler.header', $config['header']);
351 12
        $loader->load('cache_tagging.xml');
352
353 12
        if (!empty($config['expression_language'])) {
354
            $container->setAlias(
355
                $this->getAlias().'.tag_handler.expression_language',
356
                $config['expression_language']
357
            );
358
        }
359
360 12
        if (!empty($config['rules'])) {
361 2
            $this->loadTagRules($container, $config['rules']);
362
        }
363
364 12
        $tagsHeader = $config['header'];
365 12
        $container->getDefinition($this->getAlias().'.cache_manager')
366 12
            ->addMethodCall('setTagsHeader', array($tagsHeader))
367
        ;
368 12
    }
369
370 1
    private function loadTest(ContainerBuilder $container, XmlFileLoader $loader, array $config)
371
    {
372 1
        $container->setParameter($this->getAlias().'.test.cache_header', $config['cache_header']);
373
374 1
        if ($config['proxy_server']) {
375 1
            $this->loadProxyServer($container, $loader, $config['proxy_server']);
376
        }
377
378 1
        if (isset($config['client']['varnish']['enabled'])
379 1
            || isset($config['client']['nginx']['enabled'])) {
380 1
            $loader->load('test_client.xml');
381
382 1
            if ($config['client']['varnish']['enabled']) {
383 1
                $loader->load('varnish_test_client.xml');
384
            }
385
386 1
            if ($config['client']['nginx']['enabled']) {
387
                $loader->load('nginx_test_client.xml');
388
            }
389
390 1
            $container->setAlias(
391 1
                $this->getAlias().'.test.default_client',
392 1
                $this->getAlias().'.test.client.'.$this->getDefaultProxyClient($config['client'])
393
            );
394
        }
395 1
    }
396
397 1
    private function loadProxyServer(ContainerBuilder $container, XmlFileLoader $loader, array $config)
398
    {
399 1
        if (isset($config['varnish'])) {
400 1
            $this->loadVarnishProxyServer($container, $loader, $config['varnish']);
401
        }
402
403 1
        if (isset($config['nginx'])) {
404
            $this->loadNginxProxyServer($container, $loader, $config['varnish']);
405
        }
406
407 1
        $container->setAlias(
408 1
            $this->getAlias().'.test.default_proxy_server',
409 1
            $this->getAlias().'.test.proxy_server.'.$this->getDefaultProxyClient($config)
410
        );
411 1
    }
412
413 1
    private function loadVarnishProxyServer(ContainerBuilder $container, XmlFileLoader $loader, $config)
414
    {
415 1
        $loader->load('varnish_proxy.xml');
416 1
        foreach ($config as $key => $value) {
417 1
            $container->setParameter(
418 1
                $this->getAlias().'.test.proxy_server.varnish.'.$key,
419
                $value
420
            );
421
        }
422 1
    }
423
424
    private function loadNginxProxyServer(ContainerBuilder $container, XmlFileLoader $loader, $config)
425
    {
426
        $loader->load('nginx_proxy.xml');
427
        foreach ($config as $key => $value) {
428
            $container->setParameter(
429
                $this->getAlias().'.test.proxy_server.nginx.'.$key,
430
                $value
431
            );
432
        }
433
    }
434
435 2
    private function loadTagRules(ContainerBuilder $container, array $config)
436
    {
437 2
        $tagDefinition = $container->getDefinition($this->getAlias().'.event_listener.tag');
438
439 2
        foreach ($config as $rule) {
440 2
            $ruleMatcher = $this->parseRuleMatcher($container, $rule['match']);
441
442
            $tags = array(
443 2
                'tags' => $rule['tags'],
444 2
                'expressions' => $rule['tag_expressions'],
445
            );
446
447 2
            $tagDefinition->addMethodCall('addRule', array($ruleMatcher, $tags));
448
        }
449 2
    }
450
451 2
    private function loadInvalidatorRules(ContainerBuilder $container, array $config)
452
    {
453 2
        $tagDefinition = $container->getDefinition($this->getAlias().'.event_listener.invalidation');
454
455 2
        foreach ($config as $rule) {
456 2
            $ruleMatcher = $this->parseRuleMatcher($container, $rule['match']);
457 2
            $tagDefinition->addMethodCall('addRule', array($ruleMatcher, $rule['routes']));
458
        }
459 2
    }
460
461 16
    private function validateUrl($url, $msg)
462
    {
463 16
        $prefixed = $this->prefixSchema($url);
464
465 16
        if (!$parts = parse_url($prefixed)) {
466 1
            throw new InvalidConfigurationException(sprintf($msg, $url));
467
        }
468 16
    }
469
470 16
    private function prefixSchema($url)
471
    {
472 16
        if (false === strpos($url, '://')) {
473 16
            $url = sprintf('%s://%s', 'http', $url);
474
        }
475
476 16
        return $url;
477
    }
478
479 15
    private function getDefaultProxyClient(array $config)
480
    {
481 15
        if (isset($config['default'])) {
482
            return $config['default'];
483
        }
484
485 15
        if (isset($config['varnish'])) {
486 12
            return 'varnish';
487
        }
488
489 3
        if (isset($config['nginx'])) {
490 2
            return 'nginx';
491
        }
492
493 1
        if (isset($config['symfony'])) {
494 1
            return 'symfony';
495
        }
496
497
        throw new InvalidConfigurationException('No proxy client configured');
498
    }
499
}
500