Completed
Pull Request — master (#284)
by
unknown
07:57
created

UserContextSubscriber   A

Complexity

Total Complexity 14

Size/Duplication

Total Lines 132
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 8

Test Coverage

Coverage 100%

Importance

Changes 4
Bugs 1 Features 2
Metric Value
wmc 14
c 4
b 1
f 2
lcom 1
cbo 8
dl 0
loc 132
ccs 52
cts 52
cp 1
rs 10

4 Methods

Rating   Name   Duplication   Size   Complexity  
B onKernelRequest() 0 29 4
A __construct() 0 18 2
C onKernelResponse() 0 25 7
A getSubscribedEvents() 0 7 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\EventListener;
13
14
use FOS\HttpCache\UserContext\HashGenerator;
15
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
16
use Symfony\Component\HttpFoundation\RequestMatcherInterface;
17
use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
18
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
19
use Symfony\Component\HttpFoundation\Response;
20
use Symfony\Component\HttpKernel\HttpKernelInterface;
21
use Symfony\Component\HttpKernel\KernelEvents;
22
23
/**
24
 * Check requests and responses with the matcher.
25
 *
26
 * Abort context hash requests immediately and return the hash.
27
 * Add the vary information on responses to normal requests.
28
 *
29
 * @author Stefan Paschke <[email protected]>
30
 * @author Joel Wurtz <[email protected]>
31
 */
32
class UserContextSubscriber implements EventSubscriberInterface
33
{
34
    /**
35
     * @var RequestMatcherInterface
36
     */
37
    private $requestMatcher;
38
39
    /**
40
     * @var HashGenerator
41
     */
42
    private $hashGenerator;
43
44
    /**
45
     * @var string[]
46
     */
47
    private $userIdentifierHeaders;
48
49
    /**
50
     * @var string
51
     */
52
    private $hashHeader;
53
54
    /**
55
     * @var integer
56
     */
57
    private $ttl;
58
59
    /**
60
     * @var bool
61
     */
62
    private $addVaryOnHash;
63
64 23
    public function __construct(
65
        RequestMatcherInterface $requestMatcher,
66
        HashGenerator $hashGenerator,
67
        array $userIdentifierHeaders = array('Cookie', 'Authorization'),
68
        $hashHeader = "X-User-Context-Hash",
69
        $ttl = 0,
70
        $addVaryOnHash = true
71
    ) {
72 23
        if (!count($userIdentifierHeaders)) {
73 1
            throw new \InvalidArgumentException('The user context must vary on some request headers');
74
        }
75 22
        $this->requestMatcher        = $requestMatcher;
76 22
        $this->hashGenerator         = $hashGenerator;
77 22
        $this->userIdentifierHeaders = $userIdentifierHeaders;
78 22
        $this->hashHeader            = $hashHeader;
79 22
        $this->ttl                   = $ttl;
80 22
        $this->addVaryOnHash            = $addVaryOnHash;
81 22
    }
82
83
    /**
84
     * Return the response to the context hash request with a header containing
85
     * the generated hash.
86
     *
87
     * If the ttl is bigger than 0, cache headers will be set for this response.
88
     *
89
     * @param GetResponseEvent $event
90
     */
91 18
    public function onKernelRequest(GetResponseEvent $event)
92
    {
93 18
        if ($event->getRequestType() != HttpKernelInterface::MASTER_REQUEST) {
94 3
            return;
95
        }
96
97 17
        if (!$this->requestMatcher->matches($event->getRequest())) {
98 15
            return;
99
        }
100
101 2
        $hash = $this->hashGenerator->generateHash();
102
103
        // status needs to be 200 as otherwise varnish will not cache the response.
104 2
        $response = new Response('', 200, array(
105 2
            $this->hashHeader => $hash,
106 2
            'Content-Type'    => 'application/vnd.fos.user-context-hash',
107 2
        ));
108
109 2
        if ($this->ttl > 0) {
110 1
            $response->setClientTtl($this->ttl);
111 1
            $response->setVary($this->userIdentifierHeaders);
112 1
            $response->setPublic();
113 1
        } else {
114 1
            $response->setClientTtl(0);
115 1
            $response->headers->addCacheControlDirective('no-cache');
116
        }
117
118 2
        $event->setResponse($response);
119 2
    }
120
121
    /**
122
     * Add the context hash header to the headers to vary on if the header was
123
     * present in the request.
124
     *
125
     * @param FilterResponseEvent $event
126
     */
127 18
    public function onKernelResponse(FilterResponseEvent $event)
128
    {
129 18
        if ($event->getRequestType() != HttpKernelInterface::MASTER_REQUEST) {
130 3
            return;
131
        }
132
133 17
        if ($this->addVaryOnHash) {
134 17
            $response = $event->getResponse();
135 17
            $vary = $response->getVary();
136
137 17
            if ($event->getRequest()->headers->has($this->hashHeader)) {
138 1
                if (!in_array($this->hashHeader, $vary)) {
139 1
                    $vary[] = $this->hashHeader;
140 1
                }
141 1
            } else {
142 16
                foreach ($this->userIdentifierHeaders as $header) {
143 16
                    if (!in_array($header, $vary)) {
144 16
                        $vary[] = $header;
145 16
                    }
146 16
                }
147
            }
148
149 17
            $response->setVary($vary, true);
150 17
        }
151 17
    }
152
153
    /**
154
     * {@inheritdoc}
155
     */
156 23
    public static function getSubscribedEvents()
157
    {
158
        return array(
159 23
            KernelEvents::RESPONSE => 'onKernelResponse',
160 23
            KernelEvents::REQUEST  => array('onKernelRequest', 7),
161 23
        );
162
    }
163
}
164