/**
* @brief Class for an OpenStack Swift (or Ceph RGW) based file backend.
*
- * Status messages should avoid mentioning the Swift account name.
+ * StatusValue messages should avoid mentioning the Swift account name.
* Likewise, error suppression should be used to avoid path disclosure.
*
* @ingroup FileBackend
}
protected function doCreateInternal( array $params ) {
- $status = Status::newGood();
+ $status = $this->newStatus();
list( $dstCont, $dstRel ) = $this->resolveStoragePathReal( $params['dst'] );
if ( $dstRel === null ) {
] ];
$method = __METHOD__;
- $handler = function ( array $request, Status $status ) use ( $method, $params ) {
+ $handler = function ( array $request, StatusValue $status ) use ( $method, $params ) {
list( $rcode, $rdesc, $rhdrs, $rbody, $rerr ) = $request['response'];
if ( $rcode === 201 ) {
// good
}
protected function doStoreInternal( array $params ) {
- $status = Status::newGood();
+ $status = $this->newStatus();
list( $dstCont, $dstRel ) = $this->resolveStoragePathReal( $params['dst'] );
if ( $dstRel === null ) {
] ];
$method = __METHOD__;
- $handler = function ( array $request, Status $status ) use ( $method, $params ) {
+ $handler = function ( array $request, StatusValue $status ) use ( $method, $params ) {
list( $rcode, $rdesc, $rhdrs, $rbody, $rerr ) = $request['response'];
if ( $rcode === 201 ) {
// good
}
protected function doCopyInternal( array $params ) {
- $status = Status::newGood();
+ $status = $this->newStatus();
list( $srcCont, $srcRel ) = $this->resolveStoragePathReal( $params['src'] );
if ( $srcRel === null ) {
] ];
$method = __METHOD__;
- $handler = function ( array $request, Status $status ) use ( $method, $params ) {
+ $handler = function ( array $request, StatusValue $status ) use ( $method, $params ) {
list( $rcode, $rdesc, $rhdrs, $rbody, $rerr ) = $request['response'];
if ( $rcode === 201 ) {
// good
}
protected function doMoveInternal( array $params ) {
- $status = Status::newGood();
+ $status = $this->newStatus();
list( $srcCont, $srcRel ) = $this->resolveStoragePathReal( $params['src'] );
if ( $srcRel === null ) {
}
$method = __METHOD__;
- $handler = function ( array $request, Status $status ) use ( $method, $params ) {
+ $handler = function ( array $request, StatusValue $status ) use ( $method, $params ) {
list( $rcode, $rdesc, $rhdrs, $rbody, $rerr ) = $request['response'];
if ( $request['method'] === 'PUT' && $rcode === 201 ) {
// good
}
protected function doDeleteInternal( array $params ) {
- $status = Status::newGood();
+ $status = $this->newStatus();
list( $srcCont, $srcRel ) = $this->resolveStoragePathReal( $params['src'] );
if ( $srcRel === null ) {
] ];
$method = __METHOD__;
- $handler = function ( array $request, Status $status ) use ( $method, $params ) {
+ $handler = function ( array $request, StatusValue $status ) use ( $method, $params ) {
list( $rcode, $rdesc, $rhdrs, $rbody, $rerr ) = $request['response'];
if ( $rcode === 204 ) {
// good
}
protected function doDescribeInternal( array $params ) {
- $status = Status::newGood();
+ $status = $this->newStatus();
list( $srcCont, $srcRel ) = $this->resolveStoragePathReal( $params['src'] );
if ( $srcRel === null ) {
] ];
$method = __METHOD__;
- $handler = function ( array $request, Status $status ) use ( $method, $params ) {
+ $handler = function ( array $request, StatusValue $status ) use ( $method, $params ) {
list( $rcode, $rdesc, $rhdrs, $rbody, $rerr ) = $request['response'];
if ( $rcode === 202 ) {
// good
}
protected function doPrepareInternal( $fullCont, $dir, array $params ) {
- $status = Status::newGood();
+ $status = $this->newStatus();
// (a) Check if container already exists
$stat = $this->getContainerStat( $fullCont );
}
protected function doSecureInternal( $fullCont, $dir, array $params ) {
- $status = Status::newGood();
+ $status = $this->newStatus();
if ( empty( $params['noAccess'] ) ) {
return $status; // nothing to do
}
}
protected function doPublishInternal( $fullCont, $dir, array $params ) {
- $status = Status::newGood();
+ $status = $this->newStatus();
$stat = $this->getContainerStat( $fullCont );
if ( is_array( $stat ) ) {
}
protected function doCleanInternal( $fullCont, $dir, array $params ) {
- $status = Status::newGood();
+ $status = $this->newStatus();
// Only containers themselves can be removed, all else is virtual
if ( $dir != '' ) {
// Find prior metadata headers
$postHeaders += $this->getMetadataHeaders( $objHdrs );
- $status = Status::newGood();
+ $status = $this->newStatus();
/** @noinspection PhpUnusedLocalVariableInspection */
$scopeLockS = $this->getScopedFileLocks( [ $path ], LockManager::LOCK_UW, $status );
if ( $status->isOK() ) {
}
protected function doStreamFile( array $params ) {
- $status = Status::newGood();
+ $status = $this->newStatus();
+
+ $flags = !empty( $params['headless'] ) ? StreamFile::STREAM_HEADLESS : 0;
list( $srcCont, $srcRel ) = $this->resolveStoragePathReal( $params['src'] );
if ( $srcRel === null ) {
+ StreamFile::send404Message( $params['src'], $flags );
$status->fatal( 'backend-fail-invalidpath', $params['src'] );
+
+ return $status;
}
$auth = $this->getAuthentication();
if ( !$auth || !is_array( $this->getContainerStat( $srcCont ) ) ) {
+ StreamFile::send404Message( $params['src'], $flags );
$status->fatal( 'backend-fail-stream', $params['src'] );
return $status;
}
- $handle = fopen( 'php://output', 'wb' );
+ // If "headers" is set, we only want to send them if the file is there.
+ // Do not bother checking if the file exists if headers are not set though.
+ if ( $params['headers'] && !$this->fileExists( $params ) ) {
+ StreamFile::send404Message( $params['src'], $flags );
+ $status->fatal( 'backend-fail-stream', $params['src'] );
+ return $status;
+ }
+
+ // Send the requested additional headers
+ foreach ( $params['headers'] as $header ) {
+ header( $header ); // aways send
+ }
+
+ if ( empty( $params['allowOB'] ) ) {
+ // Cancel output buffering and gzipping if set
+ wfResetOutputBuffers();
+ }
+
+ $handle = fopen( 'php://output', 'wb' );
list( $rcode, $rdesc, $rhdrs, $rbody, $rerr ) = $this->http->run( [
'method' => 'GET',
'url' => $this->storageUrl( $auth, $srcCont, $srcRel ),
'headers' => $this->authTokenHeaders( $auth )
- + $this->headersFromParams( $params ),
+ + $this->headersFromParams( $params ) + $params['options'],
'stream' => $handle,
+ 'flags' => [ 'relayResponseHeaders' => empty( $params['headless'] ) ]
] );
if ( $rcode >= 200 && $rcode <= 299 ) {
// good
} elseif ( $rcode === 404 ) {
$status->fatal( 'backend-fail-stream', $params['src'] );
+ // Per bug 41113, nasty things can happen if bad cache entries get
+ // stuck in cache. It's also possible that this error can come up
+ // with simple race conditions. Clear out the stat cache to be safe.
+ $this->clearCache( [ $params['src'] ] );
+ $this->deleteFileCache( $params['src'] );
} else {
$this->onError( $status, __METHOD__, $params, $rerr, $rcode, $rdesc );
}
/**
* @param FileBackendStoreOpHandle[] $fileOpHandles
*
- * @return Status[]
+ * @return StatusValue[]
*/
protected function doExecuteOpHandlesInternal( array $fileOpHandles ) {
$statuses = [];
$auth = $this->getAuthentication();
if ( !$auth ) {
foreach ( $fileOpHandles as $index => $fileOpHandle ) {
- $statuses[$index] = Status::newFatal( 'backend-fail-connect', $this->name );
+ $statuses[$index] = $this->newStatus( 'backend-fail-connect', $this->name );
}
return $statuses;
$req['headers'] = $this->authTokenHeaders( $auth ) + $req['headers'];
$httpReqsByStage[$stage][$index] = $req;
}
- $statuses[$index] = Status::newGood();
+ $statuses[$index] = $this->newStatus();
}
// Run all requests for the first stage, then the next, and so on
* @param array $writeGrps A list of the possible criteria for a request to have
* access to write to a container. Each item is of the following format:
* - account:user : Grants access if the request is by the given user
- * @return Status
+ * @return StatusValue
*/
protected function setContainerAccess( $container, array $readGrps, array $writeGrps ) {
- $status = Status::newGood();
+ $status = $this->newStatus();
$auth = $this->getAuthentication();
if ( !$auth ) {
*
* @param string $container Container name
* @param array $params
- * @return Status
+ * @return StatusValue
*/
protected function createContainer( $container, array $params ) {
- $status = Status::newGood();
+ $status = $this->newStatus();
$auth = $this->getAuthentication();
if ( !$auth ) {
*
* @param string $container Container name
* @param array $params
- * @return Status
+ * @return StatusValue
*/
protected function deleteContainer( $container, array $params ) {
- $status = Status::newGood();
+ $status = $this->newStatus();
$auth = $this->getAuthentication();
if ( !$auth ) {
* @param string|null $after
* @param string|null $prefix
* @param string|null $delim
- * @return Status With the list as value
+ * @return StatusValue With the list as value
*/
private function objectListing(
$fullCont, $type, $limit, $after = null, $prefix = null, $delim = null
) {
- $status = Status::newGood();
+ $status = $this->newStatus();
$auth = $this->getAuthentication();
if ( !$auth ) {
/**
* Log an unexpected exception for this backend.
- * This also sets the Status object to have a fatal error.
+ * This also sets the StatusValue object to have a fatal error.
*
- * @param Status|null $status
+ * @param StatusValue|null $status
* @param string $func
* @param array $params
* @param string $err Error string
* @param int $code HTTP status
- * @param string $desc HTTP status description
+ * @param string $desc HTTP StatusValue description
*/
public function onError( $status, $func, array $params, $err = '', $code = 0, $desc = '' ) {
- if ( $status instanceof Status ) {
+ if ( $status instanceof StatusValue ) {
$status->fatal( 'backend-fail-internal', $this->name );
}
if ( $code == 401 ) { // possibly a stale token