MediaWikiTest.php 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. <?php
  2. class MediaWikiTest extends MediaWikiTestCase {
  3. private $oldServer, $oldGet, $oldPost;
  4. protected function setUp() {
  5. parent::setUp();
  6. $this->setMwGlobals( [
  7. 'wgServer' => 'http://example.org',
  8. 'wgScriptPath' => '/w',
  9. 'wgScript' => '/w/index.php',
  10. 'wgArticlePath' => '/wiki/$1',
  11. 'wgActionPaths' => [],
  12. ] );
  13. // phpcs:disable MediaWiki.Usage.SuperGlobalsUsage.SuperGlobals
  14. $this->oldServer = $_SERVER;
  15. $this->oldGet = $_GET;
  16. $this->oldPost = $_POST;
  17. }
  18. protected function tearDown() {
  19. parent::tearDown();
  20. $_SERVER = $this->oldServer;
  21. $_GET = $this->oldGet;
  22. $_POST = $this->oldPost;
  23. }
  24. public static function provideTryNormaliseRedirect() {
  25. return [
  26. [
  27. // View: Canonical
  28. 'url' => 'http://example.org/wiki/Foo_Bar',
  29. 'query' => [],
  30. 'title' => 'Foo_Bar',
  31. 'redirect' => false,
  32. ],
  33. [
  34. // View: Escaped title
  35. 'url' => 'http://example.org/wiki/Foo%20Bar',
  36. 'query' => [],
  37. 'title' => 'Foo_Bar',
  38. 'redirect' => 'http://example.org/wiki/Foo_Bar',
  39. ],
  40. [
  41. // View: Script path
  42. 'url' => 'http://example.org/w/index.php?title=Foo_Bar',
  43. 'query' => [ 'title' => 'Foo_Bar' ],
  44. 'title' => 'Foo_Bar',
  45. 'redirect' => false,
  46. ],
  47. [
  48. // View: Script path with implicit title from page id
  49. 'url' => 'http://example.org/w/index.php?curid=123',
  50. 'query' => [ 'curid' => '123' ],
  51. 'title' => 'Foo_Bar',
  52. 'redirect' => false,
  53. ],
  54. [
  55. // View: Script path with implicit title from revision id
  56. 'url' => 'http://example.org/w/index.php?oldid=123',
  57. 'query' => [ 'oldid' => '123' ],
  58. 'title' => 'Foo_Bar',
  59. 'redirect' => false,
  60. ],
  61. [
  62. // View: Script path without title
  63. 'url' => 'http://example.org/w/index.php',
  64. 'query' => [],
  65. 'title' => 'Main_Page',
  66. 'redirect' => 'http://example.org/wiki/Main_Page',
  67. ],
  68. [
  69. // View: Script path with empty title
  70. 'url' => 'http://example.org/w/index.php?title=',
  71. 'query' => [ 'title' => '' ],
  72. 'title' => 'Main_Page',
  73. 'redirect' => 'http://example.org/wiki/Main_Page',
  74. ],
  75. [
  76. // View: Index with escaped title
  77. 'url' => 'http://example.org/w/index.php?title=Foo%20Bar',
  78. 'query' => [ 'title' => 'Foo Bar' ],
  79. 'title' => 'Foo_Bar',
  80. 'redirect' => 'http://example.org/wiki/Foo_Bar',
  81. ],
  82. [
  83. // View: Script path with escaped title
  84. 'url' => 'http://example.org/w/?title=Foo_Bar',
  85. 'query' => [ 'title' => 'Foo_Bar' ],
  86. 'title' => 'Foo_Bar',
  87. 'redirect' => false,
  88. ],
  89. [
  90. // View: Root path with escaped title
  91. 'url' => 'http://example.org/?title=Foo_Bar',
  92. 'query' => [ 'title' => 'Foo_Bar' ],
  93. 'title' => 'Foo_Bar',
  94. 'redirect' => false,
  95. ],
  96. [
  97. // View: Canonical with redundant query
  98. 'url' => 'http://example.org/wiki/Foo_Bar?action=view',
  99. 'query' => [ 'action' => 'view' ],
  100. 'title' => 'Foo_Bar',
  101. 'redirect' => false,
  102. ],
  103. [
  104. // Edit: Canonical view url with action query
  105. 'url' => 'http://example.org/wiki/Foo_Bar?action=edit',
  106. 'query' => [ 'action' => 'edit' ],
  107. 'title' => 'Foo_Bar',
  108. 'redirect' => false,
  109. ],
  110. [
  111. // View: Index with action query
  112. 'url' => 'http://example.org/w/index.php?title=Foo_Bar&action=view',
  113. 'query' => [ 'title' => 'Foo_Bar', 'action' => 'view' ],
  114. 'title' => 'Foo_Bar',
  115. 'redirect' => false,
  116. ],
  117. [
  118. // Edit: Index with action query
  119. 'url' => 'http://example.org/w/index.php?title=Foo_Bar&action=edit',
  120. 'query' => [ 'title' => 'Foo_Bar', 'action' => 'edit' ],
  121. 'title' => 'Foo_Bar',
  122. 'redirect' => false,
  123. ],
  124. [
  125. // Path with double slash prefix (T100782)
  126. 'url' => 'http://example.org//wiki/Double_slash',
  127. 'query' => [],
  128. 'title' => 'Double_slash',
  129. 'redirect' => false,
  130. ],
  131. ];
  132. }
  133. /**
  134. * @dataProvider provideTryNormaliseRedirect
  135. * @covers MediaWiki::tryNormaliseRedirect
  136. */
  137. public function testTryNormaliseRedirect( $url, $query, $title, $expectedRedirect = false ) {
  138. // Set SERVER because interpolateTitle() doesn't use getRequestURL(),
  139. // whereas tryNormaliseRedirect does(). Also, using WebRequest allows
  140. // us to test some quirks in that class.
  141. $_SERVER['REQUEST_URI'] = $url;
  142. $_POST = [];
  143. $_GET = $query;
  144. $req = new WebRequest;
  145. // This adds a virtual 'title' query parameter. Normally called from Setup.php
  146. $req->interpolateTitle();
  147. $titleObj = Title::newFromText( $title );
  148. // Set global context since some involved code paths don't yet have context
  149. $context = RequestContext::getMain();
  150. $context->setRequest( $req );
  151. $context->setTitle( $titleObj );
  152. $mw = new MediaWiki( $context );
  153. $method = new ReflectionMethod( $mw, 'tryNormaliseRedirect' );
  154. $method->setAccessible( true );
  155. $ret = $method->invoke( $mw, $titleObj );
  156. $this->assertEquals(
  157. $expectedRedirect !== false,
  158. $ret,
  159. 'Return true only when redirecting'
  160. );
  161. $this->assertEquals(
  162. $expectedRedirect ?: '',
  163. $context->getOutput()->getRedirect()
  164. );
  165. }
  166. /**
  167. * Test a post-send job can not set cookies (T191537).
  168. */
  169. public function testPostSendJobDoesNotSetCookie() {
  170. // Prevent updates from running
  171. $this->setMwGlobals( 'wgCommandLineMode', false );
  172. $response = new WebResponse;
  173. // A job that attempts to set a cookie
  174. $jobHasRun = false;
  175. DeferredUpdates::addCallableUpdate( function () use ( $response, &$jobHasRun ) {
  176. $jobHasRun = true;
  177. $response->setCookie( 'JobCookie', 'yes' );
  178. $response->header( 'Foo: baz' );
  179. } );
  180. $hookWasRun = false;
  181. $this->setTemporaryHook( 'WebResponseSetCookie', function () use ( &$hookWasRun ) {
  182. $hookWasRun = true;
  183. return true;
  184. } );
  185. $logger = new TestLogger();
  186. $logger->setCollect( true );
  187. $this->setLogger( 'cookie', $logger );
  188. $this->setLogger( 'header', $logger );
  189. $mw = new MediaWiki();
  190. $mw->doPostOutputShutdown();
  191. // restInPeace() might have been registered to a callback of
  192. // register_postsend_function() and thus can not be triggered from
  193. // PHPUnit.
  194. if ( $jobHasRun === false ) {
  195. $mw->restInPeace();
  196. }
  197. $this->assertTrue( $jobHasRun, 'post-send job has run' );
  198. $this->assertFalse( $hookWasRun,
  199. 'post-send job must not trigger WebResponseSetCookie hook' );
  200. $this->assertEquals(
  201. [
  202. [ 'info', 'ignored post-send cookie {cookie}' ],
  203. [ 'info', 'ignored post-send header {header}' ],
  204. ],
  205. $logger->getBuffer()
  206. );
  207. }
  208. }