PluginProbe
DecaLog / 4.4.0
DecaLog v4.4.0
3.0.2 3.1.0 3.10.0 3.2.0 3.3.0 3.4.0 3.4.1 3.5.0 3.5.1 3.6.0 3.6.1 3.6.2 3.6.3 3.7.0 3.7.1 3.8.0 3.9.0 3.9.1 4.0.0 4.1.0 4.2.0 4.3.0 4.3.1 4.4.0 4.5.0 All 75 releases
decalog / includes / libraries / http / client-common / Plugin / AddPathPlugin.php

AddPathPlugin.php in DecaLog 4.4.0, at includes/libraries/http/client-common/Plugin/AddPathPlugin.php

79 lines 2.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 declare(strict_types=1);
4
5 namespace Http\Client\Common\Plugin;
6
7 use Http\Client\Common\Plugin;
8 use Http\Promise\Promise;
9 use Psr\Http\Message\RequestInterface;
10 use Psr\Http\Message\UriInterface;
11
12 /**
13 * Prepend a base path to the request URI. Useful for base API URLs like http://domain.com/api.
14 *
15 * @author Sullivan Senechal <soullivaneuh@gmail.com>
16 */
17 final class AddPathPlugin implements Plugin
18 {
19 /**
20 * @var UriInterface
21 */
22 private $uri;
23
24 public function __construct(UriInterface $uri)
25 {
26 if ('' === $uri->getPath()) {
27 throw new \LogicException('URI path cannot be empty');
28 }
29
30 if ('/' === substr($uri->getPath(), -1)) {
31 $uri = $uri->withPath(rtrim($uri->getPath(), '/'));
32 }
33
34 $this->uri = $uri;
35 }
36
37 /**
38 * Adds a prefix in the beginning of the URL's path.
39 *
40 * The prefix is not added if that prefix is already on the URL's path. This will fail on the edge
41 * case of the prefix being repeated, for example if `https://example.com/api/api/foo` is a valid
42 * URL on the server and the configured prefix is `/api`.
43 *
44 * We looked at other solutions, but they are all much more complicated, while still having edge
45 * cases:
46 * - Doing an spl_object_hash on `$first` will lead to collisions over time because over time the
47 * hash can collide.
48 * - Have the PluginClient provide a magic header to identify the request chain and only apply
49 * this plugin once.
50 *
51 * There are 2 reasons for the AddPathPlugin to be executed twice on the same request:
52 * - A plugin can restart the chain by calling `$first`, e.g. redirect
53 * - A plugin can call `$next` more than once, e.g. retry
54 *
55 * Depending on the scenario, the path should or should not be added. E.g. `$first` could
56 * be called after a redirect response from the server. The server likely already has the
57 * correct path.
58 *
59 * No solution fits all use cases. This implementation will work fine for the common use cases.
60 * If you have a specific situation where this is not the right thing, you can build a custom plugin
61 * that does exactly what you need.
62 *
63 * {@inheritdoc}
64 */
65 public function handleRequest(RequestInterface $request, callable $next, callable $first): Promise
66 {
67 $prepend = $this->uri->getPath();
68 $path = $request->getUri()->getPath();
69
70 if (substr($path, 0, strlen($prepend)) !== $prepend) {
71 $request = $request->withUri($request->getUri()
72 ->withPath($prepend.$path)
73 );
74 }
75
76 return $next($request);
77 }
78 }
79