View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    * 
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   * 
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  
19  package org.apache.struts2.jasper.tagplugins.jstl;
20  
21  import javax.servlet.ServletOutputStream;
22  import javax.servlet.http.HttpServletRequest;
23  import javax.servlet.http.HttpServletResponse;
24  import javax.servlet.http.HttpServletResponseWrapper;
25  import javax.servlet.jsp.JspException;
26  import javax.servlet.jsp.JspTagException;
27  import javax.servlet.jsp.PageContext;
28  import java.io.*;
29  import java.util.Locale;
30  
31  /***
32   * Util contains some often used consts, static methods and embedded class
33   * to support the JSTL tag plugin.
34   */
35  
36  public class Util {
37  
38      public static final String VALID_SCHEME_CHAR =
39              "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+.-";
40  
41      public static final String DEFAULT_ENCODING =
42              "ISO-8859-1";
43  
44      public static final int HIGHEST_SPECIAL = '>';
45  
46      public static char[][] specialCharactersRepresentation = new char[HIGHEST_SPECIAL + 1][];
47  
48      static {
49          specialCharactersRepresentation['&'] = "&".toCharArray();
50          specialCharactersRepresentation['<'] = "&lt;".toCharArray();
51          specialCharactersRepresentation['>'] = "&gt;".toCharArray();
52          specialCharactersRepresentation['"'] = "&#034;".toCharArray();
53          specialCharactersRepresentation['\''] = "&#039;".toCharArray();
54      }
55  
56      /***
57       * Converts the given string description of a scope to the corresponding
58       * PageContext constant.
59       * <p/>
60       * The validity of the given scope has already been checked by the
61       * appropriate TLV.
62       *
63       * @param scope String description of scope
64       * @return PageContext constant corresponding to given scope description
65       *         <p/>
66       *         taken from org.apache.taglibs.standard.tag.common.core.Util
67       */
68      public static int getScope(String scope) {
69          int ret = PageContext.PAGE_SCOPE;
70  
71          if ("request".equalsIgnoreCase(scope)) {
72              ret = PageContext.REQUEST_SCOPE;
73          } else if ("session".equalsIgnoreCase(scope)) {
74              ret = PageContext.SESSION_SCOPE;
75          } else if ("application".equalsIgnoreCase(scope)) {
76              ret = PageContext.APPLICATION_SCOPE;
77          }
78  
79          return ret;
80      }
81  
82      /***
83       * Returns <tt>true</tt> if our current URL is absolute,
84       * <tt>false</tt> otherwise.
85       * taken from org.apache.taglibs.standard.tag.common.core.ImportSupport
86       */
87      public static boolean isAbsoluteUrl(String url) {
88          if (url == null) {
89              return false;
90          }
91  
92          int colonPos = url.indexOf(":");
93          if (colonPos == -1) {
94              return false;
95          }
96  
97          for (int i = 0; i < colonPos; i++) {
98              if (VALID_SCHEME_CHAR.indexOf(url.charAt(i)) == -1) {
99                  return false;
100             }
101         }
102 
103         return true;
104     }
105 
106     /***
107      * Get the value associated with a content-type attribute.
108      * Syntax defined in RFC 2045, section 5.1.
109      * taken from org.apache.taglibs.standard.tag.common.core.Util
110      */
111     public static String getContentTypeAttribute(String input, String name) {
112         int begin;
113         int end;
114         int index = input.toUpperCase().indexOf(name.toUpperCase());
115         if (index == -1) return null;
116         index = index + name.length(); // positioned after the attribute name
117         index = input.indexOf('=', index); // positioned at the '='
118         if (index == -1) return null;
119         index += 1; // positioned after the '='
120         input = input.substring(index).trim();
121 
122         if (input.charAt(0) == '"') {
123             // attribute value is a quoted string
124             begin = 1;
125             end = input.indexOf('"', begin);
126             if (end == -1) return null;
127         } else {
128             begin = 0;
129             end = input.indexOf(';');
130             if (end == -1) end = input.indexOf(' ');
131             if (end == -1) end = input.length();
132         }
133         return input.substring(begin, end).trim();
134     }
135 
136     /***
137      * Strips a servlet session ID from <tt>url</tt>.  The session ID
138      * is encoded as a URL "path parameter" beginning with "jsessionid=".
139      * We thus remove anything we find between ";jsessionid=" (inclusive)
140      * and either EOS or a subsequent ';' (exclusive).
141      * <p/>
142      * taken from org.apache.taglibs.standard.tag.common.core.ImportSupport
143      */
144     public static String stripSession(String url) {
145         StringBuffer u = new StringBuffer(url);
146         int sessionStart;
147         while ((sessionStart = u.toString().indexOf(";jsessionid=")) != -1) {
148             int sessionEnd = u.toString().indexOf(";", sessionStart + 1);
149             if (sessionEnd == -1)
150                 sessionEnd = u.toString().indexOf("?", sessionStart + 1);
151             if (sessionEnd == -1)                 // still
152                 sessionEnd = u.length();
153             u.delete(sessionStart, sessionEnd);
154         }
155         return u.toString();
156     }
157 
158 
159     /***
160      * Performs the following substring replacements
161      * (to facilitate output to XML/HTML pages):
162      * <p/>
163      * & -> &amp;
164      * < -> &lt;
165      * > -> &gt;
166      * " -> &#034;
167      * ' -> &#039;
168      * <p/>
169      * See also OutSupport.writeEscapedXml().
170      * <p/>
171      * taken from org.apache.taglibs.standard.tag.common.core.Util
172      */
173     public static String escapeXml(String buffer) {
174         int start = 0;
175         int length = buffer.length();
176         char[] arrayBuffer = buffer.toCharArray();
177         StringBuffer escapedBuffer = null;
178 
179         for (int i = 0; i < length; i++) {
180             char c = arrayBuffer[i];
181             if (c <= HIGHEST_SPECIAL) {
182                 char[] escaped = specialCharactersRepresentation[c];
183                 if (escaped != null) {
184                     // create StringBuffer to hold escaped xml string
185                     if (start == 0) {
186                         escapedBuffer = new StringBuffer(length + 5);
187                     }
188                     // add unescaped portion
189                     if (start < i) {
190                         escapedBuffer.append(arrayBuffer, start, i - start);
191                     }
192                     start = i + 1;
193                     // add escaped xml
194                     escapedBuffer.append(escaped);
195                 }
196             }
197         }
198         // no xml escaping was necessary
199         if (start == 0) {
200             return buffer;
201         }
202         // add rest of unescaped portion
203         if (start < length) {
204             escapedBuffer.append(arrayBuffer, start, length - start);
205         }
206         return escapedBuffer.toString();
207     }
208 
209     /***
210      * Utility methods
211      * taken from org.apache.taglibs.standard.tag.common.core.UrlSupport
212      */
213     public static String resolveUrl(
214             String url, String context, PageContext pageContext)
215             throws JspException {
216         // don't touch absolute URLs
217         if (isAbsoluteUrl(url))
218             return url;
219 
220         // normalize relative URLs against a context root
221         HttpServletRequest request =
222                 (HttpServletRequest) pageContext.getRequest();
223         if (context == null) {
224             if (url.startsWith("/"))
225                 return (request.getContextPath() + url);
226             else
227                 return url;
228         } else {
229             if (!context.startsWith("/") || !url.startsWith("/")) {
230                 throw new JspTagException(
231                         "In URL tags, when the \"context\" attribute is specified, values of both \"context\" and \"url\" must start with \"/\".");
232             }
233             if (context.equals("/")) {
234                 // Don't produce string starting with '//', many
235                 // browsers interpret this as host name, not as
236                 // path on same host.
237                 return url;
238             } else {
239                 return (context + url);
240             }
241         }
242     }
243 
244     /***
245      * Wraps responses to allow us to retrieve results as Strings.
246      * mainly taken from org.apache.taglibs.standard.tag.common.core.importSupport
247      */
248     public static class ImportResponseWrapper extends HttpServletResponseWrapper {
249 
250         private StringWriter sw = new StringWriter();
251         private ByteArrayOutputStream bos = new ByteArrayOutputStream();
252         private ServletOutputStream sos = new ServletOutputStream() {
253             public void write(int b) throws IOException {
254                 bos.write(b);
255             }
256         };
257         private boolean isWriterUsed;
258         private boolean isStreamUsed;
259         private int status = 200;
260         private String charEncoding;
261 
262         public ImportResponseWrapper(HttpServletResponse arg0) {
263             super(arg0);
264             // TODO Auto-generated constructor stub
265         }
266 
267         public PrintWriter getWriter() {
268             if (isStreamUsed)
269                 throw new IllegalStateException("Unexpected internal error during &lt;import&gt: " +
270                         "Target servlet called getWriter(), then getOutputStream()");
271             isWriterUsed = true;
272             return new PrintWriter(sw);
273         }
274 
275         public ServletOutputStream getOutputStream() {
276             if (isWriterUsed)
277                 throw new IllegalStateException("Unexpected internal error during &lt;import&gt: " +
278                         "Target servlet called getOutputStream(), then getWriter()");
279             isStreamUsed = true;
280             return sos;
281         }
282 
283         /***
284          * Has no effect.
285          */
286         public void setContentType(String x) {
287             // ignore
288         }
289 
290         /***
291          * Has no effect.
292          */
293         public void setLocale(Locale x) {
294             // ignore
295         }
296 
297         public void setStatus(int status) {
298             this.status = status;
299         }
300 
301         public int getStatus() {
302             return status;
303         }
304 
305         public String getCharEncoding() {
306             return this.charEncoding;
307         }
308 
309         public void setCharEncoding(String ce) {
310             this.charEncoding = ce;
311         }
312 
313         public String getString() throws UnsupportedEncodingException {
314             if (isWriterUsed)
315                 return sw.toString();
316             else if (isStreamUsed) {
317                 if (this.charEncoding != null && !this.charEncoding.equals(""))
318                     return bos.toString(charEncoding);
319                 else
320                     return bos.toString("ISO-8859-1");
321             } else
322                 return "";        // target didn't write anything
323         }
324     }
325 
326 }