OLD | NEW |
1 // Copyright (C) 2008 Google Inc. | 1 // Copyright (C) 2008 Google Inc. |
2 // | 2 // |
3 // Licensed under the Apache License, Version 2.0 (the "License"); | 3 // Licensed under the Apache License, Version 2.0 (the "License"); |
4 // you may not use this file except in compliance with 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 | 5 // You may obtain a copy of the License at |
6 // | 6 // |
7 // http://www.apache.org/licenses/LICENSE-2.0 | 7 // http://www.apache.org/licenses/LICENSE-2.0 |
8 // | 8 // |
9 // Unless required by applicable law or agreed to in writing, software | 9 // Unless required by applicable law or agreed to in writing, software |
10 // distributed under the License is distributed on an "AS IS" BASIS, | 10 // distributed under the License is distributed on an "AS IS" BASIS, |
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 // See the License for the specific language governing permissions and | 12 // See the License for the specific language governing permissions and |
13 // limitations under the License. | 13 // limitations under the License. |
14 | 14 |
15 package com.google.caja.service; | 15 package com.google.caja.service; |
16 | 16 |
17 import com.google.caja.reporting.BuildInfo; | 17 import com.google.caja.reporting.BuildInfo; |
18 import com.google.caja.util.Pair; | 18 import com.google.caja.util.Pair; |
| 19 import com.google.caja.lexer.ExternalReference; |
| 20 import com.google.caja.opensocial.UriCallback; |
| 21 import com.google.caja.opensocial.UriCallbackException; |
19 | 22 |
| 23 import java.io.ByteArrayInputStream; |
20 import java.io.ByteArrayOutputStream; | 24 import java.io.ByteArrayOutputStream; |
21 import java.io.IOException; | 25 import java.io.IOException; |
22 import java.io.InputStream; | 26 import java.io.InputStream; |
| 27 import java.io.InputStreamReader; |
23 import java.io.OutputStream; | 28 import java.io.OutputStream; |
| 29 import java.io.Reader; |
24 import java.net.URI; | 30 import java.net.URI; |
25 import java.net.URISyntaxException; | 31 import java.net.URISyntaxException; |
26 import java.net.URLConnection; | 32 import java.net.URLConnection; |
27 import java.util.List; | 33 import java.util.List; |
28 import java.util.Vector; | 34 import java.util.Vector; |
29 | 35 |
30 import javax.servlet.ServletException; | 36 import javax.servlet.ServletException; |
31 import javax.servlet.http.HttpServlet; | 37 import javax.servlet.http.HttpServlet; |
32 import javax.servlet.http.HttpServletRequest; | 38 import javax.servlet.http.HttpServletRequest; |
33 import javax.servlet.http.HttpServletResponse; | 39 import javax.servlet.http.HttpServletResponse; |
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
116 closeBadRequest(resp); | 122 closeBadRequest(resp); |
117 return; | 123 return; |
118 } | 124 } |
119 | 125 |
120 if (!typeCheck.check(expectedMimeType, contentType)) { | 126 if (!typeCheck.check(expectedMimeType, contentType)) { |
121 closeBadRequest(resp); | 127 closeBadRequest(resp); |
122 return; | 128 return; |
123 } | 129 } |
124 | 130 |
125 ByteArrayOutputStream intermediateResponse = new ByteArrayOutputStream(); | 131 ByteArrayOutputStream intermediateResponse = new ByteArrayOutputStream(); |
126 Pair<String,String> contentInfo; | 132 Pair<String, String> contentInfo; |
127 try { | 133 try { |
128 contentInfo = applyHandler( | 134 contentInfo = applyHandler( |
129 URI.create(gadgetUrl.toString()), | 135 URI.create(gadgetUrl.toString()), |
130 transform, contentType, contentCharSet, | 136 transform, contentType, contentCharSet, |
131 content, intermediateResponse); | 137 content, intermediateResponse); |
132 } catch (UnsupportedContentTypeException e) { | 138 } catch (UnsupportedContentTypeException e) { |
133 closeBadRequest(resp); | 139 closeBadRequest(resp); |
134 return; | 140 return; |
135 } | 141 } |
136 | 142 |
137 byte[] response = intermediateResponse.toByteArray(); | 143 byte[] response = intermediateResponse.toByteArray(); |
138 int responseLength = response.length; | 144 int responseLength = response.length; |
139 | 145 |
140 resp.setStatus(HttpServletResponse.SC_OK); | 146 resp.setStatus(HttpServletResponse.SC_OK); |
141 String responseContentType = contentInfo.a; | 147 String responseContentType = contentInfo.a; |
142 if (contentInfo.b != null) { | 148 if (contentInfo.b != null) { |
143 responseContentType += ";charset=" + contentInfo.b; | 149 responseContentType += ";charset=" + contentInfo.b; |
144 } | 150 } |
145 resp.setHeader("Content-Type", responseContentType); | 151 if (containsNewline(responseContentType)) { |
| 152 throw new IllegalArgumentException(responseContentType); |
| 153 } |
| 154 resp.setContentType(responseContentType); |
146 resp.setContentLength(responseLength); | 155 resp.setContentLength(responseLength); |
147 | 156 |
148 try { | 157 try { |
149 resp.getOutputStream().write(response); | 158 resp.getOutputStream().write(response); |
150 resp.getOutputStream().close(); | 159 resp.getOutputStream().close(); |
151 } catch (IOException ex) { | 160 } catch (IOException ex) { |
152 throw (ServletException) new ServletException().initCause(ex); | 161 throw (ServletException) new ServletException().initCause(ex); |
153 } | 162 } |
154 } | 163 } |
155 | 164 |
(...skipping 16 matching lines...) Expand all Loading... |
172 buffer.write(barr, 0, n); | 181 buffer.write(barr, 0, n); |
173 } | 182 } |
174 } finally { | 183 } finally { |
175 stream.close(); | 184 stream.close(); |
176 } | 185 } |
177 byte[] content = buffer.toByteArray(); | 186 byte[] content = buffer.toByteArray(); |
178 return new FetchedData(content, contentType, contentCharSet); | 187 return new FetchedData(content, contentType, contentCharSet); |
179 } | 188 } |
180 | 189 |
181 public void registerHandlers(BuildInfo buildInfo) { | 190 public void registerHandlers(BuildInfo buildInfo) { |
| 191 UriCallback retriever = new UriCallback() { |
| 192 public Reader retrieve(ExternalReference extref, String mimeType) |
| 193 throws UriCallbackException { |
| 194 try { |
| 195 FetchedData data = fetch(extref.getUri()); |
| 196 if (data == null) { return null; } |
| 197 return new InputStreamReader( |
| 198 new ByteArrayInputStream(data.content), data.charSet); |
| 199 } catch (IOException ex) { |
| 200 throw new UriCallbackException(extref, ex); |
| 201 } |
| 202 } |
| 203 |
| 204 public URI rewrite(ExternalReference extref, String mimeType) { |
| 205 return null; |
| 206 } |
| 207 }; |
182 handlers.add(new JsHandler(buildInfo)); | 208 handlers.add(new JsHandler(buildInfo)); |
183 handlers.add(new ImageHandler()); | 209 handlers.add(new ImageHandler()); |
184 handlers.add(new GadgetHandler(buildInfo)); | 210 handlers.add(new GadgetHandler(buildInfo, retriever)); |
185 handlers.add(new InnocentHandler()); | 211 handlers.add(new InnocentHandler()); |
186 handlers.add(new HtmlHandler(buildInfo, host)); | 212 handlers.add(new HtmlHandler(buildInfo, host, retriever)); |
187 } | 213 } |
188 | 214 |
189 private Pair<String, String> applyHandler(URI uri, | 215 private Pair<String, String> applyHandler( |
190 Transform t, String contentType, String charSet, | 216 URI uri, Transform t, String contentType, String charSet, |
191 byte[] content, OutputStream response) | 217 byte[] content, OutputStream response) |
192 throws UnsupportedContentTypeException { | 218 throws UnsupportedContentTypeException { |
193 for (ContentHandler handler : handlers) { | 219 for (ContentHandler handler : handlers) { |
194 if (handler.canHandle(uri, t, contentType, typeCheck)) { | 220 if (handler.canHandle(uri, t, contentType, typeCheck)) { |
195 return handler.apply(uri, t, contentType, charSet, content, response); | 221 return handler.apply(uri, t, contentType, charSet, content, response); |
196 } | 222 } |
197 } | 223 } |
198 throw new UnsupportedContentTypeException(); | 224 throw new UnsupportedContentTypeException(); |
199 } | 225 } |
200 | 226 |
201 public static final class FetchedData { | 227 public static final class FetchedData { |
202 final byte[] content; | 228 final byte[] content; |
203 final String contentType; | 229 final String contentType; |
204 final String charSet; | 230 final String charSet; |
205 FetchedData(byte[] content, String contentType, String charSet) { | 231 FetchedData(byte[] content, String contentType, String charSet) { |
206 this.content = content; | 232 this.content = content; |
207 this.contentType = contentType; | 233 this.contentType = contentType; |
208 this.charSet = charSet; | 234 this.charSet = charSet; |
209 } | 235 } |
210 } | 236 } |
211 | 237 |
| 238 // Used to protect against header splitting attacks. |
| 239 private static boolean containsNewline(String s) { |
| 240 return s.indexOf('\n') >= 0 || s.indexOf('\r') >= 0; |
| 241 } |
| 242 |
212 public static enum Transform { | 243 public static enum Transform { |
213 INNOCENT, | 244 INNOCENT, |
214 VALIJA, | 245 VALIJA, |
215 CAJITA; | 246 CAJITA; |
216 } | 247 } |
217 } | 248 } |
OLD | NEW |