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 * Returns a map with all request attributes.<p> 504 * 505 * @param req the request 506 * 507 * @return the attribute map 508 */ 509 public static Map<String, Object> getAtrributeMap(ServletRequest req) { 510 511 if (req instanceof CmsFlexRequest) { 512 return ((CmsFlexRequest)req).getAttributeMap(); 513 } 514 Map<String, Object> attrs = new HashMap<String, Object>(); 515 Enumeration<String> atrrEnum = CmsCollectionsGenericWrapper.enumeration(req.getAttributeNames()); 516 while (atrrEnum.hasMoreElements()) { 517 String key = atrrEnum.nextElement(); 518 Object value = req.getAttribute(key); 519 attrs.put(key, value); 520 } 521 return attrs; 522 } 523 524 /** 525 * Returns the value of the cookie with the given name.<p/> 526 * 527 * @param jsp the CmsJspActionElement to use 528 * @param name the name of the cookie 529 * 530 * @return the value of the cookie with the given name or null, if no cookie exists with the name 531 */ 532 public static String getCookieValue(CmsJspActionElement jsp, String name) { 533 534 Cookie[] cookies = jsp.getRequest().getCookies(); 535 return getCookieValue(cookies, name); 536 } 537 538 /** 539 * Gets the value of a specific cookie from an array of cookies.<p> 540 * 541 * @param cookies the cookie array 542 * @param name the name of the cookie we want 543 * 544 * @return the cookie value, or null if cookie with the given name wasn't found 545 */ 546 public static String getCookieValue(Cookie[] cookies, String name) { 547 548 for (int i = 0; (cookies != null) && (i < cookies.length); i++) { 549 if (name.equalsIgnoreCase(cookies[i].getName())) { 550 return cookies[i].getValue(); 551 } 552 } 553 return null; 554 } 555 556 /** 557 * Converts the given parameter map into an JSON object.<p> 558 * 559 * @param params the parameters map to convert 560 * 561 * @return the JSON representation of the given parameter map 562 */ 563 public static JSONObject getJsonParameterMap(Map<String, String[]> params) { 564 565 JSONObject result = new JSONObject(); 566 for (Map.Entry<String, String[]> entry : params.entrySet()) { 567 String paramKey = entry.getKey(); 568 JSONArray paramValue = new JSONArray(); 569 for (int i = 0, l = entry.getValue().length; i < l; i++) { 570 paramValue.put(entry.getValue()[i]); 571 } 572 try { 573 result.putOpt(paramKey, paramValue); 574 } catch (JSONException e) { 575 // should never happen 576 LOG.warn(e.getLocalizedMessage(), e); 577 } 578 } 579 return result; 580 } 581 582 /** 583 * Reads value from the request parameters, 584 * will return <code>null</code> if the value is not available or only white space.<p> 585 * 586 * The value of the request will also be decoded using <code>{@link CmsEncoder#decode(String)}</code> 587 * and also trimmed using <code>{@link String#trim()}</code>.<p> 588 * 589 * @param request the request to read the parameter from 590 * @param paramName the parameter name to read 591 * 592 * @return the request parameter value for the given parameter 593 */ 594 public static String getNotEmptyDecodedParameter(HttpServletRequest request, String paramName) { 595 596 String result = getNotEmptyParameter(request, paramName); 597 if (result != null) { 598 result = CmsEncoder.decode(result.trim()); 599 } 600 return result; 601 } 602 603 /** 604 * Reads value from the request parameters, 605 * will return <code>null</code> if the value is not available or only white space.<p> 606 * 607 * @param request the request to read the parameter from 608 * @param paramName the parameter name to read 609 * 610 * @return the request parameter value for the given parameter 611 */ 612 public static String getNotEmptyParameter(HttpServletRequest request, String paramName) { 613 614 String result = request.getParameter(paramName); 615 if (CmsStringUtil.isEmptyOrWhitespaceOnly(result)) { 616 result = null; 617 } 618 return result; 619 } 620 621 /** 622 * Converts the given JSON object into a valid parameter map.<p> 623 * 624 * @param params the JSON object to convert 625 * 626 * @return the parameter map from the given JSON object 627 */ 628 public static Map<String, String[]> getParameterMapFromJSON(JSONObject params) { 629 630 Map<String, String[]> result = new HashMap<String, String[]>(); 631 Iterator<String> itKeys = params.keys(); 632 while (itKeys.hasNext()) { 633 String key = itKeys.next(); 634 JSONArray paramValue = params.optJSONArray(key); 635 result.put(key, new String[paramValue.length()]); 636 for (int i = 0, l = paramValue.length(); i < l; i++) { 637 result.get(key)[i] = paramValue.optString(i); 638 } 639 } 640 return result; 641 } 642 643 /** 644 * Parses parameter map from the given URI.<p> 645 * 646 * @param uri the URI 647 * @return the parameter map 648 */ 649 public static Multimap<String, String> getParameters(URI uri) { 650 651 return getParametersFromRawQuery(uri.getRawQuery()); 652 } 653 654 /** 655 * Parses the parameter map from a raw query string.<p> 656 * 657 * @param rawQuery the raw query string 658 * 659 * @return the parameter map 660 */ 661 public static Multimap<String, String> getParametersFromRawQuery(String rawQuery) { 662 663 Multimap<String, String> result = ArrayListMultimap.create(); 664 if (rawQuery != null) { 665 for (String keyValuePair : CmsStringUtil.splitAsList(rawQuery, "&")) { 666 try { 667 String decodedKeyValue = URLDecoder.decode(keyValuePair, "UTF-8"); 668 int eqPos = decodedKeyValue.indexOf("="); 669 if (eqPos < 0) { 670 decodedKeyValue = decodedKeyValue + "="; 671 eqPos = decodedKeyValue.indexOf("="); 672 } 673 String key = decodedKeyValue.substring(0, eqPos); 674 String value = decodedKeyValue.substring(eqPos + 1); 675 result.put(key, value); 676 } catch (UnsupportedEncodingException e) { 677 // UTF8 should be present 678 } 679 } 680 } 681 return result; 682 } 683 684 /** 685 * Returns the link without parameters from a String that is formatted for a GET request.<p> 686 * 687 * @param url the URL to remove the parameters from 688 * @return the URL without any parameters 689 */ 690 public static String getRequestLink(String url) { 691 692 if (CmsStringUtil.isEmpty(url)) { 693 return null; 694 } 695 int pos = url.indexOf(URL_DELIMITER); 696 if (pos >= 0) { 697 return url.substring(0, pos); 698 } 699 return url; 700 701 } 702 703 /** 704 * Reads an object from the session of the given HTTP request.<p> 705 * 706 * A session will be initialized if the request does not currently have a session. 707 * As a result, the request will always have a session after this method has been called.<p> 708 * 709 * Will return <code>null</code> if no corresponding object is found in the session.<p> 710 * 711 * @param request the request to get the session from 712 * @param key the key of the object to read from the session 713 * @return the object received form the session, or <code>null</code> 714 */ 715 public static Object getSessionValue(HttpServletRequest request, String key) { 716 717 HttpSession session = request.getSession(true); 718 return session.getAttribute(key); 719 } 720 721 /** 722 * Parses a request of the form <code>multipart/form-data</code>. 723 * 724 * The result list will contain items of type <code>{@link FileItem}</code>. 725 * If the request is not of type <code>multipart/form-data</code>, then <code>null</code> is returned.<p> 726 * 727 * @param request the HTTP servlet request to parse 728 * 729 * @return the list of <code>{@link FileItem}</code> extracted from the multipart request, 730 * or <code>null</code> if the request was not of type <code>multipart/form-data</code> 731 */ 732 public static List<FileItem> readMultipartFileItems(HttpServletRequest request) { 733 734 return readMultipartFileItems(request, OpenCms.getSystemInfo().getPackagesRfsPath()); 735 } 736 737 /** 738 * Parses a request of the form <code>multipart/form-data</code>. 739 * 740 * The result list will contain items of type <code>{@link FileItem}</code>. 741 * If the request is not of type <code>multipart/form-data</code>, then <code>null</code> is returned.<p> 742 * 743 * @param request the HTTP servlet request to parse 744 * @param tempFolderPath the real file system path to the temp file folder 745 * 746 * @return the list of <code>{@link FileItem}</code> extracted from the multipart request, 747 * or <code>null</code> if the request was not of type <code>multipart/form-data</code> 748 */ 749 public static List<FileItem> readMultipartFileItems(HttpServletRequest request, String tempFolderPath) { 750 751 if (!ServletFileUpload.isMultipartContent(request)) { 752 return null; 753 } 754 DiskFileItemFactory factory = new DiskFileItemFactory(); 755 // maximum size that will be stored in memory 756 factory.setSizeThreshold(4096); 757 // the location for saving data that is larger than getSizeThreshold() 758 factory.setRepository(new File(tempFolderPath)); 759 ServletFileUpload fu = new ServletFileUpload(factory); 760 // set encoding to correctly handle special chars (e.g. in filenames) 761 fu.setHeaderEncoding(request.getCharacterEncoding()); 762 List<FileItem> result = new ArrayList<FileItem>(); 763 try { 764 List<FileItem> items = CmsCollectionsGenericWrapper.list(fu.parseRequest(request)); 765 if (items != null) { 766 result = items; 767 } 768 } catch (FileUploadException e) { 769 LOG.error(Messages.get().getBundle().key(Messages.LOG_PARSE_MULIPART_REQ_FAILED_0), e); 770 } 771 return result; 772 } 773 774 /** 775 * Creates a "standard" request parameter map from the values of a 776 * <code>multipart/form-data</code> request.<p> 777 * 778 * @param encoding the encoding to use when creating the values 779 * @param multiPartFileItems the list of parsed multi part file items 780 * 781 * @return a map containing all non-file request parameters 782 * 783 * @see #readMultipartFileItems(HttpServletRequest) 784 */ 785 public static Map<String, String[]> readParameterMapFromMultiPart( 786 String encoding, 787 List<FileItem> multiPartFileItems) { 788 789 Map<String, String[]> parameterMap = new HashMap<String, String[]>(); 790 Iterator<FileItem> i = multiPartFileItems.iterator(); 791 while (i.hasNext()) { 792 FileItem item = i.next(); 793 String name = item.getFieldName(); 794 String value = null; 795 if ((name != null) && (item.getName() == null)) { 796 // only put to map if current item is no file and not null 797 try { 798 value = item.getString(encoding); 799 } catch (UnsupportedEncodingException e) { 800 LOG.error(Messages.get().getBundle().key(Messages.LOG_ENC_MULTIPART_REQ_ERROR_0), e); 801 value = item.getString(); 802 } 803 if (parameterMap.containsKey(name)) { 804 805 // append value to parameter values array 806 String[] oldValues = parameterMap.get(name); 807 String[] newValues = new String[oldValues.length + 1]; 808 System.arraycopy(oldValues, 0, newValues, 0, oldValues.length); 809 newValues[oldValues.length] = value; 810 parameterMap.put(name, newValues); 811 812 } else { 813 parameterMap.put(name, new String[] {value}); 814 } 815 } 816 } 817 return parameterMap; 818 } 819 820 /** 821 * Redirects the response to the target link using a "301 - Moved Permanently" header.<p> 822 * 823 * This implementation will work only on JSP pages in OpenCms that use the default JSP loader implementation.<p> 824 * 825 * @param jsp the OpenCms JSP context 826 * @param target the target link 827 */ 828 public static void redirectPermanently(CmsJspActionElement jsp, String target) { 829 830 target = OpenCms.getLinkManager().substituteLink(jsp.getCmsObject(), target); 831 jsp.getResponse().setHeader(HEADER_CONNECTION, "close"); 832 try { 833 HttpServletResponse response = jsp.getResponse(); 834 if (response instanceof CmsFlexResponse) { 835 ((CmsFlexResponse)jsp.getResponse()).sendRedirect(target, true); 836 } else { 837 response.setHeader("Location", target); 838 response.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY); 839 } 840 } catch (IOException e) { 841 LOG.error(Messages.get().getBundle().key(Messages.ERR_IOERROR_0), e); 842 } 843 } 844 845 /** 846 * Redirects the response to the target link.<p> 847 * 848 * Use this method instead of {@link javax.servlet.http.HttpServletResponse#sendRedirect(java.lang.String)} 849 * to avoid relative links with secure sites (and issues with apache).<p> 850 * 851 * @param jsp the OpenCms JSP context 852 * @param target the target link 853 * 854 * @throws IOException if something goes wrong during redirection 855 */ 856 public static void redirectRequestSecure(CmsJspActionElement jsp, String target) throws IOException { 857 858 jsp.getResponse().sendRedirect(OpenCms.getLinkManager().substituteLink(jsp.getCmsObject(), target, null, true)); 859 } 860 861 /** 862 * Removes an object from the session of the given http request.<p> 863 * 864 * A session will be initialized if the request does not currently have a session. 865 * As a result, the request will always have a session after this method has been called.<p> 866 * 867 * @param request the request to get the session from 868 * @param key the key of the object to be removed from the session 869 */ 870 public static void removeSessionValue(HttpServletRequest request, String key) { 871 872 HttpSession session = request.getSession(true); 873 session.removeAttribute(key); 874 } 875 876 /** 877 * Sets the value of a specific cookie.<p> 878 * If no cookie exists with the value, a new cookie will be created. 879 * 880 * @param jsp the CmsJspActionElement to use 881 * @param name the name of the cookie 882 * @param value the value of the cookie 883 */ 884 public static void setCookieValue(CmsJspActionElement jsp, String name, String value) { 885 886 Cookie[] cookies = jsp.getRequest().getCookies(); 887 for (int i = 0; (cookies != null) && (i < cookies.length); i++) { 888 if (name.equalsIgnoreCase(cookies[i].getName())) { 889 cookies[i].setValue(value); 890 return; 891 } 892 } 893 Cookie cookie = new Cookie(name, value); 894 jsp.getResponse().addCookie(cookie); 895 } 896 897 /** 898 * Sets headers to the given response to prevent client side caching.<p> 899 * 900 * The following headers are set:<p> 901 * <code> 902 * Cache-Control: max-age=0<br> 903 * Cache-Control: must-revalidate<br> 904 * Pragma: no-cache 905 * </code> 906 * 907 * @param res the request where to set the no-cache headers 908 */ 909 public static void setNoCacheHeaders(HttpServletResponse res) { 910 911 res.setHeader(CmsRequestUtil.HEADER_CACHE_CONTROL, CmsRequestUtil.HEADER_VALUE_MAX_AGE + "0"); 912 res.addHeader(CmsRequestUtil.HEADER_CACHE_CONTROL, CmsRequestUtil.HEADER_VALUE_MUST_REVALIDATE); 913 res.addHeader(CmsRequestUtil.HEADER_CACHE_CONTROL, CmsRequestUtil.HEADER_VALUE_NO_CACHE); 914 res.addHeader(CmsRequestUtil.HEADER_CACHE_CONTROL, CmsRequestUtil.HEADER_VALUE_NO_STORE); 915 res.setHeader(CmsRequestUtil.HEADER_PRAGMA, CmsRequestUtil.HEADER_VALUE_NO_CACHE); 916 } 917 918 /** 919 * Adds an object to the session of the given HTTP request.<p> 920 * 921 * A session will be initialized if the request does not currently have a session. 922 * As a result, the request will always have a session after this method has been called.<p> 923 * 924 * @param request the request to get the session from 925 * @param key the key of the object to be stored in the session 926 * @param value the object to be stored in the session 927 */ 928 public static void setSessionValue(HttpServletRequest request, String key, Object value) { 929 930 HttpSession session = request.getSession(true); 931 session.setAttribute(key, value); 932 } 933}