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