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