ContentTypeMiddleware   A
last analyzed

Complexity

Total Complexity 12

Size/Duplication

Total Lines 93
Duplicated Lines 0 %

Test Coverage

Coverage 86.11%

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 34
c 2
b 0
f 0
dl 0
loc 93
ccs 31
cts 36
cp 0.8611
rs 10
wmc 12

5 Methods

Rating   Name   Duplication   Size   Complexity  
A isJson() 0 6 1
A handleResponse() 0 3 1
B handleRequest() 0 24 8
A __construct() 0 12 1
A isXml() 0 8 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Buzz\Middleware;
6
7
use Psr\Http\Message\RequestInterface;
8
use Psr\Http\Message\ResponseInterface;
9
use Psr\Http\Message\StreamInterface;
10
use Symfony\Component\OptionsResolver\OptionsResolver;
11
12
class ContentTypeMiddleware implements MiddlewareInterface
13
{
14
    /**
15
     * Allow to disable the content type detection when stream is too large (as it can consume a lot of resource).
16
     *
17
     * @var bool
18
     *
19
     * true     skip the content type detection
20
     * false    detect the content type (default value)
21
     */
22
    protected $skipDetection;
23
24
    /**
25
     * Determine the size stream limit for which the detection as to be skipped (default to 16Mb).
26
     *
27
     * @var int
28
     */
29
    protected $sizeLimit;
30
31
    /**
32
     * @param array $config {
33
     *
34
     *     @var bool $skip_detection True skip detection if stream size is bigger than $size_limit
35
     *     @var int $size_limit size stream limit for which the detection as to be skipped.
36
     * }
37
     */
38 1
    public function __construct(array $config = [])
39
    {
40 1
        $resolver = new OptionsResolver();
41 1
        $resolver->setDefaults([
42 1
            'skip_detection' => false,
43
            'size_limit' => 16000000,
44
        ]);
45 1
        $resolver->setAllowedTypes('skip_detection', 'bool');
46 1
        $resolver->setAllowedTypes('size_limit', 'int');
47 1
        $options = $resolver->resolve($config);
48 1
        $this->skipDetection = $options['skip_detection'];
49 1
        $this->sizeLimit = $options['size_limit'];
50 1
    }
51
52
    /**
53
     * {@inheritdoc}
54
     */
55 1
    public function handleRequest(RequestInterface $request, callable $next)
56
    {
57 1
        if ($this->skipDetection || $request->hasHeader('Content-Type')) {
58
            return $next($request);
59
        }
60
61 1
        $stream = $request->getBody();
62 1
        $streamSize = $stream->getSize();
63
64 1
        if (empty($streamSize) || $streamSize >= $this->sizeLimit || !$stream->isSeekable()) {
65
            return $next($request);
66
        }
67
68 1
        if ($this->isJson($stream)) {
69 1
            $request = $request->withHeader('Content-Type', 'application/json');
70
71 1
            return $next($request);
72 1
        } elseif ($this->isXml($stream)) {
73 1
            $request = $request->withHeader('Content-Type', 'application/xml');
74
75 1
            return $next($request);
76
        }
77
78
        return $next($request);
79
    }
80
81
    /**
82
     * {@inheritdoc}
83
     */
84
    public function handleResponse(RequestInterface $request, ResponseInterface $response, callable $next)
85
    {
86
        return $next($request, $response);
87
    }
88
89 1
    private function isJson(StreamInterface $stream): bool
90
    {
91 1
        $stream->rewind();
92 1
        json_decode($stream->getContents());
93
94 1
        return JSON_ERROR_NONE === json_last_error();
95
    }
96
97 1
    private function isXml(StreamInterface $stream): bool
98
    {
99 1
        $stream->rewind();
100 1
        $previousValue = libxml_use_internal_errors(true);
101 1
        $isXml = simplexml_load_string($stream->getContents());
102 1
        libxml_use_internal_errors($previousValue);
103
104 1
        return false !== $isXml;
105
    }
106
}
107