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