From: Aaron Schulz Date: Tue, 6 Nov 2012 20:49:40 +0000 (-0800) Subject: [FileBackend] Added getFileHttpUrl() function. X-Git-Tag: 1.31.0-rc.0~21697 X-Git-Url: http://git.cyclocoop.org/fichier?a=commitdiff_plain;h=9f95bddda711da1567be0e4ad2781eefba320e1e;p=lhc%2Fweb%2Fwiklou.git [FileBackend] Added getFileHttpUrl() function. * This can speed up certain video file operations for scripts that support specifying source files via URLs and support HTTP Range headers. * Updated unit tests. Change-Id: I60cb95c2e3dd9f7df1f740e9182be7c79af69d6e --- diff --git a/includes/filebackend/FileBackend.php b/includes/filebackend/FileBackend.php index e01bfc2e5b..b5e231540b 100644 --- a/includes/filebackend/FileBackend.php +++ b/includes/filebackend/FileBackend.php @@ -904,6 +904,24 @@ abstract class FileBackend { */ abstract public function getLocalCopyMulti( array $params ); + /** + * Return an HTTP URL to a given file that requires no authentication to use. + * The URL may be pre-authenticated (via some token in the URL) and temporary. + * This will return null if the backend cannot make an HTTP URL for the file. + * + * This is useful for key/value stores when using scripts that seek around + * large files and those scripts (and the backend) support HTTP Range headers. + * Otherwise, one would need to use getLocalReference(), which involves loading + * the entire file on to local disk. + * + * @param $params Array + * $params include: + * - src : source storage path + * @return string|null + * @since 1.21 + */ + abstract public function getFileHttpUrl( array $params ); + /** * Check if a directory exists at a given storage path. * Backends using key/value stores will check if the path is a diff --git a/includes/filebackend/FileBackendMultiWrite.php b/includes/filebackend/FileBackendMultiWrite.php index 90292ee027..a443a3aadd 100644 --- a/includes/filebackend/FileBackendMultiWrite.php +++ b/includes/filebackend/FileBackendMultiWrite.php @@ -651,6 +651,15 @@ class FileBackendMultiWrite extends FileBackend { return $tempFiles; } + /** + * @see FileBackend::getFileHttpUrl() + * @return string|null + */ + public function getFileHttpUrl( array $params ) { + $realParams = $this->substOpPaths( $params, $this->backends[$this->masterIndex] ); + return $this->backends[$this->masterIndex]->getFileHttpUrl( $realParams ); + } + /** * @see FileBackend::directoryExists() * @param $params array diff --git a/includes/filebackend/FileBackendStore.php b/includes/filebackend/FileBackendStore.php index 7e91949e68..97e49a5a09 100644 --- a/includes/filebackend/FileBackendStore.php +++ b/includes/filebackend/FileBackendStore.php @@ -804,6 +804,14 @@ abstract class FileBackendStore extends FileBackend { */ abstract protected function doGetLocalCopyMulti( array $params ); + /** + * @see FileBackend::getFileHttpUrl() + * @return string|null + */ + public function getFileHttpUrl( array $params ) { + return null; // not supported + } + /** * @see FileBackend::streamFile() * @return Status diff --git a/includes/filebackend/SwiftFileBackend.php b/includes/filebackend/SwiftFileBackend.php index 8441f8fc8e..48db9d3c3f 100644 --- a/includes/filebackend/SwiftFileBackend.php +++ b/includes/filebackend/SwiftFileBackend.php @@ -40,6 +40,7 @@ class SwiftFileBackend extends FileBackendStore { /** @var CF_Authentication */ protected $auth; // Swift authentication handler protected $authTTL; // integer seconds + protected $swiftTempUrlKey; // string; shared secret value for making temp urls protected $swiftAnonUser; // string; username to handle unauthenticated requests protected $swiftUseCDN; // boolean; whether CloudFiles CDN is enabled protected $swiftCDNExpiry; // integer; how long to cache things in the CDN @@ -66,6 +67,8 @@ class SwiftFileBackend extends FileBackendStore { * - swiftUser : Swift user used by MediaWiki (account:username) * - swiftKey : Swift authentication key for the above user * - swiftAuthTTL : Swift authentication TTL (seconds) + * - swiftTempUrlKey : Swift "X-Account-Meta-Temp-URL-Key" value on the account. + * Do not set this until it has been set in the backend. * - swiftAnonUser : Swift user used for end-user requests (account:username). * If set, then views of public containers are assumed to go * through this user. If not set, then public containers are @@ -104,6 +107,9 @@ class SwiftFileBackend extends FileBackendStore { $this->swiftAnonUser = isset( $config['swiftAnonUser'] ) ? $config['swiftAnonUser'] : ''; + $this->swiftTempUrlKey = isset( $config['swiftTempUrlKey'] ) + ? $config['swiftTempUrlKey'] + : ''; $this->shardViaHashLevels = isset( $config['shardViaHashLevels'] ) ? $config['shardViaHashLevels'] : ''; @@ -1119,6 +1125,28 @@ class SwiftFileBackend extends FileBackendStore { return $tmpFiles; } + /** + * @see FileBackendStore::getFileHttpUrl() + * @return string|null + */ + public function getFileHttpUrl( array $params ) { + if ( $this->swiftTempUrlKey != '' ) { // temp urls enabled + list( $srcCont, $srcRel ) = $this->resolveStoragePathReal( $params['src'] ); + if ( $srcRel === null ) { + return null; // invalid path + } + try { + $sContObj = $this->getContainer( $srcCont ); + $obj = new CF_Object( $sContObj, $srcRel, false, false ); // skip HEAD + return $obj->get_temp_url( $this->swiftTempUrlKey, 86400, "GET" ); + } catch ( NoSuchContainerException $e ) { + } catch ( CloudFilesException $e ) { // some other exception? + $this->handleException( $e, null, __METHOD__, $params ); + } + } + return null; + } + /** * @see FileBackendStore::directoriesAreVirtual() * @return bool diff --git a/tests/phpunit/includes/filebackend/FileBackendTest.php b/tests/phpunit/includes/filebackend/FileBackendTest.php index da36e90060..b6d44fd5ed 100644 --- a/tests/phpunit/includes/filebackend/FileBackendTest.php +++ b/tests/phpunit/includes/filebackend/FileBackendTest.php @@ -1181,6 +1181,50 @@ class FileBackendTest extends MediaWikiTestCase { $this->assertEquals( null, $tmpFile, "Local ref of not existing file is null ($backendName)." ); } + /** + * @dataProvider provider_testGetFileHttpUrl + */ + public function testGetFileHttpUrl( $source, $content ) { + $this->backend = $this->singleBackend; + $this->tearDownFiles(); + $this->doTestGetFileHttpUrl( $source, $content ); + $this->tearDownFiles(); + + $this->backend = $this->multiBackend; + $this->tearDownFiles(); + $this->doTestGetFileHttpUrl( $source, $content ); + $this->tearDownFiles(); + } + + private function doTestGetFileHttpUrl( $source, $content ) { + $backendName = $this->backendClass(); + + $this->prepare( array( 'dir' => dirname( $source ) ) ); + $status = $this->backend->doOperation( + array( 'op' => 'create', 'content' => $content, 'dst' => $source ) ); + $this->assertGoodStatus( $status, + "Creation of file at $source succeeded ($backendName)." ); + + $url = $this->backend->getFileHttpUrl( array( 'src' => $source ) ); + + if ( $url !== null ) { // supported + $data = Http::request( "GET", $url ); + $this->assertEquals( $content, $data, + "HTTP GET of URL has right contents ($backendName)." ); + } + } + + function provider_testGetFileHttpUrl() { + $cases = array(); + + $base = self::baseStorePath(); + $cases[] = array( "$base/unittest-cont1/e/a/z/some_file.txt", "some file contents" ); + $cases[] = array( "$base/unittest-cont1/e/a/some-other_file.txt", "more file contents" ); + $cases[] = array( "$base/unittest-cont1/e/a/\$odd&.txt", "test file contents" ); + + return $cases; + } + /** * @dataProvider provider_testPrepareAndClean */