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