/** * Copyright (c) 2000-present Liferay, Inc. All rights reserved. * * This library is free software; you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by the Free * Software Foundation; either version 2.1 of the License, or (at your option) * any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. */ package com.liferay.portal.template; import com.liferay.portal.kernel.log.Log; import com.liferay.portal.kernel.log.LogFactoryUtil; import com.liferay.portal.kernel.template.TemplateConstants; import com.liferay.portal.kernel.template.TemplateException; import com.liferay.portal.kernel.template.TemplateResource; import com.liferay.portal.kernel.template.URLTemplateResource; import com.liferay.portal.kernel.util.ArrayUtil; import com.liferay.portal.kernel.util.CharPool; import com.liferay.portal.kernel.util.FileUtil; import com.liferay.portal.kernel.util.StringPool; import com.liferay.portal.kernel.util.StringUtil; import com.liferay.portal.kernel.util.Validator; import java.io.IOException; import java.net.URL; import java.util.ArrayList; import java.util.List; /** * @author Tina Tian */ public abstract class URLResourceParser implements TemplateResourceParser { @Override public TemplateResource getTemplateResource(String templateId) throws TemplateException { templateId = normalizePath(templateId); try { URL url = getURL(templateId); if (url == null) { return null; } return new URLTemplateResource(templateId, url); } catch (IOException ioe) { throw new TemplateException(ioe); } } public abstract URL getURL(String templateId) throws IOException; @Override public boolean isTemplateResourceValid(String templateId, String langType) { if (Validator.isBlank(templateId)) { return true; } char[] chars = templateId.toCharArray(); for (int i = 0; i < chars.length; i++) { char c = chars[i]; if ((c == CharPool.PERCENT) || (c == CharPool.POUND) || (c == CharPool.QUESTION) || (c == CharPool.SEMICOLON)) { if (_log.isWarnEnabled()) { _log.warn( "Unable to load template " + templateId + " because the template name contains one or more " + "special characters: %, #, ?, or ;"); } return false; } if (c == CharPool.BACK_SLASH) { if (_log.isWarnEnabled()) { _log.warn( "Unable to load template " + templateId + " because the template name contains a backslash"); } return false; } } String extension = FileUtil.getExtension(templateId); if (!extension.equals(langType) && !ArrayUtil.contains( TemplateConstants.ALLOWED_LANG_TYPES, extension)) { return false; } return true; } protected static String normalizePath(String path) { List<String> elements = new ArrayList<>(); boolean absolutePath = false; int previousIndex = -1; for (int index; (index = path.indexOf(CharPool.SLASH, previousIndex + 1)) != -1; previousIndex = index) { if ((previousIndex + 1) == index) { // Starts with "/" if (previousIndex == -1) { absolutePath = true; continue; } // "//" is illegal throw new IllegalArgumentException( "Unable to parse path " + path); } String pathElement = path.substring(previousIndex + 1, index); // "." needs no handling if (pathElement.equals(StringPool.PERIOD)) { continue; } // ".." pops up stack if (pathElement.equals(StringPool.DOUBLE_PERIOD)) { if (elements.isEmpty()) { throw new IllegalArgumentException( "Unable to parse path " + path); } elements.remove(elements.size() - 1); continue; } // Others push down stack elements.add(pathElement); } if (previousIndex == -1) { elements.add(path); } else if ((previousIndex + 1) < path.length()) { elements.add(path.substring(previousIndex + 1)); } String normalizedPath = StringUtil.merge(elements, StringPool.SLASH); if (absolutePath) { normalizedPath = StringPool.SLASH.concat(normalizedPath); } return normalizedPath; } private static final Log _log = LogFactoryUtil.getLog( URLResourceParser.class); }