protected void doPropfind()

in java/org/apache/catalina/servlets/WebdavServlet.java [803:997]


    protected void doPropfind(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        if (!isListings()) {
            sendNotAllowed(req, resp);
            return;
        }

        String path = getRelativePath(req);

        // Properties which are to be displayed.
        List<Node> properties = new ArrayList<>();
        // Propfind depth
        int depth;
        // Propfind type
        PropfindType type = null;

        String depthStr = req.getHeader("Depth");

        if (depthStr == null) {
            depth = maxDepth;
        } else {
            switch (depthStr) {
                case "0" -> depth = 0;
                case "1" -> depth = 1;
                case "infinity" -> depth = maxDepth;
                default -> {
                    resp.sendError(WebdavStatus.SC_BAD_REQUEST);
                    return;
                }
            }
        }

        byte[] body;
        try (InputStream is = req.getInputStream(); ByteArrayOutputStream os = new ByteArrayOutputStream()) {
            IOTools.flow(is, os);
            body = os.toByteArray();
        } catch (IOException e) {
            resp.sendError(WebdavStatus.SC_BAD_REQUEST);
            return;
        }
        if (body.length > 0) {
            DocumentBuilder documentBuilder = getDocumentBuilder();

            try {
                Document document = documentBuilder.parse(new InputSource(new ByteArrayInputStream(body)));

                // Get the root element of the document
                Element rootElement = document.getDocumentElement();
                if (!"propfind".equals(getDAVNode(rootElement))) {
                    resp.sendError(WebdavStatus.SC_BAD_REQUEST);
                    return;
                }
                NodeList childList = rootElement.getChildNodes();

                for (int i = 0; i < childList.getLength(); i++) {
                    Node currentNode = childList.item(i);
                    switch (currentNode.getNodeType()) {
                        case Node.TEXT_NODE:
                            break;
                        case Node.ELEMENT_NODE:
                            String nodeName = getDAVNode(currentNode);
                            if ("prop".equals(nodeName)) {
                                if (type != null) {
                                    // Another was already defined
                                    resp.sendError(WebdavStatus.SC_BAD_REQUEST);
                                    return;
                                }
                                type = PropfindType.FIND_BY_PROPERTY;
                                NodeList propChildList = currentNode.getChildNodes();
                                for (int j = 0; j < propChildList.getLength(); j++) {
                                    Node currentNode2 = propChildList.item(j);
                                    switch (currentNode2.getNodeType()) {
                                        case Node.TEXT_NODE:
                                            break;
                                        case Node.ELEMENT_NODE:
                                            properties.add(currentNode2);
                                            break;
                                    }
                                }
                            }
                            if ("propname".equals(nodeName)) {
                                if (type != null) {
                                    // Another was already defined
                                    resp.sendError(WebdavStatus.SC_BAD_REQUEST);
                                    return;
                                }
                                type = PropfindType.FIND_PROPERTY_NAMES;
                            }
                            if ("allprop".equals(nodeName)) {
                                if (type != null) {
                                    // Another was already defined
                                    resp.sendError(WebdavStatus.SC_BAD_REQUEST);
                                    return;
                                }
                                type = PropfindType.FIND_ALL_PROP;
                            }
                            break;
                    }
                }
            } catch (SAXException | IOException e) {
                // Something went wrong - bad request
                resp.sendError(WebdavStatus.SC_BAD_REQUEST);
                return;
            }
            if (type == null) {
                // Nothing meaningful in the propfind element
                resp.sendError(WebdavStatus.SC_BAD_REQUEST);
                return;
            }
        } else {
            type = PropfindType.FIND_ALL_PROP;
        }

        WebResource resource = resources.getResource(path);
        if (!checkIfHeaders(req, resp, resource)) {
            resp.setStatus(HttpServletResponse.SC_PRECONDITION_FAILED);
            return;
        }

        if (!resource.exists()) {
            resp.sendError(HttpServletResponse.SC_NOT_FOUND);
            return;
        }

        resp.setStatus(WebdavStatus.SC_MULTI_STATUS);

        resp.setContentType("text/xml; charset=UTF-8");

        // Create multistatus object
        XMLWriter generatedXML = new XMLWriter(resp.getWriter());
        generatedXML.writeXMLHeader();

        generatedXML.writeElement("D", DEFAULT_NAMESPACE, "multistatus", XMLWriter.OPENING);

        if (depth == 0) {
            propfindResource(generatedXML, getEncodedPath(path, resource, req), path, type, properties,
                    resource.isFile(), resource.getCreation(), resource.getLastModified(), resource.getContentLength(),
                    getServletContext().getMimeType(resource.getName()), generateETag(resource));
        } else {
            // The stack always contains the object of the current level
            Deque<String> stack = new ArrayDeque<>();
            stack.addFirst(path);

            // Stack of the objects one level below
            Deque<String> stackBelow = new ArrayDeque<>();

            while ((!stack.isEmpty()) && (depth >= 0)) {

                String currentPath = stack.remove();

                // Exclude any resource in the /WEB-INF and /META-INF subdirectories
                if (isSpecialPath(currentPath)) {
                    continue;
                }

                resource = resources.getResource(currentPath);
                // File is in directory listing but doesn't appear to exist
                // Broken symlink or odd permission settings?
                if (resource.exists()) {
                    propfindResource(generatedXML, getEncodedPath(currentPath, resource, req), currentPath, type,
                            properties, resource.isFile(), resource.getCreation(), resource.getLastModified(),
                            resource.getContentLength(), getServletContext().getMimeType(resource.getName()),
                            generateETag(resource));
                }

                if (resource.isDirectory() && (depth > 0)) {

                    String[] entries = resources.list(currentPath);
                    for (String entry : entries) {
                        String newPath = currentPath;
                        if (!(newPath.endsWith("/"))) {
                            newPath += "/";
                        }
                        newPath += entry;
                        stackBelow.addFirst(newPath);
                    }

                }

                if (stack.isEmpty()) {
                    depth--;
                    stack = stackBelow;
                    stackBelow = new ArrayDeque<>();
                }

                generatedXML.sendData();

            }
        }

        generatedXML.writeElement("D", "multistatus", XMLWriter.CLOSING);

        generatedXML.sendData();

    }