r90105 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r90104‎ | r90105 | r90106 >
Date:07:35, 15 June 2011
Author:tstarling
Status:ok (Comments)
Tags:
Comment:
* (bug 28798) Set $wgServer in the default LocalSettings.php
* (bug 14977) When detecting $wgServer, treat IPv6 addresses in $_SERVER['SERVER_NAME'] etc. in a sensible way.
* Tests for the new functions in IP.php and Installer.php
Modified paths:
  • /trunk/phase3/includes/IP.php (modified) (history)
  • /trunk/phase3/includes/installer/Installer.i18n.php (modified) (history)
  • /trunk/phase3/includes/installer/Installer.php (modified) (history)
  • /trunk/phase3/includes/installer/LocalSettingsGenerator.php (modified) (history)
  • /trunk/phase3/includes/installer/WebInstallerPage.php (modified) (history)
  • /trunk/phase3/tests/phpunit/includes/IPTest.php (modified) (history)
  • /trunk/phase3/tests/phpunit/includes/installer (added) (history)
  • /trunk/phase3/tests/phpunit/includes/installer/InstallerTest.php (added) (history)

Diff [purge]

Index: trunk/phase3/tests/phpunit/includes/installer/InstallerTest.php
@@ -0,0 +1,102 @@
 2+<?php
 3+
 4+class Installer_TestHelper extends Installer {
 5+ function showMessage( $msg ) {}
 6+ function showError( $msg ) {}
 7+ function showStatusMessage( Status $status ) {}
 8+
 9+ function __construct() {
 10+ $this->settings = array();
 11+ }
 12+
 13+}
 14+
 15+class InstallerTest extends MediaWikiTestCase {
 16+ /**
 17+ * @dataProvider provideEnvCheckServer
 18+ */
 19+ function testEnvCheckServer( $expected, $input, $description ) {
 20+ $installer = new Installer_TestHelper;
 21+ $oldServer = $_SERVER;
 22+ $_SERVER = $input;
 23+ $rm = new ReflectionMethod( 'Installer_TestHelper', 'envCheckServer' );
 24+ $rm->setAccessible( true );
 25+ $rm->invoke( $installer );
 26+ $_SERVER = $oldServer;
 27+ $this->assertEquals( $expected, $installer->getVar( 'wgServer' ), $description );
 28+ }
 29+
 30+ function provideEnvCheckServer() {
 31+ return array(
 32+ array(
 33+ 'http://x',
 34+ array(
 35+ 'HTTP_HOST' => 'x'
 36+ ),
 37+ 'Host header'
 38+ ),
 39+ array(
 40+ 'https://x',
 41+ array(
 42+ 'HTTP_HOST' => 'x',
 43+ 'HTTPS' => 'on',
 44+ ),
 45+ 'Host header with secure'
 46+ ),
 47+ array(
 48+ 'http://x',
 49+ array(
 50+ 'HTTP_HOST' => 'x',
 51+ 'SERVER_PORT' => 80,
 52+ ),
 53+ 'Default SERVER_PORT',
 54+ ),
 55+ array(
 56+ 'http://x',
 57+ array(
 58+ 'HTTP_HOST' => 'x',
 59+ 'HTTPS' => 'off',
 60+ ),
 61+ 'Secure off'
 62+ ),
 63+ array(
 64+ 'http://y',
 65+ array(
 66+ 'SERVER_NAME' => 'y',
 67+ ),
 68+ 'Server name'
 69+ ),
 70+ array(
 71+ 'http://x',
 72+ array(
 73+ 'HTTP_HOST' => 'x',
 74+ 'SERVER_NAME' => 'y',
 75+ ),
 76+ 'Host server name precedence'
 77+ ),
 78+ array(
 79+ 'http://[::1]:81',
 80+ array(
 81+ 'HTTP_HOST' => '[::1]',
 82+ 'SERVER_NAME' => '::1',
 83+ 'SERVER_PORT' => '81',
 84+ ),
 85+ 'Apache bug 26005'
 86+ ),
 87+ array(
 88+ 'http://localhost',
 89+ array(
 90+ 'SERVER_NAME' => '[2001'
 91+ ),
 92+ 'Kind of like lighttpd per commit message in MW r83847',
 93+ ),
 94+ array(
 95+ 'http://[2a01:e35:2eb4:1::2]:777',
 96+ array(
 97+ 'SERVER_NAME' => '[2a01:e35:2eb4:1::2]:777'
 98+ ),
 99+ 'Possible lighttpd environment per bug 14977 comment 13',
 100+ ),
 101+ );
 102+ }
 103+}
Property changes on: trunk/phase3/tests/phpunit/includes/installer/InstallerTest.php
___________________________________________________________________
Added: svn:eol-style
1104 + native
Index: trunk/phase3/tests/phpunit/includes/IPTest.php
@@ -426,4 +426,56 @@
427427 array( false, '2001:0DB8:F::', '2001:DB8::/96' ),
428428 );
429429 }
 430+
 431+ /**
 432+ * Test for IP::splitHostAndPort().
 433+ * @dataProvider provideSplitHostAndPort
 434+ */
 435+ function testSplitHostAndPort( $expected, $input, $description ) {
 436+ $this->assertEquals( $expected, IP::splitHostAndPort( $input ), $description );
 437+ }
 438+
 439+ /**
 440+ * Provider for IP::splitHostAndPort()
 441+ */
 442+ function provideSplitHostAndPort() {
 443+ return array(
 444+ array( false, '[', 'Unclosed square bracket' ),
 445+ array( false, '[::', 'Unclosed square bracket 2' ),
 446+ array( array( '::', false ), '::', 'Bare IPv6 0' ),
 447+ array( array( '::1', false ), '::1', 'Bare IPv6 1' ),
 448+ array( array( '::', false ), '[::]', 'Bracketed IPv6 0' ),
 449+ array( array( '::1', false ), '[::1]', 'Bracketed IPv6 1' ),
 450+ array( array( '::1', 80 ), '[::1]:80', 'Bracketed IPv6 with port' ),
 451+ array( false, '::x', 'Double colon but no IPv6' ),
 452+ array( array( 'x', 80 ), 'x:80', 'Hostname and port' ),
 453+ array( false, 'x:x', 'Hostname and invalid port' ),
 454+ array( array( 'x', false ), 'x', 'Plain hostname' )
 455+ );
 456+ }
 457+
 458+ /**
 459+ * Test for IP::combineHostAndPort()
 460+ * @dataProvider provideCombineHostAndPort
 461+ */
 462+ function testCombineHostAndPort( $expected, $input, $description ) {
 463+ list( $host, $port, $defaultPort ) = $input;
 464+ $this->assertEquals(
 465+ $expected,
 466+ IP::combineHostAndPort( $host, $port, $defaultPort ),
 467+ $description );
 468+ }
 469+
 470+ /**
 471+ * Provider for IP::combineHostAndPort()
 472+ */
 473+ function provideCombineHostAndPort() {
 474+ return array(
 475+ array( '[::1]', array( '::1', 2, 2 ), 'IPv6 default port' ),
 476+ array( '[::1]:2', array( '::1', 2, 3 ), 'IPv6 non-default port' ),
 477+ array( 'x', array( 'x', 2, 2 ), 'Normal default port' ),
 478+ array( 'x:2', array( 'x', 2, 3 ), 'Normal non-default port' ),
 479+ );
 480+ }
 481+
430482 }
Index: trunk/phase3/includes/installer/Installer.php
@@ -99,6 +99,7 @@
100100 'envCheckCache',
101101 'envCheckDiff3',
102102 'envCheckGraphics',
 103+ 'envCheckServer',
103104 'envCheckPath',
104105 'envCheckExtension',
105106 'envCheckShellLocale',
@@ -131,6 +132,8 @@
132133 'wgDiff3',
133134 'wgImageMagickConvertCommand',
134135 'IP',
 136+ 'wgServer',
 137+ 'wgProto',
135138 'wgScriptPath',
136139 'wgScriptExtension',
137140 'wgMetaNamespace',
@@ -838,6 +841,47 @@
839842 }
840843
841844 /**
 845+ * Environment check for the server hostname.
 846+ */
 847+ protected function envCheckServer() {
 848+ if ( isset( $_SERVER['HTTPS'] ) && $_SERVER['HTTPS'] == 'on') {
 849+ $proto = 'https';
 850+ $stdPort = 443;
 851+ } else {
 852+ $proto = 'http';
 853+ $stdPort = 80;
 854+ }
 855+
 856+ $varNames = array( 'HTTP_HOST', 'SERVER_NAME', 'HOSTNAME', 'SERVER_ADDR' );
 857+ $host = 'localhost';
 858+ $port = $stdPort;
 859+ foreach ( $varNames as $varName ) {
 860+ if ( !isset( $_SERVER[$varName] ) ) {
 861+ continue;
 862+ }
 863+ $parts = IP::splitHostAndPort( $_SERVER[$varName] );
 864+ if ( !$parts ) {
 865+ // Invalid, do not use
 866+ continue;
 867+ }
 868+ $host = $parts[0];
 869+ if ( $parts[1] === false ) {
 870+ if ( isset( $_SERVER['SERVER_PORT'] ) ) {
 871+ $port = $_SERVER['SERVER_PORT'];
 872+ } // else leave it as $stdPort
 873+ } else {
 874+ $port = $parts[1];
 875+ }
 876+ break;
 877+ }
 878+
 879+ $server = $proto . '://' . IP::combineHostAndPort( $host, $port, $stdPort );
 880+ $this->showMessage( 'config-using-server', $server );
 881+ $this->setVar( 'wgServer', $server );
 882+ $this->setVar( 'wgProto', $proto );
 883+ }
 884+
 885+ /**
842886 * Environment check for setting $IP and $wgScriptPath.
843887 */
844888 protected function envCheckPath() {
@@ -955,10 +999,10 @@
9561000 * TODO: document
9571001 */
9581002 protected function envCheckUploadsDirectory() {
959 - global $IP, $wgServer;
 1003+ global $IP;
9601004
9611005 $dir = $IP . '/images/';
962 - $url = $wgServer . $this->getVar( 'wgScriptPath' ) . '/images/';
 1006+ $url = $this->getVar( 'wgServer' ) . $this->getVar( 'wgScriptPath' ) . '/images/';
9631007 $safe = !$this->dirIsExecutable( $dir, $url );
9641008
9651009 if ( $safe ) {
Index: trunk/phase3/includes/installer/Installer.i18n.php
@@ -147,6 +147,7 @@
148148 Image thumbnailing will be disabled.',
149149 'config-no-uri' => "'''Error:''' Could not determine the current URI.
150150 Installation aborted.",
 151+ 'config-using-server' => 'Using server name "<nowiki>$1</nowiki>".',
151152 'config-uploads-not-safe' => "'''Warning:''' Your default directory for uploads <code>$1</code> is vulnerable to arbitrary scripts execution.
152153 Although MediaWiki checks all uploaded files for security threats, it is highly recommended to [http://www.mediawiki.org/wiki/Manual:Security#Upload_security close this security vulnerability] before enabling uploads.",
153154 'config-brokenlibxml' => 'Your system has a combination of PHP and libxml2 versions which is buggy and can cause hidden data corruption in MediaWiki and other web applications.
Index: trunk/phase3/includes/installer/LocalSettingsGenerator.php
@@ -39,7 +39,7 @@
4040
4141 $confItems = array_merge(
4242 array(
43 - 'wgScriptPath', 'wgScriptExtension',
 43+ 'wgServer', 'wgProto', 'wgScriptPath', 'wgScriptExtension',
4444 'wgPasswordSender', 'wgImageMagickConvertCommand', 'wgShellLocale',
4545 'wgLanguageCode', 'wgEnableEmail', 'wgEnableUserEmail', 'wgDiff3',
4646 'wgEnotifUserTalk', 'wgEnotifWatchlist', 'wgEmailAuthentication',
@@ -249,6 +249,12 @@
250250 \$wgScriptPath = \"{$this->values['wgScriptPath']}\";
251251 \$wgScriptExtension = \"{$this->values['wgScriptExtension']}\";
252252
 253+## The server name to use in fully-qualified URLs
 254+\$wgServer = \"{$this->values['wgServer']}\";
 255+
 256+## The URL protocol, may be http or https
 257+\$wgProto = \"{$this->values['wgProto']}\";
 258+
253259 ## The relative URL path to the skins directory
254260 \$wgStylePath = \"\$wgScriptPath/skins\";
255261
Index: trunk/phase3/includes/installer/WebInstallerPage.php
@@ -531,7 +531,7 @@
532532 $this->addHTML(
533533 $this->parent->getInfoBox(
534534 wfMsgNoTrans( $msg,
535 - $GLOBALS['wgServer'] .
 535+ $this->getVar( 'wgServer' ) .
536536 $this->getVar( 'wgScriptPath' ) . '/index' .
537537 $this->getVar( 'wgScriptExtension' )
538538 ), 'tick-32.png'
@@ -934,8 +934,8 @@
935935 * @return string
936936 */
937937 public function getCCPartnerUrl() {
938 - global $wgServer;
939 - $exitUrl = $wgServer . $this->parent->getUrl( array(
 938+ $server = $this->getVar( 'wgServer' );
 939+ $exitUrl = $server . $this->parent->getUrl( array(
940940 'page' => 'Options',
941941 'SubmitCC' => 'indeed',
942942 'config__LicenseCode' => 'cc',
@@ -943,7 +943,7 @@
944944 'config_wgRightsText' => '[license_name]',
945945 'config_wgRightsIcon' => '[license_button]',
946946 ) );
947 - $styleUrl = $wgServer . dirname( dirname( $this->parent->getUrl() ) ) .
 947+ $styleUrl = $server . dirname( dirname( $this->parent->getUrl() ) ) .
948948 '/skins/common/config-cc.css';
949949 $iframeUrl = 'http://creativecommons.org/license/?' .
950950 wfArrayToCGI( array(
@@ -1147,7 +1147,7 @@
11481148 public function execute() {
11491149 // Pop up a dialog box, to make it difficult for the user to forget
11501150 // to download the file
1151 - $lsUrl = $GLOBALS['wgServer'] . $this->parent->getURL( array( 'localsettings' => 1 ) );
 1151+ $lsUrl = $this->getVar( 'wgServer' ) . $this->parent->getURL( array( 'localsettings' => 1 ) );
11521152 if ( isset( $_SERVER['HTTP_USER_AGENT'] ) && strpos( $_SERVER['HTTP_USER_AGENT'], 'MSIE' ) !== false ) {
11531153 // JS appears the only method that works consistently with IE7+
11541154 $this->addHtml( "\n<script type=\"" . $GLOBALS['wgJsMimeType'] . '">jQuery( document ).ready( function() { document.location='
@@ -1162,7 +1162,7 @@
11631163 $this->parent->getInfoBox(
11641164 wfMsgNoTrans( 'config-install-done',
11651165 $lsUrl,
1166 - $GLOBALS['wgServer'] .
 1166+ $this->getVar( 'wgServer' ) .
11671167 $this->getVar( 'wgScriptPath' ) . '/index' .
11681168 $this->getVar( 'wgScriptExtension' ),
11691169 '<downloadlink/>'
Index: trunk/phase3/includes/IP.php
@@ -186,6 +186,76 @@
187187 }
188188
189189 /**
 190+ * Given a host/port string, like one might find in the host part of a URL
 191+ * per RFC 2732, split the hostname part and the port part and return an
 192+ * array with an element for each. If there is no port part, the array will
 193+ * have false in place of the port. If the string was invalid in some way,
 194+ * false is returned.
 195+ *
 196+ * This was easy with IPv4 and was generally done in an ad-hoc way, but
 197+ * with IPv6 it's somewhat more complicated due to the need to parse the
 198+ * square brackets and colons.
 199+ *
 200+ * A bare IPv6 address is accepted despite the lack of square brackets.
 201+ *
 202+ * @param $both The string with the host and port
 203+ * @return array
 204+ */
 205+ public static function splitHostAndPort( $both ) {
 206+ if ( substr( $both, 0, 1 ) === '[' ) {
 207+ if ( preg_match( '/^\[(' . RE_IPV6_ADD . ')\](?::(?P<port>\d+))?$/', $both, $m ) ) {
 208+ if ( isset( $m['port'] ) ) {
 209+ return array( $m[1], intval( $m['port'] ) );
 210+ } else {
 211+ return array( $m[1], false );
 212+ }
 213+ } else {
 214+ // Square bracket found but no IPv6
 215+ return false;
 216+ }
 217+ }
 218+ $numColons = substr_count( $both, ':' );
 219+ if ( $numColons >= 2 ) {
 220+ // Is it a bare IPv6 address?
 221+ if ( preg_match( '/^' . RE_IPV6_ADD . '$/', $both ) ) {
 222+ return array( $both, false );
 223+ } else {
 224+ // Not valid IPv6, but too many colons for anything else
 225+ return false;
 226+ }
 227+ }
 228+ if ( $numColons >= 1 ) {
 229+ // Host:port?
 230+ $bits = explode( ':', $both );
 231+ if ( preg_match( '/^\d+/', $bits[1] ) ) {
 232+ return array( $bits[0], intval( $bits[1] ) );
 233+ } else {
 234+ // Not a valid port
 235+ return false;
 236+ }
 237+ }
 238+ // Plain hostname
 239+ return array( $both, false );
 240+ }
 241+
 242+ /**
 243+ * Given a host name and a port, combine them into host/port string like
 244+ * you might find in a URL. If the host contains a colon, wrap it in square
 245+ * brackets like in RFC 2732. If the port matches the default port, omit
 246+ * the port specification
 247+ */
 248+ public static function combineHostAndPort( $host, $port, $defaultPort = false ) {
 249+ if ( strpos( $host, ':' ) !== false ) {
 250+ $host = "[$host]";
 251+ }
 252+ if ( $defaultPort !== false && $port == $defaultPort ) {
 253+ return $host;
 254+ } else {
 255+ return "$host:$port";
 256+ }
 257+ }
 258+
 259+ /**
190260 * Given an unsigned integer, returns an IPv6 address in octet notation
191261 *
192262 * @param $ip_int String: IP address.

Follow-up revisions

RevisionCommit summaryAuthorDate
r90154Followup r90105, ReflectionMethod::setAccessible() requires PHP 5.3.2. Mark i...demon20:57, 15 June 2011
r90193Removed $wgProto. Previously, setting this undocumented global variable to an...tstarling05:13, 16 June 2011
r90194Fixes for r90105, r90193:...tstarling05:52, 16 June 2011
r938881.17wmf1: Followup r93886: also copy IP::combineHostAndPort() from trunk, Web...catrope13:56, 4 August 2011

Past revisions this follows-up on

RevisionCommit summaryAuthorDate
r38214(bug 14977) Installations on servers using IPv6 addresses for $wgServer were ...demon03:23, 30 July 2008

Comments

#Comment by Platonides (talk | contribs)   08:01, 15 June 2011

I don't see the point of adding $wgServer (albeit I can't access the rationale)

#Comment by Tim Starling (talk | contribs)   08:40, 15 June 2011

I added you to the CC list, you should be able to view the bug now.

#Comment by Hashar (talk | contribs)   20:52, 15 June 2011

The installer test break using PHP 5.2.15 :

 Fatal error: Call to undefined method ReflectionMethod::setAccessible()

That might cause issues if we ship it in a MediaWiki version still supporting 5.2.x. It is probably time to update my Mac OS X 10.5.8 PHP version too :)

Status & tagging log