001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: package org.apache.jasper.tagplugins.jstl;
019:
020: import org.apache.jasper.Constants;
021:
022: import java.io.ByteArrayOutputStream;
023: import java.io.IOException;
024: import java.io.PrintWriter;
025: import java.io.StringWriter;
026: import java.io.UnsupportedEncodingException;
027: import java.util.Locale;
028:
029: import javax.servlet.ServletOutputStream;
030: import javax.servlet.http.HttpServletRequest;
031: import javax.servlet.http.HttpServletResponse;
032: import javax.servlet.http.HttpServletResponseWrapper;
033: import javax.servlet.jsp.JspException;
034: import javax.servlet.jsp.JspTagException;
035: import javax.servlet.jsp.PageContext;
036:
037: /**
038: * Util contains some often used consts, static methods and embedded class
039: * to support the JSTL tag plugin.
040: */
041:
042: public class Util {
043:
044: public static final String VALID_SCHEME_CHAR = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+.-";
045:
046: public static final String DEFAULT_ENCODING = "ISO-8859-1";
047:
048: public static final int HIGHEST_SPECIAL = '>';
049:
050: public static char[][] specialCharactersRepresentation = new char[HIGHEST_SPECIAL + 1][];
051:
052: static {
053: specialCharactersRepresentation['&'] = "&".toCharArray();
054: specialCharactersRepresentation['<'] = "<".toCharArray();
055: specialCharactersRepresentation['>'] = ">".toCharArray();
056: specialCharactersRepresentation['"'] = """.toCharArray();
057: specialCharactersRepresentation['\''] = "'".toCharArray();
058: }
059:
060: /**
061: * Converts the given string description of a scope to the corresponding
062: * PageContext constant.
063: *
064: * The validity of the given scope has already been checked by the
065: * appropriate TLV.
066: *
067: * @param scope String description of scope
068: *
069: * @return PageContext constant corresponding to given scope description
070: *
071: * taken from org.apache.taglibs.standard.tag.common.core.Util
072: */
073: public static int getScope(String scope) {
074: int ret = PageContext.PAGE_SCOPE;
075:
076: if ("request".equalsIgnoreCase(scope)) {
077: ret = PageContext.REQUEST_SCOPE;
078: } else if ("session".equalsIgnoreCase(scope)) {
079: ret = PageContext.SESSION_SCOPE;
080: } else if ("application".equalsIgnoreCase(scope)) {
081: ret = PageContext.APPLICATION_SCOPE;
082: }
083:
084: return ret;
085: }
086:
087: /**
088: * Returns <tt>true</tt> if our current URL is absolute,
089: * <tt>false</tt> otherwise.
090: * taken from org.apache.taglibs.standard.tag.common.core.ImportSupport
091: */
092: public static boolean isAbsoluteUrl(String url) {
093: if (url == null) {
094: return false;
095: }
096:
097: int colonPos = url.indexOf(":");
098: if (colonPos == -1) {
099: return false;
100: }
101:
102: for (int i = 0; i < colonPos; i++) {
103: if (VALID_SCHEME_CHAR.indexOf(url.charAt(i)) == -1) {
104: return false;
105: }
106: }
107:
108: return true;
109: }
110:
111: /**
112: * Get the value associated with a content-type attribute.
113: * Syntax defined in RFC 2045, section 5.1.
114: * taken from org.apache.taglibs.standard.tag.common.core.Util
115: */
116: public static String getContentTypeAttribute(String input,
117: String name) {
118: int begin;
119: int end;
120: int index = input.toUpperCase().indexOf(name.toUpperCase());
121: if (index == -1)
122: return null;
123: index = index + name.length(); // positioned after the attribute name
124: index = input.indexOf('=', index); // positioned at the '='
125: if (index == -1)
126: return null;
127: index += 1; // positioned after the '='
128: input = input.substring(index).trim();
129:
130: if (input.charAt(0) == '"') {
131: // attribute value is a quoted string
132: begin = 1;
133: end = input.indexOf('"', begin);
134: if (end == -1)
135: return null;
136: } else {
137: begin = 0;
138: end = input.indexOf(';');
139: if (end == -1)
140: end = input.indexOf(' ');
141: if (end == -1)
142: end = input.length();
143: }
144: return input.substring(begin, end).trim();
145: }
146:
147: /**
148: * Strips a servlet session ID from <tt>url</tt>. The session ID
149: * is encoded as a URL "path parameter" beginning with "jsessionid=".
150: * We thus remove anything we find between ";jsessionid=" (inclusive)
151: * and either EOS or a subsequent ';' (exclusive).
152: *
153: * taken from org.apache.taglibs.standard.tag.common.core.ImportSupport
154: */
155: public static String stripSession(String url) {
156: StringBuffer u = new StringBuffer(url);
157: int sessionStart;
158: while ((sessionStart = u.toString().indexOf(
159: ";" + Constants.SESSION_PARAMETER_NAME + "=")) != -1) {
160: int sessionEnd = u.toString()
161: .indexOf(";", sessionStart + 1);
162: if (sessionEnd == -1)
163: sessionEnd = u.toString()
164: .indexOf("?", sessionStart + 1);
165: if (sessionEnd == -1) // still
166: sessionEnd = u.length();
167: u.delete(sessionStart, sessionEnd);
168: }
169: return u.toString();
170: }
171:
172: /**
173: * Performs the following substring replacements
174: * (to facilitate output to XML/HTML pages):
175: *
176: * & -> &
177: * < -> <
178: * > -> >
179: * " -> "
180: * ' -> '
181: *
182: * See also OutSupport.writeEscapedXml().
183: *
184: * taken from org.apache.taglibs.standard.tag.common.core.Util
185: */
186: public static String escapeXml(String buffer) {
187: int start = 0;
188: int length = buffer.length();
189: char[] arrayBuffer = buffer.toCharArray();
190: StringBuffer escapedBuffer = null;
191:
192: for (int i = 0; i < length; i++) {
193: char c = arrayBuffer[i];
194: if (c <= HIGHEST_SPECIAL) {
195: char[] escaped = specialCharactersRepresentation[c];
196: if (escaped != null) {
197: // create StringBuffer to hold escaped xml string
198: if (start == 0) {
199: escapedBuffer = new StringBuffer(length + 5);
200: }
201: // add unescaped portion
202: if (start < i) {
203: escapedBuffer.append(arrayBuffer, start, i
204: - start);
205: }
206: start = i + 1;
207: // add escaped xml
208: escapedBuffer.append(escaped);
209: }
210: }
211: }
212: // no xml escaping was necessary
213: if (start == 0) {
214: return buffer;
215: }
216: // add rest of unescaped portion
217: if (start < length) {
218: escapedBuffer.append(arrayBuffer, start, length - start);
219: }
220: return escapedBuffer.toString();
221: }
222:
223: /** Utility methods
224: * taken from org.apache.taglibs.standard.tag.common.core.UrlSupport
225: */
226: public static String resolveUrl(String url, String context,
227: PageContext pageContext) throws JspException {
228: // don't touch absolute URLs
229: if (isAbsoluteUrl(url))
230: return url;
231:
232: // normalize relative URLs against a context root
233: HttpServletRequest request = (HttpServletRequest) pageContext
234: .getRequest();
235: if (context == null) {
236: if (url.startsWith("/"))
237: return (request.getContextPath() + url);
238: else
239: return url;
240: } else {
241: if (!context.startsWith("/") || !url.startsWith("/")) {
242: throw new JspTagException(
243: "In URL tags, when the \"context\" attribute is specified, values of both \"context\" and \"url\" must start with \"/\".");
244: }
245: if (context.equals("/")) {
246: // Don't produce string starting with '//', many
247: // browsers interpret this as host name, not as
248: // path on same host.
249: return url;
250: } else {
251: return (context + url);
252: }
253: }
254: }
255:
256: /** Wraps responses to allow us to retrieve results as Strings.
257: * mainly taken from org.apache.taglibs.standard.tag.common.core.importSupport
258: */
259: public static class ImportResponseWrapper extends
260: HttpServletResponseWrapper {
261:
262: private StringWriter sw = new StringWriter();
263: private ByteArrayOutputStream bos = new ByteArrayOutputStream();
264: private ServletOutputStream sos = new ServletOutputStream() {
265: public void write(int b) throws IOException {
266: bos.write(b);
267: }
268: };
269: private boolean isWriterUsed;
270: private boolean isStreamUsed;
271: private int status = 200;
272: private String charEncoding;
273:
274: public ImportResponseWrapper(HttpServletResponse arg0) {
275: super (arg0);
276: // TODO Auto-generated constructor stub
277: }
278:
279: public PrintWriter getWriter() {
280: if (isStreamUsed)
281: throw new IllegalStateException(
282: "Unexpected internal error during <import>: "
283: + "Target servlet called getWriter(), then getOutputStream()");
284: isWriterUsed = true;
285: return new PrintWriter(sw);
286: }
287:
288: public ServletOutputStream getOutputStream() {
289: if (isWriterUsed)
290: throw new IllegalStateException(
291: "Unexpected internal error during <import>: "
292: + "Target servlet called getOutputStream(), then getWriter()");
293: isStreamUsed = true;
294: return sos;
295: }
296:
297: /** Has no effect. */
298: public void setContentType(String x) {
299: // ignore
300: }
301:
302: /** Has no effect. */
303: public void setLocale(Locale x) {
304: // ignore
305: }
306:
307: public void setStatus(int status) {
308: this .status = status;
309: }
310:
311: public int getStatus() {
312: return status;
313: }
314:
315: public String getCharEncoding() {
316: return this .charEncoding;
317: }
318:
319: public void setCharEncoding(String ce) {
320: this .charEncoding = ce;
321: }
322:
323: public String getString() throws UnsupportedEncodingException {
324: if (isWriterUsed)
325: return sw.toString();
326: else if (isStreamUsed) {
327: if (this .charEncoding != null
328: && !this .charEncoding.equals(""))
329: return bos.toString(charEncoding);
330: else
331: return bos.toString("ISO-8859-1");
332: } else
333: return ""; // target didn't write anything
334: }
335: }
336:
337: }
|