| Html.java |
1 /**
2 * Copyright (c) 2000-2007 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;
24
25 import com.liferay.portal.kernel.util.StringMaker;
26 import com.liferay.portal.kernel.util.StringPool;
27 import com.liferay.portal.kernel.util.StringUtil;
28
29 /**
30 * <a href="Html.java.html"><b><i>View Source</i></b></a>
31 *
32 * @author Brian Wing Shun Chan
33 * @author Clarence Shen
34 * @author Harry Mark
35 *
36 */
37 public class Html {
38
39 public static String escape(String text) {
40 if (text == null) {
41 return null;
42 }
43
44 // Escape using XSS recommendations from
45 // http://www.owasp.org/index.php/Cross_Site_Scripting
46 // #How_to_Protect_Yourself
47
48 StringMaker sm = new StringMaker(text.length());
49
50 for (int i = 0; i < text.length(); i++) {
51 char c = text.charAt(i);
52
53 switch (c) {
54 case '<':
55 sm.append("<");
56
57 break;
58
59 case '>':
60 sm.append(">");
61
62 break;
63
64 case '&':
65 sm.append("&");
66
67 break;
68
69 case '"':
70 sm.append(""");
71
72 break;
73
74 case '\'':
75 sm.append("'");
76
77 break;
78
79 case '(':
80 sm.append("(");
81
82 break;
83
84 case ')':
85 sm.append(")");
86
87 break;
88
89 case '#':
90 sm.append("#");
91
92 break;
93
94 case '%':
95 sm.append("%");
96
97 break;
98
99 case ';':
100 sm.append(";");
101
102 break;
103
104 case '+':
105 sm.append("+");
106
107 break;
108
109 case '-':
110 sm.append("-");
111
112 break;
113
114 default:
115 sm.append(c);
116
117 break;
118 }
119 }
120
121 return sm.toString();
122 }
123
124 public static String formatTo(String text) {
125 return escape(text);
126 }
127
128 public static String formatFrom(String text) {
129 if (text == null) {
130 return null;
131 }
132
133 // Optimize this
134
135 text = StringUtil.replace(text, "<", "<");
136 text = StringUtil.replace(text, ">", ">");
137 text = StringUtil.replace(text, "&", "&");
138 text = StringUtil.replace(text, """, "\"");
139 text = StringUtil.replace(text, "'", "'");
140 text = StringUtil.replace(text, "(", "(");
141 text = StringUtil.replace(text, ")", ")");
142 text = StringUtil.replace(text, "#", "#");
143 text = StringUtil.replace(text, "%", "%");
144 text = StringUtil.replace(text, ";", ";");
145 text = StringUtil.replace(text, "+", "+");
146 text = StringUtil.replace(text, "-", "-");
147
148 return text;
149 }
150
151 public static String fromInputSafe(String text) {
152 return StringUtil.replace(text, "&", "&");
153 }
154
155 public static String stripBetween(String text, String tag) {
156 return StringUtil.stripBetween(text, "<" + tag, "</" + tag + ">");
157 }
158
159 public static String stripComments(String text) {
160 return StringUtil.stripBetween(text, "<!--", "-->");
161 }
162
163 public static String stripHtml(String text) {
164 if (text == null) {
165 return null;
166 }
167
168 text = stripComments(text);
169
170 StringMaker sm = new StringMaker(text.length());
171
172 int x = 0;
173 int y = text.indexOf("<");
174
175 while (y != -1) {
176 sm.append(text.substring(x, y));
177 sm.append(StringPool.SPACE);
178
179 // Look for text enclosed by <script></script>
180
181 boolean scriptFound = _isScriptTag(text, y + 1);
182
183 if (scriptFound) {
184 int pos = y + _TAG_SCRIPT.length;
185
186 // Find end of the tag
187
188 pos = text.indexOf(">", pos);
189
190 if (pos >= 0) {
191
192 // Check if preceding character is / (i.e. is this instance
193 // of <script/>)
194
195 if (text.charAt(pos-1) != '/') {
196
197 // Search for the ending </script> tag
198
199 for (;;) {
200 pos = text.indexOf("</", pos);
201
202 if (pos >= 0) {
203 if (_isScriptTag(text, pos + 2)) {
204 y = pos;
205
206 break;
207 }
208 else {
209
210 // Skip past "</"
211
212 pos += 2;
213 }
214 }
215 else {
216 break;
217 }
218 }
219 }
220 }
221 }
222
223 x = text.indexOf(">", y);
224
225 if (x == -1) {
226 break;
227 }
228
229 x++;
230
231 if (x < y) {
232
233 // <b>Hello</b
234
235 break;
236 }
237
238 y = text.indexOf("<", x);
239 }
240
241 if (y == -1) {
242 sm.append(text.substring(x, text.length()));
243 }
244
245 return sm.toString();
246 }
247
248 public static String toInputSafe(String text) {
249 return StringUtil.replace(
250 text,
251 new String[] {"&", "\""},
252 new String[] {"&", """});
253 }
254
255 private static boolean _isScriptTag(String text, int start) {
256 char item;
257 int pos = start;
258
259 if (pos + _TAG_SCRIPT.length + 1 <= text.length()) {
260 for (int i = 0; i < _TAG_SCRIPT.length; i++) {
261 item = text.charAt(pos++);
262
263 if (Character.toLowerCase(item) != _TAG_SCRIPT[i]) {
264 return false;
265 }
266 }
267
268 item = text.charAt(pos);
269
270 // Check that char after "script" is not a letter (i.e. another tag)
271
272 return !Character.isLetter(item);
273 }
274 else {
275 return false;
276 }
277 }
278
279 private static final char[] _TAG_SCRIPT = {'s', 'c', 'r', 'i', 'p', 't'};
280
281 }