send method

  1. @override
Future<StreamedResponse> send(
  1. BaseRequest request
)

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 ClientExceptions.

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();
    }
  }
}