[TASK] Removes extra empty lines
[Packages/TYPO3.CMS.git] / typo3 / sysext / core / Tests / Unit / Http / MessageTest.php
1 <?php
2 namespace TYPO3\CMS\Core\Tests\Unit\Http;
3
4 /*
5 * This file is part of the TYPO3 CMS project.
6 *
7 * It is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License, either version 2
9 * of the License, or any later version.
10 *
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
13 *
14 * The TYPO3 project - inspiring people to share!
15 */
16
17 use TYPO3\CMS\Core\Http\Message;
18 use TYPO3\CMS\Core\Http\Stream;
19
20 /**
21 * Testcase for \TYPO3\CMS\Core\Http\Message
22 *
23 * Adapted from https://github.com/phly/http/
24 */
25 class MessageTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
26 {
27 /**
28 * @var Stream
29 */
30 protected $stream;
31
32 /**
33 * @var Message
34 */
35 protected $message;
36
37 protected function setUp()
38 {
39 $this->stream = new Stream('php://memory', 'wb+');
40 $this->message = (new Message())->withBody($this->stream);
41 }
42
43 /**
44 * @test
45 */
46 public function protocolHasAcceptableDefault()
47 {
48 $this->assertEquals('1.1', $this->message->getProtocolVersion());
49 }
50
51 /**
52 * @test
53 */
54 public function protocolMutatorReturnsCloneWithChanges()
55 {
56 $message = $this->message->withProtocolVersion('1.0');
57 $this->assertNotSame($this->message, $message);
58 $this->assertEquals('1.0', $message->getProtocolVersion());
59 }
60
61 /**
62 * @test
63 */
64 public function usesStreamProvidedInConstructorAsBody()
65 {
66 $this->assertSame($this->stream, $this->message->getBody());
67 }
68
69 /**
70 * @test
71 */
72 public function bodyMutatorReturnsCloneWithChanges()
73 {
74 $stream = new Stream('php://memory', 'wb+');
75 $message = $this->message->withBody($stream);
76 $this->assertNotSame($this->message, $message);
77 $this->assertSame($stream, $message->getBody());
78 }
79
80 /**
81 * @test
82 */
83 public function getHeaderReturnsHeaderValueAsArray()
84 {
85 $message = $this->message->withHeader('X-Foo', ['Foo', 'Bar']);
86 $this->assertNotSame($this->message, $message);
87 $this->assertEquals(['Foo', 'Bar'], $message->getHeader('X-Foo'));
88 }
89
90 /**
91 * @test
92 */
93 public function getHeaderLineReturnsHeaderValueAsCommaConcatenatedString()
94 {
95 $message = $this->message->withHeader('X-Foo', ['Foo', 'Bar']);
96 $this->assertNotSame($this->message, $message);
97 $this->assertEquals('Foo,Bar', $message->getHeaderLine('X-Foo'));
98 }
99
100 /**
101 * @test
102 */
103 public function getHeadersKeepsHeaderCaseSensitivity()
104 {
105 $message = $this->message->withHeader('X-Foo', ['Foo', 'Bar']);
106 $this->assertNotSame($this->message, $message);
107 $this->assertEquals(['X-Foo' => ['Foo', 'Bar']], $message->getHeaders());
108 }
109
110 /**
111 * @test
112 */
113 public function getHeadersReturnsCaseWithWhichHeaderFirstRegistered()
114 {
115 $message = $this->message
116 ->withHeader('X-Foo', 'Foo')
117 ->withAddedHeader('x-foo', 'Bar');
118 $this->assertNotSame($this->message, $message);
119 $this->assertEquals(['X-Foo' => ['Foo', 'Bar']], $message->getHeaders());
120 }
121
122 /**
123 * @test
124 */
125 public function hasHeaderReturnsFalseIfHeaderIsNotPresent()
126 {
127 $this->assertFalse($this->message->hasHeader('X-Foo'));
128 }
129
130 /**
131 * @test
132 */
133 public function hasHeaderReturnsTrueIfHeaderIsPresent()
134 {
135 $message = $this->message->withHeader('X-Foo', 'Foo');
136 $this->assertNotSame($this->message, $message);
137 $this->assertTrue($message->hasHeader('X-Foo'));
138 }
139
140 /**
141 * @test
142 */
143 public function addHeaderAppendsToExistingHeader()
144 {
145 $message = $this->message->withHeader('X-Foo', 'Foo');
146 $this->assertNotSame($this->message, $message);
147 $message2 = $message->withAddedHeader('X-Foo', 'Bar');
148 $this->assertNotSame($message, $message2);
149 $this->assertEquals('Foo,Bar', $message2->getHeaderLine('X-Foo'));
150 }
151
152 /**
153 * @test
154 */
155 public function canRemoveHeaders()
156 {
157 $message = $this->message->withHeader('X-Foo', 'Foo');
158 $this->assertNotSame($this->message, $message);
159 $this->assertTrue($message->hasHeader('x-foo'));
160 $message2 = $message->withoutHeader('x-foo');
161 $this->assertNotSame($this->message, $message2);
162 $this->assertNotSame($message, $message2);
163 $this->assertFalse($message2->hasHeader('X-Foo'));
164 }
165
166 /**
167 * @test
168 */
169 public function headerRemovalIsCaseInsensitive()
170 {
171 $message = $this->message
172 ->withHeader('X-Foo', 'Foo')
173 ->withAddedHeader('x-foo', 'Bar')
174 ->withAddedHeader('X-FOO', 'Baz');
175 $this->assertNotSame($this->message, $message);
176 $this->assertTrue($message->hasHeader('x-foo'));
177 $message2 = $message->withoutHeader('x-foo');
178 $this->assertNotSame($this->message, $message2);
179 $this->assertNotSame($message, $message2);
180 $this->assertFalse($message2->hasHeader('X-Foo'));
181 $headers = $message2->getHeaders();
182 $this->assertEquals(0, count($headers));
183 }
184
185 /**
186 * @return array
187 */
188 public function invalidGeneralHeaderValuesDataProvider()
189 {
190 return [
191 'null' => [null],
192 'true' => [true],
193 'false' => [false],
194 'int' => [1],
195 'float' => [1.1],
196 'array' => [['foo' => ['bar']]],
197 'object' => [(object) ['foo' => 'bar']],
198 ];
199 }
200
201 /**
202 * @dataProvider invalidGeneralHeaderValuesDataProvider
203 */
204 public function testWithHeaderRaisesExceptionForInvalidNestedHeaderValue($value)
205 {
206 $this->setExpectedException('InvalidArgumentException', 'Invalid header value');
207 $message = $this->message->withHeader('X-Foo', [$value]);
208 }
209
210 /**
211 * @return array
212 */
213 public function invalidHeaderValuesDataProvider()
214 {
215 return [
216 'null' => [null],
217 'true' => [true],
218 'false' => [false],
219 'int' => [1],
220 'float' => [1.1],
221 'object' => [(object) ['foo' => 'bar']],
222 ];
223 }
224
225 /**
226 * @dataProvider invalidHeaderValuesDataProvider
227 */
228 public function withHeaderRaisesExceptionForInvalidValueType($value)
229 {
230 $this->setExpectedException('InvalidArgumentException', 'Invalid header value');
231 $message = $this->message->withHeader('X-Foo', $value);
232 }
233
234 /**
235 * @dataProvider invalidHeaderValuesDataProvider
236 */
237 public function withAddedHeaderRaisesExceptionForNonStringNonArrayValue($value)
238 {
239 $this->setExpectedException('InvalidArgumentException', 'must be a string');
240 $message = $this->message->withAddedHeader('X-Foo', $value);
241 }
242
243 /**
244 * @test
245 */
246 public function withoutHeaderDoesNothingIfHeaderDoesNotExist()
247 {
248 $this->assertFalse($this->message->hasHeader('X-Foo'));
249 $message = $this->message->withoutHeader('X-Foo');
250 $this->assertNotSame($this->message, $message);
251 $this->assertFalse($message->hasHeader('X-Foo'));
252 }
253
254 /**
255 * @test
256 */
257 public function getHeaderReturnsAnEmptyArrayWhenHeaderDoesNotExist()
258 {
259 $this->assertSame([], $this->message->getHeader('X-Foo-Bar'));
260 }
261
262 /**
263 * @test
264 */
265 public function getHeaderLineReturnsEmptyStringWhenHeaderDoesNotExist()
266 {
267 $this->assertSame('', $this->message->getHeaderLine('X-Foo-Bar'));
268 }
269
270 /**
271 * @return array
272 */
273 public function headersWithInjectionVectorsDataProvider()
274 {
275 return [
276 'name-with-cr' => ["X-Foo\r-Bar", 'value'],
277 'name-with-lf' => ["X-Foo\n-Bar", 'value'],
278 'name-with-crlf' => ["X-Foo\r\n-Bar", 'value'],
279 'name-with-2crlf' => ["X-Foo\r\n\r\n-Bar", 'value'],
280 'value-with-cr' => ['X-Foo-Bar', "value\rinjection"],
281 'value-with-lf' => ['X-Foo-Bar', "value\ninjection"],
282 'value-with-crlf' => ['X-Foo-Bar', "value\r\ninjection"],
283 'value-with-2crlf' => ['X-Foo-Bar', "value\r\n\r\ninjection"],
284 'array-value-with-cr' => ['X-Foo-Bar', ["value\rinjection"]],
285 'array-value-with-lf' => ['X-Foo-Bar', ["value\ninjection"]],
286 'array-value-with-crlf' => ['X-Foo-Bar', ["value\r\ninjection"]],
287 'array-value-with-2crlf' => ['X-Foo-Bar', ["value\r\n\r\ninjection"]],
288 ];
289 }
290
291 /**
292 * @dataProvider headersWithInjectionVectorsDataProvider
293 * @test
294 */
295 public function doesNotAllowCRLFInjectionWhenCallingWithHeader($name, $value)
296 {
297 $this->setExpectedException('InvalidArgumentException');
298 $this->message->withHeader($name, $value);
299 }
300
301 /**
302 * @dataProvider headersWithInjectionVectorsDataProvider
303 * @test
304 */
305 public function doesNotAllowCRLFInjectionWhenCallingWithAddedHeader($name, $value)
306 {
307 $this->setExpectedException('InvalidArgumentException');
308 $this->message->withAddedHeader($name, $value);
309 }
310
311 /**
312 * @test
313 */
314 public function testWithHeaderAllowsHeaderContinuations()
315 {
316 $message = $this->message->withHeader('X-Foo-Bar', "value,\r\n second value");
317 $this->assertEquals("value,\r\n second value", $message->getHeaderLine('X-Foo-Bar'));
318 }
319
320 /**
321 * @test
322 */
323 public function testWithAddedHeaderAllowsHeaderContinuations()
324 {
325 $message = $this->message->withAddedHeader('X-Foo-Bar', "value,\r\n second value");
326 $this->assertEquals("value,\r\n second value", $message->getHeaderLine('X-Foo-Bar'));
327 }
328 }