using EmbedIO.Utilities; using Swan.Formatters; using System; using System.Threading.Tasks; namespace EmbedIO { /// /// Provides standard response serializer callbacks. /// /// public static class ResponseSerializer { /// /// The default response serializer callback used by EmbedIO. /// Equivalent to Json. /// public static readonly ResponseSerializerCallback Default = Json; private static readonly ResponseSerializerCallback ChunkedEncodingBaseSerializer = GetBaseSerializer(false); private static readonly ResponseSerializerCallback BufferingBaseSerializer = GetBaseSerializer(true); /// /// Serializes data in JSON format to a HTTP response, /// using the utility class. /// /// The HTTP context of the request. /// The data to serialize. /// A representing the ongoing operation. public static async Task Json(IHttpContext context, object? data) { context.Response.ContentType = MimeType.Json; context.Response.ContentEncoding = WebServer.Utf8NoBomEncoding; await ChunkedEncodingBaseSerializer(context, Swan.Formatters.Json.Serialize(data)).ConfigureAwait(false); } /// /// Serializes data in JSON format with the specified /// to a HTTP response, using the utility class. /// /// The JSON serializer case. /// A that can be used to serialize /// data to a HTTP response. public static ResponseSerializerCallback Json(JsonSerializerCase jsonSerializerCase) => async (context, data) => { context.Response.ContentType = MimeType.Json; context.Response.ContentEncoding = WebServer.Utf8NoBomEncoding; await ChunkedEncodingBaseSerializer(context, Swan.Formatters.Json.Serialize(data, jsonSerializerCase)) .ConfigureAwait(false); }; /// /// Serializes data in JSON format with the specified /// to a HTTP response, using the utility class. /// /// The JSON serializer options. /// A that can be used to serialize /// data to a HTTP response. /// /// is . /// public static ResponseSerializerCallback Json(SerializerOptions serializerOptions) { _ = Validate.NotNull(nameof(serializerOptions), serializerOptions); return async (context, data) => { context.Response.ContentType = MimeType.Json; context.Response.ContentEncoding = WebServer.Utf8NoBomEncoding; await ChunkedEncodingBaseSerializer(context, Swan.Formatters.Json.Serialize(data, serializerOptions)) .ConfigureAwait(false); }; } /// /// Serializes data in JSON format to a HTTP response, using the utility class. /// /// to write the response body to a memory buffer first, /// then send it all together with a Content-Length header; to use chunked /// transfer encoding. /// A that can be used to serialize /// data to a HTTP response. public static ResponseSerializerCallback Json(bool bufferResponse) => async (context, data) => { context.Response.ContentType = MimeType.Json; context.Response.ContentEncoding = WebServer.Utf8NoBomEncoding; var baseSerializer = None(bufferResponse); await baseSerializer(context, Swan.Formatters.Json.Serialize(data)) .ConfigureAwait(false); }; /// /// Serializes data in JSON format with the specified /// to a HTTP response, using the utility class. /// /// to write the response body to a memory buffer first, /// then send it all together with a Content-Length header; to use chunked /// transfer encoding. /// The JSON serializer case. /// A that can be used to serialize /// data to a HTTP response. public static ResponseSerializerCallback Json(bool bufferResponse, JsonSerializerCase jsonSerializerCase) => async (context, data) => { context.Response.ContentType = MimeType.Json; context.Response.ContentEncoding = WebServer.Utf8NoBomEncoding; var baseSerializer = None(bufferResponse); await baseSerializer(context, Swan.Formatters.Json.Serialize(data, jsonSerializerCase)) .ConfigureAwait(false); }; /// /// Serializes data in JSON format with the specified /// to a HTTP response, using the utility class. /// /// to write the response body to a memory buffer first, /// then send it all together with a Content-Length header; to use chunked /// transfer encoding. /// The JSON serializer options. /// A that can be used to serialize /// data to a HTTP response. /// /// is . /// public static ResponseSerializerCallback Json(bool bufferResponse, SerializerOptions serializerOptions) { _ = Validate.NotNull(nameof(serializerOptions), serializerOptions); return async (context, data) => { context.Response.ContentType = MimeType.Json; context.Response.ContentEncoding = WebServer.Utf8NoBomEncoding; var baseSerializer = None(bufferResponse); await baseSerializer(context, Swan.Formatters.Json.Serialize(data, serializerOptions)) .ConfigureAwait(false); }; } /// /// Sends data in a HTTP response without serialization. /// /// to write the response body to a memory buffer first, /// then send it all together with a Content-Length header; to use chunked /// transfer encoding. /// A that can be used to serialize data to a HTTP response. /// /// s and one-dimensional arrays of s /// are sent to the client unchanged; every other type is converted to a string. /// The ContentType set on the response is used to negotiate /// a compression method, according to request headers. /// Strings (and other types converted to strings) are sent with the encoding specified by . /// public static ResponseSerializerCallback None(bool bufferResponse) => bufferResponse ? BufferingBaseSerializer : ChunkedEncodingBaseSerializer; private static ResponseSerializerCallback GetBaseSerializer(bool bufferResponse) => async (context, data) => { if (data is null) { return; } var isBinaryResponse = data is byte[]; if (!context.TryDetermineCompression(context.Response.ContentType, out var preferCompression)) { preferCompression = true; } if (isBinaryResponse) { var responseBytes = (byte[])data; using var stream = context.OpenResponseStream(bufferResponse, preferCompression); await stream.WriteAsync(responseBytes, 0, responseBytes.Length).ConfigureAwait(false); } else { var responseString = data is string stringData ? stringData : data.ToString() ?? string.Empty; using var text = context.OpenResponseText(context.Response.ContentEncoding, bufferResponse, preferCompression); await text.WriteAsync(responseString).ConfigureAwait(false); } }; } }