[FIX] http,web,website_*: return the correct Content-Type for images
* = website_profile, website_slides Before this commit, the returned Content-Type was not always correct, for example if the image tool was changing the format, which happens when given a BMP (converted to PNG), or other types being converted to JPEG. The previous method `force_contenttype` was too specific and it wasn't available in every controller. It didn't even need to be a controller method because it didn't use self. Now we create a generic helper to ease updating headers. The Content-Type is only updated when it is safe to do. It is especially unsafe for example for SVG files. task-1958000 PR: #31811
This commit is contained in:
@@ -971,11 +971,6 @@ class Binary(http.Controller):
|
||||
addons_path = http.addons_manifest['web']['addons_path']
|
||||
return open(os.path.join(addons_path, 'web', 'static', 'src', 'img', image), 'rb').read()
|
||||
|
||||
def force_contenttype(self, headers, contenttype='image/png'):
|
||||
dictheaders = dict(headers)
|
||||
dictheaders['Content-Type'] = contenttype
|
||||
return list(dictheaders.items())
|
||||
|
||||
@http.route(['/web/content',
|
||||
'/web/content/<string:xmlid>',
|
||||
'/web/content/<string:xmlid>/<string:filename>',
|
||||
@@ -1034,14 +1029,13 @@ class Binary(http.Controller):
|
||||
return request.env['ir.http']._response_by_status(status, headers, image_base64)
|
||||
if not image_base64:
|
||||
image_base64 = base64.b64encode(self.placeholder(image=placeholder))
|
||||
headers = self.force_contenttype(headers, contenttype='image/png')
|
||||
if not (width or height):
|
||||
width, height = odoo.tools.image_guess_size_from_field_name(field)
|
||||
|
||||
image_base64 = image_process(image_base64, (width, height), crop=crop)
|
||||
|
||||
content = base64.b64decode(image_base64)
|
||||
headers.append(('Content-Length', len(content)))
|
||||
headers = http.set_safe_image_headers(headers, content)
|
||||
response = request.make_response(content, headers)
|
||||
response.status_code = status
|
||||
return response
|
||||
|
||||
@@ -98,7 +98,7 @@ class WebsiteProfile(http.Controller):
|
||||
image_base64 = tools.image_process(image_base64, (width, height), crop=crop)
|
||||
|
||||
content = base64.b64decode(image_base64)
|
||||
headers.append(('Content-Length', len(content)))
|
||||
headers = http.set_safe_image_headers(headers, content)
|
||||
response = request.make_response(content, headers)
|
||||
response.status_code = status
|
||||
return response
|
||||
|
||||
@@ -531,7 +531,7 @@ class WebsiteSlides(WebsiteProfile):
|
||||
image_base64 = tools.image_process(image_base64, (width, height), crop=crop)
|
||||
|
||||
content = base64.b64decode(image_base64)
|
||||
headers.append(('Content-Length', len(content)))
|
||||
headers = http.set_safe_image_headers(headers, content)
|
||||
response = request.make_response(content, headers)
|
||||
response.status_code = status
|
||||
return response
|
||||
|
||||
@@ -50,6 +50,7 @@ from .service.server import memory_info
|
||||
from .service import security, model as service_model
|
||||
from .tools.func import lazy_property
|
||||
from .tools import ustr, consteq, frozendict, pycompat, unique, date_utils
|
||||
from .tools.mimetypes import guess_mimetype
|
||||
|
||||
from .modules.module import module_manifest
|
||||
|
||||
@@ -1617,5 +1618,39 @@ def content_disposition(filename):
|
||||
|
||||
return "attachment; filename*=UTF-8''%s" % escaped
|
||||
|
||||
|
||||
def set_safe_image_headers(headers, content):
|
||||
"""Return new headers based on `headers` but with `Content-Length` and
|
||||
`Content-Type` set appropriately depending on the given `content` only if it
|
||||
is safe to do."""
|
||||
content_type = guess_mimetype(content)
|
||||
safe_types = ['image/jpeg', 'image/png', 'image/gif', 'image/x-icon']
|
||||
if content_type in safe_types:
|
||||
headers = set_header_field(headers, 'Content-Type', content_type)
|
||||
set_header_field(headers, 'Content-Length', len(content))
|
||||
return headers
|
||||
|
||||
|
||||
def set_header_field(headers, name, value):
|
||||
""" Return new headers based on `headers` but with `value` set for the
|
||||
header field `name`.
|
||||
|
||||
:param headers: the existing headers
|
||||
:type headers: list of tuples (name, value)
|
||||
|
||||
:param name: the header field name
|
||||
:type name: string
|
||||
|
||||
:param value: the value to set for the `name` header
|
||||
:type value: string
|
||||
|
||||
:return: the updated headers
|
||||
:rtype: list of tuples (name, value)
|
||||
"""
|
||||
dictheaders = dict(headers)
|
||||
dictheaders[name] = value
|
||||
return list(dictheaders.items())
|
||||
|
||||
|
||||
# main wsgi handler
|
||||
root = Root()
|
||||
|
||||
Reference in New Issue
Block a user