handleRequest method

Future handleRequest(
  1. RequestContext req,
  2. ResponseContext res
)

A request middleware that returns true if the user has not yet exceeded the maxPointsPerWindow.

Because this handler is typically called before business logic is executed, it technically checks whether the previous call raised the number of consumed points to greater than, or equal to, the maxPointsPerWindow.

Implementation

Future handleRequest(RequestContext req, ResponseContext res) async {
  // Obtain information about the current window.
  var now = DateTime.now().toUtc();
  var currentWindow = await getCurrentWindow(req, res, now);
  // Check if the rate limit has been exceeded. If so, reject the request.
  // To perform this check, we must first determine whether a new window
  // has begun since the previous request.
  var currentWindowEnd = currentWindow.startTime.toUtc().add(windowDuration);
  // We must also compute the missing information about the current window,
  // so that we can relay that information to the client.
  var remainingPoints = maxPointsPerWindow - currentWindow.pointsConsumed;
  currentWindow
    ..pointLimit = maxPointsPerWindow
    ..remainingPoints = remainingPoints < 0 ? 0 : remainingPoints
    ..resetTime = currentWindow.startTime.add(windowDuration);

  // If the previous window ended in the past, begin a new window.
  if (now.compareTo(currentWindowEnd) >= 0) {
    // Create a new window.
    var cost = await getEndpointCost(req, res, currentWindow);
    var remainingPoints = maxPointsPerWindow - cost;
    var newWindow = RateLimitingWindow(currentWindow.user, now, cost)
      ..pointLimit = maxPointsPerWindow
      ..remainingPoints = remainingPoints < 0 ? 0 : remainingPoints
      ..resetTime = now.add(windowDuration);
    await updateCurrentWindow(req, res, newWindow, now);
    await sendWindowInformation(req, res, newWindow);
  }

  // If we are still within the previous window, check if the user has
  // exceeded the rate limit.
  //
  // Otherwise, update the current window.
  //
  // At this point in the computation,
  // we are still only considering whether the *previous* request took the
  // user over the rate limit.
  else if (currentWindow.pointsConsumed >= maxPointsPerWindow) {
    await sendWindowInformation(req, res, currentWindow);
    await rejectRequest(req, res, currentWindow, now);
    //var result = await rejectRequest(req, res, currentWindow, now);
    //if (result != null) return result;
    return false;
  } else {
    // Add the cost of the current endpoint, and update the window.
    var cost = await getEndpointCost(req, res, currentWindow);
    currentWindow.pointsConsumed += cost;
    var remaining = currentWindow.remainingPoints;
    if (remaining == null) {
      currentWindow.remainingPoints = 0;
    } else {
      currentWindow.remainingPoints = remaining - cost;
    }
    if (currentWindow.remainingPoints! < 0) {
      currentWindow.remainingPoints = 0;
    }
    await updateCurrentWindow(req, res, currentWindow, now);
    await sendWindowInformation(req, res, currentWindow);
  }

  // Pass through, so other handlers can be executed.
  return true;
}