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