﻿id	summary	reporter	owner	description	type	status	component	version	severity	resolution	keywords	cc	stage	has_patch	needs_docs	needs_tests	needs_better_patch	easy	ui_ux
12214	never_cache decorator breaks HttpResponse with iterator content	Ben Davis	nobody	"This generally isn't a problem, as normal views don't typically use never_cache.  However,  admin views use never_cache by default,  and if you're streaming content from the result of an admin action (for example, a very large csv file), you'll get an empty response.  

Code example:
{{{
#!python
    def export_assembly_list(self, request, batches):
        import csv
        from StringIO import StringIO
      
        #define output columns
        cols = get_csv_cols()

        stream = StringIO()
        writer = csv.writer(stream)
        def content():
            writer.writerow([k for k,v in cols])
            yield stream.getvalue()
            stream.truncate(0)
      
            for batch in batches:
                for invitation in batch.invitations.values(*[v for k,v in cols]):
                    writer.writerow([invitation[v] for k,v in cols])
                    yield stream.getvalue()
                    stream.truncate(0)

            return
      
        response = HttpResponse(content(), mimetype='text/csv')
        response['Content-Disposition'] = 'attachment; filename=batch_assembly_list.csv'
        return response

}}}

What happens is this:  never_cache() calls django.utils.cache.add_never_cache_headers(), which calls patch_response_headers().  This function adds the ETag header to the response,  and to get the ETag, it does this:
{{{
#!python
if not response.has_header('ETag'):
    response['ETag'] = '""%s""' % md5_constructor(response.content).hexdigest()
}}}
response.content, in turn,  does {{{"""".join(self._container)}}},  which causes the iterator to ""complete"".  The problem with this is that the next time the iterator is called, the cursor is already at the end of the iterator, thus the empty response.

The workaround is easy but not at all obvious: just define the Etag on your response. 

The overall fix should be just as easy: In the patch_response_headers() function, just detect if the response content is an iterator, and if so use a different method for generating the ETag.  Although, I have no idea what that should be."	Bug	closed	Core (Cache system)	dev	Normal	fixed		Forest Bond net147	Accepted	0	0	0	0	0	0
