(res: Response | undefined, onFinishedResolving: () => void)
| 157 | } |
| 158 | |
| 159 | async function resolveResponse(res: Response | undefined, onFinishedResolving: () => void): Promise<void> { |
| 160 | if (res?.body) { |
| 161 | const body = res.body; |
| 162 | const responseReader = body.getReader(); |
| 163 | |
| 164 | // Define a maximum duration after which we just cancel |
| 165 | const maxFetchDurationTimeout = setTimeout( |
| 166 | () => { |
| 167 | body.cancel().then(null, () => { |
| 168 | // noop |
| 169 | }); |
| 170 | }, |
| 171 | 90 * 1000, // 90s |
| 172 | ); |
| 173 | |
| 174 | let readingActive = true; |
| 175 | while (readingActive) { |
| 176 | let chunkTimeout; |
| 177 | try { |
| 178 | // abort reading if read op takes more than 5s |
| 179 | chunkTimeout = setTimeout(() => { |
| 180 | body.cancel().then(null, () => { |
| 181 | // noop on error |
| 182 | }); |
| 183 | }, 5000); |
| 184 | |
| 185 | // This .read() call will reject/throw when we abort due to timeouts through `body.cancel()` |
| 186 | const { done } = await responseReader.read(); |
| 187 | |
| 188 | clearTimeout(chunkTimeout); |
| 189 | |
| 190 | if (done) { |
| 191 | onFinishedResolving(); |
| 192 | readingActive = false; |
| 193 | } |
| 194 | } catch { |
| 195 | readingActive = false; |
| 196 | } finally { |
| 197 | clearTimeout(chunkTimeout); |
| 198 | } |
| 199 | } |
| 200 | |
| 201 | clearTimeout(maxFetchDurationTimeout); |
| 202 | |
| 203 | responseReader.releaseLock(); |
| 204 | body.cancel().then(null, () => { |
| 205 | // noop on error |
| 206 | }); |
| 207 | } |
| 208 | } |
| 209 | |
| 210 | function streamHandler(response: Response): void { |
| 211 | // clone response for awaiting stream |
no test coverage detected