platform/packages/shelf/lib/src/convert.dart

87 lines
2.9 KiB
Dart
Raw Normal View History

2017-06-12 23:53:08 +00:00
import 'dart:async';
import 'dart:io';
2021-09-14 01:23:03 +00:00
import 'package:angel3_framework/angel3_framework.dart';
2018-11-11 17:35:37 +00:00
import 'package:path/path.dart' as p;
2017-06-12 23:53:08 +00:00
import 'package:shelf/shelf.dart' as shelf;
2018-11-11 17:35:37 +00:00
import 'package:stream_channel/stream_channel.dart';
2017-06-12 23:53:08 +00:00
2018-11-11 17:35:37 +00:00
/// Creates a [shelf.Request] analogous to the input [req].
2017-06-12 23:53:08 +00:00
///
2021-09-14 01:23:03 +00:00
/// The request's `context` will contain [req.container] as `angel3_shelf.container`, as well as
2017-06-12 23:53:08 +00:00
/// the provided [context], if any.
///
2021-09-14 01:23:03 +00:00
/// The context will also have the original request available as `angel3_shelf.request`.
2017-06-12 23:53:08 +00:00
///
2018-11-11 17:35:37 +00:00
/// If you want to read the request body, you *must* set `keepRawRequestBuffers` to `true`
2017-06-12 23:53:08 +00:00
/// on your application instance.
2018-11-11 17:35:37 +00:00
Future<shelf.Request> convertRequest(RequestContext req, ResponseContext res,
2021-06-20 12:37:20 +00:00
{String? handlerPath, Map<String, Object>? context}) async {
2018-11-11 17:35:37 +00:00
var app = req.app;
2017-06-12 23:53:08 +00:00
var headers = <String, String>{};
2021-06-20 12:37:20 +00:00
req.headers!.forEach((k, v) {
2017-06-12 23:53:08 +00:00
headers[k] = v.join(',');
});
2018-11-11 17:35:37 +00:00
headers.remove(HttpHeaders.transferEncodingHeader);
2017-06-12 23:53:08 +00:00
2018-11-11 17:35:37 +00:00
void Function(void Function(StreamChannel<List<int>>)) onHijack;
String protocolVersion;
Uri requestedUri;
2019-10-14 15:28:50 +00:00
protocolVersion = '1.1';
requestedUri = Uri.parse('http://${req.hostname}');
2021-06-20 12:37:20 +00:00
requestedUri = requestedUri.replace(path: req.uri!.path);
2018-11-11 17:35:37 +00:00
2019-10-14 18:42:43 +00:00
onHijack = (void Function(StreamChannel<List<int>> channel) hijack) async {
try {
print('a');
await res.detach();
print('b');
2019-10-14 15:28:50 +00:00
var ctrl = StreamChannelController<List<int>>();
if (req.hasParsedBody) {
2021-06-20 12:37:20 +00:00
req.body!.listen(ctrl.local.sink.add,
2018-11-11 17:35:37 +00:00
onError: ctrl.local.sink.addError, onDone: ctrl.local.sink.close);
2019-10-14 15:28:50 +00:00
} else {
2019-10-14 18:42:43 +00:00
await ctrl.local.sink.close();
2019-10-14 15:28:50 +00:00
}
2019-10-14 18:42:43 +00:00
scheduleMicrotask(() => ctrl.local.stream.pipe(res));
2019-10-14 15:28:50 +00:00
hijack(ctrl.foreign);
2019-10-14 18:42:43 +00:00
} catch (e, st) {
2021-06-20 12:37:20 +00:00
app?.logger
2019-10-14 18:42:43 +00:00
?.severe('An error occurred while hijacking a shelf request', e, st);
}
2019-10-14 15:28:50 +00:00
};
2018-11-11 17:35:37 +00:00
2021-06-20 12:37:20 +00:00
var url = req.uri!;
2018-11-11 17:35:37 +00:00
if (p.isAbsolute(url.path)) {
url = url.replace(path: url.path.substring(1));
2017-06-12 23:53:08 +00:00
}
2019-10-14 15:28:50 +00:00
return shelf.Request(req.method, requestedUri,
2018-11-11 17:35:37 +00:00
protocolVersion: protocolVersion,
2017-06-12 23:53:08 +00:00
headers: headers,
handlerPath: handlerPath,
2018-11-11 17:35:37 +00:00
url: url,
2019-10-14 15:28:50 +00:00
body: req.body,
2021-09-14 01:23:03 +00:00
context: {'angel3_shelf.request': req}
..addAll({'angel3_shelf.container': req.container!})
2017-06-12 23:53:08 +00:00
..addAll(context ?? {}),
onHijack: onHijack);
}
/// Applies the state of the [shelfResponse] into the [angelResponse].
///
/// Merges all headers, sets the status code, and writes the body.
///
/// In addition, the response's context will be available in `angelResponse.properties`
/// as `shelf_context`.
Future mergeShelfResponse(
2018-01-09 14:44:59 +00:00
shelf.Response shelfResponse, ResponseContext angelResponse) {
2017-06-12 23:53:08 +00:00
angelResponse.headers.addAll(shelfResponse.headers);
angelResponse.statusCode = shelfResponse.statusCode;
angelResponse.properties['shelf_context'] = shelfResponse.context;
2017-06-20 16:23:10 +00:00
angelResponse.properties['shelf_response'] = shelfResponse;
2018-01-09 14:44:59 +00:00
return shelfResponse.read().pipe(angelResponse);
2017-06-12 23:53:08 +00:00
}