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