/** * Handles errors caused by singleRequest and multiRequest * * For transport level errors, tries to figure out what went wrong to * throw the most appropriate exception. * * @param curl $curl * @param string $response the response body * @param int $httpCode the http response code * * @throws NoSuchWorkspaceException if it was not possible to reach the server (resolve host or connect) * @throws ItemNotFoundException if the object was not found * @throws RepositoryException on any other error. * @throws PathNotFoundException if the path was not found (server returned 404 without xml response) */ protected function handleError(curl $curl, $response, $httpCode) { // first: check if the backend is too old for us if (!self::$versionChecked) { // avoid endless loops. self::$versionChecked = true; try { // getting the descriptors triggers a version check $this->client->getRepositoryDescriptors(); } catch (\Exception $e) { if ($e instanceof \PHPCR\UnsupportedRepositoryOperationException) { throw $e; } //otherwise ignore exception here as to not confuse what happened } } switch ($curl->errno()) { case CURLE_COULDNT_RESOLVE_HOST: case CURLE_COULDNT_CONNECT: $info = $curl->getinfo(); throw new NoSuchWorkspaceException($curl->error() . ' "' . $info['url'] . '"'); case CURLE_RECV_ERROR: throw new RepositoryException(sprintf('CURLE_RECV_ERROR (errno 56) encountered. This has been known to happen intermittently with ' . 'some versions of libcurl (see https://github.com/jackalope/jackalope-jackrabbit/issues/89). ' . 'You can use the "jackalope.jackrabbit_force_http_version_10" option to force HTTP 1.0 as a workaround')); } // use XML error response if it's there if (substr($response, 0, 2) === '<?') { $dom = new DOMDocument(); $dom->loadXML($response); $err = $dom->getElementsByTagNameNS(Client::NS_DCR, 'exception'); if ($err->length > 0) { $err = $err->item(0); $errClass = $err->getElementsByTagNameNS(Client::NS_DCR, 'class')->item(0)->textContent; $errMsg = $err->getElementsByTagNameNS(Client::NS_DCR, 'message')->item(0)->textContent; $exceptionMsg = 'HTTP ' . $httpCode . ': ' . $errMsg; switch ($errClass) { case 'javax.jcr.NoSuchWorkspaceException': throw new NoSuchWorkspaceException($exceptionMsg); case 'javax.jcr.nodetype.NoSuchNodeTypeException': throw new NoSuchNodeTypeException($exceptionMsg); case 'javax.jcr.ItemNotFoundException': throw new ItemNotFoundException($exceptionMsg); case 'javax.jcr.nodetype.ConstraintViolationException': throw new ConstraintViolationException($exceptionMsg); case 'javax.jcr.ReferentialIntegrityException': throw new ReferentialIntegrityException($exceptionMsg); //TODO: Two more errors needed for Transactions. How does the corresponding Jackrabbit response look like? // javax.transaction.RollbackException => \PHPCR\Transaction\RollbackException // java.lang.SecurityException => \PHPCR\AccessDeniedException //TODO: map more errors here? //TODO: Two more errors needed for Transactions. How does the corresponding Jackrabbit response look like? // javax.transaction.RollbackException => \PHPCR\Transaction\RollbackException // java.lang.SecurityException => \PHPCR\AccessDeniedException //TODO: map more errors here? default: // try to generically "guess" the right exception class name $class = substr($errClass, strlen('javax.jcr.')); $class = explode('.', $class); array_walk($class, function (&$ns) { $ns = ucfirst(str_replace('nodetype', 'NodeType', $ns)); }); $class = '\\PHPCR\\' . implode('\\', $class); if (class_exists($class)) { throw new $class($exceptionMsg); } throw new RepositoryException($exceptionMsg . " ({$errClass})"); } } } if (401 == $httpCode) { throw new LoginException("HTTP 401 Unauthorized\n" . $this->getShortErrorString()); } if (404 == $httpCode) { throw new PathNotFoundException("HTTP 404 Path Not Found: {$this->method} \n" . $this->getShortErrorString()); } if (405 == $httpCode) { throw new HTTPErrorException("HTTP 405 Method Not Allowed: {$this->method} \n" . $this->getShortErrorString(), 405); } if (412 == $httpCode) { throw new LockException("Unable to lock the non-lockable node '" . reset($this->uri) . "\n" . $this->getShortErrorString()); } if ($httpCode >= 500) { $msg = "HTTP {$httpCode} Error from backend on: {$this->method} \n" . $this->getLongErrorString($curl, $response); try { $workspaceUri = array($this->client->getWorkSpaceUri()); if (!$this->errorHandlingMode && ($workspaceUri !== $this->uri || self::GET !== $this->method)) { $this->errorHandlingMode = true; $this->setUri($workspaceUri); $this->setMethod(self::GET); $this->executeDom(); } } catch (PathNotFoundException $e) { $msg = "Error likely caused by incorrect server URL configuration '" . reset($this->uri) . "' resulted in:\n{$msg}"; } $this->errorHandlingMode = false; throw new RepositoryException($msg); } $curlError = $curl->error(); $msg = "Unexpected error: \nCURL Error: {$curlError} \nResponse (HTTP {$httpCode}): {$this->method} \n" . $this->getLongErrorString($curl, $response); throw new RepositoryException($msg); }