platform/lib/src/wings_request.dart

215 lines
5.7 KiB
Dart
Raw Normal View History

2019-04-29 08:22:36 +00:00
import 'dart:async';
import 'dart:io';
2019-04-29 08:22:36 +00:00
import 'dart:isolate';
2019-05-01 04:29:21 +00:00
import 'dart:typed_data';
2019-04-29 08:22:36 +00:00
import 'package:angel_container/angel_container.dart';
import 'package:angel_framework/angel_framework.dart';
2019-04-29 08:22:36 +00:00
import 'package:mock_request/mock_request.dart';
import 'wings_socket.dart';
2018-07-03 23:16:29 +00:00
2019-04-29 08:22:36 +00:00
enum _ParseState { method, url, headerField, headerValue, body }
final RegExp _straySlashes = new RegExp(r'(^/+)|(/+$)');
class WingsRequestContext extends RequestContext<WingsClientSocket> {
final WingsClientSocket rawRequest;
final Container container;
final StreamController<List<int>> _body = StreamController();
List<Cookie> _cookies, __cookies;
final LockableMockHttpHeaders _headers = LockableMockHttpHeaders();
final RawReceivePort _recv;
InternetAddress _remoteAddress;
String _method, _override, _path;
Uri _uri;
2018-07-03 23:16:29 +00:00
@override
2019-04-29 08:22:36 +00:00
Angel app;
WingsRequestContext._(this.app, this.rawRequest, this._recv)
: container = app.container.createChild();
2019-04-30 17:40:11 +00:00
Future<void> close() async {
await _body.close();
_recv.close();
}
2019-04-29 08:22:36 +00:00
static const int DELETE = 0,
GET = 1,
HEAD = 2,
POST = 3,
PUT = 4,
CONNECT = 5,
OPTIONS = 6,
TRACE = 7,
COPY = 8,
LOCK = 9,
MKCOL = 10,
MOVE = 11,
PROPFIND = 12,
PROPPATCH = 13,
SEARCH = 14,
UNLOCK = 15,
BIND = 16,
REBIND = 17,
UNBIND = 18,
ACL = 19,
REPORT = 20,
MKACTIVITY = 21,
CHECKOUT = 22,
MERGE = 23,
MSEARCH = 24,
NOTIFY = 25,
SUBSCRIBE = 26,
UNSUBSCRIBE = 27,
PATCH = 28,
PURGE = 29,
MKCALENDAR = 30,
LINK = 31,
UNLINK = 32,
SOURCE = 33;
static String methodToString(int method) {
switch (method) {
case DELETE:
return 'DELETE';
case GET:
return 'GET';
case HEAD:
return 'HEAD';
case POST:
return 'POST';
case PUT:
return 'PUT';
case CONNECT:
return 'CONNECT';
case OPTIONS:
return 'OPTIONS';
case PATCH:
return 'PATCH';
case PURGE:
return 'PURGE';
default:
throw new ArgumentError('Unknown method $method.');
}
}
static Future<WingsRequestContext> from(Angel app, WingsClientSocket socket) {
2019-05-01 04:29:21 +00:00
// var state = _ParseState.url;
2019-04-29 08:22:36 +00:00
var c = Completer<WingsRequestContext>();
var recv = RawReceivePort();
var rq = WingsRequestContext._(app, socket, recv);
rq._remoteAddress = socket.remoteAddress;
2019-05-01 04:29:21 +00:00
var ct = StreamController();
recv.handler = ct.add;
recv.handler = (ee) {
if (ee is Uint8List) {
if (!rq._body.isClosed) rq._body.add(ee);
} else if (ee is List) {
var type = ee[0] as int;
if (type == 2) {
rq._method = methodToString(ee[1] as int);
2019-04-29 08:22:36 +00:00
} else {
2019-05-01 04:29:21 +00:00
var value = ee[1] as String;
if (type == 0) {
rq._uri = Uri.parse(value);
var path = rq._uri.path.replaceAll(_straySlashes, '');
if (path.isEmpty) path = '/';
rq._path = path;
} else if (type == 1) {
var k = value, v = ee[2] as String;
if (k == 'cookie') {
rq.__cookies.add(Cookie.fromSetCookieValue(v));
2019-04-29 08:22:36 +00:00
} else {
2019-05-01 04:29:21 +00:00
rq._headers.add(k, v);
2019-04-29 08:22:36 +00:00
}
2019-05-01 04:29:21 +00:00
} else {
// print("h: $ee');");
2019-04-29 08:22:36 +00:00
}
}
2019-05-01 04:29:21 +00:00
} else if (ee == 100) {
// Headers done, just listen for body.
2019-04-29 08:22:36 +00:00
c.complete(rq);
2019-05-01 04:29:21 +00:00
} else if (ee == 200) {
// Message complete.
rq._body.close();
2019-04-29 08:22:36 +00:00
}
2019-05-01 04:29:21 +00:00
// if (state == _ParseState.url) {
// rq._uri = Uri.parse(e as String);
// var path = rq._uri.path.replaceAll(_straySlashes, '');
// if (path.isEmpty) path = '/';
// rq._path = path;
// state = _ParseState.headerField;
// } else if (state == _ParseState.headerField) {
// if (e == 0) {
// state = _ParseState.method;
// } else {
// lastHeader = e as String; //Uri.decodeFull(e as String);
// state = _ParseState.headerValue;
// }
// } else if (state == _ParseState.headerValue) {
// if (e == 0) {
// state = _ParseState.method;
// } else {
// var value = e as String; //Uri.decodeFull(e as String);
// if (lastHeader != null) {
// if (lastHeader == 'cookie') {
// rq.__cookies.add(Cookie.fromSetCookieValue(value));
// } else {
// rq._headers.add(lastHeader, value);
// }
// lastHeader = null;
// }
// }
// state = _ParseState.headerField;
// } else if (state == _ParseState.method) {
// rq._method = methodToString(e as int);
// state = _ParseState.body;
// c.complete(rq);
// } else if (state == _ParseState.body) {
// if (e == 1) {
// rq._body.close();
// } else {
// rq._body.add(e as List<int>);
// }
// }
2019-04-29 08:22:36 +00:00
};
wingsParseHttp().send([recv.sendPort, socket.fileDescriptor]);
return c.future;
}
2018-07-03 23:16:29 +00:00
@override
2019-04-29 08:22:36 +00:00
Stream<List<int>> get body => _body.stream;
2018-07-03 23:16:29 +00:00
@override
2019-04-29 08:22:36 +00:00
List<Cookie> get cookies => _cookies ??= List.unmodifiable(__cookies);
2018-07-03 23:16:29 +00:00
@override
2019-04-29 08:22:36 +00:00
HttpHeaders get headers => _headers;
2018-07-03 23:16:29 +00:00
@override
2019-04-29 08:22:36 +00:00
String get hostname => headers.value('host');
2018-07-03 23:16:29 +00:00
@override
2019-04-29 08:22:36 +00:00
String get method => _override ??=
(headers.value('x-http-method-override')?.toUpperCase() ?? _method);
2018-07-03 23:16:29 +00:00
@override
2019-04-29 08:22:36 +00:00
String get originalMethod => _method;
2018-07-03 23:16:29 +00:00
@override
2019-04-29 08:22:36 +00:00
String get path => _path;
2018-07-03 23:16:29 +00:00
@override
2019-04-29 08:22:36 +00:00
InternetAddress get remoteAddress => _remoteAddress;
2018-07-03 23:16:29 +00:00
@override
// TODO: implement session
HttpSession get session => null;
2018-07-03 23:16:29 +00:00
@override
2019-04-29 08:22:36 +00:00
Uri get uri => _uri;
2018-07-03 23:16:29 +00:00
}