send method
Sends an HTTP request and asynchronously returns the response.
Implementers should call BaseRequest.finalize
to get the body of the
request as a ByteStream
. They shouldn't make any assumptions about the
state of the stream; it could have data written to it asynchronously at a
later point, or it could already be closed when it's returned. Any
internal HTTP errors should be wrapped as ClientException
s.
Implementation
@override
Future<http.StreamedResponse> send(http.BaseRequest request) async {
if (_cookieStore == null) {
_cookieStore = SuperTokensCookieStore();
}
if (!SuperTokens.isInitCalled) {
throw http.ClientException(
"SuperTokens.initialise must be called before using SuperTokensHttpClient");
}
if (SuperTokensUtils.getApiDomain(request.url.toString()) !=
SuperTokens.apiDomain) {
return _innerClient.send(request);
}
if (SuperTokensUtils.getApiDomain(request.url.toString()) ==
SuperTokens.refreshTokenEndpoint) {
return _innerClient.send(request);
}
try {
while (true) {
await _refreshAPILock.acquireRead();
String? preRequestIdRefreshToken;
http.StreamedResponse response;
try {
preRequestIdRefreshToken = await IdRefreshToken.getToken();
String? antiCSRFToken =
await AntiCSRF.getToken(preRequestIdRefreshToken);
if (antiCSRFToken != null) {
request.headers[antiCSRFHeaderKey] = antiCSRFToken;
}
if (preRequestIdRefreshToken != null) {
request.headers[superTokensPlatformHeaderKey] =
superTokensPlatformName;
request.headers[superTokensSDKVersionHeaderKey] =
superTokensPluginVersion;
}
// Add cookies to request headers
String? newCookiesToAdd =
await _cookieStore?.getCookieHeaderStringForRequest(request.url);
String? existingCookieHeader =
request.headers[HttpHeaders.cookieHeader];
// If the request already has a "cookie" header, combine it with persistent cookies
if (existingCookieHeader != null) {
request.headers[HttpHeaders.cookieHeader] =
"$existingCookieHeader;${newCookiesToAdd ?? ""}";
} else {
request.headers[HttpHeaders.cookieHeader] = newCookiesToAdd ?? "";
}
// http package does not allow retries with the same request object, so we clone the request when making the network call
response =
await _innerClient.send(SuperTokensUtils.copyRequest(request));
// Save cookies from the response
String? setCookieFromResponse =
response.headers[HttpHeaders.setCookieHeader];
await _cookieStore?.saveFromSetCookieHeader(
request.url, setCookieFromResponse);
String? idRefreshTokenFromResponse =
response.headers[idRefreshHeaderKey];
if (idRefreshTokenFromResponse != null) {
await IdRefreshToken.setToken(idRefreshTokenFromResponse);
}
} finally {
_refreshAPILock.release();
}
if (response.statusCode == SuperTokens.sessionExpiryStatusCode) {
bool shouldRetry =
await _handleUnauthorised(preRequestIdRefreshToken, request);
if (!shouldRetry) {
return response;
}
} else {
String? antiCSRFFromResponse = response.headers[antiCSRFHeaderKey];
if (antiCSRFFromResponse != null) {
String? postRequestIdRefresh = await IdRefreshToken.getToken();
await AntiCSRF.setToken(
antiCSRFFromResponse,
postRequestIdRefresh,
);
}
return response;
}
}
} finally {
String? idRefreshToken = await IdRefreshToken.getToken();
if (idRefreshToken == null) {
await AntiCSRF.removeToken();
}
}
}