Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Infinite-loop error #98

Closed
natlibfi-arlehiko opened this issue Aug 6, 2020 · 5 comments · Fixed by #113
Closed

Infinite-loop error #98

natlibfi-arlehiko opened this issue Aug 6, 2020 · 5 comments · Fixed by #113
Labels
help-wanted External contributions welcome needs investigation Information is missing and needs to be researched

Comments

@natlibfi-arlehiko
Copy link

When passing an object to DOMParser's parseFromString you'll get infinetely looping error:

const {DOMParser} = require('xmldom');
new DOMParser().parseFromString({});

Obviously you shouldn't pass an object there, but still this should be fixed.

@brodybits brodybits added help-wanted External contributions welcome needs investigation Information is missing and needs to be researched labels Aug 17, 2020
@brodybits
Copy link
Member

Adding help wanted & needs-investigation labels. Maybe related to these:

@jesse-y
Copy link
Contributor

jesse-y commented Aug 23, 2020

Hi @brodybits

I've taken a look at this to see where some potential issues with input sanitation might lie.

The XMLReader.parse() method within lib/dom-parser.js runs its logic in a perpetual while loop - while (true) { ... }. The exit condition for this loop is when the parser is unable to find an opening tag <. This is determined by using native string methods (source.indexOf('<'), so when a different data type is passed through (A POJO in this case) the while loop runs into TypeError: source.indexOf is not a function errors and hits the catch block before it can reach the exiting logic.

The catch block doesn't explicitly rethrow the error - it instead defers to an errorHandler that it's provided. When DOMParser is not provided an errorHandler option, it defaults to the handler from DOMHandler that it constructed internally in DOMParser.parseFromString().

DOMHandler has three methods, warning, error, and fatalError - only fatalError actually throws - the others just log to the console. XMLReader.parse() will only call error when it encounters a problem. Interestingly, the comments in parseElementStartPart() mention "fatalError" - so it seems like there was an intent for the catch block to throw fatal errors.

DOMParser.parseFromString() only does rudimentary checks - it will at most confirm that the source provided is truthly, but won't guarantee that it's also a string, which XMLReader.parse() implicitly depends on.


It's possible to get the parser to bail out early - passing an errorHandler implementation should do the trick.

const { DOMParser } = require('xmldom');

try {
  const parser = new DOMParser({
    errorHandler: {
      error: errorMessage => {
        throw new Error(errorMessage);
      }
    }
  });
  parser.parseFromString({});
} catch (error) {
  console.error(`Caught something!`, error);
}

In terms of fixing this, perhaps:

  • Update DOMParser.parseFromString() to explicitly check that its source parameter is a string
  • Update XMLReader.parse() to cast its source parameter to a string before attempting to process it
  • Update DOMHandler.error() to throw an error, or change XMLReader.parse() to call fatalError() in the errorHandler it's provided.

@karfau
Copy link
Member

karfau commented Aug 23, 2020

Wow, great research and findings!
I would even argue that ensuring the input argument is a string could be treated as a non breaking change, since it's the only intended behavior.

Looking closer at the whole loop and error handling might also help us to fix other bugs.
Thx a lot.

@jesse-y
Copy link
Contributor

jesse-y commented Aug 24, 2020

Cheers - I'd be happy to have a go at fixing this, would you guys be alright with me raising a PR?

@brodybits
Copy link
Member

A PR would be much appreciated, thanks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
help-wanted External contributions welcome needs investigation Information is missing and needs to be researched
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants