Hi all,

There is `GZipMiddleware` that compresses response bodies using gzip.
https://github.com/django/django/blob/main/django/middleware/gzip.py

But there are other algorithms supported by browsers (e.g., Brotli).
At the moment, if somebody wants to add support for any of them in a
Django project, one has to create a new middleware class redefining
all the logic processing responses.

I propose simplifying the process by creating
`BaseCompressionMiddleware`. Its subclasses would just need to define
a tuple of supported compressors.

The tuple elements could be instances of such a data class:
```
@dataclass
class Compressor:
    name: str
    compress_string_func: Callable[[bytes], bytes]
    compress_sequence_func: Optional[
        Callable[[Iterable[bytes]], Iterator[bytes]]
    ] = None

    def is_accepted_by(self, accept_encoding):
        return bool(re.search(rf'\b{self.name}\b', accept_encoding))
```


And the class could select a compressor using such code:
```
@classmethod
def select_compressor(cls, request, response):
    ae = request.META.get('HTTP_ACCEPT_ENCODING', '')
    for compressor in cls.compressors:
        if (
            compressor.is_accepted_by(ae)
            and (not response.streaming or 
compressor.compress_sequence_func)
        ):
            return compressor
```


Note, in the example `compress_string_func` is required and
`compress_sequence_func` is optional. I think that
`compress_string_func` would usually be a library function, and
`compress_sequence_func` would require some custom logic. And we
should not force users to define the latter.

`GZipMiddleware` could be changed to
```
gzip_compressor = Compressor(
    name='gzip',
    compress_string_func=compress_string,
    compress_sequence_func=compress_sequence,
)

class GZipMiddleware(BaseCompressionMiddleware):
    compressors = (gzip_compressor,)
```


And someone wanting to support both Brotli and gzip could define:
```
import brotli
from django.middleware.gzip import gzip_compressor

brotli_compressor = Compressor(
    name='br',
    compress_string_func=brotli.compress,
)

class CompressionMiddleware(BaseCompressionMiddleware)
    compressors = (brotli_compressor, gzip_compressor)
```


Please let me know what you think about such an enhancement.
I will be happy to create a pull request if this is accepted.

Thanks,
Illia

-- 
You received this message because you are subscribed to the Google Groups 
"Django developers  (Contributions to Django itself)" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to django-developers+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-developers/49535d7e-758c-4acf-a9da-831ccfa1d17bn%40googlegroups.com.

Reply via email to