Passed
Pull Request — master (#503)
by Alejandro
07:20
created

BodyParserMiddleware::getRequestContentType()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 3
c 1
b 0
f 0
dl 0
loc 5
ccs 4
cts 4
cp 1
rs 10
cc 1
nc 1
nop 1
crap 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Shlinkio\Shlink\Rest\Middleware;
6
7
use Fig\Http\Message\RequestMethodInterface;
8
use Psr\Http\Message\ResponseInterface as Response;
9
use Psr\Http\Message\ServerRequestInterface as Request;
10
use Psr\Http\Server\MiddlewareInterface;
11
use Psr\Http\Server\RequestHandlerInterface;
12
13
use function array_shift;
14
use function explode;
15
use function Functional\contains;
16
use function parse_str;
17
use function Shlinkio\Shlink\Common\json_decode;
18
use function trim;
19
20
class BodyParserMiddleware implements MiddlewareInterface, RequestMethodInterface
21
{
22
    /**
23
     * Process an incoming server request and return a response, optionally delegating
24
     * to the next middleware component to create the response.
25
     *
26
     * @param Request $request
27
     * @param RequestHandlerInterface $handler
28
     *
29
     * @return Response
30
     */
31 6
    public function process(Request $request, RequestHandlerInterface $handler): Response
32
    {
33 6
        $method = $request->getMethod();
34 6
        $currentParams = $request->getParsedBody();
35
36
        // In requests that do not allow body or if the body has already been parsed, continue to next middleware
37
        if (
38 6
            ! empty($currentParams)
39 5
            || contains([
40 5
                self::METHOD_GET,
41 5
                self::METHOD_HEAD,
42 5
                self::METHOD_OPTIONS,
43 6
            ], $method)
44
        ) {
45 4
            return $handler->handle($request);
46
        }
47
48
        // If the accepted content is JSON, try to parse the body from JSON
49 2
        $contentType = $this->getRequestContentType($request);
50 2
        if (contains(['application/json', 'text/json', 'application/x-json'], $contentType)) {
51 1
            return $handler->handle($this->parseFromJson($request));
52
        }
53
54 1
        return $handler->handle($this->parseFromUrlEncoded($request));
55
    }
56
57
    /**
58
     * @param Request $request
59
     * @return string
60
     */
61 2
    private function getRequestContentType(Request $request): string
62
    {
63 2
        $contentType = $request->getHeaderLine('Content-type');
64 2
        $contentTypes = explode(';', $contentType);
65 2
        return trim(array_shift($contentTypes));
66
    }
67
68
    /**
69
     * @param Request $request
70
     * @return Request
71
     */
72 1
    private function parseFromJson(Request $request): Request
73
    {
74 1
        $rawBody = (string) $request->getBody();
75 1
        if (empty($rawBody)) {
76
            return $request;
77
        }
78
79 1
        $parsedJson = json_decode($rawBody);
80 1
        return $request->withParsedBody($parsedJson);
81
    }
82
83
    /**
84
     * @param Request $request
85
     * @return Request
86
     */
87 1
    private function parseFromUrlEncoded(Request $request): Request
88
    {
89 1
        $rawBody = (string) $request->getBody();
90 1
        if (empty($rawBody)) {
91
            return $request;
92
        }
93
94 1
        $parsedBody = [];
95 1
        parse_str($rawBody, $parsedBody);
96
97 1
        return $request->withParsedBody($parsedBody);
98
    }
99
}
100