001    /**
002     * Copyright (c) 2000-2011 Liferay, Inc. All rights reserved.
003     *
004     * The contents of this file are subject to the terms of the Liferay Enterprise
005     * Subscription License ("License"). You may not use this file except in
006     * compliance with the License. You can obtain a copy of the License by
007     * contacting Liferay, Inc. See the License for the specific language governing
008     * permissions and limitations under the License, including but not limited to
009     * distribution rights of the Software.
010     *
011     *
012     *
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                                    try {
177                                            response.flushBuffer();
178                                    }
179                                    catch (NullPointerException npe) {
180    
181                                            // http://java.net/jira/browse/GLASSFISH-17150
182    
183                                            if (!ServerDetector.isGlassfish()) {
184                                                    throw npe;
185                                            }
186    
187                                            if (_log.isDebugEnabled()) {
188                                                    _log.debug(
189                                                            "Ignoring NullPointerException because of " +
190                                                                    "GLASSFISH-17150");
191                                            }
192                                    }
193    
194                                    if (response instanceof ByteBufferServletResponse) {
195                                            ByteBufferServletResponse byteBufferResponse =
196                                                    (ByteBufferServletResponse)response;
197    
198                                            byteBufferResponse.setByteBuffer(
199                                                    ByteBuffer.wrap(bytes, offset, contentLength));
200                                    }
201                                    else {
202                                            ServletOutputStream servletOutputStream =
203                                                    response.getOutputStream();
204    
205                                            if ((contentLength == 0) && ServerDetector.isJetty()) {
206                                            }
207                                            else {
208                                                    servletOutputStream.write(bytes, offset, contentLength);
209                                            }
210                                    }
211                            }
212                    }
213                    catch (IOException ioe) {
214                            if ((ioe instanceof SocketException) ||
215                                    isClientAbortException(ioe)) {
216    
217                                    if (_log.isWarnEnabled()) {
218                                            _log.warn(ioe);
219                                    }
220                            }
221                            else {
222                                    throw ioe;
223                            }
224                    }
225            }
226    
227            public static void write(HttpServletResponse response, byte[][] bytesArray)
228                    throws IOException {
229    
230                    try {
231    
232                            // LEP-3122
233    
234                            if (!response.isCommitted()) {
235                                    int contentLength = 0;
236    
237                                    for (byte[] bytes : bytesArray) {
238                                            contentLength += bytes.length;
239                                    }
240    
241                                    response.setContentLength(contentLength);
242    
243                                    response.flushBuffer();
244    
245                                    ServletOutputStream servletOutputStream =
246                                            response.getOutputStream();
247    
248                                    for (byte[] bytes : bytesArray) {
249                                            servletOutputStream.write(bytes);
250                                    }
251                            }
252                    }
253                    catch (IOException ioe) {
254                            if ((ioe instanceof SocketException) ||
255                                    isClientAbortException(ioe)) {
256    
257                                    if (_log.isWarnEnabled()) {
258                                            _log.warn(ioe);
259                                    }
260                            }
261                            else {
262                                    throw ioe;
263                            }
264                    }
265            }
266    
267            public static void write(
268                            HttpServletResponse response, ByteBuffer byteBuffer)
269                    throws IOException {
270    
271                    if (response instanceof ByteBufferServletResponse) {
272                            ByteBufferServletResponse byteBufferResponse =
273                                    (ByteBufferServletResponse)response;
274    
275                            byteBufferResponse.setByteBuffer(byteBuffer);
276                    }
277                    else {
278                            write(
279                                    response, byteBuffer.array(), byteBuffer.position(),
280                                    byteBuffer.limit());
281                    }
282            }
283    
284            public static void write(HttpServletResponse response, File file)
285                    throws IOException {
286    
287                    if (response instanceof ByteBufferServletResponse) {
288                            ByteBufferServletResponse byteBufferResponse =
289                                    (ByteBufferServletResponse)response;
290    
291                            ByteBuffer byteBuffer = ByteBuffer.wrap(FileUtil.getBytes(file));
292    
293                            byteBufferResponse.setByteBuffer(byteBuffer);
294                    }
295                    else if (response instanceof StringServletResponse) {
296                            StringServletResponse stringResponse =
297                                    (StringServletResponse)response;
298    
299                            String s = FileUtil.read(file);
300    
301                            stringResponse.setString(s);
302                    }
303                    else {
304                            FileInputStream fileInputStream = new FileInputStream(file);
305    
306                            FileChannel fileChannel = fileInputStream.getChannel();
307    
308                            try {
309                                    int contentLength = (int)fileChannel.size();
310    
311                                    response.setContentLength(contentLength);
312    
313                                    response.flushBuffer();
314    
315                                    fileChannel.transferTo(
316                                            0, contentLength,
317                                            Channels.newChannel(response.getOutputStream()));
318                            }
319                            finally {
320                                    fileChannel.close();
321                            }
322                    }
323            }
324    
325            public static void write(HttpServletResponse response, InputStream is)
326                    throws IOException {
327    
328                    write(response, is, 0);
329            }
330    
331            public static void write(
332                            HttpServletResponse response, InputStream is, long contentLength)
333                    throws IOException {
334    
335                    if (response.isCommitted()) {
336                            return;
337                    }
338    
339                    if (contentLength > 0) {
340                            response.setHeader(
341                                    HttpHeaders.CONTENT_LENGTH, String.valueOf(contentLength));
342                    }
343    
344                    response.flushBuffer();
345    
346                    StreamUtil.transfer(is, response.getOutputStream());
347            }
348    
349            public static void write(HttpServletResponse response, String s)
350                    throws IOException {
351    
352                    if (response instanceof StringServletResponse) {
353                            StringServletResponse stringResponse =
354                                    (StringServletResponse)response;
355    
356                            stringResponse.setString(s);
357                    }
358                    else {
359                            ByteBuffer byteBuffer = CharsetEncoderUtil.encode(
360                                    StringPool.UTF8, s);
361    
362                            write(response, byteBuffer);
363                    }
364            }
365    
366            public static void write(
367                            HttpServletResponse response, StringServletResponse stringResponse)
368                    throws IOException {
369    
370                    if (stringResponse.isCalledGetOutputStream()) {
371                            UnsyncByteArrayOutputStream unsyncByteArrayOutputStream =
372                                    stringResponse.getUnsyncByteArrayOutputStream();
373    
374                            ByteBuffer byteBuffer =
375                                    unsyncByteArrayOutputStream.unsafeGetByteBuffer();
376    
377                            write(response, byteBuffer);
378                    }
379                    else {
380                            write(response, stringResponse.getString());
381                    }
382            }
383    
384            protected static boolean isClientAbortException(IOException ioe) {
385                    Class<?> clazz = ioe.getClass();
386    
387                    String className = clazz.getName();
388    
389                    if (className.equals(_CLIENT_ABORT_EXCEPTION)) {
390                            return true;
391                    }
392                    else {
393                            return false;
394                    }
395            }
396    
397            protected static void setHeaders(
398                    HttpServletRequest request, HttpServletResponse response,
399                    String fileName, String contentType) {
400    
401                    if (_log.isDebugEnabled()) {
402                            _log.debug("Sending file of type " + contentType);
403                    }
404    
405                    // LEP-2201
406    
407                    if (Validator.isNotNull(contentType)) {
408                            response.setContentType(contentType);
409                    }
410    
411                    response.setHeader(
412                            HttpHeaders.CACHE_CONTROL, HttpHeaders.CACHE_CONTROL_PUBLIC_VALUE);
413                    response.setHeader(HttpHeaders.PRAGMA, HttpHeaders.PRAGMA_PUBLIC_VALUE);
414    
415                    if (Validator.isNotNull(fileName)) {
416                            String contentDisposition =
417                                    "attachment; filename=\"" + fileName + "\"";
418    
419                            // If necessary for non-ASCII characters, encode based on RFC 2184.
420                            // However, not all browsers support RFC 2184. See LEP-3127.
421    
422                            boolean ascii = true;
423    
424                            for (int i = 0; i < fileName.length(); i++) {
425                                    if (!Validator.isAscii(fileName.charAt(i))) {
426                                            ascii = false;
427    
428                                            break;
429                                    }
430                            }
431    
432                            try {
433                                    if (!ascii) {
434                                            String encodedFileName = HttpUtil.encodeURL(fileName, true);
435    
436                                            if (BrowserSnifferUtil.isIe(request)) {
437                                                    contentDisposition =
438                                                            "attachment; filename=\"" + encodedFileName + "\"";
439                                            }
440                                            else {
441                                                    contentDisposition =
442                                                            "attachment; filename*=UTF-8''" + encodedFileName;
443                                            }
444                                    }
445                            }
446                            catch (Exception e) {
447                                    if (_log.isWarnEnabled()) {
448                                            _log.warn(e);
449                                    }
450                            }
451    
452                            String extension = GetterUtil.getString(
453                                    FileUtil.getExtension(fileName)).toLowerCase();
454    
455                            String[] mimeTypesContentDispositionInline = null;
456    
457                            try {
458                                    mimeTypesContentDispositionInline = PropsUtil.getArray(
459                                            "mime.types.content.disposition.inline");
460                            }
461                            catch (Exception e) {
462                                    mimeTypesContentDispositionInline = new String[0];
463                            }
464    
465                            if (ArrayUtil.contains(
466                                            mimeTypesContentDispositionInline, extension)) {
467    
468                                    contentDisposition = StringUtil.replace(
469                                            contentDisposition, "attachment; ", "inline; ");
470                            }
471    
472                            response.setHeader(
473                                    HttpHeaders.CONTENT_DISPOSITION, contentDisposition);
474                    }
475            }
476    
477            private static final String _CLIENT_ABORT_EXCEPTION =
478                    "org.apache.catalina.connector.ClientAbortException";
479    
480            private static Log _log = LogFactoryUtil.getLog(ServletResponseUtil.class);
481    
482    }