1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.eclipse.jetty.webapp;
20
21 import java.io.File;
22 import java.io.IOException;
23 import java.net.URI;
24 import java.net.URISyntaxException;
25 import java.net.URL;
26 import java.net.URLClassLoader;
27 import java.util.ArrayList;
28 import java.util.List;
29 import java.util.Locale;
30 import java.util.Set;
31 import java.util.StringTokenizer;
32 import java.util.regex.Pattern;
33
34 import org.eclipse.jetty.server.Connector;
35 import org.eclipse.jetty.server.NetworkConnector;
36 import org.eclipse.jetty.server.Server;
37 import org.eclipse.jetty.util.IO;
38 import org.eclipse.jetty.util.PatternMatcher;
39 import org.eclipse.jetty.util.URIUtil;
40 import org.eclipse.jetty.util.log.Log;
41 import org.eclipse.jetty.util.log.Logger;
42 import org.eclipse.jetty.util.resource.JarResource;
43 import org.eclipse.jetty.util.resource.Resource;
44 import org.eclipse.jetty.util.resource.ResourceCollection;
45
46 public class WebInfConfiguration extends AbstractConfiguration
47 {
48 private static final Logger LOG = Log.getLogger(WebInfConfiguration.class);
49
50 public static final String TEMPDIR_CONFIGURED = "org.eclipse.jetty.tmpdirConfigured";
51 public static final String CONTAINER_JAR_PATTERN = "org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern";
52 public static final String WEBINF_JAR_PATTERN = "org.eclipse.jetty.server.webapp.WebInfIncludeJarPattern";
53
54
55
56
57
58 public static final String RESOURCE_DIRS = "org.eclipse.jetty.resources";
59
60
61 protected Resource _preUnpackBaseResource;
62
63
64
65 @Override
66 public void preConfigure(final WebAppContext context) throws Exception
67 {
68
69 resolveTempDirectory(context);
70
71
72 unpack (context);
73
74
75
76
77 String tmp = (String)context.getAttribute(WEBINF_JAR_PATTERN);
78 Pattern webInfPattern = (tmp==null?null:Pattern.compile(tmp));
79 tmp = (String)context.getAttribute(CONTAINER_JAR_PATTERN);
80 Pattern containerPattern = (tmp==null?null:Pattern.compile(tmp));
81
82
83
84 PatternMatcher containerJarNameMatcher = new PatternMatcher ()
85 {
86 public void matched(URI uri) throws Exception
87 {
88 context.getMetaData().addContainerResource(Resource.newResource(uri));
89 }
90 };
91 ClassLoader loader = null;
92 if (context.getClassLoader() != null)
93 loader = context.getClassLoader().getParent();
94
95 while (loader != null && (loader instanceof URLClassLoader))
96 {
97 URL[] urls = ((URLClassLoader)loader).getURLs();
98 if (urls != null)
99 {
100 URI[] containerUris = new URI[urls.length];
101 int i=0;
102 for (URL u : urls)
103 {
104 try
105 {
106 containerUris[i] = u.toURI();
107 }
108 catch (URISyntaxException e)
109 {
110 containerUris[i] = new URI(u.toString().replaceAll(" ", "%20"));
111 }
112 i++;
113 }
114 containerJarNameMatcher.match(containerPattern, containerUris, false);
115 }
116 loader = loader.getParent();
117 }
118
119
120 PatternMatcher webInfJarNameMatcher = new PatternMatcher ()
121 {
122 @Override
123 public void matched(URI uri) throws Exception
124 {
125 context.getMetaData().addWebInfJar(Resource.newResource(uri));
126 }
127 };
128 List<Resource> jars = findJars(context);
129
130
131 URI[] uris = null;
132 if (jars != null)
133 {
134 uris = new URI[jars.size()];
135 int i=0;
136 for (Resource r: jars)
137 {
138 uris[i++] = r.getURI();
139 }
140 }
141 webInfJarNameMatcher.match(webInfPattern, uris, true);
142
143
144 context.getMetaData().setWebInfClassesDirs(findClassDirs(context));
145 }
146
147
148 @Override
149 public void configure(WebAppContext context) throws Exception
150 {
151
152 if (context.isStarted())
153 {
154 if (LOG.isDebugEnabled())
155 LOG.debug("Cannot configure webapp "+context+" after it is started");
156 return;
157 }
158
159 Resource web_inf = context.getWebInf();
160
161
162 if (web_inf != null && web_inf.isDirectory() && context.getClassLoader() instanceof WebAppClassLoader)
163 {
164
165 Resource classes= web_inf.addPath("classes/");
166 if (classes.exists())
167 ((WebAppClassLoader)context.getClassLoader()).addClassPath(classes);
168
169
170 Resource lib= web_inf.addPath("lib/");
171 if (lib.exists() || lib.isDirectory())
172 ((WebAppClassLoader)context.getClassLoader()).addJars(lib);
173 }
174
175
176 @SuppressWarnings("unchecked")
177 Set<Resource> resources = (Set<Resource>)context.getAttribute(RESOURCE_DIRS);
178 if (resources!=null)
179 {
180 Resource[] collection=new Resource[resources.size()+1];
181 int i=0;
182 collection[i++]=context.getBaseResource();
183 for (Resource resource : resources)
184 collection[i++]=resource;
185 context.setBaseResource(new ResourceCollection(collection));
186 }
187 }
188
189 @Override
190 public void deconfigure(WebAppContext context) throws Exception
191 {
192
193 if (!context.isPersistTempDirectory())
194 {
195 IO.delete(context.getTempDirectory());
196 }
197
198
199 Boolean tmpdirConfigured = (Boolean)context.getAttribute(TEMPDIR_CONFIGURED);
200 if (tmpdirConfigured != null && !tmpdirConfigured)
201 context.setTempDirectory(null);
202
203
204 context.setBaseResource(_preUnpackBaseResource);
205 }
206
207
208
209
210
211 @Override
212 public void cloneConfigure(WebAppContext template, WebAppContext context) throws Exception
213 {
214 File tmpDir=File.createTempFile(WebInfConfiguration.getCanonicalNameForWebAppTmpDir(context),"",template.getTempDirectory().getParentFile());
215 if (tmpDir.exists())
216 {
217 IO.delete(tmpDir);
218 }
219 tmpDir.mkdir();
220 tmpDir.deleteOnExit();
221 context.setTempDirectory(tmpDir);
222 }
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253 public void resolveTempDirectory (WebAppContext context)
254 throws Exception
255 {
256
257 File tmpDir = context.getTempDirectory();
258 if (tmpDir != null)
259 {
260 configureTempDirectory(tmpDir, context);
261 context.setAttribute(TEMPDIR_CONFIGURED, Boolean.TRUE);
262 return;
263 }
264
265
266 File servletTmpDir = asFile(context.getAttribute(WebAppContext.TEMPDIR));
267 if (servletTmpDir != null)
268 {
269
270 tmpDir = servletTmpDir;
271 configureTempDirectory(tmpDir, context);
272
273 context.setAttribute(WebAppContext.TEMPDIR,tmpDir);
274
275 context.setTempDirectory(tmpDir);
276 return;
277 }
278
279
280
281 File baseTemp = asFile(context.getAttribute(WebAppContext.BASETEMPDIR));
282 if (baseTemp != null && baseTemp.isDirectory() && baseTemp.canWrite())
283 {
284
285 makeTempDirectory(baseTemp,context);
286 }
287 else
288 {
289
290 makeTempDirectory(new File(System.getProperty("java.io.tmpdir")),context);
291 }
292 }
293
294
295
296
297
298
299
300 private File asFile(Object fileattr)
301 {
302 if (fileattr == null)
303 {
304 return null;
305 }
306 if (fileattr instanceof File)
307 {
308 return (File)fileattr;
309 }
310 if (fileattr instanceof String)
311 {
312 return new File((String)fileattr);
313 }
314 return null;
315 }
316
317
318
319 public void makeTempDirectory (File parent, WebAppContext context)
320 throws Exception
321 {
322 if (parent == null || !parent.exists() || !parent.canWrite() || !parent.isDirectory())
323 throw new IllegalStateException("Parent for temp dir not configured correctly: "+(parent==null?"null":"writeable="+parent.canWrite()));
324
325 String temp = getCanonicalNameForWebAppTmpDir(context);
326 File tmpDir = File.createTempFile(temp, ".dir", parent);
327
328 tmpDir.delete();
329
330 tmpDir.mkdirs();
331 configureTempDirectory(tmpDir, context);
332
333 if(LOG.isDebugEnabled())
334 LOG.debug("Set temp dir "+tmpDir);
335 context.setTempDirectory(tmpDir);
336 }
337
338 private void configureTempDirectory (File dir, WebAppContext context)
339 {
340 if (dir == null)
341 throw new IllegalArgumentException("Null temp dir");
342
343
344 if (dir.exists() && !context.isPersistTempDirectory())
345 {
346 if (!IO.delete(dir))
347 throw new IllegalStateException("Failed to delete temp dir "+dir);
348 }
349
350
351 if (!dir.exists())
352 dir.mkdirs();
353
354 if (!context.isPersistTempDirectory())
355 dir.deleteOnExit();
356
357
358 if (!dir.canWrite() || !dir.isDirectory())
359 throw new IllegalStateException("Temp dir "+dir+" not useable: writeable="+dir.canWrite()+", dir="+dir.isDirectory());
360 }
361
362
363 public void unpack (WebAppContext context) throws IOException
364 {
365 Resource web_app = context.getBaseResource();
366 _preUnpackBaseResource = context.getBaseResource();
367
368 if (web_app == null)
369 {
370 String war = context.getWar();
371 if (war!=null && war.length()>0)
372 web_app = context.newResource(war);
373 else
374 web_app=context.getBaseResource();
375
376
377 if (web_app.getAlias() != null)
378 {
379 LOG.debug(web_app + " anti-aliased to " + web_app.getAlias());
380 web_app = context.newResource(web_app.getAlias());
381 }
382
383 if (LOG.isDebugEnabled())
384 LOG.debug("Try webapp=" + web_app + ", exists=" + web_app.exists() + ", directory=" + web_app.isDirectory()+" file="+(web_app.getFile()));
385
386 if (web_app.exists() && !web_app.isDirectory() && !web_app.toString().startsWith("jar:"))
387 {
388
389 Resource jarWebApp = JarResource.newJarResource(web_app);
390 if (jarWebApp.exists() && jarWebApp.isDirectory())
391 web_app= jarWebApp;
392 }
393
394
395 if (web_app.exists() && (
396 (context.isCopyWebDir() && web_app.getFile() != null && web_app.getFile().isDirectory()) ||
397 (context.isExtractWAR() && web_app.getFile() != null && !web_app.getFile().isDirectory()) ||
398 (context.isExtractWAR() && web_app.getFile() == null) ||
399 !web_app.isDirectory())
400 )
401 {
402
403 File extractedWebAppDir = null;
404
405 if (war!=null)
406 {
407
408 File warfile=Resource.newResource(war).getFile();
409 if (warfile!=null && warfile.getName().toLowerCase(Locale.ENGLISH).endsWith(".war"))
410 {
411 File sibling = new File(warfile.getParent(),warfile.getName().substring(0,warfile.getName().length()-4));
412 if (sibling.exists() && sibling.isDirectory() && sibling.canWrite())
413 extractedWebAppDir=sibling;
414 }
415 }
416
417 if (extractedWebAppDir==null)
418
419 extractedWebAppDir= new File(context.getTempDirectory(), "webapp");
420
421 if (web_app.getFile()!=null && web_app.getFile().isDirectory())
422 {
423
424 LOG.debug("Copy " + web_app + " to " + extractedWebAppDir);
425 web_app.copyTo(extractedWebAppDir);
426 }
427 else
428 {
429
430
431 File extractionLock = new File (context.getTempDirectory(), ".extract_lock");
432
433 if (!extractedWebAppDir.exists())
434 {
435
436 extractionLock.createNewFile();
437 extractedWebAppDir.mkdir();
438 LOG.debug("Extract " + web_app + " to " + extractedWebAppDir);
439 Resource jar_web_app = JarResource.newJarResource(web_app);
440 jar_web_app.copyTo(extractedWebAppDir);
441 extractionLock.delete();
442 }
443 else
444 {
445
446 if (web_app.lastModified() > extractedWebAppDir.lastModified() || extractionLock.exists())
447 {
448 extractionLock.createNewFile();
449 IO.delete(extractedWebAppDir);
450 extractedWebAppDir.mkdir();
451 LOG.debug("Extract " + web_app + " to " + extractedWebAppDir);
452 Resource jar_web_app = JarResource.newJarResource(web_app);
453 jar_web_app.copyTo(extractedWebAppDir);
454 extractionLock.delete();
455 }
456 }
457 }
458 web_app = Resource.newResource(extractedWebAppDir.getCanonicalPath());
459 }
460
461
462 if (!web_app.exists() || !web_app.isDirectory())
463 {
464 LOG.warn("Web application not found " + war);
465 throw new java.io.FileNotFoundException(war);
466 }
467
468 context.setBaseResource(web_app);
469
470 if (LOG.isDebugEnabled())
471 LOG.debug("webapp=" + web_app);
472 }
473
474
475
476 if (context.isCopyWebInf() && !context.isCopyWebDir())
477 {
478 Resource web_inf= web_app.addPath("WEB-INF/");
479
480 File extractedWebInfDir= new File(context.getTempDirectory(), "webinf");
481 if (extractedWebInfDir.exists())
482 IO.delete(extractedWebInfDir);
483 extractedWebInfDir.mkdir();
484 Resource web_inf_lib = web_inf.addPath("lib/");
485 File webInfDir=new File(extractedWebInfDir,"WEB-INF");
486 webInfDir.mkdir();
487
488 if (web_inf_lib.exists())
489 {
490 File webInfLibDir = new File(webInfDir, "lib");
491 if (webInfLibDir.exists())
492 IO.delete(webInfLibDir);
493 webInfLibDir.mkdir();
494
495 LOG.debug("Copying WEB-INF/lib " + web_inf_lib + " to " + webInfLibDir);
496 web_inf_lib.copyTo(webInfLibDir);
497 }
498
499 Resource web_inf_classes = web_inf.addPath("classes/");
500 if (web_inf_classes.exists())
501 {
502 File webInfClassesDir = new File(webInfDir, "classes");
503 if (webInfClassesDir.exists())
504 IO.delete(webInfClassesDir);
505 webInfClassesDir.mkdir();
506 LOG.debug("Copying WEB-INF/classes from "+web_inf_classes+" to "+webInfClassesDir.getAbsolutePath());
507 web_inf_classes.copyTo(webInfClassesDir);
508 }
509
510 web_inf=Resource.newResource(extractedWebInfDir.getCanonicalPath());
511
512 ResourceCollection rc = new ResourceCollection(web_inf,web_app);
513
514 if (LOG.isDebugEnabled())
515 LOG.debug("context.resourcebase = "+rc);
516
517 context.setBaseResource(rc);
518 }
519 }
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535 public static String getCanonicalNameForWebAppTmpDir (WebAppContext context)
536 {
537 StringBuffer canonicalName = new StringBuffer();
538 canonicalName.append("jetty-");
539
540
541 Server server=context.getServer();
542 if (server!=null)
543 {
544 Connector[] connectors = context.getServer().getConnectors();
545
546 if (connectors.length>0)
547 {
548
549 String host=null;
550 int port=0;
551 if (connectors!=null && (connectors[0] instanceof NetworkConnector))
552 {
553 NetworkConnector connector = (NetworkConnector)connectors[0];
554 host=connector.getHost();
555 port=connector.getLocalPort();
556 if (port < 0)
557 port = connector.getPort();
558 }
559 if (host == null)
560 host = "0.0.0.0";
561 canonicalName.append(host);
562
563
564 canonicalName.append("-");
565
566
567
568 canonicalName.append(port);
569 canonicalName.append("-");
570 }
571 }
572
573
574
575 try
576 {
577 Resource resource = context.getBaseResource();
578 if (resource == null)
579 {
580 if (context.getWar()==null || context.getWar().length()==0)
581 resource=context.newResource(context.getResourceBase());
582
583
584 resource = context.newResource(context.getWar());
585 }
586
587 String tmp = URIUtil.decodePath(resource.getURL().getPath());
588 if (tmp.endsWith("/"))
589 tmp = tmp.substring(0, tmp.length()-1);
590 if (tmp.endsWith("!"))
591 tmp = tmp.substring(0, tmp.length() -1);
592
593 int i = tmp.lastIndexOf("/");
594 canonicalName.append(tmp.substring(i+1, tmp.length()));
595 canonicalName.append("-");
596 }
597 catch (Exception e)
598 {
599 LOG.warn("Can't generate resourceBase as part of webapp tmp dir name", e);
600 }
601
602
603 String contextPath = context.getContextPath();
604 contextPath=contextPath.replace('/','_');
605 contextPath=contextPath.replace('\\','_');
606 canonicalName.append(contextPath);
607
608
609 canonicalName.append("-");
610 String[] vhosts = context.getVirtualHosts();
611 if (vhosts == null || vhosts.length <= 0)
612 canonicalName.append("any");
613 else
614 canonicalName.append(vhosts[0]);
615
616
617 for (int i=0;i<canonicalName.length();i++)
618 {
619 char c=canonicalName.charAt(i);
620 if (!Character.isJavaIdentifierPart(c) && "-.".indexOf(c)<0)
621 canonicalName.setCharAt(i,'.');
622 }
623
624 canonicalName.append("-");
625
626 return canonicalName.toString();
627 }
628
629
630 protected List<Resource> findClassDirs (WebAppContext context)
631 throws Exception
632 {
633 if (context == null)
634 return null;
635
636 List<Resource> classDirs = new ArrayList<Resource>();
637
638 Resource webInfClasses = findWebInfClassesDir(context);
639 if (webInfClasses != null)
640 classDirs.add(webInfClasses);
641 List<Resource> extraClassDirs = findExtraClasspathDirs(context);
642 if (extraClassDirs != null)
643 classDirs.addAll(extraClassDirs);
644
645 return classDirs;
646 }
647
648
649
650
651
652
653
654
655
656 protected List<Resource> findJars (WebAppContext context)
657 throws Exception
658 {
659 List<Resource> jarResources = new ArrayList<Resource>();
660 List<Resource> webInfLibJars = findWebInfLibJars(context);
661 if (webInfLibJars != null)
662 jarResources.addAll(webInfLibJars);
663 List<Resource> extraClasspathJars = findExtraClasspathJars(context);
664 if (extraClasspathJars != null)
665 jarResources.addAll(extraClasspathJars);
666 return jarResources;
667 }
668
669
670
671
672
673
674
675
676 protected List<Resource> findWebInfLibJars(WebAppContext context)
677 throws Exception
678 {
679 Resource web_inf = context.getWebInf();
680 if (web_inf==null || !web_inf.exists())
681 return null;
682
683 List<Resource> jarResources = new ArrayList<Resource>();
684 Resource web_inf_lib = web_inf.addPath("/lib");
685 if (web_inf_lib.exists() && web_inf_lib.isDirectory())
686 {
687 String[] files=web_inf_lib.list();
688 for (int f=0;files!=null && f<files.length;f++)
689 {
690 try
691 {
692 Resource file = web_inf_lib.addPath(files[f]);
693 String fnlc = file.getName().toLowerCase(Locale.ENGLISH);
694 int dot = fnlc.lastIndexOf('.');
695 String extension = (dot < 0 ? null : fnlc.substring(dot));
696 if (extension != null && (extension.equals(".jar") || extension.equals(".zip")))
697 {
698 jarResources.add(file);
699 }
700 }
701 catch (Exception ex)
702 {
703 LOG.warn(Log.EXCEPTION,ex);
704 }
705 }
706 }
707 return jarResources;
708 }
709
710
711
712
713
714
715
716
717
718
719 protected List<Resource> findExtraClasspathJars(WebAppContext context)
720 throws Exception
721 {
722 if (context == null || context.getExtraClasspath() == null)
723 return null;
724
725 List<Resource> jarResources = new ArrayList<Resource>();
726 StringTokenizer tokenizer = new StringTokenizer(context.getExtraClasspath(), ",;");
727 while (tokenizer.hasMoreTokens())
728 {
729 Resource resource = context.newResource(tokenizer.nextToken().trim());
730 String fnlc = resource.getName().toLowerCase(Locale.ENGLISH);
731 int dot = fnlc.lastIndexOf('.');
732 String extension = (dot < 0 ? null : fnlc.substring(dot));
733 if (extension != null && (extension.equals(".jar") || extension.equals(".zip")))
734 {
735 jarResources.add(resource);
736 }
737 }
738
739 return jarResources;
740 }
741
742
743
744
745
746
747
748
749 protected Resource findWebInfClassesDir (WebAppContext context)
750 throws Exception
751 {
752 if (context == null)
753 return null;
754
755 Resource web_inf = context.getWebInf();
756
757
758 if (web_inf != null && web_inf.isDirectory())
759 {
760
761 Resource classes= web_inf.addPath("classes/");
762 if (classes.exists())
763 return classes;
764 }
765 return null;
766 }
767
768
769
770
771
772
773
774
775
776 protected List<Resource> findExtraClasspathDirs(WebAppContext context)
777 throws Exception
778 {
779 if (context == null || context.getExtraClasspath() == null)
780 return null;
781
782 List<Resource> dirResources = new ArrayList<Resource>();
783 StringTokenizer tokenizer = new StringTokenizer(context.getExtraClasspath(), ",;");
784 while (tokenizer.hasMoreTokens())
785 {
786 Resource resource = context.newResource(tokenizer.nextToken().trim());
787 if (resource.exists() && resource.isDirectory())
788 dirResources.add(resource);
789 }
790
791 return dirResources;
792 }
793
794
795 }