/******************************************************************************* * Copyright (c) 2012-2016 Codenvy, S.A. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Codenvy, S.A. - initial API and implementation *******************************************************************************/ package org.everrest.core.tools; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import javax.servlet.ServletContext; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.xpath.XPath; import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathFactory; import java.io.IOException; import java.io.InputStream; import java.util.HashMap; import java.util.Map; import static com.google.common.base.Throwables.propagate; import static javax.xml.XMLConstants.FEATURE_SECURE_PROCESSING; /** * Describes error-page references for web application in web.xml file. * * @author Max Shaposhnik */ public class ErrorPages { private static final Logger LOG = LoggerFactory.getLogger(ErrorPages.class); private final Map<Integer, String> errorCodes = new HashMap<>(); private final Map<String, String> exceptionTypes = new HashMap<>(); public ErrorPages(ServletContext servletContext) { loadErrorPages(servletContext, errorCodes, exceptionTypes); } public boolean hasErrorPage(int errorCode) { return errorCodes.get(errorCode) != null; } public boolean hasErrorPage(String exceptionType) { return exceptionTypes.get(exceptionType) != null; } public boolean hasErrorPage(Throwable exception) { return hasErrorPage(exception.getClass().getName()); } protected void loadErrorPages(ServletContext servletContext, Map<Integer, String> errorCodes, Map<String, String> exceptionTypes) { InputStream input = servletContext.getResourceAsStream("/WEB-INF/web.xml"); if (input != null) { try { DocumentBuilderFactory documentBuilderFactory = createFeaturedDocumentBuilderFactory(); DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder(); Document dom = documentBuilder.parse(input); XPathFactory xpathFactory = XPathFactory.newInstance(); XPath xpath = xpathFactory.newXPath(); NodeList all = (NodeList)xpath.evaluate("/web-app/error-page", dom, XPathConstants.NODESET); int length = all.getLength(); for (int i = 0; i < length; i++) { Node errorPage = all.item(i); if (errorPage.getNodeType() == Node.ELEMENT_NODE) { Element errorElement = (Element)errorPage; NodeList locationList = errorElement.getElementsByTagName("location"); if (locationList.getLength() != 0) { String location = locationList.item(0).getTextContent(); NodeList errorCodeList = errorElement.getElementsByTagName("error-code"); if (errorCodeList.getLength() != 0) { try { Integer errorCode = Integer.valueOf(errorCodeList.item(0).getTextContent()); errorCodes.put(errorCode, location); } catch (NumberFormatException ignored) { } } else { NodeList exceptionTypeList = errorElement.getElementsByTagName("exception-type"); if (exceptionTypeList.getLength() != 0) { exceptionTypes.put(exceptionTypeList.item(0).getTextContent(), location); } } } } } } catch (Exception e) { propagate(e); } finally { try { input.close(); } catch (IOException ignored) { } } } } private DocumentBuilderFactory createFeaturedDocumentBuilderFactory() { DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); try { factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); factory.setFeature("http://xml.org/sax/features/external-general-entities", false); factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false); factory.setFeature(FEATURE_SECURE_PROCESSING, true); } catch (ParserConfigurationException e) { LOG.debug(e.getMessage(), e); } return factory; } }