/* | |
* 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.struts2.jasper.tagplugins.jstl; | |
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; | |
import java.io.*; | |
import java.util.Locale; | |
/** | |
* 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(";jsessionid=")) != -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 | |
} | |
} | |
} |