chrome-aws-lambda icon indicating copy to clipboard operation
chrome-aws-lambda copied to clipboard

[BUG] chromium.font() doesn't work in lambda containers

Open imgx64 opened this issue 4 years ago • 1 comments

Environment

  • chrome-aws-lambda Version: 10.1.0
  • puppeteer / puppeteer-core Version: 10.1.0
  • OS: Linux (public.ecr.aws/lambda/nodejs:14 docker container)
  • Node.js Version: v14.17.4
  • Lambda / GCF Runtime: Lambda container

Expected Behavior

After calling chromium.font(...) in Lambda container, Chrome should use that font.

Current Behavior

Chrome doesn't use the font.

Steps to Reproduce

  1. Start the docker container with the current directory bind-mounted to /tmp/out to get the PDF out of the container: docker run -it --rm --init --mount "type=bind,src=$(pwd),dst=/tmp/out" --entrypoint bash public.ecr.aws/lambda/nodejs:14

  2. Run these commands inside the container:

npm init -y
npm install [email protected] [email protected]
curl -o ScheherazadeNew.zip 'https://fonts.google.com/download?family=Scheherazade%20New'
yum install -y unzip
unzip ScheherazadeNew.zip
  1. Paste the below code to index.js (using cat >index.js for example):
const chromium = require('chrome-aws-lambda');

exports.handler = async (event, context, callback) => {
  let browser = null;

  try {
    await chromium.font('ScheherazadeNew-Bold.ttf');
    await chromium.font('ScheherazadeNew-Regular.ttf');

    browser = await chromium.puppeteer.launch({
      args: chromium.args,
      defaultViewport: chromium.defaultViewport,
      executablePath: await chromium.executablePath,
      headless: chromium.headless,
      ignoreHTTPSErrors: true,
    });

    let page = await browser.newPage();

    await await page.setContent('<h1 style="font: \'Scheherazade New\'">&#x062A;&#x062C;&#x0631;&#x0628;&#x0629;</h1>');

    await page.pdf({ path: '/tmp/out/test.pdf' });

  } catch (error) {
    return callback(error);
  } finally {
    if (browser !== null) {
      await browser.close();
    }
  }

  return callback(null, {});
};
  1. Run the AWS Lambda Runtime Interface Emulator in the background, and invoke the lambda function:
/lambda-entrypoint.sh index.handler &
# Wait a few seconds for the server to start
curl 'http://localhost:8080/2015-03-31/functions/function/invocations' --data-binary '{}'
  1. Open test.pdf which will be written to the current directory outside the container. It will show square boxes instead of Arabic characters rendered in Scheherazade New font.

Possible Solution

I believe it's caused by this line:

https://github.com/alixaxel/chrome-aws-lambda/blob/f9d5a9f/source/index.ts#L46

It symlinks the fonts to $HOME/.fonts, but $HOME/.fonts is not in the /tmp/aws/fonts.conf file:

bash-4.2# cat /tmp/aws/fonts.conf | grep dir
  <dir>/tmp/aws/.fonts</dir>
  <dir>/tmp/.fonts</dir>
  <dir>/opt/.fonts</dir>

It only works in plain (non-container) Lambda because $HOME is not set, so it symlinks to /tmp/.fonts instead:

https://github.com/alixaxel/chrome-aws-lambda/blob/f9d5a9f/source/index.ts#L32-L34

Suggested fixes: 1- Either add <dir>~/.fonts</dir> to /tmp/aws/fonts.conf. 2- Or always symlink the fonts to /tmp/.fonts regardless of $HOME.

I prefer the first option, but I couldn't contribute a PR because I couldn't find the source for bin/aws.tar.br or how it's generated.

imgx64 avatar Nov 10 '21 06:11 imgx64

It seems like /tmp/aws/fonts.conf is no longer available in AWS lambda environment. So, the following two lines are causing the problem https://github.com/alixaxel/chrome-aws-lambda/blob/f9d5a9ff0282ef8e172a29d6d077efc468ca3c76/source/index.ts#L12 https://github.com/alixaxel/chrome-aws-lambda/blob/f9d5a9ff0282ef8e172a29d6d077efc468ca3c76/source/index.ts#L46 as lambda tries to search fonts in /tmp/aws whereas fonts are loaded in /tmp/.fonts.

Setting process.env.FONTCONFIG_PATH=/tmp/.fonts and loading fonts using await chromium.font(path_to_custom_font.ttf) worked for me.

piyushk96 avatar Aug 04 '22 15:08 piyushk96