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.log.Log;
18  import com.liferay.portal.kernel.log.LogFactoryUtil;
19  import com.liferay.portal.kernel.servlet.HttpHeaders;
20  import com.liferay.portal.kernel.util.ArrayUtil;
21  import com.liferay.portal.kernel.util.FileUtil;
22  import com.liferay.portal.kernel.util.GetterUtil;
23  import com.liferay.portal.kernel.util.PropsUtil;
24  import com.liferay.portal.kernel.util.StreamUtil;
25  import com.liferay.portal.kernel.util.StringPool;
26  import com.liferay.portal.kernel.util.StringUtil;
27  import com.liferay.portal.kernel.util.Validator;
28  
29  import java.io.IOException;
30  import java.io.InputStream;
31  
32  import java.net.SocketException;
33  
34  import javax.servlet.ServletOutputStream;
35  import javax.servlet.http.HttpServletResponse;
36  
37  import org.apache.commons.codec.net.URLCodec;
38  import org.apache.commons.lang.CharUtils;
39  
40  /**
41   * <a href="ServletResponseUtil.java.html"><b><i>View Source</i></b></a>
42   *
43   * @author Brian Wing Shun Chan
44   */
45  public class ServletResponseUtil {
46  
47      public static void sendFile(
48              HttpServletResponse response, String fileName, byte[] bytes)
49          throws IOException {
50  
51          sendFile(response, fileName, bytes, null);
52      }
53  
54      public static void sendFile(
55              HttpServletResponse response, String fileName, byte[] bytes,
56              String contentType)
57          throws IOException {
58  
59          setHeaders(response, fileName, contentType);
60  
61          write(response, bytes);
62      }
63  
64      public static void sendFile(
65              HttpServletResponse response, String fileName, InputStream is)
66          throws IOException {
67  
68          sendFile(response, fileName, is, null);
69      }
70  
71      public static void sendFile(
72              HttpServletResponse response, String fileName, InputStream is,
73              String contentType)
74          throws IOException {
75  
76          sendFile(response, fileName, is, 0, contentType);
77      }
78  
79      public static void sendFile(
80              HttpServletResponse response, String fileName, InputStream is,
81              int contentLength, String contentType)
82          throws IOException {
83  
84          setHeaders(response, fileName, contentType);
85  
86          write(response, is, contentLength);
87      }
88  
89      public static void write(HttpServletResponse response, String s)
90          throws IOException {
91  
92          write(response, s.getBytes(StringPool.UTF8));
93      }
94  
95      public static void write(HttpServletResponse response, byte[] bytes)
96          throws IOException {
97  
98          write(response, bytes, 0);
99      }
100 
101     public static void write(
102             HttpServletResponse response, byte[] bytes, int contentLength)
103         throws IOException {
104 
105         try {
106 
107             // LEP-3122
108 
109             if (!response.isCommitted()) {
110 
111                 // LEP-536
112 
113                 if (contentLength == 0) {
114                     contentLength = bytes.length;
115                 }
116 
117                 response.setContentLength(contentLength);
118 
119                 ServletOutputStream servletOutputStream =
120                     response.getOutputStream();
121 
122                 servletOutputStream.write(bytes, 0, contentLength);
123             }
124         }
125         catch (IOException ioe) {
126             if (ioe instanceof SocketException ||
127                 ioe.getClass().getName().equals(_CLIENT_ABORT_EXCEPTION)) {
128 
129                 if (_log.isWarnEnabled()) {
130                     _log.warn(ioe);
131                 }
132             }
133             else {
134                 throw ioe;
135             }
136         }
137     }
138 
139     public static void write(HttpServletResponse response, InputStream is)
140         throws IOException {
141 
142         write(response, is, 0);
143     }
144 
145     public static void write(
146             HttpServletResponse response, InputStream is, int contentLength)
147         throws IOException {
148 
149         if (response.isCommitted()) {
150             return;
151         }
152 
153         if (contentLength > 0) {
154             response.setContentLength(contentLength);
155         }
156 
157         StreamUtil.transfer(is, response.getOutputStream());
158     }
159 
160     protected static void setHeaders(
161         HttpServletResponse response, String fileName, String contentType) {
162 
163         if (_log.isDebugEnabled()) {
164             _log.debug("Sending file of type " + contentType);
165         }
166 
167         // LEP-2201
168 
169         if (Validator.isNotNull(contentType)) {
170             response.setContentType(contentType);
171         }
172 
173         response.setHeader(
174             HttpHeaders.CACHE_CONTROL, HttpHeaders.CACHE_CONTROL_PUBLIC_VALUE);
175         response.setHeader(HttpHeaders.PRAGMA, HttpHeaders.PRAGMA_PUBLIC_VALUE);
176 
177         if (Validator.isNotNull(fileName)) {
178             String contentDisposition =
179                 "attachment; filename=\"" + fileName + "\"";
180 
181             // If necessary for non-ASCII characters, encode based on RFC 2184.
182             // However, not all browsers support RFC 2184. See LEP-3127.
183 
184             boolean ascii = true;
185 
186             for (int i = 0; i < fileName.length(); i++) {
187                 if (!CharUtils.isAscii(fileName.charAt(i))) {
188                     ascii = false;
189 
190                     break;
191                 }
192             }
193 
194             try {
195                 if (!ascii) {
196                     URLCodec codec = new URLCodec(StringPool.UTF8);
197 
198                     String encodedFileName =
199                         StringUtil.replace(codec.encode(fileName), "+", "%20");
200 
201                     contentDisposition =
202                         "attachment; filename*=UTF-8''" + encodedFileName;
203                 }
204             }
205             catch (Exception e) {
206                 if (_log.isWarnEnabled()) {
207                     _log.warn(e);
208                 }
209             }
210 
211             String extension = GetterUtil.getString(
212                 FileUtil.getExtension(fileName)).toLowerCase();
213 
214             String[] mimeTypesContentDispositionInline = null;
215 
216             try {
217                 mimeTypesContentDispositionInline = PropsUtil.getArray(
218                     "mime.types.content.disposition.inline");
219             }
220             catch (Exception e) {
221                 mimeTypesContentDispositionInline = new String[0];
222             }
223 
224             if (ArrayUtil.contains(
225                     mimeTypesContentDispositionInline, extension)) {
226 
227                 contentDisposition = StringUtil.replace(
228                     contentDisposition, "attachment; ", "inline; ");
229             }
230 
231             response.setHeader(
232                 HttpHeaders.CONTENT_DISPOSITION, contentDisposition);
233         }
234     }
235 
236     private static final String _CLIENT_ABORT_EXCEPTION =
237         "org.apache.catalina.connector.ClientAbortException";
238 
239     private static Log _log = LogFactoryUtil.getLog(ServletResponseUtil.class);
240 
241 }