RequestResponseListener::isExcludedPrefix()   A
last analyzed

Complexity

Conditions 3
Paths 3

Size

Total Lines 9
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 0
Metric Value
cc 3
eloc 4
nc 3
nop 1
dl 0
loc 9
ccs 0
cts 0
cp 0
crap 12
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace RedirectionIO\Client\ProxySymfony\EventListener;
4
5
use RedirectionIO\Client\Sdk\Client;
6
use RedirectionIO\Client\Sdk\Command\CommandInterface;
7
use RedirectionIO\Client\Sdk\Command\LogCommand;
8
use RedirectionIO\Client\Sdk\Command\MatchCommand;
9
use RedirectionIO\Client\Sdk\Command\MatchWithResponseCommand;
10
use RedirectionIO\Client\Sdk\Exception\ExceptionInterface;
11
use RedirectionIO\Client\Sdk\HttpMessage\Request;
12
use RedirectionIO\Client\Sdk\HttpMessage\Response;
13
use Symfony\Component\HttpFoundation\RedirectResponse as SymfonyRedirectResponse;
14
use Symfony\Component\HttpFoundation\Request as SymfonyRequest;
15
use Symfony\Component\HttpFoundation\Response as SymfonyResponse;
16
use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
17
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
18
use Symfony\Component\HttpKernel\Event\PostResponseEvent;
19
20
/**
21
 * @internal
22
 */
23
final class RequestResponseListener
24
{
25
    private $client;
26
    private $allowMatchOnResponse;
27
    private $circuitBreakers;
28
29
    public function __construct(Client $client, bool $allowMatchOnResponse = false, /* iterable */ $circuitBreakers = [])
30
    {
31
        $this->client = $client;
32
        $this->allowMatchOnResponse = $allowMatchOnResponse;
33
        $this->circuitBreakers = $circuitBreakers;
34
    }
35
36
    public function onKernelRequest(GetResponseEvent $event)
37
    {
38
        if (!$event->isMasterRequest()) {
39
            return;
40
        }
41
42
        $request = $event->getRequest();
43
44
        foreach ($this->circuitBreakers as $circuitBreaker) {
45
            if ($circuitBreaker->shouldNotProcessRequest($request)) {
46
                return;
47
            }
48
        }
49
50
        /** @var Response $response */
51
        $response = $this->client->request($this->createMatchCommand($request));
52
        $request->attributes->set('redirectionio_response', $response);
53
54
        if (!$response) {
0 ignored issues
show
introduced by
$response is of type RedirectionIO\Client\Sdk\HttpMessage\Response, thus it always evaluated to true.
Loading history...
55
            return;
56
        }
57
58
        if ($response->getMatchOnResponseStatus() > 0) {
59
            return;
60
        }
61
62
        410 === $response->getStatusCode()
63
            ? $event->setResponse((new SymfonyResponse())->setStatusCode(410))
64
            : $event->setResponse(new SymfonyRedirectResponse($response->getLocation(), $response->getStatusCode()));
65
    }
66
67
    public function onKernelResponse(FilterResponseEvent $event)
68
    {
69
        /** @var Response $rioResponse */
70
        $rioResponse = $event->getRequest()->attributes->get('redirectionio_response');
71
72
        if (null === $rioResponse) {
73
            return;
74
        }
75
76
        $symfonyResponse = $event->getResponse();
77
78
        if (0 === $rioResponse->getMatchOnResponseStatus() || $rioResponse->getMatchOnResponseStatus() !== $symfonyResponse->getStatusCode()) {
79
            return;
80
        }
81
82
        410 === $rioResponse->getStatusCode()
83
            ? $event->setResponse((new SymfonyResponse())->setStatusCode(410))
84
            : $event->setResponse(new SymfonyRedirectResponse($rioResponse->getLocation(), $rioResponse->getStatusCode()));
85
    }
86
87
    public function onKernelTerminate(PostResponseEvent $event)
88
    {
89
        foreach ($this->circuitBreakers as $circuitBreaker) {
90
            if ($circuitBreaker->shouldNotProcessRequest($event->getRequest())) {
91
                return;
92
            }
93
        }
94
95
        $response = $event->getRequest()->attributes->get('redirectionio_response');
96
97
        if (!$response) {
98
            $symfonyResponse = $event->getResponse();
99
            $location = $symfonyResponse->headers->get('location', null);
100
101
            $response = new Response($event->getResponse()->getStatusCode(), null, $location);
102
        }
103
104
        $request = $this->createSdkRequest($event->getRequest());
105
106
        try {
107
            $this->client->request(new LogCommand($request, $response));
108
        } catch (ExceptionInterface $exception) {
109
            // do nothing
110
        }
111
    }
112
113
    private function createMatchCommand(SymfonyRequest $symfonyRequest): CommandInterface
114
    {
115
        $request = $this->createSdkRequest($symfonyRequest);
116
117
        if ($this->allowMatchOnResponse) {
118
            return new MatchWithResponseCommand($request);
119
        }
120
121
        return new MatchCommand($request);
122
    }
123
124
    private function createSdkRequest(SymfonyRequest $symfonyRequest)
125
    {
126
        return new Request(
127
            $symfonyRequest->getHttpHost(),
128
            $this->getFullPath($symfonyRequest),
129
            $symfonyRequest->headers->get('User-Agent'),
130
            $symfonyRequest->headers->get('Referer'),
131
            $symfonyRequest->getScheme()
132
        );
133
    }
134
135
    private function getFullPath(SymfonyRequest $symfonyRequest)
136
    {
137
        if (null === ($requestUri = $symfonyRequest->getRequestUri())) {
0 ignored issues
show
introduced by
The condition null === $requestUri = $...equest->getRequestUri() is always false.
Loading history...
138
            return '/';
139
        }
140
141
        if ('' !== $requestUri && '/' !== $requestUri[0]) {
142
            $requestUri = '/'.$requestUri;
143
        }
144
145
        if (null === ($baseUrl = $symfonyRequest->getBaseUrl())) {
0 ignored issues
show
introduced by
The condition null === $baseUrl = $symfonyRequest->getBaseUrl() is always false.
Loading history...
146
            return $requestUri;
147
        }
148
149
        $pathInfo = substr($requestUri, \strlen($baseUrl));
150
151
        if (false === $pathInfo || '' === $pathInfo) {
152
            return '/';
153
        }
154
155
        return (string) $pathInfo;
156
    }
157
158
    private function isExcludedPrefix($url): bool
0 ignored issues
show
Unused Code introduced by
The method isExcludedPrefix() is not used, and could be removed.

This check looks for private methods that have been defined, but are not used inside the class.

Loading history...
159
    {
160
        foreach ($this->excludedPrefixes as $excludedPrefix) {
0 ignored issues
show
Bug Best Practice introduced by
The property excludedPrefixes does not exist on RedirectionIO\Client\Pro...RequestResponseListener. Did you maybe forget to declare it?
Loading history...
161
            if (0 === strpos($url, $excludedPrefix)) {
162
                return true;
163
            }
164
        }
165
166
        return false;
167
    }
168
}
169