Skip to content

Commit

Permalink
Merge pull request #581 from highcharts/master
Browse files Browse the repository at this point in the history
Merge master -> stable
  • Loading branch information
cvasseng authored Sep 26, 2024
2 parents 23ce55a + 36b5769 commit a281b4c
Show file tree
Hide file tree
Showing 10 changed files with 58 additions and 26 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
**Note:** If you use the public Export Server at [https://export.highcharts.com](https://export.highcharts.com) you should read our [Terms of use and Fair Usage Policy](https://www.highcharts.com/docs/export-module/privacy-disclaimer-export).

# Highcharts Node.js Export Server

Convert Highcharts.JS charts into static image files.
Expand Down
3 changes: 2 additions & 1 deletion bin/cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,8 @@ const start = async () => {
}
} else {
throw new ExportError(
'[cli] No valid options provided. Please check your input and try again.'
'[cli] No valid options provided. Please check your input and try again.',
400
);
}
} catch (error) {
Expand Down
7 changes: 4 additions & 3 deletions lib/browser.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ let browser;
*/
export function get() {
if (!browser) {
throw new ExportError('[browser] No valid browser has been created.');
throw new ExportError('[browser] No valid browser has been created.', 500);
}
return browser;
}
Expand Down Expand Up @@ -119,12 +119,13 @@ export async function create(puppeteerArgs) {
}
} catch (error) {
throw new ExportError(
'[browser] Maximum retries to open a browser instance reached.'
'[browser] Maximum retries to open a browser instance reached.',
500
).setError(error);
}

if (!browser) {
throw new ExportError('[browser] Cannot find a browser to open.');
throw new ExportError('[browser] Cannot find a browser to open.', 500);
}
}

Expand Down
7 changes: 4 additions & 3 deletions lib/cache.js
Original file line number Diff line number Diff line change
Expand Up @@ -88,9 +88,10 @@ export const saveConfigToManifest = async (config, fetchedModules) => {
'utf8'
);
} catch (error) {
throw new ExportError('[cache] Error writing the cache manifest.').setError(
error
);
throw new ExportError(
'[cache] Error writing the cache manifest.',
400
).setError(error);
}
};

Expand Down
18 changes: 12 additions & 6 deletions lib/chart.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ export const startExport = async (settings, endCallback) => {
return result;
} catch (error) {
return endCallback(
new ExportError('[chart] Error loading SVG input.').setError(error)
new ExportError('[chart] Error loading SVG input.', 400).setError(error)
);
}
}
Expand All @@ -84,7 +84,9 @@ export const startExport = async (settings, endCallback) => {
return exportAsString(options.export.instr.trim(), options, endCallback);
} catch (error) {
return endCallback(
new ExportError('[chart] Error loading input file.').setError(error)
new ExportError('[chart] Error loading input file.', 400).setError(
error
)
);
}
}
Expand Down Expand Up @@ -120,7 +122,8 @@ export const startExport = async (settings, endCallback) => {
// No input specified, pass an error message to the callback
return endCallback(
new ExportError(
`[chart] No valid input specified. Check if at least one of the following parameters is correctly set: 'infile', 'instr', 'options', or 'svg'.`
`[chart] No valid input specified. Check if at least one of the following parameters is correctly set: 'infile', 'instr', 'options', or 'svg'.`,
400
)
);
};
Expand Down Expand Up @@ -344,7 +347,8 @@ const doExport = async (options, chartJson, endCallback, svg) => {
// these settings.
return endCallback(
new ExportError(
`[chart] The 'callback', 'resources' and 'customCode' options have been disabled for this server.`
`[chart] The 'callback', 'resources' and 'customCode' options have been disabled for this server.`,
400
)
);
}
Expand Down Expand Up @@ -489,7 +493,8 @@ const doStraightInject = (options, endCallback) => {
} catch (error) {
return endCallback(
new ExportError(
`[chart] Malformed input detected for ${options.export?.requestId || '?'}. Please make sure that your JSON/JavaScript options are sent using the "options" attribute, and that if you're using SVG, it is unescaped.`
`[chart] Malformed input detected for ${options.export?.requestId || '?'}. Please make sure that your JSON/JavaScript options are sent using the "options" attribute, and that if you're using SVG, it is unescaped.`,
400
).setError(error)
);
}
Expand Down Expand Up @@ -532,7 +537,8 @@ const exportAsString = (stringToExport, options, endCallback) => {
// Do not allow straight injection without the allowCodeExecution flag
return endCallback(
new ExportError(
'[chart] Only JSON configurations and SVG are allowed for this server. If this is your server, JavaScript custom code can be enabled by starting the server with the --allowCodeExecution flag.'
'[chart] Only JSON configurations and SVG are allowed for this server. If this is your server, JavaScript custom code can be enabled by starting the server with the --allowCodeExecution flag.',
400
).setError(error)
);
}
Expand Down
19 changes: 16 additions & 3 deletions lib/errors/ExportError.js
Original file line number Diff line number Diff line change
@@ -1,22 +1,35 @@
class ExportError extends Error {
constructor(message) {
/**
* @param {string} message
* @param {number} [status] describes the status code (400, 500, etc.)
*/
constructor(message, status) {
super();

this.message = message;
this.stackMessage = message;

if (status) {
this.status = status;
}
}

setError(error) {
this.error = error;

if (error.name) {
this.name = error.name;
}
if (error.statusCode) {
this.statusCode = error.statusCode;

if (!this.status && error.statusCode) {
this.status = error.statusCode;
}

if (error.stack) {
this.stackMessage = error.message;
this.stack = error.stack;
}

return this;
}
}
Expand Down
7 changes: 4 additions & 3 deletions lib/export.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ const createImage = (page, type, encoding, clip, rasterizationTimeout) =>
}),
new Promise((_resolve, reject) =>
setTimeout(
() => reject(new ExportError('Rasterization timeout')),
() => reject(new ExportError('Rasterization timeout', 408)),
rasterizationTimeout || 1500
)
)
Expand Down Expand Up @@ -106,7 +106,7 @@ const createPDF = async (
}),
new Promise((_resolve, reject) =>
setTimeout(
() => reject(new ExportError('Rasterization timeout')),
() => reject(new ExportError('Rasterization timeout', 408)),
rasterizationTimeout || 1500
)
)
Expand Down Expand Up @@ -294,7 +294,8 @@ export default async (page, chart, options) => {
);
} else {
throw new ExportError(
`[export] Unsupported output format ${exportOptions.type}.`
`[export] Unsupported output format ${exportOptions.type}.`,
400
);
}

Expand Down
2 changes: 1 addition & 1 deletion lib/highcharts.js
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ export async function triggerExport(chartOptions, options, displayErrors) {
const userOptions = options.export.strInj
? new Function(`return ${options.export.strInj}`)()
: chartOptions;

// Trigger custom code
if (options.customLogic.customCode) {
new Function('options', options.customLogic.customCode)(userOptions);
Expand Down
16 changes: 11 additions & 5 deletions lib/pool.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ const factory = {
page = await newPage();

if (!page || page.isClosed()) {
throw new ExportError('The page is invalid or closed.');
throw new ExportError('The page is invalid or closed.', 500);
}

log(
Expand All @@ -73,7 +73,8 @@ const factory = {
);
} catch (error) {
throw new ExportError(
'Error encountered when creating a new page.'
'Error encountered when creating a new page.',
500
).setError(error);
}

Expand Down Expand Up @@ -204,7 +205,8 @@ export const initPool = async (config) => {
);
} catch (error) {
throw new ExportError(
'[pool] Could not create the pool of workers.'
'[pool] Could not create the pool of workers.',
500
).setError(error);
}
};
Expand Down Expand Up @@ -262,7 +264,10 @@ export const postWork = async (chart, options) => {
}

if (!pool) {
throw new ExportError('Work received, but pool has not been started.');
throw new ExportError(
'Work received, but pool has not been started.',
500
);
}

// Acquire the worker along with the id of resource and work count
Expand Down Expand Up @@ -293,7 +298,8 @@ export const postWork = async (chart, options) => {

if (!workerHandle.page) {
throw new ExportError(
'Resolved worker page is invalid: the pool setup is wonky.'
'Resolved worker page is invalid: the pool setup is wonky.',
500
);
}

Expand Down
3 changes: 2 additions & 1 deletion lib/server/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,8 @@ export const startServer = async (serverConfig) => {
errorHandler(app);
} catch (error) {
throw new ExportError(
'[server] Could not configure and start the server.'
'[server] Could not configure and start the server.',
500
).setError(error);
}
};
Expand Down

0 comments on commit a281b4c

Please sign in to comment.