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, 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.ade.upload; 029 030import org.opencms.db.CmsDbSqlException; 031import org.opencms.db.CmsImportFolder; 032import org.opencms.file.CmsFile; 033import org.opencms.file.CmsObject; 034import org.opencms.file.CmsProperty; 035import org.opencms.file.CmsPropertyDefinition; 036import org.opencms.file.CmsResource; 037import org.opencms.file.CmsResourceFilter; 038import org.opencms.file.collectors.A_CmsResourceCollector; 039import org.opencms.file.collectors.I_CmsCollectorPostCreateHandler; 040import org.opencms.file.types.CmsResourceTypeFolder; 041import org.opencms.file.types.CmsResourceTypePlain; 042import org.opencms.gwt.shared.CmsUploadRestrictionInfo; 043import org.opencms.gwt.shared.I_CmsUploadConstants; 044import org.opencms.i18n.CmsMessages; 045import org.opencms.json.JSONArray; 046import org.opencms.json.JSONException; 047import org.opencms.json.JSONObject; 048import org.opencms.jsp.CmsJspBean; 049import org.opencms.loader.CmsLoaderException; 050import org.opencms.lock.CmsLockException; 051import org.opencms.main.CmsException; 052import org.opencms.main.CmsLog; 053import org.opencms.main.OpenCms; 054import org.opencms.security.CmsSecurityException; 055import org.opencms.util.CmsCollectionsGenericWrapper; 056import org.opencms.util.CmsPair; 057import org.opencms.util.CmsRequestUtil; 058import org.opencms.util.CmsStringUtil; 059import org.opencms.util.CmsUUID; 060 061import java.io.File; 062import java.io.UnsupportedEncodingException; 063import java.net.URLDecoder; 064import java.util.ArrayList; 065import java.util.Collections; 066import java.util.HashMap; 067import java.util.List; 068import java.util.Map; 069 070import javax.servlet.http.HttpServletRequest; 071import javax.servlet.http.HttpServletResponse; 072import javax.servlet.jsp.PageContext; 073 074import org.apache.commons.fileupload.FileItem; 075import org.apache.commons.fileupload.FileUploadBase.FileSizeLimitExceededException; 076import org.apache.commons.fileupload.FileUploadBase.SizeLimitExceededException; 077import org.apache.commons.fileupload.disk.DiskFileItemFactory; 078import org.apache.commons.fileupload.servlet.ServletFileUpload; 079import org.apache.commons.lang3.StringUtils; 080import org.apache.commons.logging.Log; 081 082/** 083 * Bean to be used in JSP scriptlet code that provides 084 * access to the upload functionality.<p> 085 * 086 * @since 8.0.0 087 */ 088public class CmsUploadBean extends CmsJspBean { 089 090 /** The default upload timeout. */ 091 public static final int DEFAULT_UPLOAD_TIMEOUT = 20000; 092 093 /** Key name for the session attribute that stores the id of the current listener. */ 094 public static final String SESSION_ATTRIBUTE_LISTENER_ID = "__CmsUploadBean.LISTENER"; 095 096 /** The log object for this class. */ 097 private static final Log LOG = CmsLog.getLog(CmsUploadBean.class); 098 099 /** A static map of all listeners. */ 100 private static Map<CmsUUID, CmsUploadListener> m_listeners = new HashMap<CmsUUID, CmsUploadListener>(); 101 102 /** The gwt message bundle. */ 103 private CmsMessages m_bundle = org.opencms.ade.upload.Messages.get().getBundle(); 104 105 /** Signals that the start method is called. */ 106 private boolean m_called; 107 108 /** A list of the file items to upload. */ 109 private List<FileItem> m_multiPartFileItems; 110 111 /** The map of parameters read from the current request. */ 112 private Map<String, String[]> m_parameterMap; 113 114 /** The names by id of the resources that have been created successfully. */ 115 private HashMap<CmsUUID, String> m_resourcesCreated = new HashMap<CmsUUID, String>(); 116 117 /** A CMS context for the root site. */ 118 private CmsObject m_rootCms; 119 120 /** The server side upload delay. */ 121 private int m_uploadDelay; 122 123 /** The upload hook URI. */ 124 private String m_uploadHook; 125 126 private CmsUploadRestrictionInfo m_uploadRestrictionInfo; 127 128 /** 129 * Constructor, with parameters.<p> 130 * 131 * @param context the JSP page context object 132 * @param req the JSP request 133 * @param res the JSP response 134 * 135 * @throws CmsException if something goes wrong 136 */ 137 public CmsUploadBean(PageContext context, HttpServletRequest req, HttpServletResponse res) 138 throws CmsException { 139 140 super(); 141 init(context, req, res); 142 143 m_rootCms = OpenCms.initCmsObject(getCmsObject()); 144 m_rootCms.getRequestContext().setSiteRoot(""); 145 m_uploadRestrictionInfo = OpenCms.getWorkplaceManager().getUploadRestriction().getUploadRestrictionInfo( 146 m_rootCms); 147 } 148 149 /** 150 * Returns the listener for given CmsUUID.<p> 151 * 152 * @param listenerId the uuid 153 * 154 * @return the according listener 155 */ 156 public static CmsUploadListener getCurrentListener(CmsUUID listenerId) { 157 158 return m_listeners.get(listenerId); 159 } 160 161 /** 162 * Returns the VFS path for the given filename and folder.<p> 163 * 164 * @param cms the cms object 165 * @param fileName the filename to combine with the folder 166 * @param folder the folder to combine with the filename 167 * @param keepFileNames skip file name translation if true 168 * 169 * @return the VFS path for the given filename and folder 170 */ 171 public static String getNewResourceName(CmsObject cms, String fileName, String folder, boolean keepFileNames) { 172 173 String newResname = CmsResource.getName(fileName.replace('\\', '/')); 174 if (!keepFileNames) { 175 newResname = cms.getRequestContext().getFileTranslator().translateResource(newResname); 176 } 177 newResname = folder + newResname; 178 return newResname; 179 } 180 181 /** 182 * Sets the uploadDelay.<p> 183 * 184 * @param uploadDelay the uploadDelay to set 185 */ 186 public void setUploadDelay(int uploadDelay) { 187 188 m_uploadDelay = uploadDelay; 189 } 190 191 /** 192 * Starts the upload.<p> 193 * 194 * @return the response String (JSON) 195 */ 196 public String start() { 197 198 // ensure that this method can only be called once 199 if (m_called) { 200 throw new UnsupportedOperationException(); 201 } 202 m_called = true; 203 204 // create a upload listener 205 CmsUploadListener listener = createListener(); 206 try { 207 // try to parse the request 208 parseRequest(listener); 209 // try to create the resources on the VFS 210 createResources(listener); 211 // trigger update offline indexes, important for gallery search 212 OpenCms.getSearchManager().updateOfflineIndexes(); 213 } catch (CmsException e) { 214 // an error occurred while creating the resources on the VFS, create a special error message 215 LOG.error(e.getMessage(), e); 216 return generateResponse(Boolean.FALSE, getCreationErrorMessage(), formatStackTrace(e)); 217 } catch (CmsUploadException e) { 218 // an expected error occurred while parsing the request, the error message is already set in the exception 219 LOG.debug(e.getMessage(), e); 220 return generateResponse(Boolean.FALSE, e.getMessage(), formatStackTrace(e)); 221 } catch (Throwable e) { 222 // an unexpected error occurred while parsing the request, create a non-specific error message 223 LOG.error(e.getMessage(), e); 224 String message = m_bundle.key(org.opencms.ade.upload.Messages.ERR_UPLOAD_UNEXPECTED_0); 225 return generateResponse(Boolean.FALSE, message, formatStackTrace(e)); 226 } finally { 227 removeListener(listener.getId()); 228 } 229 // the upload was successful inform the user about success 230 return generateResponse(Boolean.TRUE, m_bundle.key(org.opencms.ade.upload.Messages.LOG_UPLOAD_SUCCESS_0), ""); 231 } 232 233 /** 234 * Creates a upload listener and puts it into the static map.<p> 235 * 236 * @return the listener 237 */ 238 private CmsUploadListener createListener() { 239 240 CmsUploadListener listener = new CmsUploadListener(getRequest().getContentLength()); 241 listener.setDelay(m_uploadDelay); 242 m_listeners.put(listener.getId(), listener); 243 getRequest().getSession().setAttribute(SESSION_ATTRIBUTE_LISTENER_ID, listener.getId()); 244 return listener; 245 } 246 247 /** 248 * Creates the resources.<p> 249 * @param listener the listener 250 * 251 * @throws CmsException if something goes wrong 252 * @throws UnsupportedEncodingException in case the encoding is not supported 253 */ 254 private void createResources(CmsUploadListener listener) throws CmsException, UnsupportedEncodingException { 255 256 CmsObject cms = getCmsObject(); 257 String[] isRootPathVals = m_parameterMap.get(I_CmsUploadConstants.UPLOAD_IS_ROOT_PATH_FIELD_NAME); 258 if ((isRootPathVals != null) && (isRootPathVals.length > 0) && Boolean.parseBoolean(isRootPathVals[0])) { 259 cms = m_rootCms; 260 } 261 // get the target folder 262 String targetFolder = getTargetFolder(cms); 263 m_uploadHook = OpenCms.getWorkplaceManager().getUploadHook(cms, targetFolder); 264 265 List<String> filesToUnzip = getFilesToUnzip(); 266 267 // iterate over the list of files to upload and create each single resource 268 for (FileItem fileItem : m_multiPartFileItems) { 269 if ((fileItem != null) && (!fileItem.isFormField())) { 270 // read the content of the file 271 byte[] content = fileItem.get(); 272 fileItem.delete(); 273 274 // determine the new resource name 275 String fileName = m_parameterMap.get( 276 fileItem.getFieldName() + I_CmsUploadConstants.UPLOAD_FILENAME_ENCODED_SUFFIX)[0]; 277 fileName = URLDecoder.decode(fileName, "UTF-8"); 278 279 if (filesToUnzip.contains(CmsResource.getName(fileName.replace('\\', '/')))) { 280 // import the zip 281 CmsImportFolder importZip = new CmsImportFolder(); 282 try { 283 importZip.importZip(content, targetFolder, cms, false); 284 } finally { 285 // get the created resource names 286 for (CmsResource importedResource : importZip.getImportedResources()) { 287 m_resourcesCreated.put(importedResource.getStructureId(), importedResource.getName()); 288 } 289 } 290 } else { 291 // create the resource 292 CmsResource importedResource = createSingleResource(cms, fileName, targetFolder, content); 293 if (importedResource != null) { 294 // add the name of the created resource to the list of successful created resources 295 m_resourcesCreated.put(importedResource.getStructureId(), importedResource.getName()); 296 } 297 } 298 299 if (listener.isCanceled()) { 300 throw listener.getException(); 301 } 302 } 303 } 304 305 String postCreateHandlerStr = getPostCreateHandler(); 306 if (postCreateHandlerStr != null) { 307 try { 308 CmsPair<String, String> classAndConfig = I_CmsCollectorPostCreateHandler.splitClassAndConfig( 309 postCreateHandlerStr); 310 String className = classAndConfig.getFirst(); 311 String config = classAndConfig.getSecond(); 312 I_CmsCollectorPostCreateHandler handler = A_CmsResourceCollector.getPostCreateHandler(className); 313 for (Map.Entry<CmsUUID, String> resourceEntry : m_resourcesCreated.entrySet()) { 314 try { 315 CmsUUID structureId = resourceEntry.getKey(); 316 CmsResource resource = cms.readResource(structureId, CmsResourceFilter.IGNORE_EXPIRATION); 317 if (!resource.isFolder()) { 318 handler.onCreate(cms, resource, false, config); 319 } 320 } catch (Exception e) { 321 LOG.error(e.getLocalizedMessage(), e); 322 } 323 } 324 } catch (Exception e) { 325 LOG.error(e.getLocalizedMessage(), e); 326 } 327 328 } 329 } 330 331 /** 332 * Creates a single resource and returns the new resource.<p> 333 * 334 * @param cms the CMS context to use 335 * @param fileName the name of the resource to create 336 * @param targetFolder the folder to store the new resource 337 * @param content the content of the resource to create 338 * 339 * @return the new resource 340 * 341 * @throws CmsException if something goes wrong 342 * @throws CmsLoaderException if something goes wrong 343 * @throws CmsDbSqlException if something goes wrong 344 */ 345 @SuppressWarnings("deprecation") 346 private CmsResource createSingleResource(CmsObject cms, String fileName, String targetFolder, byte[] content) 347 throws CmsException, CmsLoaderException, CmsDbSqlException { 348 349 String folderRootPath = cms.getRequestContext().addSiteRoot(targetFolder); 350 if (!m_uploadRestrictionInfo.isUploadEnabled(folderRootPath)) { 351 LOG.error("Upload not enabled for folder " + targetFolder); 352 return null; 353 } 354 355 String newResname = getNewResourceName(cms, fileName, targetFolder, isKeepFileNames()); 356 CmsResource createdResource = null; 357 358 // determine Title property value to set on new resource 359 String title = fileName; 360 if (title.lastIndexOf('.') != -1) { 361 title = title.substring(0, title.lastIndexOf('.')); 362 } 363 364 // fileName really shouldn't contain the full path, but for some reason it does sometimes when the client is 365 // running on IE7, so we eliminate anything before and including the last slash or backslash in the title 366 // before setting it as a property. 367 368 int backslashIndex = title.lastIndexOf('\\'); 369 if (backslashIndex != -1) { 370 title = title.substring(backslashIndex + 1); 371 } 372 373 int slashIndex = title.lastIndexOf('/'); 374 if (slashIndex != -1) { 375 title = title.substring(slashIndex + 1); 376 } 377 378 List<CmsProperty> properties = new ArrayList<CmsProperty>(1); 379 CmsProperty titleProp = new CmsProperty(); 380 titleProp.setName(CmsPropertyDefinition.PROPERTY_TITLE); 381 if (OpenCms.getWorkplaceManager().isDefaultPropertiesOnStructure()) { 382 titleProp.setStructureValue(title); 383 } else { 384 titleProp.setResourceValue(title); 385 } 386 properties.add(titleProp); 387 388 int plainId = OpenCms.getResourceManager().getResourceType( 389 CmsResourceTypePlain.getStaticTypeName()).getTypeId(); 390 if (!cms.existsResource(newResname, CmsResourceFilter.IGNORE_EXPIRATION)) { 391 // if the resource does not exist, create it 392 393 try { 394 // create the resource 395 int resTypeId = OpenCms.getResourceManager().getDefaultTypeForName(newResname).getTypeId(); 396 createdResource = cms.createResource(newResname, resTypeId, content, properties); 397 try { 398 cms.unlockResource(newResname); 399 } catch (CmsLockException e) { 400 LOG.info("Couldn't unlock uploaded file", e); 401 } 402 } catch (CmsSecurityException e) { 403 // in case of not enough permissions, try to create a plain text file 404 createdResource = cms.createResource(newResname, plainId, content, properties); 405 cms.unlockResource(newResname); 406 } catch (CmsDbSqlException sqlExc) { 407 // SQL error, probably the file is too large for the database settings, delete file 408 cms.lockResource(newResname); 409 cms.deleteResource(newResname, CmsResource.DELETE_PRESERVE_SIBLINGS); 410 throw sqlExc; 411 } catch (OutOfMemoryError e) { 412 // the file is to large try to clear up 413 cms.lockResource(newResname); 414 cms.deleteResource(newResname, CmsResource.DELETE_PRESERVE_SIBLINGS); 415 throw e; 416 } 417 418 } else { 419 // if the resource already exists, replace it 420 CmsResource res = cms.readResource(newResname, CmsResourceFilter.ALL); 421 boolean wasLocked = false; 422 try { 423 if (!cms.getLock(res).isOwnedBy(cms.getRequestContext().getCurrentUser())) { 424 cms.lockResource(res); 425 wasLocked = true; 426 } 427 CmsFile file = cms.readFile(res); 428 byte[] contents = file.getContents(); 429 try { 430 cms.replaceResource(newResname, res.getTypeId(), content, null); 431 createdResource = res; 432 } catch (CmsDbSqlException sqlExc) { 433 // SQL error, probably the file is too large for the database settings, restore content 434 file.setContents(contents); 435 cms.writeFile(file); 436 throw sqlExc; 437 } catch (OutOfMemoryError e) { 438 // the file is to large try to clear up 439 file.setContents(contents); 440 cms.writeFile(file); 441 throw e; 442 } 443 } finally { 444 if (wasLocked) { 445 cms.unlockResource(res); 446 } 447 } 448 } 449 return createdResource; 450 } 451 452 /** 453 * Creates the upload target folder. 454 * 455 * @param cms the CMS context 456 * @param targetFolder the upload target folder 457 * @return the new folder 458 * @throws CmsException if something goes wrong 459 */ 460 private CmsResource createTargetFolder(CmsObject cms, String targetFolder) throws CmsException { 461 462 List<String> parentFolders = new ArrayList<>(); 463 String currentFolder = targetFolder; 464 while ((currentFolder != null) && !cms.existsResource(currentFolder, CmsResourceFilter.IGNORE_EXPIRATION)) { 465 parentFolders.add(currentFolder); 466 currentFolder = CmsResource.getParentFolder(currentFolder); 467 } 468 Collections.reverse(parentFolders); 469 CmsResource lastCreated = null; 470 CmsResource firstCreated = null; 471 for (String parentFolder : parentFolders) { 472 473 CmsResource createdFolder = cms.createResource( 474 parentFolder, 475 OpenCms.getResourceManager().getResourceType(CmsResourceTypeFolder.getStaticTypeName())); 476 lastCreated = createdFolder; 477 if (firstCreated == null) { 478 firstCreated = createdFolder; 479 } 480 } 481 cms.unlockResource(firstCreated); 482 return lastCreated; 483 484 } 485 486 /** 487 * Returns the stacktrace of the given exception as String.<p> 488 * 489 * @param e the exception 490 * 491 * @return the stacktrace as String 492 */ 493 private String formatStackTrace(Throwable e) { 494 495 return StringUtils.join(CmsLog.render(e), '\n'); 496 } 497 498 /** 499 * Generates a JSON object and returns its String representation for the response.<p> 500 * 501 * @param success <code>true</code> if the upload was successful 502 * @param message the message to display 503 * @param stacktrace the stack trace in case of an error 504 * 505 * @return the the response String 506 */ 507 private String generateResponse(Boolean success, String message, String stacktrace) { 508 509 JSONObject result = new JSONObject(); 510 try { 511 result.put(I_CmsUploadConstants.KEY_SUCCESS, success); 512 result.put(I_CmsUploadConstants.KEY_MESSAGE, message); 513 result.put(I_CmsUploadConstants.KEY_STACKTRACE, stacktrace); 514 result.put(I_CmsUploadConstants.KEY_REQUEST_SIZE, getRequest().getContentLength()); 515 516 // UUIDs get converted to strings when generating the JSON text 517 result.put(I_CmsUploadConstants.KEY_UPLOADED_FILES, new JSONArray(m_resourcesCreated.keySet())); 518 519 result.put(I_CmsUploadConstants.KEY_UPLOADED_FILE_NAMES, new JSONArray(m_resourcesCreated.values())); 520 if (m_uploadHook != null) { 521 result.put(I_CmsUploadConstants.KEY_UPLOAD_HOOK, m_uploadHook); 522 } 523 } catch (JSONException e) { 524 LOG.error(m_bundle.key(org.opencms.ade.upload.Messages.ERR_UPLOAD_JSON_0), e); 525 } 526 return result.toString(); 527 } 528 529 /** 530 * Returns the error message if an error occurred during the creation of resources in the VFS.<p> 531 * 532 * @return the error message 533 */ 534 private String getCreationErrorMessage() { 535 536 String message = new String(); 537 if (!m_resourcesCreated.isEmpty()) { 538 // some resources have been created, tell the user which resources were created successfully 539 StringBuffer buf = new StringBuffer(64); 540 for (String name : m_resourcesCreated.values()) { 541 buf.append("<br />"); 542 buf.append(name); 543 } 544 message = m_bundle.key(org.opencms.ade.upload.Messages.ERR_UPLOAD_CREATING_1, buf.toString()); 545 } else { 546 // no resources have been created on the VFS 547 message = m_bundle.key(org.opencms.ade.upload.Messages.ERR_UPLOAD_CREATING_0); 548 } 549 return message; 550 } 551 552 /** 553 * Gets the list of file names that should be unziped.<p> 554 * 555 * @return the list of file names that should be unziped 556 * 557 * @throws UnsupportedEncodingException if something goes wrong 558 */ 559 private List<String> getFilesToUnzip() throws UnsupportedEncodingException { 560 561 if (m_parameterMap.get(I_CmsUploadConstants.UPLOAD_UNZIP_FILES_FIELD_NAME) != null) { 562 String[] filesToUnzip = m_parameterMap.get(I_CmsUploadConstants.UPLOAD_UNZIP_FILES_FIELD_NAME); 563 if (filesToUnzip != null) { 564 List<String> result = new ArrayList<String>(); 565 for (String filename : filesToUnzip) { 566 result.add(URLDecoder.decode(filename, "UTF-8")); 567 } 568 return result; 569 } 570 } 571 return Collections.emptyList(); 572 } 573 574 /** 575 * Gets the post-create handler. 576 * 577 * @return the post-create handler 578 */ 579 private String getPostCreateHandler() { 580 581 String[] values = m_parameterMap.get(I_CmsUploadConstants.POST_CREATE_HANDLER); 582 return ((values != null) && (values.length > 0)) ? values[0] : null; 583 } 584 585 /** 586 * Returns the target folder for the new resource, 587 * if the given folder does not exist root folder 588 * of the current site is returned.<p> 589 * 590 * @param cms the CMS context to use 591 * 592 * @return the target folder for the new resource 593 * 594 * @throws CmsException if something goes wrong 595 */ 596 private String getTargetFolder(CmsObject cms) throws CmsException { 597 598 // get the target folder on the vfs 599 CmsResource target = cms.readResource("/", CmsResourceFilter.IGNORE_EXPIRATION); 600 if (m_parameterMap.get(I_CmsUploadConstants.UPLOAD_TARGET_FOLDER_FIELD_NAME) != null) { 601 String targetFolder = m_parameterMap.get(I_CmsUploadConstants.UPLOAD_TARGET_FOLDER_FIELD_NAME)[0]; 602 if (!CmsStringUtil.isEmptyOrWhitespaceOnly(targetFolder)) { 603 if (cms.existsResource(targetFolder, CmsResourceFilter.IGNORE_EXPIRATION)) { 604 CmsResource tmpTarget = cms.readResource(targetFolder, CmsResourceFilter.IGNORE_EXPIRATION); 605 if (tmpTarget.isFolder()) { 606 target = tmpTarget; 607 } 608 } else { 609 target = createTargetFolder(cms, targetFolder); 610 } 611 } 612 } 613 String targetFolder = cms.getRequestContext().removeSiteRoot(target.getRootPath()); 614 if (!targetFolder.endsWith("/")) { 615 // add folder separator to currentFolder 616 targetFolder += "/"; 617 } 618 return targetFolder; 619 } 620 621 /** 622 * Returns true if file name translation should be skipped for the upload. 623 * 624 * <p>This is mainly used for the file replacement dialog. 625 * 626 * @return true if file name translation should be skipped 627 */ 628 private boolean isKeepFileNames() { 629 630 String[] values = m_parameterMap.get(I_CmsUploadConstants.KEEP_FILE_NAMES); 631 boolean result = (values != null) && (values.length > 0) && Boolean.parseBoolean(values[0]); 632 return result; 633 } 634 635 /** 636 * Parses the request.<p> 637 * 638 * Stores the file items and the request parameters in a local variable if present.<p> 639 * 640 * @param listener the upload listener 641 * 642 * @throws Exception if anything goes wrong 643 */ 644 private void parseRequest(CmsUploadListener listener) throws Exception { 645 646 // check if the request is a multipart request 647 if (!ServletFileUpload.isMultipartContent(getRequest())) { 648 // no multipart request: Abort the upload 649 throw new CmsUploadException(m_bundle.key(org.opencms.ade.upload.Messages.ERR_UPLOAD_NO_MULTIPART_0)); 650 } 651 652 // this was indeed a multipart form request, read the files 653 m_multiPartFileItems = readMultipartFileItems(listener); 654 655 // check if there were any multipart file items in the request 656 if ((m_multiPartFileItems == null) || m_multiPartFileItems.isEmpty()) { 657 // no file items found stop process 658 throw new CmsUploadException(m_bundle.key(org.opencms.ade.upload.Messages.ERR_UPLOAD_NO_FILEITEMS_0)); 659 } 660 661 // there are file items in the request, get the request parameters 662 m_parameterMap = CmsRequestUtil.readParameterMapFromMultiPart( 663 getCmsObject().getRequestContext().getEncoding(), 664 m_multiPartFileItems); 665 666 listener.setFinished(true); 667 } 668 669 /** 670 * Parses a request of the form <code>multipart/form-data</code>.<p> 671 * 672 * The result list will contain items of type <code>{@link FileItem}</code>. 673 * If the request has no file items, then <code>null</code> is returned.<p> 674 * 675 * @param listener the upload listener 676 * 677 * @return the list of <code>{@link FileItem}</code> extracted from the multipart request, 678 * or <code>null</code> if the request has no file items 679 * 680 * @throws Exception if anything goes wrong 681 */ 682 private List<FileItem> readMultipartFileItems(CmsUploadListener listener) throws Exception { 683 684 DiskFileItemFactory factory = new DiskFileItemFactory(); 685 // maximum size that will be stored in memory 686 factory.setSizeThreshold(4096); 687 // the location for saving data that is larger than the threshold 688 File temp = new File(OpenCms.getSystemInfo().getPackagesRfsPath()); 689 if (temp.exists() || temp.mkdirs()) { 690 // make sure the folder exists 691 factory.setRepository(temp); 692 } 693 694 // create a file upload servlet 695 ServletFileUpload fu = new ServletFileUpload(factory); 696 // set the listener 697 fu.setProgressListener(listener); 698 // set encoding to correctly handle special chars (e.g. in filenames) 699 fu.setHeaderEncoding(getRequest().getCharacterEncoding()); 700 // set the maximum size for a single file (value is in bytes) 701 long maxFileSizeBytes = OpenCms.getWorkplaceManager().getFileBytesMaxUploadSize(getCmsObject()); 702 if (maxFileSizeBytes > 0) { 703 fu.setFileSizeMax(maxFileSizeBytes); 704 } 705 706 // try to parse the request 707 try { 708 return CmsCollectionsGenericWrapper.list(fu.parseRequest(getRequest())); 709 } catch (SizeLimitExceededException e) { 710 // request size is larger than maximum allowed request size, throw an error 711 Integer actualSize = Integer.valueOf((int)(e.getActualSize() / 1024)); 712 Integer maxSize = Integer.valueOf((int)(e.getPermittedSize() / 1024)); 713 throw new CmsUploadException( 714 m_bundle.key(org.opencms.ade.upload.Messages.ERR_UPLOAD_REQUEST_SIZE_LIMIT_2, actualSize, maxSize), 715 e); 716 } catch (FileSizeLimitExceededException e) { 717 // file size is larger than maximum allowed file size, throw an error 718 Integer actualSize = Integer.valueOf((int)(e.getActualSize() / 1024)); 719 Integer maxSize = Integer.valueOf((int)(e.getPermittedSize() / 1024)); 720 throw new CmsUploadException( 721 m_bundle.key( 722 org.opencms.ade.upload.Messages.ERR_UPLOAD_FILE_SIZE_LIMIT_3, 723 actualSize, 724 e.getFileName(), 725 maxSize), 726 e); 727 } 728 } 729 730 /** 731 * Remove the listener active in this session. 732 * 733 * @param listenerId the id of the listener to remove 734 */ 735 private void removeListener(CmsUUID listenerId) { 736 737 getRequest().getSession().removeAttribute(SESSION_ATTRIBUTE_LISTENER_ID); 738 m_listeners.remove(listenerId); 739 } 740}