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