Personal website
1/*
2 This file is part of NKK.
3
4 NKK is free software: you can redistribute it and/or modify it under the
5 terms of the GNU Affero General Public License as published by the Free
6 Software Foundation, either version 3 of the License, or (at your option)
7 any later version.
8
9 NKK is distributed in the hope that it will be useful, but WITHOUT ANY
10 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11 FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
12 more details.
13
14 You should have received a copy of the GNU Affero General Public License
15 along with NKK. If not, see <http://www.gnu.org/licenses/>.
16*/
17
18using System.IO.Compression;
19using System.Text;
20using NKK.Components;
21using Microsoft.AspNetCore.ResponseCompression;
22using NKK;
23
24var builder = WebApplication.CreateBuilder(new WebApplicationOptions() {
25 Args = args,
26 WebRootPath = "public"
27});
28
29// Add services to the container.
30builder.Services.AddRazorComponents();
31builder.Services.AddResponseCompression(options => {
32 options.EnableForHttps = true;
33 options.Providers.Add<BrotliCompressionProvider>();
34 options.Providers.Add<GzipCompressionProvider>();
35 options.MimeTypes = ResponseCompressionDefaults.MimeTypes;
36} );
37builder.Services.Configure<BrotliCompressionProviderOptions>(options => {
38 options.Level = CompressionLevel.SmallestSize;
39});
40
41builder.Services.Configure<GzipCompressionProviderOptions>(options => {
42 options.Level = CompressionLevel.SmallestSize;
43});
44
45var app = builder.Build();
46
47// Configure the HTTP request pipeline.
48if (!app.Environment.IsDevelopment()) {
49 app.UseExceptionHandler("/Error", createScopeForErrors: true);
50 // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
51 app.UseHsts();
52}
53
54app.UseStatusCodePagesWithReExecute("/not-found", createScopeForStatusCodePages: true);
55app.UseHttpsRedirection();
56
57app.UseAntiforgery();
58app.UseResponseCompression();
59app.Use(async (context, next) => {
60 // context.Response.Body is a direct line to the client, so
61 // swap it out for our own in-memory stream for now
62 Stream responseStream = context.Response.Body;
63 using var memoryStream = new MemoryStream();
64 context.Response.Body = memoryStream;
65
66 // let downstream render the response & write to our stream
67 await next(context);
68
69 if (context.Response.ContentType?.StartsWith("text/html") != true) {
70 // oops my bad gangalang
71 // ok now put it back
72 memoryStream.Position = 0;
73 await memoryStream.CopyToAsync(responseStream);
74 context.Response.Body = responseStream;
75
76 return;
77 }
78
79 memoryStream.Position = 0;
80 String html = await new StreamReader(memoryStream).ReadToEndAsync();
81 String minified = Utils.OptimizeHtml(html);
82
83 context.Response.ContentLength = Encoding.UTF8.GetByteCount(minified);
84 await responseStream.WriteAsync(Encoding.UTF8.GetBytes(minified));
85 context.Response.Body = responseStream;
86});
87
88app.UseStaticFiles();
89app.MapRazorComponents<App>();
90
91app.Run();