File Download Broken after Pull Request #2471

38 views
Skip to first unread message

CarlosDB

unread,
Oct 4, 2023, 3:26:46 PM10/4/23
to web2py-users
Hello,

Today, I downloaded web2py from GitHub to start testing a future update. I have several "upload" fields for images, and they have all started to fail.

After some investigation, I found that this issue started after Pull Request (PR) #2471 (Sanitize Headers) was merged. Link to PR. This PR modifies the file gluon/http.py.

The following code:
@cache.action(time_expire=86400)
def download():
    return response.download(request, db)

has stopped working.

If I remove the line "@cache.action(time_expire=86400)", it works, but that's not a good solution.

While investigating the root of the problem, I found the issue around line 123 of gluon/http.py. It used to be like this:

        rheaders = []
        for k, v in iteritems(headers):
            if isinstance(v, list):
                rheaders += [(k, item) for item in v]
            else:
                rheaders.append((k, v))
        responder(status, rheaders)

Now it looks like this:

        rheaders = []
        for k, v in iteritems(headers):
            if isinstance(v, list):
                rheaders += [(k, str(item)) for item in v]
            elif v is not None:
                rheaders.append((k, str(v)))
        responder(status, rheaders)


The variable "rheaders" contains the HTTP headers, but with these modifications, some values are int or None, but they should be str. For example:
('Content-Length', 29563)
('Pragma', None)

('Content-Length', 29563) should be ('Content-Length', '29563'), and I believe ('Pragma', None) is a deprecated header that should be removed.

A possible solution could be to revert part of the PR, but I think there might be a better solution.

The real issue seems to originate from the files gluon/streamer.py and gluon/cache.py. I have commented on the lines that have problems:

In gluon/streamer.py, line 127:

        # in all the other cases (not 304, not 206, but 200 or error page)
    if status != 206:
        enc = request.env.http_accept_encoding
        if enc and 'gzip' in enc and not 'Content-Encoding' in headers:
            gzipped = static_file + '.gz'
            if os.path.isfile(gzipped) and os.path.getmtime(gzipped) >= modified:
                static_file = gzipped
                fsize = os.path.getsize(gzipped)
                headers['Content-Encoding'] = 'gzip'
                headers['Vary'] = 'Accept-Encoding'
        try:
            stream = open(static_file, 'rb')
        except IOError as e:
            # this better not happen when returning an error page ;-)
            if e.errno in (errno.EISDIR, errno.EACCES):
                raise HTTP(403)
            else:
                raise HTTP(404)
        headers['Content-Length'] = fsize   # should be: headers['Content-Length'] = str(fsize)

In gluon/cache.py, line 676:

                if send_headers:
                    headers = {'Pragma': None,  # Deprecated: This feature is no longer recommended
                               'Expires': expires,
                               'Cache-Control': cache_control}


What is your opinion?
Best way to solve it?

Carlos.

Massimo Di Pierro

unread,
Oct 26, 2023, 5:42:25 AM10/26/23
to web2py-users
I agree with you. I committed your proposed change to master. Please confirm this indeed fixes it and I will make another release.

CarlosDB

unread,
Oct 26, 2023, 3:45:20 PM10/26/23
to web2py-users
Yes, for me it works fine now.

Thanks.
Carlos.
Reply all
Reply to author
Forward
0 new messages