I'm trying to write a Grails plugin that records the size of each HTTP response sent by the application it's installed in. The approach I've tried so far is:
(1) Write a servlet filter that wraps the response
. The response wrapper decorates the OutputStream
with an OutputStream
that counts the number of bytes in the response. These classes are shown here.
(2) Register the servlet filter in the plugin descriptor
def doWithWebDescriptor = { webXml ->
def contextParam = webXml.'context-param'
contextParam[contextParam.size() - 1] + {
'filter' {
'filter-name'('countingFilter')
'filter-class'(CountingFilter.name)
}
}
def filter = webXml.'filter'
filter[filter.size() - 1] + {
'filter-mapping' {
'filter-name'('countingFilter')
'url-pattern'('/*')
}
}
}
(3) In a Grails filter, try to retrieve the number of bytes written like so:
afterView = {
// countingFilter registers the response wrapper as an attribute of the request
// named 'counter'
request.getAttribute('counter').byteCount
}
But a value of 0 is always returned. However, I discovered that if I add the code above to both the after
and afterView
closures of the Grails filter
after = {
// returns 0
request.getAttribute('counter').byteCount
}
afterView = {
// returns the correct response size
request.getAttribute('counter').byteCount
}
It now returns the correct response size, but it seems the content generated by the sitemesh layout has disappeared, leaving only the content in the GSP itself.
So it seems I'm close to a solution. My guess is that I'm flushing buffers at the wrong time, and/or my filter is not running at the correct point in the filter chain.
This is proving to be much more difficult that I expected. Is there a simpler way?