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

Some calls to HTMLConverter.convert() are not robust against rejection of the Promise #61

Open
mvanbrab opened this issue Jan 25, 2021 · 0 comments

Comments

@mvanbrab
Copy link
Collaborator

mvanbrab commented Jan 25, 2021

Symptoms

  • No response is returned
  • The occurrence of a fragment like this on the console:
(node:4681) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 623)

Where in the code

Calls in handlers/request-handler.js and handlers/content-negotiation-handler.js, in situations that deal with a previous error. Found on the development branch:

  • } catch (e) {
    // If something goes wrong with applying the pipe modules, send status code 500
    console.error('Pipe module error: ' + e.message);
    const html = await HTMLConverter.convert(htmlInfo['500'], {});
    this.responseHandler.handle(res, 500, 'text/html')(html);
    }
  • if (!htmlInfo[String(status)]) {
    this.logger.warn(`No HTML template is defined for status code ${status}. Sending an empty string instead.`);
    handleResponse('');
    } else {
    const html = await HTMLConverter.convert(htmlInfo[String(status)], {});
    handleResponse(html);
    }
    (this one contains a workaround that will work, but changing into proposed solution is more uniform)
  • } catch (err) {
    this.logger.error(`HTML conversion failed for "${req.path}".`);
    status = 500;
    const html = await HTMLConverter.convert(htmlInfo[String(status)], {});
    this.responseHandler.handle(res, status, 'text/html')(html);
    }
  • } else {
    const html = await HTMLConverter.convert(htmlInfo[String(status)], {});
    this.responseHandler.handle(res, status, 'text/html')(html);
    }
  • catch (error) {
    // If something goes wrong with the data reformatting, send html with error code 500
    console.error('Content negotiation (reformatting) error: ' + error.message);
    const html = await HtmlConverter.convert(htmlInfo['500'], {});
    this.responseHandler.handle(res, 500, 'text/html')(html);
    }

How to test (example, not covering every call listed)

Proposed solution

Do both:

  1. Wrap each call in a code snippet like this one (or put this code in a wrapper function)
    let html;
    try {
      html = await HTMLConverter.convert(htmlInfo, data);
    } catch (error) {
      if (logger) {
        logger.warn('Empty HTML returned, because HTML conversion failed: ' + error.message);
      }
      html = '';
    }
  1. Modify this code
    try {
    fileContent = await fs.readFile(htmlInfo.file, 'utf8');
    } catch (err) {
    const error = new Error(`Reading the file "${htmlInfo.file}" failed.`);
    error.type = 'IO_READING_FAILED';
    reject(error);
    }

    into this code (this avoids extra code in the code snipped above)
      try {
        fileContent = await fs.readFile(htmlInfo.file, 'utf8');
      } catch (err) {
        if (htmlInfo && htmlInfo.file) {
          const error = new Error(`Reading the file "${htmlInfo.file ? htmlInfo.file : "(undefined)"}" failed.`);
          error.type = 'IO_READING_FAILED';
          reject(error);
        } else {
          reject(new Error(`Not given: htmlInfo.file.`));
        }
        return;
      }
mvanbrab added a commit that referenced this issue Jan 25, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants