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