public function httpPatch(RequestInterface $request, ResponseInterface $response)
    {
        $path = $request->getPath();

        // Get the node. Will throw a 404 if not found
        $node = $this->server->tree->getNodeForPath($path);
        if (!$node instanceof IPatchSupport) {
            throw new DAV\Exception\MethodNotAllowed('The target resource does not support the PATCH method.');
        }

        $range = $this->getHTTPUpdateRange($request);

        if (!$range) {
            throw new DAV\Exception\BadRequest('No valid "X-Update-Range" found in the headers');
        }

        $contentType = strtolower(
            (string) $request->getHeader('Content-Type')
        );

        if ('application/x-sabredav-partialupdate' != $contentType) {
            throw new DAV\Exception\UnsupportedMediaType('Unknown Content-Type header "'.$contentType.'"');
        }

        $len = $this->server->httpRequest->getHeader('Content-Length');
        if (!$len) {
            throw new DAV\Exception\LengthRequired('A Content-Length header is required');
        }
        switch ($range[0]) {
            case self::RANGE_START:
                // Calculate the end-range if it doesn't exist.
                if (!$range[2]) {
                    $range[2] = $range[1] + $len - 1;
                } else {
                    if ($range[2] < $range[1]) {
                        throw new DAV\Exception\RequestedRangeNotSatisfiable('The end offset ('.$range[2].') is lower than the start offset ('.$range[1].')');
                    }
                    if ($range[2] - $range[1] + 1 != $len) {
                        throw new DAV\Exception\RequestedRangeNotSatisfiable('Actual data length ('.$len.') is not consistent with begin ('.$range[1].') and end ('.$range[2].') offsets');
                    }
                }
                break;
        }

        if (!$this->server->emit('beforeWriteContent', [$path, $node, null])) {
            return;
        }

        $body = $this->server->httpRequest->getBody();

        $etag = $node->patch($body, $range[0], isset($range[1]) ? $range[1] : null);

        $this->server->emit('afterWriteContent', [$path, $node]);

        $response->setHeader('Content-Length', '0');
        if ($etag) {
            $response->setHeader('ETag', $etag);
        }
        $response->setStatus(204);

        // Breaks the event chain
        return false;
    }