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