Using build-time solution with cssUrlRewriting processor

62 views
Skip to first unread message

s.lavog...@gmail.com

unread,
Aug 27, 2014, 12:00:26 PM8/27/14
to wr...@googlegroups.com
Hi,

I am using the build-time solution with cssUrlRewriting processor and latest wro4j version.
All works just fine but I'm confused with urls generated by cssUrlRewriting processor.

The processor generates urls like dummy.css?wroAPI=wroResources&id=classpath:META-INF/resources/.../dummy.png when the css is referencing pictures.

After reading community messages, I understood that the filter was involved in processing this url.

Does that mean that the build-time solution also need some part of the runtime solution?

Tanks and Regards,
Stephane

Alex Objelean

unread,
Aug 27, 2014, 3:37:57 PM8/27/14
to wr...@googlegroups.com

Hi,

If you are using classpath resources, currently there is no other way to locate those but with the WroFilter (runtime solution). The options you have is either not using classpath resources (avoid mixing runtime solution with the build time), or configure WroFilter to handle the location of those resources.

Let me know if you have any questions or suggestions.

Cheers,
Alex

--
You received this message because you are subscribed to the Google Groups "wro4j" group.
To unsubscribe from this group and stop receiving emails from it, send an email to wro4j+un...@googlegroups.com.
To post to this group, send email to wr...@googlegroups.com.
Visit this group at http://groups.google.com/group/wro4j.
For more options, visit https://groups.google.com/d/optout.

s.lavog...@gmail.com

unread,
Aug 28, 2014, 3:37:50 AM8/28/14
to wr...@googlegroups.com
Hi,
Thanks for your quick response.

Does it mean that if I use classpath resources, I should not use build time solution?

In fact I tried to use both solutions : 
- build-time solution when packaging webapp for production, optimized resources are located in "/static/wro" context.
- runtime solution during developments in order to compile our less resources and reproduce other production optimizations if needed. wroFilter is mapped to "/static/wrofilter".

I can switch between the 2 solutions by using the taglib (a bit customized) which generates paths relative to /static/wro or /static/wrofilter depending on a request parameter.

When in production mode, I got the problem described in my previous post. I tried to intercept urls like /static/wro/dummy.css?wroAPI=wroResources&id=classpath:META-INF/resources/.../dummy.png and redirect them to /static/wrofilter/dummy.css?wroAPI=wroResources&id=classpath:META-INF/resources/.../dummy.png but the wroFilter threw a security exception.. 

Can you confirm me that to avoid security exception, the dummy.css file has to be requested using the wroFilter before I can request /static/wrofilter/dummy.css?wroAPI=wroResources&id=classpath:META-INF/resources/.../dummy.png?

Thanks and regards.

Alex Objelean

unread,
Aug 28, 2014, 8:56:48 AM8/28/14
to wr...@googlegroups.com
The security exception is a way to protect from unauthorized requests. If there won't be any such protection, your classpath would be exposed as a public service which is a big security whole. By default, wro4j add as secure only those classpath resources which are encountered in the wro.xml definition (or within the processed resources).  

So, the answer to your question is: you should either use the runtime solution or implement and use a custom ResourceAuthorizationManager (which is a field of wroManager) and control explicitly the uri which are allowed to be exposed. Or you can not use the runtime solution at all and replace it with a simple filter which would have an implementation similar to ResourceProxyRequestHandler.

Let me know if this does help or if you need more details.

Cheers,
Alex




s.lavog...@gmail.com

unread,
Aug 29, 2014, 3:32:19 AM8/29/14
to wr...@googlegroups.com
Hi,

Tanks for the tip. Il tried the second solution (filter similiar to ResourceProxyRequestHandler implementation) and it's working fine.

But for now, I can't handle resource headers properly as I didn't succeed to inject ResourceProxyRequestHandler attributes such as UriLocatorFactory, ReadOnlyContext, ResponseHeadersConfigurer...

What is the best way?
- to implement the WroServletContextListener and retrieve object references
- another way

I'm using Spring MVC 4.x

Thanks,
Stephane

Alex Objelean

unread,
Aug 29, 2014, 6:08:57 AM8/29/14
to wr...@googlegroups.com
The injection is being handled by WroFilter. If you want to use the ResourceProxyRequestHandler in your own filter, you have to inject it explicitly. 
The injector is created like this: 
Injector injector = InjectorBuilder.create(wroManagerFactory).build();
The source example can be found in WroFilter.

Let me know if that helps.

Cheers,
Alex


s.lavog...@gmail.com

unread,
Sep 3, 2014, 3:29:49 AM9/3/14
to wr...@googlegroups.com
Hi Alex,

All is now working fine.

Thanks for your help and once again, great work!

Stephane

Alex Objelean

unread,
Sep 3, 2014, 3:33:48 AM9/3/14
to wr...@googlegroups.com
Hi Stephane,

I'm glad you have sorted it out. It would be great if you could share your solution, so that other could reuse it. 

Thanks,
Alex

Stéphane Lavogiez

unread,
Sep 3, 2014, 4:29:31 AM9/3/14
to wr...@googlegroups.com
Here is the code of my filter :

public class WroResourceProxyRequestFilter implements Filter {
/**
* Logger for this class
*/
private static final Logger logger = LoggerFactory.getLogger(WroResourceProxyRequestFilter.class);

private static final String PARAM_RESOURCE_ID = "id";
private static final String PATH_RESOURCES = "wroResources";
private static final String PATH_API = "wroAPI";

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
logger.trace("doFilter(ServletRequest, ServletResponse, FilterChain) - start"); //$NON-NLS-1$

if (verifyAccess((HttpServletRequest) request, (HttpServletResponse) response)) {
serveProxyResourceUri((HttpServletRequest) request, (HttpServletResponse) response);
} else {
chain.doFilter(request, response);
}

logger.trace("doFilter(ServletRequest, ServletResponse, FilterChain) - end"); //$NON-NLS-1$
}

/**
* Serve proxy resource uri.
* @param request
*            the request
* @param response
*            the response
* @throws IOException
*             Signals that an I/O exception has occurred.
*/
private void serveProxyResourceUri(final HttpServletRequest request, final HttpServletResponse response) throws IOException {
final String resourceUri = getResourceUri(request);
logger.debug("[OK] serving proxy resource: {}", resourceUri);
final OutputStream outputStream = response.getOutputStream();
response.setContentType(ContentTypeResolver.get(resourceUri, ResourceOptimizerConfiguration.DEFAULT_ENCODING));

InputStream is = null;
try {
is = ResourceOptimizerUtil.loadResource(resourceUri);
final int length = IOUtils.copy(is, outputStream);
// servlet engine may ignore this if content body is flushed to client
response.setContentLength(length);
response.setStatus(HttpServletResponse.SC_OK);
} finally {
IOUtils.closeQuietly(is);
IOUtils.closeQuietly(outputStream);
}
}

/**
* Verify access.
* @param request
*            the request
* @param response
*            the response
* @return true, if successful
*/
private boolean verifyAccess(final HttpServletRequest request, final HttpServletResponse response) {
if (isProxyRequest(request)) {
final String resourceUri = getResourceUri(request);
if (resourceUri != null && resourceUri.startsWith(ResourceOptimizerConfiguration.CLASSPATH_RESOURCE_PREFIX)) {
return true;
}
}
return false;
}

/**
* Gets the resource uri.
* @param request
*            the request
* @return the resource uri
*/
private String getResourceUri(final HttpServletRequest request) {
final String resourceUri = request.getParameter(PARAM_RESOURCE_ID);
return resourceUri;
}

/**
* Checks if is proxy request.
* @param request
*            the request
* @return true, if is proxy request
*/
private boolean isProxyRequest(final HttpServletRequest request) {
final String apiHandlerValue = request.getParameter(PATH_API);
final String resourceId = request.getParameter(PARAM_RESOURCE_ID);
return PATH_RESOURCES.equals(apiHandlerValue) && resourceId != null;
}

/*
* (non-Javadoc)
* @see javax.servlet.Filter#init(javax.servlet.FilterConfig)
*/
@Override
public void init(FilterConfig filterConfig) throws ServletException {
logger.trace("init(FilterConfig filterConfig={}) - start", filterConfig); //$NON-NLS-1$

logger.trace("init(FilterConfig) - end"); //$NON-NLS-1$
}

/*
* (non-Javadoc)
* @see javax.servlet.Filter#destroy()
*/
@Override
public void destroy() {
logger.trace("destroy() - start"); //$NON-NLS-1$

logger.trace("destroy() - end"); //$NON-NLS-1$
}

}

As you can see, this solution is not fully optimized as I didn't handle NOT_MODIFIED response status (and I did not make injection).
Resources fetched from this filter have to be in ResourceOptimizerConfiguration.CLASSPATH_RESOURCE_PREFIX location which in my case is classpath:META-INF/resources. I only put static resources in this location so I shouldn't have any security problem.

Regards,
Stephane






Stéphane Lavogiez
Pôle Architecture Logicielle
Auchan DSI - DUST
Tél : +33(0)3.28.37.76.30
Email : s.lavog...@gmail.com


--
You received this message because you are subscribed to a topic in the Google Groups "wro4j" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/wro4j/XpdF1j9-owc/unsubscribe.
To unsubscribe from this group and all its topics, send an email to wro4j+un...@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages