/** * Creates a lock-null resource. * * In case a LOCK request is issued on a resource, that does not exists, a * so-called lock-null resource is created. This resource must support some * of the WebDAV requests, but not all. In case an MKCOL or PUT request is * issued to such a resource, it is switched to be a real resource. In case * the lock is released, all null-lock resources in it are removed. * * @param ezcWebdavLockRequest $request * @return ezcWebdavResponse */ protected function createLockNullResource(ezcWebdavLockRequest $request) { $backend = ezcWebdavServer::getInstance()->backend; // Check parent directory for locks and other violations $violation = $this->tools->checkViolations(new ezcWebdavLockCheckInfo(dirname($request->requestUri), ezcWebdavRequest::DEPTH_ZERO, $request->getHeader('If'), $request->getHeader('Authorization'), ezcWebdavAuthorizer::ACCESS_WRITE)); if ($violation !== null) { return $this->createLockError($violation); } // Create lock null resource $putReq = new ezcWebdavPutRequest($request->requestUri, ''); ezcWebdavLockTools::cloneRequestHeaders($request, $putReq, array('If')); $putReq->setHeader('Content-Length', '0'); $putReq->validateHeaders(); $putRes = $backend->put($putReq); if (!$putRes instanceof ezcWebdavPutResponse) { return $this->createLockError($putRes); } // Attention, recursion! $res = $this->acquireLock($request); if ($res->status !== ezcWebdavResponse::STATUS_200) { return $res; } $res->status = ezcWebdavResponse::STATUS_201; return $res; }
/** * Performs unlocking. * * Performs a PROPFIND request with the $depth of the lock with $token on * the given $path (which must be the lock base). All affected resources * get the neccessary properties updated to reflect the change. Lock null * resources in the lock are removed. * * @param ezcWebdavUnlockRequest $request * @param string $token * @param int $depth * @return ezcWebdavResponse */ protected function performUnlock(ezcWebdavUnlockRequest $request, $token, $depth) { $path = $request->requestUri; $backend = ezcWebdavServer::getInstance()->backend; // Find alle resources affected by the unlock, including affected properties $propFindReq = new ezcWebdavPropFindRequest($path); $propFindReq->prop = new ezcWebdavBasicPropertyStorage(); $propFindReq->prop->attach(new ezcWebdavLockDiscoveryProperty()); ezcWebdavLockTools::cloneRequestHeaders($request, $propFindReq); $propFindReq->setHeader('Depth', $depth); $propFindReq->validateHeaders(); $propFindMultistatusRes = $backend->propFind($propFindReq); // Remove lock information for the lock identified by $token from each affected resource foreach ($propFindMultistatusRes->responses as $propFindRes) { // Takes properties to be updated $changeProps = new ezcWebdavFlaggedPropertyStorage(); foreach ($propFindRes->responses as $propStatRes) { if ($propStatRes->status === ezcWebdavResponse::STATUS_200) { // Remove affected active lock part from lockdiscovery property if ($propStatRes->storage->contains('lockdiscovery')) { $lockDiscoveryProp = clone $propStatRes->storage->get('lockdiscovery'); foreach ($lockDiscoveryProp->activeLock as $id => $activeLock) { if ($activeLock->token == $token) { $lockDiscoveryProp->activeLock->offsetUnset($id); $changeProps->attach($lockDiscoveryProp, ezcWebdavPropPatchRequest::SET); break; } } } } } // Perform the PROPPATCH if (count($changeProps) > 0) { $propPatchReq = new ezcWebdavPropPatchRequest($propFindRes->node->path); $propPatchReq->updates = $changeProps; ezcWebdavLockTools::cloneRequestHeaders($request, $propPatchReq); $propPatchReq->validateHeaders(); $propPatchRes = $backend->propPatch($propPatchReq); if (!$propPatchRes instanceof ezcWebdavPropPatchResponse) { throw new ezcWebdavInconsistencyException("Lock token {$token} could not be unlocked on resource {$propFindRes->node->path}."); } } } return new ezcWebdavUnlockResponse(ezcWebdavResponse::STATUS_204); }
/** * 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; }
/** * Updates the lock properties on the target. * * Performs the neccessary PROPPATCH requests to update the lock properties * on the target (parent is locked or was lock null before). */ protected function updateLockProperties() { if (!$this->isParentProp) { // No need to update return null; } $lockDiscoveryProp = $this->lockDiscoveryProp !== null ? clone $this->lockDiscoveryProp : new ezcWebdavLockDiscoveryProperty(); $destParent = dirname($this->request->requestUri); foreach ($lockDiscoveryProp->activeLock as $id => $activeLock) { if ($activeLock->depth !== ezcWebdavRequest::DEPTH_INFINITY) { unset($lockDiscoveryProp->activeLock[$id]); continue; } if ($activeLock->baseUri === null) { $activeLock->baseUri = $destParent; $activeLock->lastAccess = null; } } $propPatchReq = new ezcWebdavPropPatchRequest($this->request->requestUri); ezcWebdavLockTools::cloneRequestHeaders($this->request, $propPatchReq); $propPatchReq->validateHeaders(); $propPatchReq->updates->attach($lockDiscoveryProp, ezcWebdavPropPatchRequest::SET); $propPatchRes = ezcWebdavServer::getInstance()->backend->propPatch($propPatchReq); if (!$propPatchRes instanceof ezcWebdavPropPatchResponse) { throw new ezcWebdavInconsistencyException('Could not patch lock properties on newly created resource/collection.'); } }
/** * Generates the requests to update the locks. * * This method generates a PROPPATCH request for each <lockinfo> property * in {@link $lockBaseProperties} and returns all of them in an array. * * @return array(ezcWebdavPropPatchRequest) */ protected function generateRequests() { $requests = array(); foreach ($this->pathsToUpdate as $path => $dummy) { $propPatch = new ezcWebdavPropPatchRequest($path); $propPatch->updates->attach($this->lockDiscoveryProperties[$path], ezcWebdavPropPatchRequest::SET); ezcWebdavLockTools::cloneRequestHeaders($this->issuingRequest, $propPatch); $requests[] = $propPatch; } return $requests; }