public static Task SendDownstreamResponse(HttpRequest request, UpstreamResponse upstreamResponse, HttpResponse response, bool cached) { response.StatusCode = upstreamResponse.StatusCode; foreach (var header in upstreamResponse.Headers) { // For cached responses, copy the client-request-id header from request since client requires these to match if (cached && header.Key == "x-ms-client-request-id") { response.Headers.Add(header.Key, request.Headers[header.Key]); } else { response.Headers.Add(header.Key, header.Value); } } return(response.Body.WriteAsync(upstreamResponse.Content, 0, upstreamResponse.Content.Length)); }
static void Run() { Console.WriteLine("=== Options ==="); Console.WriteLine(JsonSerializer.Serialize(Options, Options.GetType(), new JsonSerializerOptions() { WriteIndented = true, })); Console.WriteLine(); var allHeaders = Options.Headers.Concat(ServiceHeaders.Get(Options.Service)); Console.WriteLine("=== Headers ==="); foreach (var header in allHeaders) { Console.WriteLine(header); } Console.WriteLine(); Console.WriteLine("=== Startup ==="); new WebHostBuilder() .UseKestrel(options => { options.Listen(IPAddress.Any, 7777); options.Listen(IPAddress.Any, 7778, listenOptions => { listenOptions.UseHttps("testCert.pfx", "testPassword"); }); }) .UseContentRoot(Directory.GetCurrentDirectory()) .Configure(app => app.Run(async context => { try { var request = context.Request; var response = context.Response; if (Options.Debug && request.Path.Value == "/debug") { if (Options.Dots) { Console.Write("#"); } var buffer = Encoding.UTF8.GetBytes("debug"); await response.Body.WriteAsync(buffer, 0, buffer.Length); return; } var key = new RequestCacheKey(request, allHeaders); if (_cache.TryGetValue(key, out var upstreamResponse)) { if (Options.Dots) { Console.Write("."); } if (Options.CacheLast) { _lastUpstreamResponse = upstreamResponse; } await Proxy.SendDownstreamResponse(request, upstreamResponse, response, cached: true); } else if (Options.CacheLast && request.Path.Value == "/last") { if (Options.Dots) { Console.Write("@"); } // Used for perf testing the cache lookup and downstream response generation. This allows a perf client like // "wrk" to directly request the last response without using the server as an HTTP proxy, since "wrk" is much // slower when using a proxy (50k vs 6k RPS). await Proxy.SendDownstreamResponse(request, _lastUpstreamResponse, response, cached: true); } else { if (Options.Dots) { Console.Write("*"); } upstreamResponse = await Proxy.SendUpstreamRequest(request); await Proxy.SendDownstreamResponse(request, upstreamResponse, response, cached: false); _cache.AddOrUpdate(key, upstreamResponse, (k, r) => upstreamResponse); if (Options.CacheLast) { _lastUpstreamResponse = upstreamResponse; } } } catch (Exception e) { Console.WriteLine(e); } })) .Build() .Run(); }