1 |
| |
2 |
| |
3 |
| |
4 |
| |
5 |
| |
6 |
| |
7 |
| |
8 |
| |
9 |
| |
10 |
| |
11 |
| |
12 |
| |
13 |
| |
14 |
| |
15 |
| |
16 |
| |
17 |
| |
18 |
| |
19 |
| |
20 |
| |
21 |
| |
22 |
| |
23 |
| |
24 |
| |
25 |
| |
26 |
| |
27 |
| |
28 |
| |
29 |
| |
30 |
| |
31 |
| |
32 |
| |
33 |
| |
34 |
| |
35 |
| |
36 |
| |
37 |
| |
38 |
| |
39 |
| |
40 |
| |
41 |
| |
42 |
| |
43 |
| |
44 |
| |
45 |
| |
46 |
| |
47 |
| |
48 |
| |
49 |
| |
50 |
| |
51 |
| |
52 |
| |
53 |
| |
54 |
| |
55 |
| package org.w3c.tidy.servlet; |
56 |
| |
57 |
| |
58 |
| |
59 |
| |
60 |
| import java.io.ByteArrayOutputStream; |
61 |
| import java.io.IOException; |
62 |
| import java.io.InputStream; |
63 |
| import java.io.OutputStream; |
64 |
| import java.io.PrintWriter; |
65 |
| import java.util.Properties; |
66 |
| import java.util.StringTokenizer; |
67 |
| |
68 |
| import javax.servlet.http.Cookie; |
69 |
| import javax.servlet.http.HttpServletRequest; |
70 |
| import javax.servlet.http.HttpServletResponse; |
71 |
| import javax.servlet.http.HttpSession; |
72 |
| |
73 |
| import org.apache.commons.logging.Log; |
74 |
| import org.apache.commons.logging.LogFactory; |
75 |
| import org.w3c.tidy.Configuration; |
76 |
| import org.w3c.tidy.Tidy; |
77 |
| import org.w3c.tidy.TidyMessage; |
78 |
| import org.w3c.tidy.servlet.jsp.tagext.ValidationImageTag; |
79 |
| import org.w3c.tidy.servlet.properties.JTidyServletProperties; |
80 |
| |
81 |
| |
82 |
| |
83 |
| |
84 |
| |
85 |
| |
86 |
| |
87 |
| public class TidyProcessor |
88 |
| { |
89 |
| |
90 |
| |
91 |
| |
92 |
| |
93 |
| HttpSession httpSession; |
94 |
| |
95 |
| HttpServletRequest request; |
96 |
| |
97 |
| HttpServletResponse response; |
98 |
| |
99 |
| |
100 |
| |
101 |
| |
102 |
| private String config; |
103 |
| |
104 |
| |
105 |
| |
106 |
| |
107 |
| private boolean validateOnly; |
108 |
| |
109 |
| |
110 |
| |
111 |
| |
112 |
| |
113 |
| private boolean doubleValidation; |
114 |
| |
115 |
| private boolean commentsSubst; |
116 |
| |
117 |
| |
118 |
| |
119 |
| |
120 |
| private Log log = LogFactory.getLog(TidyProcessor.class); |
121 |
| |
122 |
| |
123 |
| |
124 |
| |
125 |
| |
126 |
| |
127 |
18
| public TidyProcessor(
|
128 |
| HttpSession httpSession, |
129 |
| HttpServletRequest httpServletRequest, |
130 |
| HttpServletResponse httpServletResponse) |
131 |
| { |
132 |
18
| this.httpSession = httpSession;
|
133 |
18
| this.request = httpServletRequest;
|
134 |
18
| this.response = httpServletResponse;
|
135 |
| } |
136 |
| |
137 |
| |
138 |
| |
139 |
| |
140 |
| |
141 |
16
| private void parsConfig(Configuration configuration)
|
142 |
| { |
143 |
16
| if (config == null)
|
144 |
| { |
145 |
1
| return;
|
146 |
| } |
147 |
15
| Properties properties = new Properties();
|
148 |
| |
149 |
15
| StringTokenizer st = new StringTokenizer(config, ";");
|
150 |
15
| while (st.hasMoreTokens())
|
151 |
| { |
152 |
17
| String nv = st.nextToken();
|
153 |
17
| int split = nv.indexOf(':');
|
154 |
17
| if (split > 0)
|
155 |
| { |
156 |
17
| String n = nv.substring(0, split).trim();
|
157 |
17
| String v = nv.substring(split + 1).trim();
|
158 |
17
| if (Configuration.isKnownOption(n))
|
159 |
| { |
160 |
17
| properties.put(n, v);
|
161 |
17
| log.debug("add option " + n + "=" + v);
|
162 |
| } |
163 |
| else |
164 |
| { |
165 |
0
| log.warn("TidyTag unknown option " + n);
|
166 |
| } |
167 |
| } |
168 |
| } |
169 |
15
| configuration.addProps(properties);
|
170 |
15
| configuration.adjust();
|
171 |
| } |
172 |
| |
173 |
16
| public boolean parse(InputStream in, OutputStream out, String html)
|
174 |
| { |
175 |
16
| if (this.request.getAttribute(Consts.ATTRIBUTE_IGNORE) != null)
|
176 |
| { |
177 |
0
| log.debug("IGNORE");
|
178 |
0
| return false;
|
179 |
| } |
180 |
| |
181 |
16
| RepositoryFactory factory = JTidyServletProperties.getInstance().getRepositoryFactoryInstance();
|
182 |
| |
183 |
16
| Object requestID = factory.getResponseID(this.httpSession, this.request, this.response, false);
|
184 |
16
| if (requestID == null)
|
185 |
| { |
186 |
0
| log.debug("IGNORE requestID == null");
|
187 |
0
| return false;
|
188 |
| } |
189 |
| |
190 |
16
| boolean secondPass = false;
|
191 |
| |
192 |
16
| if (this.request.getAttribute(Consts.ATTRIBUTE_PROCESSED) != null)
|
193 |
| { |
194 |
0
| if (!doubleValidation)
|
195 |
| { |
196 |
0
| log.debug("IGNORE !doubleValidation");
|
197 |
0
| return false;
|
198 |
| } |
199 |
0
| requestID = factory.getResponseID(this.httpSession, this.request, this.response, true);
|
200 |
0
| secondPass = true;
|
201 |
| } |
202 |
| |
203 |
16
| if (!secondPass)
|
204 |
| { |
205 |
16
| log.debug("addCookie");
|
206 |
16
| this.response.addCookie(new Cookie(Consts.ATTRIBUTE_REQUEST_ID, requestID.toString()));
|
207 |
| } |
208 |
| |
209 |
16
| boolean rc = parse(in, out, html, requestID, factory);
|
210 |
| |
211 |
16
| if (!secondPass)
|
212 |
| { |
213 |
| |
214 |
16
| this.request.setAttribute(Consts.ATTRIBUTE_PROCESSED, requestID);
|
215 |
| } |
216 |
| |
217 |
16
| if (rc && (!this.validateOnly) && (this.request.getAttribute(Consts.ATTRIBUTE_PASS) != null))
|
218 |
| { |
219 |
1
| rc = false;
|
220 |
| } |
221 |
| |
222 |
16
| return rc;
|
223 |
| } |
224 |
| |
225 |
16
| public boolean parse(InputStream in, OutputStream out, String html, Object requestID, RepositoryFactory factory)
|
226 |
| { |
227 |
16
| long start = System.currentTimeMillis();
|
228 |
| |
229 |
16
| Tidy tidy = new Tidy();
|
230 |
16
| parsConfig(tidy.getConfiguration());
|
231 |
16
| tidy.setSmartIndent(true);
|
232 |
16
| tidy.setQuiet(true);
|
233 |
| |
234 |
16
| ByteArrayOutputStream mesageBuffer = new ByteArrayOutputStream();
|
235 |
16
| PrintWriter pw = new PrintWriter(mesageBuffer);
|
236 |
16
| tidy.setErrout(pw);
|
237 |
| |
238 |
16
| boolean useOut = false;
|
239 |
| |
240 |
16
| ResponseRecord result = factory.createRecord(requestID, this.httpSession, this.request, this.response);
|
241 |
16
| result.setRequestID(requestID);
|
242 |
16
| tidy.setMessageListener(result);
|
243 |
| |
244 |
16
| boolean fatalError = false;
|
245 |
| |
246 |
16
| ByteArrayOutputStream outBuffer = new ByteArrayOutputStream();
|
247 |
| |
248 |
16
| try
|
249 |
| { |
250 |
16
| log.debug("processing request " + requestID + "...");
|
251 |
16
| tidy.parse(in, outBuffer);
|
252 |
16
| useOut = (result.getParseErrors() == 0);
|
253 |
16
| if (commentsSubst)
|
254 |
| { |
255 |
0
| doCommentsSubst(outBuffer, requestID);
|
256 |
| } |
257 |
16
| if (out != null)
|
258 |
| { |
259 |
16
| outBuffer.writeTo(out);
|
260 |
| } |
261 |
| } |
262 |
| catch (Throwable e) |
263 |
| { |
264 |
0
| log.error("JTidy parsing error", e);
|
265 |
0
| result.messageReceived(new TidyMessage(0, 0, 0, TidyMessage.Level.ERROR, "JTidy parsing error"
|
266 |
| + e.getMessage())); |
267 |
0
| fatalError = true;
|
268 |
| } |
269 |
| |
270 |
| |
271 |
| |
272 |
| |
273 |
16
| result.setHtmlInput(html);
|
274 |
| |
275 |
16
| if ((result.getParseErrors() > 0) || fatalError)
|
276 |
| { |
277 |
0
| result.setHtmlOutput(html);
|
278 |
| } |
279 |
| else |
280 |
| { |
281 |
16
| result.setHtmlOutput(outBuffer.toString());
|
282 |
| } |
283 |
| |
284 |
16
| if (!fatalError)
|
285 |
| { |
286 |
| |
287 |
| |
288 |
| |
289 |
| } |
290 |
| |
291 |
16
| long time = System.currentTimeMillis() - start;
|
292 |
16
| result.setParsTime(time);
|
293 |
16
| if (log.isDebugEnabled())
|
294 |
| { |
295 |
0
| log.debug("processed in " + time + " millis");
|
296 |
| } |
297 |
| |
298 |
16
| ResponseRecordRepository repository = factory.getRepositoryInstance(this.httpSession);
|
299 |
16
| repository.addRecord(result);
|
300 |
| |
301 |
16
| String shortMessage;
|
302 |
16
| if ((result.getParseErrors() != 0) || (result.getParseWarnings() != 0))
|
303 |
| { |
304 |
5
| if (result.getParseErrors() == 0)
|
305 |
| { |
306 |
5
| shortMessage = "found " + result.getParseWarnings() + " warnings in generated HTML";
|
307 |
| } |
308 |
| else |
309 |
| { |
310 |
0
| shortMessage = "found "
|
311 |
| + result.getParseErrors() |
312 |
| + " errors and " |
313 |
| + result.getParseWarnings() |
314 |
| + " warnings in generated HTML"; |
315 |
| } |
316 |
| } |
317 |
| else |
318 |
| { |
319 |
11
| shortMessage = "no problems found";
|
320 |
| } |
321 |
| |
322 |
16
| log.info(shortMessage + " request " + requestID);
|
323 |
| |
324 |
16
| return (useOut && (out != null));
|
325 |
| } |
326 |
| |
327 |
0
| private void doCommentsSubst(ByteArrayOutputStream outBuffer, Object requestID)
|
328 |
| { |
329 |
0
| log.debug("doCommentsSubst");
|
330 |
| |
331 |
0
| if (response != null)
|
332 |
| { |
333 |
0
| response.setHeader("Pragma", "No-cache");
|
334 |
0
| response.setHeader("Cache-Control", "no-cache");
|
335 |
0
| response.setDateHeader("Expires", -1);
|
336 |
| } |
337 |
| |
338 |
0
| String html = outBuffer.toString();
|
339 |
0
| html = replaceAll(html, "<!--jtidy:requestID-->", requestID.toString());
|
340 |
0
| String aLink = ValidationImageTag.getImageHTML(requestID.toString(), null, null, request);
|
341 |
0
| html = replaceAll(html, "<!--jtidy:validationImage-->", aLink);
|
342 |
0
| outBuffer.reset();
|
343 |
0
| try
|
344 |
| { |
345 |
| |
346 |
0
| outBuffer.write(html.getBytes());
|
347 |
| } |
348 |
| catch (IOException e) |
349 |
| { |
350 |
0
| log.error("Internal error", e);
|
351 |
| } |
352 |
| } |
353 |
| |
354 |
| |
355 |
| |
356 |
| |
357 |
18
| public void setConfig(String config)
|
358 |
| { |
359 |
18
| this.config = config;
|
360 |
| } |
361 |
| |
362 |
| |
363 |
| |
364 |
| |
365 |
0
| public boolean isDoubleValidation()
|
366 |
| { |
367 |
0
| return doubleValidation;
|
368 |
| } |
369 |
| |
370 |
| |
371 |
| |
372 |
| |
373 |
18
| public void setDoubleValidation(boolean doubleValidation)
|
374 |
| { |
375 |
18
| this.doubleValidation = doubleValidation;
|
376 |
| } |
377 |
| |
378 |
| |
379 |
| |
380 |
| |
381 |
18
| public void setValidateOnly(boolean validateOnly)
|
382 |
| { |
383 |
18
| this.validateOnly = validateOnly;
|
384 |
| } |
385 |
| |
386 |
| |
387 |
| |
388 |
| |
389 |
4
| public void setCommentsSubst(boolean commentsSubst)
|
390 |
| { |
391 |
4
| this.commentsSubst = commentsSubst;
|
392 |
| } |
393 |
| |
394 |
| |
395 |
| |
396 |
| |
397 |
| |
398 |
| |
399 |
| |
400 |
| |
401 |
0
| public String replaceAll(String str, String replace, String replacement)
|
402 |
| { |
403 |
0
| StringBuffer sb = new StringBuffer(str);
|
404 |
0
| int firstOccurrence = str.indexOf(replace);
|
405 |
| |
406 |
0
| while (firstOccurrence != -1)
|
407 |
| { |
408 |
0
| sb.replace(firstOccurrence, firstOccurrence + replace.length(), replacement);
|
409 |
0
| firstOccurrence = sb.toString().indexOf(replace);
|
410 |
| } |
411 |
| |
412 |
0
| return sb.toString();
|
413 |
| } |
414 |
| |
415 |
| } |