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