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    /** @inheritDoc */
61    public function getHeaders() {
62        if ( $this->headerCollection === null ) {
63            $this->initHeaders();
64        }
65        return $this->headerCollection->getHeaders();
66    }
67
68    /** @inheritDoc */
69    public function getHeader( $name ) {
70        if ( $this->headerCollection === null ) {
71            $this->initHeaders();
72        }
73        return $this->headerCollection->getHeader( $name );
74    }
75
76    /** @inheritDoc */
77    public function hasHeader( $name ) {
78        if ( $this->headerCollection === null ) {
79            $this->initHeaders();
80        }
81        return $this->headerCollection->hasHeader( $name );
82    }
83
84    /** @inheritDoc */
85    public function getHeaderLine( $name ) {
86        if ( $this->headerCollection === null ) {
87            $this->initHeaders();
88        }
89        return $this->headerCollection->getHeaderLine( $name );
90    }
91
92    /** @inheritDoc */
93    public function setPathParams( $params ) {
94        $this->pathParams = $params;
95    }
96
97    /** @inheritDoc */
98    public function getPathParams() {
99        return $this->pathParams;
100    }
101
102    /** @inheritDoc */
103    public function getPathParam( $name ) {
104        return $this->pathParams[$name] ?? null;
105    }
106
107    /** @inheritDoc */
108    public function getCookiePrefix() {
109        return $this->cookiePrefix;
110    }
111
112    /** @inheritDoc */
113    public function getCookie( $name, $default = null ) {
114        $cookies = $this->getCookieParams();
115        $prefixedName = $this->getCookiePrefix() . $name;
116        if ( array_key_exists( $prefixedName, $cookies ) ) {
117            return $cookies[$prefixedName];
118        } else {
119            return $default;
120        }
121    }
122
123    public function getParsedBody(): ?array {
124        return $this->parsedBody;
125    }
126
127    public function setParsedBody( ?array $data ) {
128        $this->parsedBody = $data;
129    }
130
131    public function getBodyType(): ?string {
132        [ $ct ] = explode( ';', $this->getHeaderLine( 'Content-Type' ), 2 );
133        $ct = strtolower( trim( $ct ) );
134
135        if ( $ct === '' ) {
136            return null;
137        }
138        return $ct;
139    }
140
141    /**
142     * Return true if the client provided a content-length header or a
143     * transfer-encoding header.
144     *
145     * @see https://www.rfc-editor.org/rfc/rfc9110.html#name-content-length
146     *
147     * @return bool
148     */
149    public function hasBody(): bool {
150        // From RFC9110, section 8.6: A user agent SHOULD send Content-Length
151        // in a request when the method defines a meaning for enclosed content
152        // and it is not sending Transfer-Encoding. [...]
153        // A user agent SHOULD NOT send a Content-Length header field when the
154        // request message does not contain content and the method semantics do
155        // not anticipate such data.
156
157        if ( $this->getHeaderLine( 'content-length' ) !== '' ) {
158            // If a content length is set, there is a body
159            return true;
160        }
161
162        if ( $this->getHeaderLine( 'transfer-encoding' ) !== '' ) {
163            // If a transfer encoding is set, there is a body
164            return true;
165        }
166
167        return false;
168    }
169
170}