-
Notifications
You must be signed in to change notification settings - Fork 0
/
HttpServer.cs
119 lines (95 loc) · 2.63 KB
/
HttpServer.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
using System.Diagnostics;
using System.Net;
using System.Net.Sockets;
namespace Httpd.Impl;
public class HttpServer
{
private IPEndPoint _endpoint;
private Socket _socket;
public HttpServer(int port = 2323)
{
_endpoint = new IPEndPoint(IPAddress.IPv6Any, port);
}
public ValueTask Start()
{
_socket = new Socket(AddressFamily.InterNetworkV6, SocketType.Stream, ProtocolType.Tcp);
_socket.Bind(_endpoint);
_socket.Listen(10);
_ = Task.Run(async () =>
{
while (_socket != null)
{
try
{
var client = await _socket.AcceptAsync();
_ = Task.Run(async () => await EndAccept(client));
}
catch (Exception ex)
{
Debug.WriteLine(ex);
}
await Task.Delay(16);
}
});
return ValueTask.CompletedTask;
}
public ValueTask Stop()
{
_socket?.Dispose();
_socket = default;
return ValueTask.CompletedTask;
}
async Task EndAccept(Socket client)
{
using (var ctx = new HttpContext(client))
{
var res = ctx.Response;
try
{
await ctx.ParseAsync();
await HandleRequestAsync(ctx);
}
catch (Exception ex)
{
var code = ex is HttpRequestException r
? (HttpStatusCode)r.StatusCode
: HttpStatusCode.InternalServerError;
res.WithCode(code)
.WithStringContent(ex.ToString());
}
await res.CopyToAsync(ctx.OutputStream);
}
}
async Task HandleRequestAsync(HttpContext ctx)
{
var request = ctx.Request;
var evt = new RequestEventArgs(ctx);
await _onRequest.InvokeAsync(evt);
if (!evt.Handled)
{
ctx.Response.WithCode(HttpStatusCode.NotFound)
.WithStringContent($@"
<div>
<i>404 - Not found</i> — <b>{request.LocalPath}</b>
<br/>
<hr/>
<p>
{DateTime.Now:R} — {Guid.NewGuid():N}
</p>
</div>
");
}
}
private AsyncEvent<RequestEventArgs> _onRequest = new();
public event AsyncEventHandler<RequestEventArgs> OnRequest
{
add => _onRequest.AddHandler(value);
remove => _onRequest.RemoveHandler(value);
}
}
public class RequestEventArgs : AsyncEventArgs
{
public HttpContext Context { get; }
public RequestEventArgs(HttpContext ctx)
=> Context = ctx;
}