Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions service/Core/Configuration/ServiceConfig.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// Copyright (c) Microsoft. All rights reserved.

using System;
using System.Collections.Generic;

namespace Microsoft.KernelMemory.Configuration;
Expand Down Expand Up @@ -27,4 +28,20 @@ public class ServiceConfig
/// List of handlers to enable
/// </summary>
public Dictionary<string, HandlerConfig> Handlers { get; set; } = new();

/// <summary>
/// The maximum allowed size in megabytes for a request body posted to the upload endpoint.
/// If not set the solution defaults to 30,000,000 bytes (~28.6 MB) (ASP.NET default).
/// </summary>
public long? MaxUploadSizeMb { get; set; } = null;

public long? GetMaxUploadSizeInBytes()
{
if (this.MaxUploadSizeMb.HasValue)
{
return Math.Min(10, this.MaxUploadSizeMb.Value) * 1024 * 1024;
}

return null;
}
}
15 changes: 13 additions & 2 deletions service/Service.AspNetCore/WebAPIEndpoints.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Http.HttpResults;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Routing;
Expand All @@ -22,9 +23,10 @@ public static class WebAPIEndpoints
public static IEndpointRouteBuilder AddKernelMemoryEndpoints(
this IEndpointRouteBuilder builder,
string apiPrefix = "/",
KernelMemoryConfig? kmConfig = null,
IEndpointFilter? authFilter = null)
{
builder.AddPostUploadEndpoint(apiPrefix, authFilter);
builder.AddPostUploadEndpoint(apiPrefix, authFilter, kmConfig?.Service.GetMaxUploadSizeInBytes());
builder.AddGetIndexesEndpoint(apiPrefix, authFilter);
builder.AddDeleteIndexesEndpoint(apiPrefix, authFilter);
builder.AddDeleteDocumentsEndpoint(apiPrefix, authFilter);
Expand All @@ -37,7 +39,10 @@ public static IEndpointRouteBuilder AddKernelMemoryEndpoints(
}

public static void AddPostUploadEndpoint(
this IEndpointRouteBuilder builder, string apiPrefix = "/", IEndpointFilter? authFilter = null)
this IEndpointRouteBuilder builder,
string apiPrefix = "/",
IEndpointFilter? authFilter = null,
long? maxUploadSizeInBytes = null)
{
RouteGroupBuilder group = builder.MapGroup(apiPrefix);

Expand All @@ -49,6 +54,12 @@ public static void AddPostUploadEndpoint(
IContextProvider contextProvider,
CancellationToken cancellationToken) =>
{
if (maxUploadSizeInBytes.HasValue && request.HttpContext.Features.Get<IHttpMaxRequestBodySizeFeature>() is { } feature)
{
log.LogTrace("Max upload request body size set to {0} bytes", maxUploadSizeInBytes.Value);
feature.MaxRequestBodySize = maxUploadSizeInBytes;
}

log.LogTrace("New upload HTTP request, content length {0}", request.ContentLength);

// Note: .NET doesn't yet support binding multipart forms including data and files
Expand Down
9 changes: 7 additions & 2 deletions service/Service.AspNetCore/WebApplicationBuilderExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,20 +19,25 @@ public static partial class WebApplicationBuilderExtensions
/// <param name="appBuilder">Hosting application builder</param>
/// <param name="configureMemoryBuilder">Optional configuration steps for the memory builder</param>
/// <param name="configureMemory">Optional configuration steps for the memory instance</param>
/// <param name="configureServices">Optional configuration for the internal dependencies</param>
public static WebApplicationBuilder AddKernelMemory(
this WebApplicationBuilder appBuilder,
Action<IKernelMemoryBuilder>? configureMemoryBuilder = null,
Action<IKernelMemory>? configureMemory = null)
Action<IKernelMemory>? configureMemory = null,
Action<IServiceCollection>? configureServices = null)
{
// Prepare memory builder, sharing the service collection used by the hosting service
var memoryBuilder = new KernelMemoryBuilder(appBuilder.Services);

// Optional services configuration provided by the user
configureServices?.Invoke(appBuilder.Services);

// Optional configuration provided by the user
configureMemoryBuilder?.Invoke(memoryBuilder);

var memory = memoryBuilder.Build();

// Optional configuration provided by the user
// Optional memory configuration provided by the user
configureMemory?.Invoke(memory);

appBuilder.Services.AddSingleton<IKernelMemory>(memory);
Expand Down
17 changes: 16 additions & 1 deletion service/Service/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
using System.Linq;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Server.Kestrel.Core;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
Expand Down Expand Up @@ -97,6 +99,19 @@ public static void Main(string[] args)
syncHandlersCount = AddHandlersToServerlessMemory(config, memory);

memoryType = ((memory is MemoryServerless) ? "Sync - " : "Async - ") + memory.GetType().FullName;
},
services =>
{
long? maxSize = config.Service.GetMaxUploadSizeInBytes();
if (!maxSize.HasValue) { return; }

services.Configure<IISServerOptions>(x => { x.MaxRequestBodySize = maxSize.Value; });
services.Configure<KestrelServerOptions>(x => { x.Limits.MaxRequestBodySize = maxSize.Value; });
services.Configure<FormOptions>(x =>
{
x.MultipartBodyLengthLimit = maxSize.Value;
x.ValueLengthLimit = int.MaxValue;
});
});

// CORS
Expand Down Expand Up @@ -138,7 +153,7 @@ public static void Main(string[] args)
.Produces<ProblemDetails>(StatusCodes.Status403Forbidden);

// Add HTTP endpoints using minimal API (https://learn.microsoft.com/aspnet/core/fundamentals/minimal-apis)
app.AddKernelMemoryEndpoints("/", authFilter);
app.AddKernelMemoryEndpoints("/", config, authFilter);

// Health probe
app.MapGet("/health", () => Results.Ok("Service is running."))
Expand Down
3 changes: 3 additions & 0 deletions service/Service/appsettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@
"RunWebService": true,
// Whether to expose OpenAPI swagger UI at http://127.0.0.1:9001/swagger/index.html
"OpenApiEnabled": false,
// The maximum allowed size in MB for the payload posted to the upload endpoint
// If not set the solution defaults to 30,000,000 bytes (~28.6 MB)
"MaxUploadSizeMb": null,
// Whether to run the asynchronous pipeline handlers
// Use these booleans to deploy the web service and the handlers on same/different VMs
"RunHandlers": true,
Expand Down