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.ServerDetector;
33  import com.liferay.portal.kernel.util.StringPool;
34  import com.liferay.portal.kernel.util.StringUtil;
35  import com.liferay.portal.kernel.util.Validator;
36  
37  import java.io.BufferedOutputStream;
38  import java.io.IOException;
39  import java.io.InputStream;
40  import java.io.OutputStream;
41  
42  import java.net.SocketException;
43  
44  import javax.servlet.http.HttpServletResponse;
45  
46  import org.apache.commons.codec.net.URLCodec;
47  import org.apache.commons.lang.CharUtils;
48  
49  /**
50   * <a href="ServletResponseUtil.java.html"><b><i>View Source</i></b></a>
51   *
52   * @author Brian Wing Shun Chan
53   *
54   */
55  public class ServletResponseUtil {
56  
57      public static void cleanUp(InputStream is) {
58          try {
59              if (is != null) {
60                  is.close();
61              }
62          }
63          catch (Exception e) {
64              if (_log.isWarnEnabled()) {
65                  _log.warn(e);
66              }
67          }
68      }
69  
70      public static void cleanUp(OutputStream os) {
71          try {
72              if (os != null) {
73                  os.flush();
74              }
75          }
76          catch (Exception e) {
77              if (_log.isWarnEnabled()) {
78                  _log.warn(e);
79              }
80          }
81  
82          try {
83              if (os != null) {
84                  os.close();
85              }
86          }
87          catch (Exception e) {
88              if (_log.isWarnEnabled()) {
89                  _log.warn(e);
90              }
91          }
92      }
93  
94      public static void cleanUp(OutputStream os, InputStream is) {
95          cleanUp(os);
96          cleanUp(is);
97      }
98  
99      public static void sendFile(
100             HttpServletResponse response, String fileName, byte[] bytes)
101         throws IOException {
102 
103         sendFile(response, fileName, bytes, null);
104     }
105 
106     public static void sendFile(
107             HttpServletResponse response, String fileName, byte[] bytes,
108             String contentType)
109         throws IOException {
110 
111         setHeaders(response, fileName, contentType);
112 
113         write(response, bytes);
114     }
115 
116     public static void sendFile(
117             HttpServletResponse response, String fileName, InputStream is)
118         throws IOException {
119 
120         sendFile(response, fileName, is, null);
121     }
122 
123     public static void sendFile(
124             HttpServletResponse response, String fileName, InputStream is,
125             String contentType)
126         throws IOException {
127 
128         sendFile(response, fileName, is, 0, contentType);
129     }
130 
131     public static void sendFile(
132             HttpServletResponse response, String fileName, InputStream is,
133             int contentLength, String contentType)
134         throws IOException {
135 
136         setHeaders(response, fileName, contentType);
137 
138         write(response, is, contentLength);
139     }
140 
141     public static void write(HttpServletResponse response, String s)
142         throws IOException {
143 
144         write(response, s.getBytes(StringPool.UTF8));
145     }
146 
147     public static void write(HttpServletResponse response, byte[] bytes)
148         throws IOException {
149 
150         write(response, bytes, 0);
151     }
152 
153     public static void write(
154             HttpServletResponse response, byte[] bytes, int contentLength)
155         throws IOException {
156 
157         OutputStream os = null;
158 
159         try {
160 
161             // LEP-3122
162 
163             if (!response.isCommitted() || ServerDetector.isPramati()) {
164 
165                 // LEP-536
166 
167                 if (contentLength == 0) {
168                     contentLength = bytes.length;
169                 }
170 
171                 response.setContentLength(contentLength);
172 
173                 os = new BufferedOutputStream(response.getOutputStream());
174 
175                 os.write(bytes, 0, contentLength);
176             }
177         }
178         catch (IOException ioe) {
179             if (ioe instanceof SocketException ||
180                 ioe.getClass().getName().equals(_CLIENT_ABORT_EXCEPTION)) {
181 
182                 if (_log.isWarnEnabled()) {
183                     _log.warn(ioe);
184                 }
185             }
186             else {
187                 throw ioe;
188             }
189         }
190         finally {
191             cleanUp(os);
192         }
193     }
194 
195     public static void write(HttpServletResponse response, InputStream is)
196         throws IOException {
197 
198         write(response, is, 0);
199     }
200 
201     public static void write(
202             HttpServletResponse response, InputStream is, int contentLength)
203         throws IOException {
204 
205         OutputStream os = null;
206 
207         try {
208             if (!response.isCommitted()) {
209                 if (contentLength > 0) {
210                     response.setContentLength(contentLength);
211                 }
212 
213                 os = new BufferedOutputStream(response.getOutputStream());
214 
215                 int c = is.read();
216 
217                 while (c != -1) {
218                     os.write(c);
219 
220                     c = is.read();
221                 }
222             }
223         }
224         finally {
225             cleanUp(os, is);
226         }
227     }
228 
229     protected static void setHeaders(
230         HttpServletResponse response, String fileName, String contentType) {
231 
232         if (_log.isDebugEnabled()) {
233             _log.debug("Sending file of type " + contentType);
234         }
235 
236         // LEP-2201
237 
238         if (Validator.isNotNull(contentType)) {
239             response.setContentType(contentType);
240         }
241 
242         response.setHeader(
243             HttpHeaders.CACHE_CONTROL, HttpHeaders.CACHE_CONTROL_PUBLIC_VALUE);
244         response.setHeader(HttpHeaders.PRAGMA, HttpHeaders.PRAGMA_PUBLIC_VALUE);
245 
246         if (Validator.isNotNull(fileName)) {
247             String contentDisposition =
248                 "attachment; filename=\"" + fileName + "\"";
249 
250             // If necessary for non-ASCII characters, encode based on RFC 2184.
251             // However, not all browsers support RFC 2184. See LEP-3127.
252 
253             boolean ascii = true;
254 
255             for (int i = 0; i < fileName.length(); i++) {
256                 if (!CharUtils.isAscii(fileName.charAt(i))) {
257                     ascii = false;
258 
259                     break;
260                 }
261             }
262 
263             try {
264                 if (!ascii) {
265                     URLCodec codec = new URLCodec(StringPool.UTF8);
266 
267                     String encodedFileName =
268                         StringUtil.replace(codec.encode(fileName), "+", "%20");
269 
270                     contentDisposition =
271                         "attachment; filename*=UTF-8''" + encodedFileName;
272                 }
273             }
274             catch (Exception e) {
275                 if (_log.isWarnEnabled()) {
276                     _log.warn(e);
277                 }
278             }
279 
280             String extension = GetterUtil.getString(
281                 FileUtil.getExtension(fileName)).toLowerCase();
282 
283             String[] mimeTypesContentDispositionInline = null;
284 
285             try {
286                 mimeTypesContentDispositionInline = PropsUtil.getArray(
287                     "mime.types.content.disposition.inline");
288             }
289             catch (Exception e) {
290                 mimeTypesContentDispositionInline = new String[0];
291             }
292 
293             if (ArrayUtil.contains(
294                     mimeTypesContentDispositionInline, extension)) {
295 
296                 contentDisposition = StringUtil.replace(
297                     contentDisposition, "attachment; ", "inline; ");
298             }
299 
300             response.setHeader(
301                 HttpHeaders.CONTENT_DISPOSITION, contentDisposition);
302         }
303     }
304 
305     private static final String _CLIENT_ABORT_EXCEPTION =
306         "org.apache.catalina.connector.ClientAbortException";
307 
308     private static Log _log = LogFactoryUtil.getLog(ServletResponseUtil.class);
309 
310 }