add support for parsing ASP.NET Core HTTP requests into CloudEvents

Signed-off-by: Michael Friis <friism@gmail.com>
This commit is contained in:
Michael Friis 2019-02-26 15:56:53 -08:00 committed by Tobias Lønnerød Madsen
parent a0f3e72897
commit 209247e75f
4 changed files with 158 additions and 0 deletions

View File

@ -23,6 +23,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CloudNative.CloudEvents.Amq
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CloudNative.CloudEvents.Kafka", "src\CloudNative.CloudEvents.Kafka\CloudNative.CloudEvents.Kafka.csproj", "{193D6D9D-C1A0-459E-86CF-F207CDF0FC73}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CloudNative.CloudEvents.AspNetCore", "src\CloudNative.CloudEvents.AspNetCore\CloudNative.CloudEvents.AspNetCore.csproj", "{C726DD78-2D56-48D3-928A-D10226E3750B}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -93,6 +95,7 @@ Global
{39EF4DB0-9890-4CAD-A36E-F7E25D2E72EF}.Release|x64.Build.0 = Release|Any CPU
{39EF4DB0-9890-4CAD-A36E-F7E25D2E72EF}.Release|x86.ActiveCfg = Release|Any CPU
{39EF4DB0-9890-4CAD-A36E-F7E25D2E72EF}.Release|x86.Build.0 = Release|Any CPU
<<<<<<< HEAD
{193D6D9D-C1A0-459E-86CF-F207CDF0FC73}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{193D6D9D-C1A0-459E-86CF-F207CDF0FC73}.Debug|Any CPU.Build.0 = Debug|Any CPU
{193D6D9D-C1A0-459E-86CF-F207CDF0FC73}.Debug|x64.ActiveCfg = Debug|Any CPU
@ -105,6 +108,20 @@ Global
{193D6D9D-C1A0-459E-86CF-F207CDF0FC73}.Release|x64.Build.0 = Release|Any CPU
{193D6D9D-C1A0-459E-86CF-F207CDF0FC73}.Release|x86.ActiveCfg = Release|Any CPU
{193D6D9D-C1A0-459E-86CF-F207CDF0FC73}.Release|x86.Build.0 = Release|Any CPU
=======
{C726DD78-2D56-48D3-928A-D10226E3750B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C726DD78-2D56-48D3-928A-D10226E3750B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C726DD78-2D56-48D3-928A-D10226E3750B}.Debug|x64.ActiveCfg = Debug|Any CPU
{C726DD78-2D56-48D3-928A-D10226E3750B}.Debug|x64.Build.0 = Debug|Any CPU
{C726DD78-2D56-48D3-928A-D10226E3750B}.Debug|x86.ActiveCfg = Debug|Any CPU
{C726DD78-2D56-48D3-928A-D10226E3750B}.Debug|x86.Build.0 = Debug|Any CPU
{C726DD78-2D56-48D3-928A-D10226E3750B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C726DD78-2D56-48D3-928A-D10226E3750B}.Release|Any CPU.Build.0 = Release|Any CPU
{C726DD78-2D56-48D3-928A-D10226E3750B}.Release|x64.ActiveCfg = Release|Any CPU
{C726DD78-2D56-48D3-928A-D10226E3750B}.Release|x64.Build.0 = Release|Any CPU
{C726DD78-2D56-48D3-928A-D10226E3750B}.Release|x86.ActiveCfg = Release|Any CPU
{C726DD78-2D56-48D3-928A-D10226E3750B}.Release|x86.Build.0 = Release|Any CPU
>>>>>>> dde2c54... add support for parsing ASP.NET Core HTTP requests into CloudEvents
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View File

@ -0,0 +1,6 @@
<SolutionConfiguration>
<Settings>
<AllowParallelTestExecution>False</AllowParallelTestExecution>
<SolutionConfigured>True</SolutionConfigured>
</Settings>
</SolutionConfiguration>

View File

@ -0,0 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Http" Version="2.1.1" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\CloudNative.CloudEvents\CloudNative.CloudEvents.csproj" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,120 @@
// Copyright (c) Cloud Native Foundation.
// Licensed under the Apache 2.0 license.
// See LICENSE file in the project root for full license information.
namespace CloudNative.CloudEvents
{
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Primitives;
using Newtonsoft.Json;
using System;
using System.Net.Mime;
public static class HttpRequestExtension
{
const string HttpHeaderPrefix = "ce-";
const string SpecVersionHttpHeader1 = HttpHeaderPrefix + "cloudEventsVersion";
const string SpecVersionHttpHeader2 = HttpHeaderPrefix + "specversion";
static JsonEventFormatter jsonFormatter = new JsonEventFormatter();
/// <summary>
/// Converts this HTTP request into a CloudEvent object, with the given extensions.
/// </summary>
/// <param name="httpRequest">HTTP request</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 CloudEvent ToCloudEvent(this HttpRequest httpRequest,
params ICloudEventExtension[] extensions)
{
return ToCloudEvent(httpRequest, null, extensions);
}
/// <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"></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 CloudEvent ToCloudEvent(this HttpRequest httpRequest,
ICloudEventFormatter formatter = null,
params ICloudEventExtension[] extensions)
{
if (httpRequest.ContentType != null &&
httpRequest.ContentType.StartsWith(CloudEvent.MediaType,
StringComparison.InvariantCultureIgnoreCase))
{
// handle structured mode
if (formatter == null)
{
// if we didn't get a formatter, pick one
if (httpRequest.ContentType.EndsWith(JsonEventFormatter.MediaTypeSuffix,
StringComparison.InvariantCultureIgnoreCase))
{
formatter = jsonFormatter;
}
else
{
throw new InvalidOperationException("Unsupported CloudEvents encoding");
}
}
return formatter.DecodeStructuredEvent(httpRequest.Body, extensions);
}
else
{
CloudEventsSpecVersion version = CloudEventsSpecVersion.Default;
if (httpRequest.Headers[SpecVersionHttpHeader1] != StringValues.Empty)
{
version = CloudEventsSpecVersion.V0_1;
}
if (httpRequest.Headers[SpecVersionHttpHeader2] != StringValues.Empty)
{
version = httpRequest.Headers[SpecVersionHttpHeader2] == "0.2"
? CloudEventsSpecVersion.V0_2
: CloudEventsSpecVersion.Default;
}
var cloudEvent = new CloudEvent(version, extensions);
var attributes = cloudEvent.GetAttributes();
foreach (var httpRequestHeader in httpRequest.Headers.Keys)
{
if (httpRequestHeader.Equals(SpecVersionHttpHeader1,
StringComparison.InvariantCultureIgnoreCase) ||
httpRequestHeader.Equals(SpecVersionHttpHeader2, StringComparison.InvariantCultureIgnoreCase))
{
continue;
}
if (httpRequestHeader.StartsWith(HttpHeaderPrefix, StringComparison.InvariantCultureIgnoreCase))
{
string headerValue = httpRequest.Headers[httpRequestHeader];
if (headerValue.StartsWith("{") && headerValue.EndsWith("}") ||
headerValue.StartsWith("[") && headerValue.EndsWith("]"))
{
attributes[httpRequestHeader.Substring(3)] =
JsonConvert.DeserializeObject(headerValue);
}
else
{
attributes[httpRequestHeader.Substring(3)] = headerValue;
attributes[httpRequestHeader.Substring(3)] = headerValue;
}
}
}
cloudEvent.ContentType = httpRequest.ContentType != null
? new ContentType(httpRequest.ContentType)
: null;
cloudEvent.Data = httpRequest.Body;
return cloudEvent;
}
}
}
}