range_request 0.2.0 copy "range_request: ^0.2.0" to clipboard
range_request: ^0.2.0 copied to clipboard

A Dart package for efficient HTTP range requests supporting parallel chunked downloads, resume capability, and checksum verification.

Range Request #

pub package License: BSD-3-Clause

A high-performance Dart package for HTTP range requests, enabling efficient file downloads with support for parallel chunked downloads, automatic resume capability, and checksum verification.

Features #

  • ๐Ÿš€ Parallel chunked downloads - Split large files into chunks for concurrent downloading
  • ๐Ÿ”„ Automatic resume - Continue interrupted downloads from where they left off
  • โœ… Checksum verification - Verify file integrity with MD5/SHA256
  • ๐ŸŽฏ Smart fallback - Automatically falls back to serial download if server doesn't support range requests
  • ๐Ÿ“Š Progress tracking - Real-time download progress with customizable intervals
  • โŒ Cancellation support - Gracefully cancel downloads with CancelToken
  • ๐Ÿ”ง Highly configurable - Fine-tune chunk size, concurrency, retries, and more
  • ๐Ÿ—๏ธ Isolate-based I/O - Non-blocking file operations using Dart isolates
  • ๐Ÿงน Temporary file cleanup - Manual cleanup utility for incomplete downloads

Limitations and Advantages #

Limitations #

  • No background downloads on mobile: Since this package doesn't use native device features, downloads cannot continue when the app is in the background on mobile platforms. Downloads will pause when the app is backgrounded and can be resumed when the app returns to the foreground.

Advantages #

  • Cross-platform consistency: Pure Dart implementation ensures identical behavior across iOS, Android, Web, and Desktop platforms with high-performance parallel downloads when servers support range requests
  • Minimal footprint: Depends only on http and crypto packages, keeping your app size small and reducing dependency vulnerabilities
  • Zero configuration: No native setup, platform-specific code, or complex configuration required - works out of the box on all platforms including Flutter Web
  • Maintenance-friendly: No platform-specific bugs or OS update compatibility issues to worry about - one codebase for all platforms

Installation #

dart pub add range_request

Or add it manually to your pubspec.yaml:

dependencies:
  range_request:

Then run:

dart pub get

Usage #

Basic Streaming Download #

import 'package:range_request/range_request.dart';

void main() async {
  final client = RangeRequestClient();
  final url = Uri.parse('https://example.com/large-file.zip');

  // Stream download with automatic chunking if supported
  await for (final chunk in client.fetch(url)) {
    // Process each chunk (e.g., write to file, update UI, etc.)
    print('Received ${chunk.length} bytes');
  }
}

File Download with Progress Tracking #

import 'package:range_request/range_request.dart';

void main() async {
  final downloader = FileDownloader.fromConfig(
    RangeRequestConfig(
      chunkSize: 5 * 1024 * 1024, // 5MB chunks
      maxConcurrentRequests: 4,
    ),
  );

  final result = await downloader.downloadToFile(
    Uri.parse('https://example.com/video.mp4'),
    '/downloads',
    outputFileName: 'my_video.mp4',
    onProgress: (bytes, total, status) {
      final progress = (bytes / total * 100).toStringAsFixed(1);
      print('Progress: $progress% - Status: $status');
    },
  );

  print('Downloaded to: ${result.filePath}');
  print('File size: ${result.fileSize} bytes');
}

Download with Resume Support #

// Downloads will automatically resume if interrupted
final result = await downloader.downloadToFile(
  Uri.parse('https://example.com/large-file.iso'),
  '/downloads',
  resume: true, // Enable resume (default: true)
  onProgress: (bytes, total, status) {
    if (bytes > 0) {
      print('Resuming from ${bytes} bytes...');
    }
  },
);

Note: While resume support can continue interrupted downloads, it cannot detect file corruption that may occur during write operations (e.g., if the application crashes while writing buffered data to disk). In such cases, the resumed download may result in a corrupted file. Consider using checksum verification to ensure file integrity after completion.

Checksum Verification #

final result = await downloader.downloadToFile(
  Uri.parse('https://example.com/software.exe'),
  '/downloads',
  checksumType: ChecksumType.sha256,
  onProgress: (bytes, total, status) {
    if (status == DownloadStatus.calculatingChecksum) {
      print('Verifying file integrity...');
    }
  },
);

print('SHA256: ${result.checksum}');

Using Cancellation Tokens #

final cancelToken = CancelToken();

// Start download in a separate async operation
final downloadFuture = downloader.downloadToFile(
  Uri.parse('https://example.com/huge-file.bin'),
  '/downloads',
  cancelToken: cancelToken,
);

// Cancel the download after 5 seconds
Future.delayed(Duration(seconds: 5), () {
  cancelToken.cancel();
  print('Download cancelled');
});

try {
  await downloadFuture;
} on RangeRequestException catch (e) {
  if (e.code == RangeRequestErrorCode.cancelled) {
    print('Download was cancelled');
  }
}

Managing Multiple Downloads #

You can manage multiple downloads through the FileDownloader's client instance:

final downloader = FileDownloader();

// Start multiple downloads
final download1 = downloader.downloadToFile(url1, '/downloads');
final download2 = downloader.downloadToFile(url2, '/downloads');
final download3 = downloader.downloadToFile(url3, '/downloads');

// Cancel all active downloads through the downloader's client
downloader.client.cancelAll();

// Or cancel and clear all tokens for a fresh start
downloader.client.cancelAndClear();

// Individual downloads can still use their own CancelToken
final token = CancelToken();
final download4 = downloader.downloadToFile(
  url4,
  '/downloads',
  cancelToken: token,
);
token.cancel(); // Cancel individual download

Configuration Options #

final config = RangeRequestConfig(
  chunkSize: 10 * 1024 * 1024,        // 10MB chunks
  maxConcurrentRequests: 8,           // 8 parallel connections
  maxRetries: 3,                      // Retry failed chunks 3 times
  retryDelayMs: 1000,                 // Wait 1 second before retry
  connectionTimeout: Duration(seconds: 30),
  tempFileExtension: '.tmp',          // Extension for partial downloads
  headers: {                          // Custom headers
    'Authorization': 'Bearer token',
  },
);

final client = RangeRequestClient(config: config);

File Conflict Handling #

// Choose how to handle existing files
final result = await downloader.downloadToFile(
  url,
  '/downloads',
  conflictStrategy: FileConflictStrategy.rename, // Creates "file(1).ext" if exists
  // or FileConflictStrategy.overwrite (default)
  // or FileConflictStrategy.error (throws exception)
);

Cleanup Temporary Files #

// Remove incomplete downloads older than 1 day
final deletedCount = await downloader.cleanupTempFiles(
  '/downloads',
  olderThan: Duration(days: 1),
);
print('Cleaned up $deletedCount temporary files');

API Reference #

Core Classes #

  • RangeRequestClient: Main client for performing HTTP range requests

    • fetch(): Stream download with optional progress callback
    • checkServerInfo(): Check if server supports range requests
    • cancelAll(): Cancel all active operations
    • clearTokens(): Clear all tokens without cancelling
    • cancelAndClear(): Cancel all operations and clear tokens
  • FileDownloader: High-level file download operations

    • downloadToFile(): Download directly to file with resume support
    • cleanupTempFiles(): Clean up temporary download files
  • RangeRequestConfig: Configuration for download behavior

    • Chunk size, concurrency, retries, timeouts, and more
  • CancelToken: Token for cancelling download operations

    • cancel(): Cancel the associated download
    • isCancelled: Check if operation was cancelled

Enums #

  • ChecksumType: Algorithm for file verification (sha256, md5, none)
  • DownloadStatus: Current operation status (downloading, calculatingChecksum)
  • FileConflictStrategy: How to handle existing files (overwrite, rename, error)

Advanced Features #

Parallel Chunked Downloads #

When the server supports range requests, files are automatically split into chunks and downloaded in parallel:

File: [====================] 100MB
       โ†“
Chunks: [====][====][====][====][====]  5 x 20MB
         โ†“  โ†“  โ†“  โ†“  โ†“
      Parallel Downloads (up to maxConcurrentRequests)
         โ†“  โ†“  โ†“  โ†“  โ†“
Reassembled: [====================]

Retry Logic #

Failed chunks are automatically retried with exponential backoff:

  • First retry: 2 seconds delay (2x initial delay)
  • Second retry: 4 seconds delay (4x initial delay)
  • Third retry: 8 seconds delay (8x initial delay)

Memory Efficiency #

  • Streaming API prevents loading entire files into memory
  • Configurable buffer sizes for optimal performance
  • Isolate-based checksum calculation prevents UI blocking

Error Handling #

try {
  await downloader.downloadToFile(url, '/downloads');
} on RangeRequestException catch (e) {
  switch (e.code) {
    case RangeRequestErrorCode.networkError:
      print('Network connection failed');
    case RangeRequestErrorCode.serverError:
      print('Server returned an error');
    case RangeRequestErrorCode.fileError:
      print('File system error occurred');
    case RangeRequestErrorCode.checksumMismatch:
      print('Downloaded file is corrupted');
    case RangeRequestErrorCode.cancelled:
      print('Download was cancelled');
    case RangeRequestErrorCode.invalidResponse:
      print('Invalid response from server');
    case RangeRequestErrorCode.unsupportedOperation:
      print('Operation not supported');
  }
}

License #

BSD 3-Clause License

0
likes
160
points
183
downloads

Publisher

verified publisherkyoheig3.jp

Weekly Downloads

A Dart package for efficient HTTP range requests supporting parallel chunked downloads, resume capability, and checksum verification.

Repository (GitHub)
View/report issues

Documentation

Documentation
API reference

License

BSD-3-Clause (license)

Dependencies

crypto, http

More

Packages that depend on range_request