Developer forum

Forum » Dynamicweb 10 » Validate uploaded files

Validate uploaded files

Adrian Ursu Dynamicweb Employee
Adrian Ursu
Reply

Hi guys,
I have a project that requires adding a server-side validation for files uploaded via Forms for editors.
The validation should check mime-type/extension and file size.
I assume this is not supported with the current functionality, and I suppose that I need to create an App for that. It's just that (at first glance) I may not be able to interfere with the upload process from an installed app. But I may be wrong.
Any guidance is highly appreciated.

Thank you,
Adrian

 


Replies

 
Nicolai Pedersen Dynamicweb Employee
Nicolai Pedersen
Reply

You can do a Notifications.Frontend.OnBeforeContent notification subscriber - it is fired when a form is submitted. It is a generic notification fired when modules are executed.

In the notify, see if it is the forms module, see if it is a post, then do your validation.

Alternatively do it with middleware - GPT made me this - wrap it in ipipeline for DW10.

 

using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Primitives;
using System.Net.Mime;

public sealed class FormUploadGuardMiddleware : IMiddleware
{
    private readonly long _maxFileBytes = 10 * 1024 * 1024; // 10 MB
    private static readonly HashSet<string> AllowedContentTypes = new(StringComparer.OrdinalIgnoreCase)
    {
        "image/jpeg",
        "image/png",
        "application/pdf"
    };

    public async Task InvokeAsync(HttpContext context, RequestDelegate next)
    {
        var req = context.Request;

        if (!HttpMethods.IsPost(req.Method) || !req.HasFormContentType)
        {
            await next(context);
            return;
        }

        // Optional: only for specific path(s)
        // if (!req.Path.StartsWithSegments("/upload")) { await next(context); return; }

        IFormCollection form;
        try
        {
            // This parses application/x-www-form-urlencoded OR multipart/form-data
            form = await req.ReadFormAsync(context.RequestAborted);
        }
        catch (InvalidDataException)
        {
            context.Response.StatusCode = StatusCodes.Status400BadRequest;
            await context.Response.WriteAsync("Invalid form data.");
            return;
        }

        // Gate: only enforce rules when a specific field exists
        if (!form.TryGetValue("specialField", out StringValues v) || StringValues.IsNullOrEmpty(v))
        {
            await next(context);
            return;
        }

        foreach (var file in form.Files)
        {
            if (file.Length == 0)
            {
                context.Response.StatusCode = StatusCodes.Status400BadRequest;
                await context.Response.WriteAsync("Empty file not allowed.");
                return;
            }

            if (file.Length > _maxFileBytes)
            {
                context.Response.StatusCode = StatusCodes.Status413PayloadTooLarge;
                await context.Response.WriteAsync($"File too large (max {_maxFileBytes} bytes).");
                return;
            }

            // Client-reported. Useful, but not trustworthy on its own.
            if (!AllowedContentTypes.Contains(file.ContentType))
            {
                context.Response.StatusCode = StatusCodes.Status415UnsupportedMediaType;
                await context.Response.WriteAsync($"Unsupported content type: {file.ContentType}");
                return;
            }

            // Optional: stronger check by sniffing first bytes
            // using var stream = file.OpenReadStream();
            // if (!LooksLikeAllowedType(stream)) { ... }
        }

        await next(context);
    }
}

 
Adrian Ursu Dynamicweb Employee
Adrian Ursu
Reply

Thank you very much!

Adrian

 

You must be logged in to post in the forum