(options: {
url: URL;
method: 'POST' | 'PUT';
headers: Record<string, string>;
payloadPath: string;
timeoutMessage: string;
timeoutHint?: string;
errorMessage: string;
errorHint?: string;
retryable?: boolean;
redirectCount: number;
startOffset: number;
progress?: UploadStreamProgressOptions;
})
| 52 | } |
| 53 | |
| 54 | async function streamFileToHttpRequestAttempt(options: { |
| 55 | url: URL; |
| 56 | method: 'POST' | 'PUT'; |
| 57 | headers: Record<string, string>; |
| 58 | payloadPath: string; |
| 59 | timeoutMessage: string; |
| 60 | timeoutHint?: string; |
| 61 | errorMessage: string; |
| 62 | errorHint?: string; |
| 63 | retryable?: boolean; |
| 64 | redirectCount: number; |
| 65 | startOffset: number; |
| 66 | progress?: UploadStreamProgressOptions; |
| 67 | }): Promise<UploadStreamResponse> { |
| 68 | const transport = options.url.protocol === 'https:' ? https : http; |
| 69 | const payloadSize = fs.statSync(options.payloadPath).size; |
| 70 | const headers = buildUploadRequestHeaders(options.headers, options.startOffset, payloadSize); |
| 71 | emitUploadAttemptStarted(options.progress, options.startOffset, payloadSize); |
| 72 | |
| 73 | return await new Promise((resolve, reject) => { |
| 74 | let responseReceived = false; |
| 75 | const req = transport.request( |
| 76 | { |
| 77 | protocol: options.url.protocol, |
| 78 | host: options.url.hostname, |
| 79 | port: options.url.port, |
| 80 | method: options.method, |
| 81 | path: options.url.pathname + options.url.search, |
| 82 | headers, |
| 83 | }, |
| 84 | (res) => { |
| 85 | responseReceived = true; |
| 86 | void readNodeHttpResponseBody(res) |
| 87 | .then((body) => { |
| 88 | clearTimeout(timeout); |
| 89 | const statusCode = res.statusCode ?? 500; |
| 90 | const location = res.headers.location; |
| 91 | if (location && isUploadRedirectStatus(statusCode)) { |
| 92 | if (options.redirectCount >= MAX_UPLOAD_REDIRECTS) { |
| 93 | reject( |
| 94 | new AppError('COMMAND_FAILED', 'Artifact upload exceeded redirect limit', { |
| 95 | maxRedirects: MAX_UPLOAD_REDIRECTS, |
| 96 | url: options.url.toString(), |
| 97 | }), |
| 98 | ); |
| 99 | return; |
| 100 | } |
| 101 | const redirectedUrl = new URL(location, options.url); |
| 102 | void streamFileToHttpRequestAttempt({ |
| 103 | ...options, |
| 104 | url: redirectedUrl, |
| 105 | redirectCount: options.redirectCount + 1, |
| 106 | }).then(resolve, reject); |
| 107 | return; |
| 108 | } |
| 109 | |
| 110 | const resumeOffset = isUploadResumeStatus(statusCode) |
| 111 | ? parseUploadResumeOffset(res.headers, payloadSize) |
no test coverage detected