async public Task handleRequest(HttpContext httpContext) { if (Introspection && httpContext.Request.Path == "/ast.json" && httpContext.Request.Method.ToUpperInvariant() == "GET") { await httpContext.Response.WriteAsync(Api.GetAstJson()); return; } Context? context = null; JsonDocument?bodyDocument = null; var stopWatch = new Stopwatch(); stopWatch.Start(); try { StringValues origin; if (DynamicCorsOrigin && httpContext.Request.Headers.TryGetValue("origin", out origin)) { httpContext.Response.Headers.Add("Access-Control-Allow-Origin", origin); httpContext.Response.Headers.Add("Vary", "Origin"); } string method = httpContext.Request.Method.ToUpperInvariant(); foreach (var header in Headers) { if (method == "OPTIONS" && !header.Key.ToLowerInvariant().StartsWith("access-control-")) { continue; } httpContext.Response.Headers.Add(header.Key, header.Value); } if (method == "OPTIONS") { return; } httpContext.Response.Headers.Add("Content-Type", "application/json; charset=utf-8"); if (method == "HEAD") { return; } if (method == "GET") { if (httpContext.Request.Path.Value != "/") { httpContext.Response.StatusCode = 404; return; } var ok = false; try { ok = await OnHealthCheck(); } catch (Exception) { } httpContext.Response.StatusCode = ok ? 200 : 500; await httpContext.Response.WriteAsync(ok? "{\"ok\":true}" : "{\"ok\":false}"); return; } if (method != "POST") { httpContext.Response.StatusCode = 404; return; } bodyDocument = await JsonDocument.ParseAsync(httpContext.Request.Body); context = ContextParser.DecodeContext(bodyDocument.RootElement, "body"); context.Headers = httpContext.Request.Headers; // TODO: X-Forwarded-For with trusted proxies context.Ip = httpContext.Connection.RemoteIpAddress.ToString(); var duration = stopWatch.Elapsed.TotalSeconds; var bufferWriter = new ArrayBufferWriter <byte>(); using (var resultWriter = new Utf8JsonWriter(bufferWriter)) { resultWriter.WriteStartObject(); resultWriter.WritePropertyName("result"); await Api.ExecuteFunction(context, resultWriter); resultWriter.WriteNull("error"); resultWriter.WriteNumber("duration", duration); resultWriter.WriteString("host", Dns.GetHostName()); resultWriter.WriteEndObject(); } Console.WriteLine($"{context.Id} [{duration.ToString("0.000000")}s] {context.Name}() -> OK"); await httpContext.Response.WriteAsync(Encoding.UTF8.GetString(bufferWriter.WrittenSpan)); } catch (Exception error) { Console.WriteLine(error.ToString()); SdkgenException sdkgenError; if (error is SdkgenException) { sdkgenError = (error as SdkgenException) !; } else { sdkgenError = new SdkgenException("Fatal", error.Message, error); } var duration = stopWatch.Elapsed.TotalSeconds; if (OnRequestError != null && context != null) { OnRequestError.Invoke(context, sdkgenError); Console.WriteLine($"{context.Id} [{duration.ToString("0.000000")}s] {context.Name}() -> {sdkgenError.Type}"); } httpContext.Response.StatusCode = sdkgenError.Type == "Fatal" ? 500 : 400; using (var resultWriter = new Utf8JsonWriter(httpContext.Response.Body)) { resultWriter.WriteStartObject(); resultWriter.WriteNull("result"); resultWriter.WriteStartObject("error"); resultWriter.WriteString("type", sdkgenError.Type); resultWriter.WriteString("message", sdkgenError.Message); resultWriter.WriteEndObject(); resultWriter.WriteNumber("duration", duration); resultWriter.WriteString("host", Dns.GetHostName()); resultWriter.WriteEndObject(); } } finally { bodyDocument?.Dispose(); } }