1   /**
2    * Copyright (c) 2000-2010 Liferay, Inc. All rights reserved.
3    *
4    * This library is free software; you can redistribute it and/or modify it under
5    * the terms of the GNU Lesser General Public License as published by the Free
6    * Software Foundation; either version 2.1 of the License, or (at your option)
7    * any later version.
8    *
9    * This library is distributed in the hope that it will be useful, but WITHOUT
10   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11   * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
12   * details.
13   */
14  
15  package com.liferay.util.servlet;
16  
17  import com.liferay.portal.kernel.io.unsync.UnsyncByteArrayOutputStream;
18  import com.liferay.portal.kernel.log.Log;
19  import com.liferay.portal.kernel.log.LogFactoryUtil;
20  import com.liferay.portal.kernel.servlet.BrowserSnifferUtil;
21  import com.liferay.portal.kernel.servlet.HttpHeaders;
22  import com.liferay.portal.kernel.servlet.StringServletResponse;
23  import com.liferay.portal.kernel.util.ArrayUtil;
24  import com.liferay.portal.kernel.util.FileUtil;
25  import com.liferay.portal.kernel.util.GetterUtil;
26  import com.liferay.portal.kernel.util.PropsUtil;
27  import com.liferay.portal.kernel.util.StreamUtil;
28  import com.liferay.portal.kernel.util.StringPool;
29  import com.liferay.portal.kernel.util.StringUtil;
30  import com.liferay.portal.kernel.util.Validator;
31  
32  import java.io.IOException;
33  import java.io.InputStream;
34  
35  import java.net.SocketException;
36  
37  import javax.servlet.ServletOutputStream;
38  import javax.servlet.http.HttpServletRequest;
39  import javax.servlet.http.HttpServletResponse;
40  
41  import org.apache.commons.codec.net.URLCodec;
42  import org.apache.commons.lang.CharUtils;
43  
44  /**
45   * <a href="ServletResponseUtil.java.html"><b><i>View Source</i></b></a>
46   *
47   * @author Brian Wing Shun Chan
48   * @author Shuyang Zhou
49   */
50  public class ServletResponseUtil {
51  
52      public static void sendFile(
53              HttpServletRequest request, HttpServletResponse response,
54              String fileName, byte[] bytes)
55          throws IOException {
56  
57          sendFile(request, response, fileName, bytes, null);
58      }
59  
60      public static void sendFile(
61              HttpServletRequest request, HttpServletResponse response,
62              String fileName, byte[] bytes, String contentType)
63          throws IOException {
64  
65          setHeaders(request, response, fileName, contentType);
66  
67          write(response, bytes);
68      }
69  
70      public static void sendFile(
71              HttpServletRequest request, HttpServletResponse response,
72              String fileName, InputStream is)
73          throws IOException {
74  
75          sendFile(request, response, fileName, is, null);
76      }
77  
78      public static void sendFile(
79              HttpServletRequest request, HttpServletResponse response,
80              String fileName, InputStream is, int contentLength,
81              String contentType)
82          throws IOException {
83  
84          setHeaders(request, response, fileName, contentType);
85  
86          write(response, is, contentLength);
87      }
88  
89      public static void sendFile(
90              HttpServletRequest request, HttpServletResponse response,
91              String fileName, InputStream is, String contentType)
92          throws IOException {
93  
94          sendFile(request, response, fileName, is, 0, contentType);
95      }
96  
97      /**
98       * @deprecated
99       */
100     public static void sendFile(
101             HttpServletResponse response, String fileName, byte[] bytes)
102         throws IOException {
103 
104         sendFile(null, response, fileName, bytes);
105     }
106 
107     /**
108      * @deprecated
109      */
110     public static void sendFile(
111             HttpServletResponse response, String fileName, byte[] bytes,
112             String contentType)
113         throws IOException {
114 
115         sendFile(null, response, fileName, bytes, contentType);
116     }
117 
118     /**
119      * @deprecated
120      */
121     public static void sendFile(
122             HttpServletResponse response, String fileName, InputStream is)
123         throws IOException {
124 
125         sendFile(null, response, fileName, is);
126     }
127 
128     /**
129      * @deprecated
130      */
131     public static void sendFile(
132             HttpServletResponse response, String fileName, InputStream is,
133             int contentLength, String contentType)
134         throws IOException {
135 
136         sendFile(null, response, fileName, is, contentLength, contentType);
137     }
138 
139     /**
140      * @deprecated
141      */
142     public static void sendFile(
143             HttpServletResponse response, String fileName, InputStream is,
144             String contentType)
145         throws IOException {
146 
147         sendFile(null, response, fileName, is, contentType);
148     }
149 
150     public static void write(HttpServletResponse response, byte[] bytes)
151         throws IOException {
152 
153         write(response, bytes, 0);
154     }
155 
156     public static void write(
157             HttpServletResponse response, byte[] bytes, int contentLength)
158         throws IOException {
159 
160         try {
161 
162             // LEP-3122
163 
164             if (!response.isCommitted()) {
165 
166                 // LEP-536
167 
168                 if (contentLength == 0) {
169                     contentLength = bytes.length;
170                 }
171 
172                 response.setContentLength(contentLength);
173 
174                 ServletOutputStream servletOutputStream =
175                     response.getOutputStream();
176 
177                 servletOutputStream.write(bytes, 0, contentLength);
178             }
179         }
180         catch (IOException ioe) {
181             if (ioe instanceof SocketException ||
182                 ioe.getClass().getName().equals(_CLIENT_ABORT_EXCEPTION)) {
183 
184                 if (_log.isWarnEnabled()) {
185                     _log.warn(ioe);
186                 }
187             }
188             else {
189                 throw ioe;
190             }
191         }
192     }
193 
194     public static void write(HttpServletResponse response, InputStream is)
195         throws IOException {
196 
197         write(response, is, 0);
198     }
199 
200     public static void write(
201             HttpServletResponse response, InputStream is, int contentLength)
202         throws IOException {
203 
204         if (response.isCommitted()) {
205             return;
206         }
207 
208         if (contentLength > 0) {
209             response.setContentLength(contentLength);
210         }
211 
212         StreamUtil.transfer(is, response.getOutputStream());
213     }
214 
215     public static void write(HttpServletResponse response, String s)
216         throws IOException {
217 
218         write(response, s.getBytes(StringPool.UTF8));
219     }
220 
221     public static void write(
222             HttpServletResponse response, StringServletResponse stringResponse)
223         throws IOException {
224 
225         if (stringResponse.isCalledGetOutputStream()) {
226             UnsyncByteArrayOutputStream unsyncByteArrayInputStream =
227                 stringResponse.getUnsyncByteArrayOutputStream();
228 
229             write(
230                 response, unsyncByteArrayInputStream.unsafeGetByteArray(),
231                 unsyncByteArrayInputStream.size());
232         }
233         else {
234             write(response, stringResponse.getString());
235         }
236     }
237 
238     protected static void setHeaders(
239         HttpServletRequest request, HttpServletResponse response,
240         String fileName, String contentType) {
241 
242         if (_log.isDebugEnabled()) {
243             _log.debug("Sending file of type " + contentType);
244         }
245 
246         // LEP-2201
247 
248         if (Validator.isNotNull(contentType)) {
249             response.setContentType(contentType);
250         }
251 
252         response.setHeader(
253             HttpHeaders.CACHE_CONTROL, HttpHeaders.CACHE_CONTROL_PUBLIC_VALUE);
254         response.setHeader(HttpHeaders.PRAGMA, HttpHeaders.PRAGMA_PUBLIC_VALUE);
255 
256         if (Validator.isNotNull(fileName)) {
257             String contentDisposition =
258                 "attachment; filename=\"" + fileName + "\"";
259 
260             // If necessary for non-ASCII characters, encode based on RFC 2184.
261             // However, not all browsers support RFC 2184. See LEP-3127.
262 
263             boolean ascii = true;
264 
265             for (int i = 0; i < fileName.length(); i++) {
266                 if (!CharUtils.isAscii(fileName.charAt(i))) {
267                     ascii = false;
268 
269                     break;
270                 }
271             }
272 
273             try {
274                 if (!ascii) {
275                     URLCodec codec = new URLCodec(StringPool.UTF8);
276 
277                     String encodedFileName =
278                         StringUtil.replace(codec.encode(fileName), "+", "%20");
279 
280                     if (BrowserSnifferUtil.isIe(request)) {
281                         contentDisposition =
282                             "attachment; filename=\"" + encodedFileName + "\"";
283                     }
284                     else {
285                         contentDisposition =
286                             "attachment; filename*=UTF-8''" + encodedFileName;
287                     }
288                 }
289             }
290             catch (Exception e) {
291                 if (_log.isWarnEnabled()) {
292                     _log.warn(e);
293                 }
294             }
295 
296             String extension = GetterUtil.getString(
297                 FileUtil.getExtension(fileName)).toLowerCase();
298 
299             String[] mimeTypesContentDispositionInline = null;
300 
301             try {
302                 mimeTypesContentDispositionInline = PropsUtil.getArray(
303                     "mime.types.content.disposition.inline");
304             }
305             catch (Exception e) {
306                 mimeTypesContentDispositionInline = new String[0];
307             }
308 
309             if (ArrayUtil.contains(
310                     mimeTypesContentDispositionInline, extension)) {
311 
312                 contentDisposition = StringUtil.replace(
313                     contentDisposition, "attachment; ", "inline; ");
314             }
315 
316             response.setHeader(
317                 HttpHeaders.CONTENT_DISPOSITION, contentDisposition);
318         }
319     }
320 
321     private static Log _log = LogFactoryUtil.getLog(ServletResponseUtil.class);
322 
323     private static final String _CLIENT_ABORT_EXCEPTION =
324         "org.apache.catalina.connector.ClientAbortException";
325 
326 }