We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
PDF Filename is broken when saving if it contains UTF-8 characters
## Description of the issue
When trying to save a PDF using python 3 the filename is broken if it contains UTF-8 characters. 
## Context information (for bug reports)

**Output of `bench version`**
```
erpnext 12.x.x-develop
frappe 12.x.x-develop
fatal: Not a git repository (or any of the parent directories): .git
```

## Steps to reproduce the issue
For example 
1. create an invoice naming series called "ΤΠΥ" 
2. then create an invoice in this series
3. try to save the PDF

### Observed result
filename is broken
![image](https://user-images.githubusercontent.com/20220341/67803772-62bb6f00-fa96-11e9-8a15-827a690e3fbd.png)

### Expected result
Filename renders correctly


## Additional information

OS version / distribution, `ERPNext` install method, etc.
Ubuntu 16.04
easy install script 
Python 3

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `frappe/utils/response.py`
Content:
```
1 # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
2 # MIT License. See license.txt
3 
4 from __future__ import unicode_literals
5 import json
6 import datetime
7 import decimal
8 import mimetypes
9 import os
10 import frappe
11 from frappe import _
12 import frappe.model.document
13 import frappe.utils
14 import frappe.sessions
15 import werkzeug.utils
16 from werkzeug.local import LocalProxy
17 from werkzeug.wsgi import wrap_file
18 from werkzeug.wrappers import Response
19 from werkzeug.exceptions import NotFound, Forbidden
20 from frappe.website.render import render
21 from frappe.utils import cint
22 from six import text_type
23 from six.moves.urllib.parse import quote
24 from frappe.core.doctype.access_log.access_log import make_access_log
25 
26 
27 def report_error(status_code):
28 	'''Build error. Show traceback in developer mode'''
29 	if (cint(frappe.db.get_system_setting('allow_error_traceback'))
30 		and (status_code!=404 or frappe.conf.logging)
31 		and not frappe.local.flags.disable_traceback):
32 		frappe.errprint(frappe.utils.get_traceback())
33 
34 	response = build_response("json")
35 	response.status_code = status_code
36 	return response
37 
38 def build_response(response_type=None):
39 	if "docs" in frappe.local.response and not frappe.local.response.docs:
40 		del frappe.local.response["docs"]
41 
42 	response_type_map = {
43 		'csv': as_csv,
44 		'txt': as_txt,
45 		'download': as_raw,
46 		'json': as_json,
47 		'pdf': as_pdf,
48 		'page': as_page,
49 		'redirect': redirect,
50 		'binary': as_binary
51 	}
52 
53 	return response_type_map[frappe.response.get('type') or response_type]()
54 
55 def as_csv():
56 	response = Response()
57 	response.mimetype = 'text/csv'
58 	response.charset = 'utf-8'
59 	response.headers["Content-Disposition"] = ("attachment; filename=\"%s.csv\"" % frappe.response['doctype'].replace(' ', '_')).encode("utf-8")
60 	response.data = frappe.response['result']
61 	return response
62 
63 def as_txt():
64 	response = Response()
65 	response.mimetype = 'text'
66 	response.charset = 'utf-8'
67 	response.headers["Content-Disposition"] = ("attachment; filename=\"%s.txt\"" % frappe.response['doctype'].replace(' ', '_')).encode("utf-8")
68 	response.data = frappe.response['result']
69 	return response
70 
71 def as_raw():
72 	response = Response()
73 	response.mimetype = frappe.response.get("content_type") or mimetypes.guess_type(frappe.response['filename'])[0] or "application/unknown"
74 	response.headers["Content-Disposition"] = ("attachment; filename=\"%s\"" % frappe.response['filename'].replace(' ', '_')).encode("utf-8")
75 	response.data = frappe.response['filecontent']
76 	return response
77 
78 def as_json():
79 	make_logs()
80 	response = Response()
81 	if frappe.local.response.http_status_code:
82 		response.status_code = frappe.local.response['http_status_code']
83 		del frappe.local.response['http_status_code']
84 
85 	response.mimetype = 'application/json'
86 	response.charset = 'utf-8'
87 	response.data = json.dumps(frappe.local.response, default=json_handler, separators=(',',':'))
88 	return response
89 
90 def as_pdf():
91 	response = Response()
92 	response.mimetype = "application/pdf"
93 	response.headers["Content-Disposition"] = ("filename=\"%s\"" % frappe.response['filename'].replace(' ', '_')).encode("utf-8")
94 	response.data = frappe.response['filecontent']
95 	return response
96 
97 def as_binary():
98 	response = Response()
99 	response.mimetype = 'application/octet-stream'
100 	response.headers["Content-Disposition"] = ("filename=\"%s\"" % frappe.response['filename'].replace(' ', '_')).encode("utf-8")
101 	response.data = frappe.response['filecontent']
102 	return response
103 
104 def make_logs(response = None):
105 	"""make strings for msgprint and errprint"""
106 	if not response:
107 		response = frappe.local.response
108 
109 	if frappe.error_log:
110 		response['exc'] = json.dumps([frappe.utils.cstr(d["exc"]) for d in frappe.local.error_log])
111 
112 	if frappe.local.message_log:
113 		response['_server_messages'] = json.dumps([frappe.utils.cstr(d) for
114 			d in frappe.local.message_log])
115 
116 	if frappe.debug_log and frappe.conf.get("logging") or False:
117 		response['_debug_messages'] = json.dumps(frappe.local.debug_log)
118 
119 	if frappe.flags.error_message:
120 		response['_error_message'] = frappe.flags.error_message
121 
122 def json_handler(obj):
123 	"""serialize non-serializable data for json"""
124 	# serialize date
125 	import collections
126 
127 	if isinstance(obj, (datetime.date, datetime.timedelta, datetime.datetime)):
128 		return text_type(obj)
129 
130 	elif isinstance(obj, decimal.Decimal):
131 		return float(obj)
132 
133 	elif isinstance(obj, LocalProxy):
134 		return text_type(obj)
135 
136 	elif isinstance(obj, frappe.model.document.BaseDocument):
137 		doc = obj.as_dict(no_nulls=True)
138 		return doc
139 
140 	elif isinstance(obj, collections.Iterable):
141 		return list(obj)
142 
143 	elif type(obj)==type or isinstance(obj, Exception):
144 		return repr(obj)
145 
146 	else:
147 		raise TypeError("""Object of type %s with value of %s is not JSON serializable""" % \
148 						(type(obj), repr(obj)))
149 
150 def as_page():
151 	"""print web page"""
152 	return render(frappe.response['route'], http_status_code=frappe.response.get("http_status_code"))
153 
154 def redirect():
155 	return werkzeug.utils.redirect(frappe.response.location)
156 
157 def download_backup(path):
158 	try:
159 		frappe.only_for(("System Manager", "Administrator"))
160 		make_access_log(report_name='Backup')
161 	except frappe.PermissionError:
162 		raise Forbidden(_("You need to be logged in and have System Manager Role to be able to access backups."))
163 
164 	return send_private_file(path)
165 
166 def download_private_file(path):
167 	"""Checks permissions and sends back private file"""
168 
169 	files = frappe.db.get_all('File', {'file_url': path})
170 	can_access = False
171 	# this file might be attached to multiple documents
172 	# if the file is accessible from any one of those documents
173 	# then it should be downloadable
174 	for f in files:
175 		_file = frappe.get_doc("File", f)
176 		can_access = _file.is_downloadable()
177 		if can_access:
178 			make_access_log(doctype='File', document=_file.name, file_type=os.path.splitext(path)[-1][1:])
179 			break
180 
181 	if not can_access:
182 		raise Forbidden(_("You don't have permission to access this file"))
183 
184 	return send_private_file(path.split("/private", 1)[1])
185 
186 
187 def send_private_file(path):
188 	path = os.path.join(frappe.local.conf.get('private_path', 'private'), path.strip("/"))
189 	filename = os.path.basename(path)
190 
191 	if frappe.local.request.headers.get('X-Use-X-Accel-Redirect'):
192 		path = '/protected/' + path
193 		response = Response()
194 		response.headers['X-Accel-Redirect'] = quote(frappe.utils.encode(path))
195 
196 	else:
197 		filepath = frappe.utils.get_site_path(path)
198 		try:
199 			f = open(filepath, 'rb')
200 		except IOError:
201 			raise NotFound
202 
203 		response = Response(wrap_file(frappe.local.request.environ, f), direct_passthrough=True)
204 
205 	# no need for content disposition and force download. let browser handle its opening.
206 	# Except for those that can be injected with scripts.
207 
208 	extension = os.path.splitext(path)[1]
209 	blacklist = ['.svg', '.html', '.htm', '.xml']
210 
211 	if extension.lower() in blacklist:
212 		response.headers.add(b'Content-Disposition', b'attachment', filename=filename.encode("utf-8"))
213 
214 	response.mimetype = mimetypes.guess_type(filename)[0] or 'application/octet-stream'
215 
216 	return response
217 
218 def handle_session_stopped():
219 	frappe.respond_as_web_page(_("Updating"),
220 		_("Your system is being updated. Please refresh again after a few moments"),
221 		http_status_code=503, indicator_color='orange', fullpage = True, primary_action=None)
222 	return frappe.website.render.render("message", http_status_code=503)
223
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/frappe/utils/response.py b/frappe/utils/response.py
--- a/frappe/utils/response.py
+++ b/frappe/utils/response.py
@@ -90,7 +90,8 @@
 def as_pdf():
 	response = Response()
 	response.mimetype = "application/pdf"
-	response.headers["Content-Disposition"] = ("filename=\"%s\"" % frappe.response['filename'].replace(' ', '_')).encode("utf-8")
+	encoded_filename = quote(frappe.response['filename'].replace(' ', '_'), encoding='utf-8')
+	response.headers["Content-Disposition"] = ("filename=\"%s\"" % frappe.response['filename'].replace(' ', '_') + ";filename*=utf-8''%s" % encoded_filename).encode("utf-8")
 	response.data = frappe.response['filecontent']
 	return response

{"golden_diff": "diff --git a/frappe/utils/response.py b/frappe/utils/response.py\n--- a/frappe/utils/response.py\n+++ b/frappe/utils/response.py\n@@ -90,7 +90,8 @@\n def as_pdf():\n \tresponse = Response()\n \tresponse.mimetype = \"application/pdf\"\n-\tresponse.headers[\"Content-Disposition\"] = (\"filename=\\\"%s\\\"\" % frappe.response['filename'].replace(' ', '_')).encode(\"utf-8\")\n+\tencoded_filename = quote(frappe.response['filename'].replace(' ', '_'), encoding='utf-8')\n+\tresponse.headers[\"Content-Disposition\"] = (\"filename=\\\"%s\\\"\" % frappe.response['filename'].replace(' ', '_') + \";filename*=utf-8''%s\" % encoded_filename).encode(\"utf-8\")\n \tresponse.data = frappe.response['filecontent']\n \treturn response\n", "issue": "PDF Filename is broken when saving if it contains UTF-8 characters\n## Description of the issue\r\nWhen trying to save a PDF using python 3 the filename is broken if it contains UTF-8 characters. \r\n## Context information (for bug reports)\r\n\r\n**Output of `bench version`**\r\n```\r\nerpnext 12.x.x-develop\r\nfrappe 12.x.x-develop\r\nfatal: Not a git repository (or any of the parent directories): .git\r\n```\r\n\r\n## Steps to reproduce the issue\r\nFor example \r\n1. create an invoice naming series called \"\u03a4\u03a0\u03a5\" \r\n2. then create an invoice in this series\r\n3. try to save the PDF\r\n\r\n### Observed result\r\nfilename is broken\r\n![image](https://user-images.githubusercontent.com/20220341/67803772-62bb6f00-fa96-11e9-8a15-827a690e3fbd.png)\r\n\r\n### Expected result\r\nFilename renders correctly\r\n\r\n\r\n## Additional information\r\n\r\nOS version / distribution, `ERPNext` install method, etc.\r\nUbuntu 16.04\r\neasy install script \r\nPython 3\n", "before_files": [{"content": "# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors\n# MIT License. See license.txt\n\nfrom __future__ import unicode_literals\nimport json\nimport datetime\nimport decimal\nimport mimetypes\nimport os\nimport frappe\nfrom frappe import _\nimport frappe.model.document\nimport frappe.utils\nimport frappe.sessions\nimport werkzeug.utils\nfrom werkzeug.local import LocalProxy\nfrom werkzeug.wsgi import wrap_file\nfrom werkzeug.wrappers import Response\nfrom werkzeug.exceptions import NotFound, Forbidden\nfrom frappe.website.render import render\nfrom frappe.utils import cint\nfrom six import text_type\nfrom six.moves.urllib.parse import quote\nfrom frappe.core.doctype.access_log.access_log import make_access_log\n\n\ndef report_error(status_code):\n\t'''Build error. Show traceback in developer mode'''\n\tif (cint(frappe.db.get_system_setting('allow_error_traceback'))\n\t\tand (status_code!=404 or frappe.conf.logging)\n\t\tand not frappe.local.flags.disable_traceback):\n\t\tfrappe.errprint(frappe.utils.get_traceback())\n\n\tresponse = build_response(\"json\")\n\tresponse.status_code = status_code\n\treturn response\n\ndef build_response(response_type=None):\n\tif \"docs\" in frappe.local.response and not frappe.local.response.docs:\n\t\tdel frappe.local.response[\"docs\"]\n\n\tresponse_type_map = {\n\t\t'csv': as_csv,\n\t\t'txt': as_txt,\n\t\t'download': as_raw,\n\t\t'json': as_json,\n\t\t'pdf': as_pdf,\n\t\t'page': as_page,\n\t\t'redirect': redirect,\n\t\t'binary': as_binary\n\t}\n\n\treturn response_type_map[frappe.response.get('type') or response_type]()\n\ndef as_csv():\n\tresponse = Response()\n\tresponse.mimetype = 'text/csv'\n\tresponse.charset = 'utf-8'\n\tresponse.headers[\"Content-Disposition\"] = (\"attachment; filename=\\\"%s.csv\\\"\" % frappe.response['doctype'].replace(' ', '_')).encode(\"utf-8\")\n\tresponse.data = frappe.response['result']\n\treturn response\n\ndef as_txt():\n\tresponse = Response()\n\tresponse.mimetype = 'text'\n\tresponse.charset = 'utf-8'\n\tresponse.headers[\"Content-Disposition\"] = (\"attachment; filename=\\\"%s.txt\\\"\" % frappe.response['doctype'].replace(' ', '_')).encode(\"utf-8\")\n\tresponse.data = frappe.response['result']\n\treturn response\n\ndef as_raw():\n\tresponse = Response()\n\tresponse.mimetype = frappe.response.get(\"content_type\") or mimetypes.guess_type(frappe.response['filename'])[0] or \"application/unknown\"\n\tresponse.headers[\"Content-Disposition\"] = (\"attachment; filename=\\\"%s\\\"\" % frappe.response['filename'].replace(' ', '_')).encode(\"utf-8\")\n\tresponse.data = frappe.response['filecontent']\n\treturn response\n\ndef as_json():\n\tmake_logs()\n\tresponse = Response()\n\tif frappe.local.response.http_status_code:\n\t\tresponse.status_code = frappe.local.response['http_status_code']\n\t\tdel frappe.local.response['http_status_code']\n\n\tresponse.mimetype = 'application/json'\n\tresponse.charset = 'utf-8'\n\tresponse.data = json.dumps(frappe.local.response, default=json_handler, separators=(',',':'))\n\treturn response\n\ndef as_pdf():\n\tresponse = Response()\n\tresponse.mimetype = \"application/pdf\"\n\tresponse.headers[\"Content-Disposition\"] = (\"filename=\\\"%s\\\"\" % frappe.response['filename'].replace(' ', '_')).encode(\"utf-8\")\n\tresponse.data = frappe.response['filecontent']\n\treturn response\n\ndef as_binary():\n\tresponse = Response()\n\tresponse.mimetype = 'application/octet-stream'\n\tresponse.headers[\"Content-Disposition\"] = (\"filename=\\\"%s\\\"\" % frappe.response['filename'].replace(' ', '_')).encode(\"utf-8\")\n\tresponse.data = frappe.response['filecontent']\n\treturn response\n\ndef make_logs(response = None):\n\t\"\"\"make strings for msgprint and errprint\"\"\"\n\tif not response:\n\t\tresponse = frappe.local.response\n\n\tif frappe.error_log:\n\t\tresponse['exc'] = json.dumps([frappe.utils.cstr(d[\"exc\"]) for d in frappe.local.error_log])\n\n\tif frappe.local.message_log:\n\t\tresponse['_server_messages'] = json.dumps([frappe.utils.cstr(d) for\n\t\t\td in frappe.local.message_log])\n\n\tif frappe.debug_log and frappe.conf.get(\"logging\") or False:\n\t\tresponse['_debug_messages'] = json.dumps(frappe.local.debug_log)\n\n\tif frappe.flags.error_message:\n\t\tresponse['_error_message'] = frappe.flags.error_message\n\ndef json_handler(obj):\n\t\"\"\"serialize non-serializable data for json\"\"\"\n\t# serialize date\n\timport collections\n\n\tif isinstance(obj, (datetime.date, datetime.timedelta, datetime.datetime)):\n\t\treturn text_type(obj)\n\n\telif isinstance(obj, decimal.Decimal):\n\t\treturn float(obj)\n\n\telif isinstance(obj, LocalProxy):\n\t\treturn text_type(obj)\n\n\telif isinstance(obj, frappe.model.document.BaseDocument):\n\t\tdoc = obj.as_dict(no_nulls=True)\n\t\treturn doc\n\n\telif isinstance(obj, collections.Iterable):\n\t\treturn list(obj)\n\n\telif type(obj)==type or isinstance(obj, Exception):\n\t\treturn repr(obj)\n\n\telse:\n\t\traise TypeError(\"\"\"Object of type %s with value of %s is not JSON serializable\"\"\" % \\\n\t\t\t\t\t\t(type(obj), repr(obj)))\n\ndef as_page():\n\t\"\"\"print web page\"\"\"\n\treturn render(frappe.response['route'], http_status_code=frappe.response.get(\"http_status_code\"))\n\ndef redirect():\n\treturn werkzeug.utils.redirect(frappe.response.location)\n\ndef download_backup(path):\n\ttry:\n\t\tfrappe.only_for((\"System Manager\", \"Administrator\"))\n\t\tmake_access_log(report_name='Backup')\n\texcept frappe.PermissionError:\n\t\traise Forbidden(_(\"You need to be logged in and have System Manager Role to be able to access backups.\"))\n\n\treturn send_private_file(path)\n\ndef download_private_file(path):\n\t\"\"\"Checks permissions and sends back private file\"\"\"\n\n\tfiles = frappe.db.get_all('File', {'file_url': path})\n\tcan_access = False\n\t# this file might be attached to multiple documents\n\t# if the file is accessible from any one of those documents\n\t# then it should be downloadable\n\tfor f in files:\n\t\t_file = frappe.get_doc(\"File\", f)\n\t\tcan_access = _file.is_downloadable()\n\t\tif can_access:\n\t\t\tmake_access_log(doctype='File', document=_file.name, file_type=os.path.splitext(path)[-1][1:])\n\t\t\tbreak\n\n\tif not can_access:\n\t\traise Forbidden(_(\"You don't have permission to access this file\"))\n\n\treturn send_private_file(path.split(\"/private\", 1)[1])\n\n\ndef send_private_file(path):\n\tpath = os.path.join(frappe.local.conf.get('private_path', 'private'), path.strip(\"/\"))\n\tfilename = os.path.basename(path)\n\n\tif frappe.local.request.headers.get('X-Use-X-Accel-Redirect'):\n\t\tpath = '/protected/' + path\n\t\tresponse = Response()\n\t\tresponse.headers['X-Accel-Redirect'] = quote(frappe.utils.encode(path))\n\n\telse:\n\t\tfilepath = frappe.utils.get_site_path(path)\n\t\ttry:\n\t\t\tf = open(filepath, 'rb')\n\t\texcept IOError:\n\t\t\traise NotFound\n\n\t\tresponse = Response(wrap_file(frappe.local.request.environ, f), direct_passthrough=True)\n\n\t# no need for content disposition and force download. let browser handle its opening.\n\t# Except for those that can be injected with scripts.\n\n\textension = os.path.splitext(path)[1]\n\tblacklist = ['.svg', '.html', '.htm', '.xml']\n\n\tif extension.lower() in blacklist:\n\t\tresponse.headers.add(b'Content-Disposition', b'attachment', filename=filename.encode(\"utf-8\"))\n\n\tresponse.mimetype = mimetypes.guess_type(filename)[0] or 'application/octet-stream'\n\n\treturn response\n\ndef handle_session_stopped():\n\tfrappe.respond_as_web_page(_(\"Updating\"),\n\t\t_(\"Your system is being updated. Please refresh again after a few moments\"),\n\t\thttp_status_code=503, indicator_color='orange', fullpage = True, primary_action=None)\n\treturn frappe.website.render.render(\"message\", http_status_code=503)\n", "path": "frappe/utils/response.py"}], "after_files": [{"content": "# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors\n# MIT License. See license.txt\n\nfrom __future__ import unicode_literals\nimport json\nimport datetime\nimport decimal\nimport mimetypes\nimport os\nimport frappe\nfrom frappe import _\nimport frappe.model.document\nimport frappe.utils\nimport frappe.sessions\nimport werkzeug.utils\nfrom werkzeug.local import LocalProxy\nfrom werkzeug.wsgi import wrap_file\nfrom werkzeug.wrappers import Response\nfrom werkzeug.exceptions import NotFound, Forbidden\nfrom frappe.website.render import render\nfrom frappe.utils import cint\nfrom six import text_type\nfrom six.moves.urllib.parse import quote\nfrom frappe.core.doctype.access_log.access_log import make_access_log\n\n\ndef report_error(status_code):\n\t'''Build error. Show traceback in developer mode'''\n\tif (cint(frappe.db.get_system_setting('allow_error_traceback'))\n\t\tand (status_code!=404 or frappe.conf.logging)\n\t\tand not frappe.local.flags.disable_traceback):\n\t\tfrappe.errprint(frappe.utils.get_traceback())\n\n\tresponse = build_response(\"json\")\n\tresponse.status_code = status_code\n\treturn response\n\ndef build_response(response_type=None):\n\tif \"docs\" in frappe.local.response and not frappe.local.response.docs:\n\t\tdel frappe.local.response[\"docs\"]\n\n\tresponse_type_map = {\n\t\t'csv': as_csv,\n\t\t'txt': as_txt,\n\t\t'download': as_raw,\n\t\t'json': as_json,\n\t\t'pdf': as_pdf,\n\t\t'page': as_page,\n\t\t'redirect': redirect,\n\t\t'binary': as_binary\n\t}\n\n\treturn response_type_map[frappe.response.get('type') or response_type]()\n\ndef as_csv():\n\tresponse = Response()\n\tresponse.mimetype = 'text/csv'\n\tresponse.charset = 'utf-8'\n\tresponse.headers[\"Content-Disposition\"] = (\"attachment; filename=\\\"%s.csv\\\"\" % frappe.response['doctype'].replace(' ', '_')).encode(\"utf-8\")\n\tresponse.data = frappe.response['result']\n\treturn response\n\ndef as_txt():\n\tresponse = Response()\n\tresponse.mimetype = 'text'\n\tresponse.charset = 'utf-8'\n\tresponse.headers[\"Content-Disposition\"] = (\"attachment; filename=\\\"%s.txt\\\"\" % frappe.response['doctype'].replace(' ', '_')).encode(\"utf-8\")\n\tresponse.data = frappe.response['result']\n\treturn response\n\ndef as_raw():\n\tresponse = Response()\n\tresponse.mimetype = frappe.response.get(\"content_type\") or mimetypes.guess_type(frappe.response['filename'])[0] or \"application/unknown\"\n\tresponse.headers[\"Content-Disposition\"] = (\"attachment; filename=\\\"%s\\\"\" % frappe.response['filename'].replace(' ', '_')).encode(\"utf-8\")\n\tresponse.data = frappe.response['filecontent']\n\treturn response\n\ndef as_json():\n\tmake_logs()\n\tresponse = Response()\n\tif frappe.local.response.http_status_code:\n\t\tresponse.status_code = frappe.local.response['http_status_code']\n\t\tdel frappe.local.response['http_status_code']\n\n\tresponse.mimetype = 'application/json'\n\tresponse.charset = 'utf-8'\n\tresponse.data = json.dumps(frappe.local.response, default=json_handler, separators=(',',':'))\n\treturn response\n\ndef as_pdf():\n\tresponse = Response()\n\tresponse.mimetype = \"application/pdf\"\n\tencoded_filename = quote(frappe.response['filename'].replace(' ', '_'), encoding='utf-8')\n\tresponse.headers[\"Content-Disposition\"] = (\"filename=\\\"%s\\\"\" % frappe.response['filename'].replace(' ', '_') + \";filename*=utf-8''%s\" % encoded_filename).encode(\"utf-8\")\n\tresponse.data = frappe.response['filecontent']\n\treturn response\n\ndef as_binary():\n\tresponse = Response()\n\tresponse.mimetype = 'application/octet-stream'\n\tresponse.headers[\"Content-Disposition\"] = (\"filename=\\\"%s\\\"\" % frappe.response['filename'].replace(' ', '_')).encode(\"utf-8\")\n\tresponse.data = frappe.response['filecontent']\n\treturn response\n\ndef make_logs(response = None):\n\t\"\"\"make strings for msgprint and errprint\"\"\"\n\tif not response:\n\t\tresponse = frappe.local.response\n\n\tif frappe.error_log:\n\t\tresponse['exc'] = json.dumps([frappe.utils.cstr(d[\"exc\"]) for d in frappe.local.error_log])\n\n\tif frappe.local.message_log:\n\t\tresponse['_server_messages'] = json.dumps([frappe.utils.cstr(d) for\n\t\t\td in frappe.local.message_log])\n\n\tif frappe.debug_log and frappe.conf.get(\"logging\") or False:\n\t\tresponse['_debug_messages'] = json.dumps(frappe.local.debug_log)\n\n\tif frappe.flags.error_message:\n\t\tresponse['_error_message'] = frappe.flags.error_message\n\ndef json_handler(obj):\n\t\"\"\"serialize non-serializable data for json\"\"\"\n\t# serialize date\n\timport collections\n\n\tif isinstance(obj, (datetime.date, datetime.timedelta, datetime.datetime)):\n\t\treturn text_type(obj)\n\n\telif isinstance(obj, decimal.Decimal):\n\t\treturn float(obj)\n\n\telif isinstance(obj, LocalProxy):\n\t\treturn text_type(obj)\n\n\telif isinstance(obj, frappe.model.document.BaseDocument):\n\t\tdoc = obj.as_dict(no_nulls=True)\n\t\treturn doc\n\n\telif isinstance(obj, collections.Iterable):\n\t\treturn list(obj)\n\n\telif type(obj)==type or isinstance(obj, Exception):\n\t\treturn repr(obj)\n\n\telse:\n\t\traise TypeError(\"\"\"Object of type %s with value of %s is not JSON serializable\"\"\" % \\\n\t\t\t\t\t\t(type(obj), repr(obj)))\n\ndef as_page():\n\t\"\"\"print web page\"\"\"\n\treturn render(frappe.response['route'], http_status_code=frappe.response.get(\"http_status_code\"))\n\ndef redirect():\n\treturn werkzeug.utils.redirect(frappe.response.location)\n\ndef download_backup(path):\n\ttry:\n\t\tfrappe.only_for((\"System Manager\", \"Administrator\"))\n\t\tmake_access_log(report_name='Backup')\n\texcept frappe.PermissionError:\n\t\traise Forbidden(_(\"You need to be logged in and have System Manager Role to be able to access backups.\"))\n\n\treturn send_private_file(path)\n\ndef download_private_file(path):\n\t\"\"\"Checks permissions and sends back private file\"\"\"\n\n\tfiles = frappe.db.get_all('File', {'file_url': path})\n\tcan_access = False\n\t# this file might be attached to multiple documents\n\t# if the file is accessible from any one of those documents\n\t# then it should be downloadable\n\tfor f in files:\n\t\t_file = frappe.get_doc(\"File\", f)\n\t\tcan_access = _file.is_downloadable()\n\t\tif can_access:\n\t\t\tmake_access_log(doctype='File', document=_file.name, file_type=os.path.splitext(path)[-1][1:])\n\t\t\tbreak\n\n\tif not can_access:\n\t\traise Forbidden(_(\"You don't have permission to access this file\"))\n\n\treturn send_private_file(path.split(\"/private\", 1)[1])\n\n\ndef send_private_file(path):\n\tpath = os.path.join(frappe.local.conf.get('private_path', 'private'), path.strip(\"/\"))\n\tfilename = os.path.basename(path)\n\n\tif frappe.local.request.headers.get('X-Use-X-Accel-Redirect'):\n\t\tpath = '/protected/' + path\n\t\tresponse = Response()\n\t\tresponse.headers['X-Accel-Redirect'] = quote(frappe.utils.encode(path))\n\n\telse:\n\t\tfilepath = frappe.utils.get_site_path(path)\n\t\ttry:\n\t\t\tf = open(filepath, 'rb')\n\t\texcept IOError:\n\t\t\traise NotFound\n\n\t\tresponse = Response(wrap_file(frappe.local.request.environ, f), direct_passthrough=True)\n\n\t# no need for content disposition and force download. let browser handle its opening.\n\t# Except for those that can be injected with scripts.\n\n\textension = os.path.splitext(path)[1]\n\tblacklist = ['.svg', '.html', '.htm', '.xml']\n\n\tif extension.lower() in blacklist:\n\t\tresponse.headers.add(b'Content-Disposition', b'attachment', filename=filename.encode(\"utf-8\"))\n\n\tresponse.mimetype = mimetypes.guess_type(filename)[0] or 'application/octet-stream'\n\n\treturn response\n\ndef handle_session_stopped():\n\tfrappe.respond_as_web_page(_(\"Updating\"),\n\t\t_(\"Your system is being updated. Please refresh again after a few moments\"),\n\t\thttp_status_code=503, indicator_color='orange', fullpage = True, primary_action=None)\n\treturn frappe.website.render.render(\"message\", http_status_code=503)\n", "path": "frappe/utils/response.py"}]}