View Javadoc

1   /*
2    * $Id: UrlHelper.java 630740 2008-02-25 06:09:14Z rgielen $
3    *
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *  http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  package org.apache.struts2.views.util;
23  
24  import java.io.UnsupportedEncodingException;
25  import java.net.URLDecoder;
26  import java.net.URLEncoder;
27  import java.util.ArrayList;
28  import java.util.Arrays;
29  import java.util.Iterator;
30  import java.util.LinkedHashMap;
31  import java.util.List;
32  import java.util.Map;
33  
34  import javax.servlet.http.HttpServletRequest;
35  import javax.servlet.http.HttpServletResponse;
36  
37  import org.apache.commons.logging.Log;
38  import org.apache.commons.logging.LogFactory;
39  import org.apache.struts2.ServletActionContext;
40  import org.apache.struts2.StrutsConstants;
41  
42  import com.opensymphony.xwork2.inject.Inject;
43  import com.opensymphony.xwork2.util.TextParseUtil;
44  import com.opensymphony.xwork2.util.ValueStack;
45  
46  
47  /***
48   * UrlHelper
49   *
50   */
51  public class UrlHelper {
52      private static final Log LOG = LogFactory.getLog(UrlHelper.class);
53  
54      /***
55       * Default HTTP port (80).
56       */
57      private static final int DEFAULT_HTTP_PORT = 80;
58  
59      /***
60       * Default HTTPS port (443).
61       */
62      private static final int DEFAULT_HTTPS_PORT = 443;
63  
64      private static final String AMP = "&";
65  
66      private static int httpPort = DEFAULT_HTTP_PORT;
67      private static int httpsPort = DEFAULT_HTTPS_PORT;
68      private static String customEncoding;
69  
70  
71      @Inject(StrutsConstants.STRUTS_URL_HTTP_PORT)
72      public static void setHttpPort(String val) {
73          httpPort = Integer.parseInt(val);
74      }
75  
76      @Inject(StrutsConstants.STRUTS_URL_HTTPS_PORT)
77      public static void setHttpsPort(String val) {
78          httpsPort = Integer.parseInt(val);
79      }
80  
81      @Inject(StrutsConstants.STRUTS_I18N_ENCODING)
82      public static void setCustomEncoding(String val) {
83          customEncoding = val;
84      }
85  
86      public static String buildUrl(String action, HttpServletRequest request, HttpServletResponse response, Map params) {
87          return buildUrl(action, request, response, params, null, true, true);
88      }
89  
90      public static String buildUrl(String action, HttpServletRequest request, HttpServletResponse response, Map params, String scheme, boolean includeContext, boolean encodeResult) {
91          return buildUrl(action, request, response, params, scheme, includeContext, encodeResult, false);
92      }
93  
94      public static String buildUrl(String action, HttpServletRequest request, HttpServletResponse response, Map params, String scheme, boolean includeContext, boolean encodeResult, boolean forceAddSchemeHostAndPort) {
95          return buildUrl(action, request, response, params, scheme, includeContext, encodeResult, forceAddSchemeHostAndPort, true);
96      }
97  
98      public static String buildUrl(String action, HttpServletRequest request, HttpServletResponse response, Map params, String scheme, boolean includeContext, boolean encodeResult, boolean forceAddSchemeHostAndPort, boolean escapeAmp) {
99          StringBuffer link = new StringBuffer();
100 
101         boolean changedScheme = false;
102 
103         // only append scheme if it is different to the current scheme *OR*
104         // if we explicity want it to be appended by having forceAddSchemeHostAndPort = true
105         if (forceAddSchemeHostAndPort) {
106             String reqScheme = request.getScheme();
107             changedScheme = true;
108             link.append(scheme != null ? scheme : reqScheme);
109             link.append("://");
110             link.append(request.getServerName());
111 
112             if (scheme != null) {
113                 // If switching schemes, use the configured port for the particular scheme.
114                 if (!scheme.equals(reqScheme)) {
115                     if ((scheme.equals("http") && (httpPort != DEFAULT_HTTP_PORT)) || (scheme.equals("https") && httpsPort != DEFAULT_HTTPS_PORT)) {
116                         link.append(":");
117                         link.append(scheme.equals("http") ? httpPort : httpsPort);
118                     }
119 		// Else use the port from the current request.
120                 } else {
121                     int reqPort = request.getServerPort();
122 
123                     if ((scheme.equals("http") && (reqPort != DEFAULT_HTTP_PORT)) || (scheme.equals("https") && reqPort != DEFAULT_HTTPS_PORT)) {
124                         link.append(":");
125                         link.append(reqPort);
126                     }
127                 }
128             }
129         }
130         else if ((scheme != null) && !scheme.equals(request.getScheme())) {
131             changedScheme = true;
132             link.append(scheme);
133             link.append("://");
134             link.append(request.getServerName());
135 
136             if ((scheme.equals("http") && (httpPort != DEFAULT_HTTP_PORT)) || (scheme.equals("https") && httpsPort != DEFAULT_HTTPS_PORT)) {
137                 link.append(":");
138                 link.append(scheme.equals("http") ? httpPort : httpsPort);
139             }
140         }
141 
142         if (action != null) {
143             // Check if context path needs to be added
144             // Add path to absolute links
145             if (action.startsWith("/") && includeContext) {
146                 String contextPath = request.getContextPath();
147                 if (!contextPath.equals("/")) {
148                     link.append(contextPath);
149                 }
150             } else if (changedScheme) {
151 
152                 // (Applicable to Servlet 2.4 containers)
153                 // If the request was forwarded, the attribute below will be set with the original URL
154                 String uri = (String) request.getAttribute("javax.servlet.forward.request_uri");
155 
156                 // If the attribute wasn't found, default to the value in the request object
157                 if (uri == null) {
158                     uri = request.getRequestURI();
159                 }
160 
161                 link.append(uri.substring(0, uri.lastIndexOf('/') + 1));
162             }
163 
164             // Add page
165             link.append(action);
166         } else {
167             // Go to "same page"
168             String requestURI = (String) request.getAttribute("struts.request_uri");
169 
170             // (Applicable to Servlet 2.4 containers)
171             // If the request was forwarded, the attribute below will be set with the original URL
172             if (requestURI == null) {
173                 requestURI = (String) request.getAttribute("javax.servlet.forward.request_uri");
174             }
175 
176             // If neither request attributes were found, default to the value in the request object
177             if (requestURI == null) {
178                 requestURI = request.getRequestURI();
179             }
180 
181             link.append(requestURI);
182         }
183 
184         //if the action was not explicitly set grab the params from the request
185         if (escapeAmp) {
186             buildParametersString(params, link);
187         } else {
188             buildParametersString(params, link, "&");
189         }
190 
191         String result = link.toString();
192 
193         while (result.indexOf("<script>") > 0) {
194             result = result.replaceAll("<script>", "script");
195         }
196 
197         try {
198              result = encodeResult ? response.encodeURL(result) : result;
199         } catch (Exception ex) {
200             // Could not encode the URL for some reason
201             // Use it unchanged
202             result = link.toString();
203         }
204 
205         return result;
206     }
207 
208     public static void buildParametersString(Map params, StringBuffer link) {
209         buildParametersString(params, link, AMP);
210     }
211 
212     public static void buildParametersString(Map params, StringBuffer link, String paramSeparator) {
213         if ((params != null) && (params.size() > 0)) {
214             if (link.toString().indexOf("?") == -1) {
215                 link.append("?");
216             } else {
217                 link.append(paramSeparator);
218             }
219 
220             // Set params
221             Iterator iter = params.entrySet().iterator();
222 
223             String[] valueHolder = new String[1];
224 
225             while (iter.hasNext()) {
226                 Map.Entry entry = (Map.Entry) iter.next();
227                 String name = (String) entry.getKey();
228                 Object value = entry.getValue();
229 
230                 String[] values;
231 
232                 if (value instanceof String[]) {
233                     values = (String[]) value;
234                 } else {
235                     valueHolder[0] = value.toString();
236                     values = valueHolder;
237                 }
238 
239                 for (int i = 0; i < values.length; i++) {
240                     if (values[i] != null) {
241                         link.append(name);
242                         link.append('=');
243                         link.append(translateAndEncode(values[i]));
244                     }
245 
246                     if (i < (values.length - 1)) {
247                         link.append(paramSeparator);
248                     }
249                 }
250 
251                 if (iter.hasNext()) {
252                     link.append(paramSeparator);
253                 }
254             }
255         }
256     }
257 
258     /***
259      * Translates any script expressions using {@link com.opensymphony.xwork2.util.TextParseUtil#translateVariables} and
260      * encodes the URL using {@link java.net.URLEncoder#encode} with the encoding specified in the configuration.
261      *
262      * @param input
263      * @return the translated and encoded string
264      */
265     public static String translateAndEncode(String input) {
266         String translatedInput = translateVariable(input);
267         String encoding = getEncodingFromConfiguration();
268 
269         try {
270             return URLEncoder.encode(translatedInput, encoding);
271         } catch (UnsupportedEncodingException e) {
272             LOG.warn("Could not encode URL parameter '" + input + "', returning value un-encoded");
273             return translatedInput;
274         }
275     }
276 
277     public static String translateAndDecode(String input) {
278         String translatedInput = translateVariable(input);
279         String encoding = getEncodingFromConfiguration();
280 
281         try {
282             return URLDecoder.decode(translatedInput, encoding);
283         } catch (UnsupportedEncodingException e) {
284             LOG.warn("Could not encode URL parameter '" + input + "', returning value un-encoded");
285             return translatedInput;
286         }
287     }
288 
289     private static String translateVariable(String input) {
290         ValueStack valueStack = ServletActionContext.getContext().getValueStack();
291         String output = TextParseUtil.translateVariables(input, valueStack);
292         return output;
293     }
294 
295     private static String getEncodingFromConfiguration() {
296         final String encoding;
297         if (customEncoding != null) {
298             encoding = customEncoding;
299         } else {
300             encoding = "UTF-8";
301         }
302         return encoding;
303     }
304 
305     public static Map parseQueryString(String queryString) {
306         Map queryParams = new LinkedHashMap();
307         if (queryString != null) {
308             String[] params = queryString.split("&");
309             for (int a=0; a< params.length; a++) {
310                 if (params[a].trim().length() > 0) {
311                     String[] tmpParams = params[a].split("=");
312                     String paramName = null;
313                     String paramValue = "";
314                     if (tmpParams.length > 0) {
315                         paramName = tmpParams[0];
316                     }
317                     if (tmpParams.length > 1) {
318                         paramValue = tmpParams[1];
319                     }
320                     if (paramName != null) {
321                         String translatedParamValue = translateAndDecode(paramValue);
322 
323                         if(queryParams.containsKey(paramName)) {
324                             // WW-1619 append new param value to existing value(s)
325                             Object currentParam = queryParams.get(paramName);
326                             if(currentParam instanceof String) {
327                                 queryParams.put(paramName, new String[] {
328                                         (String) currentParam, translatedParamValue});
329                             } else {
330                                 String currentParamValues[] = (String[]) currentParam;
331                                 List paramList = new ArrayList(Arrays
332                                     .asList(currentParamValues));
333                                 paramList.add(translatedParamValue);
334                                 String newParamValues[] = new String[paramList
335                                     .size()];
336                                 queryParams.put(paramName, paramList
337                                     .toArray(newParamValues));
338                             }
339                         } else {
340                             queryParams.put(paramName, translatedParamValue);
341                         }
342                     }
343                 }
344             }
345         }
346         return queryParams;
347     }
348 }