X-Git-Url: https://git.heureux-cyclage.org/?a=blobdiff_plain;f=includes%2Ffilebackend%2FFileBackendStore.php;h=b906af53ce1ecc8c1e1b23adc17a026199df3b58;hb=ac56107ba319ee1e0d268fe353fc37d0134ad57e;hp=0f435a399df4ed429ad659afc6a306c6a115e3a4;hpb=65612b4290c218731e9ac4c89ff9a87ec187214a;p=lhc%2Fweb%2Fwiklou.git diff --git a/includes/filebackend/FileBackendStore.php b/includes/filebackend/FileBackendStore.php index 0f435a399d..b906af53ce 100644 --- a/includes/filebackend/FileBackendStore.php +++ b/includes/filebackend/FileBackendStore.php @@ -90,12 +90,15 @@ abstract class FileBackendStore extends FileBackend { * Do not call this function from places outside FileBackend and FileOp. * * $params include: - * - content : the raw file contents - * - dst : destination storage path - * - disposition : Content-Disposition header value for the destination - * - async : Status will be returned immediately if supported. - * If the status is OK, then its value field will be - * set to a FileBackendStoreOpHandle object. + * - content : the raw file contents + * - dst : destination storage path + * - disposition : Content-Disposition header value for the destination + * - headers : HTTP header name/value map + * - async : Status will be returned immediately if supported. + * If the status is OK, then its value field will be + * set to a FileBackendStoreOpHandle object. + * - dstExists : Whether a file exists at the destination (optimization). + * Callers can use "false" if no existing file is being changed. * * @param $params Array * @return Status @@ -109,7 +112,9 @@ abstract class FileBackendStore extends FileBackend { } else { $status = $this->doCreateInternal( $params ); $this->clearCache( array( $params['dst'] ) ); - $this->deleteFileCache( $params['dst'] ); // persistent cache + if ( !isset( $params['dstExists'] ) || $params['dstExists'] ) { + $this->deleteFileCache( $params['dst'] ); // persistent cache + } } wfProfileOut( __METHOD__ . '-' . $this->name ); wfProfileOut( __METHOD__ ); @@ -118,6 +123,7 @@ abstract class FileBackendStore extends FileBackend { /** * @see FileBackendStore::createInternal() + * @return Status */ abstract protected function doCreateInternal( array $params ); @@ -127,12 +133,15 @@ abstract class FileBackendStore extends FileBackend { * Do not call this function from places outside FileBackend and FileOp. * * $params include: - * - src : source path on disk - * - dst : destination storage path - * - disposition : Content-Disposition header value for the destination - * - async : Status will be returned immediately if supported. - * If the status is OK, then its value field will be - * set to a FileBackendStoreOpHandle object. + * - src : source path on disk + * - dst : destination storage path + * - disposition : Content-Disposition header value for the destination + * - headers : HTTP header name/value map + * - async : Status will be returned immediately if supported. + * If the status is OK, then its value field will be + * set to a FileBackendStoreOpHandle object. + * - dstExists : Whether a file exists at the destination (optimization). + * Callers can use "false" if no existing file is being changed. * * @param $params Array * @return Status @@ -146,7 +155,9 @@ abstract class FileBackendStore extends FileBackend { } else { $status = $this->doStoreInternal( $params ); $this->clearCache( array( $params['dst'] ) ); - $this->deleteFileCache( $params['dst'] ); // persistent cache + if ( !isset( $params['dstExists'] ) || $params['dstExists'] ) { + $this->deleteFileCache( $params['dst'] ); // persistent cache + } } wfProfileOut( __METHOD__ . '-' . $this->name ); wfProfileOut( __METHOD__ ); @@ -155,6 +166,7 @@ abstract class FileBackendStore extends FileBackend { /** * @see FileBackendStore::storeInternal() + * @return Status */ abstract protected function doStoreInternal( array $params ); @@ -171,6 +183,8 @@ abstract class FileBackendStore extends FileBackend { * - async : Status will be returned immediately if supported. * If the status is OK, then its value field will be * set to a FileBackendStoreOpHandle object. + * - dstExists : Whether a file exists at the destination (optimization). + * Callers can use "false" if no existing file is being changed. * * @param $params Array * @return Status @@ -180,7 +194,9 @@ abstract class FileBackendStore extends FileBackend { wfProfileIn( __METHOD__ . '-' . $this->name ); $status = $this->doCopyInternal( $params ); $this->clearCache( array( $params['dst'] ) ); - $this->deleteFileCache( $params['dst'] ); // persistent cache + if ( !isset( $params['dstExists'] ) || $params['dstExists'] ) { + $this->deleteFileCache( $params['dst'] ); // persistent cache + } wfProfileOut( __METHOD__ . '-' . $this->name ); wfProfileOut( __METHOD__ ); return $status; @@ -188,6 +204,7 @@ abstract class FileBackendStore extends FileBackend { /** * @see FileBackendStore::copyInternal() + * @return Status */ abstract protected function doCopyInternal( array $params ); @@ -218,6 +235,7 @@ abstract class FileBackendStore extends FileBackend { /** * @see FileBackendStore::deleteInternal() + * @return Status */ abstract protected function doDeleteInternal( array $params ); @@ -234,6 +252,8 @@ abstract class FileBackendStore extends FileBackend { * - async : Status will be returned immediately if supported. * If the status is OK, then its value field will be * set to a FileBackendStoreOpHandle object. + * - dstExists : Whether a file exists at the destination (optimization). + * Callers can use "false" if no existing file is being changed. * * @param $params Array * @return Status @@ -244,7 +264,9 @@ abstract class FileBackendStore extends FileBackend { $status = $this->doMoveInternal( $params ); $this->clearCache( array( $params['src'], $params['dst'] ) ); $this->deleteFileCache( $params['src'] ); // persistent cache - $this->deleteFileCache( $params['dst'] ); // persistent cache + if ( !isset( $params['dstExists'] ) || $params['dstExists'] ) { + $this->deleteFileCache( $params['dst'] ); // persistent cache + } wfProfileOut( __METHOD__ . '-' . $this->name ); wfProfileOut( __METHOD__ ); return $status; @@ -266,6 +288,40 @@ abstract class FileBackendStore extends FileBackend { return $status; } + /** + * Alter metadata for a file at the storage path. + * Do not call this function from places outside FileBackend and FileOp. + * + * $params include: + * - src : source storage path + * - disposition : Content-Disposition header value for the destination + * - headers : HTTP header name/value map + * - async : Status will be returned immediately if supported. + * If the status is OK, then its value field will be + * set to a FileBackendStoreOpHandle object. + * + * @param $params Array + * @return Status + */ + final public function describeInternal( array $params ) { + wfProfileIn( __METHOD__ ); + wfProfileIn( __METHOD__ . '-' . $this->name ); + $status = $this->doDescribeInternal( $params ); + $this->clearCache( array( $params['src'] ) ); + $this->deleteFileCache( $params['src'] ); // persistent cache + wfProfileOut( __METHOD__ . '-' . $this->name ); + wfProfileOut( __METHOD__ ); + return $status; + } + + /** + * @see FileBackendStore::describeInternal() + * @return Status + */ + protected function doDescribeInternal( array $params ) { + return Status::newGood(); + } + /** * No-op file operation that does nothing. * Do not call this function from places outside FileBackend and FileOp. @@ -610,12 +666,19 @@ abstract class FileBackendStore extends FileBackend { if ( $this->cheapCache->has( $path, 'stat', self::CACHE_TTL ) ) { $stat = $this->cheapCache->get( $path, 'stat' ); // If we want the latest data, check that this cached - // value was in fact fetched with the latest available data - // (the process cache is ignored if it contains a negative). - if ( !$latest || ( is_array( $stat ) && $stat['latest'] ) ) { - wfProfileOut( __METHOD__ . '-' . $this->name ); - wfProfileOut( __METHOD__ ); - return $stat; + // value was in fact fetched with the latest available data. + if ( is_array( $stat ) ) { + if ( !$latest || $stat['latest'] ) { + wfProfileOut( __METHOD__ . '-' . $this->name ); + wfProfileOut( __METHOD__ ); + return $stat; + } + } elseif ( in_array( $stat, array( 'NOT_EXIST', 'NOT_EXIST_LATEST' ) ) ) { + if ( !$latest || $stat === 'NOT_EXIST_LATEST' ) { + wfProfileOut( __METHOD__ . '-' . $this->name ); + wfProfileOut( __METHOD__ ); + return false; + } } } wfProfileIn( __METHOD__ . '-miss' ); @@ -632,7 +695,7 @@ abstract class FileBackendStore extends FileBackend { array( 'hash' => $stat['sha1'], 'latest' => $latest ) ); } } elseif ( $stat === false ) { // file does not exist - $this->cheapCache->set( $path, 'stat', false ); + $this->cheapCache->set( $path, 'stat', $latest ? 'NOT_EXIST_LATEST' : 'NOT_EXIST' ); wfDebug( __METHOD__ . ": File $path does not exist.\n" ); } else { // an error occurred wfDebug( __METHOD__ . ": Could not stat file $path.\n" ); @@ -995,12 +1058,13 @@ abstract class FileBackendStore extends FileBackend { */ final public function getOperationsInternal( array $ops ) { $supportedOps = array( - 'store' => 'StoreFileOp', - 'copy' => 'CopyFileOp', - 'move' => 'MoveFileOp', - 'delete' => 'DeleteFileOp', - 'create' => 'CreateFileOp', - 'null' => 'NullFileOp' + 'store' => 'StoreFileOp', + 'copy' => 'CopyFileOp', + 'move' => 'MoveFileOp', + 'delete' => 'DeleteFileOp', + 'create' => 'CreateFileOp', + 'describe' => 'DescribeFileOp', + 'null' => 'NullFileOp' ); $performOps = array(); // array of FileOp objects @@ -1066,6 +1130,9 @@ abstract class FileBackendStore extends FileBackend { wfProfileIn( __METHOD__ . '-' . $this->name ); $status = Status::newGood(); + // Fix up custom header name/value pairs... + $ops = array_map( array( $this, 'stripInvalidHeadersFromOp' ), $ops ); + // Build up a list of FileOps... $performOps = $this->getOperationsInternal( $ops ); @@ -1115,6 +1182,12 @@ abstract class FileBackendStore extends FileBackend { wfProfileIn( __METHOD__ . '-' . $this->name ); $status = Status::newGood(); + // Fix up custom header name/value pairs... + $ops = array_map( array( $this, 'stripInvalidHeadersFromOp' ), $ops ); + + // Clear any file cache entries + $this->clearCache(); + $supportedOps = array( 'create', 'store', 'copy', 'move', 'delete', 'null' ); $async = ( $this->parallelize === 'implicit' ); $maxConcurrency = $this->concurrency; // throttle @@ -1206,6 +1279,26 @@ abstract class FileBackendStore extends FileBackend { return array(); } + /** + * Strip long HTTP headers from a file operation + * + * @param $op array Same format as doOperation() + * @return Array + */ + protected function stripInvalidHeadersFromOp( array $op ) { + if ( isset( $op['headers'] ) ) { + foreach ( $op['headers'] as $name => $value ) { + if ( strlen( $name ) > 255 || strlen( $value ) > 255 ) { + trigger_error( "Header '$name: $value' is too long." ); + unset( $op['headers'][$name] ); + } elseif ( !strlen( $value ) ) { + $op['headers'][$name] = ''; // null/false => "" + } + } + } + return $op; + } + /** * @see FileBackend::preloadCache() */ @@ -1577,6 +1670,8 @@ abstract class FileBackendStore extends FileBackend { /** * Delete the cached stat info for a file path. * The cache key is salted for a while to prevent race conditions. + * Since negatives (404s) are not cached, this does not need to be called when + * a file is created at a path were there was none before. * * @param $path string Storage path */