Ejemplo n.º 1
0
 public function testValidateHeadersFailure()
 {
     $req = new ezcWebdavMoveRequest('/foo', '/bar');
     $req->setHeader('Overwrite', null);
     try {
         $req->validateHeaders();
         $this->fail('Exception not thrown on missing Overwrite header.');
     } catch (ezcWebdavMissingHeaderException $e) {
     }
     $req->setHeader('Overwrite', 'A');
     try {
         $req->validateHeaders();
         $this->fail('Exception not thrown on invalid Overwrite header.');
     } catch (ezcWebdavInvalidHeaderException $e) {
     }
 }
Ejemplo n.º 2
0
 public function move(ezcWebdavMoveRequest $request)
 {
     global $prefs;
     global $filegallib;
     include_once 'lib/filegals/filegallib.php';
     print_debug("-- HTTP method: MOVE --\n");
     $this->acquireLock();
     // Indicates wheather a destiantion resource has been replaced or not.
     // The success response code depends on this.
     $replaced = false;
     // Extract paths from request
     $source = $request->requestUri;
     $dest = $request->getHeader('Destination');
     // Check authorization
     // Need to do this before checking of node existence is checked, to
     // avoid leaking information
     if (!ezcWebdavServer::getInstance()->isAuthorized($dest, $request->getHeader('Authorization'), ezcWebdavAuthorizer::ACCESS_WRITE)) {
         $this->freeLock();
         return $this->createUnauthorizedResponse($dest, $request->getHeader('Authorization'));
     }
     // Check if resource is available
     if (!$this->nodeExists($source)) {
         $this->freeLock();
         return new ezcWebdavErrorResponse(ezcWebdavResponse::STATUS_404, $source);
     }
     // If source and destination are equal, the request should always fail.
     if ($source === $dest) {
         $this->freeLock();
         return new ezcWebdavErrorResponse(ezcWebdavResponse::STATUS_403, $source);
     }
     // Check if destination resource exists and throw error, when
     // overwrite header is F
     if ($request->getHeader('Overwrite') === 'F' && $this->nodeExists($dest)) {
         $this->freeLock();
         return new ezcWebdavErrorResponse(ezcWebdavResponse::STATUS_412, $dest);
     }
     // Check if the destination parent directory already exists, otherwise
     // bail out.
     if (!$this->nodeExists($destDir = dirname($dest))) {
         $this->freeLock();
         return new ezcWebdavErrorResponse(ezcWebdavResponse::STATUS_409, $dest);
     }
     // Verify If-[None-]Match headers on the $dest if it exists
     if ($this->nodeExists($dest) && ($res = $this->checkIfMatchHeaders($request, $dest)) !== null) {
         $this->freeLock();
         return $res;
     } elseif (($res = $this->checkIfMatchHeaders($request, $destDir)) !== null) {
         // Verify If-[None-]Match headers on the on $dests parent dir, if it
         // does not exist
         $this->freeLock();
         return $res;
     }
     // The destination resource should be deleted if it exists and the
     // overwrite headers is T
     if ($request->getHeader('Overwrite') === 'T' && $this->nodeExists($dest)) {
         // Check sub-sequent authorization on destination
         $authState = $this->recursiveAuthCheck($request, $dest, ezcWebdavAuthorizer::ACCESS_WRITE, true);
         if (count($authState['errors']) !== 0) {
             // Permission denied on deleting destination
             $this->freeLock();
             return $authState['errors'][0];
         }
         $replaced = true;
         if (count($delteErrors = $this->performDelete($dest)) > 0) {
             $this->freeLock();
             return new ezcWebdavMultistatusResponse($delteErrors);
         }
     }
     // All checks are passed, we can actually move now.
     $infos = array();
     $doRename = false;
     $doMove = false;
     foreach (array('source', 'dest') as $k) {
         // Get source and dest infos
         if (($infos[$k] = $filegallib->get_objectid_from_virtual_path(${$k})) !== false) {
             switch ($infos[$k]['type']) {
                 case 'filegal':
                     $infos[$k]['infos'] = $filegallib->get_file_gallery_info($infos[$k]['id']);
                     $infos[$k]['parentId'] = $infos[$k]['infos']['parentId'];
                     $infos[$k]['name'] = $infos[$k]['infos']['name'];
                     break;
                 case 'file':
                     ///TODO: Throw an error if dest is a file, but source is a filegal
                     $infos[$k]['infos'] = $filegallib->get_file($infos[$k]['id']);
                     $infos[$k]['parentId'] = $infos[$k]['infos']['galleryId'];
                     $infos[$k]['name'] = $infos[$k]['infos']['filename'];
                     break;
             }
         } elseif ($k == 'dest') {
             // If dest doesn't exist, it usually means that the file / filegal has to be renamed
             ///TODO: Throw an error if dest is a new filegal, but source is a file
             if (($objectId = $filegallib->get_objectid_from_virtual_path(dirname(${$k}))) !== false && $objectId['type'] == 'filegal') {
                 $infos[$k] = array('id' => $infos['source']['id'], 'type' => $infos['source']['type'], 'infos' => $infos['source']['infos'], 'parentId' => $objectId['id'], 'name' => basename(${$k}));
                 switch ($infos[$k]['type']) {
                     case 'filegal':
                         $infos[$k]['infos']['name'] = $infos[$k]['name'];
                         $infos[$k]['infos']['parentId'] = $infos[$k]['parentId'];
                         break;
                     case 'file':
                         $infos[$k]['infos']['name'] = $infos[$k]['name'];
                         $infos[$k]['infos']['filename'] = $infos[$k]['name'];
                         $infos[$k]['infos']['galleryId'] = $infos[$k]['parentId'];
                         break;
                 }
                 $doRename = true;
             }
         } else {
             // If source doesn't exist, we stop here
             break;
         }
     }
     $doMove = $infos['source']['parentId'] != $infos['dest']['parentId'];
     $noErrors = true;
     switch ($infos['source']['type']) {
         case 'filegal':
             if ($doRename) {
                 $noErrors = (bool) $filegallib->replace_file_gallery($infos['dest']['infos']);
             } elseif ($doMove) {
                 // Move is not needed if the rename occurred, since filegal renaming function handle the move already
                 $noErrors = (bool) $filegallib->move_file_gallery($infos['source']['id'], $infos['dest']['parentId']);
             }
             break;
         case 'file':
             if ($doRename) {
                 if ($prefs['fgal_use_db'] === 'n') {
                     $newPath = md5($infos['dest']['name']);
                     do {
                         $newPath = md5(uniqid($newPath));
                     } while (file_exists($this->root . '/' . $newPath));
                     if (@rename($this->root . '/' . $infos['source']['infos']['path'], $this->root . '/' . $newPath) === false || @file_put_contents($this->root . '/' . $infos['source']['infos']['path'], '') === false) {
                         $this->freeLock();
                         return false;
                     }
                 } else {
                     $newPath = '';
                 }
                 global $user;
                 $noErrors = (bool) $filegallib->replace_file($infos['source']['id'], $infos['dest']['name'], $infos['source']['infos']['description'], $infos['dest']['name'], $infos['source']['infos']['data'], $infos['source']['infos']['filesize'], $infos['source']['infos']['filetype'], $user, $newPath, '', $filegallib->get_file_gallery_info($infos['source']['parentId']), false, $infos['source']['infos']['author'], $infos['source']['infos']['created'], $infos['source']['infos']['lockedby']);
             }
             if ($doMove && $noErrors) {
                 $noErrors = (bool) $filegallib->set_file_gallery($infos['source']['id'], $infos['dest']['parentId']);
             }
             break;
     }
     $this->freeLock();
     // Send proper response on success
     if ($noErrors) {
         $return = new ezcWebdavMoveResponse($replaced);
     } else {
         $return = new ezcWebdavErrorResponse(ezcWebdavResponse::STATUS_500);
     }
     print_debug("-- HTTP method: MOVE end --\n");
     return $return;
 }
Ejemplo n.º 3
0
 public function testMoveCollectionWithInvalidETag()
 {
     $testSourcePath = '/collection';
     $testSource = "{$testSourcePath}/deep_collection";
     $testDestPath = $testSourcePath;
     $testDest = "{$testDestPath}/copied_collection";
     $backend = new ezcWebdavFileBackend($this->tempDir . 'backend/');
     // Initialize all property directories
     $req = new ezcWebdavPropFindRequest($testSource);
     $req->allProp = true;
     $req->setHeader('Depth', ezcWebdavRequest::DEPTH_INFINITY);
     $req->validateHeaders();
     $backend->propFind($req);
     $eTag = $backend->getProperty($testDestPath, 'getetag')->etag;
     $req = new ezcWebdavMoveRequest($testSource, $testDest);
     $req->setHeader('If-None-Match', array('abc23', $eTag));
     $req->validateHeaders();
     $res = $backend->move($req);
     $this->assertEquals(new ezcWebdavErrorResponse(ezcWebdavResponse::STATUS_412, '/collection', 'If-None-Match header check failed.'), $res, 'Expected response does not match real response.', 0, 20);
 }
Ejemplo n.º 4
0
 public function testResourceMoveDepthInfinityErrors()
 {
     $backend = new ezcWebdavMemoryBackend(false);
     $backend->addContents(array('bar' => array('_1' => 'contents', '_2' => 'contents', '_3' => 'contents', '_4' => 'contents', '_5' => 'contents')));
     $backend->options->failingOperations = ezcWebdavMemoryBackendOptions::REQUEST_COPY;
     $backend->options->failForRegexp = '(_[24]$)';
     $request = new ezcWebdavMoveRequest('/bar', '/foo');
     $request->setHeader('Depth', ezcWebdavRequest::DEPTH_INFINITY);
     $request->validateHeaders();
     $response = $backend->move($request);
     $this->assertEquals(new ezcWebdavMultistatusResponse(new ezcWebdavErrorResponse(ezcWebdavResponse::STATUS_423, '/bar/_2'), new ezcWebdavErrorResponse(ezcWebdavResponse::STATUS_423, '/bar/_4')), $response, 'Expected response does not match real response.', 0, 20);
     $content = $this->readAttribute($backend, 'content');
     $this->assertEquals(array('/' => array('/bar', '/foo'), '/bar' => array('/bar/_1', '/bar/_2', '/bar/_3', '/bar/_4', '/bar/_5'), '/bar/_1' => 'contents', '/bar/_2' => 'contents', '/bar/_3' => 'contents', '/bar/_4' => 'contents', '/bar/_5' => 'contents', '/foo' => array('/foo/_1', '/foo/_3', '/foo/_5'), '/foo/_1' => 'contents', '/foo/_3' => 'contents', '/foo/_5' => 'contents'), $content);
 }
Ejemplo n.º 5
0
 public function testResourceMoveDepthInfinityErrors()
 {
     $backend = new ezcWebdavFileBackend($this->tempDir . 'backend/');
     // Cause error by making file not readable
     chmod($this->tempDir . 'backend/collection/test.txt', 0);
     $this->assertTrue(is_dir($this->tempDir . 'backend/collection'), 'Expected existing collection before request.');
     $request = new ezcWebdavMoveRequest('/collection', '/new_collection');
     $request->setHeader('Depth', ezcWebdavRequest::DEPTH_INFINITY);
     $request->validateHeaders();
     $response = $backend->move($request);
     $this->assertEquals($response, new ezcWebdavMultistatusResponse(new ezcWebdavErrorResponse(ezcWebdavResponse::STATUS_423, '/collection/test.txt')), 'Expected response does not match real response.', 0, 20);
     $this->assertTrue(is_dir($this->tempDir . 'backend/collection'), 'Expected collection not to be removed.');
     $this->assertTrue(is_dir($this->tempDir . 'backend/new_collection'), 'Expected created collection.');
     $this->assertFalse(is_file($this->tempDir . 'backend/new_collection/test.txt'), 'Expected file in collection not to be created.');
     $this->assertTrue(is_file($this->tempDir . 'backend/new_collection/deep_collection/deep_test.txt'), 'Expected created deep file in collection.');
     chmod($this->tempDir . 'backend/collection/test.txt', 0777);
 }
Ejemplo n.º 6
0
 /**
  * Serves MOVE requests.
  *
  * The method receives a {@link ezcWebdavMoveRequest} objects containing
  * all relevant information obout the clients request and will return an
  * instance of {@link ezcWebdavErrorResponse} on error or {@link
  * ezcWebdavMoveResponse} on success. If only some operations failed, this
  * method may return an instance of {@link ezcWebdavMultistatusResponse}.
  * 
  * @param ezcWebdavMoveRequest $request 
  * @return ezcWebdavResponse
  */
 public function move(ezcWebdavMoveRequest $request)
 {
     // Indicates wheather a destiantion resource has been replaced or not.
     // The success response code depends on this.
     $replaced = false;
     // Extract paths from request
     $source = $request->requestUri;
     $dest = $request->getHeader('Destination');
     // Check authorization
     // Need to do this before checking of node existence is checked, to
     // avoid leaking information
     $authState = $this->recursiveAuthCheck($request, $dest, ezcWebdavAuthorizer::ACCESS_WRITE, true);
     if (count($authState['errors']) !== 0) {
         // Source permission denied
         return $authState['errors'][0];
     }
     if (!ezcWebdavServer::getInstance()->isAuthorized($dest, $request->getHeader('Authorization'), ezcWebdavAuthorizer::ACCESS_WRITE)) {
         return $this->createUnauthorizedResponse($dest, $request->getHeader('Authorization'));
     }
     // Check if resource is available
     if (!$this->nodeExists($source)) {
         return new ezcWebdavErrorResponse(ezcWebdavResponse::STATUS_404, $source);
     }
     // If source and destination are equal, the request should always fail.
     if ($source === $dest) {
         return new ezcWebdavErrorResponse(ezcWebdavResponse::STATUS_403, $source);
     }
     // Check if destination resource exists and throw error, when
     // overwrite header is F
     if ($request->getHeader('Overwrite') === 'F' && $this->nodeExists($dest)) {
         return new ezcWebdavErrorResponse(ezcWebdavResponse::STATUS_412, $dest);
     }
     // Check if the destination parent directory already exists, otherwise
     // bail out.
     if (!$this->nodeExists($destDir = dirname($dest))) {
         return new ezcWebdavErrorResponse(ezcWebdavResponse::STATUS_409, $dest);
     }
     // Verify If-[None-]Match headers on the $source
     $res = $this->checkIfMatchHeadersRecursive($request, $source, ezcWebdavRequest::DEPTH_INFINITY);
     if ($res !== null) {
         return $res;
     }
     // Verify If-[None-]Match headers on the $dest if it exists
     if ($this->nodeExists($dest) && ($res = $this->checkIfMatchHeaders($request, $dest)) !== null) {
         return $res;
     } elseif (($res = $this->checkIfMatchHeaders($request, $destDir)) !== null) {
         return $res;
     }
     // The destination resource should be deleted if it exists and the
     // overwrite headers is T
     if ($request->getHeader('Overwrite') === 'T' && $this->nodeExists($dest)) {
         // Check sub-sequent authorization on destination
         $authState = $this->recursiveAuthCheck($request, $dest, ezcWebdavAuthorizer::ACCESS_WRITE, true);
         if (count($authState['errors']) !== 0) {
             // Permission denied on deleting destination
             return $authState['errors'][0];
         }
         $replaced = true;
         if (count($delteErrors = $this->performDelete($dest)) > 0) {
             return new ezcWebdavMultistatusResponse($delteErrors);
         }
     }
     // All checks are passed, we can actuall copy now.
     //
     // MOVEd contents should always be copied using infinity depth.
     //
     // @todo: handle keepalive setting somehow - even the RFC is quite
     // vague how to handle them exactly.
     $errors = $this->performCopy($source, $dest, ezcWebdavRequest::DEPTH_INFINITY);
     // If an error occured we skip deletion of source.
     //
     // @IMPORTANT: This is a definition / assumption made by us, because it
     // is not defined in the RFC how to handle such a case.
     if (count($errors)) {
         // We need a multistatus response, because some errors occured for some
         // of the resources.
         return new ezcWebdavMultistatusResponse($errors);
     }
     // Delete the source, COPY has been successful
     $deletion = $this->performDelete($source);
     // If deletion failed, this has again been caused by the automatic
     // error causing facilities of the backend. Send 423 by choice.
     //
     // @todo: The error generated here should depend on the actual backend
     // implementation and  not be generated guessing what may fit.
     if (count($deletion) > 0) {
         return new ezcWebdavMultistatusResponse($deletion);
     }
     // Send proper response on success
     return new ezcWebdavMoveResponse($replaced);
 }
Ejemplo n.º 7
0
 /**
  * Parses the MOVE request and returns a request object.
  *
  * This method is responsible for parsing the MOVE request. It retrieves
  * the current request URI in $path and the request body as $body.  The
  * return value, if no exception is thrown, is a valid {@link
  * ezcWebdavMoveRequest} object.
  *
  * This method may be overwritten to adjust it to special client behaviour.
  * 
  * @param string $path 
  * @param string $body 
  * @return ezcWebdavMoveRequest
  */
 protected function parseMoveRequest($path, $body)
 {
     $headers = ezcWebdavServer::getInstance()->headerHandler->parseHeaders(array('Destination', 'Depth', 'Overwrite'));
     if (!isset($headers['Destination'])) {
         throw new ezcWebdavMissingHeaderException('Destination');
     }
     $request = new ezcWebdavMoveRequest($path, $headers['Destination']);
     $request->setHeaders($headers);
     if (trim($body) === '') {
         // No body present
         return $request;
     }
     try {
         $dom = ezcWebdavServer::getInstance()->xmlTool->createDom($body);
     } catch (ezcWebdavInvalidXmlException $e) {
         throw new ezcWebdavInvalidRequestBodyException('MOVE', $e->getMessage());
     }
     if ($dom->documentElement->localName !== 'propertybehavior') {
         throw new ezcWebdavInvalidRequestBodyException('MOVE', "Expected XML element <propertybehavior />, received <{$dom->documentElement->localName} />.");
     }
     return $this->parsePropertyBehaviourContent($dom, $request);
 }