Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add original content length header #39

Open
Alex-ley opened this issue Jan 19, 2023 · 2 comments
Open

add original content length header #39

Alex-ley opened this issue Jan 19, 2023 · 2 comments

Comments

@Alex-ley
Copy link

Feature request:

  • can we add the original content length into an 'Original-Content-Length' header in the after_request func (behind an optional flag in the init method if you don't want it to be a default behaviour), something like the below?

If you would be open to it, I can also do a PR for it? But I didn't want to assume it would be accepted and do the PR without a discussion first.

    def after_request(self, response):
        app = self.app or current_app

        vary = response.headers.get('Vary')
        if not vary:
            response.headers['Vary'] = 'Accept-Encoding'
        elif 'accept-encoding' not in vary.lower():
            response.headers['Vary'] = '{}, Accept-Encoding'.format(vary)

        accept_encoding = request.headers.get('Accept-Encoding', '')
        chosen_algorithm = self._choose_compress_algorithm(accept_encoding)

        if (chosen_algorithm is None or
            response.mimetype not in app.config["COMPRESS_MIMETYPES"] or
            response.status_code < 200 or
            response.status_code >= 300 or
            (response.is_streamed and app.config["COMPRESS_STREAMS"] is False)or
            "Content-Encoding" in response.headers or
            (response.content_length is not None and
             response.content_length < app.config["COMPRESS_MIN_SIZE"])):
            return response

        response.direct_passthrough = False
        
        # add original content length for clients that want to update a download progress bar with
        # the progress event of the `XMLHttpRequest` instance
        # https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/progress_event
        # https://github.com/axios/axios/issues/1591#issuecomment-431400903
        # https://stackoverflow.com/a/42345816/9792594 (non-ideal approximation)
        response.headers["Original-Content-Length"] = response.content_length

        if self.cache is not None:
            key = self.cache_key(request)
            compressed_content = self.cache.get(key)
            if compressed_content is None:
                compressed_content = self.compress(app, response, chosen_algorithm)
            self.cache.set(key, compressed_content)
        else:
            compressed_content = self.compress(app, response, chosen_algorithm)

        response.set_data(compressed_content)

        response.headers['Content-Encoding'] = chosen_algorithm
        response.headers['Content-Length'] = response.content_length # compressed length

        # "123456789"   => "123456789:gzip"   - A strong ETag validator
        # W/"123456789" => W/"123456789:gzip" - A weak ETag validator
        etag = response.headers.get('ETag')
        if etag:
            response.headers['ETag'] = '{0}:{1}"'.format(etag[:-1], chosen_algorithm)

        return response
@alexprengere
Copy link
Collaborator

From what I understand this is not standard right? More of a workaround for more accurate progress bars when downloading compressed content?

@Alex-ley
Copy link
Author

@alexprengere yeah exactly. Sometimes the Brotli compression factor can be huge (which is great) but then any approximation of the compression factor is way off and the progress bar is almost useless. We’re using flask-compress at my start-up and we’re now adding this custom header to improve that. We’re sending huge files around so progress bars are really important.

I realize it’s non standard so that’s why I asked before doing a PR.

If you are open to it, I could put it behind a flag that is by default False/None and also potentially allow the user to chose the naming of this non standard header. So for most users they wouldn’t notice anything or be affected by it.

Of course, understand if you don’t want it in your library. Just thought I’d offer as we can’t be the only people who will face this challenge.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants