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