Skip to content

Commit ce55ab8

Browse files
committed
Installer cache: fix github release url normalization; Improve test coverage
1 parent ae83b7f commit ce55ab8

File tree

4 files changed

+65
-12
lines changed

4 files changed

+65
-12
lines changed

src/lib/download.js

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
import * as fsSync from 'fs';
2+
import {URL} from 'url';
23
import {default as createHttpsProxyAgent} from 'https-proxy-agent';
34
import {default as TFileCache} from '@derhuerst/http-basic/lib/FileCache.js';
4-
import * as querystring from 'querystring';
55
import {default as request} from '@derhuerst/http-basic';
66
import {default as ProgressBar} from 'progress';
77
import {default as AdmZip} from 'adm-zip';
8-
9-
import {URL} from 'url';
108
import {argQuote, getCachePath, runTool} from './tools.js';
9+
import { URLSearchParams } from 'node:url';
1110

1211
/**
1312
* @typedef {import('@derhuerst/http-basic/lib/FileCache.js').default} FileCacheInst
@@ -27,13 +26,18 @@ const requestAsync = (method, url, options = null) => new Promise((resolve, reje
2726
else resolve(response);
2827
}));
2928

30-
const normalizeS3Url = (url) => {
31-
url = new URL(url);
32-
if (url.hostname.slice(-17) !== '.s3.amazonaws.com') return url.href;
33-
const query = Array.from(url.searchParams.entries())
34-
.filter(([key]) => key.slice(0, 6).toLowerCase() !== 'x-amz-')
35-
.reduce((query, [key, val]) => ({...query, [key]: val}), {});
36-
url.search = querystring.stringify(query);
29+
/**
30+
* Returns normalized URL with X-Amz params stripped and application/x-www-form-urlencoded format
31+
* (spaces %20 are encoded as +)
32+
* @param {string} inUrl
33+
* @return {string}
34+
*/
35+
export const normalizeGithubReleaseURL = (inUrl) => {
36+
const url = new URL(inUrl), hostname = url.hostname.toLowerCase();
37+
if (hostname === 'github-releases.githubusercontent.com' || hostname.endsWith('.s3.amazonaws.com')) {
38+
url.search = new URLSearchParams([...url.searchParams]
39+
.filter(([key]) => !key.toLowerCase().startsWith('x-amz-'))).toString();
40+
}
3741
return url.href;
3842
};
3943

@@ -54,7 +58,7 @@ function initHTTP() {
5458
}
5559
httpHelpers.cache = new FileCache(getCachePath());
5660
httpHelpers.cache.getCacheKey = (url) => {
57-
return FileCache.prototype.getCacheKey(normalizeS3Url(url));
61+
return FileCache.prototype.getCacheKey(normalizeGithubReleaseURL(url));
5862
};
5963
}
6064

test/tests/glslify.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ export function glslifyTests(glslOptimize) {
2222
this.timeout(30000);
2323
before('uninstall glslify', glslifyUninstall);
2424
it('should not have glslify available when uninstalled', async function() {
25-
assert.isRejected(rollup({
25+
await assert.isRejected(rollup({
2626
input: 'test/fixtures/basic.js',
2727
plugins: [glslOptimize({optimize: false, glslify: true})],
2828
}), /glslify could not be found/);

test/tests/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import chai from 'chai';
33
import chaiAsPromised from 'chai-as-promised';
44

55
import {installTests} from './install.js';
6+
import {utilTests} from './util.js';
67
import {glslifyTests} from './glslify.js';
78
import {shaderTests} from './shader.js';
89
import {settings} from '../../settings.js';
@@ -22,6 +23,7 @@ export function runTests(glslOptimize) {
2223
chai.use(chaiAsPromised);
2324

2425
installTests();
26+
utilTests();
2527
shaderTests(glslOptimize);
2628
glslifyTests(glslOptimize);
2729
}

test/tests/util.js

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import {assert} from 'chai';
2+
import * as download from '../../src/lib/download.js';
3+
import * as tools from '../../src/lib/tools.js';
4+
5+
export function utilTests() {
6+
describe('Utility functions', function() {
7+
it('should correctly normalize a github release URL', function() {
8+
9+
const baseURL = 'https://github-releases.githubusercontent.com/123456/123456-123456';
10+
const baseParams = 'actor_id=0&key_id=0&repo_id=123456&' +
11+
'response-content-disposition=attachment%3B+filename%3DglslangValidator&' +
12+
'response-content-type=application%2Foctet-stream';
13+
const amzParams = 'X-Amz-Algorithm=AWS4-HMAC-SHA256' +
14+
'&X-Amz-Credential=A123456%2Fus-east-1%2Fs3%2Faws4_request&' +
15+
'X-Amz-Date=123456Z&X-Amz-Expires=123&' +
16+
'X-Amz-Signature=123456&' +
17+
'X-Amz-SignedHeaders=host';
18+
const cleanURL = `${baseURL}?${baseParams}`;
19+
const testURL = `${baseURL}?${baseParams}&${amzParams}`;
20+
21+
assert.strictEqual(download.normalizeGithubReleaseURL(testURL), cleanURL);
22+
});
23+
it('should warn about missing Khronos binaries', function() {
24+
process.env.GLSLANG_VALIDATOR = process.env.GLSLANG_OPTIMIZER = process.env.GLSLANG_CROSS = '/does/not/exist';
25+
assert.throws(() => tools.configureTools({}), /Khronos tool binaries could not be found/i);
26+
delete process.env.GLSLANG_VALIDATOR; delete process.env.GLSLANG_OPTIMIZER; delete process.env.GLSLANG_CROSS;
27+
});
28+
it('should output stderr from failing command', async function() {
29+
// Mock console output:
30+
const consoleOrig = global.console;
31+
let outBuf = '';
32+
global.console = {
33+
log: (...args) => {
34+
outBuf += `${args.map(String).join(' ')}\n`;
35+
},
36+
};
37+
global.console.error = global.console.warn = global.console.log;
38+
39+
await assert.isRejected(tools.runToolBuffered('ping', '.', 'ping', ['-']), /failed/i);
40+
41+
// Unmock:
42+
global.console = consoleOrig;
43+
44+
assert.isNotEmpty(outBuf, 'stdout/stderr empty');
45+
});
46+
});
47+
}

0 commit comments

Comments
 (0)