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