1<?php
2/**
3 * Deal with importing all those nasty globals and things
4 *
5 * Copyright © 2003 Brion Vibber <brion@pobox.com>
6 * https://www.mediawiki.org/
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 * http://www.gnu.org/copyleft/gpl.html
22 *
23 * @file
24 */
25
26use MediaWiki\Session\SessionManager;
27
28/**
29 * WebRequest clone which takes values from a provided array.
30 *
31 * @newable
32 *
33 * @ingroup HTTP
34 */
35class FauxRequest extends WebRequest {
36	private $wasPosted = false;
37	private $requestUrl;
38	protected $cookies = [];
39	/** @var array */
40	private $uploadData = [];
41
42	/**
43	 * @stable to call
44	 *
45	 * @param array $data Array of *non*-urlencoded key => value pairs, the
46	 *   fake GET/POST values
47	 * @param bool $wasPosted Whether to treat the data as POST
48	 * @param MediaWiki\Session\Session|array|null $session Session, session
49	 *  data array, or null
50	 * @param string $protocol 'http' or 'https'
51	 * @throws MWException
52	 */
53	public function __construct( $data = [], $wasPosted = false,
54		$session = null, $protocol = 'http'
55	) {
56		$this->requestTime = microtime( true );
57
58		if ( is_array( $data ) ) {
59			$this->data = $data;
60		} else {
61			throw new MWException( "FauxRequest() got bogus data" );
62		}
63		$this->wasPosted = $wasPosted;
64		if ( $session instanceof MediaWiki\Session\Session ) {
65			$this->sessionId = $session->getSessionId();
66		} elseif ( is_array( $session ) ) {
67			$mwsession = SessionManager::singleton()->getEmptySession( $this );
68			$this->sessionId = $mwsession->getSessionId();
69			foreach ( $session as $key => $value ) {
70				$mwsession->set( $key, $value );
71			}
72		} elseif ( $session !== null ) {
73			throw new MWException( "FauxRequest() got bogus session" );
74		}
75		$this->protocol = $protocol;
76	}
77
78	/**
79	 * Initialise the header list
80	 */
81	protected function initHeaders() {
82		// Nothing to init
83	}
84
85	/**
86	 * @param string $name
87	 * @param string $default
88	 * @return string
89	 */
90	public function getText( $name, $default = '' ) {
91		# Override; don't recode since we're using internal data
92		return (string)$this->getVal( $name, $default );
93	}
94
95	/**
96	 * @return array
97	 */
98	public function getQueryValues() {
99		if ( $this->wasPosted ) {
100			return [];
101		} else {
102			return $this->data;
103		}
104	}
105
106	public function getMethod() {
107		return $this->wasPosted ? 'POST' : 'GET';
108	}
109
110	/**
111	 * @return bool
112	 */
113	public function wasPosted() {
114		return $this->wasPosted;
115	}
116
117	public function getCookie( $key, $prefix = null, $default = null ) {
118		if ( $prefix === null ) {
119			global $wgCookiePrefix;
120			$prefix = $wgCookiePrefix;
121		}
122		$name = $prefix . $key;
123		return $this->cookies[$name] ?? $default;
124	}
125
126	/**
127	 * @since 1.26
128	 * @param string $key Unprefixed name of the cookie to set
129	 * @param string|null $value Value of the cookie to set
130	 * @param string|null $prefix Cookie prefix. Defaults to $wgCookiePrefix
131	 */
132	public function setCookie( $key, $value, $prefix = null ) {
133		$this->setCookies( [ $key => $value ], $prefix );
134	}
135
136	/**
137	 * @since 1.26
138	 * @param array $cookies
139	 * @param string|null $prefix Cookie prefix. Defaults to $wgCookiePrefix
140	 */
141	public function setCookies( $cookies, $prefix = null ) {
142		if ( $prefix === null ) {
143			global $wgCookiePrefix;
144			$prefix = $wgCookiePrefix;
145		}
146		foreach ( $cookies as $key => $value ) {
147			$name = $prefix . $key;
148			$this->cookies[$name] = $value;
149		}
150	}
151
152	/**
153	 * Set fake upload data for all files
154	 *
155	 * @since 1.37
156	 * @param (array|WebRequestUpload)[] $uploadData
157	 */
158	public function setUploadData( $uploadData ) {
159		foreach ( $uploadData as $key => $data ) {
160			$this->setUpload( $key, $data );
161		}
162	}
163
164	/**
165	 * Set fake upload data for one file with specific key
166	 *
167	 * @since 1.37
168	 * @param string $key
169	 * @param array|WebRequestUpload $data
170	 */
171	public function setUpload( $key, $data ) {
172		if ( $data instanceof WebRequestUpload ) {
173			// cannot reuse WebRequestUpload, because it contains the original web request object
174			$data = [
175				'name' => $data->getName(),
176				'type' => $data->getType(),
177				'tmp_name' => $data->getTempName(),
178				'size' => $data->getSize(),
179				'error' => $data->getError(),
180			];
181		}
182		// Check if everything is provided
183		if ( !is_array( $data ) ||
184			array_diff( WebRequestUpload::REQUIRED_FILEINFO_KEYS, array_keys( $data ) ) !== []
185		) {
186			throw new MWException( __METHOD__ . ' got bogus data' );
187		}
188		$this->uploadData[$key] = $data;
189	}
190
191	/**
192	 * Return a FauxRequestUpload object corresponding to the key
193	 *
194	 * @param string $key
195	 * @return FauxRequestUpload
196	 */
197	public function getUpload( $key ) {
198		return new FauxRequestUpload( $this->uploadData, $this, $key );
199	}
200
201	/**
202	 * @since 1.25
203	 * @param string $url
204	 */
205	public function setRequestURL( $url ) {
206		$this->requestUrl = $url;
207	}
208
209	/**
210	 * @since 1.25 MWException( "getRequestURL not implemented" )
211	 * no longer thrown.
212	 * @return string
213	 */
214	public function getRequestURL() {
215		if ( $this->requestUrl === null ) {
216			throw new MWException( 'Request URL not set' );
217		}
218		return $this->requestUrl;
219	}
220
221	public function getProtocol() {
222		return $this->protocol;
223	}
224
225	/**
226	 * @param string $name
227	 * @param string $val
228	 */
229	public function setHeader( $name, $val ) {
230		$this->setHeaders( [ $name => $val ] );
231	}
232
233	/**
234	 * @since 1.26
235	 * @param array $headers
236	 */
237	public function setHeaders( $headers ) {
238		foreach ( $headers as $name => $val ) {
239			$name = strtoupper( $name );
240			$this->headers[$name] = $val;
241		}
242	}
243
244	/**
245	 * @return array|null
246	 */
247	public function getSessionArray() {
248		if ( $this->sessionId !== null ) {
249			return iterator_to_array( $this->getSession() );
250		}
251		return null;
252	}
253
254	public function getPostValues() {
255		return $this->wasPosted ? $this->data : [];
256	}
257
258	/**
259	 * FauxRequests shouldn't depend on raw request data (but that could be implemented here)
260	 * @return string
261	 */
262	public function getRawQueryString() {
263		return '';
264	}
265
266	/**
267	 * FauxRequests shouldn't depend on raw request data (but that could be implemented here)
268	 * @return string
269	 */
270	public function getRawPostString() {
271		return '';
272	}
273
274	/**
275	 * FauxRequests shouldn't depend on raw request data (but that could be implemented here)
276	 * @return string
277	 */
278	public function getRawInput() {
279		return '';
280	}
281
282	/**
283	 * @codeCoverageIgnore
284	 * @return string
285	 */
286	protected function getRawIP() {
287		return '127.0.0.1';
288	}
289}
290