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