CachedMapTileMetadata.fromHttpHeaders constructor

CachedMapTileMetadata.fromHttpHeaders(
  1. Map<String, String> headers, {
  2. Uri? warnOnFallbackUsage,
  3. Duration fallbackFreshnessAge = const Duration(days: 7),
})

Create new metadata based off an HTTP response's headers

Where a response does not include enough information to calculate the freshness age, fallbackFreshnessAge is used. This will emit a console log in debug mode if warnOnFallbackUsage is is set.

This may throw if the required headers were in an unexpected format.

Implementation

factory CachedMapTileMetadata.fromHttpHeaders(
  Map<String, String> headers, {
  Uri? warnOnFallbackUsage,
  Duration fallbackFreshnessAge = const Duration(days: 7),
}) {
  void warnFallbackUsage() {
    if (kDebugMode && warnOnFallbackUsage != null) {
      Logger(printer: SimplePrinter()).w(
        '[flutter_map cache] Using fallback freshness age '
        '($fallbackFreshnessAge) for ${warnOnFallbackUsage.path}\n'
        '\tThis indicates the tile server did not send enough '
        'information to calculate a freshness age. Optionally override '
        "in the caching provider's config.",
      );
    }
  }

  // There is no guarantee that this meets the HTTP specification - however,
  // it was designed with it in mind
  DateTime calculateStaleAt() {
    final addToNow = DateTime.timestamp().add;

    if (headers[HttpHeaders.cacheControlHeader]?.toLowerCase()
        case final cacheControl?) {
      final maxAge = RegExp(r'max-age=(\d+)').firstMatch(cacheControl)?[1];

      if (maxAge == null) {
        if (headers[HttpHeaders.expiresHeader]?.toLowerCase()
            case final expires?) {
          return HttpDate.parse(expires);
        }

        warnFallbackUsage();
        return addToNow(fallbackFreshnessAge);
      }

      if (headers[HttpHeaders.ageHeader] case final currentAge?) {
        return addToNow(
          Duration(seconds: int.parse(maxAge) - int.parse(currentAge)),
        );
      }

      final estimatedAge = max(
        0,
        DateTime.timestamp()
            .difference(HttpDate.parse(headers[HttpHeaders.dateHeader]!))
            .inSeconds,
      );
      return addToNow(Duration(seconds: int.parse(maxAge) - estimatedAge));
    }

    warnFallbackUsage();
    return addToNow(fallbackFreshnessAge);
  }

  final lastModified = headers[HttpHeaders.lastModifiedHeader];
  final etag = headers[HttpHeaders.etagHeader];

  return CachedMapTileMetadata(
    staleAt: calculateStaleAt(),
    lastModified: lastModified != null ? HttpDate.parse(lastModified) : null,
    etag: etag,
  );
}