Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
81.82% covered (warning)
81.82%
18 / 22
33.33% covered (danger)
33.33%
1 / 3
CRAP
0.00% covered (danger)
0.00%
0 / 1
RequestBody
81.82% covered (warning)
81.82%
18 / 22
33.33% covered (danger)
33.33%
1 / 3
12.87
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 json
83.33% covered (warning)
83.33%
5 / 6
0.00% covered (danger)
0.00%
0 / 1
3.04
 raw
80.00% covered (warning)
80.00%
12 / 15
0.00% covered (danger)
0.00%
0 / 1
8.51
1<?php
2
3declare(strict_types=1);
4
5namespace LambdaTwelve\OneRecord\Server\Http;
6
7use LambdaTwelve\OneRecord\JsonLd\Json;
8use LambdaTwelve\OneRecord\JsonLd\JsonLdException;
9use Psr\Http\Message\ServerRequestInterface;
10
11/**
12 * Reads a JSON-LD body within the configured size limit. The limit is checked
13 * against Content-Length first and enforced while reading, so a body without
14 * a length header cannot exhaust memory either.
15 */
16final class RequestBody
17{
18    public function __construct(private readonly int $maxBytes) {}
19
20    /**
21     * @return array<string, mixed>
22     */
23    public function json(ServerRequestInterface $request): array
24    {
25        $raw = $this->raw($request);
26        if (trim($raw) === '') {
27            throw HttpException::badRequest('The request body is missing.');
28        }
29        try {
30            return Json::decodeObject($raw);
31        } catch (JsonLdException $e) {
32            throw HttpException::badRequest($e->getMessage());
33        }
34    }
35
36    public function raw(ServerRequestInterface $request): string
37    {
38        $declared = $request->getHeaderLine('Content-Length');
39        if ($declared !== '' && is_numeric($declared) && (int) $declared > $this->maxBytes) {
40            throw HttpException::payloadTooLarge($this->maxBytes);
41        }
42        $stream = $request->getBody();
43        if ($stream->isSeekable()) {
44            $stream->rewind();
45        }
46        $body = '';
47        while (!$stream->eof()) {
48            $chunk = $stream->read(8192);
49            if ($chunk === '') {
50                break;
51            }
52            $body .= $chunk;
53            if (\strlen($body) > $this->maxBytes) {
54                throw HttpException::payloadTooLarge($this->maxBytes);
55            }
56        }
57
58        return $body;
59    }
60}