@@ -105,9 +105,16 @@ def parse(self, source):
|
105 | 105 | source = saxutils.prepare_input_source(source) |
106 | 106 | |
107 | 107 | self._source = source |
108 | | -self.reset() |
109 | | -self._cont_handler.setDocumentLocator(ExpatLocator(self)) |
110 | | -xmlreader.IncrementalParser.parse(self, source) |
| 108 | +try: |
| 109 | +self.reset() |
| 110 | +self._cont_handler.setDocumentLocator(ExpatLocator(self)) |
| 111 | +xmlreader.IncrementalParser.parse(self, source) |
| 112 | +except: |
| 113 | +# bpo-30264: Close the source on error to not leak resources: |
| 114 | +# xml.sax.parse() doesn't give access to the underlying parser |
| 115 | +# to the caller |
| 116 | +self._close_source() |
| 117 | +raise |
111 | 118 | |
112 | 119 | def prepareParser(self, source): |
113 | 120 | if source.getSystemId() is not None: |
@@ -216,6 +223,17 @@ def feed(self, data, isFinal = 0):
|
216 | 223 | # FIXME: when to invoke error()? |
217 | 224 | self._err_handler.fatalError(exc) |
218 | 225 | |
| 226 | +def _close_source(self): |
| 227 | +source = self._source |
| 228 | +try: |
| 229 | +file = source.getCharacterStream() |
| 230 | +if file is not None: |
| 231 | +file.close() |
| 232 | +finally: |
| 233 | +file = source.getByteStream() |
| 234 | +if file is not None: |
| 235 | +file.close() |
| 236 | + |
219 | 237 | def close(self): |
220 | 238 | if (self._entity_stack or self._parser is None or |
221 | 239 | isinstance(self._parser, _ClosedParser)): |
@@ -235,6 +253,7 @@ def close(self):
|
235 | 253 | parser.ErrorColumnNumber = self._parser.ErrorColumnNumber |
236 | 254 | parser.ErrorLineNumber = self._parser.ErrorLineNumber |
237 | 255 | self._parser = parser |
| 256 | +self._close_source() |
238 | 257 | |
239 | 258 | def _reset_cont_handler(self): |
240 | 259 | self._parser.ProcessingInstructionHandler = \ |
|