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