Passed
Push — master ( 859d10...cb36d3 )
by Chris
07:07
created

ResourceServlet::sendHeaders()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 0
Metric Value
cc 3
eloc 5
nc 4
nop 1
dl 0
loc 10
ccs 0
cts 8
cp 0
crap 12
rs 9.4285
c 0
b 0
f 0
1
<?php declare(strict_types=1);
2
3
namespace DaveRandom\Resume;
4
5
final class ResourceServlet
6
{
7
    /**
8
     * @var \DaveRandom\Resume\Resource
9
     */
10
    private $resource;
11
12
    /**
13
     * Generate the default response headers for this resource
14
     *
15
     * @return string[]
16
     */
17
    private function generateDefaultHeaders(): array
18
    {
19
        $ranges = $this->resource instanceof RangeUnitProvider
20
            ? \implode(',', $this->resource->getRangeUnits())
21
            : 'bytes';
22
23
        if ($ranges === '') {
24
            $ranges = 'none';
25
        }
26
27
        return [
28
            'content-type' => $this->resource->getMimeType(),
29
            'content-length' => (string)$this->resource->getLength(),
30
            'accept-ranges' => $ranges,
31
        ];
32
    }
33
34
    /**
35
     * Send the headers that are included regardless of whether a range was requested
36
     *
37
     * @param OutputWriter $outputWriter
38
     */
39
    private function sendHeaders(OutputWriter $outputWriter): void
40
    {
41
        $headers = $this->generateDefaultHeaders();
42
43
        foreach ($this->resource->getAdditionalHeaders() as $name => $value) {
44
            $headers[\strtolower($name)] = $value;
45
        }
46
47
        foreach ($headers as $name => $value) {
48
            $outputWriter->sendHeader(\trim($name), \trim($value));
49
        }
50
    }
51
52
    /**
53
     * Create a Content-Range header corresponding to the specified unit and ranges
54
     *
55
     * @param string $unit
56
     * @param Range[] $ranges
57
     * @param int $size
58
     * @return string
59
     */
60
    public function getContentRangeHeader(string $unit, array $ranges, int $size): string
61
    {
62
        return $unit . ' ' . \implode(',', $ranges) . '/' . $size;
63
    }
64
65
    public function __construct(Resource $resource)
66
    {
67
        $this->resource = $resource;
68
    }
69
70
    /**
71
     * Send data from a file based on the current Range header
72
     *
73
     * @param RangeSet|null $rangeSet Range header on which the transmission will be based
74
     * @param OutputWriter|null $outputWriter Output writer via which resource will be sent
75
     */
76
    public function sendResource(RangeSet $rangeSet = null, OutputWriter $outputWriter = null): void
77
    {
78
        $outputWriter = $outputWriter ?? new DefaultOutputWriter();
79
80
        if ($rangeSet === null) {
81
            // No ranges requested, just send the whole file
82
            $outputWriter->setResponseCode(200);
83
            $this->sendHeaders($outputWriter);
84
            $this->resource->sendData($outputWriter);
85
86
            return;
87
        }
88
89
        // Send the requested ranges
90
        $size = $this->resource->getLength();
91
        $ranges = $rangeSet->getRangesForSize($size);
92
93
        $outputWriter->setResponseCode(206);
94
        $this->sendHeaders($outputWriter);
95
        $outputWriter->sendHeader('Content-Range', $this->getContentRangeHeader($rangeSet->getUnit(), $ranges, $size));
96
97
        foreach ($ranges as $range) {
98
            $this->resource->sendData($outputWriter, $range);
99
        }
100
    }
101
}
102