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