We have a storage system which doesn't provide http api to access its content. So I write a proxy service using Django to map http request to storage systems's protocol. What proxy service does is bulding http headers and reading content from storage system and writing back to client.
For some reasons, I also need a cache layer above the proxy service and choose squid to act as such a role.
I insert 'Cache-Control' headers in response, when the representation expired squid will refresh it. When proxy receives request, we check 'If-Modified-Since' header and return 304 code if the file doesn't changed.
When the representation expired in squid and the client want to read the data, squid will make a request to proxy(originserver) and get a 304 code. But the client get a empty body! And squid print TCP_REFRESH_UNMODIFIED_ABORTED code in log. But the next request can get the complete data before it expires!
According to squid's manual and code, TCP_REFRESH_UNMODIFIED_ABORTED can be divided to two parts: TCP_REFRESH_UNMODIFIED and _ABORTED. TCP_REFRESH_UNMODIFIED means the representation in client is valid. _ABORTED means write back failed. Transmission failure reason is that squid doesn't write the full data of representaion.
I write proxy service using Django framework and return django.http.HttpResponseNotModified
object if the file isn't changed. When django sends response, it will always add 'Content-Length' header with value of content length. In this case, the 'Content-Length' is ZERO. When squid get 304 response, it knows the local representation is valid, and send first 'Content-Length' bytes of local representations to client, which is ZERO. When send finished, squid find the send length isn't same with the length of local represention, so it add a '_ABORTED' to squid status.
The code about django add 'Content-Length' header is here.
According to rfc7232#section-4.1, we should not send 'Content-Length' and we don't need it at all. But adding 'Content-Length' header is the common mechanism in Django without any options. Currently in order to to solve this problem we set 'Content-Length' by ourselves with represention's actual length.