Index: src/wp-includes/ms-load.php
===================================================================
--- src/wp-includes/ms-load.php	(revision 28179)
+++ src/wp-includes/ms-load.php	(working copy)
@@ -348,13 +348,30 @@
 	 * then cache whether we can just always ignore paths.
 	 */
 
+	// Either www or non-www is supported, not both. If a www domain is requested,
+	// query for both to provide the proper redirect.
+	$domains = array( $domain );
+	if ( substr( $domain, 0, 4 ) == 'www.' ) {
+		$domains[] = substr( $domain, 4 );
+		$search_domains = "'" . implode( "', '", $wpdb->_escape( $domains ) ) . "'";
+	}
+
 	if ( count( $paths ) > 1 ) {
-		$paths = "'" . implode( "', '", $wpdb->_escape( $paths ) ) . "'";
-		$sql = $wpdb->prepare( "SELECT * FROM $wpdb->blogs WHERE domain = %s", $domain );
-		$sql .= " AND path IN ($paths) ORDER BY CHAR_LENGTH(path) DESC LIMIT 1";
+		$search_paths = "'" . implode( "', '", $wpdb->_escape( $paths ) ) . "'";
+	}
+
+	if ( count( $domains ) > 1 && count( $paths ) > 1 ) {
+		$site = $wpdb->get_row( "SELECT * FROM $wpdb->blogs WHERE domain IN ($search_domains) AND path IN ($search_paths) ORDER BY CHAR_LENGTH(domain) DESC, CHAR_LENGTH(path) DESC LIMIT 1" );
+	} elseif ( count( $domains ) > 1 ) {
+		$sql = $wpdb->prepare( "SELECT * FROM $wpdb->blogs WHERE path = %s", $paths[0] );
+		$sql .= " AND domain IN ($search_domains) ORDER BY CHAR_LENGTH(domain) DESC LIMIT 1";
 		$site = $wpdb->get_row( $sql );
+	} elseif ( count( $paths ) > 1 ) {
+		$sql = $wpdb->prepare( "SELECT * FROM $wpdb->blogs WHERE domain = %s", $domains[0] );
+		$sql .= " AND path IN ($search_paths) ORDER BY CHAR_LENGTH(path) DESC LIMIT 1";
+		$site = $wpdb->get_row( $sql );
 	} else {
-		$site = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $wpdb->blogs WHERE domain = %s and path = %s", $domain, $paths[0] ) );
+		$site = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $wpdb->blogs WHERE domain = %s AND path = %s", $domains[0], $paths[0] ) );
 	}
 
 	if ( $site ) {
Index: tests/phpunit/tests/ms.php
===================================================================
--- tests/phpunit/tests/ms.php	(revision 28158)
+++ tests/phpunit/tests/ms.php	(working copy)
@@ -1233,6 +1233,9 @@
 			'wordpress.org/foo/bar/'      => array( 'domain' => 'wordpress.org',      'path' => '/foo/bar/' ),
 			'make.wordpress.org/'         => array( 'domain' => 'make.wordpress.org', 'path' => '/' ),
 			'make.wordpress.org/foo/'     => array( 'domain' => 'make.wordpress.org', 'path' => '/foo/' ),
+			'www.wp.org/'                 => array( 'domain' => 'www.wp.org',         'path' => '/' ),
+			'www.wp.org/foo/'             => array( 'domain' => 'www.wp.org',         'path' => '/foo/' ),
+			'www.wp.org/foo/bar/'         => array( 'domain' => 'www.wp.org',         'path' => '/foo/bar/' ),
 		);
 
 		foreach ( $ids as &$id ) {
@@ -1243,23 +1246,66 @@
 		$this->assertEquals( $ids['wordpress.org/'],
 			get_site_by_path( 'wordpress.org', '/notapath/' )->blog_id );
 
+		$this->assertEquals( $ids['wordpress.org/'],
+			get_site_by_path( 'www.wordpress.org', '/notapath/' )->blog_id );
+
 		$this->assertEquals( $ids['wordpress.org/foo/bar/'],
 			get_site_by_path( 'wordpress.org', '/foo/bar/baz/' )->blog_id );
 
 		$this->assertEquals( $ids['wordpress.org/foo/bar/'],
+			get_site_by_path( 'www.wordpress.org', '/foo/bar/baz/' )->blog_id );
+
+		$this->assertEquals( $ids['wordpress.org/foo/bar/'],
 			get_site_by_path( 'wordpress.org', '/foo/bar/baz/', 3 )->blog_id );
 
 		$this->assertEquals( $ids['wordpress.org/foo/bar/'],
+			get_site_by_path( 'www.wordpress.org', '/foo/bar/baz/', 3 )->blog_id );
+
+		$this->assertEquals( $ids['wordpress.org/foo/bar/'],
 			get_site_by_path( 'wordpress.org', '/foo/bar/baz/', 2 )->blog_id );
 
+		$this->assertEquals( $ids['wordpress.org/foo/bar/'],
+			get_site_by_path( 'www.wordpress.org', '/foo/bar/baz/', 2 )->blog_id );
+
 		$this->assertEquals( $ids['wordpress.org/foo/'],
 			get_site_by_path( 'wordpress.org', '/foo/bar/baz/', 1 )->blog_id );
 
+		$this->assertEquals( $ids['wordpress.org/foo/'],
+			get_site_by_path( 'www.wordpress.org', '/foo/bar/baz/', 1 )->blog_id );
+
 		$this->assertEquals( $ids['wordpress.org/'],
 			get_site_by_path( 'wordpress.org', '/', 0 )->blog_id );
 
+		$this->assertEquals( $ids['wordpress.org/'],
+			get_site_by_path( 'www.wordpress.org', '/', 0 )->blog_id );
+
 		$this->assertEquals( $ids['make.wordpress.org/foo/'],
 			get_site_by_path( 'make.wordpress.org', '/foo/bar/baz/qux/', 4 )->blog_id );
+
+		$this->assertEquals( $ids['make.wordpress.org/foo/'],
+			get_site_by_path( 'www.make.wordpress.org', '/foo/bar/baz/qux/', 4 )->blog_id );
+
+		$this->assertEquals( $ids['www.wp.org/'],
+			get_site_by_path( 'www.wp.org', '/', 0 )->blog_id );
+
+		$this->assertEquals( $ids['www.wp.org/'],
+			get_site_by_path( 'www.wp.org', '/notapath/' )->blog_id );
+
+		$this->assertEquals( $ids['www.wp.org/foo/bar/'],
+			get_site_by_path( 'www.wp.org', '/foo/bar/baz/' )->blog_id );
+
+		$this->assertEquals( $ids['www.wp.org/foo/'],
+			get_site_by_path( 'www.wp.org', '/foo/bar/baz/', 1 )->blog_id );
+
+		// A site installed with www will not be found by the root domain.
+		$this->assertFalse( get_site_by_path( 'wp.org', '/' ) );
+		$this->assertFalse( get_site_by_path( 'wp.org', '/notapath/' ) );
+		$this->assertFalse( get_site_by_path( 'wp.org', '/foo/bar/baz/' ) );
+		$this->assertFalse( get_site_by_path( 'wp.org', '/foo/bar/baz/', 1 ) );
+
+		// A site will not be found by its root domain when an invalid subdomain is requested.
+		$this->assertFalse( get_site_by_path( 'invalid.wordpress.org', '/' ) );
+		$this->assertFalse( get_site_by_path( 'invalid.wordpress.org', '/foo/bar/' ) );
 	}
 
 	/**
