handleRawRequest method

Future handleRawRequest(
  1. Request request,
  2. Response response
)

Handles a single request.

Implementation

Future handleRawRequest(Request request, Response response) {
  app.logger.info('[Server] Called handleRawRequest');

  return createRequestContext(request, response).then((req) {
    return createResponseContext(request, response, req).then((res) {
      Future handle() {
        var path = req.path;
        if (path == '/') path = '';

        Tuple4<
          List,
          Map<String, dynamic>,
          ParseResult<RouteResult>,
          MiddlewarePipeline
        >
        resolveTuple() {
          var r = app.optimizedRouter;
          var resolved = r.resolveAbsolute(
            path,
            method: req.method,
            strip: false,
          );
          var pipeline = MiddlewarePipeline<RequestHandler>(resolved);
          return Tuple4(
            pipeline.handlers,
            resolved.fold<Map<String, dynamic>>(
              <String, dynamic>{},
              (out, r) => out..addAll(r.allParams),
            ),
            //(resolved.isEmpty ? null : resolved.first.parseResult),
            resolved.first.parseResult,
            pipeline,
          );
        }

        var cacheKey = req.method + path;
        var tuple = app.environment.isProduction
            ? app.handlerCache.putIfAbsent(cacheKey, resolveTuple)
            : resolveTuple();
        var line = tuple.item4 as MiddlewarePipeline<RequestHandler>;
        var it = MiddlewarePipelineIterator<RequestHandler>(line);

        req.params.addAll(tuple.item2);

        req.container
          ?..registerSingleton<RequestContext>(req)
          ..registerSingleton<ResponseContext>(res)
          ..registerSingleton<MiddlewarePipeline>(tuple.item4)
          ..registerSingleton<MiddlewarePipeline<RequestHandler>>(line)
          ..registerSingleton<MiddlewarePipelineIterator>(it)
          ..registerSingleton<MiddlewarePipelineIterator<RequestHandler>>(it)
          ..registerSingleton<ParseResult<RouteResult>?>(tuple.item3)
          ..registerSingleton<ParseResult?>(tuple.item3);

        if (!app.environment.isProduction) {
          req.container?.registerSingleton<Stopwatch>(Stopwatch()..start());
        }

        return runPipeline(
          it,
          req,
          res,
          app,
        ).then((_) => sendResponse(request, response, req, res));
      }

      if (useZone == false) {
        Future f;

        try {
          f = handle();
        } catch (e, st) {
          f = Future.error(e, st);
        }

        return f
            .catchError((e, StackTrace st) {
              if (e is FormatException) {
                throw AngelHttpException.badRequest(message: e.message)
                  ..stackTrace = st;
              }
              throw AngelHttpException(
                stackTrace: st,
                statusCode: (e is AngelHttpException) ? e.statusCode : 500,
                message: e?.toString() ?? '500 Internal Server Error',
              );
            }, test: (e) => e is AngelHttpException)
            .catchError((ee, StackTrace st) {
              //print(">>>> Framework error: $ee");
              //var t = (st).runtimeType;
              //print(">>>> StackTrace: $t");
              AngelHttpException e;
              if (ee is AngelHttpException) {
                e = ee;
              } else {
                e = AngelHttpException(
                  stackTrace: st,
                  statusCode: 500,
                  message: ee?.toString() ?? '500 Internal Server Error',
                );
              }

              var error = e.error ?? e;
              var trace = Trace.from(StackTrace.current).terse;
              app.logger.severe(e.message, error, trace);

              return handleAngelHttpException(
                e,
                st,
                req,
                res,
                request,
                response,
              );
            });
      } else {
        var zoneSpec = ZoneSpecification(
          print: (self, parent, zone, line) {
            app.logger.info(line);
          },
          handleUncaughtError: (self, parent, zone, error, stackTrace) {
            var trace = Trace.from(stackTrace).terse;

            // TODO: To be revisited
            Future(() {
              AngelHttpException e;

              if (error is FormatException) {
                e = AngelHttpException.badRequest(message: error.message);
              } else if (error is AngelHttpException) {
                e = error;
              } else {
                e = AngelHttpException(
                  stackTrace: stackTrace,
                  message: error.toString(),
                );
              }

              app.logger.severe(e.message, error, trace);

              return handleAngelHttpException(
                e,
                trace,
                req,
                res,
                request,
                response,
              );
            }).catchError((e, StackTrace st) {
              var trace = Trace.from(st).terse;
              closeResponse(response);
              // Ideally, we won't be in a position where an absolutely fatal error occurs,
              // but if so, we'll need to log it.
              app.logger.severe(
                'Fatal error occurred when processing $uri.',
                e,
                trace,
              );
            });
          },
        );

        var zone = Zone.current.fork(specification: zoneSpec);
        req.container?.registerSingleton<Zone>(zone);
        req.container?.registerSingleton<ZoneSpecification>(zoneSpec);

        // If a synchronous error is thrown, it's not caught by `zone.run`,
        // so use a try/catch, and recover when need be.

        try {
          return zone.run(handle);
        } catch (e, st) {
          zone.handleUncaughtError(e, st);
          return Future.value();
        }
      }
    });
  });
}