sdk-csharp/src/CloudNative.CloudEvents.Asp.../HttpRequestExtension.cs

76 lines
3.3 KiB
C#

// Copyright (c) Cloud Native Foundation.
// Licensed under the Apache 2.0 license.
// See LICENSE file in the project root for full license information.
using CloudNative.CloudEvents.Http;
using Microsoft.AspNetCore.Http;
using System;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
namespace CloudNative.CloudEvents
{
public static class HttpRequestExtension
{
/// <summary>
/// Converts this HTTP request into a CloudEvent object, with the given extensions,
/// overriding the formatter.
/// </summary>
/// <param name="httpRequest">HTTP request</param>
/// <param name="formatter">The event formatter to use to process the request body.</param>
/// <param name="extensions">List of extension instances</param>
/// <returns>A CloudEvent instance or 'null' if the request message doesn't hold a CloudEvent</returns>
public static async ValueTask<CloudEvent> ReadCloudEventAsync(this HttpRequest httpRequest,
CloudEventFormatter formatter,
params CloudEventAttribute[] extensionAttributes)
{
if (HasCloudEventsContentType(httpRequest))
{
// TODO: Handle formatter being null
return await formatter.DecodeStructuredEventAsync(httpRequest.Body, extensionAttributes).ConfigureAwait(false);
}
else
{
var headers = httpRequest.Headers;
CloudEventsSpecVersion version = CloudEventsSpecVersion.Default;
if (headers.TryGetValue(HttpUtilities.SpecVersionHttpHeader, out var values))
{
string versionId = values.First();
version = CloudEventsSpecVersion.FromVersionId(versionId);
}
var cloudEvent = new CloudEvent(version, extensionAttributes);
foreach (var header in headers)
{
string attributeName = HttpUtilities.GetAttributeNameFromHeaderName(header.Key);
if (attributeName is null || attributeName == CloudEventsSpecVersion.SpecVersionAttribute.Name)
{
continue;
}
string attributeValue = HttpUtilities.DecodeHeaderValue(header.Value.First());
cloudEvent.SetAttributeFromString(attributeName, attributeValue);
}
cloudEvent.DataContentType = httpRequest.ContentType;
if (httpRequest.Body is Stream body)
{
// TODO: This is a bit ugly.
var memoryStream = new MemoryStream();
await body.CopyToAsync(memoryStream).ConfigureAwait(false);
if (memoryStream.Length != 0)
{
cloudEvent.Data = formatter.DecodeData(memoryStream.ToArray(), cloudEvent.DataContentType);
}
}
return cloudEvent;
}
}
private static bool HasCloudEventsContentType(HttpRequest request) =>
request?.ContentType is var contentType &&
contentType.StartsWith(CloudEvent.MediaType, StringComparison.InvariantCultureIgnoreCase);
}
}