-
Notifications
You must be signed in to change notification settings - Fork 2.2k
Expand file tree
/
Copy pathtransferHandler.ts
More file actions
142 lines (130 loc) · 3.94 KB
/
transferHandler.ts
File metadata and controls
142 lines (130 loc) · 3.94 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
import { AmplifyClassV6 } from '@aws-amplify/core';
import {
Headers,
HttpRequest,
RetryOptions,
getRetryDecider,
jitteredBackoff,
} from '@aws-amplify/core/internals/aws-client-utils';
import {
AWSCredentials,
DocumentType,
RetryStrategy,
} from '@aws-amplify/core/internals/utils';
import {
logger,
parseRestApiServiceError,
parseSigningInfo,
} from '../../utils';
import { resolveHeaders } from '../../utils/resolveHeaders';
import { RestApiResponse, SigningServiceInfo } from '../../types';
import { authenticatedHandler } from './baseHandlers/authenticatedHandler';
import { unauthenticatedHandler } from './baseHandlers/unauthenticatedHandler';
type HandlerOptions = Omit<HttpRequest, 'body' | 'headers'> & {
body?: DocumentType | FormData;
headers?: Headers;
withCredentials?: boolean;
retryStrategy?: RetryStrategy;
};
type RetryDecider = RetryOptions['retryDecider'];
/**
* Make REST API call with best-effort IAM auth.
* @param amplify Amplify instance to to resolve credentials and tokens. Should use different instance in client-side
* and SSR
* @param options Options accepted from public API options when calling the handlers.
* @param signingServiceInfo Internal-only options enable IAM auth as well as to to overwrite the IAM signing service
* and region. If specified, and NONE of API Key header or Auth header is present, IAM auth will be used.
* @param iamAuthApplicable Callback function that is used to determine if IAM Auth should be used or not.
*
* @internal
*/
export const transferHandler = async (
amplify: AmplifyClassV6,
options: HandlerOptions & { abortSignal: AbortSignal },
iamAuthApplicable: (
{ headers }: HttpRequest,
signingServiceInfo?: SigningServiceInfo,
) => boolean,
signingServiceInfo?: SigningServiceInfo,
): Promise<RestApiResponse> => {
const {
url,
method,
headers,
body,
withCredentials,
abortSignal,
retryStrategy,
} = options;
const resolvedBody = body
? body instanceof FormData
? body
: JSON.stringify(body ?? '')
: undefined;
const resolvedHeaders: Headers = resolveHeaders(headers, body);
const request = {
url,
headers: resolvedHeaders,
method,
body: resolvedBody,
};
const baseOptions = {
retryDecider: getRetryDeciderFromStrategy(
retryStrategy ?? amplify?.libraryOptions?.API?.REST?.retryStrategy,
),
computeDelay: jitteredBackoff,
withCrossDomainCredentials: withCredentials,
abortSignal,
};
const isIamAuthApplicable = iamAuthApplicable(request, signingServiceInfo);
let response: RestApiResponse;
const credentials = await resolveCredentials(amplify);
if (isIamAuthApplicable && credentials) {
const signingInfoFromUrl = parseSigningInfo(url);
const signingService =
signingServiceInfo?.service ?? signingInfoFromUrl.service;
const signingRegion =
signingServiceInfo?.region ?? signingInfoFromUrl.region;
response = await authenticatedHandler(request, {
...baseOptions,
credentials,
region: signingRegion,
service: signingService,
});
} else {
response = await unauthenticatedHandler(request, {
...baseOptions,
});
}
// Clean-up un-modeled properties from response.
return {
statusCode: response.statusCode,
headers: response.headers,
body: response.body,
};
};
const getRetryDeciderFromStrategy = (
retryStrategy: RetryStrategy | undefined,
): RetryDecider => {
const strategy = retryStrategy?.strategy;
if (strategy === 'no-retry') {
return () => Promise.resolve({ retryable: false });
}
return getRetryDecider(parseRestApiServiceError);
};
const resolveCredentials = async (
amplify: AmplifyClassV6,
): Promise<AWSCredentials | null> => {
amplify.assertConfigured();
try {
const { credentials } = await amplify.Auth.fetchAuthSession();
if (credentials) {
return credentials;
}
} catch (e) {
logger.debug('No credentials available, the request will be unsigned.');
}
return null;
};