-
Notifications
You must be signed in to change notification settings - Fork 25
/
HTTP.cs
224 lines (207 loc) · 8.75 KB
/
HTTP.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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
using DuetAPI.ObjectModel;
using System;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
namespace DuetPiManagementPlugin.Network.Protocols
{
/// <summary>
/// Protocol management for HTTP/HTTPS
/// </summary>
public static class HTTP
{
/// <summary>
/// Configured HTTP port
/// </summary>
private static int _httpPort = 80;
/// <summary>
/// Configured HTTPS port
/// </summary>
private static int _httpsPort = 443;
/// <summary>
/// Internal representation of the ASP.NET JSON config
/// </summary>
private sealed class AspNetConfig
{
public sealed class KestrelConfig
{
public sealed class EndpointsConfig
{
public sealed class HttpConfig
{
public string Url { get; set; }
}
public HttpConfig Http { get; set; } = new HttpConfig();
public HttpConfig Https { get; set; } = new HttpConfig();
}
public EndpointsConfig Endpoints { get; set; } = new EndpointsConfig();
}
public KestrelConfig Kestrel { get; set; } = new KestrelConfig();
}
/// <summary>
/// Initialize the protocol configuration
/// </summary>
/// <returns>Asynchronous task</returns>
public static async Task Init()
{
if (File.Exists("/opt/dsf/conf/http.json"))
{
AspNetConfig config;
using (FileStream configStream = new("/opt/dsf/conf/http.json", FileMode.Open, FileAccess.Read))
{
config = await JsonSerializer.DeserializeAsync<AspNetConfig>(configStream, null, Program.CancellationToken);
}
bool dwsEnabled = await Command.ExecQuery("/usr/bin/systemctl", "is-enabled -q duetwebserver.service");
if (config?.Kestrel?.Endpoints?.Http?.Url != null && Uri.TryCreate(config.Kestrel.Endpoints.Http.Url.Replace('*', 'x'), UriKind.Absolute, out Uri url))
{
_httpPort = url.Port;
if (dwsEnabled)
{
await Manager.SetProtocol(NetworkProtocol.HTTP, true);
}
}
if (config?.Kestrel?.Endpoints?.Https?.Url != null && Uri.TryCreate(config.Kestrel.Endpoints.Https.Url.Replace('*', 'x'), UriKind.Absolute, out url))
{
_httpsPort = url.Port;
if (dwsEnabled)
{
await Manager.SetProtocol(NetworkProtocol.HTTPS, true);
}
}
}
}
/// <summary>
/// Configure the HTTP(S) server
/// </summary>
/// <param name="enabled">Enable HTTP(S)</param>
/// <param name="port">Port</param>
/// <param name="secure">Configure HTTPS</param>
/// <returns>Configuration result</returns>
public static async Task<Message> Configure(bool? enabled, int port, bool secure)
{
// If we need to enable HTTPS, weed a valid certificate first...
if (secure && !File.Exists("/opt/dsf/conf/https.pfx"))
{
using Process genCertProcess = Process.Start(Path.Combine(Directory.GetCurrentDirectory(), "gen-https-cert.sh"));
await genCertProcess.WaitForExitAsync(Program.CancellationToken);
}
// Check whether HTTP(S) should be enabled or not
bool useHTTP = Manager.IsEnabled(NetworkProtocol.HTTP);
bool useHTTPS = Manager.IsEnabled(NetworkProtocol.HTTPS);
bool enableService = false, disableService = false;
if (secure)
{
if (enabled != null && enabled != useHTTPS)
{
enableService = !useHTTP && !useHTTPS && enabled.Value;
disableService = !useHTTP && useHTTPS && !enabled.Value;
useHTTPS = enabled.Value;
await Manager.SetProtocol(NetworkProtocol.HTTPS, useHTTPS);
}
else if (port <= 0 || port == _httpsPort)
{
// No changes requested, don't do anything
return new Message();
}
}
else
{
if (enabled != null && enabled != useHTTP)
{
enableService = !useHTTP && !useHTTPS && enabled.Value;
disableService = useHTTP && !useHTTPS && !enabled.Value;
useHTTP = enabled.Value;
await Manager.SetProtocol(NetworkProtocol.HTTP, useHTTP);
}
else if (port <= 0 || port == _httpPort)
{
// No changes requested, don't do anything
return new Message();
}
}
// Do we need to disable DWS?
if (disableService)
{
string stopOutput = await Command.Execute("/usr/bin/systemctl", "stop duetwebserver.service");
string disableOutput = await Command.Execute("/usr/bin/systemctl", "disable duetwebserver.service");
return new Message(MessageType.Success, string.Join('\n', stopOutput, disableOutput).Trim());
}
// Choose the config template to use
string templateFile;
if (useHTTP && useHTTPS)
{
templateFile = Path.Combine(Directory.GetCurrentDirectory(), "http-mixed.json");
}
else if (useHTTP)
{
templateFile = Path.Combine(Directory.GetCurrentDirectory(), "http-simple.json");
}
else
{
templateFile = Path.Combine(Directory.GetCurrentDirectory(), "http-secure.json");
}
// Copy the template file and replace the port variables
using (FileStream templateStream = new(templateFile, FileMode.Open, FileAccess.Read))
{
using StreamReader reader = new(templateStream);
using FileStream configStream = new("/opt/dsf/conf/http.json", FileMode.Create, FileAccess.Write);
using StreamWriter writer = new(configStream);
while (!reader.EndOfStream)
{
string line = await reader.ReadLineAsync();
line = line.Replace("{httpPort}", _httpPort.ToString());
line = line.Replace("{httpsPort}", _httpsPort.ToString());
await writer.WriteLineAsync(line);
}
}
// Enable the service if it was disabled before
if (enableService)
{
string enableOutput = await Command.Execute("/usr/bin/systemctl", "enable -q duetwebserver.service");
string startOutput = await Command.Execute("/usr/bin/systemctl", "start duetwebserver.service");
return new Message(MessageType.Success, string.Join('\n', enableOutput, startOutput).Trim());
}
// Restart the service
string restartOutput = await Command.Execute("/usr/bin/systemctl", "restart duetwebserver.service");
return new Message(MessageType.Success, restartOutput.TrimEnd());
}
/// <summary>
/// Report the current state of the HTTP and HTTPS protocols
/// </summary>
/// <param name="builder">String builder</param>
/// <returns>Asynchronous task</returns>
public static async Task Report(StringBuilder builder)
{
// HTTP
if (Manager.IsEnabled(NetworkProtocol.HTTP))
{
builder.AppendLine($"HTTP is enabled on port {_httpPort}");
}
else
{
builder.AppendLine("HTTP is disabled");
}
// HTTPS
if (Manager.IsEnabled(NetworkProtocol.HTTPS))
{
builder.AppendLine($"HTTPS is enabled on port {_httpsPort}");
}
else
{
builder.AppendLine("HTTPS is disabled");
}
// CORS
ObjectModel model = await Program.Connection.GetObjectModel(Program.CancellationToken);
if (string.IsNullOrEmpty(model.Network.CorsSite))
{
builder.AppendLine("CORS disabled");
}
else
{
builder.AppendLine($"CORS enabled for site '{model.Network.CorsSite}'");
}
}
}
}