blob: 0904a738542a1424ddc0ae66446d8bf71547fcb4 [file] [log] [blame]
<?php
/**
* File containing the ezcWebdavLockCopyRequestResponseHandler class.
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
* @package Webdav
* @version //autogentag//
* @copyright Copyright (C) 2005-2010 eZ Systems AS. All rights reserved.
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0
*
* @access private
*/
/**
* Handler class for the COPY request.
*
* This class provides plugin callbacks for the COPY request for {@link
* ezcWebdavLockPlugin}.
*
* @package Webdav
* @version //autogen//
*
* @access private
*/
class ezcWebdavLockCopyRequestResponseHandler extends ezcWebdavLockRequestResponseHandler
{
/**
* Properties of the destination parent.
*
* These properties need to be set on the successfully moved the source to
* the destination. The properties still need to be manipulated in {@link
* generatedResponse()}
*
* @var ezcWebdavBasicPropertyStorage
*/
protected $lockProperties;
/**
* The original request.
*
* @var ezcWebdavCopyRequest
*/
protected $request;
/**
* Pathes moved to the destination.
*
* Used to determine all paths that need lock updates.
*
* @var array(string)
*/
protected $sourcePaths;
/**
* Handles COPY requests.
*
* Performs all lock related checks necessary for the COPY request. In case
* a violation with locks is detected or any other pre-condition check
* fails, this method returns an instance of {@link ezcWebdavResponse}. If
* everything is correct, null is returned, so that the $request is handled
* by the backend.
*
* @param ezcWebdavRequest $request ezcWebdavCopyRequest
* @return ezcWebdavResponse|null
*/
public function receivedRequest( ezcWebdavRequest $request )
{
$backend = ezcWebdavServer::getInstance()->backend;
$this->request = $request;
$destination = $request->getHeader( 'Destination' );
$destParent = dirname( $destination );
$ifHeader = $request->getHeader( 'If' );
$authHeader = $request->getHeader( 'Authorization' );
// Check destination parent and collect the lock properties to
// set after successfully moving
$destinationLockRefresher = new ezcWebdavLockRefreshRequestGenerator(
$request
);
$violation = $this->tools->checkViolations(
// Destination parent dir
// We also get the lock property from here and refresh the
// locks on it
new ezcWebdavLockCheckInfo(
$destParent,
ezcWebdavRequest::DEPTH_ZERO,
$ifHeader,
$authHeader,
ezcWebdavAuthorizer::ACCESS_WRITE,
$destinationLockRefresher
),
// Return on first violation
true
);
if ( $violation !== null )
{
if ( $violation->status === ezcWebdavResponse::STATUS_404 )
{
// Destination parent not found
return new ezcWebdavErrorResponse(
ezcWebdavResponse::STATUS_409,
$violation->requestUri
);
}
return $violation;
}
// Check destination itself, if it exsists
$violation = $this->tools->checkViolations(
// Destination (maybe overwritten, maybe not, but we must not
// care)
new ezcWebdavLockCheckInfo(
$destination,
ezcWebdavRequest::DEPTH_INFINITY,
$ifHeader,
$authHeader,
ezcWebdavAuthorizer::ACCESS_WRITE,
$destinationLockRefresher
),
// Return on first violation
true
);
// Destination might be there but not violated, or might not be there
if ( $violation !== null && $violation->status !== ezcWebdavResponse::STATUS_404 )
{
// ezcWebdavErrorResponse
return $violation;
}
// Perform lock refresh (must occur no matter if request succeeds)
$destinationLockRefresher->sendRequests();
// Store infos for use on correct moving
// @TODO: Do we always get the correct property here?
$this->lockDiscoveryProp = $destinationLockRefresher->getLockDiscoveryProperty(
$destParent
);
$sourcePaths = $this->getSourcePaths();
if ( is_object( $sourcePaths ) )
{
// ezcWebdavErrorResponse
return $sourcePaths;
}
$this->sourcePaths = $sourcePaths;
// Backend now handles the request
return null;
}
/**
* Returns all pathes in the copy source.
*
* This method performs the necessary checks on the source to copy. It
* returns all paths that are to be moved. In case of any violation of the
* checks, the method must hold and return an instance of
* ezcWebdavErrorResponse instead of the desired paths.
*
* @return array(string)|ezcWebdavErrorResponse
*/
protected function getSourcePaths()
{
$propFindReq = new ezcWebdavPropFindRequest( $this->request->requestUri );
$propFindReq->prop = new ezcWebdavBasicPropertyStorage();
$propFindReq->prop->attach( new ezcWebdavLockDiscoveryProperty() );
ezcWebdavLockTools::cloneRequestHeaders(
$this->request,
$propFindReq,
array( 'If', 'Depth' )
);
$propFindReq->validateHeaders();
$propFindMultiStatusRes = ezcWebdavServer::getInstance()->backend->propFind(
$propFindReq
);
if ( !( $propFindMultiStatusRes instanceof ezcWebdavMultiStatusResponse ) )
{
return $propFindMultiStatusRes;
}
$paths = array();
foreach ( $propFindMultiStatusRes->responses as $propFindRes )
{
$paths[] = $propFindRes->node->path;
}
return $paths;
}
/**
* Handles responses to the COPY request.
*
* This method reacts on the response generated by the backend for a COPY
* request. It takes care to release all locks that existed on the source
* URI from the newly created destination and to add all necessary locks to
* it, indicated by its parent.
*
* Returns null, if no errors occured, an {@link ezcWebdavErrorResponse}
* otherwise.
*
* @param ezcWebdavResponse $response ezcWebdavCopyResponse
* @return ezcWebdavResponse|null
*/
public function generatedResponse( ezcWebdavResponse $response )
{
if ( !( $response instanceof ezcWebdavCopyResponse ) )
{
return null;
}
$backend = ezcWebdavServer::getInstance()->backend;
// Backend successfully performed request, update with LOCK from parent
$request = $this->request;
$source = $request->requestUri;
$dest = $request->getHeader( 'Destination' );
$destParent = dirname( $dest );
$paths = $this->sourcePaths;
$lockDiscovery = ( isset( $this->lockDiscoveryProp )
? clone $this->lockDiscoveryProp
: new ezcWebdavLockDiscoveryProperty()
);
// Update active locks to reflect new resources
foreach ( $lockDiscovery->activeLock as $id => $activeLock )
{
if ( $activeLock->depth !== ezcWebdavRequest::DEPTH_INFINITY )
{
unset( $lockDiscovery->activeLock[$id] );
continue;
}
if ( $activeLock->baseUri === null )
{
$activeLock->baseUri = $destParent;
$activeLock->lastAccess = null;
}
}
// Perform lock updates
foreach ( $paths as $path )
{
$newPath = str_replace( $source, $dest, $path );
$propPatchReq = new ezcWebdavPropPatchRequest( $newPath );
$propPatchReq->updates->attach( $lockDiscovery, ezcWebdavPropPatchRequest::SET );
ezcWebdavLockTools::cloneRequestHeaders(
$request,
$propPatchReq
);
$propPatchReq->validateHeaders();
$propPatchRes = $backend->propPatch( $propPatchReq );
if ( !( $propPatchRes instanceof ezcWebdavPropPatchResponse ) )
{
throw new ezcWebdavInconsistencyException(
"Could not set lock on resource {$newPath}."
);
}
}
return null;
}
}
?>