Skip to content

Commit

Permalink
feat: compatible verdaccio path style (#723)
Browse files Browse the repository at this point in the history
兼容Verdaccio下载地址风格,镜像库从Verdaccio切换至cnpmcore后无需大面积调整lock文件

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- **New Features**
- Introduced a comprehensive test suite for the download functionality,
ensuring robust behavior for various package retrieval scenarios.
- Enhanced validation for CORS requests and CDN redirection during
package downloads.
- Added new test cases for downloading version tarballs with scoped
package handling.

- **Bug Fixes**
- Improved error handling for non-existent packages and versions,
providing clearer error messages.
- Ensured proper handling of deprecated download paths and
scoped/non-scoped package names.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
  • Loading branch information
fangzhengjin authored Nov 3, 2024
1 parent 4facf90 commit 7158e66
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 1 deletion.
20 changes: 20 additions & 0 deletions app/port/controller/package/DownloadPackageVersionTar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,4 +133,24 @@ export class DownloadPackageVersionTarController extends AbstractController {
});
return res;
}

// Compatible Verdaccio path style

@HTTPMethod({
// GET /:fullname/-/:scope/:filenameWithVersion.tgz
path: `/:fullname(${FULLNAME_REG_STRING})/-/:scope/:filenameWithVersion.tgz`,
method: HTTPMethodEnum.OPTIONS,
})
async downloadVerdaccioPathStyleorOptions(@Context() ctx: EggContext) {
return this.downloadForOptions(ctx);
}

@HTTPMethod({
// GET /:fullname/-/:scope/:filenameWithVersion.tgz
path: `/:fullname(${FULLNAME_REG_STRING})/-/:scope/:filenameWithVersion.tgz`,
method: HTTPMethodEnum.GET,
})
async downloadVerdaccioPathStyle(@Context() ctx: EggContext, @HTTPParam() fullname: string, @HTTPParam() filenameWithVersion: string) {
return this.download(ctx, fullname, filenameWithVersion);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@ describe('test/port/controller/package/DownloadPackageVersionTarController.test.
nfsClientAdapter = await app.getEggObject(NFSClientAdapter);
});

const scopedName = '@cnpm/testmodule-download-version-tar';
const scope = '@cnpm';
const name = 'testmodule-download-version-tar';
const scopedName = `${scope}/${name}`;
beforeEach(async () => {
mock(app.config.cnpmcore, 'allowPublishNonScopePackage', true);
let pkg = await TestUtil.getFullPackage({ name, version: '1.0.0' });
Expand Down Expand Up @@ -367,4 +368,52 @@ describe('test/port/controller/package/DownloadPackageVersionTarController.test.
assert(res.body.error === `[NOT_FOUND] "${name}-1.0.0.tgz" not found`);
});
});

describe('[GET /:fullname/-/:scope/:name-:version.tgz] download()', () => {
it('should download a version tar redirect to mock cdn success', async () => {
mock(nfsClientAdapter, 'url', async (storeKey: string) => {
// console.log('call url: ', storeKey);
return `https://cdn.mock.com${storeKey}`;
});
let res = await app.httpRequest()
.get(`/${name}/-/${scope}/${name}-1.0.0.tgz`);
assert(res.status === 302);
assert(res.headers.location === `https://cdn.mock.com/packages/${name}/1.0.0/${name}-1.0.0.tgz`);
res = await app.httpRequest()
.get(`/${scopedName}/-/${scope}/${name}-1.0.0.tgz`);
assert(res.status === 302);
assert(res.headers.location === `https://cdn.mock.com/packages/${scopedName}/1.0.0/${name}-1.0.0.tgz`);
});

it('should download a version tar with streaming success', async () => {
mock(nfsClientAdapter, 'url', 'not-function');
const res = await app.httpRequest()
.get(`/${name}/-/${scope}/${name}-1.0.0.tgz`);
assert(res.status === 200);
assert(res.headers['content-type'] === 'application/octet-stream');
assert(res.headers['content-disposition'] === `attachment; filename="${name}-1.0.0.tgz"`);

await app.httpRequest()
.get(`/${scopedName}/-/${scope}/${name}-1.0.0.tgz`);
assert(res.status === 200);
assert(res.headers['content-type'] === 'application/octet-stream');
assert(res.headers['content-disposition'] === `attachment; filename="${name}-1.0.0.tgz"`);
});

it('should mock getDownloadUrlOrStream return undefined', async () => {
mock(nfsClientAdapter, 'createDownloadStream', async () => {
return undefined;
});
if (process.env.CNPMCORE_NFS_TYPE === 'oss') {
mock(nfsClientAdapter, 'url', async () => {
return undefined;
});
}
const res = await app.httpRequest()
.get(`/${name}/-/${scope}/${name}-1.0.0.tgz`);
assert(res.status === 404);
assert(res.headers['content-type'] === 'application/json; charset=utf-8');
assert(res.body.error === `[NOT_FOUND] "${name}-1.0.0.tgz" not found`);
});
});
});

0 comments on commit 7158e66

Please sign in to comment.