X-Git-Url: https://git.heureux-cyclage.org/?a=blobdiff_plain;f=includes%2Ffilebackend%2FSwiftFileBackend.php;h=27493ae2c5f9ed52f544767f0871b43dc3f3a358;hb=0259fccfe3ac35088510b5e5765750b72d109a35;hp=d6bbfbe3be36f1ea1fdbe597fa8625237ea2a31e;hpb=d69d4a90442159bdc8d1bf07fdac3dcdb9292327;p=lhc%2Fweb%2Fwiklou.git diff --git a/includes/filebackend/SwiftFileBackend.php b/includes/filebackend/SwiftFileBackend.php index d6bbfbe3be..27493ae2c5 100644 --- a/includes/filebackend/SwiftFileBackend.php +++ b/includes/filebackend/SwiftFileBackend.php @@ -176,7 +176,7 @@ class SwiftFileBackend extends FileBackendStore { $headers = array(); // Normalize casing, and strip out illegal headers - if ( isset( $params['headers'] ) ) { + if ( isset( $params['headers'] ) ) { foreach ( $params['headers'] as $name => $value ) { $name = strtolower( $name ); if ( preg_match( '/^content-(type|length)$/', $name ) ) { @@ -220,20 +220,20 @@ class SwiftFileBackend extends FileBackendStore { $contentType = $this->getContentType( $params['dst'], $params['content'], null ); $reqs = array( array( - 'method' => 'PUT', - 'url' => array( $dstCont, $dstRel ), + 'method' => 'PUT', + 'url' => array( $dstCont, $dstRel ), 'headers' => array( - 'content-length' => strlen( $params['content'] ), - 'etag' => md5( $params['content'] ), - 'content-type' => $contentType, + 'content-length' => strlen( $params['content'] ), + 'etag' => md5( $params['content'] ), + 'content-type' => $contentType, 'x-object-meta-sha1base36' => $sha1Hash ) + $this->sanitizeHdrs( $params ), - 'body' => $params['content'] + 'body' => $params['content'] ) ); $be = $this; $method = __METHOD__; - $handler = function( array $request, Status $status ) use ( $be, $method, $params ) { + $handler = function ( array $request, Status $status ) use ( $be, $method, $params ) { list( $rcode, $rdesc, $rhdrs, $rbody, $rerr ) = $request['response']; if ( $rcode === 201 ) { // good @@ -275,7 +275,7 @@ class SwiftFileBackend extends FileBackendStore { $sha1Hash = wfBaseConvert( $sha1Hash, 16, 36, 31 ); $contentType = $this->getContentType( $params['dst'], null, $params['src'] ); - $handle = fopen( $params['src'], 'rb+' ); + $handle = fopen( $params['src'], 'rb' ); if ( $handle === false ) { // source doesn't exist? $status->fatal( 'backend-fail-store', $params['src'], $params['dst'] ); @@ -283,20 +283,20 @@ class SwiftFileBackend extends FileBackendStore { } $reqs = array( array( - 'method' => 'PUT', - 'url' => array( $dstCont, $dstRel ), + 'method' => 'PUT', + 'url' => array( $dstCont, $dstRel ), 'headers' => array( - 'content-length' => filesize( $params['src'] ), - 'etag' => md5_file( $params['src'] ), - 'content-type' => $contentType, + 'content-length' => filesize( $params['src'] ), + 'etag' => md5_file( $params['src'] ), + 'content-type' => $contentType, 'x-object-meta-sha1base36' => $sha1Hash ) + $this->sanitizeHdrs( $params ), - 'body' => $handle // resource + 'body' => $handle // resource ) ); $be = $this; $method = __METHOD__; - $handler = function( array $request, Status $status ) use ( $be, $method, $params ) { + $handler = function ( array $request, Status $status ) use ( $be, $method, $params ) { list( $rcode, $rdesc, $rhdrs, $rbody, $rerr ) = $request['response']; if ( $rcode === 201 ) { // good @@ -335,8 +335,8 @@ class SwiftFileBackend extends FileBackendStore { } $reqs = array( array( - 'method' => 'PUT', - 'url' => array( $dstCont, $dstRel ), + 'method' => 'PUT', + 'url' => array( $dstCont, $dstRel ), 'headers' => array( 'x-copy-from' => '/' . rawurlencode( $srcCont ) . '/' . str_replace( "%2F", "/", rawurlencode( $srcRel ) ) @@ -345,7 +345,7 @@ class SwiftFileBackend extends FileBackendStore { $be = $this; $method = __METHOD__; - $handler = function( array $request, Status $status ) use ( $be, $method, $params ) { + $handler = function ( array $request, Status $status ) use ( $be, $method, $params ) { list( $rcode, $rdesc, $rhdrs, $rbody, $rerr ) = $request['response']; if ( $rcode === 201 ) { // good @@ -385,8 +385,8 @@ class SwiftFileBackend extends FileBackendStore { $reqs = array( array( - 'method' => 'PUT', - 'url' => array( $dstCont, $dstRel ), + 'method' => 'PUT', + 'url' => array( $dstCont, $dstRel ), 'headers' => array( 'x-copy-from' => '/' . rawurlencode( $srcCont ) . '/' . str_replace( "%2F", "/", rawurlencode( $srcRel ) ) @@ -395,15 +395,15 @@ class SwiftFileBackend extends FileBackendStore { ); if ( "{$srcCont}/{$srcRel}" !== "{$dstCont}/{$dstRel}" ) { $reqs[] = array( - 'method' => 'DELETE', - 'url' => array( $srcCont, $srcRel ), + 'method' => 'DELETE', + 'url' => array( $srcCont, $srcRel ), 'headers' => array() ); } $be = $this; $method = __METHOD__; - $handler = function( array $request, Status $status ) use ( $be, $method, $params ) { + $handler = function ( array $request, Status $status ) use ( $be, $method, $params ) { list( $rcode, $rdesc, $rhdrs, $rbody, $rerr ) = $request['response']; if ( $request['method'] === 'PUT' && $rcode === 201 ) { // good @@ -436,16 +436,15 @@ class SwiftFileBackend extends FileBackendStore { return $status; } - $reqs = array( - array( - 'method' => 'DELETE', - 'url' => array( $srcCont, $srcRel ), - 'headers' => array() + $reqs = array( array( + 'method' => 'DELETE', + 'url' => array( $srcCont, $srcRel ), + 'headers' => array() ) ); $be = $this; $method = __METHOD__; - $handler = function( array $request, Status $status ) use ( $be, $method, $params ) { + $handler = function ( array $request, Status $status ) use ( $be, $method, $params ) { list( $rcode, $rdesc, $rhdrs, $rbody, $rerr ) = $request['response']; if ( $rcode === 204 ) { // good @@ -497,14 +496,14 @@ class SwiftFileBackend extends FileBackendStore { $customHdrs = $this->sanitizeHdrs( $params ) + $stat['xattr']['headers']; $reqs = array( array( - 'method' => 'POST', - 'url' => array( $srcCont, $srcRel ), + 'method' => 'POST', + 'url' => array( $srcCont, $srcRel ), 'headers' => $metaHdrs + $customHdrs ) ); $be = $this; $method = __METHOD__; - $handler = function( array $request, Status $status ) use ( $be, $method, $params ) { + $handler = function ( array $request, Status $status ) use ( $be, $method, $params ) { list( $rcode, $rdesc, $rhdrs, $rbody, $rerr ) = $request['response']; if ( $rcode === 202 ) { // good @@ -534,6 +533,7 @@ class SwiftFileBackend extends FileBackendStore { return $status; // already there } elseif ( $stat === null ) { $status->fatal( 'backend-fail-internal', $this->name ); + return $status; } @@ -603,6 +603,7 @@ class SwiftFileBackend extends FileBackendStore { return $status; // ok, nothing to do } elseif ( !is_array( $stat ) ) { $status->fatal( 'backend-fail-internal', $this->name ); + return $status; } @@ -636,8 +637,8 @@ class SwiftFileBackend extends FileBackendStore { // (b) Check the file list( $rcode, $rdesc, $rhdrs, $rbody, $rerr ) = $this->http->run( array( - 'method' => 'HEAD', - 'url' => $this->storageUrl( $auth, $srcCont, $srcRel ), + 'method' => 'HEAD', + 'url' => $this->storageUrl( $auth, $srcCont, $srcRel ), 'headers' => $this->authTokenHeaders( $auth ) + $this->headersFromParams( $params ) ) ); if ( $rcode === 200 || $rcode === 204 ) { @@ -656,9 +657,9 @@ class SwiftFileBackend extends FileBackendStore { // Convert various random Swift dates to TS_MW 'mtime' => $this->convertSwiftDate( $rhdrs['last-modified'], TS_MW ), // Empty objects actually return no content-length header in Ceph - 'size' => isset( $rhdrs['content-length'] ) ? (int)$rhdrs['content-length'] : 0, - 'sha1' => $rhdrs[ 'x-object-meta-sha1base36'], - 'md5' => ctype_xdigit( $rhdrs['etag'] ) ? $rhdrs['etag'] : null, + 'size' => isset( $rhdrs['content-length'] ) ? (int)$rhdrs['content-length'] : 0, + 'sha1' => $rhdrs['x-object-meta-sha1base36'], + 'md5' => ctype_xdigit( $rhdrs['etag'] ) ? $rhdrs['etag'] : null, 'xattr' => array( 'metadata' => $metadata, 'headers' => $headers ) ); } elseif ( $rcode === 404 ) { @@ -684,6 +685,7 @@ class SwiftFileBackend extends FileBackendStore { protected function convertSwiftDate( $ts, $format = TS_MW ) { try { $timestamp = new MWTimestamp( $ts ); + return $timestamp->getTimestamp( $format ); } catch ( MWException $e ) { throw new FileBackendError( $e->getMessage() ); @@ -708,6 +710,7 @@ class SwiftFileBackend extends FileBackendStore { $auth = $this->getAuthentication(); if ( !$auth ) { $objHdrs['x-object-meta-sha1base36'] = false; + return $objHdrs; // failed } @@ -721,8 +724,8 @@ class SwiftFileBackend extends FileBackendStore { $objHdrs['x-object-meta-sha1base36'] = $hash; list( $srcCont, $srcRel ) = $this->resolveStoragePathReal( $path ); list( $rcode, $rdesc, $rhdrs, $rbody, $rerr ) = $this->http->run( array( - 'method' => 'POST', - 'url' => $this->storageUrl( $auth, $srcCont, $srcRel ), + 'method' => 'POST', + 'url' => $this->storageUrl( $auth, $srcCont, $srcRel ), 'headers' => $this->authTokenHeaders( $auth ) + $objHdrs ) ); if ( $rcode >= 200 && $rcode <= 299 ) { @@ -745,46 +748,42 @@ class SwiftFileBackend extends FileBackendStore { $ep = array_diff_key( $params, array( 'srcs' => 1 ) ); // for error logging // Blindly create tmp files and stream to them, catching any exception if the file does // not exist. Doing stats here is useless and will loop infinitely in addMissingMetadata(). - foreach ( array_chunk( $params['srcs'], $params['concurrency'] ) as $pathBatch ) { - $reqs = array(); // (path => op) - - foreach ( $pathBatch as $path ) { // each path in this concurrent batch - list( $srcCont, $srcRel ) = $this->resolveStoragePathReal( $path ); - if ( $srcRel === null || !$auth ) { - $contents[$path] = false; - continue; - } - $data = false; - // Create a new temporary memory file... - $handle = fopen( 'php://temp', 'wb' ); - if ( $handle ) { - $reqs[$path] = array( - 'method' => 'GET', - 'url' => $this->storageUrl( $auth, $srcCont, $srcRel ), - 'headers' => $this->authTokenHeaders( $auth ) - + $this->headersFromParams( $params ), - 'stream' => $handle, - ); - } else { - $data = false; - } - $contents[$path] = $data; + $reqs = array(); // (path => op) + + foreach ( $params['srcs'] as $path ) { // each path in this concurrent batch + list( $srcCont, $srcRel ) = $this->resolveStoragePathReal( $path ); + if ( $srcRel === null || !$auth ) { + $contents[$path] = false; + continue; + } + // Create a new temporary memory file... + $handle = fopen( 'php://temp', 'wb' ); + if ( $handle ) { + $reqs[$path] = array( + 'method' => 'GET', + 'url' => $this->storageUrl( $auth, $srcCont, $srcRel ), + 'headers' => $this->authTokenHeaders( $auth ) + + $this->headersFromParams( $params ), + 'stream' => $handle, + ); } + $contents[$path] = false; + } - $reqs = $this->http->runMulti( $reqs ); - foreach ( $reqs as $path => $op ) { - list( $rcode, $rdesc, $rhdrs, $rbody, $rerr ) = $op['response']; - if ( $rcode >= 200 && $rcode <= 299 ) { - rewind( $op['stream'] ); // start from the beginning - $contents[$path] = stream_get_contents( $op['stream'] ); - } elseif ( $rcode === 404 ) { - $contents[$path] = false; - } else { - $this->onError( null, __METHOD__, - array( 'src' => $path ) + $ep, $rerr, $rcode, $rdesc ); - } - fclose( $op['stream'] ); // close open handle + $opts = array( 'maxConnsPerHost' => $params['concurrency'] ); + $reqs = $this->http->runMulti( $reqs, $opts ); + foreach ( $reqs as $path => $op ) { + list( $rcode, $rdesc, $rhdrs, $rbody, $rerr ) = $op['response']; + if ( $rcode >= 200 && $rcode <= 299 ) { + rewind( $op['stream'] ); // start from the beginning + $contents[$path] = stream_get_contents( $op['stream'] ); + } elseif ( $rcode === 404 ) { + $contents[$path] = false; + } else { + $this->onError( null, __METHOD__, + array( 'src' => $path ) + $ep, $rerr, $rcode, $rdesc ); } + fclose( $op['stream'] ); // close open handle } return $contents; @@ -796,6 +795,7 @@ class SwiftFileBackend extends FileBackendStore { if ( $status->isOk() ) { return ( count( $status->value ) ); } + return null; // error } @@ -853,20 +853,25 @@ class SwiftFileBackend extends FileBackendStore { $dirs[] = $object; // directories end in '/' } } - // Recursive: list all dirs under $dir and its subdirs } else { - $getParentDir = function( $path ) { + // Recursive: list all dirs under $dir and its subdirs + $getParentDir = function ( $path ) { return ( strpos( $path, '/' ) !== false ) ? dirname( $path ) : false; }; + // Get directory from last item of prior page $lastDir = $getParentDir( $after ); // must be first page $status = $this->objectListing( $fullCont, 'names', $limit, $after, $prefix ); + if ( !$status->isOk() ) { return $dirs; // error } + $objects = $status->value; + foreach ( $objects as $object ) { // files $objectDir = $getParentDir( $object ); // directory of object + if ( $objectDir !== false && $objectDir !== $dir ) { // Swift stores paths in UTF-8, using binary sorting. // See function "create_container_table" in common/db.py. @@ -924,20 +929,23 @@ class SwiftFileBackend extends FileBackendStore { } else { $status = $this->objectListing( $fullCont, 'names', $limit, $after, $prefix, '/' ); } - // Recursive: list all files under $dir and its subdirs } else { + // Recursive: list all files under $dir and its subdirs if ( !empty( $params['adviseStat'] ) ) { $status = $this->objectListing( $fullCont, 'info', $limit, $after, $prefix ); } else { $status = $this->objectListing( $fullCont, 'names', $limit, $after, $prefix ); } } + // Reformat this list into a list of (name, stat array or null) entries if ( !$status->isOk() ) { return $files; // error } + $objects = $status->value; $files = $this->buildFileObjectListing( $params, $dir, $objects ); + // Page on the unfiltered object listing (what is returned may be filtered) if ( count( $objects ) < $limit ) { $after = INF; // avoid a second RTT @@ -967,9 +975,9 @@ class SwiftFileBackend extends FileBackendStore { } $stat = array( // Convert various random Swift dates to TS_MW - 'mtime' => $this->convertSwiftDate( $object->last_modified, TS_MW ), - 'size' => (int)$object->bytes, - 'md5' => ctype_xdigit( $object->hash ) ? $object->hash : null, + 'mtime' => $this->convertSwiftDate( $object->last_modified, TS_MW ), + 'size' => (int)$object->bytes, + 'md5' => ctype_xdigit( $object->hash ) ? $object->hash : null, 'latest' => false // eventually consistent ); $names[] = array( $object->name, $stat ); @@ -1000,6 +1008,7 @@ class SwiftFileBackend extends FileBackendStore { $this->clearCache( array( $params['src'] ) ); $stat = $this->getFileStat( $params ); } + return $stat['xattr']; } else { return false; @@ -1032,17 +1041,18 @@ class SwiftFileBackend extends FileBackendStore { $auth = $this->getAuthentication(); if ( !$auth || !is_array( $this->getContainerStat( $srcCont ) ) ) { $status->fatal( 'backend-fail-stream', $params['src'] ); + return $status; } $handle = fopen( 'php://output', 'wb' ); list( $rcode, $rdesc, $rhdrs, $rbody, $rerr ) = $this->http->run( array( - 'method' => 'GET', - 'url' => $this->storageUrl( $auth, $srcCont, $srcRel ), + 'method' => 'GET', + 'url' => $this->storageUrl( $auth, $srcCont, $srcRel ), 'headers' => $this->authTokenHeaders( $auth ) + $this->headersFromParams( $params ), - 'stream' => $handle, + 'stream' => $handle, ) ); if ( $rcode >= 200 && $rcode <= 299 ) { @@ -1064,54 +1074,52 @@ class SwiftFileBackend extends FileBackendStore { $ep = array_diff_key( $params, array( 'srcs' => 1 ) ); // for error logging // Blindly create tmp files and stream to them, catching any exception if the file does // not exist. Doing a stat here is useless causes infinite loops in addMissingMetadata(). - foreach ( array_chunk( $params['srcs'], $params['concurrency'] ) as $pathBatch ) { - $reqs = array(); // (path => op) - - foreach ( $pathBatch as $path ) { // each path in this concurrent batch - list( $srcCont, $srcRel ) = $this->resolveStoragePathReal( $path ); - if ( $srcRel === null || !$auth ) { - $tmpFiles[$path] = null; - continue; - } - $tmpFile = null; - // Get source file extension - $ext = FileBackend::extensionFromPath( $path ); - // Create a new temporary file... - $tmpFile = TempFSFile::factory( 'localcopy_', $ext ); - if ( $tmpFile ) { - $handle = fopen( $tmpFile->getPath(), 'wb' ); - if ( $handle ) { - $reqs[$path] = array( - 'method' => 'GET', - 'url' => $this->storageUrl( $auth, $srcCont, $srcRel ), - 'headers' => $this->authTokenHeaders( $auth ) - + $this->headersFromParams( $params ), - 'stream' => $handle, - ); - } else { - $tmpFile = null; - } - } - $tmpFiles[$path] = $tmpFile; - } + $reqs = array(); // (path => op) - $reqs = $this->http->runMulti( $reqs ); - foreach ( $reqs as $path => $op ) { - list( $rcode, $rdesc, $rhdrs, $rbody, $rerr ) = $op['response']; - fclose( $op['stream'] ); // close open handle - if ( $rcode >= 200 && $rcode <= 299 - // double check that the disk is not full/broken - && $tmpFiles[$path]->getSize() == $rhdrs['content-length'] - ) { - // good - } elseif ( $rcode === 404 ) { - $tmpFiles[$path] = false; + foreach ( $params['srcs'] as $path ) { // each path in this concurrent batch + list( $srcCont, $srcRel ) = $this->resolveStoragePathReal( $path ); + if ( $srcRel === null || !$auth ) { + $tmpFiles[$path] = null; + continue; + } + // Get source file extension + $ext = FileBackend::extensionFromPath( $path ); + // Create a new temporary file... + $tmpFile = TempFSFile::factory( 'localcopy_', $ext ); + if ( $tmpFile ) { + $handle = fopen( $tmpFile->getPath(), 'wb' ); + if ( $handle ) { + $reqs[$path] = array( + 'method' => 'GET', + 'url' => $this->storageUrl( $auth, $srcCont, $srcRel ), + 'headers' => $this->authTokenHeaders( $auth ) + + $this->headersFromParams( $params ), + 'stream' => $handle, + ); } else { - $tmpFiles[$path] = null; - $this->onError( null, __METHOD__, - array( 'src' => $path ) + $ep, $rerr, $rcode, $rdesc ); + $tmpFile = null; } } + $tmpFiles[$path] = $tmpFile; + } + + $opts = array( 'maxConnsPerHost' => $params['concurrency'] ); + $reqs = $this->http->runMulti( $reqs, $opts ); + foreach ( $reqs as $path => $op ) { + list( $rcode, $rdesc, $rhdrs, $rbody, $rerr ) = $op['response']; + fclose( $op['stream'] ); // close open handle + if ( $rcode >= 200 && $rcode <= 299 + // double check that the disk is not full/broken + && $tmpFiles[$path]->getSize() == $rhdrs['content-length'] + ) { + // good + } elseif ( $rcode === 404 ) { + $tmpFiles[$path] = false; + } else { + $tmpFiles[$path] = null; + $this->onError( null, __METHOD__, + array( 'src' => $path ) + $ep, $rerr, $rcode, $rdesc ); + } } return $tmpFiles; @@ -1142,6 +1150,7 @@ class SwiftFileBackend extends FileBackendStore { "GET\n{$expires}\n{$contPath}/{$srcRel}", $this->swiftTempUrlKey ); + return "{$url}?temp_url_sig={$signature}&temp_url_expires={$expires}"; } else { // give S3 API URL for rgw // Path for signature starts with the bucket @@ -1199,6 +1208,7 @@ class SwiftFileBackend extends FileBackendStore { foreach ( $fileOpHandles as $index => $fileOpHandle ) { $statuses[$index] = Status::newFatal( 'backend-fail-connect', $this->name ); } + return $statuses; } @@ -1218,7 +1228,8 @@ class SwiftFileBackend extends FileBackendStore { } // Run all requests for the first stage, then the next, and so on - for ( $stage = 0; $stage < count( $httpReqsByStage ); ++$stage ) { + $reqCount = count( $httpReqsByStage ); + for ( $stage = 0; $stage < $reqCount; ++$stage ) { $httpReqs = $this->http->runMulti( $httpReqsByStage[$stage] ); foreach ( $httpReqs as $index => $httpReq ) { // Run the callback for each request of this operation @@ -1262,18 +1273,19 @@ class SwiftFileBackend extends FileBackendStore { */ protected function setContainerAccess( $container, array $readGrps, array $writeGrps ) { $status = Status::newGood(); - $auth = $this->getAuthentication(); + if ( !$auth ) { $status->fatal( 'backend-fail-connect', $this->name ); + return $status; } list( $rcode, $rdesc, $rhdrs, $rbody, $rerr ) = $this->http->run( array( - 'method' => 'POST', - 'url' => $this->storageUrl( $auth, $container ), + 'method' => 'POST', + 'url' => $this->storageUrl( $auth, $container ), 'headers' => $this->authTokenHeaders( $auth ) + array( - 'x-container-read' => implode( ',', $readGrps ), + 'x-container-read' => implode( ',', $readGrps ), 'x-container-write' => implode( ',', $writeGrps ) ) ) ); @@ -1306,8 +1318,8 @@ class SwiftFileBackend extends FileBackendStore { } list( $rcode, $rdesc, $rhdrs, $rbody, $rerr ) = $this->http->run( array( - 'method' => 'HEAD', - 'url' => $this->storageUrl( $auth, $container ), + 'method' => 'HEAD', + 'url' => $this->storageUrl( $auth, $container ), 'headers' => $this->authTokenHeaders( $auth ) ) ); @@ -1320,12 +1332,14 @@ class SwiftFileBackend extends FileBackendStore { return $stat; } else { $this->containerStatCache->set( $container, 'stat', $stat ); // cache it + $this->setContainerCache( $container, $stat ); // update persistent cache } } elseif ( $rcode === 404 ) { return false; } else { $this->onError( null, __METHOD__, array( 'cont' => $container ), $rerr, $rcode, $rdesc ); + return null; } } @@ -1346,6 +1360,7 @@ class SwiftFileBackend extends FileBackendStore { $auth = $this->getAuthentication(); if ( !$auth ) { $status->fatal( 'backend-fail-connect', $this->name ); + return $status; } @@ -1358,10 +1373,10 @@ class SwiftFileBackend extends FileBackendStore { $writeGrps = array( $this->swiftUser ); // sanity list( $rcode, $rdesc, $rhdrs, $rbody, $rerr ) = $this->http->run( array( - 'method' => 'PUT', - 'url' => $this->storageUrl( $auth, $container ), + 'method' => 'PUT', + 'url' => $this->storageUrl( $auth, $container ), 'headers' => $this->authTokenHeaders( $auth ) + array( - 'x-container-read' => implode( ',', $readGrps ), + 'x-container-read' => implode( ',', $readGrps ), 'x-container-write' => implode( ',', $writeGrps ) ) ) ); @@ -1390,12 +1405,13 @@ class SwiftFileBackend extends FileBackendStore { $auth = $this->getAuthentication(); if ( !$auth ) { $status->fatal( 'backend-fail-connect', $this->name ); + return $status; } list( $rcode, $rdesc, $rhdrs, $rbody, $rerr ) = $this->http->run( array( - 'method' => 'DELETE', - 'url' => $this->storageUrl( $auth, $container ), + 'method' => 'DELETE', + 'url' => $this->storageUrl( $auth, $container ), 'headers' => $this->authTokenHeaders( $auth ) ) ); @@ -1432,6 +1448,7 @@ class SwiftFileBackend extends FileBackendStore { $auth = $this->getAuthentication(); if ( !$auth ) { $status->fatal( 'backend-fail-connect', $this->name ); + return $status; } @@ -1450,9 +1467,9 @@ class SwiftFileBackend extends FileBackendStore { } list( $rcode, $rdesc, $rhdrs, $rbody, $rerr ) = $this->http->run( array( - 'method' => 'GET', - 'url' => $this->storageUrl( $auth, $fullCont ), - 'query' => $query, + 'method' => 'GET', + 'url' => $this->storageUrl( $auth, $fullCont ), + 'query' => $query, 'headers' => $this->authTokenHeaders( $auth ) ) ); @@ -1505,29 +1522,35 @@ class SwiftFileBackend extends FileBackendStore { $this->authSessionTimestamp = time() - ceil( $this->authTTL / 2 ); } else { // cache miss list( $rcode, $rdesc, $rhdrs, $rbody, $rerr ) = $this->http->run( array( - 'method' => 'GET', - 'url' => "{$this->swiftAuthUrl}/v1.0", + 'method' => 'GET', + 'url' => "{$this->swiftAuthUrl}/v1.0", 'headers' => array( - 'x-auth-user' => $this->swiftUser, 'x-auth-key' => $this->swiftKey ) + 'x-auth-user' => $this->swiftUser, + 'x-auth-key' => $this->swiftKey + ) ) ); if ( $rcode >= 200 && $rcode <= 299 ) { // OK $this->authCreds = array( - 'auth_token' => $rhdrs['x-auth-token'], + 'auth_token' => $rhdrs['x-auth-token'], 'storage_url' => $rhdrs['x-storage-url'] ); + $this->srvCache->set( $cacheKey, $this->authCreds, ceil( $this->authTTL / 2 ) ); $this->authSessionTimestamp = time(); } elseif ( $rcode === 401 ) { $this->onError( null, __METHOD__, array(), "Authentication failed.", $rcode ); $this->authErrorTimestamp = time(); + return null; } else { $this->onError( null, __METHOD__, array(), "HTTP return code: $rcode", $rcode ); $this->authErrorTimestamp = time(); + return null; } } } + return $this->authCreds; } @@ -1545,6 +1568,7 @@ class SwiftFileBackend extends FileBackendStore { if ( strlen( $object ) ) { $parts[] = str_replace( "%2F", "/", rawurlencode( $object ) ); } + return implode( '/', $parts ); } @@ -1563,7 +1587,7 @@ class SwiftFileBackend extends FileBackendStore { * @return string */ private function getCredsCacheKey( $username ) { - return wfMemcKey( 'backend', $this->getName(), 'usercreds', $username ); + return 'swiftcredentials:' . md5( $username . ':' . $this->swiftAuthUrl ); } /**