Skip to content

Commit

Permalink
Add the ability to control the URL cache. (#1020)
Browse files Browse the repository at this point in the history
  • Loading branch information
brianquinlan authored Sep 19, 2023
1 parent decefa6 commit 1251619
Show file tree
Hide file tree
Showing 8 changed files with 5,585 additions and 4,720 deletions.
2 changes: 2 additions & 0 deletions pkgs/cupertino_http/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
* Disable additional analyses for generated Objective-C bindings to prevent
errors from `dart analyze`.
* Throw `ClientException` when the `'Content-Length'` header is invalid.
* Add support for configurable caching through
`URLSessionConfiguration.cache`.

## 1.0.1

Expand Down
2 changes: 2 additions & 0 deletions pkgs/cupertino_http/example/integration_test/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import 'error_test.dart' as error_test;
import 'http_url_response_test.dart' as http_url_response_test;
import 'mutable_data_test.dart' as mutable_data_test;
import 'mutable_url_request_test.dart' as mutable_url_request_test;
import 'url_cache_test.dart' as url_cache_test;
import 'url_request_test.dart' as url_request_test;
import 'url_response_test.dart' as url_response_test;
import 'url_session_configuration_test.dart' as url_session_configuration_test;
Expand All @@ -34,6 +35,7 @@ void main() {
http_url_response_test.main();
mutable_data_test.main();
mutable_url_request_test.main();
url_cache_test.main();
url_request_test.main();
url_response_test.main();
url_session_configuration_test.main();
Expand Down
72 changes: 72 additions & 0 deletions pkgs/cupertino_http/example/integration_test/url_cache_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

import 'dart:async';
import 'dart:io';

import 'package:cupertino_http/cupertino_http.dart';
import 'package:integration_test/integration_test.dart';
import 'package:test/test.dart';

void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();

group('dataTaskWithCompletionHandler', () {
late HttpServer server;
var uncachedRequestCount = 0;

setUp(() async {
uncachedRequestCount = 0;
server = (await HttpServer.bind('localhost', 0))
..listen((request) async {
await request.drain<void>();
if (request.headers['if-none-match']?.first == '1234') {
request.response.statusCode = 304;
await request.response.close();
return;
}
++uncachedRequestCount;
request.response.headers.set('Content-Type', 'text/plain');
request.response.headers.set('ETag', '1234');
request.response.write('Hello World');
await request.response.close();
});
});
tearDown(() {
server.close();
});

Future<void> doRequest(URLSession session) {
final request =
URLRequest.fromUrl(Uri.parse('http://localhost:${server.port}'));
final c = Completer<void>();
session.dataTaskWithCompletionHandler(request, (d, r, e) {
c.complete();
}).resume();
return c.future;
}

test('no cache', () async {
final config = URLSessionConfiguration.defaultSessionConfiguration()
..cache = null;
final session = URLSession.sessionWithConfiguration(config);

await doRequest(session);
await doRequest(session);

expect(uncachedRequestCount, 2);
});

test('with cache', () async {
final config = URLSessionConfiguration.defaultSessionConfiguration()
..cache = URLCache.withCapacity(memoryCapacity: 100000);
final session = URLSession.sessionWithConfiguration(config);

await doRequest(session);
await doRequest(session);

expect(uncachedRequestCount, 1);
});
});
}
1 change: 1 addition & 0 deletions pkgs/cupertino_http/ffigen.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ headers:
- '/System/Volumes/Data/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/System/Library/Frameworks/Foundation.framework/Versions/C/Headers/NSArray.h'
- '/System/Volumes/Data/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/System/Library/Frameworks/Foundation.framework/Versions/C/Headers/NSData.h'
- '/System/Volumes/Data/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/System/Library/Frameworks/Foundation.framework/Versions/C/Headers/NSDictionary.h'
- '/System/Volumes/Data/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/System/Library/Frameworks/Foundation.framework/Versions/C/Headers/NSURLCache.h'
- '/System/Volumes/Data/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/System/Library/Frameworks/Foundation.framework/Versions/C/Headers/NSURLRequest.h'
- '/System/Volumes/Data/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/System/Library/Frameworks/Foundation.framework/Versions/C/Headers/NSURLSession.h'
- '/System/Volumes/Data/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/System/Library/Frameworks/Foundation.framework/Versions/C/Headers/NSURL.h'
Expand Down
69 changes: 52 additions & 17 deletions pkgs/cupertino_http/lib/src/cupertino_api.dart
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,35 @@ class Error extends _ObjectHolder<ncb.NSError> implements Exception {
']';
}

/// A cache for [URLRequest]s. Used by [URLSessionConfiguration.cache].
///
/// See [NSURLCache](https://developer.apple.com/documentation/foundation/nsurlcache)
class URLCache extends _ObjectHolder<ncb.NSURLCache> {
URLCache._(super.c);

/// The default URLCache.
///
/// See [NSURLCache.sharedURLCache](https://developer.apple.com/documentation/foundation/nsurlcache/1413377-sharedurlcache)
static URLCache? get sharedURLCache {
final sharedCache = ncb.NSURLCache.getSharedURLCache(linkedLibs);
return sharedCache == null ? null : URLCache._(sharedCache);
}

/// Create a new [URLCache] with the given memory and disk cache sizes.
///
/// [memoryCapacity] and [diskCapacity] are specified in bytes.
///
/// [directory] is the file system location where the disk cache will be
/// stored. If `null` then the default directory will be used.
///
/// See [NSURLCache initWithMemoryCapacity:diskCapacity:directoryURL:](https://developer.apple.com/documentation/foundation/nsurlcache/3240612-initwithmemorycapacity)
factory URLCache.withCapacity(
{int memoryCapacity = 0, int diskCapacity = 0, Uri? directory}) =>
URLCache._(ncb.NSURLCache.alloc(linkedLibs)
.initWithMemoryCapacity_diskCapacity_directoryURL_(memoryCapacity,
diskCapacity, directory == null ? null : uriToNSURL(directory)));
}

/// Controls the behavior of a URLSession.
///
/// See [NSURLSessionConfiguration](https://developer.apple.com/documentation/foundation/nsurlsessionconfiguration)
Expand Down Expand Up @@ -300,6 +329,15 @@ class URLSessionConfiguration
set allowsExpensiveNetworkAccess(bool value) =>
_nsObject.allowsExpensiveNetworkAccess = value;

/// The [URLCache] used to cache the results of [URLSessionTask]s.
///
/// A value of `nil` indicates that no cache will be used.
///
/// See [NSURLSessionConfiguration.URLCache](https://developer.apple.com/documentation/foundation/nsurlsessionconfiguration/1410148-urlcache)
URLCache? get cache =>
_nsObject.URLCache == null ? null : URLCache._(_nsObject.URLCache!);
set cache(URLCache? cache) => _nsObject.URLCache = cache?._nsObject;

/// Whether background tasks can be delayed by the system.
///
/// See [NSURLSessionConfiguration.discretionary](https://developer.apple.com/documentation/foundation/nsurlsessionconfiguration/1411552-discretionary)
Expand All @@ -314,10 +352,10 @@ class URLSessionConfiguration
set httpCookieAcceptPolicy(HTTPCookieAcceptPolicy value) =>
_nsObject.HTTPCookieAcceptPolicy = value.index;

// The maximum number of connections that a URLSession can have open to the
// same host.
/// The maximum number of connections that a URLSession can have open to the
/// same host.
//
// See [NSURLSessionConfiguration.HTTPMaximumConnectionsPerHost](https://developer.apple.com/documentation/foundation/nsurlsessionconfiguration/1407597-httpmaximumconnectionsperhost).
/// See [NSURLSessionConfiguration.HTTPMaximumConnectionsPerHost](https://developer.apple.com/documentation/foundation/nsurlsessionconfiguration/1407597-httpmaximumconnectionsperhost).
int get httpMaximumConnectionsPerHost =>
_nsObject.HTTPMaximumConnectionsPerHost;
set httpMaximumConnectionsPerHost(int value) =>
Expand Down Expand Up @@ -354,9 +392,9 @@ class URLSessionConfiguration
set networkServiceType(URLRequestNetworkService value) =>
_nsObject.networkServiceType = value.index;

// Controls how to deal with response caching.
//
// See [NSURLSessionConfiguration.requestCachePolicy](https://developer.apple.com/documentation/foundation/nsurlsessionconfiguration/1411655-requestcachepolicy)
/// Controls how to deal with response caching.
///
/// See [NSURLSessionConfiguration.requestCachePolicy](https://developer.apple.com/documentation/foundation/nsurlsessionconfiguration/1411655-requestcachepolicy)
URLRequestCachePolicy get requestCachePolicy =>
URLRequestCachePolicy.values[_nsObject.requestCachePolicy];
set requestCachePolicy(URLRequestCachePolicy value) =>
Expand Down Expand Up @@ -422,9 +460,9 @@ class URLSessionConfiguration
class Data extends _ObjectHolder<ncb.NSData> {
Data._(super.c);

// A new [Data] from an existing one.
//
// See [NSData dataWithData:](https://developer.apple.com/documentation/foundation/nsdata/1547230-datawithdata)
/// A new [Data] from an existing one.
///
/// See [NSData dataWithData:](https://developer.apple.com/documentation/foundation/nsdata/1547230-datawithdata)
factory Data.fromData(Data d) =>
Data._(ncb.NSData.dataWithData_(linkedLibs, d._nsObject));

Expand Down Expand Up @@ -916,11 +954,8 @@ class URLRequest extends _ObjectHolder<ncb.NSURLRequest> {
/// Creates a request for a URL.
///
/// See [NSURLRequest.requestWithURL:](https://developer.apple.com/documentation/foundation/nsurlrequest/1528603-requestwithurl)
factory URLRequest.fromUrl(Uri uri) {
final url = ncb.NSURL
.URLWithString_(linkedLibs, uri.toString().toNSString(linkedLibs));
return URLRequest._(ncb.NSURLRequest.requestWithURL_(linkedLibs, url));
}
factory URLRequest.fromUrl(Uri uri) => URLRequest._(
ncb.NSURLRequest.requestWithURL_(linkedLibs, uriToNSURL(uri)));

/// Returns all of the HTTP headers for the request.
///
Expand All @@ -934,9 +969,9 @@ class URLRequest extends _ObjectHolder<ncb.NSURLRequest> {
}
}

// Controls how to deal with caching for the request.
//
// See [NSURLSession.cachePolicy](https://developer.apple.com/documentation/foundation/nsurlrequest/1407944-cachepolicy)
/// Controls how to deal with caching for the request.
///
/// See [NSURLSession.cachePolicy](https://developer.apple.com/documentation/foundation/nsurlrequest/1407944-cachepolicy)
URLRequestCachePolicy get cachePolicy =>
URLRequestCachePolicy.values[_nsObject.cachePolicy];

Expand Down
Loading

0 comments on commit 1251619

Please sign in to comment.