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