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