Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
11 / 11
100.00% covered (success)
100.00%
2 / 2
CRAP
100.00% covered (success)
100.00%
1 / 1
IcapRequest
100.00% covered (success)
100.00%
11 / 11
100.00% covered (success)
100.00%
2 / 2
2
100.00% covered (success)
100.00%
1 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 withHeader
100.00% covered (success)
100.00%
10 / 10
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3/**
4 * SPDX-License-Identifier: EUPL-1.2
5 *
6 * This file is part of icap-flow.
7 *
8 * Licensed under the EUPL, Version 1.2 only (the "Licence");
9 * you may not use this work except in compliance with the Licence.
10 * You may obtain a copy of the Licence at:
11 *
12 *     https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
13 *
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the Licence is distributed on an "AS IS" basis,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 */
18
19declare(strict_types=1);
20
21namespace Ndrstmr\Icap\DTO;
22
23/**
24 * Immutable data object representing an ICAP request.
25 *
26 * An ICAP request is an ICAP envelope (method/URI/ICAP-headers) that
27 * optionally carries a single encapsulated HTTP request (REQMOD) or a
28 * single encapsulated HTTP response (RESPMOD), per RFC 3507 §4.4.
29 *
30 * Rendering into wire bytes is the {@see \Ndrstmr\Icap\RequestFormatter}'s
31 * job; this class is a pure value object.
32 */
33final readonly class IcapRequest
34{
35    /** @var array<string, string[]> */
36    public array $headers;
37
38    /**
39     * @param string                  $method               ICAP method (OPTIONS, REQMOD, RESPMOD)
40     * @param string                  $uri                  Fully-qualified ICAP URI, e.g. icap://host:1344/service
41     * @param array<string, string|string[]> $headers       ICAP headers (Host is filled in from $uri when missing);
42     *                                                       scalar values are promoted to a one-element list
43     * @param HttpRequest|null        $encapsulatedRequest  Encapsulated HTTP request (REQMOD)
44     * @param HttpResponse|null       $encapsulatedResponse Encapsulated HTTP response (RESPMOD)
45     * @param bool                    $previewIsComplete    When true, the body attached to the encapsulated HTTP
46     *                                                      message represents the complete payload in a preview
47     *                                                      scenario, so the terminator must be `0; ieof\r\n\r\n`
48     *                                                      rather than `0\r\n\r\n` (RFC 3507 §4.5).
49     */
50    public function __construct(
51        public string $method,
52        public string $uri = '/',
53        array $headers = [],
54        public ?HttpRequest $encapsulatedRequest = null,
55        public ?HttpResponse $encapsulatedResponse = null,
56        public bool $previewIsComplete = false,
57    ) {
58        $this->headers = array_map(fn ($v) => (array) $v, $headers);
59    }
60
61    /**
62     * @param string|string[] $value
63     */
64    public function withHeader(string $name, string|array $value): self
65    {
66        $headers = $this->headers;
67        $headers[$name] = (array) $value;
68
69        return new self(
70            $this->method,
71            $this->uri,
72            $headers,
73            $this->encapsulatedRequest,
74            $this->encapsulatedResponse,
75            $this->previewIsComplete,
76        );
77    }
78}