isNotAnEmptyDeleteRequestWithNoSetContentType()   A
last analyzed

Complexity

Conditions 3
Paths 3

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 3

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
c 0
b 0
f 0
cc 3
nc 3
nop 3
crap 3
1
<?php
2
3
/*
4
 * This file is part of the FOSRestBundle 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\RestBundle\EventListener;
13
14
use FOS\RestBundle\Decoder\DecoderProviderInterface;
15
use FOS\RestBundle\FOSRestBundle;
16
use FOS\RestBundle\Normalizer\ArrayNormalizerInterface;
17
use FOS\RestBundle\Normalizer\Exception\NormalizationException;
18
use Symfony\Component\HttpFoundation\ParameterBag;
19
use Symfony\Component\HttpFoundation\Request;
20
use Symfony\Component\HttpKernel\Event\RequestEvent;
21
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
22
use Symfony\Component\HttpKernel\Exception\UnsupportedMediaTypeHttpException;
23
24
/**
25
 * This listener handles Request body decoding.
26
 *
27
 * @author Lukas Kahwe Smith <[email protected]>
28
 *
29
 * @internal
30
 */
31
class BodyListener
32
{
33
    private $decoderProvider;
34
    private $throwExceptionOnUnsupportedContentType;
35
    private $defaultFormat;
36
    private $arrayNormalizer;
37
    private $normalizeForms;
38
39 35
    public function __construct(
40
        DecoderProviderInterface $decoderProvider,
41
        bool $throwExceptionOnUnsupportedContentType = false,
42
        ArrayNormalizerInterface $arrayNormalizer = null,
43
        bool $normalizeForms = false
44
    ) {
45 35
        $this->decoderProvider = $decoderProvider;
46 35
        $this->throwExceptionOnUnsupportedContentType = $throwExceptionOnUnsupportedContentType;
47 35
        $this->arrayNormalizer = $arrayNormalizer;
48 35
        $this->normalizeForms = $normalizeForms;
49 35
    }
50
51 1
    public function setDefaultFormat(?string $defaultFormat): void
52
    {
53 1
        $this->defaultFormat = $defaultFormat;
54 1
    }
55
56 35
    public function onKernelRequest(RequestEvent $event): void
57
    {
58 35
        $request = $event->getRequest();
59
60 35
        if (!$request->attributes->get(FOSRestBundle::ZONE_ATTRIBUTE, true)) {
61 1
            return;
62
        }
63
64 34
        $method = $request->getMethod();
65 34
        $contentType = $request->headers->get('Content-Type');
66 34
        $normalizeRequest = $this->normalizeForms && $this->isFormRequest($request);
67
68 34
        if ($this->isDecodeable($request)) {
69 16
            $format = null === $contentType
70 4
                ? $request->getRequestFormat()
71 16
                : $request->getFormat($contentType);
72
73 16
            $format = $format ?: $this->defaultFormat;
74
75 16
            $content = $request->getContent();
76
77 16
            if (null === $format || !$this->decoderProvider->supports($format)) {
78 7
                if ($this->throwExceptionOnUnsupportedContentType
79 7
                    && $this->isNotAnEmptyDeleteRequestWithNoSetContentType($method, $content, $contentType)
80
                ) {
81 1
                    throw new UnsupportedMediaTypeHttpException("Request body format '$format' not supported");
82
                }
83
84 6
                return;
85
            }
86
87 9
            if (!empty($content)) {
88 9
                $decoder = $this->decoderProvider->getDecoder($format);
89 9
                $data = $decoder->decode($content);
0 ignored issues
show
Bug introduced by
It seems like $content defined by $request->getContent() on line 75 can also be of type resource; however, FOS\RestBundle\Decoder\DecoderInterface::decode() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
90 9
                if (is_array($data)) {
91 8
                    $request->request = new ParameterBag($data);
92 8
                    $normalizeRequest = true;
93
                } else {
94 1
                    throw new BadRequestHttpException('Invalid '.$format.' message received');
95
                }
96
            }
97
        }
98
99 26
        if (null !== $this->arrayNormalizer && $normalizeRequest) {
100 18
            $data = $request->request->all();
101
102
            try {
103 18
                $data = $this->arrayNormalizer->normalize($data);
104 1
            } catch (NormalizationException $e) {
105 1
                throw new BadRequestHttpException($e->getMessage());
106
            }
107
108 17
            $request->request = new ParameterBag($data);
109
        }
110 25
    }
111
112 2
    private function isNotAnEmptyDeleteRequestWithNoSetContentType(string $method, $content, ?string $contentType): bool
113
    {
114 2
        return false === ('DELETE' === $method && empty($content) && empty($contentType));
115
    }
116
117 34
    private function isDecodeable(Request $request): bool
118
    {
119 34
        if (!in_array($request->getMethod(), ['POST', 'PUT', 'PATCH', 'DELETE'])) {
120 1
            return false;
121
        }
122
123 33
        return !$this->isFormRequest($request);
124
    }
125
126 33
    private function isFormRequest(Request $request): bool
127
    {
128 33
        $contentTypeParts = explode(';', $request->headers->get('Content-Type'));
129
130 33
        if (isset($contentTypeParts[0])) {
131 33
            return in_array($contentTypeParts[0], ['multipart/form-data', 'application/x-www-form-urlencoded']);
132
        }
133
134
        return false;
135
    }
136
}
137