/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.jasper.tagplugins.jstl; import org.apache.jasper.Constants; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.PrintWriter; import java.io.StringWriter; import java.io.UnsupportedEncodingException; import java.util.Locale; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponseWrapper; import javax.servlet.jsp.JspException; import javax.servlet.jsp.JspTagException; import javax.servlet.jsp.PageContext; /** * Util contains some often used consts, static methods and embedded class * to support the JSTL tag plugin. */ public class Util { public static final String VALID_SCHEME_CHAR = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+.-"; public static final String DEFAULT_ENCODING = "ISO-8859-1"; public static final int HIGHEST_SPECIAL = '>'; public static char[][] specialCharactersRepresentation = new char[HIGHEST_SPECIAL + 1][]; static { specialCharactersRepresentation['&'] = "&".toCharArray(); specialCharactersRepresentation['<'] = "<".toCharArray(); specialCharactersRepresentation['>'] = ">".toCharArray(); specialCharactersRepresentation['"'] = """.toCharArray(); specialCharactersRepresentation['\''] = "'".toCharArray(); } /** * Converts the given string description of a scope to the corresponding * PageContext constant. * * The validity of the given scope has already been checked by the * appropriate TLV. * * @param scope String description of scope * * @return PageContext constant corresponding to given scope description * * taken from org.apache.taglibs.standard.tag.common.core.Util */ public static int getScope(String scope){ int ret = PageContext.PAGE_SCOPE; if("request".equalsIgnoreCase(scope)){ ret = PageContext.REQUEST_SCOPE; }else if("session".equalsIgnoreCase(scope)){ ret = PageContext.SESSION_SCOPE; }else if("application".equalsIgnoreCase(scope)){ ret = PageContext.APPLICATION_SCOPE; } return ret; } /** * Returns <tt>true</tt> if our current URL is absolute, * <tt>false</tt> otherwise. * taken from org.apache.taglibs.standard.tag.common.core.ImportSupport */ public static boolean isAbsoluteUrl(String url){ if(url == null){ return false; } int colonPos = url.indexOf(":"); if(colonPos == -1){ return false; } for(int i=0;i<colonPos;i++){ if(VALID_SCHEME_CHAR.indexOf(url.charAt(i)) == -1){ return false; } } return true; } /** * Get the value associated with a content-type attribute. * Syntax defined in RFC 2045, section 5.1. * taken from org.apache.taglibs.standard.tag.common.core.Util */ public static String getContentTypeAttribute(String input, String name) { int begin; int end; int index = input.toUpperCase().indexOf(name.toUpperCase()); if (index == -1) return null; index = index + name.length(); // positioned after the attribute name index = input.indexOf('=', index); // positioned at the '=' if (index == -1) return null; index += 1; // positioned after the '=' input = input.substring(index).trim(); if (input.charAt(0) == '"') { // attribute value is a quoted string begin = 1; end = input.indexOf('"', begin); if (end == -1) return null; } else { begin = 0; end = input.indexOf(';'); if (end == -1) end = input.indexOf(' '); if (end == -1) end = input.length(); } return input.substring(begin, end).trim(); } /** * Strips a servlet session ID from <tt>url</tt>. The session ID * is encoded as a URL "path parameter" beginning with "jsessionid=". * We thus remove anything we find between ";jsessionid=" (inclusive) * and either EOS or a subsequent ';' (exclusive). * * taken from org.apache.taglibs.standard.tag.common.core.ImportSupport */ public static String stripSession(String url) { StringBuffer u = new StringBuffer(url); int sessionStart; while ((sessionStart = u.toString().indexOf(";" + Constants.SESSION_PARAMETER_NAME + "=")) != -1) { int sessionEnd = u.toString().indexOf(";", sessionStart + 1); if (sessionEnd == -1) sessionEnd = u.toString().indexOf("?", sessionStart + 1); if (sessionEnd == -1) // still sessionEnd = u.length(); u.delete(sessionStart, sessionEnd); } return u.toString(); } /** * Performs the following substring replacements * (to facilitate output to XML/HTML pages): * * & -> & * < -> < * > -> > * " -> " * ' -> ' * * See also OutSupport.writeEscapedXml(). * * taken from org.apache.taglibs.standard.tag.common.core.Util */ public static String escapeXml(String buffer) { int start = 0; int length = buffer.length(); char[] arrayBuffer = buffer.toCharArray(); StringBuffer escapedBuffer = null; for (int i = 0; i < length; i++) { char c = arrayBuffer[i]; if (c <= HIGHEST_SPECIAL) { char[] escaped = specialCharactersRepresentation[c]; if (escaped != null) { // create StringBuffer to hold escaped xml string if (start == 0) { escapedBuffer = new StringBuffer(length + 5); } // add unescaped portion if (start < i) { escapedBuffer.append(arrayBuffer,start,i-start); } start = i + 1; // add escaped xml escapedBuffer.append(escaped); } } } // no xml escaping was necessary if (start == 0) { return buffer; } // add rest of unescaped portion if (start < length) { escapedBuffer.append(arrayBuffer,start,length-start); } return escapedBuffer.toString(); } /** Utility methods * taken from org.apache.taglibs.standard.tag.common.core.UrlSupport */ public static String resolveUrl( String url, String context, PageContext pageContext) throws JspException { // don't touch absolute URLs if (isAbsoluteUrl(url)) return url; // normalize relative URLs against a context root HttpServletRequest request = (HttpServletRequest) pageContext.getRequest(); if (context == null) { if (url.startsWith("/")) return (request.getContextPath() + url); else return url; } else { if (!context.startsWith("/") || !url.startsWith("/")) { throw new JspTagException( "In URL tags, when the \"context\" attribute is specified, values of both \"context\" and \"url\" must start with \"/\"."); } if (context.equals("/")) { // Don't produce string starting with '//', many // browsers interpret this as host name, not as // path on same host. return url; } else { return (context + url); } } } /** Wraps responses to allow us to retrieve results as Strings. * mainly taken from org.apache.taglibs.standard.tag.common.core.importSupport */ public static class ImportResponseWrapper extends HttpServletResponseWrapper{ private StringWriter sw = new StringWriter(); private ByteArrayOutputStream bos = new ByteArrayOutputStream(); private ServletOutputStream sos = new ServletOutputStream() { public void write(int b) throws IOException { bos.write(b); } }; private boolean isWriterUsed; private boolean isStreamUsed; private int status = 200; private String charEncoding; public ImportResponseWrapper(HttpServletResponse arg0) { super(arg0); // TODO Auto-generated constructor stub } public PrintWriter getWriter() { if (isStreamUsed) throw new IllegalStateException("Unexpected internal error during <import>: " + "Target servlet called getWriter(), then getOutputStream()"); isWriterUsed = true; return new PrintWriter(sw); } public ServletOutputStream getOutputStream() { if (isWriterUsed) throw new IllegalStateException("Unexpected internal error during <import>: " + "Target servlet called getOutputStream(), then getWriter()"); isStreamUsed = true; return sos; } /** Has no effect. */ public void setContentType(String x) { // ignore } /** Has no effect. */ public void setLocale(Locale x) { // ignore } public void setStatus(int status) { this.status = status; } public int getStatus() { return status; } public String getCharEncoding(){ return this.charEncoding; } public void setCharEncoding(String ce){ this.charEncoding = ce; } public String getString() throws UnsupportedEncodingException { if (isWriterUsed) return sw.toString(); else if (isStreamUsed) { if (this.charEncoding != null && !this.charEncoding.equals("")) return bos.toString(charEncoding); else return bos.toString("ISO-8859-1"); } else return ""; // target didn't write anything } } }