001    /**
002     * Copyright (c) 2000-2011 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.util.servlet;
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.StringPool;
028    import com.liferay.portal.kernel.util.StringUtil;
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
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
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
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
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
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                    setHeaders(portletRequest, mimeResponse, fileName, contentType);
119    
120                    write(mimeResponse, bytes);
121            }
122    
123            public static void sendFile(
124                            PortletRequest portletRequest, MimeResponse mimeResponse,
125                            String fileName, InputStream is)
126                    throws IOException {
127    
128                    sendFile(portletRequest, mimeResponse, fileName, is, null);
129            }
130    
131            public static void sendFile(
132                            PortletRequest portletRequest, MimeResponse mimeResponse,
133                            String fileName, InputStream is, int contentLength,
134                            String contentType)
135                    throws IOException {
136    
137                    setHeaders(portletRequest, mimeResponse, fileName, contentType);
138    
139                    write(mimeResponse, is, contentLength);
140            }
141    
142            public static void sendFile(
143                            PortletRequest portletRequest, MimeResponse mimeResponse,
144                            String fileName, InputStream is, String contentType)
145                    throws IOException {
146    
147                    sendFile(portletRequest, mimeResponse, fileName, is, 0, contentType);
148            }
149    
150            public static void write(MimeResponse mimeResponse, byte[] bytes)
151                    throws IOException {
152    
153                    write(mimeResponse, bytes, 0, 0);
154            }
155    
156            public static void write(
157                            MimeResponse mimeResponse, byte[] bytes, int offset,
158                            int contentLength)
159                    throws IOException {
160    
161                    // LEP-3122
162    
163                    if (!mimeResponse.isCommitted()) {
164    
165                            // LEP-536
166    
167                            if (contentLength == 0) {
168                                    contentLength = bytes.length;
169                            }
170    
171                            if (mimeResponse instanceof ResourceResponse) {
172                                    ResourceResponse resourceResponse =
173                                            (ResourceResponse)mimeResponse;
174    
175                                    resourceResponse.setContentLength(contentLength);
176                            }
177    
178                            OutputStream outputStream = mimeResponse.getPortletOutputStream();
179    
180                            outputStream.write(bytes, offset, contentLength);
181                    }
182            }
183    
184            public static void write(MimeResponse mimeResponse, byte[][] bytesArray)
185                    throws IOException {
186    
187                    // LEP-3122
188    
189                    if (!mimeResponse.isCommitted()) {
190    
191                            // LEP-536
192    
193                            int contentLength = 0;
194    
195                            for (byte[] bytes : bytesArray) {
196                                    contentLength += bytes.length;
197                            }
198    
199                            if (mimeResponse instanceof ResourceResponse) {
200                                    ResourceResponse resourceResponse =
201                                            (ResourceResponse)mimeResponse;
202    
203                                    resourceResponse.setContentLength(contentLength);
204                            }
205    
206                            OutputStream outputStream = mimeResponse.getPortletOutputStream();
207    
208                            for (byte[] bytes : bytesArray) {
209                                    outputStream.write(bytes);
210                            }
211                    }
212            }
213    
214            public static void write(MimeResponse mimeResponse, File file)
215                    throws IOException {
216    
217                    FileInputStream fileInputStream = new FileInputStream(file);
218    
219                    FileChannel fileChannel = fileInputStream.getChannel();
220    
221                    try {
222                            int contentLength = (int)fileChannel.size();
223    
224                            if (mimeResponse instanceof ResourceResponse) {
225                                    ResourceResponse resourceResponse =
226                                            (ResourceResponse)mimeResponse;
227    
228                                    resourceResponse.setContentLength(contentLength);
229                            }
230    
231                            fileChannel.transferTo(
232                                    0, contentLength,
233                                    Channels.newChannel(mimeResponse.getPortletOutputStream()));
234                    }
235                    finally {
236                            fileChannel.close();
237                    }
238            }
239    
240            public static void write(MimeResponse mimeResponse, InputStream is)
241                    throws IOException {
242    
243                    write(mimeResponse, is, 0);
244            }
245    
246            public static void write(
247                            MimeResponse mimeResponse, InputStream is, int contentLength)
248                    throws IOException {
249    
250                    if (mimeResponse.isCommitted()) {
251                            return;
252                    }
253    
254                    if (contentLength > 0) {
255                            if (mimeResponse instanceof ResourceResponse) {
256                                    ResourceResponse resourceResponse =
257                                            (ResourceResponse)mimeResponse;
258    
259                                    resourceResponse.setContentLength(contentLength);
260                            }
261                    }
262    
263                    StreamUtil.transfer(is, mimeResponse.getPortletOutputStream());
264            }
265    
266            public static void write(MimeResponse mimeResponse, String s)
267                    throws IOException {
268    
269                    write(mimeResponse, s.getBytes(StringPool.UTF8));
270            }
271    
272            protected static void setHeaders(
273                    PortletRequest portletRequest, MimeResponse mimeResponse,
274                    String fileName, String contentType) {
275    
276                    if (_log.isDebugEnabled()) {
277                            _log.debug("Sending file of type " + contentType);
278                    }
279    
280                    // LEP-2201
281    
282                    if (Validator.isNotNull(contentType)) {
283                            mimeResponse.setContentType(contentType);
284                    }
285    
286                    mimeResponse.setProperty(
287                            HttpHeaders.CACHE_CONTROL, HttpHeaders.CACHE_CONTROL_PUBLIC_VALUE);
288                    mimeResponse.setProperty(
289                            HttpHeaders.PRAGMA, HttpHeaders.PRAGMA_PUBLIC_VALUE);
290    
291                    if (Validator.isNotNull(fileName)) {
292                            String contentDisposition =
293                                    "attachment; filename=\"" + fileName + "\"";
294    
295                            // If necessary for non-ASCII characters, encode based on RFC 2184.
296                            // However, not all browsers support RFC 2184. See LEP-3127.
297    
298                            boolean ascii = true;
299    
300                            for (int i = 0; i < fileName.length(); i++) {
301                                    if (!Validator.isAscii(fileName.charAt(i))) {
302                                            ascii = false;
303    
304                                            break;
305                                    }
306                            }
307    
308                            try {
309                                    if (!ascii) {
310                                            String encodedFileName = HttpUtil.encodeURL(fileName, true);
311    
312                                            HttpServletRequest request =
313                                                    PortalUtil.getHttpServletRequest(portletRequest);
314    
315                                            if (BrowserSnifferUtil.isIe(request)) {
316                                                    contentDisposition =
317                                                            "attachment; filename=\"" + encodedFileName + "\"";
318                                            }
319                                            else {
320                                                    contentDisposition =
321                                                            "attachment; filename*=UTF-8''" + encodedFileName;
322                                            }
323                                    }
324                            }
325                            catch (Exception e) {
326                                    if (_log.isWarnEnabled()) {
327                                            _log.warn(e);
328                                    }
329                            }
330    
331                            String extension = GetterUtil.getString(
332                                    FileUtil.getExtension(fileName)).toLowerCase();
333    
334                            String[] mimeTypesContentDispositionInline = null;
335    
336                            try {
337                                    mimeTypesContentDispositionInline = PropsUtil.getArray(
338                                            "mime.types.content.disposition.inline");
339                            }
340                            catch (Exception e) {
341                                    mimeTypesContentDispositionInline = new String[0];
342                            }
343    
344                            if (ArrayUtil.contains(
345                                            mimeTypesContentDispositionInline, extension)) {
346    
347                                    contentDisposition = StringUtil.replace(
348                                            contentDisposition, "attachment; ", "inline; ");
349                            }
350    
351                            mimeResponse.setProperty(
352                                    HttpHeaders.CONTENT_DISPOSITION, contentDisposition);
353                    }
354            }
355    
356            private static Log _log = LogFactoryUtil.getLog(PortletResponseUtil.class);
357    
358    }