Skip to content

Instantly share code, notes, and snippets.

@alexwilson
Last active July 22, 2020 12:41
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save alexwilson/5354d78c13c38ed103e87e6430f5ee98 to your computer and use it in GitHub Desktop.
Save alexwilson/5354d78c13c38ed103e87e6430f5ee98 to your computer and use it in GitHub Desktop.
<?php declare(strict_types=1);
namespace AppBundle\EventListener;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\{GetResponseEvent, FilterResponseEvent};
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\HttpFoundation\HeaderBag;
class SpecialistPreflightLegacyHandler implements EventSubscriberInterface
{
// Try to run as soon as possible.
const HIGH_PRIORITY_REQUEST = 999999;
/**
* {@inheritDoc}
*/
public static function getSubscribedEvents(): array
{
return [
KernelEvents::REQUEST => [
['recordRequestedHeaders', self::HIGH_PRIORITY_REQUEST],
['parseSpecialistFlags', self::HIGH_PRIORITY_REQUEST-1]
],
KernelEvents::RESPONSE => 'varyOnRequestedSpecialistHeaders'
];
}
/**
* Replace the HeaderBag with one that keeps track of which Headers are read.
*
* @param GetResponseEvent $event
*
* @return void
*/
public function recordRequestedHeaders(GetResponseEvent $event)
{
$request = $event->getRequest();
$request->originalHeaderBag = $request->headers;
/**
* Wrap the Request object with a shim that records all property accesses..
*/
$request->headers = new class($request->originalHeaderBag->all()) extends HeaderBag {
/**
* @var string[]
*/
protected $varyHeaders = [];
/**
* {@inheritDoc}
*/
public function all()
{
$this->varyHeaders += parent::keys();
return parent::all();
}
/**
* {@inheritDoc}
*/
public function keys()
{
$keys = parent::keys();
$this->varyHeaders += $keys;
return $keys;
}
/**
* {@inheritDoc}
*/
public function get($key, $default = null, $first = true)
{
$this->varyHeaders[] = $key;
return parent::get($key, $default, $first);
}
/**
* {@inheritDoc}
*/
public function has($key)
{
$this->varyHeaders[] = $key;
return parent::has($key);
}
/**
* {@inheritDoc}
*/
public function contains($key, $value)
{
$this->varyHeaders[] = $key;
return parent::contains($key, $value);
}
/**
* @return string[] An array of headers we may Vary on.
*/
public function getVaryHeaders()
{
return array_unique($this->varyHeaders);
}
};
}
/**
* Interpret KV flag data of format "KEY=VALUE,KEY=VALUE" passed in 'Specialist-Flags' header
*
* @param GetResponseEvent $event
* @return void
*/
public function parseSpecialistFlags(GetResponseEvent $event)
{
$request = $event->getRequest();
$request->flags = new HeaderBag();
if ($flags = $request->headers->get('Specialist-Flags')) {
parse_str(str_replace(',', '&', $flags), $parsedFlags);
foreach ($parsedFlags as $key => $value){
$sanitizeFlagValue = filter_var($value, FILTER_VALIDATE_BOOLEAN);
$request->flags->set($key, $sanitizeFlagValue);
}
}
}
/**
* Automatically tags a FilterResponseEvent with the correct Vary based on what we have read during a request.
*
* @param FilterResponseEvent $event
*
* @return void
*/
public function varyOnRequestedSpecialistHeaders(FilterResponseEvent $event): void
{
$request = $event->getRequest();
$response = $event->getResponse();
foreach ($request->headers->getVaryHeaders() as $header) {
if (0 === strpos($header, 'Specialist')) {
$response->setVary($header, false);
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment