From cca87e7ad266e2ffbdf06f2f0bdbf20ded612e95 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sun, 10 Sep 2017 06:39:41 +0530 Subject: [PATCH] Browser viewer: Do not fail if the book contains javascript that has errors. Fixes #1715781 [Private bug](https://bugs.launchpad.net/calibre/+bug/1715781) --- src/pyj/read_book/iframe.pyj | 25 +++++++++++++++---------- src/pyj/read_book/resources.pyj | 13 ++++++++----- 2 files changed, 23 insertions(+), 15 deletions(-) diff --git a/src/pyj/read_book/iframe.pyj b/src/pyj/read_book/iframe.pyj index c8f095b7ef..d7e27a2ae9 100644 --- a/src/pyj/read_book/iframe.pyj +++ b/src/pyj/read_book/iframe.pyj @@ -69,6 +69,7 @@ class IframeBoss: self.replace_history_on_next_cfi_update = True self.encrypted_communications = False self.blob_url_map = {} + self.resource_urls = {} self.content_ready = False self.last_window_width = self.last_window_height = -1 window.addEventListener('message', self.handle_message, False) @@ -145,15 +146,19 @@ class IframeBoss: # type of error console.log(f'Unhandled error from external javascript, ignoring: {msg} {script_url} {line_number}') return - console.log(error_object) - try: - fname = script_url.rpartition('/')[-1] or script_url - msg = msg + '
' + 'Error at {}:{}:{}'.format(fname, line_number, column_number or '') + '' - details = traceback.format_exception(error_object).join('') if error_object else '' - self.send_message('error', title=_('Unhandled error'), details=details, msg=msg) - return True - except: - console.log('There was an error in the iframe unhandled exception handler') + is_internal_error = not self.resource_urls[script_url] + if is_internal_error: # dont report errors from scripts in the book itself + console.log(error_object) + try: + fname = script_url.rpartition('/')[-1] or script_url + msg = msg + '
' + 'Error at {}:{}:{}'.format(fname, line_number, column_number or '') + '' + details = traceback.format_exception(error_object).join('') if error_object else '' + self.send_message('error', title=_('Unhandled error'), details=details, msg=msg) + return True + except: + console.log('There was an error in the iframe unhandled exception handler') + else: + (console.error or console.log)('There was an error in the JavaScript from within the book') def display(self, data): self.length_before = None @@ -186,7 +191,7 @@ class IframeBoss: for name in self.blob_url_map: window.URL.revokeObjectURL(self.blob_url_map[name]) root_data, self.mathjax, self.blob_url_map = finalize_resources(self.book, data.name, data.resource_data) - unserialize_html(root_data, self.content_loaded) + self.resource_urls = unserialize_html(root_data, self.content_loaded) def handle_gesture(self, gesture): if gesture.type is 'show-chrome': diff --git a/src/pyj/read_book/resources.pyj b/src/pyj/read_book/resources.pyj index b8dd57d52a..22cdfe17fe 100644 --- a/src/pyj/read_book/resources.pyj +++ b/src/pyj/read_book/resources.pyj @@ -185,7 +185,7 @@ def apply_attributes(src, elem, ns_map): else: elem.setAttribute(a[0], a[1]) -def process_stack(stack, tag_map, ns_map, load_required, onload): +def process_stack(stack, tag_map, ns_map, load_required, onload, resource_urls): while stack.length: node, parent = stack.pop() src = tag_map[node[0]] @@ -194,13 +194,14 @@ def process_stack(stack, tag_map, ns_map, load_required, onload): else: elem = document.createElement(src.n) loadable = False - if src.n in resource_tag_names: - attr = resource_tag_names[src.n] + attr = resource_tag_names[src.n] + if attr: if attr.indexOf(':') != -1: attr = attr.replace('xlink:', '') for a in (src.a or v'[]'): if a[0] is attr: loadable = a[1].startswith('blob:') + resource_urls[a[1]] = True break if loadable: load_required.add(node[0]) @@ -227,6 +228,7 @@ def unserialize_html(serialized_data, proceed): apply_attributes(html, document.documentElement, ns_map) head, body = tree[1], tree[2] # noqa: unused-local clear(document.head, document.body) + resource_urls = {} load_required = set() proceeded = False hang_timeout = 5 @@ -248,14 +250,14 @@ def unserialize_html(serialized_data, proceed): stack = v'[]' for v'var i = head.length - 1; i >= 1; i--': stack.push(v'[head[i], document.head]') - process_stack(stack, tag_map, ns_map, load_required, onload) + process_stack(stack, tag_map, ns_map, load_required, onload, resource_urls) bnode = tag_map[body[0]] apply_attributes(bnode, document.body, ns_map) if bnode.x: document.body.appendChild(document.createTextNode(bnode.x)) for v'var i = body.length - 1; i >= 1; i--': # noqa: unused-local stack.push(v'[body[i], document.body]') - process_stack(stack, tag_map, ns_map, load_required, onload) + process_stack(stack, tag_map, ns_map, load_required, onload, resource_urls) ev = document.createEvent('Event') ev.initEvent('DOMContentLoaded', True, True) document.dispatchEvent(ev) @@ -264,6 +266,7 @@ def unserialize_html(serialized_data, proceed): else: proceeded = True proceed() + return resource_urls def text_from_serialized_html(data): serialized_data = JSON.parse(data)