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;
}