2018-02-07 03:46:52 +00:00
|
|
|
import 'dart:async';
|
|
|
|
import 'dart:convert';
|
2018-06-08 07:06:26 +00:00
|
|
|
import 'dart:io'
|
|
|
|
show
|
2018-11-08 04:11:10 +00:00
|
|
|
Cookie,
|
2018-06-08 07:06:26 +00:00
|
|
|
HttpRequest,
|
|
|
|
HttpResponse,
|
|
|
|
HttpServer,
|
|
|
|
Platform,
|
|
|
|
SecurityContext;
|
2018-11-08 04:11:10 +00:00
|
|
|
import 'package:angel_framework/angel_framework.dart';
|
2018-08-20 20:53:30 +00:00
|
|
|
import '../core/core.dart';
|
2018-02-07 04:59:05 +00:00
|
|
|
import 'http_request_context.dart';
|
2018-02-07 05:21:14 +00:00
|
|
|
import 'http_response_context.dart';
|
2018-02-07 03:46:52 +00:00
|
|
|
|
2019-05-02 22:48:31 +00:00
|
|
|
final RegExp _straySlashes = RegExp(r'(^/+)|(/+$)');
|
2018-02-07 03:32:31 +00:00
|
|
|
|
|
|
|
/// Adapts `dart:io`'s [HttpServer] to serve Angel.
|
2018-11-08 04:11:10 +00:00
|
|
|
class AngelHttp extends Driver<HttpRequest, HttpResponse, HttpServer,
|
|
|
|
HttpRequestContext, HttpResponseContext> {
|
|
|
|
@override
|
|
|
|
Uri get uri =>
|
2019-05-02 22:48:31 +00:00
|
|
|
Uri(scheme: 'http', host: server.address.address, port: server.port);
|
2018-11-08 04:11:10 +00:00
|
|
|
|
|
|
|
AngelHttp._(Angel app,
|
|
|
|
Future<HttpServer> Function(dynamic, int) serverGenerator, bool useZone)
|
|
|
|
: super(app, serverGenerator, useZone: useZone);
|
|
|
|
|
2019-04-11 02:37:05 +00:00
|
|
|
factory AngelHttp(Angel app, {bool useZone = true}) {
|
2019-05-02 22:48:31 +00:00
|
|
|
return AngelHttp._(app, HttpServer.bind, useZone);
|
2018-11-08 04:11:10 +00:00
|
|
|
}
|
2018-02-07 04:17:40 +00:00
|
|
|
|
2018-02-07 04:10:49 +00:00
|
|
|
/// An instance mounted on a server started by the [serverGenerator].
|
2018-02-07 04:17:40 +00:00
|
|
|
factory AngelHttp.custom(
|
2018-06-08 07:06:26 +00:00
|
|
|
Angel app, Future<HttpServer> Function(dynamic, int) serverGenerator,
|
2019-04-11 02:37:05 +00:00
|
|
|
{bool useZone = true}) {
|
2019-05-02 22:48:31 +00:00
|
|
|
return AngelHttp._(app, serverGenerator, useZone);
|
2018-02-07 04:10:49 +00:00
|
|
|
}
|
|
|
|
|
2018-06-08 07:06:26 +00:00
|
|
|
factory AngelHttp.fromSecurityContext(Angel app, SecurityContext context,
|
2019-04-11 02:37:05 +00:00
|
|
|
{bool useZone = true}) {
|
2019-05-02 22:48:31 +00:00
|
|
|
return AngelHttp._(app, (address, int port) {
|
2018-06-08 07:06:26 +00:00
|
|
|
return HttpServer.bindSecure(address, port, context);
|
2018-11-08 04:11:10 +00:00
|
|
|
}, useZone);
|
2018-02-07 04:10:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Creates an HTTPS server.
|
|
|
|
///
|
|
|
|
/// Provide paths to a certificate chain and server key (both .pem).
|
|
|
|
/// If no password is provided, a random one will be generated upon running
|
|
|
|
/// the server.
|
2018-02-07 04:17:40 +00:00
|
|
|
factory AngelHttp.secure(
|
|
|
|
Angel app, String certificateChainPath, String serverKeyPath,
|
2019-04-11 02:37:05 +00:00
|
|
|
{String password, bool useZone = true}) {
|
2018-02-07 04:10:49 +00:00
|
|
|
var certificateChain =
|
2018-02-07 04:17:40 +00:00
|
|
|
Platform.script.resolve(certificateChainPath).toFilePath();
|
2018-02-07 04:10:49 +00:00
|
|
|
var serverKey = Platform.script.resolve(serverKeyPath).toFilePath();
|
2019-05-02 22:48:31 +00:00
|
|
|
var serverContext = SecurityContext();
|
2018-02-07 04:10:49 +00:00
|
|
|
serverContext.useCertificateChain(certificateChain, password: password);
|
|
|
|
serverContext.usePrivateKey(serverKey, password: password);
|
2019-05-02 22:48:31 +00:00
|
|
|
return AngelHttp.fromSecurityContext(app, serverContext, useZone: useZone);
|
2018-02-07 04:10:49 +00:00
|
|
|
}
|
|
|
|
|
2018-11-08 04:11:10 +00:00
|
|
|
/// Use [server] instead.
|
|
|
|
@deprecated
|
|
|
|
HttpServer get httpServer => server;
|
2018-02-07 03:46:52 +00:00
|
|
|
|
2018-11-08 04:11:10 +00:00
|
|
|
Future handleRequest(HttpRequest request) =>
|
|
|
|
handleRawRequest(request, request.response);
|
2018-08-21 01:27:39 +00:00
|
|
|
|
2018-11-08 04:11:10 +00:00
|
|
|
@override
|
|
|
|
void addCookies(HttpResponse response, Iterable<Cookie> cookies) =>
|
|
|
|
response.cookies.addAll(cookies);
|
2018-08-21 01:27:39 +00:00
|
|
|
|
2018-11-11 01:07:09 +00:00
|
|
|
@override
|
|
|
|
Future<HttpServer> close() async {
|
|
|
|
await server?.close();
|
|
|
|
return await super.close();
|
|
|
|
}
|
|
|
|
|
2018-11-08 04:11:10 +00:00
|
|
|
@override
|
|
|
|
Future closeResponse(HttpResponse response) => response.close();
|
2018-08-21 14:28:53 +00:00
|
|
|
|
2018-11-08 04:11:10 +00:00
|
|
|
@override
|
|
|
|
Future<HttpRequestContext> createRequestContext(
|
|
|
|
HttpRequest request, HttpResponse response) {
|
|
|
|
var path = request.uri.path.replaceAll(_straySlashes, '');
|
2019-04-11 02:37:05 +00:00
|
|
|
if (path.isEmpty) path = '/';
|
2018-11-08 04:11:10 +00:00
|
|
|
return HttpRequestContext.from(request, app, path);
|
2018-02-07 03:46:52 +00:00
|
|
|
}
|
|
|
|
|
2018-11-08 04:11:10 +00:00
|
|
|
@override
|
|
|
|
Future<HttpResponseContext> createResponseContext(
|
|
|
|
HttpRequest request, HttpResponse response,
|
|
|
|
[HttpRequestContext correspondingRequest]) {
|
2019-05-02 22:48:31 +00:00
|
|
|
return Future<HttpResponseContext>.value(
|
|
|
|
HttpResponseContext(response, app, correspondingRequest)
|
2018-11-08 04:11:10 +00:00
|
|
|
..serializer = (app.serializer ?? json.encode)
|
|
|
|
..encoders.addAll(app.encoders ?? {}));
|
2018-02-07 03:46:52 +00:00
|
|
|
}
|
|
|
|
|
2018-11-08 04:11:10 +00:00
|
|
|
@override
|
2018-11-11 01:07:09 +00:00
|
|
|
Stream<HttpResponse> createResponseStreamFromRawRequest(
|
|
|
|
HttpRequest request) =>
|
2019-05-02 22:48:31 +00:00
|
|
|
Stream.fromIterable([request.response]);
|
2018-07-09 16:50:20 +00:00
|
|
|
|
2018-11-08 04:11:10 +00:00
|
|
|
@override
|
|
|
|
void setChunkedEncoding(HttpResponse response, bool value) =>
|
|
|
|
response.headers.chunkedTransferEncoding = value;
|
2018-07-09 16:50:20 +00:00
|
|
|
|
2018-11-08 04:11:10 +00:00
|
|
|
@override
|
|
|
|
void setContentLength(HttpResponse response, int length) =>
|
|
|
|
response.headers.contentLength = length;
|
2018-02-07 03:46:52 +00:00
|
|
|
|
2018-11-08 04:11:10 +00:00
|
|
|
@override
|
|
|
|
void setHeader(HttpResponse response, String key, String value) =>
|
|
|
|
response.headers.set(key, value);
|
2018-02-07 03:46:52 +00:00
|
|
|
|
2018-11-08 04:11:10 +00:00
|
|
|
@override
|
|
|
|
void setStatusCode(HttpResponse response, int value) =>
|
|
|
|
response.statusCode = value;
|
2018-02-07 03:46:52 +00:00
|
|
|
|
2018-11-08 04:11:10 +00:00
|
|
|
@override
|
|
|
|
void writeStringToResponse(HttpResponse response, String value) =>
|
|
|
|
response.write(value);
|
2018-02-07 03:46:52 +00:00
|
|
|
|
2018-11-08 04:11:10 +00:00
|
|
|
@override
|
|
|
|
void writeToResponse(HttpResponse response, List<int> data) =>
|
|
|
|
response.add(data);
|
2018-02-07 04:17:40 +00:00
|
|
|
}
|