Skip to content

HTTPS Direct URL with AWS Lambda AOT dose not responed content-type text/html, awayes application/octet-stream. #2076

@CalvadosHof

Description

@CalvadosHof

Describe the bug

I wish return HTML direct to client from HTTPS Direct URL with AWS Lambda AOT Application, but it not work, return with content-type application/octet alwayes.
How to solve this problem?

Problem List

  1. APIGatewayProxyResponse with follwing parameter, but respose is content-type application/octet-stream.
  2. Overwrite APIGatewayProxyResponse by generated JsonDeserizer, but respose is content-type application/octet-stream.
  3. Specify TrimmerRootAssembly that Amazon.Lambda.APIGatewayEvents", but respose is content-type application/octet-stream.
  4. Overwrite LambdaSerializer by custom Serializer, but respose is content-type application/octet-stream.
  5. Specify JsonSerializable for Dictionary<string, string> and APIGatewayProxyResponse, but respose is content-type application/octet-stream.
  6. Specify DynamicallyAccessedMembers DynamicallyAccessedMemberTypes.All, but respose is content-type application/octet-stream.

Source Code
Sorry, comment as Japanese

using Amazon.Lambda.APIGatewayEvents;
using Amazon.Lambda.Core;
using Amazon.Lambda.RuntimeSupport;
using System;
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Net;
using System.Text.Json;
using System.Text.Json.Serialization;
[assembly: LambdaSerializer(typeof(MyLambdaJsonSerializer))]
[JsonSerializable(typeof(Dictionary<string, string>))]
[JsonSerializable(typeof(APIGatewayProxyResponse))]
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)]

internal partial class MyJsonContext : JsonSerializerContext { }

public class MyLambdaJsonSerializer : ILambdaSerializer
{
    private readonly JsonSerializerOptions _options;

    public MyLambdaJsonSerializer()
    {
        // ここで MyJsonContext.Default.Options を使用
        _options = MyJsonContext.Default.Options;
    }

    public T Deserialize<T>(Stream stream)
    {
        return JsonSerializer.Deserialize<T>(stream, _options);
    }

    public void Serialize<T>(T response, Stream stream)
    {
        JsonSerializer.Serialize(stream, response, _options);
    }
}

namespace CloudURLAOT01
{
    public class Function
    {
        /// <summary>
        /// 入力ストリームからデータを読み取り、FunctionHandlerを呼び出し、
        /// 結果を出力ストリームに書き込むアダプター関数
        /// </summary>
        public static void StreamHandler(Stream input, ILambdaContext context, MemoryStream output)
        {
            // 入力ストリームからテキストを読み込む
            string inputText;
            using (var reader = new StreamReader(input))
            {
                inputText = reader.ReadToEnd();
            }

            // 最小限のAPIGatewayProxyRequestを作成(必要に応じてプロパティを追加してください)
            var request = new APIGatewayProxyRequest { Body = inputText };

            // FunctionHandlerを同期的に呼び出す
            var function = new Function();
            APIGatewayProxyResponse response = function.FunctionHandler(request, context);

            // 出力ストリームに結果を書き込む(例:response.Bodyのみ)
            using (var writer = new StreamWriter(output, leaveOpen: true))
            {
                writer.Write(response.Body);
                writer.Flush();
            }
            output.Position = 0;
        }

        public static async Task Main(string[] args)
        {
            // ハンドラーを定義(ここではストリームベースの関数を利用)
            var handler = (Action<Stream, ILambdaContext, MemoryStream>)StreamHandler;

            // ビルダーから実行可能なブートストラップインスタンスを作成する
            using var bootstrap = LambdaBootstrapBuilder.Create(handler).Build();

            // ブートストラップインスタンスの RunAsync を呼び出してLambdaループを開始
            await bootstrap.RunAsync();
        }



        public APIGatewayProxyResponse FunctionHandler(APIGatewayProxyRequest request, ILambdaContext context)
        {
            // クエリパラメータを手動で解析(Dictionary を使わず文字列処理)
            string queryString = request.QueryStringParameters != null && request.QueryStringParameters.Count > 0
                ? string.Join("&", request.QueryStringParameters.Select(kv => $"{kv.Key}={kv.Value}"))
                : "No query string";

            // HTMLレスポンスの作成
            string body = "<html><head><title>Lambda AOT</title></head><body>";
            body += "<h1>Hello from AWS Lambda (Native AOT)!</h1>";
            body += $"<p>QueryString: {queryString}</p>";
            body += $"<p>Timestamp: {DateTime.UtcNow:O}</p>";
            body += "</body></html>";

            return new APIGatewayProxyResponse
            {
                StatusCode = (int)HttpStatusCode.OK,
                Body = body,
                IsBase64Encoded = false,
                Headers = new Dictionary<string, string>
                {
                    { "Content-Type", "text/html; charset=utf-8" },
                    { "Content-Disposition", "inline" }, // ブラウザに inline 表示を指示
                    { "Access-Control-Allow-Methods", "GET, POST, OPTIONS" }
                }
            };
        }
    }
}

Regression Issue

  • Select this option if this issue appears to be a regression.

Expected Behavior

Recive HTML text with content-type text/html.

Current Behavior

All response is content-type application/octet-stream, but I wish text/html.

Reproduction Steps

Please try my sample program.
This program(you must remove additional logic for AOT) work well under non AOT, but under AOT, all of respose is content-type application/octet-stream.

Possible Solution

No response

Additional Information/Context

No response

AWS .NET SDK and/or Package version used

Amazon.Lambda.APIGatewayEvents 2.7.1
Amazon.Lambda.Core 2.5.1
Amazon.Lambda.RuntimeSupport 1.13.0
Amazon.Lambda.Serialization.SystemTextJson 2.4.4
Lambdajection.Core 0.9.2
Microsoft.DotNet.ILCompiler 8.0.16
Lambdajection.Framework 0.9.2

Targeted .NET Platform

.NET 8

Operating System and version

AWS Lambda HTTPS Direct

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions