MediaWiki r37161 - Code Review

Jump to: navigation, search
Repository:MediaWiki
Revision:r37160‎ | r37161 (on ViewVC)‎ | r37162 >
Date:12:04, 6 July 2008
Author:shinjiman
Status:old
Tags:
Comment:
Renaming WebDav.php to WebDavServer.php.
As the filename "WebDav.php" and "webdav.php" are treated as a same file on the case-insensistive file system used on their operating systems, such as Windows.
This will causes the problem while these two files are being checked out or updated.
Thanks StasFomin for pointing out this problem.
Modified paths:

Diff [purge]

Index: trunk/extensions/WebDAV/WebDavServer.php
===================================================================
--- trunk/extensions/WebDAV/WebDavServer.php	(revision 0)
+++ trunk/extensions/WebDAV/WebDavServer.php	(revision 37161)
@@ -0,0 +1,779 @@
+<?php
+
+define( 'MW_SEARCH_LIMIT', 50 );
+
+require_once( './lib/HTTP/WebDAV/Server.php' );
+
+class WebDavServer extends HTTP_WebDAV_Server {
+
+	function init() {
+		parent::init();
+
+		# Prepend script path component to path components
+		array_unshift( $this->pathComponents, array_pop( $this->baseUrlComponents['pathComponents'] ) );
+	}
+
+	function getAllowedMethods() {
+		return array( 'OPTIONS', 'PROPFIND', 'GET', 'HEAD', 'DELETE', 'PUT', 'REPORT', 'SEARCH' );
+	}
+
+	function options( &$serverOptions ) {
+		parent::options( &$serverOptions );
+
+		if ( $serverOptions['xpath']->evaluate( 'boolean(/D:options/D:activity-collection-set)' ) ) {
+			$this->setResponseHeader( 'Content-Type: text/xml; charset="utf-8"' );
+
+			echo "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n";
+			echo "<D:options-response xmlns:D=\"DAV:\">\n";
+			echo '  <D:activity-collection-set><D:href>' . $this->getUrl( array( 'path' => 'deltav.php/act' ) ) . "</D:href></D:activity-collection-set>\n";
+			echo "</D:options-response>\n";
+		}
+
+		return true;
+	}
+
+	function propfind( &$serverOptions ) {
+		if ( empty( $this->pathComponents ) ) {
+			return;
+		}
+		$pathComponent = array_shift( $this->pathComponents );
+		if ( $pathComponent != 'deltav.php' && $pathComponent != 'webdav.php' ) {
+			return;
+		}
+
+		if ( $pathComponent == 'deltav.php' ) {
+			if ( empty( $this->pathComponents ) ) {
+				return;
+			}
+			$pathComponent = array_shift( $this->pathComponents );
+			if ( $pathComponent != 'bc' && $pathComponent != 'bln' && $pathComponent != 'vcc' && $pathComponent != 'ver' ) {
+				return;
+			}
+
+			if ( $pathComponent == 'vcc' ) {
+				if ( empty( $this->pathComponents ) ) {
+					return;
+				}
+				$pathComponent = array_shift( $this->pathComponents );
+				if ( $pathComponent != 'default' ) {
+					return;
+				}
+				if ( !empty( $this->pathComponents ) ) {
+					return;
+				}
+
+				if ( isset( $serverOptions['label'] ) ) {
+					return $this->propfindBln( $serverOptions, $serverOptions['label'] );
+				}
+
+				return $this->propfindVcc( $serverOptions );
+			}
+
+			if ( empty( $this->pathComponents ) ) {
+				return;
+			}
+			$revisionId = array_shift( $this->pathComponents );
+
+			if ( $pathComponent == 'bc' ) {
+				return $this->propfindBc( $serverOptions, $revisionId, $this->pathComponents );
+			}
+
+			if ( !empty( $this->pathComponents ) ) {
+				return;
+			}
+
+			if ( $pathComponent == 'bln' ) {
+				return $this->propfindBln( $serverOptions, $revisionId );
+			}
+
+			return $this->propfindVer( $serverOptions, $revisionId );
+		}
+
+		if ( isset( $serverOptions['label'] ) ) {
+			# TODO: Verify revision belongs to this resource, or should we care?
+			return $this->propfindVer( $serverOptions, $serverOptions['label'] );
+		}
+
+		$serverOptions['namespaces']['http://subversion.tigris.org/xmlns/dav/'] = 'V';
+
+		$status = array();
+
+		# Handle root collection
+		if ( empty( $this->pathComponents ) ) {
+			global $wgSitename;
+
+			$response = array();
+			$response['path'] = 'webdav.php/';
+
+			# TODO: Use Main_Page revision?
+			$response['props'][] = WebDavServer::mkprop( 'checked-in', $this->getUrl( array( 'path' => 'deltav.php/ver' ) ) );
+
+			$response['props'][] = WebDavServer::mkprop( 'displayname', $wgSitename );
+			$response['props'][] = WebDavServer::mkprop( 'getcontentlength', 0 );
+			$response['props'][] = WebDavServer::mkprop( 'getcontenttype', 'httpd/unix-directory' );
+			$response['props'][] = WebDavServer::mkprop( 'resourcetype', 'collection' );
+			$response['props'][] = WebDavServer::mkprop( 'version-controlled-configuration', $this->getUrl( array( 'path' => 'deltav.php/vcc/default' ) ) );
+
+			$response['props'][] = WebDavServer::mkprop( 'http://subversion.tigris.org/xmlns/dav/', 'baseline-relative-path', null );
+
+			# TODO: Don't hardcode this
+			$response['props'][] = WebDavServer::mkprop( 'http://subversion.tigris.org/xmlns/dav/', 'repository-uuid', '87a9137c-6795-46f8-83b9-2ee953e66e08' );
+
+			$status[] = $response;
+
+			# Don't descend if depth is zero
+			if ( empty( $serverOptions['depth'] ) ) {
+				return $status;
+			}
+		}
+
+		# TODO: Use $wgMemc
+		$dbr =& wfGetDB( DB_SLAVE );
+
+		# TODO: Think harder about pages' hierarchical structure.  The trouble is most filesystems don't support directories which themselves have file content, which is a problem for making pages descendents of other pages.
+		$where = array();
+		if ( !empty( $this->pathComponents ) ) {
+			$where[] = 'page_title = ' . $dbr->addQuotes( implode( '/', $this->pathComponents ) );
+		}
+
+		$whereClause = null;
+		if ( !empty( $where ) ) {
+			$whereClause = ' WHERE ' . implode( ' AND ', $where );
+		}
+		$results = $dbr->query( '
+			SELECT page_title, page_latest, page_len, page_touched
+			FROM page' . $whereClause );
+
+		while ( ( $result = $dbr->fetchRow( $results ) ) !== false ) {
+			# TODO: Should maybe not be using page_title as URL component, but it's currently what we do elsewhere
+			$title = Title::newFromUrl( $result[0] );
+
+			$response = array();
+			$response['path'] = 'webdav.php/' . $result[0];
+			$response['props'][] = WebDavServer::mkprop( 'checked-in', $this->getUrl( array( 'path' => 'deltav.php/ver/' . $result[1] ) ) );
+			$response['props'][] = WebDavServer::mkprop( 'displayname', $title->getText() );
+			$response['props'][] = WebDavServer::mkprop( 'getcontentlength', $result[2] );
+			$response['props'][] = WebDavServer::mkprop( 'getcontenttype', 'text/x-wiki' );
+			$response['props'][] = WebDavServer::mkprop( 'getlastmodified', wfTimestamp( TS_UNIX, $result[3] ) );
+			$response['props'][] = WebDavServer::mkprop( 'resourcetype', null );
+			$response['props'][] = WebDavServer::mkprop( 'version-controlled-configuration', $this->getUrl( array( 'path' => 'deltav.php/vcc/default' ) ) );
+
+			$response['props'][] = WebDavServer::mkprop( 'http://subversion.tigris.org/xmlns/dav/', 'baseline-relative-path', $result[0] );
+
+			$status[] = $response;
+		}
+
+		return $status;
+	}
+
+	function propfindBc( &$serverOptions, $revisionId, $pathComponents ) {
+		$serverOptions['namespaces']['http://subversion.tigris.org/xmlns/dav/'] = 'V';
+
+		$status = array();
+
+		# TODO: Verify $revisionId is valid
+		# Handle root collection
+		if ( empty( $pathComponents ) ) {
+			global $wgSitename;
+
+			$response = array();
+			$response['path'] = 'deltav.php/bc/' . $revisionId . '/';
+			# TODO: Use Main_Page revision?
+			$response['props'][] = WebDavServer::mkprop( 'checked-in', $this->getUrl( array( 'path' => 'deltav.php/ver' ) ) );
+
+			$response['props'][] = WebDavServer::mkprop( 'displayname', $wgSitename );
+			$response['props'][] = WebDavServer::mkprop( 'getcontentlength', 0 );
+			$response['props'][] = WebDavServer::mkprop( 'getcontenttype', 'httpd/unix-directory' );
+			$response['props'][] = WebDavServer::mkprop( 'resourcetype', 'collection' );
+			$response['props'][] = WebDavServer::mkprop( 'version-controlled-configuration', $this->getUrl( array( 'path' => 'deltav.php/vcc/default' ) ) );
+			$response['props'][] = WebDavServer::mkprop( 'version-name', null );
+
+			$response['props'][] = WebDavServer::mkprop( 'http://subversion.tigris.org/xmlns/dav/', 'baseline-relative-path', null );
+
+			# TODO: Don't hardcode this
+			$response['props'][] = WebDavServer::mkprop( 'http://subversion.tigris.org/xmlns/dav/', 'repository-uuid', '87a9137c-6795-46f8-83b9-2ee953e66e08' );
+
+			$status[] = $response;
+
+			# Don't descend if depth is zero
+			if ( empty( $serverOptions['depth'] ) ) {
+				return $status;
+			}
+		}
+
+		# TODO: Use $wgMemc
+		$dbr =& wfGetDB( DB_SLAVE );
+
+		# TODO: Think harder about pages' hierarchical structure.  The trouble is most filesystems don't support directories which themselves have file content, which is a problem for making pages descendents of other pages.
+		$where = array();
+		$where[] = 'rev_page = page_id';
+		$where[] = 'rev_id <= ' . $dbr->addQuotes( $revisionId );
+		if ( !empty( $pathComponents ) ) {
+			$where[] = 'page_title = ' . $dbr->addQuotes( implode( '/', $pathComponents ) );
+		}
+
+		$whereClause = null;
+		if ( !empty( $where ) ) {
+			$whereClause = ' WHERE ' . implode( ' AND ', $where );
+		}
+		$results = $dbr->query( '
+			SELECT page_title, MAX(rev_id), page_len, page_touched
+			FROM page, revision' . $whereClause . '
+			GROUP BY page_id' );
+
+		while ( ( $result = $dbr->fetchRow( $results ) ) !== false ) {
+			# TODO: Should maybe not be using page_title as URL component, but it's currently what we do elsewhere
+			$title = Title::newFromUrl( $result[0] );
+
+			$response = array();
+			$response['path'] = 'deltav.php/bc/' . $revisionId . '/' . $result[0];
+			$response['props'][] = WebDavServer::mkprop( 'checked-in', $this->getUrl( array( 'path' => 'deltav.php/ver/' . $result[1] ) ) );
+			$response['props'][] = WebDavServer::mkprop( 'displayname', $title->getText() );
+			$response['props'][] = WebDavServer::mkprop( 'getcontentlength', $result[2] );
+			$response['props'][] = WebDavServer::mkprop( 'getcontenttype', 'text/x-wiki' );
+			$response['props'][] = WebDavServer::mkprop( 'getlastmodified', wfTimestamp( TS_UNIX, $result[3] ) );
+			$response['props'][] = WebDavServer::mkprop( 'resourcetype', null );
+			$response['props'][] = WebDavServer::mkprop( 'version-controlled-configuration', $this->getUrl( array( 'path' => 'deltav.php/vcc/default' ) ) );
+			$response['props'][] = WebDavServer::mkprop( 'version-name', $result[1] );
+
+			$response['props'][] = WebDavServer::mkprop( 'http://subversion.tigris.org/xmlns/dav/', 'baseline-relative-path', $result[0] );
+
+			# TODO: Don't hardcode this
+			$response['props'][] = WebDavServer::mkprop( 'http://subversion.tigris.org/xmlns/dav/', 'repository-uuid', '87a9137c-6795-46f8-83b9-2ee953e66e08' );
+
+			$status[] = $response;
+		}
+
+		return $status;
+	}
+
+	function propfindBln( &$serverOptions, $revisionId ) {
+		$response = array();
+		$response['path'] = 'bln/' . $revisionId;
+		$response['props'][] = WebDavServer::mkprop( 'baseline-collection', $this->getUrl( array( 'path' => 'deltav.php/bc/' . $revisionId . '/' ) ) );
+		$response['props'][] = WebDavServer::mkprop( 'version-name', $revisionId );
+
+		return array( $response );
+	}
+
+	function propfindVcc( &$serverOptions ) {
+		# TODO: Use $wgMemc
+		$dbr =& wfGetDB( DB_SLAVE );
+
+		$results = $dbr->query( '
+			SELECT MAX(rev_id)
+			FROM revision' );
+
+		if ( ( $result = $dbr->fetchRow( $results ) ) === false ) {
+			return;
+		}
+
+		$response = array();
+		$response['path'] = 'deltav.php/vcc/default';
+		$response['props'][] = WebDavServer::mkprop( 'checked-in', $this->getUrl( array( 'path' => 'deltav.php/bln/' . $result[0] ) ) );
+
+		return array( $response );
+	}
+
+	function propfindVer( &$serverOptions, $revisionId ) {
+		$response = array();
+		$response['path'] = 'deltav.php/ver/' . $revisionId;
+		$response['props'][] = WebDavServer::mkprop( 'resourcetype', null );
+		#$response['props'][] = WebDavServer::mkprop( 'version-controlled-configuration', $this->getUrl( array( 'path' => 'deltav.php/vcc/default' ) ) );
+
+		#$response['props'][] = WebDavServer::mkprop( 'http://subversion.tigris.org/xmlns/dav/', 'baseline-relative-path', null );
+
+		return array( $response );
+	}
+
+	function getRawPage() {
+		if ( empty( $this->pathComponents ) ) {
+			return;
+		}
+		$pathComponent = array_shift( $this->pathComponents );
+		if ( $pathComponent != 'deltav.php' && $pathComponent != 'webdav.php' ) {
+			return;
+		}
+
+		if ( $pathComponent == 'deltav.php' ) {
+			if ( empty( $this->pathComponents ) ) {
+				return;
+			}
+			$pathComponent = array_shift( $this->pathComponents );
+			if ( $pathComponent != 'bc' && $pathComponent != 'ver' ) {
+				return;
+			}
+
+			if ( empty( $this->pathComponents ) ) {
+				return;
+			}
+			$revisionId = array_shift( $this->pathComponents );
+
+			if ( $pathComponent == 'bc' ) {
+				$title = Title::newFromUrl( implode( '/', $this->pathComponents ) );
+				if (!isset( $title )) {
+					$title = Title::newMainPage();
+				}
+			} else {
+				if ( !empty( $this->pathComponents ) ) {
+					return;
+				}
+
+				$revision = Revision::newFromId( $revisionId );
+				$title = $revision->getTitle();
+			}
+		} else {
+			if ( isset( $serverOptions['label'] ) ) {
+				# TODO: Verify revision belongs to this resource, or should we care?
+				$revisionId = $serverOptions['label'];
+			}
+
+			$title = Title::newFromUrl( implode( '/', $this->pathComponents ) );
+			if (!isset( $title )) {
+				$title = Title::newMainPage();
+			}
+		}
+
+		$mediaWiki = new MediaWiki();
+		$article = $mediaWiki->articleFromTitle( $title );
+
+		$rawPage = new RawPage( $article );
+
+		if ( isset( $revisionId ) ) {
+			$rawPage->mOldId = $revisionId;
+		}
+		
+		return $rawPage;
+	}
+
+	# RawPage::view handles Content-Type, Cache-Control, etc. and we don't want get_response_helper to overwrite, but MediaWiki doesn't let us get response headers.  It could work if we kept setResponseHeader updated with headers_list on PHP 5.
+	function get_wrapper() {
+		$rawPage = $this->getRawPage();
+		if ( !isset( $rawPage ) ) {
+			$this->setResponseStatus( false, false );
+			return;
+		}
+
+		$rawPage->view();
+	}
+
+	function head_wrapper() {
+		$rawPage = $this->getRawPage();
+		if ( !isset( $rawPage ) ) {
+			$this->setResponseStatus( false, false );
+			return;
+		}
+
+		# TODO: Does MediaWiki handle HEAD requests specially?
+		ob_start();
+		$rawPage->view();
+		ob_end_clean();
+	}
+
+	function delete( $serverOptions ) {
+		global $wgUser;
+
+		if ( !$wgUser->isAllowed( 'delete' ) ) {
+			$this->setResponseStatus( '401 Unauthorized' );
+			return;
+		}
+
+		if ( wfReadOnly() ) {
+			$this->setResponseStatus( '403 Forbidden' );
+			return;
+		}
+
+		if ( empty( $this->pathComponents ) ) {
+			return;
+		}
+		$pathComponent = array_shift( $this->pathComponents );
+		if ( $pathComponent != 'webdav.php' ) {
+			return;
+		}
+
+		$title = Title::newFromUrl( implode( '/', $this->pathComponents ) );
+		if (!isset( $title )) {
+			$title = Title::newMainPage();
+		}
+
+		$mediaWiki = new MediaWiki();
+		$article = $mediaWiki->articleFromTitle( $title );
+
+		# Must check if article exists to avoid 500 Internal Server Error
+
+		# No way to get reason for deletion.  Can't use null: MySQL returned error "<tt>1048: Column 'log_comment' cannot be null (localhost)</tt>".
+		$article->doDelete( null );
+	}
+
+	function put( $serverOptions ) {
+		global $wgUser;
+
+		if ( !$wgUser->isAllowed( 'edit' ) ) {
+			$this->setResponseStatus( '401 Unauthorized' );
+			return;
+		}
+
+		if ( wfReadOnly() ) {
+			$this->setResponseStatus( '403 Forbidden' );
+			return;
+		}
+
+		if ( empty( $this->pathComponents ) ) {
+			return;
+		}
+		$pathComponent = array_shift( $this->pathComponents );
+		if ( $pathComponent != 'webdav.php' ) {
+			return;
+		}
+
+		$title = Title::newFromUrl( implode( '/', $this->pathComponents ) );
+		if (!isset( $title )) {
+			$title = Title::newMainPage();
+		}
+
+		if ( !$title->exists() && !$title->userCan( 'create' ) ) {
+			$this->setResponseStatus( '401 Unauthorized' );
+			return;
+		}
+
+		$mediaWiki = new MediaWiki();
+		$article = $mediaWiki->articleFromTitle( $title );
+
+		if ( ( $handle = $this->openRequestBody() ) === false ) {
+			return;
+		}
+
+		$text = null;
+		while ( !feof( $handle ) ) {
+			if ( ( $buffer = fread( $handle, 4096 ) ) === false ) {
+				return;
+			}
+
+			$text .= $buffer;
+		}
+
+		$article->doEdit( $text, null );
+
+		return true;
+	}
+
+	function versionTreeReport( &$serverOptions ) {
+		if ( empty( $this->pathComponents ) ) {
+			return;
+		}
+		$pathComponent = array_shift( $this->pathComponents );
+		if ( $pathComponent != 'deltav.php' && $pathComponent != 'webdav.php' ) {
+			return;
+		}
+
+		$serverOptions['props'] = array();
+		foreach ( $serverOptions['xpath']->query( '/D:version-tree/D:prop/*' ) as $node) {
+			$serverOptions['props'][] = $this->mkprop( $node->namespaceURI, $node->localName, null );
+
+			# Namespace handling
+			if ( empty( $node->namespaceURI ) || empty( $node->prefix ) ) {
+			    continue;
+			}
+
+			# http://bugs.php.net/bug.php?id=42082
+			#$serverOptions['namespaces'][$node->namespaceURI] = $node->prefix;
+		}
+
+		if (empty($serverOptions['props'])) {
+			$serverOptions['props'] = $serverOptions['xpath']->evaluate( 'local-name(/D:version-tree/*)' );
+		}
+
+		$status = array();
+
+		# Handle root collection
+		if ( empty( $this->pathComponents ) ) {
+			$response = array();
+			$response['props'][] = WebDavServer::mkprop( 'getcontentlength', 0 );
+			$response['props'][] = WebDavServer::mkprop( 'getcontenttype', 'httpd/unix-directory' );
+			$response['props'][] = WebDavServer::mkprop( 'resourcetype', 'collection' );
+
+			$status[] = $response;
+
+			# Don't descend if depth is zero
+			if ( empty( $serverOptions['depth'] ) ) {
+				return $status;
+			}
+		}
+
+		# TODO: Use $wgMemc
+		$dbr =& wfGetDB( DB_SLAVE );
+
+		# TODO: Think harder about pages' hierarchical structure.  The trouble is most filesystems don't support directories which themselves have file content, which is a problem for making pages descendents of other pages.
+		$where = array();
+		$where[] = 'rev_page = page_id';
+		if ( !empty( $this->pathComponents ) ) {
+			$where[] = 'page_title = ' . $dbr->addQuotes( implode( '/', $this->pathComponents ) );
+		}
+
+		$whereClause = null;
+		if ( !empty( $where ) ) {
+			$whereClause = ' WHERE ' . implode( ' AND ', $where );
+		}
+		$results = $dbr->query( '
+			SELECT page_title, rev_id, rev_comment, rev_user_text, rev_len, rev_timestamp, rev_parent_id
+			FROM page, revision' . $whereClause );
+
+		$successors = array();
+		while ( ( $result = $dbr->fetchRow( $results ) ) !== false ) {
+			$response = array();
+			$response['path'] = 'deltav.php/ver/' . $result[1];
+			$response['props'][] = WebDavServer::mkprop( 'comment', $result[2] );
+			$response['props'][] = WebDavServer::mkprop( 'creator-displayname', $result[3] );
+			$response['props'][] = WebDavServer::mkprop( 'getcontentlength', $result[4] );
+			$response['props'][] = WebDavServer::mkprop( 'getcontenttype', 'text/x-wiki' );
+			$response['props'][] = WebDavServer::mkprop( 'getlastmodified', wfTimestamp( TS_UNIX, $result[5] ) );
+			$response['props'][] = WebDavServer::mkprop( 'predecessor-set', array( $result[6] ) );
+			$response['props'][] = WebDavServer::mkprop( 'resourcetype', null );
+			$response['props'][] = WebDavServer::mkprop( 'successor-set', array() );
+			$response['props'][] = WebDavServer::mkprop( 'version-name', $result[1] );
+
+			$status[$result[1]] = $response;
+
+			# Build successor-set
+			$successors[$result[6]][] = $result[1];
+		}
+
+		return $status;
+	}
+
+	function updateReport( &$serverOptions ) {
+		if ( empty( $this->pathComponents ) ) {
+			return;
+		}
+		$pathComponent = array_shift( $this->pathComponents );
+		if ( $pathComponent != 'deltav.php' ) {
+			return;
+		}
+
+		if ( empty( $this->pathComponents ) ) {
+			return;
+		}
+		$pathComponent = array_shift( $this->pathComponents );
+		if ( $pathComponent != 'vcc' ) {
+			return;
+		}
+
+		if ( empty( $this->pathComponents ) ) {
+			return;
+		}
+		$pathComponent = array_shift( $this->pathComponents );
+		if ( $pathComponent != 'default' ) {
+			return;
+		}
+		if ( !empty( $this->pathComponents ) ) {
+			return;
+		}
+
+		# TODO: Can we ignore this?
+		if ( isset( $serverOptions['label'] ) ) {
+			return;
+		}
+
+		$serverOptions['xpath']->registerNamespace( 'S', 'svn:' );
+
+		# TODO: Error checking?
+		$targetRevision = $serverOptions['xpath']->evaluate( 'string(/S:update-report/S:target-revision)' );
+
+		# src-path is a misnomer, it's a URL
+		$srcPath = $serverOptions['xpath']->evaluate( 'string(/S:update-report/S:src-path)' );
+		$srcComponents = $this->parseUrl( $srcPath );
+		$srcComponents['pathComponents'] = array_slice( $srcComponents['pathComponents'], count( $this->baseUrlComponents['pathComponents'] ) + 1 );
+
+		# TODO: Use $wgMemc
+		$dbr =& wfGetDB( DB_SLAVE );
+
+		$entryConditions = array();
+		foreach ( $serverOptions['xpath']->query( '/S:update-report/S:entry' ) as $node ) {
+			$entryConditions[$node->textContent] = null;
+			if ( !$node->hasAttribute( 'start-empty' ) ) {
+
+				# TODO: Error checking?
+				$entryConditions[$node->textContent] = 'new.rev_id > ' . $dbr->addQuotes( $node->getAttribute( 'rev' ) );
+			}
+		}
+
+		function cmp( $a, $b ) {
+			return strlen( $a ) - strlen( $b );
+		}
+		uksort( $entryConditions, 'cmp' );
+
+		$entryCondition = null;
+		foreach ( $entryConditions as $path => $revisionCondition ) {
+			if ( !empty( $path ) ) {
+				$pathCondition = '(page_title = ' . $dbr->addQuotes( $path ) . ' OR page_title LIKE \'' . $dbr->escapeLike( $path ) . '/%\')';
+
+				if ( !empty( $revisionCondition ) ) {
+					$revisionCondition = ' AND ' . $revisionCondition;
+				}
+				$revisionCondition = $pathCondition . $revisionCondition;
+
+				if ( !empty( $entryCondition ) ) {
+					$entryCondition = ' AND ' . $entryCondition;
+				}
+				$entryCondition = 'NOT ' . $pathCondition . $entryCondition;
+			}
+
+			if ( !empty( $revisionCondition ) ) {
+				if ( !empty( $entryCondition ) ) {
+					$revisionCondition = '(' . $revisionCondition;
+					$entryCondition = ' OR ' . $entryCondition . ')';
+				}
+				$entryCondition = $revisionCondition . $entryCondition;
+			}
+		}
+		if ( !empty( $entryCondition ) ) {
+			$entryCondition = ' AND ' . $entryCondition;
+		}
+
+		$where = array();
+		if ( !empty( $targetRevision ) ) {
+			$where[] = 'old.rev_id <= ' . $dbr->addQuotes( $targetRevision );
+		}
+		if ( !empty( $srcComponents['pathComponents'] ) ) {
+			$where[] = 'page_title = ' . $dbr->addQuotes( implode( '/', $srcComponents['pathComponents'] ) );
+		}
+
+		if ( empty( $targetRevision ) ) {
+			$results = $dbr->query( '
+				SELECT MAX(rev_id)
+				FROM revision' );
+
+			if ( ( $result = $dbr->fetchRow( $results ) ) === false ) {
+				return;
+			}
+
+			$targetRevision = $result[0];
+		}
+
+		$this->setResponseHeader( 'Content-Type: text/xml; charset="utf-8"', false );
+
+		echo "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n";
+		echo "<S:update-report xmlns:D=\"DAV:\" xmlns:S=\"svn:\" xmlns:V=\"http://subversion.tigris.org/xmlns/dav\" send-all=\"true\">\n";
+
+		# TODO: Get the revision from the report request
+		echo "  <S:target-revision rev=\"$targetRevision\"/>\n";
+
+		# TODO: Use Main_Page revision?
+		echo "  <S:open-directory rev=\"$targetRevision\">\n";
+		echo '    <D:checked-in><D:href>' . $this->getUrl( array( 'path' => 'deltav.php/ver' ) ) . "</D:href></D:checked-in>\n";
+
+		$whereClause = null;
+		if ( !empty( $where ) ) {
+			$whereClause = ' WHERE ' . implode( ' AND ', $where );
+		}
+
+		# SUM(new.rev_id IS NULL) is the number of revisions which didn't match the entry condition
+		# TODO: Invert entry condition to make getting the base revision cleaner
+		$results = $dbr->query( '
+			SELECT page_title, SUM(new.rev_id IS NULL), MAX(CASE WHEN new.rev_id IS NULL THEN old.rev_id ELSE NULL END), MAX(new.rev_id)
+			FROM page
+			JOIN revision AS old
+			ON page_id = old.rev_page
+			LEFT JOIN revision AS new
+			ON old.rev_id = new.rev_id' . $entryCondition . $whereClause . '
+			GROUP BY page_id
+			HAVING COUNT(new.rev_id)' );
+
+		while ( ( $result = $dbr->fetchRow( $results ) ) !== false ) {
+			$addOrOpen = 'add';
+			$baseRev = null;
+
+			$newText = Revision::newFromId( $result[3] )->revText();
+			$oldText = null;
+
+			if ( $result[1] > 0 ) {
+				$addOrOpen = 'open';
+				$baseRev = ' rev="' . $result[2] . '"';
+
+				$oldText = Revision::newFromId( $result[2] )->revText();
+			}
+
+			# TODO: Use only last path component
+			echo "    <S:$addOrOpen-file name=\"$result[0]\"$baseRev>\n";
+
+			echo '      <D:checked-in><D:href>' . $this->getUrl( array( 'path' => 'deltav.php/ver/' . $result[3] ) ) . "</D:href></D:checked-in>\n";
+			echo '      <S:txdelta>' . base64_encode( $this->getSvnDiff( $oldText, $newText ) ) . "\n</S:txdelta>\n";
+			echo '      <S:prop><V:md5-checksum>' . md5( $newText ) . "</V:md5-checksum></S:prop>\n";
+			echo "    </S:$addOrOpen-file>\n";
+		}
+
+		echo "  </S:open-directory>\n";
+		echo "</S:update-report>\n";
+
+		return true;
+	}
+
+	function getSvnDiff( $oldText, $newText ) {
+		$instructions = chr( 0x80 | strlen( $newText ) );
+		if ( strlen( $newText ) > 0x37 ) {
+			$instructions = "\x80" . $this->encodeInt( strlen( $newText ) );
+		}
+
+		return "SVN\x00\x00"
+			. $this->encodeInt( strlen( $oldText ) )
+			. $this->encodeInt( strlen( $newText ) )
+			. $this->encodeInt( strlen( $instructions ) )
+			. $this->encodeInt( strlen( $newText ) )
+			. $instructions
+			. $newText;
+	}
+
+	function encodeInt( $int ) {
+		# Least seven bits
+		$bytes = chr( $int & 0x7f );
+
+		# Shift by seven bits until nothing remains
+		while ( 0 < $int >>= 7 ) {
+			# Prepend seven bits with the eighth bit, the continuation bit, set, to the string of bytes
+			$bytes = chr( $int & 0x7f | 0x80 ) . $bytes;
+		}
+
+		return $bytes;
+	}
+
+	function search( &$serverOptions ) {
+		$serverOptions['namespaces']['http://subversion.tigris.org/xmlns/dav/'] = 'V';
+
+		$status = array();
+
+		$search = SearchEngine::create();
+
+		# TODO: Use (int)$wgUser->getOption( 'searchlimit' );
+		$search->setLimitOffset( MW_SEARCH_LIMIT );
+
+		$results = $search->searchText( $serverOptions['xpath']->evaluate( 'string(/D:searchrequest/D:basicsearch/D:where/D:contains)' ) );
+
+		while ( ( $result = $results->next() ) !== false ) {
+			$title = $result->getTitle();
+			$revision = Revision::newFromTitle( $title );
+
+			$response = array();
+			$response['path'] = 'webdav.php/' . $title->getPrefixedUrl();
+			$response['props'][] = WebDavServer::mkprop( 'checked-in', $this->getUrl( array( 'path' => 'deltav.php/ver/' . $revision->getId() ) ) );
+			$response['props'][] = WebDavServer::mkprop( 'displayname', $title->getText() );
+			$response['props'][] = WebDavServer::mkprop( 'getcontentlength', $revision->getSize() );
+			$response['props'][] = WebDavServer::mkprop( 'getcontenttype', 'text/x-wiki' );
+			$response['props'][] = WebDavServer::mkprop( 'getlastmodified', wfTimestamp( TS_UNIX, $revision->mTimestamp ) );
+			$response['props'][] = WebDavServer::mkprop( 'resourcetype', null );
+			$response['props'][] = WebDavServer::mkprop( 'version-controlled-configuration', $this->getUrl( array( 'path' => 'deltav.php/vcc/default' ) ) );
+
+			$response['props'][] = WebDavServer::mkprop( 'http://subversion.tigris.org/xmlns/dav/', 'baseline-relative-path', $title->getFullUrl() );
+			$response['score'] = $result->getScore();
+
+			$status[] = $response;
+		}
+
+		# TODO: Check if we exceed our limit
+		#$response = array();
+		#$response['status'] = '507 Insufficient Storage';
+
+		#$status[] = $response;
+
+		return $status;
+	}
+}

Property changes on: trunk/extensions/WebDAV/WebDavServer.php
___________________________________________________________________
Added: svn:eol-style
   + native
Added: svn:keywords
   + Author Id Revision

Index: trunk/extensions/WebDAV/deltav.php
===================================================================
--- trunk/extensions/WebDAV/deltav.php	(revision 37160)
+++ trunk/extensions/WebDAV/deltav.php	(revision 37161)
@@ -3,7 +3,7 @@
 # Initialise common code
 require_once( './includes/WebStart.php' );
 
-require_once( './WebDav.php' );
+require_once( './WebDavServer.php' );
 
 $server = new WebDavServer();
 $server->handleRequest();
Index: trunk/extensions/WebDAV/webdav.php
===================================================================
--- trunk/extensions/WebDAV/webdav.php	(revision 37160)
+++ trunk/extensions/WebDAV/webdav.php	(revision 37161)
@@ -3,7 +3,7 @@
 # Initialise common code
 require_once( './includes/WebStart.php' );
 
-require_once( './WebDav.php' );
+require_once( './WebDavServer.php' );
 
 $server = new WebDavServer;
 $server->handleRequest();

Follow-up revisions

Rev.Commit summaryAuthorDate
r37162some leftout on the previous commit r37161shinjiman12:06, 6 July 2008

Status & tagging log

  • 15:28, 12 September 2011 Meno25 (Talk | contribs) changed the status of r37161 [removed: ok added: old]
Personal tools
Namespaces
Variants
Views
Actions
Site
Support
Download
Development
Communication
Toolbox