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 List<Resource> resources = (List<Resource>)context.getAttribute(RESOURCE_URLS);
147 if (resources!=null)
148 {
149 Resource[] collection=new Resource[resources.size()+1];
150 int i=0;
151 collection[i++]=context.getBaseResource();
152 for (Resource resource : resources)
153 collection[i++]=resource;
154 context.setBaseResource(new ResourceCollection(collection));
155 }
156 }
157
158 @Override
159 public void deconfigure(WebAppContext context) throws Exception
160 {
161
162 Boolean tmpdirConfigured = (Boolean)context.getAttribute(TEMPDIR_CONFIGURED);
163
164 if (context.getTempDirectory()!=null && (tmpdirConfigured == null || !tmpdirConfigured.booleanValue()) && !isTempWorkDirectory(context.getTempDirectory()))
165 {
166 IO.delete(context.getTempDirectory());
167 context.setTempDirectory(null);
168 }
169
170 context.setAttribute(TEMPDIR_CONFIGURED, null);
171 context.setAttribute(context.TEMPDIR, null);
172
173
174 context.setBaseResource(_preUnpackBaseResource);
175 }
176
177
178
179
180
181 @Override
182 public void cloneConfigure(WebAppContext template, WebAppContext context) throws Exception
183 {
184 File tmpDir=File.createTempFile(WebInfConfiguration.getCanonicalNameForWebAppTmpDir(context),"",template.getTempDirectory().getParentFile());
185 if (tmpDir.exists())
186 {
187 IO.delete(tmpDir);
188 }
189 tmpDir.mkdir();
190 tmpDir.deleteOnExit();
191 context.setTempDirectory(tmpDir);
192 }
193
194
195
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 public void resolveTempDirectory (WebAppContext context)
232 {
233
234 File tmpDir = context.getTempDirectory();
235 if (tmpDir != null && tmpDir.isDirectory() && tmpDir.canWrite())
236 {
237 context.setAttribute(TEMPDIR_CONFIGURED, Boolean.TRUE);
238 return;
239 }
240
241
242
243
244 File servletTmpDir = asFile(context.getAttribute(WebAppContext.TEMPDIR));
245 if (servletTmpDir != null && servletTmpDir.isDirectory() && servletTmpDir.canWrite())
246 {
247
248 tmpDir = servletTmpDir;
249
250 context.setAttribute(WebAppContext.TEMPDIR,tmpDir);
251
252 context.setTempDirectory(tmpDir);
253 return;
254 }
255
256 try
257 {
258
259 File work = new File(System.getProperty("jetty.home"),"work");
260 if (work.exists() && work.canWrite() && work.isDirectory())
261 {
262 makeTempDirectory(work, context, false);
263 }
264 else
265 {
266 File baseTemp = asFile(context.getAttribute(WebAppContext.BASETEMPDIR));
267 if (baseTemp != null && baseTemp.isDirectory() && baseTemp.canWrite())
268 {
269
270 makeTempDirectory(baseTemp,context,false);
271 }
272 else
273 {
274 makeTempDirectory(new File(System.getProperty("java.io.tmpdir")),context,true);
275 }
276 }
277 }
278 catch(Exception e)
279 {
280 tmpDir=null;
281 Log.ignore(e);
282 }
283
284
285
286 if (context.getTempDirectory() == null)
287 {
288 try
289 {
290
291 tmpDir=File.createTempFile("JettyContext","");
292 if (tmpDir.exists())
293 IO.delete(tmpDir);
294 tmpDir.mkdir();
295 tmpDir.deleteOnExit();
296 context.setTempDirectory(tmpDir);
297 }
298 catch(IOException e)
299 {
300 Log.warn("tmpdir",e); System.exit(1);
301 }
302 }
303 }
304
305
306
307
308
309
310
311 private File asFile(Object fileattr)
312 {
313 if (fileattr == null)
314 {
315 return null;
316 }
317 if (fileattr instanceof File)
318 {
319 return (File)fileattr;
320 }
321 if (fileattr instanceof String)
322 {
323 return new File((String)fileattr);
324 }
325 return null;
326 }
327
328
329
330 public void makeTempDirectory (File parent, WebAppContext context, boolean deleteExisting)
331 throws IOException
332 {
333 if (parent != null && parent.exists() && parent.canWrite() && parent.isDirectory())
334 {
335 String temp = getCanonicalNameForWebAppTmpDir(context);
336 File tmpDir = new File(parent,temp);
337
338 if (deleteExisting && tmpDir.exists())
339 {
340 if (!IO.delete(tmpDir))
341 {
342 if(Log.isDebugEnabled())Log.debug("Failed to delete temp dir "+tmpDir);
343 }
344
345
346 if (tmpDir.exists())
347 {
348 String old=tmpDir.toString();
349 tmpDir=File.createTempFile(temp+"_","");
350 if (tmpDir.exists())
351 IO.delete(tmpDir);
352 Log.warn("Can't reuse "+old+", using "+tmpDir);
353 }
354 }
355
356 if (!tmpDir.exists())
357 tmpDir.mkdir();
358
359
360 if (!isTempWorkDirectory(tmpDir))
361 {
362 tmpDir.deleteOnExit();
363
364 File sentinel = new File(tmpDir, ".active");
365 if(!sentinel.exists())
366 sentinel.mkdir();
367 }
368
369 if(Log.isDebugEnabled())
370 Log.debug("Set temp dir "+tmpDir);
371 context.setTempDirectory(tmpDir);
372 }
373 }
374
375
376 public void unpack (WebAppContext context) throws IOException
377 {
378 Resource web_app = context.getBaseResource();
379 _preUnpackBaseResource = context.getBaseResource();
380
381 if (web_app == null)
382 {
383 String war = context.getWar();
384 if (war!=null && war.length()>0)
385 web_app = context.newResource(war);
386 else
387 web_app=context.getBaseResource();
388
389
390 if (web_app.getAlias() != null)
391 {
392 Log.debug(web_app + " anti-aliased to " + web_app.getAlias());
393 web_app = context.newResource(web_app.getAlias());
394 }
395
396 if (Log.isDebugEnabled())
397 Log.debug("Try webapp=" + web_app + ", exists=" + web_app.exists() + ", directory=" + web_app.isDirectory());
398
399
400 if (web_app.exists() && !web_app.isDirectory() && !web_app.toString().startsWith("jar:"))
401 {
402
403 Resource jarWebApp = JarResource.newJarResource(web_app);
404 if (jarWebApp.exists() && jarWebApp.isDirectory())
405 web_app= jarWebApp;
406 }
407
408
409 if (web_app.exists() && (
410 (context.isCopyWebDir() && web_app.getFile() != null && web_app.getFile().isDirectory()) ||
411 (context.isExtractWAR() && web_app.getFile() != null && !web_app.getFile().isDirectory()) ||
412 (context.isExtractWAR() && web_app.getFile() == null) ||
413 !web_app.isDirectory())
414 )
415 {
416
417 File extractedWebAppDir = null;
418
419 if (war!=null)
420 {
421
422 File warfile=Resource.newResource(war).getFile();
423 if (warfile!=null)
424 {
425 File sibling = new File(warfile.getParent(),warfile.getName().substring(0,warfile.getName().length()-4));
426 if (sibling.exists() && sibling.isDirectory() && sibling.canWrite())
427 extractedWebAppDir=sibling;
428 }
429 }
430
431 if (extractedWebAppDir==null)
432
433 extractedWebAppDir= new File(context.getTempDirectory(), "webapp");
434
435 if (web_app.getFile()!=null && web_app.getFile().isDirectory())
436 {
437
438 Log.info("Copy " + web_app + " to " + extractedWebAppDir);
439 web_app.copyTo(extractedWebAppDir);
440 }
441 else
442 {
443 if (!extractedWebAppDir.exists())
444 {
445
446 extractedWebAppDir.mkdir();
447 Log.info("Extract " + web_app + " to " + extractedWebAppDir);
448 Resource jar_web_app = JarResource.newJarResource(web_app);
449 jar_web_app.copyTo(extractedWebAppDir);
450 }
451 else
452 {
453
454 if (web_app.lastModified() > extractedWebAppDir.lastModified())
455 {
456 IO.delete(extractedWebAppDir);
457 extractedWebAppDir.mkdir();
458 Log.info("Extract " + web_app + " to " + extractedWebAppDir);
459 Resource jar_web_app = JarResource.newJarResource(web_app);
460 jar_web_app.copyTo(extractedWebAppDir);
461 }
462 }
463 }
464 web_app = Resource.newResource(extractedWebAppDir.getCanonicalPath());
465 }
466
467
468 if (!web_app.exists() || !web_app.isDirectory())
469 {
470 Log.warn("Web application not found " + war);
471 throw new java.io.FileNotFoundException(war);
472 }
473
474 context.setBaseResource(web_app);
475
476 if (Log.isDebugEnabled())
477 Log.debug("webapp=" + web_app);
478 }
479
480
481
482
483 if (context.isCopyWebInf())
484 {
485 Resource web_inf= web_app.addPath("WEB-INF/");
486
487 if (web_inf instanceof ResourceCollection ||
488 web_inf.exists() &&
489 web_inf.isDirectory() &&
490 (web_inf.getFile()==null || !web_inf.getFile().isDirectory()))
491 {
492 File extractedWebInfDir= new File(context.getTempDirectory(), "webinf");
493 if (extractedWebInfDir.exists())
494 IO.delete(extractedWebInfDir);
495 extractedWebInfDir.mkdir();
496 Resource web_inf_lib = web_inf.addPath("lib/");
497 File webInfDir=new File(extractedWebInfDir,"WEB-INF");
498 webInfDir.mkdir();
499
500 if (web_inf_lib.exists())
501 {
502 File webInfLibDir = new File(webInfDir, "lib");
503 if (webInfLibDir.exists())
504 IO.delete(webInfLibDir);
505 webInfLibDir.mkdir();
506
507 Log.info("Copying WEB-INF/lib " + web_inf_lib + " to " + webInfLibDir);
508 web_inf_lib.copyTo(webInfLibDir);
509 }
510
511 Resource web_inf_classes = web_inf.addPath("classes/");
512 if (web_inf_classes.exists())
513 {
514 File webInfClassesDir = new File(webInfDir, "classes");
515 if (webInfClassesDir.exists())
516 IO.delete(webInfClassesDir);
517 webInfClassesDir.mkdir();
518 Log.info("Copying WEB-INF/classes from "+web_inf_classes+" to "+webInfClassesDir.getAbsolutePath());
519 web_inf_classes.copyTo(webInfClassesDir);
520 }
521
522 web_inf=Resource.newResource(extractedWebInfDir.getCanonicalPath());
523
524 ResourceCollection rc = new ResourceCollection(web_inf,web_app);
525
526 if (Log.isDebugEnabled())
527 Log.debug("context.resourcebase = "+rc);
528
529 context.setBaseResource(rc);
530 }
531 }
532 }
533
534
535 public File findWorkDirectory (WebAppContext context) throws IOException
536 {
537 if (context.getBaseResource() != null)
538 {
539 Resource web_inf = context.getWebInf();
540 if (web_inf !=null && web_inf.exists())
541 {
542 return new File(web_inf.getFile(),"work");
543 }
544 }
545 return null;
546 }
547
548
549
550
551
552
553
554 public boolean isTempWorkDirectory (File tmpDir)
555 {
556 if (tmpDir == null)
557 return false;
558 if (tmpDir.getName().equalsIgnoreCase("work"))
559 return true;
560 File t = tmpDir.getParentFile();
561 if (t == null)
562 return false;
563 return (t.getName().equalsIgnoreCase("work"));
564 }
565
566
567
568
569
570
571
572
573
574
575
576 public static String getCanonicalNameForWebAppTmpDir (WebAppContext context)
577 {
578 StringBuffer canonicalName = new StringBuffer();
579 canonicalName.append("jetty-");
580
581
582 Server server=context.getServer();
583 if (server!=null)
584 {
585 Connector[] connectors = context.getServer().getConnectors();
586
587 if (connectors.length>0)
588 {
589
590 String host = (connectors==null||connectors[0]==null?"":connectors[0].getHost());
591 if (host == null)
592 host = "0.0.0.0";
593 canonicalName.append(host);
594
595
596 canonicalName.append("-");
597
598 int port = (connectors==null||connectors[0]==null?0:connectors[0].getLocalPort());
599
600
601 if (port < 0)
602 port = connectors[0].getPort();
603 canonicalName.append(port);
604 canonicalName.append("-");
605 }
606 }
607
608
609
610 try
611 {
612 Resource resource = context.getBaseResource();
613 if (resource == null)
614 {
615 if (context.getWar()==null || context.getWar().length()==0)
616 resource=context.newResource(context.getResourceBase());
617
618
619 resource = context.newResource(context.getWar());
620 }
621
622 String tmp = URIUtil.decodePath(resource.getURL().getPath());
623 if (tmp.endsWith("/"))
624 tmp = tmp.substring(0, tmp.length()-1);
625 if (tmp.endsWith("!"))
626 tmp = tmp.substring(0, tmp.length() -1);
627
628 int i = tmp.lastIndexOf("/");
629 canonicalName.append(tmp.substring(i+1, tmp.length()));
630 canonicalName.append("-");
631 }
632 catch (Exception e)
633 {
634 Log.warn("Can't generate resourceBase as part of webapp tmp dir name", e);
635 }
636
637
638 String contextPath = context.getContextPath();
639 contextPath=contextPath.replace('/','_');
640 contextPath=contextPath.replace('\\','_');
641 canonicalName.append(contextPath);
642
643
644 canonicalName.append("-");
645 String[] vhosts = context.getVirtualHosts();
646 if (vhosts == null || vhosts.length <= 0)
647 canonicalName.append("any");
648 else
649 canonicalName.append(vhosts[0]);
650
651
652 for (int i=0;i<canonicalName.length();i++)
653 {
654 char c=canonicalName.charAt(i);
655 if (!Character.isJavaIdentifierPart(c) && "-.".indexOf(c)<0)
656 canonicalName.setCharAt(i,'.');
657 }
658
659 canonicalName.append("-");
660 return canonicalName.toString();
661 }
662
663
664
665
666
667
668
669 protected List<Resource> findJars (WebAppContext context)
670 throws Exception
671 {
672 List<Resource> jarResources = new ArrayList<Resource>();
673
674 Resource web_inf = context.getWebInf();
675 if (web_inf==null || !web_inf.exists())
676 return null;
677
678 Resource web_inf_lib = web_inf.addPath("/lib");
679
680
681 if (web_inf_lib.exists() && web_inf_lib.isDirectory())
682 {
683 String[] files=web_inf_lib.list();
684 for (int f=0;files!=null && f<files.length;f++)
685 {
686 try
687 {
688 Resource file = web_inf_lib.addPath(files[f]);
689 String fnlc = file.getName().toLowerCase();
690 int dot = fnlc.lastIndexOf('.');
691 String extension = (dot < 0 ? null : fnlc.substring(dot));
692 if (extension != null && (extension.equals(".jar") || extension.equals(".zip")))
693 {
694 jarResources.add(file);
695 }
696 }
697 catch (Exception ex)
698 {
699 Log.warn(Log.EXCEPTION,ex);
700 }
701 }
702 }
703 return jarResources;
704 }
705 }