Skip to content
Open
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
49 changes: 49 additions & 0 deletions .autover/changes/9e75413c-9cb6-4521-aaca-09b557fff2b3.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
{
"Projects": [
{
"Name": "Amazon.Lambda.Core",
"Type": "Minor",
"ChangelogMessages": [
"Lambda response streaming is now available as GA. The RequiresPreviewFeatures attribute has been removed",
"The LambdaLogger.ConfigureStructuredLogging API has been deployed to the managed runtime. The RequiresPreviewFeatures attribute has been removed"
]
},
{
"Name": "Amazon.Lambda.Annotations",
"Type": "Minor",
"ChangelogMessages": [
"Updated Amazon.Lambda.Core dependency to include Lambda Response Streaming support."
]
},
{
"Name": "Amazon.Lambda.AspNetCoreServer",
"Type": "Minor",
"ChangelogMessages": [
"Removed RequiresPreviewFeatures attribute for Lambda Response Streaming."
"Updated Amazon.Lambda.Core dependency to include Lambda Response Streaming support."
]
},
{
"Name": "Amazon.Lambda.AspNetCoreServer.Hosting",
"Type": "Minor",
"ChangelogMessages": [
"Removed RequiresPreviewFeatures attribute for Lambda Response Streaming."
"Updated Amazon.Lambda.Core dependency to include Lambda Response Streaming support."
]
},
{
"Name": "Amazon.Lambda.PowerShellHost",
"Type": "Minor",
"ChangelogMessages": [
"Updated Amazon.Lambda.Core dependency to include Lambda Response Streaming support."
]
},
{
"Name": "Amazon.Lambda.RuntimeSupport",
"Type": "Minor",
"ChangelogMessages": [
"Updated Amazon.Lambda.Core dependency to include Lambda Response Streaming support."
]
}
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ public class HostingOptions
/// <c>FunctionHandlerAsync</c> writes directly to the Lambda response stream and
/// returns <c>null</c>. Requires net8.0 or later.
/// </summary>
[System.Runtime.Versioning.RequiresPreviewFeatures(ParameterizedPreviewMessage)]
public bool EnableResponseStreaming { get; set; } = false;

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,6 @@ private protected override void InternalCustomResponseExceptionHandling(APIGatew
/// instead of <c>multiValueHeaders</c>. API Gateway HTTP API v2 expects the <c>headers</c>
/// format; using <c>multiValueHeaders</c> causes a 500 Internal Server Error.
/// </summary>
[System.Runtime.Versioning.RequiresPreviewFeatures(ParameterizedPreviewMessage)]
protected override Amazon.Lambda.Core.ResponseStreaming.HttpResponseStreamPrelude BuildStreamingPrelude(IHttpResponseFeature responseFeature)
{
var prelude = new Amazon.Lambda.Core.ResponseStreaming.HttpResponseStreamPrelude
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,6 @@ private protected override void InternalCustomResponseExceptionHandling(APIGatew
/// </summary>
/// <param name="responseFeature">The ASP.NET Core response feature for the current invocation.</param>
/// <returns>A populated <see cref="Amazon.Lambda.Core.ResponseStreaming.HttpResponseStreamPrelude"/>.</returns>
[System.Runtime.Versioning.RequiresPreviewFeatures(ParameterizedPreviewMessage)]
protected override Amazon.Lambda.Core.ResponseStreaming.HttpResponseStreamPrelude BuildStreamingPrelude(IHttpResponseFeature responseFeature)
{
var prelude = new Amazon.Lambda.Core.ResponseStreaming.HttpResponseStreamPrelude
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,6 @@ namespace Amazon.Lambda.AspNetCoreServer
/// </summary>
public abstract class AbstractAspNetCoreFunction
{
internal const string ParameterizedPreviewMessage =
"Response streaming is in preview till a new version of .NET Lambda runtime client that supports response streaming " +
"has been deployed to the .NET Lambda managed runtime. Till deployment has been made the feature can be used by deploying as an " +
"executable including the latest version of Amazon.Lambda.RuntimeSupport and setting the \"EnablePreviewFeatures\" in the Lambda " +
"project file to \"true\"";

/// <summary>
/// Key to access the ILambdaContext object from the HttpContext.Items collection.
/// </summary>
Expand Down Expand Up @@ -206,7 +200,6 @@ public void RegisterResponseContentEncodingForContentEncoding(string contentEnco
/// buffering it and returning a typed response object (which will be <c>null</c>).
/// Requires net8.0 or later.
/// </summary>
[System.Runtime.Versioning.RequiresPreviewFeatures(ParameterizedPreviewMessage)]
public virtual bool EnableResponseStreaming { get; set; } = false;


Expand Down Expand Up @@ -678,7 +671,6 @@ protected virtual void PostMarshallResponseFeature(IHttpResponseFeature aspNetCo
/// </summary>
/// <param name="responseFeature">The ASP.NET Core response feature for the current invocation.</param>
/// <returns>A populated <see cref="Amazon.Lambda.Core.ResponseStreaming.HttpResponseStreamPrelude"/>.</returns>
[System.Runtime.Versioning.RequiresPreviewFeatures(ParameterizedPreviewMessage)]
protected abstract Amazon.Lambda.Core.ResponseStreaming.HttpResponseStreamPrelude BuildStreamingPrelude(IHttpResponseFeature responseFeature);

/// <summary>
Expand All @@ -689,7 +681,6 @@ protected virtual void PostMarshallResponseFeature(IHttpResponseFeature aspNetCo
/// </summary>
/// <param name="prelude">The HTTP response prelude containing status code and headers.</param>
/// <returns>A writable <see cref="System.IO.Stream"/> for the response body.</returns>
[System.Runtime.Versioning.RequiresPreviewFeatures(ParameterizedPreviewMessage)]
protected virtual System.IO.Stream CreateLambdaResponseStream(
Amazon.Lambda.Core.ResponseStreaming.HttpResponseStreamPrelude prelude)
{
Expand All @@ -701,7 +692,6 @@ protected virtual System.IO.Stream CreateLambdaResponseStream(
/// <see cref="EnableResponseStreaming"/> is <c>true</c>. Writes the response directly to a
/// <see cref="Amazon.Lambda.Core.ResponseStreaming.LambdaResponseStream"/>.
/// </summary>
[System.Runtime.Versioning.RequiresPreviewFeatures(ParameterizedPreviewMessage)]
private async Task ExecuteStreamingRequestAsync(InvokeFeatures features)
{
var responseFeature = (IHttpResponseFeature)features;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,6 @@ private protected override void InternalCustomResponseExceptionHandling(Applicat
}

/// <inheritdoc/>
[System.Runtime.Versioning.RequiresPreviewFeatures(ParameterizedPreviewMessage)]
protected override HttpResponseStreamPrelude BuildStreamingPrelude(IHttpResponseFeature responseFeature) => throw new NotImplementedException();

private string GetSingleHeaderValue(ApplicationLoadBalancerRequest request, string headerName)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ namespace Amazon.Lambda.AspNetCoreServer.Internal
/// <see cref="MemoryStream"/>; after <see cref="StartAsync"/> all writes go directly to the
/// <see cref="LambdaResponseStream"/> obtained from the stream opener delegate.
/// </summary>
[RequiresPreviewFeatures(AbstractAspNetCoreFunction.ParameterizedPreviewMessage)]
internal class StreamingResponseBodyFeature : IHttpResponseBodyFeature
{
private readonly ILogger _logger;
Expand Down
1 change: 0 additions & 1 deletion Libraries/src/Amazon.Lambda.Core/LambdaLogger.cs
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,6 @@ public static void Log(string level, Exception exception, string message, params
/// When structured logging is enabled this method will allow overriding the default configuration the Lambda runtime uses for structured logging.
/// </summary>
/// <param name="options">The options to use for configuring structured logging.</param>
[RequiresPreviewFeatures("This method is in preview until the latest changes of the .NET Lambda runtime client have been deployed to the Lambda managed runtimes")]
public static void ConfigureStructuredLogging(StructuredLoggingOptions options) => _configureStructuredLoggingAction(options);

internal static void SetConfigureStructuredLoggingAction(Action<StructuredLoggingOptions> configureStructuredLoggingAction)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ namespace Amazon.Lambda.Core.ResponseStreaming
/// headers, and cookies for the response. The prelude must be sent as the first chunk of the response stream, followed by the response body chunks.
/// This allows you to set the status code and headers for the response before sending any of the response body.
/// </summary>
[RequiresPreviewFeatures(LambdaResponseStreamFactory.PreviewMessage)]
public class HttpResponseStreamPrelude
{
/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ namespace Amazon.Lambda.Core.ResponseStreaming
/// to the Lambda Runtime API. Returned by <see cref="LambdaResponseStreamFactory.CreateStream"/>.
/// Integrates with standard .NET stream consumers such as <see cref="System.IO.StreamWriter"/>.
/// </summary>
[RequiresPreviewFeatures(LambdaResponseStreamFactory.PreviewMessage)]
public class LambdaResponseStream : Stream
{
private readonly ILambdaResponseStream _responseStream;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,8 @@ namespace Amazon.Lambda.Core.ResponseStreaming
/// <summary>
/// Factory to create Lambda response streams for writing streaming responses in AWS Lambda functions. The created streams are write-only and non-seekable.
/// </summary>
[RequiresPreviewFeatures(LambdaResponseStreamFactory.PreviewMessage)]
public class LambdaResponseStreamFactory
{
internal const string PreviewMessage =
"Response streaming is in preview till a new version of .NET Lambda runtime client that supports response streaming " +
"has been deployed to the .NET Lambda managed runtime. Till deployment has been made the feature can be used by deploying as an " +
"executable including the latest version of Amazon.Lambda.RuntimeSupport and setting the \"EnablePreviewFeatures\" in the Lambda " +
"project file to \"true\"";

internal const string UninitializedFactoryMessage =
"LambdaResponseStreamFactory is not initialized. This is caused by mismatch versions of Amazon.Lambda.Core and Amazon.Lambda.RuntimeSupport. " +
"Update both packages to the current version to address the issue.";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ namespace Amazon.Lambda.AspNetCoreServer.Hosting.Tests;
/// <summary>
/// Tests for response streaming integration in hosting (Requirement 10).
/// </summary>
[RequiresPreviewFeatures]
public class ResponseStreamingHostingTests
{
[Fact]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@

namespace Amazon.Lambda.AspNetCoreServer.Hosting.Tests;

[RequiresPreviewFeatures]
public class ResponseStreamingPropertyTests
{
private static IServiceProvider BuildServiceProvider(HostingOptions hostingOptions)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@

namespace Amazon.Lambda.AspNetCoreServer.Test
{
[RequiresPreviewFeatures]
public class BuildStreamingPreludeTests
{
// Subclass that skips host startup entirely and
Expand Down Expand Up @@ -83,10 +82,12 @@ public void StatusCode_DefaultsTo200_WhenFeatureStatusCodeIsZero()
}

// -----------------------------------------------------------------------
// 6.3 Non-Set-Cookie headers appear in MultiValueHeaders with all values preserved
// 6.3 Non-Set-Cookie headers appear in Headers with all values preserved.
// HTTP API v2 uses the single-value "headers" collection (not "multiValueHeaders"),
// so multiple values for the same header are joined with ", ".
// -----------------------------------------------------------------------
[Fact]
public void NonSetCookieHeaders_AppearInMultiValueHeaders_WithAllValuesPreserved()
public void NonSetCookieHeaders_AppearInHeaders_WithAllValuesPreserved()
{
var builder = CreateBuilder();
var rf = MakeResponseFeature(200, new System.Collections.Generic.Dictionary<string, string[]>
Expand All @@ -98,18 +99,18 @@ public void NonSetCookieHeaders_AppearInMultiValueHeaders_WithAllValuesPreserved

var prelude = builder.InvokeBuildStreamingPrelude(rf);

Assert.True(prelude.MultiValueHeaders.ContainsKey("Content-Type"));
Assert.Equal(new[] { "application/json" }, prelude.MultiValueHeaders["Content-Type"]);
Assert.True(prelude.Headers.ContainsKey("Content-Type"));
Assert.Equal("application/json", prelude.Headers["Content-Type"]);

Assert.True(prelude.MultiValueHeaders.ContainsKey("X-Custom"));
Assert.Equal(new[] { "val1", "val2" }, prelude.MultiValueHeaders["X-Custom"]);
Assert.True(prelude.Headers.ContainsKey("X-Custom"));
Assert.Equal("val1, val2", prelude.Headers["X-Custom"]);

Assert.True(prelude.MultiValueHeaders.ContainsKey("Cache-Control"));
Assert.Equal(new[] { "no-cache", "no-store" }, prelude.MultiValueHeaders["Cache-Control"]);
Assert.True(prelude.Headers.ContainsKey("Cache-Control"));
Assert.Equal("no-cache, no-store", prelude.Headers["Cache-Control"]);
}

[Fact]
public void NonSetCookieHeaders_MultiValueHeaders_PreservesMultipleValues()
public void NonSetCookieHeaders_Headers_JoinsMultipleValues()
{
var builder = CreateBuilder();
var rf = MakeResponseFeature(200, new System.Collections.Generic.Dictionary<string, string[]>
Expand All @@ -119,8 +120,8 @@ public void NonSetCookieHeaders_MultiValueHeaders_PreservesMultipleValues()

var prelude = builder.InvokeBuildStreamingPrelude(rf);

Assert.Equal(new[] { "text/html", "application/xhtml+xml", "application/xml" },
prelude.MultiValueHeaders["Accept"]);
Assert.Equal("text/html, application/xhtml+xml, application/xml",
prelude.Headers["Accept"]);
}

// -----------------------------------------------------------------------
Expand All @@ -141,12 +142,12 @@ public void SetCookieHeader_MovedToCookies_AbsentFromMultiValueHeaders()
// Cookie value is in Cookies
Assert.Contains("session=abc123; Path=/; HttpOnly", prelude.Cookies);

// Set-Cookie is NOT in MultiValueHeaders
Assert.False(prelude.MultiValueHeaders.ContainsKey("Set-Cookie"));
Assert.False(prelude.MultiValueHeaders.ContainsKey("set-cookie"));
// Set-Cookie is NOT in Headers
Assert.False(prelude.Headers.ContainsKey("Set-Cookie"));
Assert.False(prelude.Headers.ContainsKey("set-cookie"));

// Other headers are still present
Assert.True(prelude.MultiValueHeaders.ContainsKey("Content-Type"));
Assert.True(prelude.Headers.ContainsKey("Content-Type"));
}

[Fact]
Expand All @@ -164,8 +165,8 @@ public void SetCookieHeader_IsCaseInsensitive()
var prelude = builder.InvokeBuildStreamingPrelude(rf);

Assert.Contains("id=xyz; Path=/", prelude.Cookies);
Assert.False(prelude.MultiValueHeaders.ContainsKey("Set-Cookie"));
Assert.False(prelude.MultiValueHeaders.ContainsKey("set-cookie"));
Assert.False(prelude.Headers.ContainsKey("Set-Cookie"));
Assert.False(prelude.Headers.ContainsKey("set-cookie"));
}

// -----------------------------------------------------------------------
Expand All @@ -192,8 +193,8 @@ public void MultipleSetCookieValues_AllAppearInCookies()
Assert.Contains("theme=dark; Path=/", prelude.Cookies);
Assert.Contains("lang=en; Path=/; SameSite=Strict", prelude.Cookies);

// None of them should be in MultiValueHeaders
Assert.False(prelude.MultiValueHeaders.ContainsKey("Set-Cookie"));
// None of them should be in Headers
Assert.False(prelude.Headers.ContainsKey("Set-Cookie"));
}

[Fact]
Expand All @@ -212,8 +213,8 @@ public void MultipleSetCookieValues_WithOtherHeaders_CookiesAndHeadersAreSeparat
Assert.Equal(2, prelude.Cookies.Count);
Assert.Contains("a=1", prelude.Cookies);
Assert.Contains("b=2", prelude.Cookies);
Assert.True(prelude.MultiValueHeaders.ContainsKey("Location"));
Assert.False(prelude.MultiValueHeaders.ContainsKey("Set-Cookie"));
Assert.True(prelude.Headers.ContainsKey("Location"));
Assert.False(prelude.Headers.ContainsKey("Set-Cookie"));
}

[Fact]
Expand All @@ -225,7 +226,7 @@ public void EmptyHeaders_ProducesEmptyMultiValueHeadersAndCookies()
var prelude = builder.InvokeBuildStreamingPrelude(rf);

Assert.Equal(HttpStatusCode.NoContent, prelude.StatusCode);
Assert.Empty(prelude.MultiValueHeaders);
Assert.Empty(prelude.Headers);
Assert.Empty(prelude.Cookies);
}

Expand All @@ -244,8 +245,8 @@ public void ContentLengthHeader_ExcludedFromPrelude()

var prelude = builder.InvokeBuildStreamingPrelude(rf);

Assert.True(prelude.MultiValueHeaders.ContainsKey("Content-Type"));
Assert.False(prelude.MultiValueHeaders.ContainsKey("Content-Length"));
Assert.True(prelude.Headers.ContainsKey("Content-Type"));
Assert.False(prelude.Headers.ContainsKey("Content-Length"));
}

[Fact]
Expand All @@ -260,8 +261,8 @@ public void TransferEncodingHeader_ExcludedFromPrelude()

var prelude = builder.InvokeBuildStreamingPrelude(rf);

Assert.True(prelude.MultiValueHeaders.ContainsKey("Content-Type"));
Assert.False(prelude.MultiValueHeaders.ContainsKey("Transfer-Encoding"));
Assert.True(prelude.Headers.ContainsKey("Content-Type"));
Assert.False(prelude.Headers.ContainsKey("Transfer-Encoding"));
}
}
}
Loading
Loading