From 9a9ece64a518ea911de94ee802a848dc7e45f8e8 Mon Sep 17 00:00:00 2001
From: Sam Spencer <54915162+samsp-msft@users.noreply.github.com>
Date: Tue, 23 Feb 2021 13:09:25 -0800
Subject: [PATCH 1/3] Added readme, cleaned up existing code
---
.../Controllers/EchoController.cs | 63 +++++++++
.../Controllers/HealthController.cs | 2 +-
.../Controllers/HttpController.cs | 123 ------------------
.../Controllers/UpgradeController.cs | 70 ----------
samples/SampleServer/README.md | 28 ++++
5 files changed, 92 insertions(+), 194 deletions(-)
create mode 100644 samples/SampleServer/Controllers/EchoController.cs
delete mode 100644 samples/SampleServer/Controllers/HttpController.cs
delete mode 100644 samples/SampleServer/Controllers/UpgradeController.cs
create mode 100644 samples/SampleServer/README.md
diff --git a/samples/SampleServer/Controllers/EchoController.cs b/samples/SampleServer/Controllers/EchoController.cs
new file mode 100644
index 0000000..332dc96
--- /dev/null
+++ b/samples/SampleServer/Controllers/EchoController.cs
@@ -0,0 +1,63 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Mvc;
+
+namespace SampleServer.Controllers
+{
+ ///
+ /// Controller that will echo headers and send back specific codes for testing with
+ ///
+ [ApiController]
+ public class EchoController : ControllerBase
+ {
+ ///
+ /// Returns a 200 response dumping all info from the incoming request.
+ ///
+ [HttpGet, HttpPost]
+ [Route("/api/dump")]
+ [Route("/{**catchall}", Order = int.MaxValue)] // Make this the default route if nothing matches
+ public async Task Dump()
+ {
+ var result = new {
+ Request.Protocol,
+ Request.Method,
+ Request.Scheme,
+ Host = Request.Host.Value,
+ PathBase = Request.PathBase.Value,
+ Path = Request.Path.Value,
+ Query = Request.QueryString.Value,
+ Headers = Request.Headers.ToDictionary(kvp => kvp.Key, kvp => kvp.Value.ToArray()),
+ Time = DateTimeOffset.UtcNow,
+ Body = await new StreamReader(Request.Body).ReadToEndAsync(),
+ };
+
+ return Ok(result);
+ }
+
+ ///
+ /// Returns the specific status code specified
+ ///
+ [HttpGet]
+ [Route("/api/statuscode")]
+ public void Status(int statusCode)
+ {
+ Response.StatusCode = statusCode;
+ }
+
+ ///
+ /// Returns a 200 response.
+ ///
+ [HttpGet]
+ [Route("/api/noop")]
+ public void NoOp()
+ {
+ }
+
+ }
+}
diff --git a/samples/SampleServer/Controllers/HealthController.cs b/samples/SampleServer/Controllers/HealthController.cs
index a683a0e..1b34865 100644
--- a/samples/SampleServer/Controllers/HealthController.cs
+++ b/samples/SampleServer/Controllers/HealthController.cs
@@ -21,7 +21,7 @@ public IActionResult CheckHealth()
{
_count++;
// Simulate temporary health degradation.
- return _count % 10 < 4 ? Ok() : StatusCode(500);
+ return ((_count % 10) < 4) ? Ok() : StatusCode(500);
}
}
}
diff --git a/samples/SampleServer/Controllers/HttpController.cs b/samples/SampleServer/Controllers/HttpController.cs
deleted file mode 100644
index 575f662..0000000
--- a/samples/SampleServer/Controllers/HttpController.cs
+++ /dev/null
@@ -1,123 +0,0 @@
-// Copyright (c) Microsoft Corporation.
-// Licensed under the MIT License.
-
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Threading.Tasks;
-using Microsoft.AspNetCore.Mvc;
-
-namespace SampleServer.Controllers
-{
- ///
- /// Sample controller.
- ///
- [ApiController]
- public class HttpController : ControllerBase
- {
- ///
- /// Returns a 200 response.
- ///
- [HttpGet]
- [Route("/api/noop")]
- public void NoOp()
- {
- }
-
- ///
- /// Returns a 200 response dumping all info from the incoming request.
- ///
- [HttpGet, HttpPost]
- [Route("/api/dump")]
- [Route("/{**catchall}", Order = int.MaxValue)] // Make this the default route if nothing matches
- public async Task Dump()
- {
- var result = new {
- Request.Protocol,
- Request.Method,
- Request.Scheme,
- Host = Request.Host.Value,
- PathBase = Request.PathBase.Value,
- Path = Request.Path.Value,
- Query = Request.QueryString.Value,
- Headers = Request.Headers.ToDictionary(kvp => kvp.Key, kvp => kvp.Value.ToArray()),
- Time = DateTimeOffset.UtcNow,
- Body = await new StreamReader(Request.Body).ReadToEndAsync(),
- };
-
- return Ok(result);
- }
-
- ///
- /// Returns a 200 response dumping all info from the incoming request.
- ///
- [HttpGet]
- [Route("/api/statuscode")]
- public void Status(int statusCode)
- {
- Response.StatusCode = statusCode;
- }
-
- ///
- /// Returns a 200 response dumping all info from the incoming request.
- ///
- [HttpGet]
- [Route("/api/headers")]
- public void Headers([FromBody] Dictionary headers)
- {
- foreach (var (key, value) in headers)
- {
- Response.Headers.Add(key, value);
- }
- }
-
- ///
- /// Returns a 200 response after milliseconds
- /// and containing with bytes in the response body.
- ///
- [HttpGet]
- [HttpPut]
- [HttpPost]
- [HttpPatch]
- [Route("/api/stress")]
- public async Task Stress([FromQuery] int delay, [FromQuery] int responseSize)
- {
- var bodyReader = Request.BodyReader;
- if (bodyReader != null)
- {
- while (true)
- {
- var a = await Request.BodyReader.ReadAsync();
- if (a.IsCompleted)
- {
- break;
- }
- }
- }
-
- if (delay > 0)
- {
- await Task.Delay(delay);
- }
-
- var bodyWriter = Response.BodyWriter;
- if (bodyWriter != null && responseSize > 0)
- {
- const int WriteBufferSize = 4096;
-
- var remaining = responseSize;
- var buffer = new byte[WriteBufferSize];
-
- while (remaining > 0)
- {
- buffer[0] = (byte)(remaining * 17); // Make the output not all zeros
- var toWrite = Math.Min(buffer.Length, remaining);
- await bodyWriter.WriteAsync(new ReadOnlyMemory(buffer, 0, toWrite),
- HttpContext.RequestAborted);
- remaining -= toWrite;
- }
- }
- }
- }
-}
diff --git a/samples/SampleServer/Controllers/UpgradeController.cs b/samples/SampleServer/Controllers/UpgradeController.cs
deleted file mode 100644
index b963df8..0000000
--- a/samples/SampleServer/Controllers/UpgradeController.cs
+++ /dev/null
@@ -1,70 +0,0 @@
-// Copyright (c) Microsoft Corporation.
-// Licensed under the MIT License.
-
-using System.IO;
-using System.Threading.Tasks;
-using Microsoft.AspNetCore.Http;
-using Microsoft.AspNetCore.Http.Features;
-using Microsoft.AspNetCore.Mvc;
-using Microsoft.Extensions.Logging;
-
-namespace SampleServer.Controllers
-{
- ///
- /// Sample controller.
- ///
- [ApiController]
- public class UpgradeController : ControllerBase
- {
- private readonly ILogger _logger;
-
- ///
- /// Initializes a new instance of the class.
- ///
- public UpgradeController(ILogger logger)
- {
- _logger = logger;
- }
-
- ///
- /// Upgrades the connection to a raw socket stream, then implements a simple byte ping/pong server.
- /// Note that this does not use WebSockets, and relies solely on HTTP/1.1 connection upgrade mechanism.
- ///
- [HttpGet]
- [Route("/api/rawupgrade")]
- public async Task RawUpgrade()
- {
- var upgradeFeature = HttpContext.Features.Get();
- if (upgradeFeature == null || !upgradeFeature.IsUpgradableRequest)
- {
- HttpContext.Response.StatusCode = StatusCodes.Status426UpgradeRequired;
- return;
- }
-
- await using var stream = await upgradeFeature.UpgradeAsync();
- _logger.LogInformation("Upgraded connection.");
- await RunPingPongAsync(stream);
- _logger.LogInformation("Finished.");
- }
-
- ///
- /// Simple echo protocol that echo's each received byte.
- /// 255 is treated as a special "goodbye" message, which causes us to drop the connection.
- ///
- private async Task RunPingPongAsync(Stream stream)
- {
- var buffer = new byte[1];
- int read;
- while ((read = await stream.ReadAsync(buffer, HttpContext.RequestAborted)) != 0)
- {
- if (buffer[0] == 255)
- {
- // Goodbye
- break;
- }
-
- await stream.WriteAsync(buffer, 0, read);
- }
- }
- }
-}
diff --git a/samples/SampleServer/README.md b/samples/SampleServer/README.md
new file mode 100644
index 0000000..86d550e
--- /dev/null
+++ b/samples/SampleServer/README.md
@@ -0,0 +1,28 @@
+# Sample Server
+
+This is a simple web server implementation that can be used to test YARP proxy, by using it as the destination.
+
+Functionality in this sample server includes:
+
+### Echoing of Request Headers
+
+Provided that the request URI path doesn't match other endpoints described below, then the request headers will be reported back as text in the response body. This enables you to quickly see what headers were sent, for example to analyze header transforms made by the reverse proxy.
+
+
+### Healthcheck status endpoint
+
+[HealthController](Controllers/HealthController.cs) implements an API endpoint for /api/health that will randomly return bad health status.
+
+### WebSockets endpoint
+
+[WebSocketsController](Controllers/WebSocketsController.cs) implements an endpoint for testing web sockets at /api/websockets.
+
+
+## Usage
+
+To run the sample server use:
+- ```dotnet run``` from the sample folder
+- ```dotnet run SampleServer/SampleServer.csproj``` passing in the path to the .csproj file
+- Build an executable using ```dotnet build SampleServer.csproj``` and then run the executable directly
+
+The server will listen to http://localhost:5000 and https://localhost:5001 by default. The ports and interface can be changed using the urls option on the cmd line. For example ```dotnet run SampleServer/SampleServer.csproj --urls "https://localhost:10000;http://localhost:10010"```
From 6c5f83a25885bc34c2615e949221b7e1c4cc4c9d Mon Sep 17 00:00:00 2001
From: Sam Spencer <54915162+samsp-msft@users.noreply.github.com>
Date: Tue, 23 Feb 2021 16:40:38 -0800
Subject: [PATCH 2/3] removed urls from launchsettings
---
samples/SampleServer/Properties/launchSettings.json | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/samples/SampleServer/Properties/launchSettings.json b/samples/SampleServer/Properties/launchSettings.json
index 10caee0..4a363ab 100644
--- a/samples/SampleServer/Properties/launchSettings.json
+++ b/samples/SampleServer/Properties/launchSettings.json
@@ -5,8 +5,7 @@
"launchBrowser": false,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
- },
- "applicationUrl": "https://localhost:10000;https://localhost:10001;http://localhost:10010;http://localhost:10011"
+ }
}
}
}
From a7c38f16f0c2c4dc43d89358cf8ee99342759d38 Mon Sep 17 00:00:00 2001
From: Sam Spencer <54915162+samsp-msft@users.noreply.github.com>
Date: Wed, 24 Feb 2021 10:48:43 -0800
Subject: [PATCH 3/3] Delete EchoController.cs
---
.../Controllers/EchoController.cs | 63 -------------------
1 file changed, 63 deletions(-)
delete mode 100644 samples/SampleServer/Controllers/EchoController.cs
diff --git a/samples/SampleServer/Controllers/EchoController.cs b/samples/SampleServer/Controllers/EchoController.cs
deleted file mode 100644
index 332dc96..0000000
--- a/samples/SampleServer/Controllers/EchoController.cs
+++ /dev/null
@@ -1,63 +0,0 @@
-// Copyright (c) Microsoft Corporation.
-// Licensed under the MIT License.
-
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Threading.Tasks;
-using Microsoft.AspNetCore.Mvc;
-
-namespace SampleServer.Controllers
-{
- ///
- /// Controller that will echo headers and send back specific codes for testing with
- ///
- [ApiController]
- public class EchoController : ControllerBase
- {
- ///
- /// Returns a 200 response dumping all info from the incoming request.
- ///
- [HttpGet, HttpPost]
- [Route("/api/dump")]
- [Route("/{**catchall}", Order = int.MaxValue)] // Make this the default route if nothing matches
- public async Task Dump()
- {
- var result = new {
- Request.Protocol,
- Request.Method,
- Request.Scheme,
- Host = Request.Host.Value,
- PathBase = Request.PathBase.Value,
- Path = Request.Path.Value,
- Query = Request.QueryString.Value,
- Headers = Request.Headers.ToDictionary(kvp => kvp.Key, kvp => kvp.Value.ToArray()),
- Time = DateTimeOffset.UtcNow,
- Body = await new StreamReader(Request.Body).ReadToEndAsync(),
- };
-
- return Ok(result);
- }
-
- ///
- /// Returns the specific status code specified
- ///
- [HttpGet]
- [Route("/api/statuscode")]
- public void Status(int statusCode)
- {
- Response.StatusCode = statusCode;
- }
-
- ///
- /// Returns a 200 response.
- ///
- [HttpGet]
- [Route("/api/noop")]
- public void NoOp()
- {
- }
-
- }
-}