1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace SilverStripe\Control\Tests; |
4
|
|
|
|
5
|
|
|
use ReflectionMethod; |
6
|
|
|
use SilverStripe\Control\HTTPRequest; |
7
|
|
|
use SilverStripe\Control\Middleware\TrustedProxyMiddleware; |
8
|
|
|
use SilverStripe\Control\Session; |
9
|
|
|
use SilverStripe\Dev\SapphireTest; |
10
|
|
|
|
11
|
|
|
class HTTPRequestTest extends SapphireTest |
12
|
|
|
{ |
13
|
|
|
protected static $fixture_file = null; |
14
|
|
|
|
15
|
|
|
public function testMatch() |
16
|
|
|
{ |
17
|
|
|
$request = new HTTPRequest("GET", "admin/crm/add"); |
18
|
|
|
|
19
|
|
|
/* When a rule matches, but has no variables, array("_matched" => true) is returned. */ |
20
|
|
|
$this->assertEquals(["_matched" => true], $request->match('admin/crm', true)); |
21
|
|
|
|
22
|
|
|
/* Becasue we shifted admin/crm off the stack, just "add" should be remaining */ |
23
|
|
|
$this->assertEquals("add", $request->remaining()); |
24
|
|
|
|
25
|
|
|
$this->assertEquals(["_matched" => true], $request->match('add', true)); |
26
|
|
|
} |
27
|
|
|
|
28
|
|
|
/** |
29
|
|
|
* @useDatabase false |
30
|
|
|
*/ |
31
|
|
|
public function testWildCardMatch() |
32
|
|
|
{ |
33
|
|
|
$request = new HTTPRequest('GET', 'admin/crm/test'); |
34
|
|
|
$this->assertEquals(['$1' => 'crm', '$2' => 'test'], $request->match('admin/$@', true)); |
35
|
|
|
$this->assertTrue($request->allParsed()); |
36
|
|
|
|
37
|
|
|
$request = new HTTPRequest('GET', 'admin/crm/test'); |
38
|
|
|
$this->assertEquals(['_matched' => true], $request->match('admin/$*', true)); |
39
|
|
|
$this->assertTrue($request->allParsed()); |
40
|
|
|
$this->assertEquals('crm/test', $request->remaining()); |
41
|
|
|
|
42
|
|
|
$request = new HTTPRequest('GET', 'admin/crm/test/part1/part2'); |
43
|
|
|
$this->assertEquals(['Action' => 'crm', '$1' => 'test', '$2' => 'part1', '$3' => 'part2'], $request->match('admin/$Action/$@', true)); |
44
|
|
|
$this->assertTrue($request->allParsed()); |
45
|
|
|
|
46
|
|
|
$request = new HTTPRequest('GET', 'admin/crm/test/part1/part2'); |
47
|
|
|
$this->assertEquals(['Action' => 'crm'], $request->match('admin/$Action/$*', true)); |
48
|
|
|
$this->assertTrue($request->allParsed()); |
49
|
|
|
$this->assertEquals('test/part1/part2', $request->remaining()); |
50
|
|
|
} |
51
|
|
|
|
52
|
|
|
/** |
53
|
|
|
* This test just asserts a warning is given if there is more than one wildcard parameter. Note that this isn't an |
54
|
|
|
* enforcement of an API and we an add new behaviour in the future to allow many wildcard params if we want to |
55
|
|
|
* |
56
|
|
|
* @expectedException \PHPUnit_Framework_Error_Warning |
57
|
|
|
*/ |
58
|
|
|
public function testWildCardWithFurtherParams() |
59
|
|
|
{ |
60
|
|
|
$request = new HTTPRequest('GET', 'admin/crm/test'); |
61
|
|
|
// all parameters after the first wildcard parameter are ignored |
62
|
|
|
$request->match('admin/$Action/$@/$Other/$*', true); |
63
|
|
|
} |
64
|
|
|
|
65
|
|
|
public function testHttpMethodOverrides() |
66
|
|
|
{ |
67
|
|
|
$request = new HTTPRequest( |
68
|
|
|
'GET', |
69
|
|
|
'admin/crm' |
70
|
|
|
); |
71
|
|
|
$this->assertTrue( |
72
|
|
|
$request->isGET(), |
73
|
|
|
'GET with no method override' |
74
|
|
|
); |
75
|
|
|
|
76
|
|
|
$request = new HTTPRequest( |
77
|
|
|
'POST', |
78
|
|
|
'admin/crm' |
79
|
|
|
); |
80
|
|
|
$this->assertTrue( |
81
|
|
|
$request->isPOST(), |
82
|
|
|
'POST with no method override' |
83
|
|
|
); |
84
|
|
|
|
85
|
|
|
$request = new HTTPRequest( |
86
|
|
|
'GET', |
87
|
|
|
'admin/crm', |
88
|
|
|
['_method' => 'DELETE'] |
89
|
|
|
); |
90
|
|
|
$this->assertTrue( |
91
|
|
|
$request->isGET(), |
92
|
|
|
'GET with invalid POST method override' |
93
|
|
|
); |
94
|
|
|
|
95
|
|
|
$request = new HTTPRequest( |
96
|
|
|
'POST', |
97
|
|
|
'admin/crm', |
98
|
|
|
[], |
99
|
|
|
['_method' => 'DELETE'] |
100
|
|
|
); |
101
|
|
|
|
102
|
|
|
$this->assertTrue( |
103
|
|
|
$request->isPOST(), |
104
|
|
|
'_method override is no longer honored' |
105
|
|
|
); |
106
|
|
|
|
107
|
|
|
$this->assertFalse( |
108
|
|
|
$request->isDELETE(), |
109
|
|
|
'DELETE _method override is not honored' |
110
|
|
|
); |
111
|
|
|
|
112
|
|
|
$request = new HTTPRequest( |
113
|
|
|
'POST', |
114
|
|
|
'admin/crm', |
115
|
|
|
[], |
116
|
|
|
['_method' => 'put'] |
117
|
|
|
); |
118
|
|
|
$this->assertFalse( |
119
|
|
|
$request->isPUT(), |
120
|
|
|
'PUT _method override is not honored' |
121
|
|
|
); |
122
|
|
|
|
123
|
|
|
$request = new HTTPRequest( |
124
|
|
|
'POST', |
125
|
|
|
'admin/crm', |
126
|
|
|
[], |
127
|
|
|
['_method' => 'head'] |
128
|
|
|
); |
129
|
|
|
$this->assertFalse( |
130
|
|
|
$request->isHEAD(), |
131
|
|
|
'HEAD _method override is not honored' |
132
|
|
|
); |
133
|
|
|
} |
134
|
|
|
|
135
|
|
|
public function detectMethodDataProvider() |
136
|
|
|
{ |
137
|
|
|
return [ |
138
|
|
|
'Plain POST request' => ['POST', [], 'POST'], |
139
|
|
|
'Plain GET request' => ['GET', [], 'GET'], |
140
|
|
|
'Plain DELETE request' => ['DELETE', [], 'DELETE'], |
141
|
|
|
'Plain PUT request' => ['PUT', [], 'PUT'], |
142
|
|
|
'Plain HEAD request' => ['HEAD', [], 'HEAD'], |
143
|
|
|
|
144
|
|
|
'Request with GET method override' => ['POST', ['_method' => 'GET'], 'GET'], |
145
|
|
|
'Request with HEAD method override' => ['POST', ['_method' => 'HEAD'], 'HEAD'], |
146
|
|
|
'Request with DELETE method override' => ['POST', ['_method' => 'DELETE'], 'DELETE'], |
147
|
|
|
'Request with PUT method override' => ['POST', ['_method' => 'PUT'], 'PUT'], |
148
|
|
|
'Request with POST method override' => ['POST', ['_method' => 'POST'], 'POST'], |
149
|
|
|
|
150
|
|
|
'Request with mixed case method override' => ['POST', ['_method' => 'gEt'], 'GET'] |
151
|
|
|
]; |
152
|
|
|
} |
153
|
|
|
|
154
|
|
|
/** |
155
|
|
|
* @dataProvider detectMethodDataProvider |
156
|
|
|
*/ |
157
|
|
|
public function testDetectMethod($realMethod, $post, $expected) |
158
|
|
|
{ |
159
|
|
|
$actual = HTTPRequest::detect_method($realMethod, $post); |
|
|
|
|
160
|
|
|
$this->assertEquals($expected, $actual); |
161
|
|
|
} |
162
|
|
|
|
163
|
|
|
/** |
164
|
|
|
* @expectedException PHPUnit_Framework_Error |
165
|
|
|
*/ |
166
|
|
|
public function testBadDetectMethod() |
167
|
|
|
{ |
168
|
|
|
HTTPRequest::detect_method('POST', ['_method' => 'Boom']); |
|
|
|
|
169
|
|
|
} |
170
|
|
|
|
171
|
|
|
public function setHttpMethodDataProvider() |
172
|
|
|
{ |
173
|
|
|
return [ |
174
|
|
|
'POST request' => ['POST','POST'], |
175
|
|
|
'GET request' => ['GET', 'GET'], |
176
|
|
|
'DELETE request' => ['DELETE', 'DELETE'], |
177
|
|
|
'PUT request' => ['PUT', 'PUT'], |
178
|
|
|
'HEAD request' => ['HEAD', 'HEAD'], |
179
|
|
|
'Mixed case POST' => ['gEt', 'GET'], |
180
|
|
|
]; |
181
|
|
|
} |
182
|
|
|
|
183
|
|
|
/** |
184
|
|
|
* @dataProvider setHttpMethodDataProvider |
185
|
|
|
*/ |
186
|
|
|
public function testSetHttpMethod($method, $expected) |
187
|
|
|
{ |
188
|
|
|
$request = new HTTPRequest('GET', '/hello'); |
189
|
|
|
$returnedRequest = $request->setHttpMethod($method); |
190
|
|
|
$this->assertEquals($expected, $request->httpMethod()); |
191
|
|
|
$this->assertEquals($request, $returnedRequest); |
192
|
|
|
} |
193
|
|
|
|
194
|
|
|
/** |
195
|
|
|
* @expectedException PHPUnit_Framework_Error |
196
|
|
|
*/ |
197
|
|
|
public function testBadSetHttpMethod() |
198
|
|
|
{ |
199
|
|
|
$request = new HTTPRequest('GET', '/hello'); |
200
|
|
|
$request->setHttpMethod('boom'); |
201
|
|
|
} |
202
|
|
|
|
203
|
|
|
public function testRequestVars() |
204
|
|
|
{ |
205
|
|
|
$getVars = [ |
206
|
|
|
'first' => 'a', |
207
|
|
|
'second' => 'b', |
208
|
|
|
]; |
209
|
|
|
$postVars = [ |
210
|
|
|
'third' => 'c', |
211
|
|
|
'fourth' => 'd', |
212
|
|
|
]; |
213
|
|
|
$requestVars = [ |
214
|
|
|
'first' => 'a', |
215
|
|
|
'second' => 'b', |
216
|
|
|
'third' => 'c', |
217
|
|
|
'fourth' => 'd', |
218
|
|
|
]; |
219
|
|
|
$request = new HTTPRequest( |
220
|
|
|
'POST', |
221
|
|
|
'admin/crm', |
222
|
|
|
$getVars, |
223
|
|
|
$postVars |
224
|
|
|
); |
225
|
|
|
$this->assertEquals( |
226
|
|
|
$requestVars, |
227
|
|
|
$request->requestVars(), |
228
|
|
|
'GET parameters should supplement POST parameters' |
229
|
|
|
); |
230
|
|
|
|
231
|
|
|
$getVars = [ |
232
|
|
|
'first' => 'a', |
233
|
|
|
'second' => 'b', |
234
|
|
|
]; |
235
|
|
|
$postVars = [ |
236
|
|
|
'first' => 'c', |
237
|
|
|
'third' => 'd', |
238
|
|
|
]; |
239
|
|
|
$requestVars = [ |
240
|
|
|
'first' => 'c', |
241
|
|
|
'second' => 'b', |
242
|
|
|
'third' => 'd', |
243
|
|
|
]; |
244
|
|
|
$request = new HTTPRequest( |
245
|
|
|
'POST', |
246
|
|
|
'admin/crm', |
247
|
|
|
$getVars, |
248
|
|
|
$postVars |
249
|
|
|
); |
250
|
|
|
$this->assertEquals( |
251
|
|
|
$requestVars, |
252
|
|
|
$request->requestVars(), |
253
|
|
|
'POST parameters should override GET parameters' |
254
|
|
|
); |
255
|
|
|
|
256
|
|
|
$getVars = [ |
257
|
|
|
'first' => [ |
258
|
|
|
'first' => 'a', |
259
|
|
|
], |
260
|
|
|
'second' => [ |
261
|
|
|
'second' => 'b', |
262
|
|
|
], |
263
|
|
|
]; |
264
|
|
|
$postVars = [ |
265
|
|
|
'first' => [ |
266
|
|
|
'first' => 'c', |
267
|
|
|
], |
268
|
|
|
'third' => [ |
269
|
|
|
'third' => 'd', |
270
|
|
|
], |
271
|
|
|
]; |
272
|
|
|
$requestVars = [ |
273
|
|
|
'first' => [ |
274
|
|
|
'first' => 'c', |
275
|
|
|
], |
276
|
|
|
'second' => [ |
277
|
|
|
'second' => 'b', |
278
|
|
|
], |
279
|
|
|
'third' => [ |
280
|
|
|
'third' => 'd', |
281
|
|
|
], |
282
|
|
|
]; |
283
|
|
|
$request = new HTTPRequest( |
284
|
|
|
'POST', |
285
|
|
|
'admin/crm', |
286
|
|
|
$getVars, |
287
|
|
|
$postVars |
288
|
|
|
); |
289
|
|
|
$this->assertEquals( |
290
|
|
|
$requestVars, |
291
|
|
|
$request->requestVars(), |
292
|
|
|
'Nested POST parameters should override GET parameters' |
293
|
|
|
); |
294
|
|
|
|
295
|
|
|
$getVars = [ |
296
|
|
|
'first' => [ |
297
|
|
|
'first' => 'a', |
298
|
|
|
], |
299
|
|
|
'second' => [ |
300
|
|
|
'second' => 'b', |
301
|
|
|
], |
302
|
|
|
]; |
303
|
|
|
$postVars = [ |
304
|
|
|
'first' => [ |
305
|
|
|
'second' => 'c', |
306
|
|
|
], |
307
|
|
|
'third' => [ |
308
|
|
|
'third' => 'd', |
309
|
|
|
], |
310
|
|
|
]; |
311
|
|
|
$requestVars = [ |
312
|
|
|
'first' => [ |
313
|
|
|
'first' => 'a', |
314
|
|
|
'second' => 'c', |
315
|
|
|
], |
316
|
|
|
'second' => [ |
317
|
|
|
'second' => 'b', |
318
|
|
|
], |
319
|
|
|
'third' => [ |
320
|
|
|
'third' => 'd', |
321
|
|
|
], |
322
|
|
|
]; |
323
|
|
|
$request = new HTTPRequest( |
324
|
|
|
'POST', |
325
|
|
|
'admin/crm', |
326
|
|
|
$getVars, |
327
|
|
|
$postVars |
328
|
|
|
); |
329
|
|
|
$this->assertEquals( |
330
|
|
|
$requestVars, |
331
|
|
|
$request->requestVars(), |
332
|
|
|
'Nested GET parameters should supplement POST parameters' |
333
|
|
|
); |
334
|
|
|
} |
335
|
|
|
|
336
|
|
|
public function testIsAjax() |
337
|
|
|
{ |
338
|
|
|
$req = new HTTPRequest('GET', '/', ['ajax' => 0]); |
339
|
|
|
$this->assertFalse($req->isAjax()); |
340
|
|
|
|
341
|
|
|
$req = new HTTPRequest('GET', '/', ['ajax' => 1]); |
342
|
|
|
$this->assertTrue($req->isAjax()); |
343
|
|
|
|
344
|
|
|
$req = new HTTPRequest('GET', '/'); |
345
|
|
|
$req->addHeader('X-Requested-With', 'XMLHttpRequest'); |
346
|
|
|
$this->assertTrue($req->isAjax()); |
347
|
|
|
} |
348
|
|
|
|
349
|
|
|
public function testGetURL() |
350
|
|
|
{ |
351
|
|
|
$req = new HTTPRequest('GET', '/'); |
352
|
|
|
$this->assertEquals('', $req->getURL()); |
353
|
|
|
|
354
|
|
|
$req = new HTTPRequest('GET', '/assets/somefile.gif'); |
355
|
|
|
$this->assertEquals('assets/somefile.gif', $req->getURL()); |
356
|
|
|
|
357
|
|
|
$req = new HTTPRequest('GET', '/home?test=1'); |
358
|
|
|
$this->assertEquals('home?test=1', $req->getURL(true)); |
359
|
|
|
$this->assertEquals('home', $req->getURL()); |
360
|
|
|
} |
361
|
|
|
|
362
|
|
|
public function testSetIPFromHeaderValue() |
363
|
|
|
{ |
364
|
|
|
$req = new TrustedProxyMiddleware(); |
365
|
|
|
$reflectionMethod = new ReflectionMethod($req, 'getIPFromHeaderValue'); |
366
|
|
|
$reflectionMethod->setAccessible(true); |
367
|
|
|
|
368
|
|
|
$headers = [ |
369
|
|
|
'80.79.208.21, 149.126.76.1, 10.51.0.68' => '80.79.208.21', |
370
|
|
|
'52.19.19.103, 10.51.0.49' => '52.19.19.103', |
371
|
|
|
'10.51.0.49, 52.19.19.103' => '52.19.19.103', |
372
|
|
|
'10.51.0.49' => '10.51.0.49', |
373
|
|
|
'127.0.0.1, 10.51.0.49' => '127.0.0.1', |
374
|
|
|
]; |
375
|
|
|
|
376
|
|
|
foreach ($headers as $header => $ip) { |
377
|
|
|
$this->assertEquals($ip, $reflectionMethod->invoke($req, $header)); |
378
|
|
|
} |
379
|
|
|
} |
380
|
|
|
|
381
|
|
|
public function testHasSession() |
382
|
|
|
{ |
383
|
|
|
$request = new HTTPRequest('GET', '/'); |
384
|
|
|
$this->assertFalse($request->hasSession()); |
385
|
|
|
|
386
|
|
|
$request->setSession($this->createMock(Session::class)); |
387
|
|
|
$this->assertTrue($request->hasSession()); |
388
|
|
|
} |
389
|
|
|
} |
390
|
|
|
|
This function has been deprecated. The supplier of the function has supplied an explanatory message.
The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.