1
2
3
4
5
6
7
8
9
10
11
12
13 package org.eclipse.jetty.util.resource;
14
15 import java.io.File;
16 import java.io.FileOutputStream;
17 import java.io.IOException;
18 import java.io.InputStream;
19 import java.io.OutputStream;
20 import java.net.MalformedURLException;
21 import java.net.URI;
22 import java.net.URL;
23 import java.net.URLConnection;
24 import java.text.DateFormat;
25 import java.util.Arrays;
26 import java.util.Date;
27
28 import org.eclipse.jetty.util.IO;
29 import org.eclipse.jetty.util.Loader;
30 import org.eclipse.jetty.util.StringUtil;
31 import org.eclipse.jetty.util.URIUtil;
32 import org.eclipse.jetty.util.log.Log;
33 import org.eclipse.jetty.util.log.Logger;
34
35
36
37
38
39
40 public abstract class Resource implements ResourceFactory
41 {
42 private static final Logger LOG = Log.getLogger(Resource.class);
43 public static boolean __defaultUseCaches = true;
44 volatile Object _associate;
45
46
47
48
49
50
51 public static void setDefaultUseCaches (boolean useCaches)
52 {
53 __defaultUseCaches=useCaches;
54 }
55
56
57 public static boolean getDefaultUseCaches ()
58 {
59 return __defaultUseCaches;
60 }
61
62
63
64
65
66
67
68 public static Resource newResource(URI uri)
69 throws IOException
70 {
71 return newResource(uri.toURL());
72 }
73
74
75
76
77
78
79
80 public static Resource newResource(URL url)
81 throws IOException
82 {
83 return newResource(url, __defaultUseCaches);
84 }
85
86
87
88
89
90
91
92
93 static Resource newResource(URL url, boolean useCaches)
94 {
95 if (url==null)
96 return null;
97
98 String url_string=url.toExternalForm();
99 if( url_string.startsWith( "file:"))
100 {
101 try
102 {
103 FileResource fileResource= new FileResource(url);
104 return fileResource;
105 }
106 catch(Exception e)
107 {
108 LOG.debug(Log.EXCEPTION,e);
109 return new BadResource(url,e.toString());
110 }
111 }
112 else if( url_string.startsWith( "jar:file:"))
113 {
114 return new JarFileResource(url, useCaches);
115 }
116 else if( url_string.startsWith( "jar:"))
117 {
118 return new JarResource(url, useCaches);
119 }
120
121 return new URLResource(url,null,useCaches);
122 }
123
124
125
126
127
128
129
130
131 public static Resource newResource(String resource)
132 throws MalformedURLException, IOException
133 {
134 return newResource(resource, __defaultUseCaches);
135 }
136
137
138
139
140
141
142
143 public static Resource newResource (String resource, boolean useCaches)
144 throws MalformedURLException, IOException
145 {
146 URL url=null;
147 try
148 {
149
150 url = new URL(resource);
151 }
152 catch(MalformedURLException e)
153 {
154 if(!resource.startsWith("ftp:") &&
155 !resource.startsWith("file:") &&
156 !resource.startsWith("jar:"))
157 {
158 try
159 {
160
161 if (resource.startsWith("./"))
162 resource=resource.substring(2);
163
164 File file=new File(resource).getCanonicalFile();
165 url=Resource.toURL(file);
166
167 URLConnection connection=url.openConnection();
168 connection.setUseCaches(useCaches);
169 return new FileResource(url,connection,file);
170 }
171 catch(Exception e2)
172 {
173 LOG.debug(Log.EXCEPTION,e2);
174 throw e;
175 }
176 }
177 else
178 {
179 LOG.warn("Bad Resource: "+resource);
180 throw e;
181 }
182 }
183
184
185 String nurl=url.toString();
186 if (nurl.length()>0 && nurl.charAt(nurl.length()-1)!=resource.charAt(resource.length()-1))
187 {
188 if ((nurl.charAt(nurl.length()-1)!='/' ||
189 nurl.charAt(nurl.length()-2)!=resource.charAt(resource.length()-1))
190 &&
191 (resource.charAt(resource.length()-1)!='/' ||
192 resource.charAt(resource.length()-2)!=nurl.charAt(nurl.length()-1)
193 ))
194 {
195 return new BadResource(url,"Trailing special characters stripped by URL in "+resource);
196 }
197 }
198 return newResource(url);
199 }
200
201
202 public static Resource newResource (File file)
203 throws MalformedURLException, IOException
204 {
205 file = file.getCanonicalFile();
206 URL url = Resource.toURL(file);
207
208 URLConnection connection = url.openConnection();
209 FileResource fileResource = new FileResource(url, connection, file);
210 return fileResource;
211 }
212
213
214
215
216
217
218
219
220
221 public static Resource newSystemResource(String resource)
222 throws IOException
223 {
224 URL url=null;
225
226 ClassLoader
227 loader=Thread.currentThread().getContextClassLoader();
228 if (loader!=null)
229 {
230 try
231 {
232 url = loader.getResource(resource);
233 if (url == null && resource.startsWith("/"))
234 url = loader.getResource(resource.substring(1));
235 }
236 catch (IllegalArgumentException e)
237 {
238
239
240
241 url = null;
242 }
243 }
244 if (url==null)
245 {
246 loader=Resource.class.getClassLoader();
247 if (loader!=null)
248 {
249 url=loader.getResource(resource);
250 if (url==null && resource.startsWith("/"))
251 url=loader.getResource(resource.substring(1));
252 }
253 }
254
255 if (url==null)
256 {
257 url=ClassLoader.getSystemResource(resource);
258 if (url==null && resource.startsWith("/"))
259 url=loader.getResource(resource.substring(1));
260 }
261
262 if (url==null)
263 return null;
264
265 return newResource(url);
266 }
267
268
269
270
271 public static Resource newClassPathResource(String resource)
272 {
273 return newClassPathResource(resource,true,false);
274 }
275
276
277
278
279
280
281
282
283
284
285
286
287
288 public static Resource newClassPathResource(String name,boolean useCaches,boolean checkParents)
289 {
290 URL url=Resource.class.getResource(name);
291
292 if (url==null)
293 {
294 try
295 {
296 url=Loader.getResource(Resource.class,name,checkParents);
297 }
298 catch(ClassNotFoundException e)
299 {
300 url=ClassLoader.getSystemResource(name);
301 }
302 }
303 if (url==null)
304 return null;
305 return newResource(url,useCaches);
306 }
307
308
309 public static boolean isContainedIn (Resource r, Resource containingResource) throws MalformedURLException
310 {
311 return r.isContainedIn(containingResource);
312 }
313
314
315 @Override
316 protected void finalize()
317 {
318 release();
319 }
320
321
322 public abstract boolean isContainedIn (Resource r) throws MalformedURLException;
323
324
325
326
327
328 public abstract void release();
329
330
331
332
333
334
335 public abstract boolean exists();
336
337
338
339
340
341
342
343
344 public abstract boolean isDirectory();
345
346
347
348
349
350 public abstract long lastModified();
351
352
353
354
355
356
357 public abstract long length();
358
359
360
361
362
363
364 public abstract URL getURL();
365
366
367
368
369
370 public URI getURI()
371 {
372 try
373 {
374 return getURL().toURI();
375 }
376 catch(Exception e)
377 {
378 throw new RuntimeException(e);
379 }
380 }
381
382
383
384
385
386
387
388 public abstract File getFile()
389 throws IOException;
390
391
392
393
394
395
396 public abstract String getName();
397
398
399
400
401
402
403 public abstract InputStream getInputStream()
404 throws java.io.IOException;
405
406
407
408
409
410 public abstract OutputStream getOutputStream()
411 throws java.io.IOException, SecurityException;
412
413
414
415
416
417 public abstract boolean delete()
418 throws SecurityException;
419
420
421
422
423
424 public abstract boolean renameTo( Resource dest)
425 throws SecurityException;
426
427
428
429
430
431
432 public abstract String[] list();
433
434
435
436
437
438
439
440
441 public abstract Resource addPath(String path)
442 throws IOException,MalformedURLException;
443
444
445
446
447
448
449
450
451 public Resource getResource(String path)
452 {
453 try
454 {
455 return addPath(path);
456 }
457 catch(Exception e)
458 {
459 LOG.debug(e);
460 return null;
461 }
462 }
463
464
465
466
467
468
469
470 public String encode(String uri)
471 {
472 return URIUtil.encodePath(uri);
473 }
474
475
476 public Object getAssociate()
477 {
478 return _associate;
479 }
480
481
482 public void setAssociate(Object o)
483 {
484 _associate=o;
485 }
486
487
488
489
490
491 public URL getAlias()
492 {
493 return null;
494 }
495
496
497
498
499
500
501
502 public String getListHTML(String base,boolean parent)
503 throws IOException
504 {
505 base=URIUtil.canonicalPath(base);
506 if (base==null || !isDirectory())
507 return null;
508
509 String[] ls = list();
510 if (ls==null)
511 return null;
512 Arrays.sort(ls);
513
514 String decodedBase = URIUtil.decodePath(base);
515 String title = "Directory: "+deTag(decodedBase);
516
517 StringBuilder buf=new StringBuilder(4096);
518 buf.append("<HTML><HEAD>");
519 buf.append("<LINK HREF=\"").append("jetty-dir.css").append("\" REL=\"stylesheet\" TYPE=\"text/css\"/><TITLE>");
520 buf.append(title);
521 buf.append("</TITLE></HEAD><BODY>\n<H1>");
522 buf.append(title);
523 buf.append("</H1>\n<TABLE BORDER=0>\n");
524
525 if (parent)
526 {
527 buf.append("<TR><TD><A HREF=\"");
528 buf.append(URIUtil.addPaths(base,"../"));
529 buf.append("\">Parent Directory</A></TD><TD></TD><TD></TD></TR>\n");
530 }
531
532 String encodedBase = hrefEncodeURI(base);
533
534 DateFormat dfmt=DateFormat.getDateTimeInstance(DateFormat.MEDIUM,
535 DateFormat.MEDIUM);
536 for (int i=0 ; i< ls.length ; i++)
537 {
538 Resource item = addPath(ls[i]);
539
540 buf.append("\n<TR><TD><A HREF=\"");
541 String path=URIUtil.addPaths(encodedBase,URIUtil.encodePath(ls[i]));
542
543 buf.append(path);
544
545 if (item.isDirectory() && !path.endsWith("/"))
546 buf.append(URIUtil.SLASH);
547
548
549 buf.append("\">");
550 buf.append(deTag(ls[i]));
551 buf.append(" ");
552 buf.append("</A></TD><TD ALIGN=right>");
553 buf.append(item.length());
554 buf.append(" bytes </TD><TD>");
555 buf.append(dfmt.format(new Date(item.lastModified())));
556 buf.append("</TD></TR>");
557 }
558 buf.append("</TABLE>\n");
559 buf.append("</BODY></HTML>\n");
560
561 return buf.toString();
562 }
563
564
565
566
567
568
569
570
571
572
573
574 private static String hrefEncodeURI(String raw)
575 {
576 StringBuffer buf = null;
577
578 loop:
579 for (int i=0;i<raw.length();i++)
580 {
581 char c=raw.charAt(i);
582 switch(c)
583 {
584 case '\'':
585 case '"':
586 case '<':
587 case '>':
588 buf=new StringBuffer(raw.length()<<1);
589 break loop;
590 }
591 }
592 if (buf==null)
593 return raw;
594
595 for (int i=0;i<raw.length();i++)
596 {
597 char c=raw.charAt(i);
598 switch(c)
599 {
600 case '"':
601 buf.append("%22");
602 continue;
603 case '\'':
604 buf.append("%27");
605 continue;
606 case '<':
607 buf.append("%3C");
608 continue;
609 case '>':
610 buf.append("%3E");
611 continue;
612 default:
613 buf.append(c);
614 continue;
615 }
616 }
617
618 return buf.toString();
619 }
620
621 private static String deTag(String raw)
622 {
623 return StringUtil.replace( StringUtil.replace(raw,"<","<"), ">", ">");
624 }
625
626
627
628
629
630
631
632 public void writeTo(OutputStream out,long start,long count)
633 throws IOException
634 {
635 InputStream in = getInputStream();
636 try
637 {
638 in.skip(start);
639 if (count<0)
640 IO.copy(in,out);
641 else
642 IO.copy(in,out,count);
643 }
644 finally
645 {
646 in.close();
647 }
648 }
649
650
651 public void copyTo(File destination)
652 throws IOException
653 {
654 if (destination.exists())
655 throw new IllegalArgumentException(destination+" exists");
656 writeTo(new FileOutputStream(destination),0,-1);
657 }
658
659
660
661
662
663
664
665 public static URL toURL(File file) throws MalformedURLException
666 {
667 return file.toURI().toURL();
668 }
669 }