protected $maxFileSize = 4294967296; // integer bytes (4GiB)
+ const CACHE_TTL = 10; // integer; TTL in seconds for process cache entries
+
/**
* @see FileBackend::__construct()
*
* - 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.
* - 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.
$subDir = $params['dir'] . "/{$subDirRel}"; // full path
$status->merge( $this->doClean( array( 'dir' => $subDir ) + $params ) );
}
+ unset( $subDirsRel ); // free directory for rmdir() on Windows (for FS backends)
}
}
wfProfileIn( __METHOD__ );
wfProfileIn( __METHOD__ . '-' . $this->name );
$latest = !empty( $params['latest'] ); // use latest data?
- if ( !$this->cheapCache->has( $path, 'stat' ) ) {
+ if ( !$this->cheapCache->has( $path, 'stat', self::CACHE_TTL ) ) {
$this->primeFileCache( array( $path ) ); // check persistent cache
}
- if ( $this->cheapCache->has( $path, 'stat' ) ) {
+ 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.
- if ( !$latest || $stat['latest'] ) {
+ // 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;
$stat = $this->doGetFileStat( $params );
wfProfileOut( __METHOD__ . '-miss-' . $this->name );
wfProfileOut( __METHOD__ . '-miss' );
- if ( is_array( $stat ) ) { // don't cache negatives
+ if ( is_array( $stat ) ) { // file exists
$stat['latest'] = $latest;
$this->cheapCache->set( $path, 'stat', $stat );
$this->setFileCache( $path, $stat ); // update persistent cache
$this->cheapCache->set( $path, 'sha1',
array( 'hash' => $stat['sha1'], 'latest' => $latest ) );
}
- } else {
+ } elseif ( $stat === false ) { // file does not exist
+ $this->cheapCache->set( $path, 'stat', false );
wfDebug( __METHOD__ . ": File $path does not exist.\n" );
+ } else { // an error occurred
+ wfDebug( __METHOD__ . ": Could not stat file $path.\n" );
}
wfProfileOut( __METHOD__ . '-' . $this->name );
wfProfileOut( __METHOD__ );
wfProfileIn( __METHOD__ );
wfProfileIn( __METHOD__ . '-' . $this->name );
$latest = !empty( $params['latest'] ); // use latest data?
- if ( $this->cheapCache->has( $path, 'sha1' ) ) {
+ if ( $this->cheapCache->has( $path, 'sha1', self::CACHE_TTL ) ) {
$stat = $this->cheapCache->get( $path, 'sha1' );
// If we want the latest data, check that this cached
// value was in fact fetched with the latest available data.
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 );
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
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] );
+ }
+ }
+ }
+ return $op;
+ }
+
/**
* @see FileBackend::preloadCache()
*/