diff --git a/src/Microsoft.Tye.Hosting/HttpProxyService.cs b/src/Microsoft.Tye.Hosting/HttpProxyService.cs index 8b0b1386..12d2291d 100644 --- a/src/Microsoft.Tye.Hosting/HttpProxyService.cs +++ b/src/Microsoft.Tye.Hosting/HttpProxyService.cs @@ -154,7 +154,8 @@ namespace Microsoft.Tye.Hosting var uri = new UriBuilder(uris[next].Uri) { - Path = (string)context.Request.RouteValues["path"] + Path = (string)context.Request.RouteValues["path"], + Query = context.Request.QueryString.Value }; await context.ProxyRequest(invoker, uri.Uri); diff --git a/test/E2ETest/TyeRunTests.cs b/test/E2ETest/TyeRunTests.cs index 1f70d793..4db9d5e5 100644 --- a/test/E2ETest/TyeRunTests.cs +++ b/test/E2ETest/TyeRunTests.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System; +using System.Collections.Generic; using System.CommandLine.IO; using System.IO; using System.Linq; @@ -517,6 +518,39 @@ namespace E2ETest }); } + [Fact] + public async Task IngressQueryAndContentProxyingTest() + { + using var projectDirectory = CopyTestProjectDirectory("apps-with-ingress"); + + var projectFile = new FileInfo(Path.Combine(projectDirectory.DirectoryPath, "tye.yaml")); + var outputContext = new OutputContext(_sink, Verbosity.Debug); + var application = await ApplicationFactory.CreateAsync(outputContext, projectFile); + + var handler = new HttpClientHandler + { + ServerCertificateCustomValidationCallback = (a, b, c, d) => true, + AllowAutoRedirect = false + }; + + var client = new HttpClient(new RetryHandler(handler)); + + await RunHostingApplication(application, new HostOptions(), async (app, uri) => + { + var ingressUri = await GetServiceUrl(client, uri, "ingress"); + + var request = new HttpRequestMessage(HttpMethod.Post, ingressUri + "/A/data?key1=value1&key2=value2"); + request.Content = new StringContent("some content"); + + var response = await client.SendAsync(request); + var responseContent = + JsonSerializer.Deserialize>(await response.Content.ReadAsStringAsync()); + + Assert.Equal("some content", responseContent["content"]); + Assert.Equal("?key1=value1&key2=value2", responseContent["query"]); + }); + } + [ConditionalFact] [SkipIfDockerNotRunning] public async Task NginxIngressTest() diff --git a/test/E2ETest/testassets/projects/apps-with-ingress/ApplicationA/Startup.cs b/test/E2ETest/testassets/projects/apps-with-ingress/ApplicationA/Startup.cs index 257fd799..294319e4 100644 --- a/test/E2ETest/testassets/projects/apps-with-ingress/ApplicationA/Startup.cs +++ b/test/E2ETest/testassets/projects/apps-with-ingress/ApplicationA/Startup.cs @@ -1,7 +1,6 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; +using System.IO; +using System.Text.Json; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; @@ -34,6 +33,20 @@ namespace ApplicationA { await context.Response.WriteAsync("Hello from Application A " + Environment.GetEnvironmentVariable("APP_INSTANCE") ?? Environment.GetEnvironmentVariable("HOSTNAME")); }); + + // This method returns the body content and query string back to the caller, to test that the ingress passes those properly + endpoints.MapPost("/data", async context => + { + using var reader = new StreamReader(context.Request.Body); + var content = await reader.ReadToEndAsync(); + var query = context.Request.QueryString.Value; + + await context.Response.WriteAsync(JsonSerializer.Serialize(new + { + content, + query + })); + }); }); } } diff --git a/test/E2ETest/testassets/projects/apps-with-ingress/ApplicationB/Startup.cs b/test/E2ETest/testassets/projects/apps-with-ingress/ApplicationB/Startup.cs index 1a6b68d8..6dcc21ad 100644 --- a/test/E2ETest/testassets/projects/apps-with-ingress/ApplicationB/Startup.cs +++ b/test/E2ETest/testassets/projects/apps-with-ingress/ApplicationB/Startup.cs @@ -1,7 +1,6 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; +using System.IO; +using System.Text.Json; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; @@ -34,6 +33,20 @@ namespace ApplicationB { await context.Response.WriteAsync("Hello from Application B " + Environment.GetEnvironmentVariable("APP_INSTANCE") ?? Environment.GetEnvironmentVariable("HOSTNAME")); }); + + // This method returns the body content and query string back to the caller, to test that the ingress passes those properly + endpoints.MapPost("/data", async context => + { + using var reader = new StreamReader(context.Request.Body); + var content = await reader.ReadToEndAsync(); + var query = context.Request.QueryString.Value; + + await context.Response.WriteAsync(JsonSerializer.Serialize(new + { + content, + query + })); + }); }); } }