001    /**
002     * Copyright (c) 2000-present Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portal.upload;
016    
017    import com.liferay.portal.kernel.io.ByteArrayFileInputStream;
018    import com.liferay.portal.kernel.log.Log;
019    import com.liferay.portal.kernel.log.LogFactoryUtil;
020    import com.liferay.portal.kernel.upload.FileItem;
021    import com.liferay.portal.kernel.upload.UploadException;
022    import com.liferay.portal.kernel.upload.UploadServletRequest;
023    import com.liferay.portal.kernel.util.ArrayUtil;
024    import com.liferay.portal.kernel.util.FileUtil;
025    import com.liferay.portal.kernel.util.ProgressTracker;
026    import com.liferay.portal.kernel.util.PropsKeys;
027    import com.liferay.portal.kernel.util.StringBundler;
028    import com.liferay.portal.kernel.util.SystemProperties;
029    import com.liferay.portal.kernel.util.Validator;
030    import com.liferay.portal.kernel.util.WebKeys;
031    import com.liferay.portal.util.PrefsPropsUtil;
032    
033    import java.io.File;
034    import java.io.IOException;
035    import java.io.InputStream;
036    
037    import java.util.ArrayList;
038    import java.util.Collections;
039    import java.util.Enumeration;
040    import java.util.HashMap;
041    import java.util.LinkedHashMap;
042    import java.util.LinkedHashSet;
043    import java.util.List;
044    import java.util.Map;
045    import java.util.Set;
046    import java.util.TreeSet;
047    
048    import javax.servlet.ServletInputStream;
049    import javax.servlet.http.HttpServletRequest;
050    import javax.servlet.http.HttpServletRequestWrapper;
051    import javax.servlet.http.HttpSession;
052    
053    import org.apache.commons.fileupload.FileUploadBase;
054    import org.apache.commons.fileupload.servlet.ServletFileUpload;
055    
056    /**
057     * @author Brian Wing Shun Chan
058     * @author Zongliang Li
059     * @author Harry Mark
060     * @author Raymond Aug??
061     */
062    public class UploadServletRequestImpl
063            extends HttpServletRequestWrapper implements UploadServletRequest {
064    
065            public static File getTempDir() {
066                    if (_tempDir == null) {
067                            _tempDir = new File(
068                                    PrefsPropsUtil.getString(
069                                            PropsKeys.UPLOAD_SERVLET_REQUEST_IMPL_TEMP_DIR,
070                                            SystemProperties.get(SystemProperties.TMP_DIR)));
071                    }
072    
073                    return _tempDir;
074            }
075    
076            public static void setTempDir(File tempDir) {
077                    _tempDir = tempDir;
078            }
079    
080            public UploadServletRequestImpl(HttpServletRequest request) {
081                    super(request);
082    
083                    _fileParameters = new LinkedHashMap<>();
084                    _regularParameters = new LinkedHashMap<>();
085    
086                    LiferayServletRequest liferayServletRequest = null;
087    
088                    try {
089                            HttpSession session = request.getSession();
090    
091                            session.removeAttribute(ProgressTracker.PERCENT);
092    
093                            ServletFileUpload servletFileUpload = new ServletFileUpload(
094                                    new LiferayFileItemFactory(getTempDir()));
095    
096                            liferayServletRequest = new LiferayServletRequest(request);
097    
098                            List<org.apache.commons.fileupload.FileItem> fileItems =
099                                    servletFileUpload.parseRequest(liferayServletRequest);
100    
101                            liferayServletRequest.setFinishedReadingOriginalStream(true);
102    
103                            long uploadServletRequestImplMaxSize = PrefsPropsUtil.getLong(
104                                    PropsKeys.UPLOAD_SERVLET_REQUEST_IMPL_MAX_SIZE);
105                            long uploadServletRequestImplSize = 0;
106    
107                            int contentLength = request.getContentLength();
108    
109                            if ((uploadServletRequestImplMaxSize > 0) &&
110                                    ((contentLength == -1) ||
111                                     (contentLength > uploadServletRequestImplMaxSize))) {
112    
113                                    fileItems = sort(fileItems);
114                            }
115    
116                            for (org.apache.commons.fileupload.FileItem fileItem : fileItems) {
117                                    LiferayFileItem liferayFileItem = (LiferayFileItem)fileItem;
118    
119                                    if (uploadServletRequestImplMaxSize > 0) {
120                                            long itemSize = liferayFileItem.getItemSize();
121    
122                                            if ((uploadServletRequestImplSize + itemSize) >
123                                                            uploadServletRequestImplMaxSize) {
124    
125                                                    StringBundler sb = new StringBundler(3);
126    
127                                                    sb.append(
128                                                            "Request reached the maximum permitted size of ");
129                                                    sb.append(uploadServletRequestImplMaxSize);
130                                                    sb.append(" bytes");
131    
132                                                    UploadException uploadException = new UploadException(
133                                                            sb.toString());
134    
135                                                    uploadException.setExceededUploadRequestSizeLimit(true);
136    
137                                                    request.setAttribute(
138                                                            WebKeys.UPLOAD_EXCEPTION, uploadException);
139    
140                                                    continue;
141                                            }
142    
143                                            uploadServletRequestImplSize += itemSize;
144                                    }
145    
146                                    if (liferayFileItem.isFormField()) {
147                                            liferayFileItem.setString(request.getCharacterEncoding());
148    
149                                            String fieldName = liferayFileItem.getFieldName();
150    
151                                            if (!_regularParameters.containsKey(fieldName)) {
152                                                    _regularParameters.put(
153                                                            fieldName, new ArrayList<String>());
154                                            }
155    
156                                            List<String> values = _regularParameters.get(fieldName);
157    
158                                            if (liferayFileItem.getSize() >
159                                                            LiferayFileItem.THRESHOLD_SIZE) {
160    
161                                                    StringBundler sb = new StringBundler(5);
162    
163                                                    sb.append("The field ");
164                                                    sb.append(fieldName);
165                                                    sb.append(" exceeds its maximum permitted size of ");
166                                                    sb.append(LiferayFileItem.THRESHOLD_SIZE);
167                                                    sb.append(" bytes");
168    
169                                                    UploadException uploadException = new UploadException(
170                                                            sb.toString());
171    
172                                                    uploadException.setExceededLiferayFileItemSizeLimit(
173                                                            true);
174    
175                                                    request.setAttribute(
176                                                            WebKeys.UPLOAD_EXCEPTION, uploadException);
177                                            }
178    
179                                            values.add(liferayFileItem.getEncodedString());
180    
181                                            continue;
182                                    }
183    
184                                    FileItem[] liferayFileItems = _fileParameters.get(
185                                            liferayFileItem.getFieldName());
186    
187                                    if (liferayFileItems == null) {
188                                            liferayFileItems = new LiferayFileItem[] {liferayFileItem};
189                                    }
190                                    else {
191                                            LiferayFileItem[] newLiferayFileItems =
192                                                    new LiferayFileItem[liferayFileItems.length + 1];
193    
194                                            System.arraycopy(
195                                                    liferayFileItems, 0, newLiferayFileItems, 0,
196                                                    liferayFileItems.length);
197    
198                                            newLiferayFileItems[newLiferayFileItems.length - 1] =
199                                                    liferayFileItem;
200    
201                                            liferayFileItems = newLiferayFileItems;
202                                    }
203    
204                                    _fileParameters.put(
205                                            liferayFileItem.getFieldName(), liferayFileItems);
206                            }
207                    }
208                    catch (Exception e) {
209                            UploadException uploadException = new UploadException(e);
210    
211                            if (e instanceof FileUploadBase.FileSizeLimitExceededException) {
212                                    uploadException.setExceededFileSizeLimit(true);
213                            }
214                            else if (e instanceof FileUploadBase.SizeLimitExceededException ) {
215                                    uploadException.setExceededUploadRequestSizeLimit(true);
216                            }
217    
218                            request.setAttribute(WebKeys.UPLOAD_EXCEPTION, uploadException);
219    
220                            if (_log.isDebugEnabled()) {
221                                    _log.debug(e, e);
222                            }
223                    }
224    
225                    _liferayServletRequest = liferayServletRequest;
226            }
227    
228            public UploadServletRequestImpl(
229                    HttpServletRequest request, Map<String, FileItem[]> fileParameters,
230                    Map<String, List<String>> regularParameters) {
231    
232                    super(request);
233    
234                    _fileParameters = new LinkedHashMap<>();
235                    _regularParameters = new LinkedHashMap<>();
236    
237                    if (fileParameters != null) {
238                            _fileParameters.putAll(fileParameters);
239                    }
240    
241                    if (regularParameters != null) {
242                            _regularParameters.putAll(regularParameters);
243                    }
244    
245                    _liferayServletRequest = null;
246            }
247    
248            @Override
249            public void cleanUp() {
250                    if ((_fileParameters != null) && !_fileParameters.isEmpty()) {
251                            for (FileItem[] liferayFileItems : _fileParameters.values()) {
252                                    for (FileItem liferayFileItem : liferayFileItems) {
253                                            liferayFileItem.delete();
254                                    }
255                            }
256                    }
257    
258                    if (_liferayServletRequest != null) {
259                            _liferayServletRequest.cleanUp();
260                    }
261            }
262    
263            @Override
264            public String getContentType(String name) {
265                    FileItem[] liferayFileItems = _fileParameters.get(name);
266    
267                    if (ArrayUtil.isNotEmpty(liferayFileItems)) {
268                            FileItem liferayFileItem = liferayFileItems[0];
269    
270                            return liferayFileItem.getContentType();
271                    }
272    
273                    return null;
274            }
275    
276            @Override
277            public File getFile(String name) {
278                    return getFile(name, false);
279            }
280    
281            @Override
282            public File getFile(String name, boolean forceCreate) {
283                    if (getFileName(name) == null) {
284                            return null;
285                    }
286    
287                    FileItem[] liferayFileItems = _fileParameters.get(name);
288    
289                    if (ArrayUtil.isEmpty(liferayFileItems)) {
290                            return null;
291                    }
292    
293                    FileItem liferayFileItem = liferayFileItems[0];
294    
295                    long size = liferayFileItem.getSize();
296    
297                    if ((size > 0) && (size <= liferayFileItem.getSizeThreshold())) {
298                            forceCreate = true;
299                    }
300    
301                    File file = liferayFileItem.getStoreLocation();
302    
303                    if (liferayFileItem.isInMemory() && forceCreate) {
304                            try {
305                                    FileUtil.write(file, liferayFileItem.getInputStream());
306                            }
307                            catch (IOException ioe) {
308                                    if (_log.isWarnEnabled()) {
309                                            _log.warn(
310                                                    "Unable to write temporary file " +
311                                                            file.getAbsolutePath(),
312                                                    ioe);
313                                    }
314                            }
315                    }
316    
317                    return file;
318            }
319    
320            @Override
321            public InputStream getFileAsStream(String name) throws IOException {
322                    return getFileAsStream(name, true);
323            }
324    
325            @Override
326            public InputStream getFileAsStream(String name, boolean deleteOnClose)
327                    throws IOException {
328    
329                    if (getFileName(name) == null) {
330                            return null;
331                    }
332    
333                    InputStream inputStream = null;
334    
335                    FileItem[] liferayFileItems = _fileParameters.get(name);
336    
337                    if (ArrayUtil.isNotEmpty(liferayFileItems)) {
338                            FileItem liferayFileItem = liferayFileItems[0];
339    
340                            inputStream = getInputStream(liferayFileItem, deleteOnClose);
341                    }
342    
343                    return inputStream;
344            }
345    
346            @Override
347            public String getFileName(String name) {
348                    FileItem[] liferayFileItems = _fileParameters.get(name);
349    
350                    if (ArrayUtil.isNotEmpty(liferayFileItems)) {
351                            FileItem liferayFileItem = liferayFileItems[0];
352    
353                            return liferayFileItem.getFileName();
354                    }
355    
356                    return null;
357            }
358    
359            @Override
360            public String[] getFileNames(String name) {
361                    FileItem[] liferayFileItems = _fileParameters.get(name);
362    
363                    if (ArrayUtil.isNotEmpty(liferayFileItems)) {
364                            String[] fileNames = new String[liferayFileItems.length];
365    
366                            for (int i = 0; i < liferayFileItems.length; i++) {
367                                    FileItem liferayFileItem = liferayFileItems[i];
368    
369                                    fileNames[i] = liferayFileItem.getFileName();
370                            }
371    
372                            return fileNames;
373                    }
374    
375                    return null;
376            }
377    
378            @Override
379            public File[] getFiles(String name) {
380                    String[] fileNames = getFileNames(name);
381    
382                    if (fileNames == null) {
383                            return null;
384                    }
385    
386                    FileItem[] liferayFileItems = _fileParameters.get(name);
387    
388                    if (ArrayUtil.isNotEmpty(liferayFileItems)) {
389                            File[] files = new File[liferayFileItems.length];
390    
391                            for (int i = 0; i < liferayFileItems.length; i++) {
392                                    FileItem liferayFileItem = liferayFileItems[i];
393    
394                                    if (Validator.isNotNull(liferayFileItem.getFileName())) {
395                                            files[i] = liferayFileItem.getStoreLocation();
396                                    }
397                            }
398    
399                            return files;
400                    }
401    
402                    return null;
403            }
404    
405            @Override
406            public InputStream[] getFilesAsStream(String name) throws IOException {
407                    return getFilesAsStream(name, true);
408            }
409    
410            @Override
411            public InputStream[] getFilesAsStream(String name, boolean deleteOnClose)
412                    throws IOException {
413    
414                    String[] fileNames = getFileNames(name);
415    
416                    if (fileNames == null) {
417                            return null;
418                    }
419    
420                    InputStream[] inputStreams = null;
421    
422                    FileItem[] liferayFileItems = _fileParameters.get(name);
423    
424                    if (ArrayUtil.isNotEmpty(liferayFileItems)) {
425                            inputStreams = new InputStream[liferayFileItems.length];
426    
427                            for (int i = 0; i < liferayFileItems.length; i++) {
428                                    FileItem liferayFileItem = liferayFileItems[i];
429    
430                                    if (Validator.isNotNull(liferayFileItem.getFileName())) {
431                                            inputStreams[i] = getInputStream(
432                                                    liferayFileItem, deleteOnClose);
433                                    }
434                            }
435                    }
436    
437                    return inputStreams;
438            }
439    
440            @Override
441            public String getFullFileName(String name) {
442                    FileItem[] liferayFileItems = _fileParameters.get(name);
443    
444                    if (ArrayUtil.isNotEmpty(liferayFileItems)) {
445                            FileItem liferayFileItem = liferayFileItems[0];
446    
447                            return liferayFileItem.getFullFileName();
448                    }
449    
450                    return null;
451            }
452    
453            @Override
454            public ServletInputStream getInputStream() throws IOException {
455                    if (_liferayServletRequest != null) {
456                            return _liferayServletRequest.getInputStream();
457                    }
458    
459                    return super.getInputStream();
460            }
461    
462            @Override
463            public Map<String, FileItem[]> getMultipartParameterMap() {
464                    return _fileParameters;
465            }
466    
467            @Override
468            public String getParameter(String name) {
469                    List<String> values = _regularParameters.get(name);
470    
471                    if ((values != null) && !values.isEmpty()) {
472                            return values.get(0);
473                    }
474    
475                    return super.getParameter(name);
476            }
477    
478            @Override
479            public Map<String, String[]> getParameterMap() {
480                    Map<String, String[]> map = new HashMap<>();
481    
482                    Enumeration<String> enu = getParameterNames();
483    
484                    while (enu.hasMoreElements()) {
485                            String name = enu.nextElement();
486    
487                            String[] values = getParameterValues(name);
488    
489                            if (values != null) {
490                                    map.put(name, values);
491                            }
492                    }
493    
494                    return map;
495            }
496    
497            @Override
498            public Enumeration<String> getParameterNames() {
499                    Set<String> parameterNames = new LinkedHashSet<>();
500    
501                    Enumeration<String> enu = super.getParameterNames();
502    
503                    while (enu.hasMoreElements()) {
504                            parameterNames.add(enu.nextElement());
505                    }
506    
507                    parameterNames.addAll(_regularParameters.keySet());
508                    parameterNames.addAll(_fileParameters.keySet());
509    
510                    return Collections.enumeration(parameterNames);
511            }
512    
513            @Override
514            public String[] getParameterValues(String name) {
515                    String[] parameterValues = null;
516    
517                    List<String> values = _regularParameters.get(name);
518    
519                    if (values != null) {
520                            parameterValues = values.toArray(new String[values.size()]);
521                    }
522    
523                    String[] parentParameterValues = super.getParameterValues(name);
524    
525                    if (parameterValues == null) {
526                            return parentParameterValues;
527                    }
528                    else if (parentParameterValues == null) {
529                            return parameterValues;
530                    }
531    
532                    return ArrayUtil.append(parameterValues, parentParameterValues);
533            }
534    
535            @Override
536            public Map<String, List<String>> getRegularParameterMap() {
537                    return _regularParameters;
538            }
539    
540            @Override
541            public Long getSize(String name) {
542                    FileItem[] liferayFileItems = _fileParameters.get(name);
543    
544                    if (ArrayUtil.isNotEmpty(liferayFileItems)) {
545                            FileItem liferayFileItem = liferayFileItems[0];
546    
547                            return Long.valueOf(liferayFileItem.getSize());
548                    }
549    
550                    return null;
551            }
552    
553            @Override
554            public Boolean isFormField(String name) {
555                    FileItem[] liferayFileItems = _fileParameters.get(name);
556    
557                    if (ArrayUtil.isNotEmpty(liferayFileItems)) {
558                            FileItem liferayFileItem = liferayFileItems[0];
559    
560                            return liferayFileItem.isFormField();
561                    }
562    
563                    return null;
564            }
565    
566            protected InputStream getInputStream(
567                            FileItem liferayFileItem, boolean deleteOnClose)
568                    throws IOException {
569    
570                    InputStream inputStream = null;
571    
572                    if (liferayFileItem.isInMemory() && (liferayFileItem.getSize() > 0)) {
573                            inputStream = liferayFileItem.getInputStream();
574                    }
575                    else if (!liferayFileItem.isInMemory()) {
576                            inputStream = new ByteArrayFileInputStream(
577                                    liferayFileItem.getStoreLocation(),
578                                    liferayFileItem.getSizeThreshold(), deleteOnClose);
579                    }
580    
581                    return inputStream;
582            }
583    
584            protected List<org.apache.commons.fileupload.FileItem> sort(
585                    List<org.apache.commons.fileupload.FileItem> fileItems) {
586    
587                    Map<String, GroupedFileItems> groupedFileItemsMap = new HashMap<>();
588    
589                    for (org.apache.commons.fileupload.FileItem fileItem : fileItems) {
590                            String fieldName = fileItem.getFieldName();
591    
592                            GroupedFileItems groupedFileItems = groupedFileItemsMap.get(
593                                    fieldName);
594    
595                            if (groupedFileItems == null) {
596                                    groupedFileItems = new GroupedFileItems(fieldName);
597    
598                                    groupedFileItemsMap.put(fieldName, groupedFileItems);
599                            }
600    
601                            groupedFileItems.addFileItem(fileItem);
602                    }
603    
604                    Set<GroupedFileItems> groupedFileItemsList = new TreeSet<>(
605                            groupedFileItemsMap.values());
606    
607                    List<org.apache.commons.fileupload.FileItem> sortedFileItems =
608                            new ArrayList<>();
609    
610                    for (GroupedFileItems groupedFileItems : groupedFileItemsList) {
611                            sortedFileItems.addAll(groupedFileItems.getFileItems());
612                    }
613    
614                    return sortedFileItems;
615            }
616    
617            private static final Log _log = LogFactoryUtil.getLog(
618                    UploadServletRequestImpl.class);
619    
620            private static File _tempDir;
621    
622            private final Map<String, FileItem[]> _fileParameters;
623            private final LiferayServletRequest _liferayServletRequest;
624            private final Map<String, List<String>> _regularParameters;
625    
626            private class GroupedFileItems implements Comparable<GroupedFileItems> {
627    
628                    public GroupedFileItems(String key) {
629                            _key = key;
630                    }
631    
632                    public void addFileItem(
633                            org.apache.commons.fileupload.FileItem fileItem) {
634    
635                            _fileItems.add(fileItem);
636    
637                            _fileItemsSize += fileItem.getSize();
638                    }
639    
640                    @Override
641                    public int compareTo(GroupedFileItems groupedFileItems) {
642                            if (groupedFileItems == null) {
643                                    return 1;
644                            }
645    
646                            if (equals(groupedFileItems)) {
647                                    return 0;
648                            }
649    
650                            if (_key.equals(groupedFileItems._key)) {
651                                    return 1;
652                            }
653    
654                            if (getFileItemsSize() >= groupedFileItems.getFileItemsSize()) {
655                                    return 1;
656                            }
657    
658                            return -1;
659                    }
660    
661                    public List<org.apache.commons.fileupload.FileItem> getFileItems() {
662                            return _fileItems;
663                    }
664    
665                    public int getFileItemsSize() {
666                            return _fileItemsSize;
667                    }
668    
669                    private final List<org.apache.commons.fileupload.FileItem> _fileItems =
670                            new ArrayList<>();
671                    private int _fileItemsSize;
672                    private final String _key;
673    
674            }
675    
676    }