Skip to content

Commit 9bf8116

Browse files
committed
fix isServingURLAllowed in development mode, add caching and disable grailsResourceLocator in others than development mode by default
1 parent e247f0a commit 9bf8116

File tree

1 file changed

+53
-9
lines changed

1 file changed

+53
-9
lines changed

src/groovy/org/grails/plugin/resource/ResourceProcessor.groovy

Lines changed: 53 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import grails.util.Holders
55
import groovy.util.logging.Commons
66

77
import java.util.concurrent.ConcurrentHashMap
8+
import java.util.concurrent.ConcurrentMap
89

910
import javax.servlet.ServletContext
1011
import javax.servlet.ServletRequest
@@ -24,6 +25,8 @@ import org.springframework.util.AntPathMatcher
2425
import org.springframework.web.context.ServletContextAware
2526
import org.springframework.web.util.WebUtils
2627

28+
import com.googlecode.concurrentlinkedhashmap.ConcurrentLinkedHashMap
29+
2730
/**
2831
* Primary service facade to actions on resources.
2932
*
@@ -91,11 +94,26 @@ class ResourceProcessor implements InitializingBean, ServletContextAware {
9194
List adHocExcludesLowerCase
9295

9396
List optionalDispositions
97+
98+
boolean resourceLocatorEnabled
99+
boolean serveUnderRootPathOnly
100+
101+
ConcurrentMap<String, Boolean> servingAllowedCache
102+
ConcurrentMap<String, Boolean> resourceAllowedCache
103+
104+
protected ConcurrentLinkedHashMap<String, Boolean> createDefaultAuthorizationCache() {
105+
return new ConcurrentLinkedHashMap.Builder<String, Boolean>()
106+
.maximumWeightedCapacity(5000)
107+
.build();
108+
}
94109

95110
/**
96111
* Initialize bean after properties have been set.
97112
*/
98113
void afterPropertiesSet() {
114+
servingAllowedCache = createDefaultAuthorizationCache()
115+
resourceAllowedCache = createDefaultAuthorizationCache()
116+
99117
processingEnabled = getConfigParamOrDefault('processing.enabled', true)
100118
adHocIncludes = getConfigParamOrDefault('adhoc.includes', DEFAULT_ADHOC_INCLUDES)
101119
adHocIncludes = adHocIncludes.collect { it.startsWith('/') ? it : '/' + it }
@@ -111,6 +129,10 @@ class ResourceProcessor implements InitializingBean, ServletContextAware {
111129
optionalDispositions = getConfigParamOrDefault('optional.dispositions', ['inline', 'image'])
112130

113131
rootUrlNormalized = urlToNormalizedFormat(resolveUriToURL('/'))
132+
133+
boolean developmentMode = Environment.getCurrent().isDevelopmentMode()
134+
resourceLocatorEnabled = getConfigParamOrDefault('resourceLocatorEnabled', developmentMode)
135+
serveUnderRootPathOnly = getConfigParamOrDefault('serveUnderRootPathOnly', (resourceLocatorEnabled==false))
114136
}
115137

116138
/**
@@ -206,6 +228,15 @@ class ResourceProcessor implements InitializingBean, ServletContextAware {
206228
}
207229

208230
boolean canProcessLegacyResource(uri) {
231+
Boolean result = resourceAllowedCache.get(uri)
232+
if(result == null) {
233+
result = doCanProcessLegacyResource(uri)
234+
resourceAllowedCache.put(uri, result)
235+
}
236+
result
237+
}
238+
239+
boolean doCanProcessLegacyResource(uri) {
209240
// Apply our own url filtering rules because servlet mapping uris are too lame
210241
boolean included = adHocIncludes.find { p ->
211242
PATH_MATCHER.match(p, uri)
@@ -221,16 +252,29 @@ class ResourceProcessor implements InitializingBean, ServletContextAware {
221252
return included
222253
}
223254

224-
boolean isServingURLAllowed(URL url) {
255+
boolean isServingURLAllowed(String uri, URL url) {
256+
Boolean result = servingAllowedCache.get(uri)
257+
if(result == null) {
258+
result = doIsServingURLAllowed(uri, url)
259+
servingAllowedCache.put(uri, result)
260+
}
261+
result
262+
}
263+
264+
boolean doIsServingURLAllowed(String uri, URL url) {
225265
if(url == null) return null
226-
String urlAsString = urlToNormalizedFormat(url)
227-
if(urlAsString==null || rootUrlNormalized == null || !urlAsString.startsWith(rootUrlNormalized)) {
228-
return false;
266+
if(serveUnderRootPathOnly) {
267+
String urlAsString = urlToNormalizedFormat(url)
268+
if(urlAsString==null || rootUrlNormalized == null || !urlAsString.startsWith(rootUrlNormalized)) {
269+
return false
270+
}
271+
String relativePath = urlAsString.substring(rootUrlNormalized.length()-1)
272+
return canProcessLegacyResource(relativePath)
273+
} else {
274+
return canProcessLegacyResource(uri)
229275
}
230-
String relativePath = urlAsString.substring(rootUrlNormalized.length()-1)
231-
return canProcessLegacyResource(relativePath)
232276
}
233-
277+
234278
static String urlToNormalizedFormat(URL url) {
235279
url != null ? url.toURI().normalize().toASCIIString() : null
236280
}
@@ -530,7 +574,7 @@ class ResourceProcessor implements InitializingBean, ServletContextAware {
530574
if (url == null) {
531575
return null
532576
}
533-
if (isServingURLAllowed(url)) {
577+
if (isServingURLAllowed(uri, url)) {
534578
return url
535579
} else {
536580
log.warn("Serving url ${url} isn't allowed.")
@@ -540,7 +584,7 @@ class ResourceProcessor implements InitializingBean, ServletContextAware {
540584

541585
private URL resolveUriToURL(uri) {
542586
URL url = null
543-
if (grailsResourceLocator != null) {
587+
if (resourceLocatorEnabled && grailsResourceLocator != null) {
544588
def res = grailsResourceLocator.findResourceForURI(uri)
545589
if (res != null) {
546590
url = res.URL

0 commit comments

Comments
 (0)