fix: 拒绝插件重定向HTTP错误状态
This commit is contained in:
parent
fc12e608a6
commit
87522a4326
@ -361,7 +361,7 @@ function getHttpRequestOptions(
|
||||
function getRedirectRequestOptions(
|
||||
args: Record<string, unknown>,
|
||||
): QqbotPluginResolveRedirectRequest {
|
||||
const candidate = args.input || args.options || args;
|
||||
const candidate = args.input ?? args.options ?? args;
|
||||
if (!isRecord(candidate)) {
|
||||
throw new Error('Plugin host redirect options must be an object');
|
||||
}
|
||||
|
||||
@ -16,6 +16,7 @@ export type QqbotPluginHttpClientRequest = {
|
||||
|
||||
export type QqbotPluginResolveRedirectRequest = {
|
||||
context?: string;
|
||||
failureMessage?: (statusCode: number) => string;
|
||||
headers?: Record<string, string>;
|
||||
maxRedirects?: number;
|
||||
timeoutMessage?: string;
|
||||
@ -194,7 +195,7 @@ export class QqbotPluginHttpClientService {
|
||||
* Requests one URL and returns its redirect Location after the response body is drained.
|
||||
* @param url - Validated HTTP(S) URL to request.
|
||||
* @param input - Headers and timeout options shared across the redirect chain.
|
||||
* @returns Redirect Location header when the response is 3xx, otherwise `undefined`.
|
||||
* @returns Redirect Location header when the response is 3xx, otherwise `undefined`; rejects for HTTP error statuses.
|
||||
*/
|
||||
private requestRedirectLocation(
|
||||
url: URL,
|
||||
@ -222,6 +223,16 @@ export class QqbotPluginHttpClientService {
|
||||
|
||||
response.on('error', reject);
|
||||
response.on('end', () => {
|
||||
if (statusCode >= 400) {
|
||||
reject(
|
||||
createPluginHttpError(
|
||||
input.failureMessage?.(statusCode) ||
|
||||
`${context}请求失败:${statusCode}`,
|
||||
statusCode,
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
if (
|
||||
statusCode >= 300 &&
|
||||
statusCode < 400 &&
|
||||
|
||||
@ -132,11 +132,11 @@ describe('QQBot plugin host bridge', () => {
|
||||
const options = {
|
||||
maxRedirects: 3,
|
||||
timeoutMs: 1000,
|
||||
url: 'https://b23.tv/abc123',
|
||||
url: 'https://short.example/abc123',
|
||||
};
|
||||
httpClient.resolveRedirect.mockResolvedValue({
|
||||
finalUrl: 'https://www.bilibili.com/video/BV1xx411c7mD',
|
||||
redirects: ['https://www.bilibili.com/video/BV1xx411c7mD'],
|
||||
finalUrl: 'https://target.example/video/123',
|
||||
redirects: ['https://target.example/video/123'],
|
||||
});
|
||||
|
||||
await expect(
|
||||
@ -148,8 +148,8 @@ describe('QQBot plugin host bridge', () => {
|
||||
).resolves.toEqual({
|
||||
ok: true,
|
||||
value: {
|
||||
finalUrl: 'https://www.bilibili.com/video/BV1xx411c7mD',
|
||||
redirects: ['https://www.bilibili.com/video/BV1xx411c7mD'],
|
||||
finalUrl: 'https://target.example/video/123',
|
||||
redirects: ['https://target.example/video/123'],
|
||||
},
|
||||
});
|
||||
expect(httpClient.resolveRedirect).toHaveBeenCalledWith(options);
|
||||
|
||||
@ -23,6 +23,11 @@ describe('QQBot plugin HTTP client redirect resolver', () => {
|
||||
response.end();
|
||||
return;
|
||||
}
|
||||
if (request.url === '/missing') {
|
||||
response.writeHead(404, { 'Content-Type': 'text/plain' });
|
||||
response.end('missing');
|
||||
return;
|
||||
}
|
||||
response.writeHead(200, { 'Content-Type': 'text/plain' });
|
||||
response.end('ok');
|
||||
});
|
||||
@ -67,4 +72,13 @@ describe('QQBot plugin HTTP client redirect resolver', () => {
|
||||
}),
|
||||
).rejects.toThrow('插件 HTTP 重定向仅支持 http/https');
|
||||
});
|
||||
|
||||
it('rejects HTTP error statuses while resolving redirects', async () => {
|
||||
await expect(
|
||||
new QqbotPluginHttpClientService().resolveRedirect({
|
||||
timeoutMs: 1000,
|
||||
url: `${baseUrl}/missing`,
|
||||
}),
|
||||
).rejects.toMatchObject({ statusCode: 404 });
|
||||
});
|
||||
});
|
||||
|
||||
Loading…
Reference in New Issue
Block a user