-
Notifications
You must be signed in to change notification settings - Fork 695
/
Copy pathBodyListener.php
137 lines (113 loc) · 4.58 KB
/
BodyListener.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
<?php
/*
* This file is part of the FOSRestBundle package.
*
* (c) FriendsOfSymfony <http://friendsofsymfony.github.com/>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace FOS\RestBundle\EventListener;
use FOS\RestBundle\Decoder\DecoderProviderInterface;
use FOS\RestBundle\FOSRestBundle;
use FOS\RestBundle\Normalizer\ArrayNormalizerInterface;
use FOS\RestBundle\Normalizer\Exception\NormalizationException;
use Symfony\Component\HttpFoundation\ParameterBag;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
use Symfony\Component\HttpKernel\Exception\UnsupportedMediaTypeHttpException;
/**
* This listener handles Request body decoding.
*
* @author Lukas Kahwe Smith <smith@pooteeweet.org>
*
* @internal
*/
class BodyListener
{
private $decoderProvider;
private $throwExceptionOnUnsupportedContentType;
private $defaultFormat;
private $arrayNormalizer;
private $normalizeForms;
public function __construct(
DecoderProviderInterface $decoderProvider,
bool $throwExceptionOnUnsupportedContentType = false,
ArrayNormalizerInterface $arrayNormalizer = null,
bool $normalizeForms = false
) {
$this->decoderProvider = $decoderProvider;
$this->throwExceptionOnUnsupportedContentType = $throwExceptionOnUnsupportedContentType;
$this->arrayNormalizer = $arrayNormalizer;
$this->normalizeForms = $normalizeForms;
}
public function setDefaultFormat(?string $defaultFormat): void
{
$this->defaultFormat = $defaultFormat;
}
public function onKernelRequest(RequestEvent $event): void
{
$request = $event->getRequest();
if (!$request->attributes->get(FOSRestBundle::ZONE_ATTRIBUTE, true)) {
return;
}
$method = $request->getMethod();
$contentType = $request->headers->get('Content-Type');
$normalizeRequest = $this->normalizeForms && $this->isFormRequest($request);
if ($this->isDecodeable($request)) {
$format = null === $contentType
? $request->getRequestFormat()
: $request->getFormat($contentType);
$format = $format ?: $this->defaultFormat;
$content = $request->getContent();
if (null === $format || !$this->decoderProvider->supports($format)) {
if ($this->throwExceptionOnUnsupportedContentType
&& $this->isNotAnEmptyDeleteRequestWithNoSetContentType($method, $content, $contentType)
) {
throw new UnsupportedMediaTypeHttpException("Request body format '$format' not supported");
}
return;
}
if (!empty($content)) {
$decoder = $this->decoderProvider->getDecoder($format);
$data = $decoder->decode($content);
if (is_array($data)) {
$request->request = new ParameterBag($data);
$normalizeRequest = true;
$request->attributes->set('_fosrestbundle_decoder', get_class($decoder));
} else {
throw new BadRequestHttpException('Invalid '.$format.' message received');
}
}
}
if (null !== $this->arrayNormalizer && $normalizeRequest) {
$data = $request->request->all();
try {
$data = $this->arrayNormalizer->normalize($data);
} catch (NormalizationException $e) {
throw new BadRequestHttpException($e->getMessage());
}
$request->request = new ParameterBag($data);
}
}
private function isNotAnEmptyDeleteRequestWithNoSetContentType(string $method, $content, ?string $contentType): bool
{
return false === ('DELETE' === $method && empty($content) && empty($contentType));
}
private function isDecodeable(Request $request): bool
{
if (!in_array($request->getMethod(), ['POST', 'PUT', 'PATCH', 'DELETE'])) {
return false;
}
return !$this->isFormRequest($request);
}
private function isFormRequest(Request $request): bool
{
$contentTypeParts = explode(';', $request->headers->get('Content-Type'));
if (isset($contentTypeParts[0])) {
return in_array($contentTypeParts[0], ['multipart/form-data', 'application/x-www-form-urlencoded']);
}
return false;
}
}