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.kernel.portlet;
016    
017    import com.liferay.portal.kernel.log.Log;
018    import com.liferay.portal.kernel.log.LogFactoryUtil;
019    import com.liferay.portal.kernel.servlet.BrowserSnifferUtil;
020    import com.liferay.portal.kernel.servlet.HttpHeaders;
021    import com.liferay.portal.kernel.util.ArrayUtil;
022    import com.liferay.portal.kernel.util.FileUtil;
023    import com.liferay.portal.kernel.util.GetterUtil;
024    import com.liferay.portal.kernel.util.HttpUtil;
025    import com.liferay.portal.kernel.util.PropsUtil;
026    import com.liferay.portal.kernel.util.StreamUtil;
027    import com.liferay.portal.kernel.util.StringBundler;
028    import com.liferay.portal.kernel.util.StringPool;
029    import com.liferay.portal.kernel.util.StringUtil;
030    import com.liferay.portal.kernel.util.Validator;
031    import com.liferay.portal.util.PortalUtil;
032    
033    import java.io.File;
034    import java.io.FileInputStream;
035    import java.io.IOException;
036    import java.io.InputStream;
037    import java.io.OutputStream;
038    
039    import java.nio.channels.Channels;
040    import java.nio.channels.FileChannel;
041    
042    import javax.portlet.MimeResponse;
043    import javax.portlet.PortletRequest;
044    import javax.portlet.ResourceResponse;
045    
046    import javax.servlet.http.HttpServletRequest;
047    
048    /**
049     * @author Brian Wing Shun Chan
050     */
051    public class PortletResponseUtil {
052    
053            /**
054             * @deprecated As of 6.1.0
055             */
056            @Deprecated
057            public static void sendFile(
058                            MimeResponse mimeResponse, String fileName, byte[] bytes)
059                    throws IOException {
060    
061                    sendFile(null, mimeResponse, fileName, bytes);
062            }
063    
064            /**
065             * @deprecated As of 6.1.0
066             */
067            @Deprecated
068            public static void sendFile(
069                            MimeResponse mimeResponse, String fileName, byte[] bytes,
070                            String contentType)
071                    throws IOException {
072    
073                    sendFile(null, mimeResponse, fileName, bytes, contentType);
074            }
075    
076            /**
077             * @deprecated As of 6.1.0
078             */
079            @Deprecated
080            public static void sendFile(
081                            MimeResponse mimeResponse, String fileName, InputStream inputStream)
082                    throws IOException {
083    
084                    sendFile(null, mimeResponse, fileName, inputStream);
085            }
086    
087            /**
088             * @deprecated As of 6.1.0
089             */
090            @Deprecated
091            public static void sendFile(
092                            MimeResponse mimeResponse, String fileName, InputStream inputStream,
093                            int contentLength, String contentType)
094                    throws IOException {
095    
096                    sendFile(
097                            null, mimeResponse, fileName, inputStream, contentLength,
098                            contentType);
099            }
100    
101            /**
102             * @deprecated As of 6.1.0
103             */
104            @Deprecated
105            public static void sendFile(
106                            MimeResponse mimeResponse, String fileName, InputStream inputStream,
107                            String contentType)
108                    throws IOException {
109    
110                    sendFile(null, mimeResponse, fileName, inputStream, contentType);
111            }
112    
113            public static void sendFile(
114                            PortletRequest portletRequest, MimeResponse mimeResponse,
115                            String fileName, byte[] bytes)
116                    throws IOException {
117    
118                    sendFile(portletRequest, mimeResponse, fileName, bytes, null);
119            }
120    
121            public static void sendFile(
122                            PortletRequest portletRequest, MimeResponse mimeResponse,
123                            String fileName, byte[] bytes, String contentType)
124                    throws IOException {
125    
126                    sendFile(
127                            portletRequest, mimeResponse, fileName, bytes, contentType, null);
128            }
129    
130            public static void sendFile(
131                            PortletRequest portletRequest, MimeResponse mimeResponse,
132                            String fileName, byte[] bytes, String contentType,
133                            String contentDispositionType)
134                    throws IOException {
135    
136                    setHeaders(
137                            portletRequest, mimeResponse, fileName, contentType,
138                            contentDispositionType);
139    
140                    write(mimeResponse, bytes);
141            }
142    
143            public static void sendFile(
144                            PortletRequest portletRequest, MimeResponse mimeResponse,
145                            String fileName, InputStream inputStream)
146                    throws IOException {
147    
148                    sendFile(portletRequest, mimeResponse, fileName, inputStream, null);
149            }
150    
151            public static void sendFile(
152                            PortletRequest portletRequest, MimeResponse mimeResponse,
153                            String fileName, InputStream inputStream, int contentLength,
154                            String contentType)
155                    throws IOException {
156    
157                    sendFile(
158                            portletRequest, mimeResponse, fileName, inputStream, contentLength,
159                            contentType, null);
160            }
161    
162            public static void sendFile(
163                            PortletRequest portletRequest, MimeResponse mimeResponse,
164                            String fileName, InputStream inputStream, int contentLength,
165                            String contentType, String contentDispositionType)
166                    throws IOException {
167    
168                    setHeaders(
169                            portletRequest, mimeResponse, fileName, contentType,
170                            contentDispositionType);
171    
172                    write(mimeResponse, inputStream, contentLength);
173            }
174    
175            public static void sendFile(
176                            PortletRequest portletRequest, MimeResponse mimeResponse,
177                            String fileName, InputStream inputStream, String contentType)
178                    throws IOException {
179    
180                    sendFile(
181                            portletRequest, mimeResponse, fileName, inputStream, 0,
182                            contentType);
183            }
184    
185            public static void write(MimeResponse mimeResponse, byte[] bytes)
186                    throws IOException {
187    
188                    write(mimeResponse, bytes, 0, 0);
189            }
190    
191            public static void write(
192                            MimeResponse mimeResponse, byte[] bytes, int offset,
193                            int contentLength)
194                    throws IOException {
195    
196                    // LEP-3122
197    
198                    if (!mimeResponse.isCommitted()) {
199    
200                            // LEP-536
201    
202                            if (contentLength == 0) {
203                                    contentLength = bytes.length;
204                            }
205    
206                            if (mimeResponse instanceof ResourceResponse) {
207                                    ResourceResponse resourceResponse =
208                                            (ResourceResponse)mimeResponse;
209    
210                                    resourceResponse.setContentLength(contentLength);
211                            }
212    
213                            OutputStream outputStream = mimeResponse.getPortletOutputStream();
214    
215                            outputStream.write(bytes, offset, contentLength);
216                    }
217            }
218    
219            public static void write(MimeResponse mimeResponse, byte[][] bytesArray)
220                    throws IOException {
221    
222                    // LEP-3122
223    
224                    if (mimeResponse.isCommitted()) {
225                            return;
226                    }
227    
228                    // LEP-536
229    
230                    long contentLength = 0;
231    
232                    for (byte[] bytes : bytesArray) {
233                            contentLength += bytes.length;
234                    }
235    
236                    if (mimeResponse instanceof ResourceResponse) {
237                            ResourceResponse resourceResponse = (ResourceResponse)mimeResponse;
238    
239                            setContentLength(resourceResponse, contentLength);
240                    }
241    
242                    OutputStream outputStream = mimeResponse.getPortletOutputStream();
243    
244                    for (byte[] bytes : bytesArray) {
245                            outputStream.write(bytes);
246                    }
247            }
248    
249            public static void write(MimeResponse mimeResponse, File file)
250                    throws IOException {
251    
252                    FileInputStream fileInputStream = new FileInputStream(file);
253    
254                    try (FileChannel fileChannel = fileInputStream.getChannel()) {
255                            long contentLength = fileChannel.size();
256    
257                            if (mimeResponse instanceof ResourceResponse) {
258                                    ResourceResponse resourceResponse =
259                                            (ResourceResponse)mimeResponse;
260    
261                                    setContentLength(resourceResponse, contentLength);
262                            }
263    
264                            fileChannel.transferTo(
265                                    0, contentLength,
266                                    Channels.newChannel(mimeResponse.getPortletOutputStream()));
267                    }
268            }
269    
270            public static void write(MimeResponse mimeResponse, InputStream inputStream)
271                    throws IOException {
272    
273                    write(mimeResponse, inputStream, 0);
274            }
275    
276            public static void write(
277                            MimeResponse mimeResponse, InputStream inputStream,
278                            int contentLength)
279                    throws IOException {
280    
281                    if (mimeResponse.isCommitted()) {
282                            StreamUtil.cleanUp(inputStream);
283    
284                            return;
285                    }
286    
287                    if (contentLength > 0) {
288                            if (mimeResponse instanceof ResourceResponse) {
289                                    ResourceResponse resourceResponse =
290                                            (ResourceResponse)mimeResponse;
291    
292                                    resourceResponse.setContentLength(contentLength);
293                            }
294                    }
295    
296                    StreamUtil.transfer(inputStream, mimeResponse.getPortletOutputStream());
297            }
298    
299            public static void write(MimeResponse mimeResponse, String s)
300                    throws IOException {
301    
302                    write(mimeResponse, s.getBytes(StringPool.UTF8));
303            }
304    
305            protected static void setContentLength(
306                    ResourceResponse response, long contentLength) {
307    
308                    response.setProperty(
309                            HttpHeaders.CONTENT_LENGTH, String.valueOf(contentLength));
310            }
311    
312            protected static void setHeaders(
313                    PortletRequest portletRequest, MimeResponse mimeResponse,
314                    String fileName, String contentType, String contentDispositionType) {
315    
316                    if (_log.isDebugEnabled()) {
317                            _log.debug("Sending file of type " + contentType);
318                    }
319    
320                    // LEP-2201
321    
322                    if (Validator.isNotNull(contentType)) {
323                            mimeResponse.setContentType(contentType);
324                    }
325    
326                    mimeResponse.setProperty(
327                            HttpHeaders.CACHE_CONTROL, HttpHeaders.CACHE_CONTROL_PRIVATE_VALUE);
328    
329                    if (Validator.isNull(fileName)) {
330                            return;
331                    }
332    
333                    String contentDispositionFileName = "filename=\"" + fileName + "\"";
334    
335                    // If necessary for non-ASCII characters, encode based on RFC 2184.
336                    // However, not all browsers support RFC 2184. See LEP-3127.
337    
338                    boolean ascii = true;
339    
340                    for (int i = 0; i < fileName.length(); i++) {
341                            if (!Validator.isAscii(fileName.charAt(i))) {
342                                    ascii = false;
343    
344                                    break;
345                            }
346                    }
347    
348                    try {
349                            if (!ascii) {
350                                    String encodedFileName = HttpUtil.encodeURL(fileName, true);
351    
352                                    HttpServletRequest request = PortalUtil.getHttpServletRequest(
353                                            portletRequest);
354    
355                                    if (BrowserSnifferUtil.isIe(request)) {
356                                            contentDispositionFileName =
357                                                    "filename=\"" + encodedFileName + "\"";
358                                    }
359                                    else {
360                                            contentDispositionFileName =
361                                                    "filename*=UTF-8''" + encodedFileName;
362                                    }
363                            }
364                    }
365                    catch (Exception e) {
366                            if (_log.isWarnEnabled()) {
367                                    _log.warn(e);
368                            }
369                    }
370    
371                    if (Validator.isNull(contentDispositionType)) {
372                            String extension = GetterUtil.getString(
373                                    FileUtil.getExtension(fileName));
374    
375                            extension = StringUtil.toLowerCase(extension);
376    
377                            String[] mimeTypesContentDispositionInline = null;
378    
379                            try {
380                                    mimeTypesContentDispositionInline = PropsUtil.getArray(
381                                            "mime.types.content.disposition.inline");
382                            }
383                            catch (Exception e) {
384                                    mimeTypesContentDispositionInline = new String[0];
385                            }
386    
387                            if (ArrayUtil.contains(
388                                            mimeTypesContentDispositionInline, extension)) {
389    
390                                    contentDispositionType = HttpHeaders.CONTENT_DISPOSITION_INLINE;
391                            }
392                            else {
393                                    contentDispositionType =
394                                            HttpHeaders.CONTENT_DISPOSITION_ATTACHMENT;
395                            }
396                    }
397    
398                    StringBundler sb = new StringBundler(4);
399    
400                    sb.append(contentDispositionType);
401                    sb.append(StringPool.SEMICOLON);
402                    sb.append(StringPool.SPACE);
403                    sb.append(contentDispositionFileName);
404    
405                    mimeResponse.setProperty(
406                            HttpHeaders.CONTENT_DISPOSITION, sb.toString());
407            }
408    
409            private static final Log _log = LogFactoryUtil.getLog(
410                    PortletResponseUtil.class);
411    
412    }