1 | // Copyright (C) 2008 Google Inc. |
2 | // |
3 | // Licensed under the Apache License, Version 2.0 (the "License"); |
4 | // you may not use this file except in compliance with the License. |
5 | // You may obtain a copy of the License at |
6 | // |
7 | // http://www.apache.org/licenses/LICENSE-2.0 |
8 | // |
9 | // Unless required by applicable law or agreed to in writing, software |
10 | // distributed under the License is distributed on an "AS IS" BASIS, |
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 | // See the License for the specific language governing permissions and |
13 | // limitations under the License. |
14 | |
15 | package com.google.caja.service; |
16 | |
17 | import junit.framework.AssertionFailedError; |
18 | import org.json.simple.JSONArray; |
19 | import org.json.simple.JSONObject; |
20 | |
21 | import com.google.caja.reporting.MessageLevel; |
22 | |
23 | /** |
24 | * @author jasvir@google.com (Jasvir Nagra) |
25 | */ |
26 | public class HtmlHandlerTest extends ServiceTestCase { |
27 | public final void testHtml2Json() throws Exception { |
28 | assertHtml2Json("*/*"); |
29 | assertHtml2Json("text/html"); |
30 | assertHtml2Json("text/html"); |
31 | } |
32 | |
33 | public final void testHtmlWithJsonpCallback() throws Exception { |
34 | registerUri("http://foo/bar.html", "<p>some random text</p>", "text/html"); |
35 | |
36 | { |
37 | String s = (String) requestGet("?url=http://foo/bar.html" |
38 | + "&input-mime-type=text/html" |
39 | + "&alt=json-in-script" |
40 | + "&callback=foo"); |
41 | assertCallbackInJsonp(s, "foo"); |
42 | assertSubstringsInJsonp(s, "html", "some random text"); |
43 | } |
44 | |
45 | try { |
46 | assertCallbackInJsonp( |
47 | (String) requestGet("?url=http://foo/bar.html" |
48 | + "&input-mime-type=text/html" |
49 | + "&alt=json-in-script" |
50 | + "&callback=foo.bar"), |
51 | "foo.bar"); |
52 | fail("Failed to reject non-identifier JSONP callback"); |
53 | } catch (AssertionFailedError e) { |
54 | // Success |
55 | } |
56 | |
57 | try { |
58 | assertCallbackInJsonp( |
59 | (String) requestGet("?url=http://foo/bar.html" |
60 | + "&input-mime-type=text/html" |
61 | + "&callback=foo.bar"), |
62 | "foo.bar"); |
63 | fail("Added JSONP callback when not requested"); |
64 | } catch (AssertionFailedError e) { |
65 | // Success |
66 | } |
67 | |
68 | try { |
69 | assertCallbackInJsonp( |
70 | (String) requestGet("?url=http://foo/bar.html" |
71 | + "&input-mime-type=text/html" |
72 | + "&alt=json" |
73 | + "&callback=foo.bar"), |
74 | "foo.bar"); |
75 | fail("Added JSONP callback when not requested"); |
76 | } catch (AssertionFailedError e) { |
77 | // Success |
78 | } |
79 | } |
80 | |
81 | public final void testSandboxedLink() throws Exception { |
82 | registerUri( |
83 | "http://foo/bar.css", "a { background-image: url(baz.png) }", |
84 | "text/css"); |
85 | registerUri( |
86 | "http://foo/index.html", |
87 | "<link rel=stylesheet href=bar.css><a href=\"shizzle.html\">Clicky</a>", |
88 | "text/html"); |
89 | String result = (String) requestGet( |
90 | "?url=http://foo/index.html&input-mime-type=text/html" |
91 | + "&output-mime-type=text/html&sext=true&idclass=foo___"); |
92 | JSONObject json = (JSONObject) json(result); |
93 | assertContainsIgnoreSpace( |
94 | (String) json.get("html"), |
95 | " background-image: url('http://caja.appspot.com/cajole?url=http%3a%2f%2fcaja.appspot.com%2fcajole%3furl%3dhttp%253a%252f%252ffoo%252fbaz.png%26effect%3dSAME%5fDOCUMENT%26loader%3dSANDBOXED%26sext%3dtrue&effect=SAME%5fDOCUMENT&loader=SANDBOXED&sext=true')"); |
96 | assertContainsIgnoreSpace( |
97 | (String) json.get("html"), |
98 | "<a href=\"http://caja.appspot.com/cajole" |
99 | + "?url=http%3a%2f%2ffoo%2fshizzle.html&effect=NEW_DOCUMENT" |
100 | + "&loader=UNSANDBOXED&sext=true\" target=\"_blank\">"); |
101 | } |
102 | |
103 | public final void testUnsandboxedLink() throws Exception { |
104 | registerUri( |
105 | "http://foo/bar.css", "a { background-image: url(baz.png) }", |
106 | "text/css"); |
107 | registerUri( |
108 | "http://foo/index.html", |
109 | "<link rel=stylesheet href=bar.css><a href=\"shizzle.html\">Clicky</a>", |
110 | "text/html"); |
111 | String result = (String) requestGet( |
112 | "?url=http://foo/index.html&input-mime-type=text/html" |
113 | + "&output-mime-type=text/html&sext=false&idclass=foo___"); |
114 | JSONObject json = (JSONObject) json(result); |
115 | assertContainsIgnoreSpace( |
116 | (String) json.get("html"), |
117 | "background-image: url('http://foo/baz.png')"); |
118 | assertContainsIgnoreSpace( |
119 | (String) json.get("html"), |
120 | "<a href=\"http://foo/shizzle.html\" target=\"_blank\">Clicky</a>"); |
121 | } |
122 | |
123 | private void assertHtml2Json(String inputMimeType) |
124 | throws Exception { |
125 | registerUri( |
126 | "http://foo/bar.html", "<p>hi</p><script>42;</script><p>bye</p>", |
127 | "text/html"); |
128 | |
129 | Object result = json((String) requestGet( |
130 | "?url=http://foo/bar.html&input-mime-type=" + inputMimeType)); |
131 | assertNotNull(result); |
132 | assertTrue(result instanceof JSONObject); |
133 | JSONObject json = (JSONObject) result; |
134 | |
135 | // Check html generation is correct |
136 | assertEquals("<p>hi<span id=\"id_1___\"></span></p><p>bye</p>", |
137 | (String)json.get("html")); |
138 | assertEquals("{" |
139 | + "___.loadModule({" |
140 | + "'instantiate':function(___,IMPORTS___){" |
141 | + "return ___.prepareModule({" |
142 | + "'instantiate':function(___,IMPORTS___){" |
143 | + "var\nmoduleResult___,el___,emitter___;" |
144 | + "moduleResult___=___.NO_RESULT;" |
145 | + "{" |
146 | + "emitter___=IMPORTS___.htmlEmitter___;" |
147 | + "emitter___.discard(emitter___.attach('id_1___'))" |
148 | + "}" |
149 | + "return moduleResult___" |
150 | + "}," |
151 | + "'cajolerName':'com.google.caja'," |
152 | + "'cajolerVersion':'testBuildVersion'," |
153 | + "'cajoledDate':0})(IMPORTS___)," |
154 | + "___.prepareModule({" |
155 | + "'instantiate':function(___,IMPORTS___){var\n" |
156 | + "$v=___.readImport(IMPORTS___,'$v',{" |
157 | + "'getOuters':{'()':{}}," |
158 | + "'initOuter':{'()':{}}," |
159 | + "'ro':{'()':{}}" |
160 | + "});" |
161 | + "var\nmoduleResult___,$dis;" |
162 | + "moduleResult___=___.NO_RESULT;" |
163 | + "$dis=$v.getOuters();" |
164 | + "$v.initOuter('onerror');" |
165 | + "try{" |
166 | + "{moduleResult___=42}" |
167 | + "}catch(ex___){" |
168 | + "___.getNewModuleHandler().handleUncaughtException(" |
169 | + "ex___,$v.ro('onerror'),'bar.html','1')" |
170 | + "}" |
171 | + "return moduleResult___" |
172 | + "}," |
173 | + "'cajolerName':'com.google.caja'," |
174 | + "'cajolerVersion':'testBuildVersion'," |
175 | + "'cajoledDate':0" |
176 | + "})(IMPORTS___),___.prepareModule({" |
177 | + "'instantiate':function(___,IMPORTS___){" |
178 | + "var\nmoduleResult___,el___,emitter___;" |
179 | + "moduleResult___=___.NO_RESULT;" |
180 | + "{" |
181 | + "emitter___=IMPORTS___.htmlEmitter___;" |
182 | + "el___=emitter___.finish();" |
183 | + "emitter___.signalLoaded()" |
184 | + "}" |
185 | + "return moduleResult___" |
186 | + "}," |
187 | + "'cajolerName':'com.google.caja'," |
188 | + "'cajolerVersion':'testBuildVersion'," |
189 | + "'cajoledDate':0" |
190 | + "})(IMPORTS___)" |
191 | + "}," |
192 | + "'cajolerName':'com.google.caja'," |
193 | + "'cajolerVersion':'testBuildVersion'," |
194 | + "'cajoledDate':0" |
195 | + "})" |
196 | + "}", |
197 | (String)json.get("js")); |
198 | |
199 | assertTrue(json.get("messages") instanceof JSONArray); |
200 | JSONArray messages = (JSONArray)json.get("messages"); |
201 | assertMessagesLessSevereThan(messages, MessageLevel.ERROR); |
202 | } |
203 | |
204 | public final void testErrors2Json() throws Exception { |
205 | registerUri("http://foo/bar.html", |
206 | "<script>with(foo){}</script>", "text/html"); |
207 | |
208 | Object result = json((String) requestGet( |
209 | "?url=http://foo/bar.html&input-mime-type=text/html")); |
210 | assertTrue(result instanceof JSONObject); |
211 | JSONObject json = (JSONObject) result; |
212 | |
213 | assertTrue(json.containsKey("messages")); |
214 | JSONArray messages = (JSONArray)json.get("messages"); |
215 | boolean containsError = false; |
216 | for (Object msg : messages) { |
217 | JSONObject jsonMsg = (JSONObject) msg; |
218 | containsError = containsError || jsonMsg.get("name").equals("ERROR"); |
219 | } |
220 | assertTrue(containsError); |
221 | } |
222 | } |