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