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