1 package org.apache.velocity.tools.view;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.io.BufferedReader;
23 import java.io.ByteArrayOutputStream;
24 import java.io.IOException;
25 import java.io.InputStream;
26 import java.io.InputStreamReader;
27 import java.io.PrintWriter;
28 import java.io.Reader;
29 import java.io.StringReader;
30 import java.io.StringWriter;
31 import java.io.UnsupportedEncodingException;
32 import java.net.HttpURLConnection;
33 import java.net.URL;
34 import java.net.URLConnection;
35 import java.util.Locale;
36 import javax.servlet.RequestDispatcher;
37 import javax.servlet.ServletContext;
38 import javax.servlet.ServletOutputStream;
39 import javax.servlet.http.HttpServletRequest;
40 import javax.servlet.http.HttpServletResponse;
41 import javax.servlet.http.HttpServletResponseWrapper;
42 import org.apache.velocity.runtime.log.Log;
43
44
45
46
47
48
49
50
51
52 public abstract class ImportSupport
53 {
54 protected static final String VALID_SCHEME_CHARS =
55 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+.-";
56
57
58 protected static final String DEFAULT_ENCODING = "ISO-8859-1";
59
60 protected Log LOG;
61 protected ServletContext application;
62 protected HttpServletRequest request;
63 protected HttpServletResponse response;
64
65
66
67
68 public void setLog(Log log)
69 {
70 if (log == null)
71 {
72 throw new NullPointerException("log should not be set to null");
73 }
74 this.LOG = log;
75 }
76
77
78
79
80
81
82 public void setRequest(HttpServletRequest request)
83 {
84 if (request == null)
85 {
86 throw new NullPointerException("request should not be null");
87 }
88 this.request = request;
89 }
90
91
92
93
94
95
96 public void setResponse(HttpServletResponse response)
97 {
98 if (response == null)
99 {
100 throw new NullPointerException("response should not be null");
101 }
102 this.response = response;
103 }
104
105
106
107
108
109
110 public void setServletContext(ServletContext application)
111 {
112 if (application == null)
113 {
114 throw new NullPointerException("servlet context should not be null");
115 }
116 this.application = application;
117 }
118
119 /
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145 protected String acquireString(String url) throws IOException, Exception {
146
147 if (isAbsoluteUrl(url))
148 {
149
150 BufferedReader r = null;
151 try
152 {
153 r = new BufferedReader(acquireReader(url));
154 StringBuilder sb = new StringBuilder();
155 int i;
156
157
158 while ((i = r.read()) != -1)
159 {
160 sb.append((char)i);
161 }
162 return sb.toString();
163 }
164 finally
165 {
166 if(r != null)
167 {
168 try
169 {
170 r.close();
171 }
172 catch (IOException ioe)
173 {
174 LOG.error("ImportSupport : Could not close reader.", ioe);
175 }
176 }
177 }
178 }
179 else
180 {
181
182 if (!(request instanceof HttpServletRequest
183 && response instanceof HttpServletResponse))
184 {
185 throw new Exception("Relative import from non-HTTP request not allowed");
186 }
187
188
189
190 if (!url.startsWith("/"))
191 {
192 String sp = ((HttpServletRequest)request).getServletPath();
193 url = sp.substring(0, sp.lastIndexOf('/')) + '/' + url;
194 }
195
196
197 url = stripSession(url);
198
199
200 RequestDispatcher rd = application.getRequestDispatcher(url);
201 if (rd == null)
202 {
203 throw new Exception("Couldn't get a RequestDispatcher for \""
204 + url + "\"");
205 }
206
207
208 ImportResponseWrapper irw =
209 new ImportResponseWrapper((HttpServletResponse)response);
210 try
211 {
212 rd.include(request, irw);
213 }
214 catch (IOException ex)
215 {
216 throw new Exception("Problem importing the relative URL \""
217 + url + "\". " + ex);
218 }
219 catch (RuntimeException ex)
220 {
221 throw new Exception("Problem importing the relative URL \""
222 + url + "\". " + ex);
223 }
224
225
226 if (irw.getStatus() < 200 || irw.getStatus() > 299)
227 {
228 throw new Exception("Invalid response code '" + irw.getStatus()
229 + "' for \"" + url + "\"");
230 }
231
232
233 return irw.getString();
234 }
235 }
236
237
238
239
240
241
242
243
244 protected Reader acquireReader(String url) throws IOException, Exception
245 {
246 if (!isAbsoluteUrl(url))
247 {
248
249 return new StringReader(acquireString(url));
250 }
251 else
252 {
253
254 URLConnection uc = null;
255 HttpURLConnection huc = null;
256 InputStream i = null;
257
258 try
259 {
260
261 URL u = new URL(url);
262
263 uc = u.openConnection();
264 i = uc.getInputStream();
265
266
267 if (uc instanceof HttpURLConnection)
268 {
269 huc = (HttpURLConnection)uc;
270
271 int status = huc.getResponseCode();
272 if (status < 200 || status > 299)
273 {
274 throw new Exception(status + " " + url);
275 }
276 }
277
278
279 Reader r = null;
280 String charSet;
281
282
283 String contentType = uc.getContentType();
284 if (contentType != null)
285 {
286 charSet = ImportSupport.getContentTypeAttribute(contentType, "charset");
287 if (charSet == null)
288 {
289 charSet = DEFAULT_ENCODING;
290 }
291 }
292 else
293 {
294 charSet = DEFAULT_ENCODING;
295 }
296
297 try
298 {
299 r = new InputStreamReader(i, charSet);
300 }
301 catch (UnsupportedEncodingException ueex)
302 {
303 r = new InputStreamReader(i, DEFAULT_ENCODING);
304 }
305
306 if (huc == null)
307 {
308 return r;
309 }
310 else
311 {
312 return new SafeClosingHttpURLConnectionReader(r, huc);
313 }
314 }
315 catch (IOException ex)
316 {
317 if (i != null)
318 {
319 try
320 {
321 i.close();
322 }
323 catch (IOException ioe)
324 {
325 LOG.error("ImportSupport : Could not close InputStream", ioe);
326 }
327 }
328
329 if (huc != null)
330 {
331 huc.disconnect();
332 }
333 throw new Exception("Problem accessing the absolute URL \""
334 + url + "\". " + ex);
335 }
336 catch (RuntimeException ex)
337 {
338 if (i != null)
339 {
340 try
341 {
342 i.close();
343 }
344 catch (IOException ioe)
345 {
346 LOG.error("ImportSupport : Could not close InputStream", ioe);
347 }
348 }
349
350 if (huc != null)
351 {
352 huc.disconnect();
353 }
354
355 throw new Exception("Problem accessing the absolute URL \""
356 + url + "\". " + ex);
357 }
358 }
359 }
360
361 protected static class SafeClosingHttpURLConnectionReader extends Reader
362 {
363 private final HttpURLConnection huc;
364 private final Reader wrappedReader;
365
366 SafeClosingHttpURLConnectionReader(Reader r, HttpURLConnection huc)
367 {
368 this.wrappedReader = r;
369 this.huc = huc;
370 }
371
372 public void close() throws IOException
373 {
374 if(null != huc)
375 {
376 huc.disconnect();
377 }
378
379 wrappedReader.close();
380 }
381
382
383 public void mark(int readAheadLimit) throws IOException
384 {
385 wrappedReader.mark(readAheadLimit);
386 }
387
388 public boolean markSupported()
389 {
390 return wrappedReader.markSupported();
391 }
392
393 public int read() throws IOException
394 {
395 return wrappedReader.read();
396 }
397
398 public int read(char[] buf) throws IOException
399 {
400 return wrappedReader.read(buf);
401 }
402
403 public int read(char[] buf, int off, int len) throws IOException
404 {
405 return wrappedReader.read(buf, off, len);
406 }
407
408 public boolean ready() throws IOException
409 {
410 return wrappedReader.ready();
411 }
412
413 public void reset() throws IOException
414 {
415 wrappedReader.reset();
416 }
417
418 public long skip(long n) throws IOException
419 {
420 return wrappedReader.skip(n);
421 }
422 }
423
424
425
426 protected static class ImportResponseWrapper extends HttpServletResponseWrapper
427 {
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448 private StringWriter sw;
449
450
451 private ByteArrayOutputStream bos;
452
453
454 private boolean isWriterUsed;
455
456
457 private boolean isStreamUsed;
458
459
460 private int status = 200;
461
462 /
463
464
465
466
467
468
469 public ImportResponseWrapper(HttpServletResponse response)
470 {
471 super(response);
472 }
473
474
475
476
477 public PrintWriter getWriter()
478 {
479 if (isStreamUsed)
480 {
481 throw new IllegalStateException("Unexpected internal error during import: "
482 + "Target servlet called getWriter(), then getOutputStream()");
483 }
484 isWriterUsed = true;
485 if (sw == null)
486 {
487 sw = new StringWriter();
488 }
489 return new PrintWriter(sw);
490 }
491
492
493
494
495 public ServletOutputStream getOutputStream()
496 {
497 if (isWriterUsed)
498 {
499 throw new IllegalStateException("Unexpected internal error during import: "
500 + "Target servlet called getOutputStream(), then getWriter()");
501 }
502 isStreamUsed = true;
503 if (bos == null)
504 {
505 bos = new ByteArrayOutputStream();
506 }
507 ServletOutputStream sos = new ServletOutputStream()
508 {
509 public void write(int b) throws IOException
510 {
511 bos.write(b);
512 }
513 };
514 return sos;
515 }
516
517
518 public void setContentType(String x)
519 {
520
521 }
522
523
524 public void setLocale(Locale x)
525 {
526
527 }
528
529
530
531
532
533 public void setStatus(int status)
534 {
535 this.status = status;
536 }
537
538
539
540
541 public int getStatus()
542 {
543 return status;
544 }
545
546
547
548
549
550
551
552
553 public String getString() throws UnsupportedEncodingException
554 {
555 if (isWriterUsed)
556 {
557 return sw.toString();
558 }
559 else if (isStreamUsed)
560 {
561 return bos.toString(this.getCharacterEncoding());
562 }
563 else
564 {
565 return "";
566 }
567 }
568 }
569
570 /
571
572
573
574
575
576
577
578
579
580 public static boolean isAbsoluteUrl(String url) {
581
582 if (url == null)
583 {
584 return false;
585 }
586
587
588 int colonPos;
589 if ((colonPos = url.indexOf(':')) == -1)
590 {
591 return false;
592 }
593
594
595
596 for (int i = 0; i < colonPos; i++)
597 {
598 if (VALID_SCHEME_CHARS.indexOf(url.charAt(i)) == -1)
599 {
600 return false;
601 }
602 }
603
604 return true;
605 }
606
607
608
609
610
611
612
613
614
615
616 public static String stripSession(String url)
617 {
618 StringBuilder u = new StringBuilder(url);
619 int sessionStart;
620 while ((sessionStart = u.toString().indexOf(";jsessionid=")) != -1)
621 {
622 int sessionEnd = u.toString().indexOf(";", sessionStart + 1);
623 if (sessionEnd == -1)
624 {
625 sessionEnd = u.toString().indexOf("?", sessionStart + 1);
626 }
627 if (sessionEnd == -1)
628 {
629
630 sessionEnd = u.length();
631 }
632 u.delete(sessionStart, sessionEnd);
633 }
634 return u.toString();
635 }
636
637
638
639
640
641
642
643
644
645 public static String getContentTypeAttribute(String input, String name)
646 {
647 int begin;
648 int end;
649 int index = input.toUpperCase().indexOf(name.toUpperCase());
650 if (index == -1)
651 {
652 return null;
653 }
654 index = index + name.length();
655 index = input.indexOf('=', index);
656 if (index == -1)
657 {
658 return null;
659 }
660 index += 1;
661 input = input.substring(index).trim();
662
663 if (input.charAt(0) == '"')
664 {
665
666 begin = 1;
667 end = input.indexOf('"', begin);
668 if (end == -1)
669 {
670 return null;
671 }
672 }
673 else
674 {
675 begin = 0;
676 end = input.indexOf(';');
677 if (end == -1)
678 {
679 end = input.indexOf(' ');
680 }
681 if (end == -1)
682 {
683 end = input.length();
684 }
685 }
686 return input.substring(begin, end).trim();
687 }
688
689 }