324 lines
8.2 KiB
Dart
324 lines
8.2 KiB
Dart
|
import 'dart:async';
|
||
|
import 'dart:convert';
|
||
|
import 'dart:io';
|
||
|
import 'dart:typed_data';
|
||
|
import 'package:charcode/ascii.dart';
|
||
|
import 'connection_info.dart';
|
||
|
import 'lockable_headers.dart';
|
||
|
import 'response.dart';
|
||
|
import 'session.dart';
|
||
|
|
||
|
class MockHttpRequest
|
||
|
implements HttpRequest, StreamSink<List<int>>, StringSink {
|
||
|
int _contentLength = 0;
|
||
|
late BytesBuilder _buf;
|
||
|
final Completer _done = Completer();
|
||
|
final LockableMockHttpHeaders _headers = LockableMockHttpHeaders();
|
||
|
Uri? _requestedUri;
|
||
|
late MockHttpSession _session;
|
||
|
final StreamController<Uint8List> _stream = StreamController<Uint8List>();
|
||
|
|
||
|
@override
|
||
|
final List<Cookie> cookies = [];
|
||
|
|
||
|
@override
|
||
|
HttpConnectionInfo connectionInfo =
|
||
|
MockHttpConnectionInfo(remoteAddress: InternetAddress.loopbackIPv4);
|
||
|
|
||
|
@override
|
||
|
MockHttpResponse response = MockHttpResponse(
|
||
|
contentLength: 0,
|
||
|
encoding: utf8,
|
||
|
persistentConnection: false,
|
||
|
reasonPhrase: '',
|
||
|
statusCode: 200);
|
||
|
|
||
|
@override
|
||
|
HttpSession get session => _session;
|
||
|
|
||
|
@override
|
||
|
final String method;
|
||
|
|
||
|
@override
|
||
|
final Uri uri;
|
||
|
|
||
|
@override
|
||
|
bool persistentConnection = true;
|
||
|
|
||
|
/// [copyBuffer] corresponds to `copy` on the [BytesBuilder] constructor.
|
||
|
MockHttpRequest(this.method, this.uri,
|
||
|
{bool copyBuffer = true,
|
||
|
String? protocolVersion,
|
||
|
String? sessionId,
|
||
|
this.certificate,
|
||
|
this.persistentConnection = true}) {
|
||
|
_buf = BytesBuilder(copy: copyBuffer != false);
|
||
|
_session = MockHttpSession(id: sessionId ?? 'mock-http-session');
|
||
|
|
||
|
this.protocolVersion = protocolVersion ?? '1.1';
|
||
|
}
|
||
|
|
||
|
@override
|
||
|
int get contentLength => _contentLength;
|
||
|
|
||
|
@override
|
||
|
HttpHeaders get headers => _headers;
|
||
|
|
||
|
@override
|
||
|
Uri get requestedUri {
|
||
|
if (_requestedUri != null) {
|
||
|
return _requestedUri!;
|
||
|
} else {
|
||
|
return _requestedUri = Uri(
|
||
|
scheme: 'http',
|
||
|
host: 'example.com',
|
||
|
path: uri.path,
|
||
|
query: uri.query,
|
||
|
);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
set requestedUri(Uri value) {
|
||
|
_requestedUri = value;
|
||
|
}
|
||
|
|
||
|
@override
|
||
|
late String protocolVersion;
|
||
|
|
||
|
@override
|
||
|
X509Certificate? certificate;
|
||
|
|
||
|
@override
|
||
|
void add(List<int> data) {
|
||
|
if (_done.isCompleted) {
|
||
|
throw StateError('Cannot add to closed MockHttpRequest.');
|
||
|
} else {
|
||
|
_headers.lock();
|
||
|
_contentLength += data.length;
|
||
|
_buf.add(data);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
@override
|
||
|
void addError(error, [StackTrace? stackTrace]) {
|
||
|
if (_done.isCompleted) {
|
||
|
throw StateError('Cannot add to closed MockHttpRequest.');
|
||
|
} else {
|
||
|
_stream.addError(error, stackTrace);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
@override
|
||
|
Future addStream(Stream<List<int>> stream) {
|
||
|
var c = Completer();
|
||
|
stream.listen(add, onError: addError, onDone: c.complete);
|
||
|
return c.future;
|
||
|
}
|
||
|
|
||
|
@override
|
||
|
Future close() async {
|
||
|
await flush();
|
||
|
_headers.lock();
|
||
|
scheduleMicrotask(_stream.close);
|
||
|
_done.complete();
|
||
|
return await _done.future;
|
||
|
}
|
||
|
|
||
|
@override
|
||
|
Future get done => _done.future;
|
||
|
|
||
|
// @override
|
||
|
Future flush() async {
|
||
|
_contentLength += _buf.length;
|
||
|
_stream.add(_buf.takeBytes());
|
||
|
}
|
||
|
|
||
|
@override
|
||
|
void write(Object? obj) {
|
||
|
obj?.toString().codeUnits.forEach(writeCharCode);
|
||
|
}
|
||
|
|
||
|
@override
|
||
|
void writeAll(Iterable objects, [String separator = '']) {
|
||
|
write(objects.join(separator));
|
||
|
}
|
||
|
|
||
|
@override
|
||
|
void writeCharCode(int charCode) {
|
||
|
add([charCode]);
|
||
|
}
|
||
|
|
||
|
@override
|
||
|
void writeln([Object? obj = '']) {
|
||
|
write(obj ?? '');
|
||
|
add([$cr, $lf]);
|
||
|
}
|
||
|
|
||
|
@override
|
||
|
Future<bool> any(bool Function(Uint8List element) test) {
|
||
|
return _stream.stream.any((List<int> e) {
|
||
|
return test(Uint8List.fromList(e));
|
||
|
});
|
||
|
}
|
||
|
|
||
|
@override
|
||
|
Stream<Uint8List> asBroadcastStream({
|
||
|
void Function(StreamSubscription<Uint8List> subscription)? onListen,
|
||
|
void Function(StreamSubscription<Uint8List> subscription)? onCancel,
|
||
|
}) {
|
||
|
return _stream.stream
|
||
|
.asBroadcastStream(onListen: onListen, onCancel: onCancel);
|
||
|
}
|
||
|
|
||
|
@override
|
||
|
Stream<E> asyncExpand<E>(Stream<E>? Function(Uint8List event) convert) =>
|
||
|
_stream.stream.asyncExpand(convert);
|
||
|
|
||
|
@override
|
||
|
Stream<E> asyncMap<E>(FutureOr<E> Function(Uint8List event) convert) =>
|
||
|
_stream.stream.asyncMap(convert);
|
||
|
|
||
|
@override
|
||
|
Future<bool> contains(Object? needle) => _stream.stream.contains(needle);
|
||
|
|
||
|
@override
|
||
|
Stream<Uint8List> distinct(
|
||
|
[bool Function(Uint8List previous, Uint8List next)? equals]) =>
|
||
|
_stream.stream.distinct(equals);
|
||
|
|
||
|
@override
|
||
|
Future<E> drain<E>([E? futureValue]) => _stream.stream.drain(futureValue);
|
||
|
|
||
|
@override
|
||
|
Future<Uint8List> elementAt(int index) => _stream.stream.elementAt(index);
|
||
|
|
||
|
@override
|
||
|
Future<bool> every(bool Function(Uint8List element) test) =>
|
||
|
_stream.stream.every(test);
|
||
|
|
||
|
@override
|
||
|
Stream<S> expand<S>(Iterable<S> Function(Uint8List value) convert) =>
|
||
|
_stream.stream.expand(convert);
|
||
|
|
||
|
@override
|
||
|
Future<Uint8List> get first => _stream.stream.first;
|
||
|
|
||
|
@override
|
||
|
Future<Uint8List> firstWhere(bool Function(Uint8List element) test,
|
||
|
{List<int> Function()? orElse}) =>
|
||
|
_stream.stream
|
||
|
.firstWhere(test, orElse: () => Uint8List.fromList(orElse!()));
|
||
|
|
||
|
@override
|
||
|
Future<S> fold<S>(
|
||
|
S initialValue, S Function(S previous, Uint8List element) combine) =>
|
||
|
_stream.stream.fold(initialValue, combine);
|
||
|
|
||
|
@override
|
||
|
Future forEach(void Function(Uint8List element) action) =>
|
||
|
_stream.stream.forEach(action);
|
||
|
|
||
|
@override
|
||
|
Stream<Uint8List> handleError(Function onError,
|
||
|
{bool Function(Object?)? test}) =>
|
||
|
_stream.stream.handleError(onError, test: test);
|
||
|
|
||
|
@override
|
||
|
bool get isBroadcast => _stream.stream.isBroadcast;
|
||
|
|
||
|
@override
|
||
|
Future<bool> get isEmpty => _stream.stream.isEmpty;
|
||
|
|
||
|
@override
|
||
|
Future<String> join([String separator = '']) =>
|
||
|
_stream.stream.join(separator);
|
||
|
|
||
|
@override
|
||
|
Future<Uint8List> get last => _stream.stream.last;
|
||
|
|
||
|
@override
|
||
|
Future<Uint8List> lastWhere(bool Function(Uint8List element) test,
|
||
|
{List<int> Function()? orElse}) =>
|
||
|
_stream.stream
|
||
|
.lastWhere(test, orElse: () => Uint8List.fromList(orElse!()));
|
||
|
|
||
|
@override
|
||
|
Future<int> get length => _stream.stream.length;
|
||
|
|
||
|
@override
|
||
|
StreamSubscription<Uint8List> listen(
|
||
|
void Function(Uint8List event)? onData, {
|
||
|
Function? onError,
|
||
|
void Function()? onDone,
|
||
|
bool? cancelOnError,
|
||
|
}) {
|
||
|
return _stream.stream.listen(
|
||
|
onData,
|
||
|
onError: onError,
|
||
|
onDone: onDone,
|
||
|
cancelOnError: cancelOnError == true,
|
||
|
);
|
||
|
}
|
||
|
|
||
|
@override
|
||
|
Stream<S> map<S>(S Function(Uint8List event) convert) =>
|
||
|
_stream.stream.map(convert);
|
||
|
|
||
|
@override
|
||
|
Future pipe(StreamConsumer<List<int>> streamConsumer) =>
|
||
|
_stream.stream.cast<List<int>>().pipe(streamConsumer);
|
||
|
|
||
|
@override
|
||
|
Future<Uint8List> reduce(
|
||
|
List<int> Function(Uint8List previous, Uint8List element) combine) {
|
||
|
return _stream.stream.reduce((Uint8List previous, Uint8List element) {
|
||
|
return Uint8List.fromList(combine(previous, element));
|
||
|
});
|
||
|
}
|
||
|
|
||
|
@override
|
||
|
Future<Uint8List> get single => _stream.stream.single;
|
||
|
|
||
|
@override
|
||
|
Future<Uint8List> singleWhere(bool Function(Uint8List element) test,
|
||
|
{List<int> Function()? orElse}) =>
|
||
|
_stream.stream
|
||
|
.singleWhere(test, orElse: () => Uint8List.fromList(orElse!()));
|
||
|
|
||
|
@override
|
||
|
Stream<Uint8List> skip(int count) => _stream.stream.skip(count);
|
||
|
|
||
|
@override
|
||
|
Stream<Uint8List> skipWhile(bool Function(Uint8List element) test) =>
|
||
|
_stream.stream.skipWhile(test);
|
||
|
|
||
|
@override
|
||
|
Stream<Uint8List> take(int count) => _stream.stream.take(count);
|
||
|
|
||
|
@override
|
||
|
Stream<Uint8List> takeWhile(bool Function(Uint8List element) test) =>
|
||
|
_stream.stream.takeWhile(test);
|
||
|
|
||
|
@override
|
||
|
Stream<Uint8List> timeout(Duration timeLimit,
|
||
|
{void Function(EventSink<Uint8List> sink)? onTimeout}) =>
|
||
|
_stream.stream.timeout(timeLimit, onTimeout: onTimeout);
|
||
|
|
||
|
@override
|
||
|
Future<List<Uint8List>> toList() => _stream.stream.toList();
|
||
|
|
||
|
@override
|
||
|
Future<Set<Uint8List>> toSet() => _stream.stream.toSet();
|
||
|
|
||
|
@override
|
||
|
Stream<S> transform<S>(StreamTransformer<List<int>, S> streamTransformer) =>
|
||
|
_stream.stream.cast<List<int>>().transform(streamTransformer);
|
||
|
|
||
|
@override
|
||
|
Stream<Uint8List> where(bool Function(Uint8List event) test) =>
|
||
|
_stream.stream.where(test);
|
||
|
|
||
|
@override
|
||
|
Stream<R> cast<R>() => Stream.castFrom<List<int>, R>(this);
|
||
|
}
|