001/* 002 * This library is part of OpenCms - 003 * the Open Source Content Management System 004 * 005 * Copyright (c) Alkacon Software GmbH & Co. KG (http://www.alkacon.com) 006 * 007 * This library is free software; you can redistribute it and/or 008 * modify it under the terms of the GNU Lesser General Public 009 * License as published by the Free Software Foundation; either 010 * version 2.1 of the License, or (at your option) any later version. 011 * 012 * This library is distributed in the hope that it will be useful, 013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 015 * Lesser General Public License for more details. 016 * 017 * For further information about Alkacon Software GmbH & Co. KG, please see the 018 * company website: http://www.alkacon.com 019 * 020 * For further information about OpenCms, please see the 021 * project website: http://www.opencms.org 022 * 023 * You should have received a copy of the GNU Lesser General Public 024 * License along with this library; if not, write to the Free Software 025 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 026 */ 027 028package org.opencms.util; 029 030import org.opencms.flex.CmsFlexRequest; 031import org.opencms.flex.CmsFlexResponse; 032import org.opencms.i18n.CmsEncoder; 033import org.opencms.json.JSONArray; 034import org.opencms.json.JSONException; 035import org.opencms.json.JSONObject; 036import org.opencms.jsp.CmsJspActionElement; 037import org.opencms.main.CmsLog; 038import org.opencms.main.OpenCms; 039 040import java.io.File; 041import java.io.IOException; 042import java.io.UnsupportedEncodingException; 043import java.net.URI; 044import java.net.URLDecoder; 045import java.util.ArrayList; 046import java.util.Enumeration; 047import java.util.HashMap; 048import java.util.Iterator; 049import java.util.List; 050import java.util.Map; 051import java.util.Map.Entry; 052 053import javax.servlet.ServletException; 054import javax.servlet.ServletRequest; 055import javax.servlet.http.Cookie; 056import javax.servlet.http.HttpServletRequest; 057import javax.servlet.http.HttpServletResponse; 058import javax.servlet.http.HttpSession; 059 060import org.apache.commons.fileupload.FileItem; 061import org.apache.commons.fileupload.FileUploadException; 062import org.apache.commons.fileupload.disk.DiskFileItemFactory; 063import org.apache.commons.fileupload.servlet.ServletFileUpload; 064import org.apache.commons.logging.Log; 065 066import com.google.common.collect.ArrayListMultimap; 067import com.google.common.collect.Multimap; 068 069/** 070 * Provides utility functions for dealing with values a <code>{@link HttpServletRequest}</code>.<p> 071 * 072 * @since 6.0.0 073 */ 074public final class CmsRequestUtil { 075 076 /** Request attribute that contains the original error code. */ 077 public static final String ATTRIBUTE_ERRORCODE = "org.opencms.util.CmsErrorCode"; 078 079 /** HTTP Accept Header for the cms:device-tag. */ 080 public static final String HEADER_ACCEPT = "Accept"; 081 082 /** HTTP Accept-Charset Header for internal requests used during static export. */ 083 public static final String HEADER_ACCEPT_CHARSET = "Accept-Charset"; 084 085 /** HTTP Accept-Language Header for internal requests used during static export. */ 086 public static final String HEADER_ACCEPT_LANGUAGE = "Accept-Language"; 087 088 /** HTTP Header "Cache-Control". */ 089 public static final String HEADER_CACHE_CONTROL = "Cache-Control"; 090 091 /** HTTP Header "Connection". */ 092 public static final String HEADER_CONNECTION = "Connection"; 093 094 /** The "Content-Disposition" http header. */ 095 public static final String HEADER_CONTENT_DISPOSITION = "Content-Disposition"; 096 097 /** The "Content-Type" http header. */ 098 public static final String HEADER_CONTENT_TYPE = "Content-Type"; 099 100 /** HTTP Header "Expires". */ 101 public static final String HEADER_EXPIRES = "Expires"; 102 103 /** HTTP Header "If-Modified-Since". */ 104 public static final String HEADER_IF_MODIFIED_SINCE = "If-Modified-Since"; 105 106 /** The Header that stores the session id (used by OpenCms upload applet). */ 107 public static final String HEADER_JSESSIONID = "JSESSIONID"; 108 109 /** HTTP Header "Last-Modified". */ 110 public static final String HEADER_LAST_MODIFIED = "Last-Modified"; 111 112 /** HTTP Header "Location". */ 113 public static final String HEADER_LOCATION = "Location"; 114 115 /** HTTP Header for internal requests used during static export. */ 116 public static final String HEADER_OPENCMS_EXPORT = "OpenCms-Export"; 117 118 /** HTTP Header "Pragma". */ 119 public static final String HEADER_PRAGMA = "Pragma"; 120 121 /** HTTP Header "Server". */ 122 public static final String HEADER_SERVER = "Server"; 123 124 /** HTTP Header "user-agent". */ 125 public static final String HEADER_USER_AGENT = "user-agent"; 126 127 /** HTTP Header value "max-age=" (for "Cache-Control"). */ 128 public static final String HEADER_VALUE_MAX_AGE = "max-age="; 129 130 /** HTTP Header value "must-revalidate" (for "Cache-Control"). */ 131 public static final String HEADER_VALUE_MUST_REVALIDATE = "must-revalidate"; 132 133 /** HTTP Header value "no-cache" (for "Cache-Control"). */ 134 public static final String HEADER_VALUE_NO_CACHE = "no-cache"; 135 136 /** HTTP Header value "no-store" (for "Cache-Control"). */ 137 public static final String HEADER_VALUE_NO_STORE = "no-store"; 138 139 /** HTTP Header "WWW-Authenticate". */ 140 public static final String HEADER_WWW_AUTHENTICATE = "WWW-Authenticate"; 141 142 /** Identifier for x-forwarded-for (i.e. proxied) request headers. */ 143 public static final String HEADER_X_FORWARDED_FOR = "x-forwarded-for"; 144 145 /** Assignment char between parameter name and values. */ 146 public static final String PARAMETER_ASSIGNMENT = "="; 147 148 /** Delimiter char between parameters. */ 149 public static final String PARAMETER_DELIMITER = "&"; 150 151 /** Delimiter char between url and query. */ 152 public static final String URL_DELIMITER = "?"; 153 154 /** The prefix for &. */ 155 private static final String AMP = "amp;"; 156 157 /** The log object for this class. */ 158 private static final Log LOG = CmsLog.getLog(CmsRequestUtil.class); 159 160 /** 161 * Default constructor (empty), private because this class has only 162 * static methods.<p> 163 */ 164 private CmsRequestUtil() { 165 166 // empty 167 } 168 169 /** 170 * Appends a request parameter to the given URL.<p> 171 * 172 * This method takes care about the adding the parameter as an additional 173 * parameter (appending <code>¶m=value</code>) or as the first parameter 174 * (appending <code>?param=value</code>).<p> 175 * 176 * @param url the URL where to append the parameter to 177 * @param paramName the paramter name to append 178 * @param paramValue the parameter value to append 179 * 180 * @return the URL with the given parameter appended 181 */ 182 public static String appendParameter(String url, String paramName, String paramValue) { 183 184 if (CmsStringUtil.isEmpty(url)) { 185 return null; 186 } 187 int pos = url.indexOf(URL_DELIMITER); 188 StringBuffer result = new StringBuffer(256); 189 result.append(url); 190 if (pos >= 0) { 191 // url already has parameters 192 result.append(PARAMETER_DELIMITER); 193 } else { 194 // url does not have parameters 195 result.append(URL_DELIMITER); 196 } 197 result.append(paramName); 198 result.append(PARAMETER_ASSIGNMENT); 199 result.append(paramValue); 200 return result.toString(); 201 } 202 203 /** 204 * Appends a map of request parameters to the given URL.<p> 205 * 206 * The map can contains values of <code>String[]</code> or 207 * simple <code>String</code> values.<p> 208 * 209 * This method takes care about the adding the parameter as an additional 210 * parameter (appending <code>¶m=value</code>) or as the first parameter 211 * (appending <code>?param=value</code>).<p> 212 * 213 * @param url the URL where to append the parameter to 214 * @param params the parameters to append 215 * @param encode if <code>true</code>, the parameter values are encoded before they are appended 216 * 217 * @return the URL with the given parameter appended 218 */ 219 public static String appendParameters(String url, Map<String, String[]> params, boolean encode) { 220 221 if (CmsStringUtil.isEmpty(url)) { 222 return null; 223 } 224 if ((params == null) || params.isEmpty()) { 225 return url; 226 } 227 int pos = url.indexOf(URL_DELIMITER); 228 StringBuffer result = new StringBuffer(256); 229 result.append(url); 230 if (pos >= 0) { 231 // url already has parameters 232 result.append(PARAMETER_DELIMITER); 233 } else { 234 // url does not have parameters 235 result.append(URL_DELIMITER); 236 } 237 // ensure all values are of type String[] 238 Iterator<Map.Entry<String, String[]>> i = params.entrySet().iterator(); 239 while (i.hasNext()) { 240 Map.Entry<String, String[]> entry = i.next(); 241 String key = entry.getKey(); 242 Object value = entry.getValue(); 243 // generics where added later, so make sure that the value really is a String[] 244 String[] values = value instanceof String[] ? (String[])value : new String[] {value.toString()}; 245 for (int j = 0; j < values.length; j++) { 246 String strValue = values[j]; 247 if (encode) { 248 strValue = CmsEncoder.encode(strValue); 249 } 250 result.append(key); 251 result.append(PARAMETER_ASSIGNMENT); 252 result.append(strValue); 253 if ((j + 1) < values.length) { 254 result.append(PARAMETER_DELIMITER); 255 } 256 } 257 if (i.hasNext()) { 258 result.append(PARAMETER_DELIMITER); 259 } 260 } 261 return result.toString(); 262 } 263 264 /** 265 * Creates a valid request parameter map from the given map, 266 * most notably changing the values form <code>String</code> 267 * to <code>String[]</code> if required.<p> 268 * 269 * If the given parameter map is <code>null</code>, then <code>null</code> is returned.<p> 270 * 271 * @param params the map of parameters to create a parameter map from 272 * @return the created parameter map, all values will be instances of <code>String[]</code> 273 */ 274 public static Map<String, String[]> createParameterMap(Map<String, ?> params) { 275 276 if (params == null) { 277 return null; 278 } 279 Map<String, String[]> result = new HashMap<String, String[]>(); 280 Iterator<?> i = params.entrySet().iterator(); 281 while (i.hasNext()) { 282 @SuppressWarnings("unchecked") 283 Map.Entry<String, ?> entry = (Entry<String, ?>)i.next(); 284 String key = entry.getKey(); 285 Object values = entry.getValue(); 286 if (values instanceof String[]) { 287 result.put(key, (String[])values); 288 } else { 289 if (values != null) { 290 result.put(key, new String[] {values.toString()}); 291 } 292 } 293 } 294 return result; 295 } 296 297 /** 298 * Parses the parameters of the given request query part and creates a parameter map out of them.<p> 299 * 300 * Please note: This does not parse a full request URI/URL, only the query part that 301 * starts after the "?". For example, in the URI <code>/system/index.html?a=b&c=d</code>, 302 * the query part is <code>a=b&c=d</code>.<p> 303 * 304 * If the given String is empty, an empty map is returned.<p> 305 * 306 * @param query the query to parse 307 * @return the parameter map created from the query 308 */ 309 public static Map<String, String[]> createParameterMap(String query) { 310 311 return createParameterMap(query, false, null); 312 } 313 314 /** 315 * Parses the parameters of the given request query part, optionally decodes them, and creates a parameter map out of them.<p> 316 * 317 * Please note: This does not parse a full request URI/URL, only the query part that 318 * starts after the "?". For example, in the URI <code>/system/index.html?a=b&c=d</code>, 319 * the query part is <code>a=b&c=d</code>.<p> 320 * 321 * If the given String is empty, an empty map is returned.<p> 322 * 323 * @param query the query to parse 324 * @param decodeParameters a flag, indicating if the parameters should be decoded. 325 * @param encoding the character encoding used while decoding. If <code>null</code>, the default character encoding is used. 326 * @return the parameter map created from the query 327 */ 328 public static Map<String, String[]> createParameterMap(String query, boolean decodeParameters, String encoding) { 329 330 if (CmsStringUtil.isEmpty(query)) { 331 // empty query 332 return new HashMap<String, String[]>(); 333 } 334 if (query.charAt(0) == URL_DELIMITER.charAt(0)) { 335 // remove leading '?' if required 336 query = query.substring(1); 337 } 338 // cut along the different parameters 339 String[] params = CmsStringUtil.splitAsArray(query, PARAMETER_DELIMITER); 340 Map<String, String[]> parameters = new HashMap<String, String[]>(params.length); 341 for (int i = 0; i < params.length; i++) { 342 String key = null; 343 String value = null; 344 // get key and value, separated by a '=' 345 int pos = params[i].indexOf(PARAMETER_ASSIGNMENT); 346 if (pos > 0) { 347 key = params[i].substring(0, pos); 348 value = params[i].substring(pos + 1); 349 } else if (pos < 0) { 350 key = params[i]; 351 value = ""; 352 } 353 // adjust the key if it starts with "amp;" 354 // this happens when "&" is used instead of a simple "&" 355 if ((key != null) && (key.startsWith(AMP))) { 356 key = key.substring(AMP.length()); 357 } 358 // now make sure the values are of type String[] 359 if (key != null) { 360 if (decodeParameters) { 361 key = CmsEncoder.decode(key, encoding); 362 value = CmsEncoder.decode(value, encoding); 363 } 364 String[] values = parameters.get(key); 365 if (values == null) { 366 // this is the first value, create new array 367 values = new String[] {value}; 368 } else { 369 // append to the existing value array 370 String[] copy = new String[values.length + 1]; 371 System.arraycopy(values, 0, copy, 0, values.length); 372 copy[copy.length - 1] = value; 373 values = copy; 374 } 375 parameters.put(key, values); 376 } 377 } 378 return parameters; 379 } 380 381 /** 382 * Returns all parameters of the given request 383 * as a request parameter URL String, that is in the form <code>key1=value1&key2=value2</code> etc. 384 * 385 * The result will be encoded using the <code>{@link CmsEncoder#encode(String)}</code> function.<p> 386 * 387 * @param req the request to read the parameters from 388 * 389 * @return all initialized parameters of the given request as request parameter URL String 390 */ 391 public static String encodeParams(HttpServletRequest req) { 392 393 StringBuffer result = new StringBuffer(512); 394 Map<String, String[]> params = CmsCollectionsGenericWrapper.map(req.getParameterMap()); 395 Iterator<Map.Entry<String, String[]>> i = params.entrySet().iterator(); 396 while (i.hasNext()) { 397 Map.Entry<String, String[]> entry = i.next(); 398 String param = entry.getKey(); 399 String[] values = entry.getValue(); 400 for (int j = 0; j < values.length; j++) { 401 result.append(param); 402 result.append("="); 403 result.append(CmsEncoder.encode(values[j])); 404 if ((j + 1) < values.length) { 405 result.append("&"); 406 } 407 } 408 if (i.hasNext()) { 409 result.append("&"); 410 } 411 } 412 return CmsEncoder.encode(result.toString()); 413 } 414 415 /** 416 * Encodes the given URI, with all parameters from the given request appended.<p> 417 * 418 * The result will be encoded using the <code>{@link CmsEncoder#encode(String)}</code> function.<p> 419 * 420 * @param req the request where to read the parameters from 421 * @param uri the URI to encode 422 * @return the encoded URI, with all parameters from the given request appended 423 */ 424 public static String encodeParamsWithUri(String uri, HttpServletRequest req) { 425 426 String result; 427 String params = encodeParams(req); 428 if (CmsStringUtil.isNotEmpty(params)) { 429 result = CmsEncoder.encode(uri + "?") + params; 430 } else { 431 result = CmsEncoder.encode(uri); 432 } 433 return result; 434 } 435 436 /** 437 * Forwards the response to the given target, which may contain parameters appended like for example <code>?a=b&c=d</code>.<p> 438 * 439 * Please note: If possible, use <code>{@link #forwardRequest(String, Map, HttpServletRequest, HttpServletResponse)}</code> 440 * where the parameters are passed as a map, since the parsing of the parameters may introduce issues with encoding 441 * and is in general much less effective.<p> 442 * 443 * The parsing of parameters will likely fail for "large values" (e.g. full blown web forms with <textarea> 444 * elements etc. Use this method only if you know that the target will just contain up to 3 parameters which 445 * are relatively short and have no encoding or line break issues.<p> 446 * 447 * @param target the target to forward to (may contain parameters like <code>?a=b&c=d</code>) 448 * @param req the request to forward 449 * @param res the response to forward 450 * 451 * @throws IOException in case the forwarding fails 452 * @throws ServletException in case the forwarding fails 453 */ 454 public static void forwardRequest(String target, HttpServletRequest req, HttpServletResponse res) 455 throws IOException, ServletException { 456 457 // clear the current parameters 458 CmsUriSplitter uri = new CmsUriSplitter(target); 459 Map<String, String[]> params = createParameterMap(uri.getQuery()); 460 forwardRequest(uri.getPrefix(), params, req, res); 461 } 462 463 /** 464 * Forwards the response to the given target, with the provided parameter map.<p> 465 * 466 * The target URI must NOT have parameters appended like for example <code>?a=b&c=d</code>. 467 * The values in the provided map must be of type <code>String[]</code>. If required, use 468 * <code>{@link #createParameterMap(Map)}</code> before calling this method to make sure 469 * all values are actually of the required array type.<p> 470 * 471 * @param target the target to forward to (may NOT contain parameters like <code>?a=b&c=d</code>) 472 * @param params the parameter map (the values must be of type <code>String[]</code> 473 * @param req the request to forward 474 * @param res the response to forward 475 * 476 * @throws IOException in case the forwarding fails 477 * @throws ServletException in case the forwarding fails 478 */ 479 public static void forwardRequest( 480 String target, 481 Map<String, String[]> params, 482 HttpServletRequest req, 483 HttpServletResponse res) 484 throws IOException, ServletException { 485 486 // cast the request back to a flex request so the parameter map can be accessed 487 CmsFlexRequest f_req = (CmsFlexRequest)req; 488 // set the parameters 489 f_req.setParameterMap(params); 490 // check for links "into" OpenCms, these may need the webapp name to be removed 491 String vfsPrefix = OpenCms.getStaticExportManager().getVfsPrefix(); 492 if (target.startsWith(vfsPrefix)) { 493 // remove VFS prefix (will also work for empty vfs prefix in ROOT webapp case with proxy rules) 494 target = target.substring(vfsPrefix.length()); 495 // append the servlet name 496 target = OpenCms.getSystemInfo().getServletPath() + target; 497 } 498 // forward the request 499 f_req.getRequestDispatcher(target).forward(f_req, res); 500 } 501 502 /** 503 * Exactly like getAttributeMap, but incorrectly spelled.<p> 504 * 505 * Kept for backward compatibility. 506 * 507 * @param req the request 508 * 509 * @return the attribute map 510 */ 511 public static Map<String, Object> getAtrributeMap(ServletRequest req) { 512 513 return getAttributeMap(req); 514 } 515 516 /** 517 * Returns a map with all request attributes.<p> 518 * 519 * @param req the request 520 * 521 * @return the attribute map 522 */ 523 public static Map<String, Object> getAttributeMap(ServletRequest req) { 524 525 if (req instanceof CmsFlexRequest) { 526 return ((CmsFlexRequest)req).getAttributeMap(); 527 } 528 Map<String, Object> attrs = new HashMap<String, Object>(); 529 Enumeration<String> atrrEnum = CmsCollectionsGenericWrapper.enumeration(req.getAttributeNames()); 530 while (atrrEnum.hasMoreElements()) { 531 String key = atrrEnum.nextElement(); 532 Object value = req.getAttribute(key); 533 attrs.put(key, value); 534 } 535 return attrs; 536 } 537 538 /** 539 * Returns the value of the cookie with the given name.<p/> 540 * 541 * @param jsp the CmsJspActionElement to use 542 * @param name the name of the cookie 543 * 544 * @return the value of the cookie with the given name or null, if no cookie exists with the name 545 */ 546 public static String getCookieValue(CmsJspActionElement jsp, String name) { 547 548 Cookie[] cookies = jsp.getRequest().getCookies(); 549 return getCookieValue(cookies, name); 550 } 551 552 /** 553 * Gets the value of a specific cookie from an array of cookies.<p> 554 * 555 * @param cookies the cookie array 556 * @param name the name of the cookie we want 557 * 558 * @return the cookie value, or null if cookie with the given name wasn't found 559 */ 560 public static String getCookieValue(Cookie[] cookies, String name) { 561 562 for (int i = 0; (cookies != null) && (i < cookies.length); i++) { 563 if (name.equalsIgnoreCase(cookies[i].getName())) { 564 return cookies[i].getValue(); 565 } 566 } 567 return null; 568 } 569 570 /** 571 * Converts the given parameter map into an JSON object.<p> 572 * 573 * @param params the parameters map to convert 574 * 575 * @return the JSON representation of the given parameter map 576 */ 577 public static JSONObject getJsonParameterMap(Map<String, String[]> params) { 578 579 JSONObject result = new JSONObject(); 580 for (Map.Entry<String, String[]> entry : params.entrySet()) { 581 String paramKey = entry.getKey(); 582 JSONArray paramValue = new JSONArray(); 583 for (int i = 0, l = entry.getValue().length; i < l; i++) { 584 paramValue.put(entry.getValue()[i]); 585 } 586 try { 587 result.putOpt(paramKey, paramValue); 588 } catch (JSONException e) { 589 // should never happen 590 LOG.warn(e.getLocalizedMessage(), e); 591 } 592 } 593 return result; 594 } 595 596 /** 597 * Reads value from the request parameters, 598 * will return <code>null</code> if the value is not available or only white space.<p> 599 * 600 * The value of the request will also be decoded using <code>{@link CmsEncoder#decode(String)}</code> 601 * and also trimmed using <code>{@link String#trim()}</code>.<p> 602 * 603 * @param request the request to read the parameter from 604 * @param paramName the parameter name to read 605 * 606 * @return the request parameter value for the given parameter 607 */ 608 public static String getNotEmptyDecodedParameter(HttpServletRequest request, String paramName) { 609 610 String result = getNotEmptyParameter(request, paramName); 611 if (result != null) { 612 result = CmsEncoder.decode(result.trim()); 613 } 614 return result; 615 } 616 617 /** 618 * Reads value from the request parameters, 619 * will return <code>null</code> if the value is not available or only white space.<p> 620 * 621 * @param request the request to read the parameter from 622 * @param paramName the parameter name to read 623 * 624 * @return the request parameter value for the given parameter 625 */ 626 public static String getNotEmptyParameter(HttpServletRequest request, String paramName) { 627 628 String result = request.getParameter(paramName); 629 if (CmsStringUtil.isEmptyOrWhitespaceOnly(result)) { 630 result = null; 631 } 632 return result; 633 } 634 635 /** 636 * Converts the given JSON object into a valid parameter map.<p> 637 * 638 * @param params the JSON object to convert 639 * 640 * @return the parameter map from the given JSON object 641 */ 642 public static Map<String, String[]> getParameterMapFromJSON(JSONObject params) { 643 644 Map<String, String[]> result = new HashMap<String, String[]>(); 645 Iterator<String> itKeys = params.keys(); 646 while (itKeys.hasNext()) { 647 String key = itKeys.next(); 648 JSONArray paramValue = params.optJSONArray(key); 649 result.put(key, new String[paramValue.length()]); 650 for (int i = 0, l = paramValue.length(); i < l; i++) { 651 result.get(key)[i] = paramValue.optString(i); 652 } 653 } 654 return result; 655 } 656 657 /** 658 * Parses parameter map from the given URI.<p> 659 * 660 * @param uri the URI 661 * @return the parameter map 662 */ 663 public static Multimap<String, String> getParameters(URI uri) { 664 665 return getParametersFromRawQuery(uri.getRawQuery()); 666 } 667 668 /** 669 * Parses the parameter map from a raw query string.<p> 670 * 671 * @param rawQuery the raw query string 672 * 673 * @return the parameter map 674 */ 675 public static Multimap<String, String> getParametersFromRawQuery(String rawQuery) { 676 677 Multimap<String, String> result = ArrayListMultimap.create(); 678 if (rawQuery != null) { 679 for (String keyValuePair : CmsStringUtil.splitAsList(rawQuery, "&")) { 680 try { 681 String decodedKeyValue = URLDecoder.decode(keyValuePair, "UTF-8"); 682 int eqPos = decodedKeyValue.indexOf("="); 683 if (eqPos < 0) { 684 decodedKeyValue = decodedKeyValue + "="; 685 eqPos = decodedKeyValue.indexOf("="); 686 } 687 String key = decodedKeyValue.substring(0, eqPos); 688 String value = decodedKeyValue.substring(eqPos + 1); 689 result.put(key, value); 690 } catch (UnsupportedEncodingException e) { 691 // UTF8 should be present 692 } 693 } 694 } 695 return result; 696 } 697 698 /** 699 * Returns the link without parameters from a String that is formatted for a GET request.<p> 700 * 701 * @param url the URL to remove the parameters from 702 * @return the URL without any parameters 703 */ 704 public static String getRequestLink(String url) { 705 706 if (CmsStringUtil.isEmpty(url)) { 707 return null; 708 } 709 int pos = url.indexOf(URL_DELIMITER); 710 if (pos >= 0) { 711 return url.substring(0, pos); 712 } 713 return url; 714 715 } 716 717 /** 718 * Reads an object from the session of the given HTTP request.<p> 719 * 720 * A session will be initialized if the request does not currently have a session. 721 * As a result, the request will always have a session after this method has been called.<p> 722 * 723 * Will return <code>null</code> if no corresponding object is found in the session.<p> 724 * 725 * @param request the request to get the session from 726 * @param key the key of the object to read from the session 727 * @return the object received form the session, or <code>null</code> 728 */ 729 public static Object getSessionValue(HttpServletRequest request, String key) { 730 731 HttpSession session = request.getSession(true); 732 return session.getAttribute(key); 733 } 734 735 /** 736 * Parses a request of the form <code>multipart/form-data</code>. 737 * 738 * The result list will contain items of type <code>{@link FileItem}</code>. 739 * If the request is not of type <code>multipart/form-data</code>, then <code>null</code> is returned.<p> 740 * 741 * @param request the HTTP servlet request to parse 742 * 743 * @return the list of <code>{@link FileItem}</code> extracted from the multipart request, 744 * or <code>null</code> if the request was not of type <code>multipart/form-data</code> 745 */ 746 public static List<FileItem> readMultipartFileItems(HttpServletRequest request) { 747 748 return readMultipartFileItems(request, OpenCms.getSystemInfo().getPackagesRfsPath()); 749 } 750 751 /** 752 * Parses a request of the form <code>multipart/form-data</code>. 753 * 754 * The result list will contain items of type <code>{@link FileItem}</code>. 755 * If the request is not of type <code>multipart/form-data</code>, then <code>null</code> is returned.<p> 756 * 757 * @param request the HTTP servlet request to parse 758 * @param tempFolderPath the real file system path to the temp file folder 759 * 760 * @return the list of <code>{@link FileItem}</code> extracted from the multipart request, 761 * or <code>null</code> if the request was not of type <code>multipart/form-data</code> 762 */ 763 public static List<FileItem> readMultipartFileItems(HttpServletRequest request, String tempFolderPath) { 764 765 if (!ServletFileUpload.isMultipartContent(request)) { 766 return null; 767 } 768 DiskFileItemFactory factory = new DiskFileItemFactory(); 769 // maximum size that will be stored in memory 770 factory.setSizeThreshold(4096); 771 // the location for saving data that is larger than getSizeThreshold() 772 factory.setRepository(new File(tempFolderPath)); 773 ServletFileUpload fu = new ServletFileUpload(factory); 774 // set encoding to correctly handle special chars (e.g. in filenames) 775 fu.setHeaderEncoding(request.getCharacterEncoding()); 776 List<FileItem> result = new ArrayList<FileItem>(); 777 try { 778 List<FileItem> items = CmsCollectionsGenericWrapper.list(fu.parseRequest(request)); 779 if (items != null) { 780 result = items; 781 } 782 } catch (FileUploadException e) { 783 LOG.error(Messages.get().getBundle().key(Messages.LOG_PARSE_MULIPART_REQ_FAILED_0), e); 784 } 785 return result; 786 } 787 788 /** 789 * Creates a "standard" request parameter map from the values of a 790 * <code>multipart/form-data</code> request.<p> 791 * 792 * @param encoding the encoding to use when creating the values 793 * @param multiPartFileItems the list of parsed multi part file items 794 * 795 * @return a map containing all non-file request parameters 796 * 797 * @see #readMultipartFileItems(HttpServletRequest) 798 */ 799 public static Map<String, String[]> readParameterMapFromMultiPart( 800 String encoding, 801 List<FileItem> multiPartFileItems) { 802 803 Map<String, String[]> parameterMap = new HashMap<String, String[]>(); 804 Iterator<FileItem> i = multiPartFileItems.iterator(); 805 while (i.hasNext()) { 806 FileItem item = i.next(); 807 String name = item.getFieldName(); 808 String value = null; 809 if ((name != null) && (item.getName() == null)) { 810 // only put to map if current item is no file and not null 811 try { 812 value = item.getString(encoding); 813 } catch (UnsupportedEncodingException e) { 814 LOG.error(Messages.get().getBundle().key(Messages.LOG_ENC_MULTIPART_REQ_ERROR_0), e); 815 value = item.getString(); 816 } 817 if (parameterMap.containsKey(name)) { 818 819 // append value to parameter values array 820 String[] oldValues = parameterMap.get(name); 821 String[] newValues = new String[oldValues.length + 1]; 822 System.arraycopy(oldValues, 0, newValues, 0, oldValues.length); 823 newValues[oldValues.length] = value; 824 parameterMap.put(name, newValues); 825 826 } else { 827 parameterMap.put(name, new String[] {value}); 828 } 829 } 830 } 831 return parameterMap; 832 } 833 834 /** 835 * Redirects the response to the target link using a "301 - Moved Permanently" header.<p> 836 * 837 * This implementation will work only on JSP pages in OpenCms that use the default JSP loader implementation.<p> 838 * 839 * @param jsp the OpenCms JSP context 840 * @param target the target link 841 */ 842 public static void redirectPermanently(CmsJspActionElement jsp, String target) { 843 844 target = OpenCms.getLinkManager().substituteLink(jsp.getCmsObject(), target); 845 jsp.getResponse().setHeader(HEADER_CONNECTION, "close"); 846 try { 847 HttpServletResponse response = jsp.getResponse(); 848 if (response instanceof CmsFlexResponse) { 849 ((CmsFlexResponse)jsp.getResponse()).sendRedirect(target, true); 850 } else { 851 response.setHeader("Location", target); 852 response.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY); 853 } 854 } catch (IOException e) { 855 LOG.error(Messages.get().getBundle().key(Messages.ERR_IOERROR_0), e); 856 } 857 } 858 859 /** 860 * Redirects the response to the target link.<p> 861 * 862 * Use this method instead of {@link javax.servlet.http.HttpServletResponse#sendRedirect(java.lang.String)} 863 * to avoid relative links with secure sites (and issues with apache).<p> 864 * 865 * @param jsp the OpenCms JSP context 866 * @param target the target link 867 * 868 * @throws IOException if something goes wrong during redirection 869 */ 870 public static void redirectRequestSecure(CmsJspActionElement jsp, String target) throws IOException { 871 872 jsp.getResponse().sendRedirect(OpenCms.getLinkManager().substituteLink(jsp.getCmsObject(), target, null, true)); 873 } 874 875 /** 876 * Removes an object from the session of the given http request.<p> 877 * 878 * A session will be initialized if the request does not currently have a session. 879 * As a result, the request will always have a session after this method has been called.<p> 880 * 881 * @param request the request to get the session from 882 * @param key the key of the object to be removed from the session 883 */ 884 public static void removeSessionValue(HttpServletRequest request, String key) { 885 886 HttpSession session = request.getSession(true); 887 session.removeAttribute(key); 888 } 889 890 /** 891 * Sets the value of a specific cookie.<p> 892 * If no cookie exists with the value, a new cookie will be created. 893 * 894 * @param jsp the CmsJspActionElement to use 895 * @param name the name of the cookie 896 * @param value the value of the cookie 897 */ 898 public static void setCookieValue(CmsJspActionElement jsp, String name, String value) { 899 900 Cookie[] cookies = jsp.getRequest().getCookies(); 901 for (int i = 0; (cookies != null) && (i < cookies.length); i++) { 902 if (name.equalsIgnoreCase(cookies[i].getName())) { 903 cookies[i].setValue(value); 904 return; 905 } 906 } 907 Cookie cookie = new Cookie(name, value); 908 jsp.getResponse().addCookie(cookie); 909 } 910 911 /** 912 * Sets headers to the given response to prevent client side caching.<p> 913 * 914 * The following headers are set:<p> 915 * <code> 916 * Cache-Control: max-age=0<br> 917 * Cache-Control: must-revalidate<br> 918 * Pragma: no-cache 919 * </code> 920 * 921 * @param res the request where to set the no-cache headers 922 */ 923 public static void setNoCacheHeaders(HttpServletResponse res) { 924 925 res.setHeader(CmsRequestUtil.HEADER_CACHE_CONTROL, CmsRequestUtil.HEADER_VALUE_MAX_AGE + "0"); 926 res.addHeader(CmsRequestUtil.HEADER_CACHE_CONTROL, CmsRequestUtil.HEADER_VALUE_MUST_REVALIDATE); 927 res.addHeader(CmsRequestUtil.HEADER_CACHE_CONTROL, CmsRequestUtil.HEADER_VALUE_NO_CACHE); 928 res.addHeader(CmsRequestUtil.HEADER_CACHE_CONTROL, CmsRequestUtil.HEADER_VALUE_NO_STORE); 929 res.setHeader(CmsRequestUtil.HEADER_PRAGMA, CmsRequestUtil.HEADER_VALUE_NO_CACHE); 930 } 931 932 /** 933 * Adds an object to the session of the given HTTP request.<p> 934 * 935 * A session will be initialized if the request does not currently have a session. 936 * As a result, the request will always have a session after this method has been called.<p> 937 * 938 * @param request the request to get the session from 939 * @param key the key of the object to be stored in the session 940 * @param value the object to be stored in the session 941 */ 942 public static void setSessionValue(HttpServletRequest request, String key, Object value) { 943 944 HttpSession session = request.getSession(true); 945 session.setAttribute(key, value); 946 } 947}