fix: Check if binary file in Page Renderers

* Check if binary before rendering using StaticPage resolver
* Check if not binary before rendering using TemplatePage resolver
This commit is contained in:
Gavin D'souza 2022-01-19 19:30:45 +05:30
parent 897b8a5b66
commit 9dbaf252f0
3 changed files with 15 additions and 7 deletions

View file

@ -6,6 +6,7 @@ from werkzeug.wsgi import wrap_file
import frappe
from frappe.website.page_renderers.base_renderer import BaseRenderer
from frappe.website.utils import is_binary_file
UNSUPPORTED_STATIC_PAGE_TYPES = ('html', 'md', 'js', 'xml', 'css', 'txt', 'py', 'json')
@ -20,21 +21,20 @@ class StaticPage(BaseRenderer):
return
for app in frappe.get_installed_apps():
file_path = frappe.get_app_path(app, 'www') + '/' + self.path
if os.path.isfile(file_path):
if os.path.isfile(file_path) and is_binary_file(file_path):
self.file_path = file_path
def can_render(self):
return self.is_valid_file_path() and self.file_path
def is_valid_file_path(self):
if ('.' not in self.path):
return False
extension = self.path.rsplit('.', 1)[-1]
if extension in UNSUPPORTED_STATIC_PAGE_TYPES:
return False
return True
def render(self):
# file descriptor to be left open, closed by middleware
f = open(self.file_path, 'rb')
response = Response(wrap_file(frappe.local.request.environ, f), direct_passthrough=True)
response.mimetype = mimetypes.guess_type(self.file_path)[0] or 'application/octet-stream'

View file

@ -7,7 +7,7 @@ from frappe.website.router import get_page_info
from frappe.website.page_renderers.base_template_page import BaseTemplatePage
from frappe.website.router import get_base_template
from frappe.website.utils import (extract_comment_tag, extract_title, get_next_link,
get_toc, get_frontmatter, cache_html, get_sidebar_items)
get_toc, get_frontmatter, is_binary_file, cache_html, get_sidebar_items)
WEBPAGE_PY_MODULE_PROPERTIES = ("base_template_path", "template", "no_cache", "sitemap", "condition_field")
@ -39,7 +39,7 @@ class TemplatePage(BaseTemplatePage):
for dirname in folders:
search_path = os.path.join(app_path, dirname, self.path)
for file_path in self.get_index_path_options(search_path):
if os.path.isfile(file_path):
if os.path.isfile(file_path) and not is_binary_file(file_path):
self.app = app
self.app_path = app_path
self.file_dir = dirname

View file

@ -1,10 +1,10 @@
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and Contributors
# License: MIT. See LICENSE
import json
import mimetypes
import os
import re
from functools import wraps
from functools import cache, wraps
import yaml
from six import iteritems
@ -511,3 +511,11 @@ def add_preload_headers(response):
except Exception:
import traceback
traceback.print_exc()
@cache
def is_binary_file(path):
# ref: https://stackoverflow.com/a/7392391/10309266
textchars = bytearray({7,8,9,10,12,13,27} | set(range(0x20, 0x100)) - {0x7f})
with open(path, 'rb') as f:
content = f.read(1024)
return bool(content.translate(None, textchars))