Add HTTP redirect following support
- Add followRedirects option in Transport (enabled by default) - Add redirectCount to limit redirects to 3 - Detect and follow 301/302/307/308 redirects - Add forceHttps parameter for redirect handling - Log redirects when verbose mode is enabled
This commit is contained in:
@@ -241,6 +241,7 @@ interface TransportOptions {
|
|||||||
connectTimeout?: number | undefined;
|
connectTimeout?: number | undefined;
|
||||||
timeout?: number | undefined;
|
timeout?: number | undefined;
|
||||||
useHttps?: boolean;
|
useHttps?: boolean;
|
||||||
|
followRedirects?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface JsonRpcRequest {
|
interface JsonRpcRequest {
|
||||||
@@ -267,6 +268,8 @@ export class Transport {
|
|||||||
private connectTimeout: number;
|
private connectTimeout: number;
|
||||||
private timeout: number;
|
private timeout: number;
|
||||||
private useHttps: boolean;
|
private useHttps: boolean;
|
||||||
|
private followRedirects: boolean;
|
||||||
|
private redirectCount: number;
|
||||||
|
|
||||||
constructor(options: TransportOptions = {}) {
|
constructor(options: TransportOptions = {}) {
|
||||||
this.fingerprints = options.fingerprints || null;
|
this.fingerprints = options.fingerprints || null;
|
||||||
@@ -276,6 +279,8 @@ export class Transport {
|
|||||||
this.connectTimeout = options.connectTimeout || CONNECT_TIMEOUT;
|
this.connectTimeout = options.connectTimeout || CONNECT_TIMEOUT;
|
||||||
this.timeout = options.timeout || DEFAULT_TIMEOUT;
|
this.timeout = options.timeout || DEFAULT_TIMEOUT;
|
||||||
this.useHttps = options.useHttps || false;
|
this.useHttps = options.useHttps || false;
|
||||||
|
this.followRedirects = options.followRedirects ?? true;
|
||||||
|
this.redirectCount = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -291,6 +296,21 @@ export class Transport {
|
|||||||
handler: string,
|
handler: string,
|
||||||
requestData: string,
|
requestData: string,
|
||||||
verbose: boolean = false
|
verbose: boolean = false
|
||||||
|
): Promise<JsonRpcResponse> {
|
||||||
|
// Reset redirect count for each new request
|
||||||
|
this.redirectCount = 0;
|
||||||
|
return this.doRequest(host, handler, requestData, verbose);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal method to make HTTP request with redirect support
|
||||||
|
*/
|
||||||
|
private async doRequest(
|
||||||
|
host: string,
|
||||||
|
handler: string,
|
||||||
|
requestData: string,
|
||||||
|
verbose: boolean = false,
|
||||||
|
forceHttps?: boolean
|
||||||
): Promise<JsonRpcResponse> {
|
): Promise<JsonRpcResponse> {
|
||||||
// Detect protocol based on port or explicit protocol
|
// Detect protocol based on port or explicit protocol
|
||||||
const hostParts = host.split(":");
|
const hostParts = host.split(":");
|
||||||
@@ -299,6 +319,7 @@ export class Transport {
|
|||||||
|
|
||||||
// Use HTTPS if explicitly configured, or for standard HTTPS ports
|
// Use HTTPS if explicitly configured, or for standard HTTPS ports
|
||||||
const shouldUseHttps =
|
const shouldUseHttps =
|
||||||
|
forceHttps === true ||
|
||||||
this.useHttps ||
|
this.useHttps ||
|
||||||
port === 443 ||
|
port === 443 ||
|
||||||
port === 8443 ||
|
port === 8443 ||
|
||||||
@@ -364,6 +385,49 @@ export class Transport {
|
|||||||
|
|
||||||
res.on("end", () => {
|
res.on("end", () => {
|
||||||
try {
|
try {
|
||||||
|
// Handle redirects BEFORE parsing response body
|
||||||
|
const statusCode = res.statusCode;
|
||||||
|
if (
|
||||||
|
this.followRedirects &&
|
||||||
|
statusCode &&
|
||||||
|
this.redirectCount < 3 &&
|
||||||
|
[301, 302, 307, 308].includes(statusCode)
|
||||||
|
) {
|
||||||
|
const location = res.headers["location"];
|
||||||
|
if (location) {
|
||||||
|
this.redirectCount++;
|
||||||
|
if (verbose) {
|
||||||
|
console.log(
|
||||||
|
`🔄 Redirect (${statusCode}): ${host}${handler} → ${location}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const redirectUrl = new URL(
|
||||||
|
location,
|
||||||
|
`http://${host}`
|
||||||
|
);
|
||||||
|
const newHost = redirectUrl.host;
|
||||||
|
const newUseHttps =
|
||||||
|
redirectUrl.protocol === "https:";
|
||||||
|
|
||||||
|
this.doRequest(
|
||||||
|
newHost,
|
||||||
|
handler,
|
||||||
|
requestData,
|
||||||
|
verbose,
|
||||||
|
newUseHttps
|
||||||
|
)
|
||||||
|
.then(resolve)
|
||||||
|
.catch(reject);
|
||||||
|
return;
|
||||||
|
} catch (redirectError) {
|
||||||
|
reject(redirectError);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Handle compression
|
// Handle compression
|
||||||
const encoding = res.headers["content-encoding"];
|
const encoding = res.headers["content-encoding"];
|
||||||
let responseText: string;
|
let responseText: string;
|
||||||
|
|||||||
Reference in New Issue
Block a user