// --- BEGIN COPYRIGHT BLOCK --- // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; version 2 of the License. // // This program 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 General Public License for more details. // // You should have received a copy of the GNU General Public License along // with this program; if not, write to the Free Software Foundation, Inc., // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. // // (C) 2007 Red Hat, Inc. // All rights reserved. // --- END COPYRIGHT BLOCK --- package com.netscape.cms.servlet.common; import java.io.BufferedReader; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.io.UnsupportedEncodingException; import java.math.BigInteger; import java.util.Enumeration; import com.netscape.certsrv.apps.CMS; import com.netscape.certsrv.base.EBaseException; import com.netscape.certsrv.base.IArgBlock; import com.netscape.certsrv.logging.ILogger; /** * File templates. This implementation will take * an HTML file with a special customer tag * <CMS_TEMPLATE> and replace the tag with * a series of javascript variable definitions * (depending on the servlet) * * @version $Revision$, $Date$ */ public class CMSTemplate extends CMSFile { public static final String SUFFIX = ".template"; /*========================================================== * variables *==========================================================*/ /* public vaiables */ public String mPreOutput; public String mPostOutput; public static final String TEMPLATE_TAG = ""; /* Character set for i18n */ /* Will be set by CMSServlet.getTemplate() */ private String mCharset = null; /*========================================================== * constructors *==========================================================*/ /** * Constructor * * @param file template file to load * @param charset character set * @throws IOException if the there was an error opening the file */ public CMSTemplate(File file, String charset) throws IOException, EBaseException { mCharset = charset; mAbsPath = file.getAbsolutePath(); mLastModified = file.lastModified(); try { init(file); } catch (IOException e) { log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSGW_CANT_LOAD_TEMPLATE", mAbsPath, e.toString())); throw new ECMSGWException( CMS.getLogMessage("CMSGW_ERROR_LOADING_TEMPLATE")); } String content = mPreOutput + mPostOutput; mContent = content.getBytes(mCharset); } /*========================================================== * public methods *==========================================================*/ /* * * Load the form from the file and setup the * pre/post output buffer if it is a template * file. Otherwise, only post output buffer is * filled. * @param template the template file to load * @return true if successful */ public boolean init(File template) throws EBaseException, IOException { /* load template */ String content = loadFile(template); if (content == null) { log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSGW_TEMPLATE_EMPTY", mAbsPath)); throw new ECMSGWException( CMS.getLogMessage("CMSGW_TEMPLATE_NO_CONTENT_1", mAbsPath)); } /* if template file, find template tag substring and set * pre/post output string */ int location = content.indexOf(TEMPLATE_TAG); if (location == -1) { log(ILogger.LL_FAILURE, CMS.getLogMessage( "CMSGW_TEMPLATE_MISSING", mAbsPath, TEMPLATE_TAG)); throw new ECMSGWException( CMS.getLogMessage("CMSGW_MISSING_TEMPLATE_TAG_2", TEMPLATE_TAG, mAbsPath)); } mPreOutput = content.substring(0, location); mPostOutput = content.substring(TEMPLATE_TAG.length() + location); return true; } /** * Write a javascript representation of 'input' * surrounded by SCRIPT tags to the outputstream * * @param rout the outputstream to write to * @param input the parameters to write */ public void renderOutput(OutputStream rout, CMSTemplateParams input) throws IOException { Enumeration e = null; Enumeration q = null; IArgBlock r = null; CMSTemplateParams data = input; try (HTTPOutputStreamWriter http_out = (mCharset == null ? new HTTPOutputStreamWriter(rout) : new HTTPOutputStreamWriter(rout, mCharset))) { templateLine out = new templateLine(); // Output the prolog out.print(mPreOutput); // Output the header data out.println(""); out.println(mPostOutput); http_out.print(out.toString()); } catch (EBaseException ex) { throw new IOException(ex.getMessage()); } } /** * Ouput the pre-amble HTML Header including * the pre-output buffer. * * @param out output stream specified * @return success or error */ public boolean outputProlog(PrintWriter out) { //Debug.trace("FormCache:outputProlog"); /* output pre-output buffer */ out.print(mPreOutput); /* output JavaScript variables and objects */ out.println(""); out.println(mPostOutput); return true; } /** * @return full path of template */ public String getTemplateName() { return mAbsPath; } // inherit getabspath, getContent, get last access and set last access /*========================================================== * private methods *==========================================================*/ /* load file into string */ private String loadFile(File template) throws IOException { // Debug.trace("FormCache:loadFile"); /* create input stream, can throw IOException */ FileInputStream inStream = new FileInputStream(template); InputStreamReader inReader = new InputStreamReader(inStream, mCharset); ; BufferedReader in = new BufferedReader(inReader); StringBuffer buf = new StringBuffer(); String line; while ((line = in.readLine()) != null) { buf.append(line); buf.append('\n'); } try { in.close(); inStream.close(); } catch (IOException e) { log(ILogger.LL_WARN, CMS.getLogMessage("CMSGW_ERR_CLOSE_TEMPL_FILE", mAbsPath, e.getMessage())); } return buf.toString(); } private String renderValue(Object v) { String s = null; // Figure out the type of object if (v instanceof IRawJS) { s = v.toString(); } else if (v instanceof String) { if (v.equals("")) s = "null"; else s = "\"" + CMSTemplate.escapeJavaScriptString((String) v) + "\""; } else if (v instanceof Integer) { s = ((Integer) v).toString(); } else if (v instanceof Boolean) { if (((Boolean) v).booleanValue() == true) { s = "true"; } else { s = "false"; } } else if (v instanceof BigInteger) { s = ((BigInteger) v).toString(10); } else if (v instanceof Character && ((Character) v).equals(Character.valueOf((char) 0))) { s = "null"; } else { s = "\"" + v.toString() + "\""; } return s; } /** * Escape the contents of src string in preparation to be enclosed in * double quotes as a JavaScript String Literal within an <script> * portion of an HTML document. * stevep - performance improvements - about 4 times faster than before. */ public static String escapeJavaScriptString(String v) { int l = v.length(); char in[] = new char[l]; char out[] = new char[l * 4]; int j = 0; v.getChars(0, l, in, 0); for (int i = 0; i < l; i++) { char c = in[i]; if ((c > 0x23) && (c != 0x5c) && (c != 0x3c) && (c != 0x3e) && (c != 0x3b)) { out[j++] = c; continue; } /* some inputs are coming in as '\' and 'n' */ /* see BZ 500736 for details */ if ((c == 0x5c) && ((i+1)' || in[i+1] == 'x' || in[i+1] == ';' || in[i+1] == '\"' || in[i+1] == '\'' || in[i+1] == '\\')) { if (in[i+1] == 'x' && ((i+3)') { c = in[i+1]; i++; } else if (in[i+1] == ';') { out[j++] = in[i+1]; i++; continue; } else { out[j++] = '\\'; out[j++] = in[i+1]; i++; continue; } } if (c == '&') { int k; for (k = 0; k < 8 && (i+k) < l; k++) { out[j+k] = in[i+k]; if (in[i+k] == ';') break; if (in[i+k] == '<' || in[i+k] == '>') { k = 8; break; } } if (k < 8) { i += k; j += k + 1; continue; } } switch (c) { case '\n': out[j++] = '\\'; out[j++] = 'n'; break; case '\\': out[j++] = '\\'; out[j++] = '\\'; break; case '\"': out[j++] = '\\'; out[j++] = '\"'; break; case '\r': out[j++] = '\\'; out[j++] = 'r'; break; case '\f': out[j++] = '\\'; out[j++] = 'f'; break; case '\t': out[j++] = '\\'; out[j++] = 't'; break; case '<': out[j++] = '\\'; out[j++] = 'x'; out[j++] = '3'; out[j++] = 'c'; break; case '>': out[j++] = '\\'; out[j++] = 'x'; out[j++] = '3'; out[j++] = 'e'; break; case '&': out[j++] = '&'; out[j++] = 'a'; out[j++] = 'm'; out[j++] = 'p'; out[j++] = ';'; break; default: out[j++] = c; } } return new String(out, 0, j); } /** * Like escapeJavaScriptString(String s) but also escape '[' for * HTML processing. */ public static String escapeJavaScriptStringHTML(String v) { int l = v.length(); char in[] = new char[l]; char out[] = new char[l * 8]; int j = 0; v.getChars(0, l, in, 0); for (int i = 0; i < l; i++) { char c = in[i]; if (c > 0x5C) { out[j++] = c; continue; } if ((c == 0x5c) && ((i + 1) < l) && (in[i + 1] == 'n' || in[i + 1] == 'r' || in[i + 1] == 'f' || in[i + 1] == 't' || in[i + 1] == '<' || in[i + 1] == '>' || in[i + 1] == 'x' || in[i + 1] == ';' || in[i + 1] == '\"' || in[i + 1] == '\'' || in[i + 1] == '\\')) { if (in[i + 1] == 'x' && ((i + 3) < l) && in[i + 2] == '3' && (in[i + 3] == 'c' || in[i + 3] == 'e')) { out[j++] = '\\'; out[j++] = in[i + 1]; out[j++] = in[i + 2]; out[j++] = in[i + 3]; i += 3; continue; } else if (in[i + 1] == '<' || in[i + 1] == '>') { c = in[i + 1]; i++; } else if (in[i + 1] == ';') { out[j++] = in[i + 1]; i++; continue; } else { out[j++] = '\\'; out[j++] = in[i + 1]; i++; continue; } } if (c == '&') { int k; for (k = 0; k < 8 && (i + k) < l; k++) { out[j + k] = in[i + k]; if (in[i + k] == ';') break; if (in[i + k] == '<' || in[i + k] == '>') { k = 8; break; } } if (k < 8) { i += k; j += k + 1; continue; } } switch (c) { case '\n': out[j++] = '\\'; out[j++] = 'n'; break; case '\\': out[j++] = '\\'; out[j++] = '\\'; break; case '\"': out[j++] = '\\'; out[j++] = '\"'; break; case '\r': out[j++] = '\\'; out[j++] = 'r'; break; case '\f': out[j++] = '\\'; out[j++] = 'f'; break; case '\t': out[j++] = '\\'; out[j++] = 't'; break; case '<': out[j++] = '&'; out[j++] = 'l'; out[j++] = 't'; out[j++] = ';'; break; case '>': out[j++] = '&'; out[j++] = 'g'; out[j++] = 't'; out[j++] = ';'; break; default: out[j++] = c; } } return new String(out, 0, j); } /** * for debugging, return contents that would've been outputed. */ public String getOutput(CMSTemplateParams input) throws IOException { ByteArrayOutputStream out = new ByteArrayOutputStream(); renderOutput(out, input); return out.toString(); } private class HTTPOutputStreamWriter extends OutputStreamWriter { public HTTPOutputStreamWriter(OutputStream out) throws UnsupportedEncodingException { super(out); } public HTTPOutputStreamWriter(OutputStream out, String enc) throws UnsupportedEncodingException { super(out, enc); } public void print(String s) throws IOException { write(s, 0, s.length()); flush(); return; } } private class templateLine { private StringBuffer s = new StringBuffer(); void println(String p) { s.append('\n'); s.append(p); } void print(String p) { s.append(p); } public String toString() { return s.toString(); } } }