From e5d6a6ef9fdbc1095f7735e7f1c2620234480777 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sun, 29 Dec 2019 18:24:56 +0530 Subject: [PATCH] Use a per-thread XML parser instance --- src/calibre/utils/xml_parse.py | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/src/calibre/utils/xml_parse.py b/src/calibre/utils/xml_parse.py index a82d4bc773..d0228d5e3f 100644 --- a/src/calibre/utils/xml_parse.py +++ b/src/calibre/utils/xml_parse.py @@ -6,14 +6,29 @@ from __future__ import absolute_import, division, print_function, unicode_litera from lxml import etree +import threading + # resolve_entities is turned off as entities can cause # reads of local files, for example: # ]> -SAFE_XML_PARSER = etree.XMLParser(recover=True, no_network=True, resolve_entities=False) -SAFE_XML_PARSER_NO_RECOVER = etree.XMLParser(recover=False, no_network=True, resolve_entities=False) + + +class GlobalParserTLS(threading.local): + + def __call__(self, recover): + parsers = getattr(self, 'parsers', None) + if parsers is None: + self.parsers = parsers = { + True: etree.XMLParser(recover=True, no_network=True, resolve_entities=False), + False: etree.XMLParser(recover=False, no_network=True, resolve_entities=False) + } + return parsers[recover] + + +_global_tls = GlobalParserTLS() fs = etree.fromstring def safe_xml_fromstring(string_or_bytes, recover=True): - return fs(string_or_bytes, SAFE_XML_PARSER if recover else SAFE_XML_PARSER_NO_RECOVER) + return fs(string_or_bytes, _global_tls(recover))