platform/packages/wings/lib/src/wings_request.dart
Tobe O 13e863f295 Add 'packages/wings/' from commit '361e7e5f4a3ec6463f0348bdc8eb0a3b7549340a'
git-subtree-dir: packages/wings
git-subtree-mainline: 61c716502b
git-subtree-split: 361e7e5f4a
2020-02-16 12:21:46 -05:00

215 lines
5.7 KiB
Dart

import 'dart:async';
import 'dart:io';
import 'dart:isolate';
import 'dart:typed_data';
import 'package:angel_container/angel_container.dart';
import 'package:angel_framework/angel_framework.dart';
import 'package:mock_request/mock_request.dart';
import 'wings_socket.dart';
enum _ParseState { method, url, headerField, headerValue, body }
final RegExp _straySlashes = 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;
@override
Angel app;
WingsRequestContext._(this.app, this.rawRequest, this._recv)
: container = app.container.createChild();
Future<void> close() async {
await _body.close();
_recv.close();
await super.close();
}
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 ArgumentError('Unknown method $method.');
}
}
static Future<WingsRequestContext> from(Angel app, WingsClientSocket socket) {
// var state = _ParseState.url;
var c = Completer<WingsRequestContext>();
var recv = RawReceivePort();
var rq = WingsRequestContext._(app, socket, recv);
rq._remoteAddress = socket.remoteAddress;
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);
} else {
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));
} else {
rq._headers.add(k, v);
}
} else {
// print("h: $ee');");
}
}
} else if (ee == 100) {
// Headers done, just listen for body.
c.complete(rq);
} else if (ee == 200) {
// Message complete.
rq._body.close();
}
// 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>);
// }
// }
};
wingsParseHttp().send([recv.sendPort, socket.fileDescriptor]);
return c.future;
}
@override
Stream<List<int>> get body => _body.stream;
@override
List<Cookie> get cookies => _cookies ??= List.unmodifiable(__cookies);
@override
HttpHeaders get headers => _headers;
@override
String get hostname => headers.value('host');
@override
String get method => _override ??=
(headers.value('x-http-method-override')?.toUpperCase() ?? _method);
@override
String get originalMethod => _method;
@override
String get path => _path;
@override
InternetAddress get remoteAddress => _remoteAddress;
@override
// TODO: implement session
HttpSession get session => null;
@override
Uri get uri => _uri;
}