Moved tests to maintenance - one directory less to care about when configuring access.
[lhc/web/wiklou.git] / maintenance / tests / HttpTest.php
1 <?php
2
3 class MockCookie extends Cookie {
4 public function canServeDomain($arg) { return parent::canServeDomain($arg); }
5 public function canServePath($arg) { return parent::canServePath($arg); }
6 public function isUnExpired() { return parent::isUnExpired(); }
7 }
8
9 class HttpTest extends PhpUnit_Framework_TestCase {
10 static $content;
11 static $headers;
12 static $has_curl;
13 static $has_fopen;
14 static $has_proxy = false;
15 static $proxy = "http://hulk:8080/";
16 var $test_geturl = array(
17 "http://www.example.com/",
18 "http://pecl.php.net/feeds/pkg_apc.rss",
19 "http://toolserver.org/~jan/poll/dev/main.php?page=wiki_output&id=3",
20 "http://meta.wikimedia.org/w/index.php?title=Interwiki_map&action=raw",
21 "http://www.mediawiki.org/w/api.php?action=query&list=categorymembers&cmtitle=Category:MediaWiki_hooks&format=php",
22 );
23 var $test_requesturl = array( "http://en.wikipedia.org/wiki/Special:Export/User:MarkAHershberger" );
24
25 var $test_posturl = array( "http://www.comp.leeds.ac.uk/cgi-bin/Perl/environment-example" => "review=test" );
26
27 function setup() {
28 putenv("http_proxy"); /* Remove any proxy env var, so curl doesn't get confused */
29 if ( is_array( self::$content ) ) {
30 return;
31 }
32 self::$has_curl = function_exists( 'curl_init' );
33 self::$has_fopen = wfIniGetBool( 'allow_url_fopen' );
34
35 if ( !file_exists("/usr/bin/curl") ) {
36 $this->markTestIncomplete("This test requires the curl binary at /usr/bin/curl. If you have curl, please file a bug on this test, or, better yet, provide a patch.");
37 }
38
39 $content = tempnam( wfTempDir(), "" );
40 $headers = tempnam( wfTempDir(), "" );
41 if ( !$content && !$headers ) {
42 die( "Couldn't create temp file!" );
43 }
44
45 // This probably isn't the best test for a proxy, but it works on my system!
46 system("curl -0 -o $content -s ".self::$proxy);
47 $out = file_get_contents( $content );
48 if( $out ) {
49 self::$has_proxy = true;
50 }
51
52 /* Maybe use wget instead of curl here ... just to use a different codebase? */
53 foreach ( $this->test_geturl as $u ) {
54 system( "curl -0 -s -D $headers '$u' -o $content" );
55 self::$content["GET $u"] = file_get_contents( $content );
56 self::$headers["GET $u"] = file_get_contents( $headers );
57 }
58 foreach ( $this->test_requesturl as $u ) {
59 system( "curl -0 -s -X POST -H 'Content-Length: 0' -D $headers '$u' -o $content" );
60 self::$content["POST $u"] = file_get_contents( $content );
61 self::$headers["POST $u"] = file_get_contents( $headers );
62 }
63 foreach ( $this->test_posturl as $u => $postData ) {
64 system( "curl -0 -s -X POST -d '$postData' -D $headers '$u' -o $content" );
65 self::$content["POST $u => $postData"] = file_get_contents( $content );
66 self::$headers["POST $u => $postData"] = file_get_contents( $headers );
67 }
68 unlink( $content );
69 unlink( $headers );
70 }
71
72
73 function testInstantiation() {
74 Http::$httpEngine = false;
75
76 $r = HttpRequest::factory("http://www.example.com/");
77 if ( self::$has_curl ) {
78 $this->assertThat($r, $this->isInstanceOf( 'CurlHttpRequest' ));
79 } else {
80 $this->assertThat($r, $this->isInstanceOf( 'PhpHttpRequest' ));
81 }
82 unset($r);
83
84 if( !self::$has_fopen ) {
85 $this->setExpectedException( 'MWException' );
86 }
87 Http::$httpEngine = 'php';
88 $r = HttpRequest::factory("http://www.example.com/");
89 $this->assertThat($r, $this->isInstanceOf( 'PhpHttpRequest' ));
90 unset($r);
91
92 if( !self::$has_curl ) {
93 $this->setExpectedException( 'MWException' );
94 }
95 Http::$httpEngine = 'curl';
96 $r = HttpRequest::factory("http://www.example.com/");
97 if( self::$has_curl ) {
98 $this->assertThat($r, $this->isInstanceOf( 'CurlHttpRequest' ));
99 }
100 }
101
102 function runHTTPFailureChecks() {
103 // Each of the following requests should result in a failure.
104
105 $timeout = 1;
106 $start_time = time();
107 $r = HTTP::get( "http://www.example.com:1/", $timeout);
108 $end_time = time();
109 $this->assertLessThan($timeout+2, $end_time - $start_time,
110 "Request took less than {$timeout}s via ".Http::$httpEngine);
111 $this->assertEquals($r, false, "false -- what we get on error from Http::get()");
112 }
113
114 function testFailureDefault() {
115 Http::$httpEngine = false;
116 self::runHTTPFailureChecks();
117 }
118
119 function testFailurePhp() {
120 if ( !self::$has_fopen ) {
121 $this->markTestIncomplete( "This test requires allow_url_fopen=true." );
122 }
123
124 Http::$httpEngine = "php";
125 self::runHTTPFailureChecks();
126 }
127
128 function testFailureCurl() {
129 if ( !self::$has_curl ) {
130 $this->markTestIncomplete( "This test requires curl." );
131 }
132
133 Http::$httpEngine = "curl";
134 self::runHTTPFailureChecks();
135 }
136
137 /* ./phase3/includes/Import.php:1108: $data = Http::request( $method, $url ); */
138 /* ./includes/Import.php:1124: $link = Title::newFromText( "$interwiki:Special:Export/$page" ); */
139 /* ./includes/Import.php:1134: return ImportStreamSource::newFromURL( $url, "POST" ); */
140 function runHTTPRequests($proxy=null) {
141 $opt = array();
142
143 if($proxy) {
144 $opt['proxy'] = $proxy;
145 } elseif( $proxy === false ) {
146 $opt['noProxy'] = true;
147 }
148
149 /* no postData here because the only request I could find in code so far didn't have any */
150 foreach ( $this->test_requesturl as $u ) {
151 $r = Http::request( "POST", $u, $opt );
152 $this->assertEquals( self::$content["POST $u"], "$r", "POST $u with ".Http::$httpEngine );
153 }
154 }
155
156 function testRequestDefault() {
157 Http::$httpEngine = false;
158 self::runHTTPRequests();
159 }
160
161 function testRequestPhp() {
162 if ( !self::$has_fopen ) {
163 $this->markTestIncomplete( "This test requires allow_url_fopen=true." );
164 }
165
166 Http::$httpEngine = "php";
167 self::runHTTPRequests();
168 }
169
170 function testRequestCurl() {
171 if ( !self::$has_curl ) {
172 $this->markTestIncomplete( "This test requires curl." );
173 }
174
175 Http::$httpEngine = "curl";
176 self::runHTTPRequests();
177 }
178
179 /* ./extensions/SpamBlacklist/SpamBlacklist_body.php:164: $httpText = Http::get( $fileName ); */
180 /* ./extensions/ApiSVGProxy/ApiSVGProxy.body.php:44: $contents = Http::get( $file->getFullUrl() ); */
181 /* ./extensions/BookInformation/drivers/IsbnDb.php:24: if( ( $xml = Http::get( $uri ) ) !== false ) { */
182 /* ./extensions/BookInformation/drivers/Amazon.php:23: if( ( $xml = Http::get( $uri ) ) !== false ) { */
183 /* ./extensions/TitleBlacklist/TitleBlacklist.list.php:217: $result = Http::get( $url ); */
184 /* ./extensions/TSPoll/TSPoll.php:68: $get_server = Http::get( 'http://toolserver.org/~jan/poll/dev/main.php?page=wiki_output&id='.$id ); */
185 /* ./extensions/TSPoll/TSPoll.php:70: $get_server = Http::get( 'http://toolserver.org/~jan/poll/main.php?page=wiki_output&id='.$id ); */
186 /* ./extensions/DoubleWiki/DoubleWiki.php:56: $translation = Http::get( $url.$sep.'action=render' ); */
187 /* ./extensions/ExternalPages/ExternalPages_body.php:177: $serializedText = Http::get( $this->mPageURL ); */
188 /* ./extensions/Translate/utils/TranslationHelpers.php:143: $suggestions = Http::get( $url, $timeout ); */
189 /* ./extensions/Translate/SpecialImportTranslations.php:169: $filedata = Http::get( $url ); ; */
190 /* ./extensions/Translate/TranslateEditAddons.php:338: $suggestions = Http::get( $url, $timeout ); */
191 /* ./extensions/SecurePoll/includes/user/Auth.php:283: $value = Http::get( $url, 20, $curlParams ); */
192 /* ./extensions/DumpHTML/dumpHTML.inc:778: $contents = Http::get( $url ); */
193 /* ./extensions/DumpHTML/dumpHTML.inc:1298: $contents = Http::get( $sourceUrl ); */
194 /* ./extensions/DumpHTML/dumpHTML.inc:1373: $contents = Http::get( $sourceUrl ); */
195 /* ./phase3/maintenance/rebuildInterwiki.inc:101: $intermap = Http::get( 'http://meta.wikimedia.org/w/index.php?title=Interwiki_map&action=raw', 30 ); */
196 /* ./phase3/maintenance/findhooks.php:98: $allhookdata = Http::get( 'http://www.mediawiki.org/w/api.php?action=query&list=categorymembers&cmtitle=Category:MediaWiki_hooks&cmlimit=500&format=php' ); */
197 /* ./phase3/maintenance/findhooks.php:109: $oldhookdata = Http::get( 'http://www.mediawiki.org/w/api.php?action=query&list=categorymembers&cmtitle=Category:Removed_hooks&cmlimit=500&format=php' ); */
198 /* ./phase3/maintenance/dumpInterwiki.inc:95: $intermap = Http::get( 'http://meta.wikimedia.org/w/index.php?title=Interwiki_map&action=raw', 30 ); */
199 /* ./phase3/includes/parser/Parser.php:3204: $text = Http::get($url); */
200 /* ./phase3/includes/filerepo/ForeignAPIRepo.php:131: $data = Http::get( $url ); */
201 /* ./phase3/includes/filerepo/ForeignAPIRepo.php:205: $thumb = Http::get( $foreignUrl ); */
202 /* ./phase3/includes/filerepo/File.php:1105: $res = Http::get( $renderUrl ); */
203 /* ./phase3/includes/GlobalFunctions.php:2760: * @deprecated Use Http::get() instead */
204 /* ./phase3/includes/GlobalFunctions.php:2764: return Http::get( $url ); */
205 /* ./phase3/includes/ExternalStoreHttp.php:18: $ret = Http::get( $url ); */
206 /* ./phase3/includes/Import.php:357: $data = Http::get( $src ); */
207 /* ./extensions/ExternalData/ED_Utils.php:291: return Http::get( $url, 'default', array(CURLOPT_SSL_VERIFYPEER => false) ); */
208 /* ./extensions/ExternalData/ED_Utils.php:293: return Http::get( $url ); */
209 /* ./extensions/ExternalData/ED_Utils.php:306: $page = Http::get( $url, 'default', array(CURLOPT_SSL_VERIFYPEER => false) ); */
210 /* ./extensions/ExternalData/ED_Utils.php:308: $page = Http::get( $url ); */
211 /* ./extensions/CodeReview/backend/Subversion.php:320: $blob = Http::get( $target, $this->mTimeout ); */
212 /* ./extensions/AmazonPlus/AmazonPlus.php:214: $this->response = Http::get( $urlstr ); */
213 /* ./extensions/StaticWiki/StaticWiki.php:24: $text = Http::get( $url ) ; */
214 /* ./extensions/StaticWiki/StaticWiki.php:64: $history = Http::get ( $wgStaticWikiExternalSite . "index.php?title=" . urlencode ( $url_title ) . "&action=history" ) ; */
215 /* ./extensions/Configure/scripts/findSettings.php:126: $cont = Http::get( "http://www.mediawiki.org/w/index.php?title={$page}&action=raw" ); */
216 /* ./extensions/TorBlock/TorBlock.class.php:148: $data = Http::get( $url ); */
217 /* ./extensions/HoneypotIntegration/HoneypotIntegration.class.php:60: $data = Http::get( $wgHoneypotURLSource, 'default', */
218 /* ./extensions/SemanticForms/includes/SF_Utils.inc:378: $page_contents = Http::get($url); */
219 /* ./extensions/LocalisationUpdate/LocalisationUpdate.class.php:172: $basefilecontents = Http::get( $basefile ); */
220 /* ./extensions/APC/SpecialAPC.php:245: $rss = Http::get( 'http://pecl.php.net/feeds/pkg_apc.rss' ); */
221 /* ./extensions/Interlanguage/Interlanguage.php:56: $a = Http::get( $url ); */
222 /* ./extensions/MWSearch/MWSearch_body.php:492: $data = Http::get( $searchUrl, $wgLuceneSearchTimeout, $httpOpts); */
223 function runHTTPGets($proxy=null) {
224 $opt = array();
225
226 if($proxy) {
227 $opt['proxy'] = $proxy;
228 } elseif( $proxy === false ) {
229 $opt['noProxy'] = true;
230 }
231
232 foreach ( $this->test_geturl as $u ) {
233 $r = Http::get( $u, 30, $opt ); /* timeout of 30s */
234 $this->assertEquals( self::$content["GET $u"], "$r", "Get $u with ".Http::$httpEngine );
235 }
236 }
237
238 function testGetDefault() {
239 Http::$httpEngine = false;
240 self::runHTTPGets();
241 }
242
243 function testGetPhp() {
244 if ( !self::$has_fopen ) {
245 $this->markTestIncomplete( "This test requires allow_url_fopen=true." );
246 }
247
248 Http::$httpEngine = "php";
249 self::runHTTPGets();
250 }
251
252 function testGetCurl() {
253 if ( !self::$has_curl ) {
254 $this->markTestIncomplete( "This test requires curl." );
255 }
256
257 Http::$httpEngine = "curl";
258 self::runHTTPGets();
259 }
260
261 /* ./phase3/maintenance/parserTests.inc:1618: return Http::post( $url, array( 'postData' => wfArrayToCGI( $data ) ) ); */
262 function runHTTPPosts($proxy=null) {
263 $opt = array();
264
265 if($proxy) {
266 $opt['proxy'] = $proxy;
267 } elseif( $proxy === false ) {
268 $opt['noProxy'] = true;
269 }
270
271 foreach ( $this->test_posturl as $u => $postData ) {
272 $opt['postData'] = $postData;
273 $r = Http::post( $u, $opt );
274 $this->assertEquals( self::$content["POST $u => $postData"], "$r",
275 "POST $u (postData=$postData) with ".Http::$httpEngine );
276 }
277 }
278
279 function testPostDefault() {
280 Http::$httpEngine = false;
281 self::runHTTPPosts();
282 }
283
284 function testPostPhp() {
285 if ( !self::$has_fopen ) {
286 $this->markTestIncomplete( "This test requires allow_url_fopen=true." );
287 }
288
289 Http::$httpEngine = "php";
290 self::runHTTPPosts();
291 }
292
293 function testPostCurl() {
294 if ( !self::$has_curl ) {
295 $this->markTestIncomplete( "This test requires curl." );
296 }
297
298 Http::$httpEngine = "curl";
299 self::runHTTPPosts();
300 }
301
302 function runProxyRequests() {
303 if(!self::$has_proxy) {
304 $this->markTestIncomplete( "This test requires a proxy." );
305 }
306 self::runHTTPGets(self::$proxy);
307 self::runHTTPPosts(self::$proxy);
308 self::runHTTPRequests(self::$proxy);
309
310 // Set false here to do noProxy
311 self::runHTTPGets(false);
312 self::runHTTPPosts(false);
313 self::runHTTPRequests(false);
314 }
315
316 function testProxyDefault() {
317 Http::$httpEngine = false;
318 self::runProxyRequests();
319 }
320
321 function testProxyPhp() {
322 if ( !self::$has_fopen ) {
323 $this->markTestIncomplete( "This test requires allow_url_fopen=true." );
324 }
325
326 Http::$httpEngine = 'php';
327 self::runProxyRequests();
328 }
329
330 function testProxyCurl() {
331 if ( !self::$has_curl ) {
332 $this->markTestIncomplete( "This test requires curl." );
333 }
334
335 Http::$httpEngine = 'curl';
336 self::runProxyRequests();
337 }
338
339 function testIsLocalUrl() {
340 }
341
342 /* ./extensions/DonationInterface/payflowpro_gateway/payflowpro_gateway.body.php:559: $user_agent = Http::userAgent(); */
343 function testUserAgent() {
344 }
345
346 function testIsValidUrl() {
347 }
348
349 function testSetCookie() {
350 $c = new MockCookie( "name", "value",
351 array(
352 "domain" => ".example.com",
353 "path" => "/path/",
354 ) );
355
356 $this->assertFalse($c->canServeDomain("example.com"));
357 $this->assertFalse($c->canServeDomain("www.example.net"));
358 $this->assertTrue($c->canServeDomain("www.example.com"));
359
360 $this->assertFalse($c->canServePath("/"));
361 $this->assertFalse($c->canServePath("/bogus/path/"));
362 $this->assertFalse($c->canServePath("/path"));
363 $this->assertTrue($c->canServePath("/path/"));
364
365 $this->assertTrue($c->isUnExpired());
366
367 $this->assertEquals("", $c->serializeToHttpRequest("/path/", "www.example.net"));
368 $this->assertEquals("", $c->serializeToHttpRequest("/", "www.example.com"));
369 $this->assertEquals("name=value", $c->serializeToHttpRequest("/path/", "www.example.com"));
370
371 $c = new MockCookie( "name", "value",
372 array(
373 "domain" => ".example.com",
374 "path" => "/path/",
375 "expires" => "January 1, 1990",
376 ) );
377 $this->assertFalse($c->isUnExpired());
378 $this->assertEquals("", $c->serializeToHttpRequest("/path/", "www.example.com"));
379
380 $c = new MockCookie( "name", "value",
381 array(
382 "domain" => ".example.com",
383 "path" => "/path/",
384 "expires" => "January 1, 2999",
385 ) );
386 $this->assertTrue($c->isUnExpired());
387 $this->assertEquals("name=value", $c->serializeToHttpRequest("/path/", "www.example.com"));
388
389
390 }
391
392 function testCookieJarSetCookie() {
393 $cj = new CookieJar;
394 $cj->setCookie( "name", "value",
395 array(
396 "domain" => ".example.com",
397 "path" => "/path/",
398 ) );
399 $cj->setCookie( "name2", "value",
400 array(
401 "domain" => ".example.com",
402 "path" => "/path/sub",
403 ) );
404 $cj->setCookie( "name3", "value",
405 array(
406 "domain" => ".example.com",
407 "path" => "/",
408 ) );
409 $cj->setCookie( "name4", "value",
410 array(
411 "domain" => ".example.net",
412 "path" => "/path/",
413 ) );
414 $cj->setCookie( "name5", "value",
415 array(
416 "domain" => ".example.net",
417 "path" => "/path/",
418 "expires" => "January 1, 1999",
419 ) );
420
421 $this->assertEquals("name4=value", $cj->serializeToHttpRequest("/path/", "www.example.net"));
422 $this->assertEquals("name3=value", $cj->serializeToHttpRequest("/", "www.example.com"));
423 $this->assertEquals("name=value; name3=value", $cj->serializeToHttpRequest("/path/", "www.example.com"));
424
425 $cj->setCookie( "name5", "value",
426 array(
427 "domain" => ".example.net",
428 "path" => "/path/",
429 "expires" => "January 1, 2999",
430 ) );
431 $this->assertEquals("name4=value; name5=value", $cj->serializeToHttpRequest("/path/", "www.example.net"));
432
433 $cj->setCookie( "name4", "value",
434 array(
435 "domain" => ".example.net",
436 "path" => "/path/",
437 "expires" => "January 1, 1999",
438 ) );
439 $this->assertEquals("name5=value", $cj->serializeToHttpRequest("/path/", "www.example.net"));
440 }
441
442 function testParseResponseHeader() {
443 $cj = new CookieJar;
444
445 $h[] = "Set-Cookie: name4=value; domain=.example.com; path=/; expires=Mon, 09-Dec-2999 13:46:00 GMT";
446 $cj->parseCookieResponseHeader( $h[0] );
447 $this->assertEquals("name4=value", $cj->serializeToHttpRequest("/", "www.example.com"));
448
449 $h[] = "name4=value2; domain=.example.com; path=/path/; expires=Mon, 09-Dec-2999 13:46:00 GMT";
450 $cj->parseCookieResponseHeader( $h[1] );
451 $this->assertEquals("", $cj->serializeToHttpRequest("/", "www.example.com"));
452 $this->assertEquals("name4=value2", $cj->serializeToHttpRequest("/path/", "www.example.com"));
453
454 $h[] = "name5=value3; domain=.example.com; path=/path/; expires=Mon, 09-Dec-2999 13:46:00 GMT";
455 $cj->parseCookieResponseHeader( $h[2] );
456 $this->assertEquals("name4=value2; name5=value3", $cj->serializeToHttpRequest("/path/", "www.example.com"));
457
458 $h[] = "name6=value3; domain=.example.net; path=/path/; expires=Mon, 09-Dec-1999 13:46:00 GMT";
459 $cj->parseCookieResponseHeader( $h[3] );
460 $this->assertEquals("", $cj->serializeToHttpRequest("/path/", "www.example.net"));
461
462 $h[] = "name6=value4; domain=.example.net; path=/path/; expires=Mon, 09-Dec-2999 13:46:00 GMT";
463 $cj->parseCookieResponseHeader( $h[4] );
464 $this->assertEquals("name6=value4", $cj->serializeToHttpRequest("/path/", "www.example.net"));
465 }
466
467 function runCookieRequests() {
468 $r = HttpRequest::factory( "http://www.php.net/manual" );
469 $r->execute();
470
471 $jar = $r->getCookieJar();
472
473 $this->assertThat( $jar, $this->isInstanceOf( 'CookieJar' ) );
474 $this->assertRegExp( '/^COUNTRY=.*; LAST_LANG=.*$/', $jar->serializeToHttpRequest( "/search?q=test", "www.php.net" ) );
475 $this->assertEquals( '', $jar->serializeToHttpRequest( "/search?q=test", "www.php.com" ) );
476 }
477
478 function testCookieRequestDefault() {
479 Http::$httpEngine = false;
480 self::runCookieRequests();
481 }
482 function testCookieRequestPhp() {
483 if ( !self::$has_fopen ) {
484 $this->markTestIncomplete( "This test requires allow_url_fopen=true." );
485 }
486
487 Http::$httpEngine = 'php';
488 self::runCookieRequests();
489 }
490 function testCookieRequestCurl() {
491 if ( !self::$has_curl ) {
492 $this->markTestIncomplete( "This test requires curl." );
493 }
494
495 Http::$httpEngine = 'curl';
496 self::runCookieRequests();
497 }
498
499 }