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