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