Skip to content

Commit cb3e5b0

Browse files
Updated HTTP Server
- Fix issue with HTTP Probe 'Device Not Found' error when device does not exist in Agent - Allow 'root' static file location
1 parent c2041ce commit cb3e5b0

2 files changed

Lines changed: 97 additions & 16 deletions

File tree

libraries/MTConnect.NET-HTTP/Servers/MTConnectHttpServer.cs

Lines changed: 32 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright (c) 2024 TrakHound Inc., All Rights Reserved.
1+
// Copyright (c) 2026 TrakHound Inc., All Rights Reserved.
22
// TrakHound Inc. licenses this file to you under the MIT license.
33

44
using Ceen;
@@ -321,10 +321,6 @@ private ServerConfig CreateServerConfig(IHttpServerConfiguration serverConfigura
321321

322322
// Setup Routes (Processed in Order)
323323
serverConfig.AddRoute(async (context) =>
324-
{
325-
return await DeviceRootHandler(probeHandler, context);
326-
});
327-
serverConfig.AddRoute(async (context) =>
328324
{
329325
return await PutHandler(putHandler, context);
330326
});
@@ -342,27 +338,49 @@ private ServerConfig CreateServerConfig(IHttpServerConfiguration serverConfigura
342338
serverConfig.AddRoute("/assets", assetsHandler);
343339
serverConfig.AddRoute("/*/assets", assetsHandler);
344340
serverConfig.AddRoute("/asset/*", assetHandler);
345-
serverConfig.AddRoute(staticHandler);
341+
serverConfig.AddRoute(async (context) =>
342+
{
343+
return await StaticHandler(staticHandler, context);
344+
});
345+
serverConfig.AddRoute(async (context) =>
346+
{
347+
return await DeviceRootHandler(probeHandler, context);
348+
});
346349

347350
return serverConfig;
348351
}
349352

350-
private async Task<bool> DeviceRootHandler(MTConnectProbeResponseHandler handler, IHttpContext context)
353+
private static async Task<bool> StaticHandler(MTConnectStaticResponseHandler handler, IHttpContext context)
354+
{
355+
if (context != null && context.Request != null && context.Request.Path != null)
356+
{
357+
if (context.Request.Method == HttpMethod.Get.Method)
358+
{
359+
var valid = handler.IsValidFile(context.Request.Path);
360+
if (valid)
361+
{
362+
await handler.HandleAsync(context, CancellationToken.None);
363+
364+
return true;
365+
}
366+
}
367+
}
368+
369+
return false;
370+
}
371+
372+
private static async Task<bool> DeviceRootHandler(MTConnectProbeResponseHandler handler, IHttpContext context)
351373
{
352374
if (context != null && context.Request != null && context.Request.Path != null)
353375
{
354376
if (context.Request.Method == HttpMethod.Get.Method)
355377
{
356378
var deviceKey = context.Request.Path.Trim('/');
357-
if (!string.IsNullOrEmpty(deviceKey))
379+
if (!string.IsNullOrEmpty(deviceKey) && !deviceKey.Contains('/'))
358380
{
359-
var device = _mtconnectAgent.GetDevice(deviceKey);
360-
if (device != null)
361-
{
362-
await handler.HandleAsync(context, CancellationToken.None);
381+
await handler.HandleAsync(context, CancellationToken.None);
363382

364-
return true;
365-
}
383+
return true;
366384
}
367385
}
368386
}

libraries/MTConnect.NET-HTTP/Servers/MTConnectStaticResponseHandler.cs

Lines changed: 65 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright (c) 2024 TrakHound Inc., All Rights Reserved.
1+
// Copyright (c) 2026 TrakHound Inc., All Rights Reserved.
22
// TrakHound Inc. licenses this file to you under the MIT license.
33

44
using Ceen;
@@ -66,7 +66,7 @@ protected async override Task<MTConnectHttpResponse> OnRequestReceived(IHttpCont
6666

6767
var relativePath = Path.GetDirectoryName(requestedPath);
6868
if (!string.IsNullOrEmpty(relativePath)) relativePath = relativePath.Replace('\\', '/');
69-
else relativePath = resource;
69+
else relativePath = "/"; // Assume Root
7070

7171
if (!string.IsNullOrEmpty(relativePath))
7272
{
@@ -138,5 +138,68 @@ protected async override Task<MTConnectHttpResponse> OnRequestReceived(IHttpCont
138138

139139
return response;
140140
}
141+
142+
internal bool IsValidFile(string path)
143+
{
144+
try
145+
{
146+
var requestedPath = path.Trim('/');
147+
var localPath = path.TrimEnd('/');
148+
149+
// Get File extension to prevent certain files (.exe, .dll, etc) from being accessed
150+
// that could cause security concerns
151+
var pathExtension = Path.GetExtension(requestedPath);
152+
var valid = pathExtension != ".exe" && pathExtension != ".dll";
153+
154+
if (valid)
155+
{
156+
valid = false;
157+
158+
// Check to see if the path matches one that is configured
159+
if (!_serverConfiguration.Files.IsNullOrEmpty())
160+
{
161+
var resource = Path.GetFileName(requestedPath);
162+
163+
var relativePath = Path.GetDirectoryName(requestedPath);
164+
if (!string.IsNullOrEmpty(relativePath)) relativePath = relativePath.Replace('\\', '/');
165+
else relativePath = "/"; // Assume Root
166+
167+
if (!string.IsNullOrEmpty(relativePath))
168+
{
169+
// Find a FileConfiguration whose Location matches the requested Resource
170+
var fileConfiguration = _serverConfiguration.Files.FirstOrDefault(o => o.Location == resource);
171+
if (fileConfiguration != null)
172+
{
173+
// Rewrite the localPath to the one that is configured that matches the 'Location' property
174+
localPath = fileConfiguration.Path;
175+
valid = true;
176+
}
177+
else
178+
{
179+
// Find a FileConfiguration whose Location matches the requested Resource
180+
fileConfiguration = _serverConfiguration.Files.FirstOrDefault(o => o.Location == relativePath);
181+
if (fileConfiguration != null)
182+
{
183+
// Rewrite the localPath to the one that is configured that matches the 'Location' property
184+
localPath = Path.Combine(fileConfiguration.Path, resource);
185+
localPath = localPath.Replace('/', '\\');
186+
valid = true;
187+
}
188+
}
189+
}
190+
}
191+
}
192+
193+
if (valid)
194+
{
195+
var filePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, localPath);
196+
197+
return File.Exists(filePath);
198+
}
199+
}
200+
catch { }
201+
202+
return false;
203+
}
141204
}
142205
}

0 commit comments

Comments
 (0)