(attempt, expires, delay, _request, _response)
| 418 | } |
| 419 | } |
| 420 | async #send(attempt, expires, delay, _request, _response) { |
| 421 | if (attempt >= this.#throttle.maxAttempts) { |
| 422 | return _response.makeServerError("exceeded maximum retry limit"); |
| 423 | } |
| 424 | assert(getTime() <= expires, "timeout", "TIMEOUT", { |
| 425 | operation: "request.send", reason: "timeout", request: _request |
| 426 | }); |
| 427 | if (delay > 0) { |
| 428 | await wait(delay); |
| 429 | } |
| 430 | let req = this.clone(); |
| 431 | const scheme = (req.url.split(":")[0] || "").toLowerCase(); |
| 432 | // Process any Gateways |
| 433 | if (scheme in Gateways) { |
| 434 | const result = await Gateways[scheme](req.url, checkSignal(_request.#signal)); |
| 435 | if (result instanceof FetchResponse) { |
| 436 | let response = result; |
| 437 | if (this.processFunc) { |
| 438 | checkSignal(_request.#signal); |
| 439 | try { |
| 440 | response = await this.processFunc(req, response); |
| 441 | } |
| 442 | catch (error) { |
| 443 | // Something went wrong during processing; throw a 5xx server error |
| 444 | if (error.throttle == null || typeof (error.stall) !== "number") { |
| 445 | response.makeServerError("error in post-processing function", error).assertOk(); |
| 446 | } |
| 447 | // Ignore throttling |
| 448 | } |
| 449 | } |
| 450 | return response; |
| 451 | } |
| 452 | req = result; |
| 453 | } |
| 454 | // We have a preflight function; update the request |
| 455 | if (this.preflightFunc) { |
| 456 | req = await this.preflightFunc(req); |
| 457 | } |
| 458 | const resp = await this.getUrlFunc(req, checkSignal(_request.#signal)); |
| 459 | let response = new FetchResponse(resp.statusCode, resp.statusMessage, resp.headers, resp.body, _request); |
| 460 | if (response.statusCode === 301 || response.statusCode === 302) { |
| 461 | // Redirect |
| 462 | try { |
| 463 | const location = response.headers.location || ""; |
| 464 | return req.redirect(location).#send(attempt + 1, expires, 0, _request, response); |
| 465 | } |
| 466 | catch (error) { } |
| 467 | // Things won't get any better on another attempt; abort |
| 468 | return response; |
| 469 | } |
| 470 | else if (response.statusCode === 429) { |
| 471 | // Throttle |
| 472 | if (this.retryFunc == null || (await this.retryFunc(req, response, attempt))) { |
| 473 | const retryAfter = response.headers["retry-after"]; |
| 474 | let delay = this.#throttle.slotInterval * Math.trunc(Math.random() * Math.pow(2, attempt)); |
| 475 | if (typeof (retryAfter) === "string" && retryAfter.match(/^[1-9][0-9]*$/)) { |
| 476 | delay = parseInt(retryAfter); |
| 477 | } |
no test coverage detected