1   /**
2    * Copyright (c) 2000-2009 Liferay, Inc. All rights reserved.
3    *
4    * Permission is hereby granted, free of charge, to any person obtaining a copy
5    * of this software and associated documentation files (the "Software"), to deal
6    * in the Software without restriction, including without limitation the rights
7    * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8    * copies of the Software, and to permit persons to whom the Software is
9    * furnished to do so, subject to the following conditions:
10   *
11   * The above copyright notice and this permission notice shall be included in
12   * all copies or substantial portions of the Software.
13   *
14   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20   * SOFTWARE.
21   */
22  
23  package com.liferay.util.servlet;
24  
25  import com.liferay.portal.kernel.log.Log;
26  import com.liferay.portal.kernel.log.LogFactoryUtil;
27  import com.liferay.portal.kernel.servlet.HttpHeaders;
28  import com.liferay.portal.kernel.util.ArrayUtil;
29  import com.liferay.portal.kernel.util.FileUtil;
30  import com.liferay.portal.kernel.util.GetterUtil;
31  import com.liferay.portal.kernel.util.PropsUtil;
32  import com.liferay.portal.kernel.util.StringPool;
33  import com.liferay.portal.kernel.util.StringUtil;
34  import com.liferay.portal.kernel.util.Validator;
35  
36  import java.io.BufferedOutputStream;
37  import java.io.IOException;
38  import java.io.InputStream;
39  import java.io.OutputStream;
40  
41  import java.net.SocketException;
42  
43  import javax.servlet.http.HttpServletResponse;
44  
45  import org.apache.commons.codec.net.URLCodec;
46  import org.apache.commons.lang.CharUtils;
47  
48  /**
49   * <a href="ServletResponseUtil.java.html"><b><i>View Source</i></b></a>
50   *
51   * @author Brian Wing Shun Chan
52   *
53   */
54  public class ServletResponseUtil {
55  
56      public static void cleanUp(InputStream is) {
57          try {
58              if (is != null) {
59                  is.close();
60              }
61          }
62          catch (Exception e) {
63              if (_log.isWarnEnabled()) {
64                  _log.warn(e);
65              }
66          }
67      }
68  
69      public static void cleanUp(OutputStream os) {
70          try {
71              if (os != null) {
72                  os.flush();
73              }
74          }
75          catch (Exception e) {
76              if (_log.isWarnEnabled()) {
77                  _log.warn(e);
78              }
79          }
80  
81          try {
82              if (os != null) {
83                  os.close();
84              }
85          }
86          catch (Exception e) {
87              if (_log.isWarnEnabled()) {
88                  _log.warn(e);
89              }
90          }
91      }
92  
93      public static void cleanUp(OutputStream os, InputStream is) {
94          cleanUp(os);
95          cleanUp(is);
96      }
97  
98      public static void sendFile(
99              HttpServletResponse response, String fileName, byte[] bytes)
100         throws IOException {
101 
102         sendFile(response, fileName, bytes, null);
103     }
104 
105     public static void sendFile(
106             HttpServletResponse response, String fileName, byte[] bytes,
107             String contentType)
108         throws IOException {
109 
110         setHeaders(response, fileName, contentType);
111 
112         write(response, bytes);
113     }
114 
115     public static void sendFile(
116             HttpServletResponse response, String fileName, InputStream is)
117         throws IOException {
118 
119         sendFile(response, fileName, is, null);
120     }
121 
122     public static void sendFile(
123             HttpServletResponse response, String fileName, InputStream is,
124             String contentType)
125         throws IOException {
126 
127         sendFile(response, fileName, is, 0, contentType);
128     }
129 
130     public static void sendFile(
131             HttpServletResponse response, String fileName, InputStream is,
132             int contentLength, String contentType)
133         throws IOException {
134 
135         setHeaders(response, fileName, contentType);
136 
137         write(response, is, contentLength);
138     }
139 
140     public static void write(HttpServletResponse response, String s)
141         throws IOException {
142 
143         write(response, s.getBytes(StringPool.UTF8));
144     }
145 
146     public static void write(HttpServletResponse response, byte[] bytes)
147         throws IOException {
148 
149         write(response, bytes, 0);
150     }
151 
152     public static void write(
153             HttpServletResponse response, byte[] bytes, int contentLength)
154         throws IOException {
155 
156         OutputStream os = null;
157 
158         try {
159 
160             // LEP-3122
161 
162             if (!response.isCommitted()) {
163 
164                 // LEP-536
165 
166                 if (contentLength == 0) {
167                     contentLength = bytes.length;
168                 }
169 
170                 response.setContentLength(contentLength);
171 
172                 os = new BufferedOutputStream(response.getOutputStream());
173 
174                 os.write(bytes, 0, contentLength);
175             }
176         }
177         catch (IOException ioe) {
178             if (ioe instanceof SocketException ||
179                 ioe.getClass().getName().equals(_CLIENT_ABORT_EXCEPTION)) {
180 
181                 if (_log.isWarnEnabled()) {
182                     _log.warn(ioe);
183                 }
184             }
185             else {
186                 throw ioe;
187             }
188         }
189         finally {
190             cleanUp(os);
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         OutputStream os = null;
205 
206         try {
207             if (!response.isCommitted()) {
208                 if (contentLength > 0) {
209                     response.setContentLength(contentLength);
210                 }
211 
212                 os = new BufferedOutputStream(response.getOutputStream());
213 
214                 int c = is.read();
215 
216                 while (c != -1) {
217                     os.write(c);
218 
219                     c = is.read();
220                 }
221             }
222         }
223         finally {
224             cleanUp(os, is);
225         }
226     }
227 
228     protected static void setHeaders(
229         HttpServletResponse response, String fileName, String contentType) {
230 
231         if (_log.isDebugEnabled()) {
232             _log.debug("Sending file of type " + contentType);
233         }
234 
235         // LEP-2201
236 
237         if (Validator.isNotNull(contentType)) {
238             response.setContentType(contentType);
239         }
240 
241         response.setHeader(
242             HttpHeaders.CACHE_CONTROL, HttpHeaders.CACHE_CONTROL_PUBLIC_VALUE);
243         response.setHeader(HttpHeaders.PRAGMA, HttpHeaders.PRAGMA_PUBLIC_VALUE);
244 
245         if (Validator.isNotNull(fileName)) {
246             String contentDisposition =
247                 "attachment; filename=\"" + fileName + "\"";
248 
249             // If necessary for non-ASCII characters, encode based on RFC 2184.
250             // However, not all browsers support RFC 2184. See LEP-3127.
251 
252             boolean ascii = true;
253 
254             for (int i = 0; i < fileName.length(); i++) {
255                 if (!CharUtils.isAscii(fileName.charAt(i))) {
256                     ascii = false;
257 
258                     break;
259                 }
260             }
261 
262             try {
263                 if (!ascii) {
264                     URLCodec codec = new URLCodec(StringPool.UTF8);
265 
266                     String encodedFileName =
267                         StringUtil.replace(codec.encode(fileName), "+", "%20");
268 
269                     contentDisposition =
270                         "attachment; filename*=UTF-8''" + encodedFileName;
271                 }
272             }
273             catch (Exception e) {
274                 if (_log.isWarnEnabled()) {
275                     _log.warn(e);
276                 }
277             }
278 
279             String extension = GetterUtil.getString(
280                 FileUtil.getExtension(fileName)).toLowerCase();
281 
282             String[] mimeTypesContentDispositionInline = null;
283 
284             try {
285                 mimeTypesContentDispositionInline = PropsUtil.getArray(
286                     "mime.types.content.disposition.inline");
287             }
288             catch (Exception e) {
289                 mimeTypesContentDispositionInline = new String[0];
290             }
291 
292             if (ArrayUtil.contains(
293                     mimeTypesContentDispositionInline, extension)) {
294 
295                 contentDisposition = StringUtil.replace(
296                     contentDisposition, "attachment; ", "inline; ");
297             }
298 
299             response.setHeader(
300                 HttpHeaders.CONTENT_DISPOSITION, contentDisposition);
301         }
302     }
303 
304     private static final String _CLIENT_ABORT_EXCEPTION =
305         "org.apache.catalina.connector.ClientAbortException";
306 
307     private static Log _log = LogFactoryUtil.getLog(ServletResponseUtil.class);
308 
309 }