Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
53.85% covered (warning)
53.85%
21 / 39
47.06% covered (danger)
47.06%
8 / 17
CRAP
0.00% covered (danger)
0.00%
0 / 1
RequestBase
53.85% covered (warning)
53.85%
21 / 39
47.06% covered (danger)
47.06%
8 / 17
92.46
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
 initHeaders
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 __clone
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
6
 setHeaders
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 getHeaders
66.67% covered (warning)
66.67%
2 / 3
0.00% covered (danger)
0.00%
0 / 1
2.15
 getHeader
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
6
 hasHeader
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
6
 getHeaderLine
66.67% covered (warning)
66.67%
2 / 3
0.00% covered (danger)
0.00%
0 / 1
2.15
 setPathParams
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getPathParams
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getPathParam
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getCookiePrefix
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getCookie
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
2
 getParsedBody
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 setParsedBody
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getBodyType
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
6
 hasBody
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
3
1<?php
2
3namespace MediaWiki\Rest;
4
5/**
6 * Shared code between RequestData and RequestFromGlobals
7 */
8abstract class RequestBase implements RequestInterface {
9    /**
10     * @var HeaderContainer|null
11     */
12    private $headerCollection;
13
14    /** @var array */
15    private $pathParams = [];
16
17    /** @var string */
18    private $cookiePrefix;
19
20    protected ?array $parsedBody = null;
21
22    /**
23     * @internal
24     * @param string $cookiePrefix
25     */
26    public function __construct( $cookiePrefix ) {
27        $this->cookiePrefix = $cookiePrefix;
28    }
29
30    /**
31     * Override this in the implementation class if lazy initialisation of
32     * header values is desired. It should call setHeaders().
33     *
34     * @internal
35     */
36    protected function initHeaders() {
37    }
38
39    public function __clone() {
40        if ( $this->headerCollection !== null ) {
41            $this->headerCollection = clone $this->headerCollection;
42        }
43    }
44
45    /**
46     * Erase any existing headers and replace them with the specified header
47     * lines.
48     *
49     * Call this either from the constructor or from initHeaders() of the
50     * implementing class.
51     *
52     * @internal
53     * @param string[] $headers The header lines
54     */
55    public function setHeaders( $headers ) {
56        $this->headerCollection = new HeaderContainer;
57        $this->headerCollection->resetHeaders( $headers );
58    }
59
60    public function getHeaders() {
61        if ( $this->headerCollection === null ) {
62            $this->initHeaders();
63        }
64        return $this->headerCollection->getHeaders();
65    }
66
67    public function getHeader( $name ) {
68        if ( $this->headerCollection === null ) {
69            $this->initHeaders();
70        }
71        return $this->headerCollection->getHeader( $name );
72    }
73
74    public function hasHeader( $name ) {
75        if ( $this->headerCollection === null ) {
76            $this->initHeaders();
77        }
78        return $this->headerCollection->hasHeader( $name );
79    }
80
81    public function getHeaderLine( $name ) {
82        if ( $this->headerCollection === null ) {
83            $this->initHeaders();
84        }
85        return $this->headerCollection->getHeaderLine( $name );
86    }
87
88    public function setPathParams( $params ) {
89        $this->pathParams = $params;
90    }
91
92    public function getPathParams() {
93        return $this->pathParams;
94    }
95
96    public function getPathParam( $name ) {
97        return $this->pathParams[$name] ?? null;
98    }
99
100    public function getCookiePrefix() {
101        return $this->cookiePrefix;
102    }
103
104    public function getCookie( $name, $default = null ) {
105        $cookies = $this->getCookieParams();
106        $prefixedName = $this->getCookiePrefix() . $name;
107        if ( array_key_exists( $prefixedName, $cookies ) ) {
108            return $cookies[$prefixedName];
109        } else {
110            return $default;
111        }
112    }
113
114    public function getParsedBody(): ?array {
115        return $this->parsedBody;
116    }
117
118    public function setParsedBody( ?array $data ) {
119        $this->parsedBody = $data;
120    }
121
122    public function getBodyType(): ?string {
123        [ $ct ] = explode( ';', $this->getHeaderLine( 'Content-Type' ), 2 );
124        $ct = strtolower( trim( $ct ) );
125
126        if ( $ct === '' ) {
127            return null;
128        }
129        return $ct;
130    }
131
132    /**
133     * Return true if the client provided a content-length header or a
134     * transfer-encoding header.
135     *
136     * @see https://www.rfc-editor.org/rfc/rfc9110.html#name-content-length
137     *
138     * @return bool
139     */
140    public function hasBody(): bool {
141        // From RFC9110, section 8.6: A user agent SHOULD send Content-Length
142        // in a request when the method defines a meaning for enclosed content
143        // and it is not sending Transfer-Encoding. [...]
144        // A user agent SHOULD NOT send a Content-Length header field when the
145        // request message does not contain content and the method semantics do
146        // not anticipate such data.
147
148        if ( $this->getHeaderLine( 'content-length' ) !== '' ) {
149            // If a content length is set, there is a body
150            return true;
151        }
152
153        if ( $this->getHeaderLine( 'transfer-encoding' ) !== '' ) {
154            // If a transfer encoding is set, there is a body
155            return true;
156        }
157
158        return false;
159    }
160
161}