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

Merge master -> stable #581

Merged
merged 6 commits into from
Sep 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading