Skip to content

Commit

Permalink
Report error on invalid catalog URI
Browse files Browse the repository at this point in the history
Signed-off-by: Jessica He <jhe@redhat.com>
  • Loading branch information
JessicaJHee authored and angelozerr committed Aug 5, 2022
1 parent 9827ac2 commit 39eefb7
Show file tree
Hide file tree
Showing 7 changed files with 211 additions and 22 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,15 @@
import java.util.Collections;
import java.util.List;

import org.apache.xerces.impl.XMLEntityManager;
import org.apache.xerces.util.URI.MalformedURIException;
import org.eclipse.lemminx.dom.DOMAttr;
import org.eclipse.lemminx.dom.DOMDocument;
import org.eclipse.lemminx.dom.DOMElement;
import org.eclipse.lemminx.dom.DOMNode;
import org.eclipse.lemminx.utils.DOMUtils;
import org.eclipse.lemminx.utils.FilesUtils;
import org.eclipse.lemminx.utils.StringUtils;
import org.eclipse.lsp4j.jsonrpc.validation.NonNull;

/**
Expand Down Expand Up @@ -195,4 +199,24 @@ private static CatalogEntry createCatalogEntry(@NonNull String baseURI, DOMEleme
return null;
}

/**
* Returns the expanded system location
*
* @param document the xml document
* @param catalogEntry the catalog entry
* @return the expanded system location
*/
public static String getResolvedLocation(DOMDocument document, CatalogEntry catalogEntry) {
String location = catalogEntry.getResolvedURI();

if (StringUtils.isBlank(location)) {
return null;
}
try {
return XMLEntityManager.expandSystemId(location, FilesUtils.removeFileScheme(document.getDocumentURI()),
false);
} catch (MalformedURIException e) {
return location;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/*******************************************************************************
* Copyright (c) 2022 Red Hat Inc. and others.
* All rights reserved. This program and the accompanying materials
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v20.html
*
* Contributors:
* Red Hat Inc. - initial API and implementation
*******************************************************************************/

package org.eclipse.lemminx.extensions.catalog;

import java.text.MessageFormat;
import java.util.List;

import org.eclipse.lemminx.dom.DOMDocument;
import org.eclipse.lemminx.extensions.contentmodel.settings.XMLValidationSettings;
import org.eclipse.lemminx.services.extensions.diagnostics.IDiagnosticsParticipant;
import org.eclipse.lemminx.utils.DOMUtils;
import org.eclipse.lemminx.utils.FilesUtils;
import org.eclipse.lemminx.utils.URIUtils;
import org.eclipse.lemminx.utils.XMLPositionUtility;
import org.eclipse.lsp4j.Diagnostic;
import org.eclipse.lsp4j.DiagnosticSeverity;
import org.eclipse.lsp4j.Range;
import org.eclipse.lsp4j.jsonrpc.CancelChecker;

/**
* Validate XML catalog.
*
*/
public class XMLCatalogDiagnosticsParticipant implements IDiagnosticsParticipant {

private static final String ERROR_STRING = "The file ''{0}'' cannot be found.";

@Override
public void doDiagnostics(DOMDocument xmlDocument, List<Diagnostic> diagnostics,
XMLValidationSettings validationSettings, CancelChecker monitor) {
if (!DOMUtils.isCatalog(xmlDocument)) {
return;
}

for (CatalogEntry catalogEntry : CatalogUtils.getCatalogEntries(xmlDocument)) {
// CatalogUtils.getResolvedLocation() always returns path with 'file://' scheme,
// appending it in the case when original URI does not start with 'file://'.
// Ex: originalURI ="foo/bar.xsd" -> path ="file://foo/bar.xsd"
String path = CatalogUtils.getResolvedLocation(xmlDocument, catalogEntry);
if (!FilesUtils.isValidPath(FilesUtils.getPath(path)) && URIUtils.isFileResource(path)) {
Range range = XMLPositionUtility.selectValueWithoutQuote(catalogEntry.getLinkRange());
String msg = MessageFormat.format(ERROR_STRING, catalogEntry.getResolvedURI());

diagnostics
.add(new Diagnostic(range, msg, DiagnosticSeverity.Error, xmlDocument.getDocumentURI(),
XMLCatalogErrorCode.catalog_uri.name()));
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,9 @@
import java.util.logging.Level;
import java.util.logging.Logger;

import org.apache.xerces.impl.XMLEntityManager;
import org.apache.xerces.util.URI.MalformedURIException;
import org.eclipse.lemminx.commons.BadLocationException;
import org.eclipse.lemminx.dom.DOMDocument;
import org.eclipse.lemminx.services.extensions.IDocumentLinkParticipant;
import org.eclipse.lemminx.utils.FilesUtils;
import org.eclipse.lemminx.utils.StringUtils;
import org.eclipse.lemminx.utils.XMLPositionUtility;
import org.eclipse.lsp4j.DocumentLink;

Expand Down Expand Up @@ -52,8 +48,7 @@ public void findDocumentLinks(DOMDocument document, List<DocumentLink> links) {
*/
private static DocumentLink createDocumentLinkFromCatalogEntry(DOMDocument document, CatalogEntry catalogEntry) {
try {
String path = getResolvedLocation(FilesUtils.removeFileScheme(document.getDocumentURI()),
catalogEntry.getResolvedURI());
String path = CatalogUtils.getResolvedLocation(document, catalogEntry);
if (path != null && catalogEntry.getLinkRange() != null) {
return XMLPositionUtility.createDocumentLink(catalogEntry.getLinkRange(), path, true);
}
Expand All @@ -63,20 +58,4 @@ private static DocumentLink createDocumentLinkFromCatalogEntry(DOMDocument docum
return null;
}

/**
* Returns the expanded system location
*
* @return the expanded system location
*/
private static String getResolvedLocation(String documentURI, String location) {
if (StringUtils.isBlank(location)) {
return null;
}
try {
return XMLEntityManager.expandSystemId(location, documentURI, false);
} catch (MalformedURIException e) {
return location;
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*******************************************************************************
* Copyright (c) 2022 Red Hat Inc. and others.
* All rights reserved. This program and the accompanying materials
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v20.html
*
* Contributors:
* Red Hat Inc. - initial API and implementation
*******************************************************************************/

package org.eclipse.lemminx.extensions.catalog;

import org.eclipse.lemminx.services.extensions.diagnostics.IXMLErrorCode;

/**
* XML Catalog error code.
*
*/
public enum XMLCatalogErrorCode implements IXMLErrorCode {
catalog_uri("catalog_uri");

private final String code;

private XMLCatalogErrorCode(String code) {
this.code = code;
}

@Override
public String getCode() {
if (code == null) {
return name();
}
return code;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import org.eclipse.lemminx.services.extensions.IDocumentLinkParticipant;
import org.eclipse.lemminx.services.extensions.IXMLExtension;
import org.eclipse.lemminx.services.extensions.XMLExtensionsRegistry;
import org.eclipse.lemminx.services.extensions.diagnostics.IDiagnosticsParticipant;
import org.eclipse.lemminx.services.extensions.save.ISaveContext;
import org.eclipse.lemminx.utils.FilesUtils;
import org.eclipse.lsp4j.InitializeParams;
Expand All @@ -35,11 +36,13 @@ public class XMLCatalogPlugin implements IXMLExtension {

private XMLCatalogURIResolverExtension uiResolver;
private final IDocumentLinkParticipant documentLinkParticipant;
private final IDiagnosticsParticipant diagnosticsParticipant;

private InvalidPathWarner pathWarner;

public XMLCatalogPlugin() {
documentLinkParticipant = new XMLCatalogDocumentLinkParticipant();
diagnosticsParticipant = new XMLCatalogDiagnosticsParticipant();
}

@Override
Expand All @@ -61,11 +64,13 @@ public void start(InitializeParams params, XMLExtensionsRegistry registry) {
this.pathWarner = new InvalidPathWarner(notificationService);
}
registry.registerDocumentLinkParticipant(documentLinkParticipant);
registry.registerDiagnosticsParticipant(diagnosticsParticipant);
}

@Override
public void stop(XMLExtensionsRegistry registry) {
registry.getResolverExtensionManager().unregisterResolver(uiResolver);
registry.unregisterDiagnosticsParticipant(diagnosticsParticipant);
}

private void validateCatalogPaths(ContentModelSettings cmSettings) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -289,4 +289,18 @@ public static String encodePath(String path) {
public static String readString(Path path) throws IOException {
return Files.readAllLines(path).stream().collect(Collectors.joining(System.lineSeparator()));
}

/**
* Returns true if the file at the given path exists.
*
* @param path the path.
*
* @return true if the file at the given path exists.
*/
public static boolean isValidPath(Path path){
if (Files.exists(path)) {
return true;
}
return false;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package org.eclipse.lemminx.extensions.catalog;

import static org.eclipse.lemminx.XMLAssert.d;

import org.eclipse.lemminx.XMLAssert;
import org.junit.jupiter.api.Test;

public class XMLCatalogDiagnosticsTest {
@Test
public void testCatalogWithValidFile() {
String xml = "<?xml version=\"1.0\"?>\n" + //
"<catalog xmlns=\"urn:oasis:names:tc:entity:xmlns:xml:catalog\">\n" + //
"<system systemId=\"http://www.springframework.org/schema/beans/spring-beans-3.0.xsd\"\n" + //
"uri=\"src/test/resources/xsd/spring-beans-3.0.xsd\" />" + //
"</catalog>";
XMLAssert.testDiagnosticsFor(xml);
}

@Test
public void testCatalogWithInvalidFile() {
String xml = "<?xml version=\"1.0\"?>\n" + //
"<catalog xmlns=\"urn:oasis:names:tc:entity:xmlns:xml:catalog\">\n" + //
"<system systemId=\"http://www.springframework.org/schema/beans/spring-beans-3.0.xsd\"\n" + //
"uri=\"src/test/resources/xsd/spring-beans-3.0ABCDE.xsd\" />" + //
"</catalog>";
XMLAssert.testDiagnosticsFor(xml, d(3, 5, 3, 53, XMLCatalogErrorCode.catalog_uri));
}

@Test
public void testCatalogWithHttpLink() {
String xml = "<?xml version=\"1.0\"?>\n" + //
"<catalog xmlns=\"urn:oasis:names:tc:entity:xmlns:xml:catalog\">\n" + //
"<system systemId=\"http://www.springframework.org/schema/beans/spring-beans-3.0.xsd\"\n" + //
"uri=\"http://www.springframework.org/schema/beans/spring-beans-3.0.xsd\" />" + //
"</catalog>";
XMLAssert.testDiagnosticsFor(xml);
}

@Test
public void testCatalogEntryWithXMLBaseGroupValidFile() {
String xml = "<?xml version=\"1.0\"?>\n" + //
" <catalog xmlns=\"urn:oasis:names:tc:entity:xmlns:xml:catalog\" xml:base= \"src\">\n" + //
" <group xml:base=\"test/resources/xsd/\">\n" + //
" <system systemId=\"http://www.springframework.org/schema/beans/spring-beans-3.0.xsd\"\n" + //
" uri=\"spring-beans-3.0.xsd\" />" + //
" </group>" + //
" </catalog>";
XMLAssert.testDiagnosticsFor(xml);
}

@Test
public void testCatalogEntryWithXMLBaseGroupInvalidFile() {
String xml = "<?xml version=\"1.0\"?>\n" + //
" <catalog xmlns=\"urn:oasis:names:tc:entity:xmlns:xml:catalog\" xml:base= \"src\">\n" + //
" <group xml:base=\"test/resources/xsd/\">\n" + //
" <system systemId=\"http://www.springframework.org/schema/beans/spring-beans-3.0.xsd\"\n" + //
" uri=\"spring-beans-3.0ABCDE.xsd\" />" + //
" </group>" + //
" </catalog>";
XMLAssert.testDiagnosticsFor(xml, d(4, 11, 4, 36, XMLCatalogErrorCode.catalog_uri));
}

@Test
public void testCatalogEntryWithXMLBaseGroupInvalidBase() {
String xml = "<?xml version=\"1.0\"?>\n" + //
" <catalog xmlns=\"urn:oasis:names:tc:entity:xmlns:xml:catalog\" xml:base= \"srcABCDE\">\n" + //
" <group xml:base=\"test/resources/xsd/\">\n" + //
" <system systemId=\"http://www.springframework.org/schema/beans/spring-beans-3.0.xsd\"\n" + //
" uri=\"spring-beans-3.0.xsd\" />" + //
" </group>" + //
" </catalog>";
XMLAssert.testDiagnosticsFor(xml, d(4, 11, 4, 31, XMLCatalogErrorCode.catalog_uri));
}
}

0 comments on commit 39eefb7

Please sign in to comment.