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