from static method

Future<Http2RequestContext> from(
  1. ServerTransportStream stream,
  2. Socket socket,
  3. Angel app,
  4. Map<String, MockHttpSession> sessions,
  5. Uuid uuid,
)

Implementation

static Future<Http2RequestContext> from(
    ServerTransportStream stream,
    Socket socket,
    Angel app,
    Map<String, MockHttpSession> sessions,
    Uuid uuid) {
  var c = Completer<Http2RequestContext>();
  var req = Http2RequestContext._(app.container!.createChild())
    ..app = app
    .._socket = socket
    .._stream = stream;

  var headers = req._headers = MockHttpHeaders();
  // String scheme = 'https', host = socket.address.address, path = '';
  var uri =
      Uri(scheme: 'https', host: socket.address.address, port: socket.port);
  var cookies = <Cookie>[];

  void finalize() {
    req
      .._cookies = List.unmodifiable(cookies)
      .._uri = uri;
    if (!c.isCompleted) c.complete(req);
  }

  void parseHost(String value) {
    var inUri = Uri.tryParse(value);
    if (inUri == null) return;
    // if (uri == null || uri.scheme == 'localhost') return;

    if (inUri.hasScheme) uri = uri.replace(scheme: inUri.scheme);

    if (inUri.hasAuthority) {
      uri = uri.replace(host: inUri.host, userInfo: inUri.userInfo);
    }

    if (inUri.hasPort) uri = uri.replace(port: inUri.port);
  }

  stream.incomingMessages.listen((msg) {
    if (msg is DataStreamMessage) {
      finalize();
      req._body.add(msg.bytes);
    } else if (msg is HeadersStreamMessage) {
      for (var header in msg.headers) {
        var name = ascii.decode(header.name).toLowerCase();
        var value = Uri.decodeComponent(ascii.decode(header.value));

        switch (name) {
          case ':method':
            req._method = value;
            break;
          case ':path':
            var inUri = Uri.parse(value);
            uri = uri.replace(path: inUri.path);
            if (inUri.hasQuery) uri = uri.replace(query: inUri.query);
            var path = uri.path.replaceAll(_straySlashes, '');
            req._path = path;
            if (path.isEmpty) req._path = '/';
            break;
          case ':scheme':
            uri = uri.replace(scheme: value);
            break;
          case ':authority':
            parseHost(value);
            break;
          case 'cookie':
            var cookieStrings = value.split(';').map((s) => s.trim());

            for (var cookieString in cookieStrings) {
              try {
                cookies.add(Cookie.fromSetCookieValue(cookieString));
              } catch (_) {
                // Ignore malformed cookies, and just don't add them to the container.
              }
            }
            break;
          default:
            var name = ascii.decode(header.name).toLowerCase();

            if (name == 'host') {
              parseHost(value);
            }

            headers.add(name, value.split(_comma));
            break;
        }
      }

      if (msg.endStream) finalize();
    }
  }, onDone: () {
    finalize();
    req._body.close();
  }, cancelOnError: true, onError: c.completeError);

  // Apply session
  var dartSessId = cookies.firstWhereOrNull((c) => c.name == 'DARTSESSID');

  dartSessId ??= Cookie('DARTSESSID', uuid.v4());

  req._session = sessions.putIfAbsent(
    dartSessId.value,
    () => MockHttpSession(id: dartSessId!.value),
  );

  return c.future;
}