diff --git a/src/Ch17/QUICConsole/Program.cs b/src/Ch17/QUICConsole/Program.cs
new file mode 100644
index 00000000..6a28d598
--- /dev/null
+++ b/src/Ch17/QUICConsole/Program.cs
@@ -0,0 +1,17 @@
+using System.Net;
+
+using var client = new HttpClient();
+client.DefaultRequestVersion = HttpVersion.Version30;
+
+Console.WriteLine("--- localhost:5001 ---");
+
+// The client falls back to HTTP2 or HTTP1 if HTTP3 is not supported
+client.DefaultVersionPolicy = HttpVersionPolicy.RequestVersionExact;
+
+// Will use HTTP3 if the server supports it
+var resp = await client.GetAsync("https://localhost:5001/");
+string body = await resp.Content.ReadAsStringAsync();
+
+Console.WriteLine(
+ $"status: {resp.StatusCode}, version: {resp.Version}, " +
+ $"body: {body.Substring(0, Math.Min(100, body.Length))}");
\ No newline at end of file
diff --git a/src/Ch17/QUICConsole/QUICConsole.csproj b/src/Ch17/QUICConsole/QUICConsole.csproj
new file mode 100644
index 00000000..93d83c1d
--- /dev/null
+++ b/src/Ch17/QUICConsole/QUICConsole.csproj
@@ -0,0 +1,16 @@
+
+
+
+ Exe
+ net9.0
+ latest
+ enable
+ enable
+
+
+
+
+
+
+
diff --git "a/src/Ch17/QUICServer/C:\\logs/w3clog-20241215.0000.txt" "b/src/Ch17/QUICServer/C:\\logs/w3clog-20241215.0000.txt"
new file mode 100644
index 00000000..32a35e60
--- /dev/null
+++ "b/src/Ch17/QUICServer/C:\\logs/w3clog-20241215.0000.txt"
@@ -0,0 +1,6 @@
+#Version: 1.0
+#Start-Date: 2024-12-15 19:52:19
+#Fields: date time c-ip cs-username s-computername s-ip s-port cs-method cs-uri-stem cs-uri-query sc-status time-taken cs-version cs-host cs(User-Agent) cs(Cookie) cs(Referer)
+2024-12-15 19:52:18 ::1 - Chriss-Mac-Studio ::1 5001 GET / - 200 6.6914 HTTP/2 localhost:5001 Mozilla/5.0+(Macintosh;+Intel+Mac+OS+X+10_15_7)+AppleWebKit/537.36+(KHTML,+like+Gecko)+Chrome/131.0.0.0+Safari/537.36 _ga=GA1.1.576880434.1730288122;+_ga_VJEMRLLXJN=GS1.1.1730410342.6.1.1730410458.0.0.0 -
+2024-12-15 19:52:18 ::1 - Chriss-Mac-Studio ::1 5001 GET /favicon.ico - 404 0.1531 HTTP/2 localhost:5001 Mozilla/5.0+(Macintosh;+Intel+Mac+OS+X+10_15_7)+AppleWebKit/537.36+(KHTML,+like+Gecko)+Chrome/131.0.0.0+Safari/537.36 _ga=GA1.1.576880434.1730288122;+_ga_VJEMRLLXJN=GS1.1.1730410342.6.1.1730410458.0.0.0 https://localhost:5001/
+2024-12-15 19:52:29 ::1 - Chriss-Mac-Studio ::1 5001 GET / - 200 0.1208 HTTP/2 localhost:5001 Mozilla/5.0+(Macintosh;+Intel+Mac+OS+X+10_15_7)+AppleWebKit/537.36+(KHTML,+like+Gecko)+Chrome/131.0.0.0+Safari/537.36 _ga=GA1.1.576880434.1730288122;+_ga_VJEMRLLXJN=GS1.1.1730410342.6.1.1730410458.0.0.0 -
diff --git a/src/Ch17/QUICServer/Program.cs b/src/Ch17/QUICServer/Program.cs
new file mode 100755
index 00000000..4cb25d5e
--- /dev/null
+++ b/src/Ch17/QUICServer/Program.cs
@@ -0,0 +1,26 @@
+using System.Security.Cryptography.X509Certificates;
+using Microsoft.AspNetCore.Server.Kestrel.Core;
+using Microsoft.AspNetCore.Server.Kestrel.Https;
+
+var builder = WebApplication.CreateBuilder(args);
+
+var cert = CertificateLoader.LoadFromStoreCert("localhost", StoreName.My.ToString(), StoreLocation.CurrentUser, false);
+
+builder.WebHost.ConfigureKestrel(options =>
+{
+ options.ListenAnyIP(5001, listenOptions =>
+ {
+ listenOptions.UseConnectionLogging();
+ listenOptions.Protocols = HttpProtocols.Http1AndHttp2AndHttp3;
+ listenOptions.UseHttps(httpsOptions =>
+ {
+ httpsOptions.ServerCertificateSelector = (context, host) => cert;
+ });
+ });
+});
+
+var app = builder.Build();
+
+app.MapGet("/", () => "Hello, QUIC!");
+
+app.Run();
\ No newline at end of file
diff --git a/src/Ch17/QUICServer/Properties/launchSettings.json b/src/Ch17/QUICServer/Properties/launchSettings.json
new file mode 100644
index 00000000..51c0a732
--- /dev/null
+++ b/src/Ch17/QUICServer/Properties/launchSettings.json
@@ -0,0 +1,14 @@
+{
+ "$schema": "https://json.schemastore.org/launchsettings.json",
+ "profiles": {
+ "https": {
+ "commandName": "Project",
+ "dotnetRunMessages": true,
+ "launchBrowser": true,
+ "applicationUrl": "https://localhost:5001;http://localhost:5000",
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ }
+ }
+ }
+}
diff --git a/src/Ch17/QUICServer/QUICServer.csproj b/src/Ch17/QUICServer/QUICServer.csproj
new file mode 100644
index 00000000..a8f963d9
--- /dev/null
+++ b/src/Ch17/QUICServer/QUICServer.csproj
@@ -0,0 +1,10 @@
+
+
+
+ net9.0
+ enable
+ enable
+ True
+
+
+
diff --git a/src/Ch17/QUICServer/appsettings.Development.json b/src/Ch17/QUICServer/appsettings.Development.json
new file mode 100644
index 00000000..0c208ae9
--- /dev/null
+++ b/src/Ch17/QUICServer/appsettings.Development.json
@@ -0,0 +1,8 @@
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft.AspNetCore": "Warning"
+ }
+ }
+}
diff --git a/src/Ch17/QUICServer/appsettings.json b/src/Ch17/QUICServer/appsettings.json
new file mode 100644
index 00000000..23a36b12
--- /dev/null
+++ b/src/Ch17/QUICServer/appsettings.json
@@ -0,0 +1,11 @@
+{
+ "DetailedErrors": true,
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft.AspNetCore": "Warning",
+ "Microsoft.AspNetCore.Hosting.Diagnostics": "Information"
+ }
+ },
+ "AllowedHosts": "*"
+}
diff --git a/src/Ch17/ch17.sln b/src/Ch17/ch17.sln
index a55ff74c..4a7ee6ff 100644
--- a/src/Ch17/ch17.sln
+++ b/src/Ch17/ch17.sln
@@ -1,8 +1,22 @@
Microsoft Visual Studio Solution File, Format Version 12.00
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "QUICServer", "QUICServer\QUICServer.csproj", "{86A3638C-CB35-4EA5-A21D-DC7A6A17E8F6}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "QUICConsole", "QUICConsole\QUICConsole.csproj", "{86478148-88AB-4C71-A0DE-42BAB0BF2BB8}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {86A3638C-CB35-4EA5-A21D-DC7A6A17E8F6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {86A3638C-CB35-4EA5-A21D-DC7A6A17E8F6}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {86A3638C-CB35-4EA5-A21D-DC7A6A17E8F6}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {86A3638C-CB35-4EA5-A21D-DC7A6A17E8F6}.Release|Any CPU.Build.0 = Release|Any CPU
+ {86478148-88AB-4C71-A0DE-42BAB0BF2BB8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {86478148-88AB-4C71-A0DE-42BAB0BF2BB8}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {86478148-88AB-4C71-A0DE-42BAB0BF2BB8}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {86478148-88AB-4C71-A0DE-42BAB0BF2BB8}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
EndGlobal