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.portal.servlet.filters.strip;
24  
25  import com.liferay.portal.kernel.log.Log;
26  import com.liferay.portal.kernel.log.LogFactoryUtil;
27  import com.liferay.portal.kernel.portlet.LiferayWindowState;
28  import com.liferay.portal.kernel.util.GetterUtil;
29  import com.liferay.portal.kernel.util.HttpUtil;
30  import com.liferay.portal.kernel.util.JavaConstants;
31  import com.liferay.portal.kernel.util.ParamUtil;
32  import com.liferay.portal.servlet.filters.BasePortalFilter;
33  import com.liferay.util.servlet.ServletResponseUtil;
34  
35  import java.io.IOException;
36  
37  import javax.servlet.FilterChain;
38  import javax.servlet.ServletException;
39  import javax.servlet.http.HttpServletRequest;
40  import javax.servlet.http.HttpServletResponse;
41  
42  /**
43   * <a href="StripFilter.java.html"><b><i>View Source</i></b></a>
44   *
45   * @author Brian Wing Shun Chan
46   * @author Raymond Augé
47   *
48   */
49  public class StripFilter extends BasePortalFilter {
50  
51      public static final String SKIP_FILTER =
52          StripFilter.class.getName() + "SKIP_FILTER";
53  
54      protected boolean isAlreadyFiltered(HttpServletRequest request) {
55          if (request.getAttribute(SKIP_FILTER) != null) {
56              return true;
57          }
58          else {
59              return false;
60          }
61      }
62  
63      protected boolean isInclude(HttpServletRequest request) {
64          String uri = (String)request.getAttribute(
65              JavaConstants.JAVAX_SERVLET_INCLUDE_REQUEST_URI);
66  
67          if (uri == null) {
68              return false;
69          }
70          else {
71              return true;
72          }
73      }
74  
75      protected boolean isStrip(HttpServletRequest request) {
76          if (!ParamUtil.getBoolean(request, _STRIP, true)) {
77              return false;
78          }
79          else {
80  
81              // Modifying binary content through a servlet filter under certain
82              // conditions is bad on performance the user will not start
83              // downloading the content until the entire content is modified.
84  
85              String lifecycle = ParamUtil.getString(request, "p_p_lifecycle");
86  
87              if ((lifecycle.equals("1") &&
88                   LiferayWindowState.isExclusive(request)) ||
89                  lifecycle.equals("2")) {
90  
91                  return false;
92              }
93              else {
94                  return true;
95              }
96          }
97      }
98  
99      protected void processFilter(
100             HttpServletRequest request, HttpServletResponse response,
101             FilterChain filterChain)
102         throws IOException, ServletException {
103 
104         String completeURL = HttpUtil.getCompleteURL(request);
105 
106         if (isStrip(request) && !isInclude(request) &&
107             !isAlreadyFiltered(request)) {
108 
109             if (_log.isDebugEnabled()) {
110                 _log.debug("Stripping " + completeURL);
111             }
112 
113             request.setAttribute(SKIP_FILTER, Boolean.TRUE);
114 
115             StripResponse stripResponse = new StripResponse(response);
116 
117             processFilter(
118                 StripFilter.class, request, stripResponse, filterChain);
119 
120             String contentType = GetterUtil.getString(
121                 stripResponse.getContentType());
122 
123             byte[] oldByteArray = stripResponse.getData();
124 
125             if ((oldByteArray != null) && (oldByteArray.length > 0)) {
126                 byte[] newByteArray = new byte[oldByteArray.length];
127                 int newByteArrayPos = 0;
128 
129                 if (_log.isDebugEnabled()) {
130                     _log.debug("Stripping content of type " + contentType);
131                 }
132 
133                 if (contentType.toLowerCase().indexOf("text/") != -1) {
134                     boolean ignore = false;
135                     char prevChar = '\n';
136 
137                     for (int i = 0; i < oldByteArray.length; i++) {
138                         byte b = oldByteArray[i];
139                         char c = (char)b;
140 
141                         if (c == '<') {
142 
143                             // Ignore text inside certain HTML tags.
144 
145                             if (!ignore) {
146 
147                                 // Check for <pre>
148 
149                                 if ((i + 4) < oldByteArray.length) {
150                                     char c1 = (char)oldByteArray[i + 1];
151                                     char c2 = (char)oldByteArray[i + 2];
152                                     char c3 = (char)oldByteArray[i + 3];
153                                     char c4 = (char)oldByteArray[i + 4];
154 
155                                     if (((c1 == 'p') || (c1 == 'P')) &&
156                                         ((c2 == 'r') || (c2 == 'R')) &&
157                                         ((c3 == 'e') || (c3 == 'E')) &&
158                                         ((c4 == '>'))) {
159 
160                                         ignore = true;
161                                     }
162                                 }
163 
164                                 // Check for <textarea
165 
166                                 if (!ignore &&
167                                     ((i + 9) < oldByteArray.length)) {
168 
169                                     char c1 = (char)oldByteArray[i + 1];
170                                     char c2 = (char)oldByteArray[i + 2];
171                                     char c3 = (char)oldByteArray[i + 3];
172                                     char c4 = (char)oldByteArray[i + 4];
173                                     char c5 = (char)oldByteArray[i + 5];
174                                     char c6 = (char)oldByteArray[i + 6];
175                                     char c7 = (char)oldByteArray[i + 7];
176                                     char c8 = (char)oldByteArray[i + 8];
177                                     char c9 = (char)oldByteArray[i + 9];
178 
179                                     if (((c1 == 't') || (c1 == 'T')) &&
180                                         ((c2 == 'e') || (c2 == 'E')) &&
181                                         ((c3 == 'x') || (c3 == 'X')) &&
182                                         ((c4 == 't') || (c4 == 'T')) &&
183                                         ((c5 == 'a') || (c5 == 'A')) &&
184                                         ((c6 == 'r') || (c6 == 'R')) &&
185                                         ((c7 == 'e') || (c7 == 'E')) &&
186                                         ((c8 == 'a') || (c8 == 'A')) &&
187                                         ((c9 == ' '))) {
188 
189                                         ignore = true;
190                                     }
191                                 }
192                             }
193                             else if (ignore) {
194 
195                                 // Check for </pre>
196 
197                                 if ((i + 5) < oldByteArray.length) {
198                                     char c1 = (char)oldByteArray[i + 1];
199                                     char c2 = (char)oldByteArray[i + 2];
200                                     char c3 = (char)oldByteArray[i + 3];
201                                     char c4 = (char)oldByteArray[i + 4];
202                                     char c5 = (char)oldByteArray[i + 5];
203 
204                                     if (((c1 == '/')) &&
205                                         ((c2 == 'p') || (c2 == 'P')) &&
206                                         ((c3 == 'r') || (c3 == 'R')) &&
207                                         ((c4 == 'e') || (c4 == 'E')) &&
208                                         ((c5 == '>'))) {
209 
210                                         ignore = false;
211                                     }
212                                 }
213 
214                                 // Check for </textarea>
215 
216                                 if (ignore &&
217                                     ((i + 10) < oldByteArray.length)) {
218 
219                                     char c1 = (char)oldByteArray[i + 1];
220                                     char c2 = (char)oldByteArray[i + 2];
221                                     char c3 = (char)oldByteArray[i + 3];
222                                     char c4 = (char)oldByteArray[i + 4];
223                                     char c5 = (char)oldByteArray[i + 5];
224                                     char c6 = (char)oldByteArray[i + 6];
225                                     char c7 = (char)oldByteArray[i + 7];
226                                     char c8 = (char)oldByteArray[i + 8];
227                                     char c9 = (char)oldByteArray[i + 9];
228                                     char c10 = (char)oldByteArray[i + 10];
229 
230                                     if (((c1 == '/')) &&
231                                         ((c2 == 't') || (c2 == 'T')) &&
232                                         ((c3 == 'e') || (c3 == 'E')) &&
233                                         ((c4 == 'x') || (c4 == 'X')) &&
234                                         ((c5 == 't') || (c5 == 'T')) &&
235                                         ((c6 == 'a') || (c6 == 'A')) &&
236                                         ((c7 == 'r') || (c7 == 'R')) &&
237                                         ((c8 == 'e') || (c8 == 'E')) &&
238                                         ((c9 == 'a') || (c9 == 'A')) &&
239                                         ((c10 == '>'))) {
240 
241                                         ignore = false;
242                                     }
243                                 }
244                             }
245                         }
246 
247                         if ((!ignore) &&
248                             ((c == '\n') || (c == '\r') || (c == '\t'))) {
249 
250                             if ((i + 1) == oldByteArray.length) {
251                             }
252 
253                             if ((prevChar == '\n') || (prevChar == '\r')) {
254                             }
255                             else {
256                                 if (c != '\t') {
257                                     prevChar = c;
258                                 }
259 
260                                 newByteArray[newByteArrayPos++] = b;
261                             }
262                         }
263                         else {
264                             prevChar = c;
265 
266                             newByteArray[newByteArrayPos++] = b;
267                         }
268                     }
269                 }
270                 else {
271                     newByteArray = oldByteArray;
272                     newByteArrayPos = oldByteArray.length;
273                 }
274 
275                 ServletResponseUtil.write(
276                     response, newByteArray, newByteArrayPos);
277             }
278         }
279         else {
280             if (_log.isDebugEnabled()) {
281                 _log.debug("Not stripping " + completeURL);
282             }
283 
284             processFilter(StripFilter.class, request, response, filterChain);
285         }
286     }
287 
288     private static final String _STRIP = "strip";
289 
290     private static Log _log = LogFactoryUtil.getLog(StripFilter.class);
291 
292 }