1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.myfaces.application;
20
21 import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFWebConfigParam;
22 import org.apache.myfaces.shared.resource.ResourceHandlerCache;
23 import org.apache.myfaces.shared.resource.ResourceHandlerCache.ResourceValue;
24 import org.apache.myfaces.shared.resource.ResourceHandlerSupport;
25 import org.apache.myfaces.shared.resource.ResourceImpl;
26 import org.apache.myfaces.shared.resource.ResourceLoader;
27 import org.apache.myfaces.shared.resource.ResourceMeta;
28 import org.apache.myfaces.shared.resource.ResourceValidationUtils;
29 import org.apache.myfaces.shared.util.ClassUtils;
30 import org.apache.myfaces.shared.util.ExternalContextUtils;
31 import org.apache.myfaces.shared.util.StringUtils;
32 import org.apache.myfaces.shared.util.WebConfigParamUtils;
33
34 import javax.faces.application.Resource;
35 import javax.faces.application.ResourceHandler;
36 import javax.faces.application.ResourceWrapper;
37 import javax.faces.context.ExternalContext;
38 import javax.faces.context.FacesContext;
39 import javax.servlet.http.HttpServletResponse;
40 import java.io.IOException;
41 import java.io.InputStream;
42 import java.io.OutputStream;
43 import java.net.URL;
44 import java.util.Locale;
45 import java.util.Map;
46 import java.util.MissingResourceException;
47 import java.util.ResourceBundle;
48 import java.util.logging.Level;
49 import java.util.logging.Logger;
50
51
52
53
54
55
56
57
58 public class ResourceHandlerImpl extends ResourceHandler
59 {
60
61 private static final String IS_RESOURCE_REQUEST = "org.apache.myfaces.IS_RESOURCE_REQUEST";
62
63 private ResourceHandlerSupport _resourceHandlerSupport;
64
65 private ResourceHandlerCache _resourceHandlerCache;
66
67
68 private static final Logger log = Logger.getLogger(ResourceHandlerImpl.class.getName());
69
70
71
72
73 @JSFWebConfigParam(since="2.1.6, 2.0.12", defaultValue="false",
74 expectedValues="true, false", group="resources")
75 public static final String INIT_PARAM_STRICT_JSF_2_ALLOW_SLASH_LIBRARY_NAME =
76 "org.apache.myfaces.STRICT_JSF_2_ALLOW_SLASH_LIBRARY_NAME";
77 public static final boolean INIT_PARAM_STRICT_JSF_2_ALLOW_SLASH_LIBRARY_NAME_DEFAULT = false;
78
79
80
81
82
83
84 @JSFWebConfigParam(since="2.1.10, 2.0.16", defaultValue="2048", group="resources")
85 public static final String INIT_PARAM_RESOURCE_BUFFER_SIZE = "org.apache.myfaces.RESOURCE_BUFFER_SIZE";
86 private static final int INIT_PARAM_RESOURCE_BUFFER_SIZE_DEFAULT = 2048;
87
88 private Boolean _allowSlashLibraryName;
89 private int _resourceBufferSize = -1;
90
91 @Override
92 public Resource createResource(String resourceName)
93 {
94 return createResource(resourceName, null);
95 }
96
97 @Override
98 public Resource createResource(String resourceName, String libraryName)
99 {
100 return createResource(resourceName, libraryName, null);
101 }
102
103 @Override
104 public Resource createResource(String resourceName, String libraryName,
105 String contentType)
106 {
107 Resource resource = null;
108
109 if (!ResourceValidationUtils.isValidResourceName(resourceName))
110 {
111 return null;
112 }
113 if (libraryName != null && !ResourceValidationUtils.isValidLibraryName(
114 libraryName, isAllowSlashesLibraryName()))
115 {
116 return null;
117 }
118
119 if (contentType == null)
120 {
121
122 contentType = FacesContext.getCurrentInstance().getExternalContext().getMimeType(resourceName);
123 }
124
125 final String localePrefix = getLocalePrefixForLocateResource();
126
127
128 if(getResourceLoaderCache().containsResource(resourceName, libraryName, contentType, localePrefix))
129 {
130 ResourceValue resourceValue = getResourceLoaderCache().getResource(
131 resourceName, libraryName, contentType, localePrefix);
132
133 resource = new ResourceImpl(resourceValue.getResourceMeta(), resourceValue.getResourceLoader(),
134 getResourceHandlerSupport(), contentType);
135 }
136 else
137 {
138 for (ResourceLoader loader : getResourceHandlerSupport().getResourceLoaders())
139 {
140 ResourceMeta resourceMeta = deriveResourceMeta(loader, resourceName, libraryName, localePrefix);
141
142 if (resourceMeta != null)
143 {
144 resource = new ResourceImpl(resourceMeta, loader, getResourceHandlerSupport(), contentType);
145
146
147 getResourceLoaderCache().putResource(resourceName, libraryName, contentType,
148 localePrefix, resourceMeta, loader);
149 break;
150 }
151 }
152 }
153
154 return resource;
155 }
156
157
158
159
160
161
162
163 protected ResourceMeta deriveResourceMeta(ResourceLoader resourceLoader,
164 String resourceName, String libraryName, String localePrefix)
165 {
166 String resourceVersion = null;
167 String libraryVersion = null;
168 ResourceMeta resourceId = null;
169
170
171 if (localePrefix != null)
172 {
173 if (null != libraryName)
174 {
175 String pathToLib = localePrefix + '/' + libraryName;
176 libraryVersion = resourceLoader.getLibraryVersion(pathToLib);
177
178 if (null != libraryVersion)
179 {
180 String pathToResource = localePrefix + '/'
181 + libraryName + '/' + libraryVersion + '/'
182 + resourceName;
183 resourceVersion = resourceLoader
184 .getResourceVersion(pathToResource);
185 }
186 else
187 {
188 String pathToResource = localePrefix + '/'
189 + libraryName + '/' + resourceName;
190 resourceVersion = resourceLoader
191 .getResourceVersion(pathToResource);
192 }
193
194 if (!(resourceVersion != null && ResourceLoader.VERSION_INVALID.equals(resourceVersion)))
195 {
196 resourceId = resourceLoader.createResourceMeta(localePrefix, libraryName,
197 libraryVersion, resourceName, resourceVersion);
198 }
199 }
200 else
201 {
202 resourceVersion = resourceLoader
203 .getResourceVersion(localePrefix + '/'+ resourceName);
204 if (!(resourceVersion != null && ResourceLoader.VERSION_INVALID.equals(resourceVersion)))
205 {
206 resourceId = resourceLoader.createResourceMeta(localePrefix, null, null,
207 resourceName, resourceVersion);
208 }
209 }
210
211 if (resourceId != null)
212 {
213 URL url = resourceLoader.getResourceURL(resourceId);
214 if (url == null)
215 {
216 resourceId = null;
217 }
218 }
219 }
220
221
222 if (resourceId == null)
223 {
224 if (null != libraryName)
225 {
226 libraryVersion = resourceLoader.getLibraryVersion(libraryName);
227
228 if (null != libraryVersion)
229 {
230 String pathToResource = (libraryName + '/' + libraryVersion
231 + '/' + resourceName);
232 resourceVersion = resourceLoader
233 .getResourceVersion(pathToResource);
234 }
235 else
236 {
237 String pathToResource = (libraryName + '/'
238 + resourceName);
239 resourceVersion = resourceLoader
240 .getResourceVersion(pathToResource);
241 }
242
243 if (!(resourceVersion != null && ResourceLoader.VERSION_INVALID.equals(resourceVersion)))
244 {
245 resourceId = resourceLoader.createResourceMeta(null, libraryName,
246 libraryVersion, resourceName, resourceVersion);
247 }
248 }
249 else
250 {
251 resourceVersion = resourceLoader
252 .getResourceVersion(resourceName);
253
254 if (!(resourceVersion != null && ResourceLoader.VERSION_INVALID.equals(resourceVersion)))
255 {
256 resourceId = resourceLoader.createResourceMeta(null, null, null,
257 resourceName, resourceVersion);
258 }
259 }
260
261 if (resourceId != null)
262 {
263 URL url = resourceLoader.getResourceURL(resourceId);
264 if (url == null)
265 {
266 resourceId = null;
267 }
268 }
269 }
270
271 return resourceId;
272 }
273
274 @Override
275 public String getRendererTypeForResourceName(String resourceName)
276 {
277 if (resourceName.endsWith(".js"))
278 {
279 return "javax.faces.resource.Script";
280 }
281 else if (resourceName.endsWith(".css"))
282 {
283 return "javax.faces.resource.Stylesheet";
284 }
285 return null;
286 }
287
288
289
290
291
292
293
294 @Override
295 public void handleResourceRequest(FacesContext facesContext) throws IOException
296 {
297
298
299 String resourceBasePath = getResourceHandlerSupport()
300 .calculateResourceBasePath(facesContext);
301
302 if (resourceBasePath == null)
303 {
304
305
306
307
308 return;
309 }
310
311
312
313
314
315
316 ExternalContext extContext = facesContext.getExternalContext();
317 Object response = extContext.getResponse();
318 HttpServletResponse httpServletResponse = ExternalContextUtils.getHttpServletResponse(response);
319 if (httpServletResponse == null)
320 {
321 throw new IllegalStateException("Could not obtain an instance of HttpServletResponse.");
322 }
323
324 if (isResourceIdentifierExcluded(facesContext, resourceBasePath))
325 {
326 httpServletResponse.setStatus(HttpServletResponse.SC_NOT_FOUND);
327 return;
328 }
329
330 String resourceName = null;
331 if (resourceBasePath.startsWith(ResourceHandler.RESOURCE_IDENTIFIER))
332 {
333 resourceName = resourceBasePath
334 .substring(ResourceHandler.RESOURCE_IDENTIFIER.length() + 1);
335
336 if (resourceBasePath != null && !ResourceValidationUtils.isValidResourceName(resourceName))
337 {
338 httpServletResponse.setStatus(HttpServletResponse.SC_NOT_FOUND);
339 return;
340 }
341 }
342 else
343 {
344
345 httpServletResponse.setStatus(HttpServletResponse.SC_NOT_FOUND);
346 return;
347 }
348
349 String libraryName = facesContext.getExternalContext()
350 .getRequestParameterMap().get("ln");
351
352 if (libraryName != null && !ResourceValidationUtils.isValidLibraryName(
353 libraryName, isAllowSlashesLibraryName()))
354 {
355 httpServletResponse.setStatus(HttpServletResponse.SC_NOT_FOUND);
356 return;
357 }
358
359 Resource resource = null;
360 if (libraryName != null)
361 {
362
363 resource = facesContext.getApplication().getResourceHandler().createResource(resourceName, libraryName);
364 }
365 else
366 {
367 resource = facesContext.getApplication().getResourceHandler().createResource(resourceName);
368 }
369
370 if (resource == null)
371 {
372 httpServletResponse.setStatus(HttpServletResponse.SC_NOT_FOUND);
373 return;
374 }
375
376 if (!resource.userAgentNeedsUpdate(facesContext))
377 {
378 httpServletResponse.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
379 return;
380 }
381
382 httpServletResponse.setContentType(_getContentType(resource, facesContext.getExternalContext()));
383
384 Map<String, String> headers = resource.getResponseHeaders();
385
386 for (Map.Entry<String, String> entry : headers.entrySet())
387 {
388 httpServletResponse.setHeader(entry.getKey(), entry.getValue());
389 }
390
391
392 extContext.setResponseBufferSize(this.getResourceBufferSize());
393
394
395 try
396 {
397 InputStream in = resource.getInputStream();
398 OutputStream out = httpServletResponse.getOutputStream();
399
400 byte[] buffer = new byte[this.getResourceBufferSize()];
401
402 try
403 {
404 int count = pipeBytes(in, out, buffer);
405
406 httpServletResponse.setContentLength(count);
407 }
408 finally
409 {
410 try
411 {
412 in.close();
413 }
414 finally
415 {
416 out.close();
417 }
418 }
419 }
420 catch (IOException e)
421 {
422
423 if (log.isLoggable(Level.SEVERE))
424 {
425 log.severe("Error trying to load resource " + resourceName
426 + " with library " + libraryName + " :"
427 + e.getMessage());
428 }
429 httpServletResponse.setStatus(HttpServletResponse.SC_NOT_FOUND);
430 }
431
432
433
434
435
436
437
438
439 }
440
441
442
443
444
445 private static int pipeBytes(InputStream in, OutputStream out, byte[] buffer)
446 throws IOException
447 {
448 int count = 0;
449 int length;
450
451 while ((length = (in.read(buffer))) >= 0)
452 {
453 out.write(buffer, 0, length);
454 count += length;
455 }
456 return count;
457 }
458
459 @Override
460 public boolean isResourceRequest(FacesContext facesContext)
461 {
462
463
464
465 Boolean value = (Boolean) facesContext.getAttributes().get(IS_RESOURCE_REQUEST);
466
467 if (value != null && value)
468 {
469
470 return value;
471 }
472 else
473 {
474 String resourceBasePath = getResourceHandlerSupport()
475 .calculateResourceBasePath(facesContext);
476
477 if (resourceBasePath != null
478 && resourceBasePath.startsWith(ResourceHandler.RESOURCE_IDENTIFIER))
479 {
480 facesContext.getAttributes().put(IS_RESOURCE_REQUEST, Boolean.TRUE);
481 return true;
482 }
483 else
484 {
485 facesContext.getAttributes().put(IS_RESOURCE_REQUEST, Boolean.FALSE);
486 return false;
487 }
488 }
489 }
490
491 protected String getLocalePrefixForLocateResource()
492 {
493 String localePrefix = null;
494 FacesContext context = FacesContext.getCurrentInstance();
495 boolean isResourceRequest = context.getApplication().getResourceHandler().isResourceRequest(context);
496
497 if (isResourceRequest)
498 {
499 localePrefix = context.getExternalContext().getRequestParameterMap().get("loc");
500
501 if (localePrefix != null)
502 {
503 if (!ResourceValidationUtils.isValidLocalePrefix(localePrefix))
504 {
505 return null;
506 }
507 return localePrefix;
508 }
509 }
510
511 String bundleName = context.getApplication().getMessageBundle();
512
513 if (null != bundleName)
514 {
515 Locale locale = null;
516
517 if (isResourceRequest || context.getViewRoot() == null)
518 {
519 locale = context.getApplication().getViewHandler()
520 .calculateLocale(context);
521 }
522 else
523 {
524 locale = context.getViewRoot().getLocale();
525 }
526
527 try
528 {
529 ResourceBundle bundle = ResourceBundle
530 .getBundle(bundleName, locale, ClassUtils.getContextClassLoader());
531
532 if (bundle != null)
533 {
534 localePrefix = bundle.getString(ResourceHandler.LOCALE_PREFIX);
535 }
536 }
537 catch (MissingResourceException e)
538 {
539
540 }
541 }
542 return localePrefix;
543 }
544
545 protected boolean isResourceIdentifierExcluded(FacesContext context,
546 String resourceIdentifier)
547 {
548 String value = context.getExternalContext().getInitParameter(
549 RESOURCE_EXCLUDES_PARAM_NAME);
550 if (value == null)
551 {
552 value = RESOURCE_EXCLUDES_DEFAULT_VALUE;
553 }
554
555 String[] extensions = StringUtils.splitShortString(value, ' ');
556 for (int i = 0; i < extensions.length; i++)
557 {
558 if (resourceIdentifier.endsWith(extensions[i]))
559 {
560 return true;
561 }
562 }
563 return false;
564 }
565
566
567
568
569
570
571
572 @Override
573 public boolean libraryExists(String libraryName)
574 {
575 String localePrefix = getLocalePrefixForLocateResource();
576
577 String pathToLib = null;
578
579 if (libraryName != null && !ResourceValidationUtils.isValidLibraryName(
580 libraryName, isAllowSlashesLibraryName()))
581 {
582 return false;
583 }
584
585 if (localePrefix != null)
586 {
587
588 pathToLib = localePrefix + '/' + libraryName;
589
590 for (ResourceLoader loader : getResourceHandlerSupport()
591 .getResourceLoaders())
592 {
593 if (loader.libraryExists(pathToLib))
594 {
595 return true;
596 }
597 }
598 }
599
600
601 for (ResourceLoader loader : getResourceHandlerSupport()
602 .getResourceLoaders())
603 {
604 if (loader.libraryExists(libraryName))
605 {
606 return true;
607 }
608 }
609
610 return false;
611 }
612
613
614
615
616
617 public void setResourceHandlerSupport(
618 ResourceHandlerSupport resourceHandlerSupport)
619 {
620 _resourceHandlerSupport = resourceHandlerSupport;
621 }
622
623
624
625
626 protected ResourceHandlerSupport getResourceHandlerSupport()
627 {
628 if (_resourceHandlerSupport == null)
629 {
630 _resourceHandlerSupport = new DefaultResourceHandlerSupport();
631 }
632 return _resourceHandlerSupport;
633 }
634
635 private ResourceHandlerCache getResourceLoaderCache()
636 {
637 if (_resourceHandlerCache == null)
638 {
639 _resourceHandlerCache = new ResourceHandlerCache();
640 }
641 return _resourceHandlerCache;
642 }
643
644 private String _getContentType(Resource resource, ExternalContext externalContext)
645 {
646 String contentType = resource.getContentType();
647
648
649 if (contentType == null || contentType.length() == 0)
650 {
651 String resourceName = getWrappedResourceName(resource);
652
653 if (resourceName != null)
654 {
655 contentType = externalContext.getMimeType(resourceName);
656 }
657 }
658
659 return contentType;
660 }
661
662
663
664
665
666
667
668
669 private String getWrappedResourceName(Resource resource)
670 {
671 String resourceName = resource.getResourceName();
672 if (resourceName != null)
673 {
674 return resourceName;
675 }
676
677 if (resource instanceof ResourceWrapper)
678 {
679 return getWrappedResourceName(((ResourceWrapper) resource).getWrapped());
680 }
681
682 return null;
683 }
684
685 protected boolean isAllowSlashesLibraryName()
686 {
687 if (_allowSlashLibraryName == null)
688 {
689 _allowSlashLibraryName = WebConfigParamUtils.getBooleanInitParameter(
690 FacesContext.getCurrentInstance().getExternalContext(),
691 INIT_PARAM_STRICT_JSF_2_ALLOW_SLASH_LIBRARY_NAME,
692 INIT_PARAM_STRICT_JSF_2_ALLOW_SLASH_LIBRARY_NAME_DEFAULT);
693 }
694 return _allowSlashLibraryName;
695 }
696
697 protected int getResourceBufferSize()
698 {
699 if (_resourceBufferSize == -1)
700 {
701 _resourceBufferSize = WebConfigParamUtils.getIntegerInitParameter(
702 FacesContext.getCurrentInstance().getExternalContext(),
703 INIT_PARAM_RESOURCE_BUFFER_SIZE,
704 INIT_PARAM_RESOURCE_BUFFER_SIZE_DEFAULT);
705 }
706 return _resourceBufferSize;
707 }
708
709 }