fix: Use content headers when parsing HTTP requests/responses
Fixes #221 Signed-off-by: Jon Skeet <jonskeet@google.com>
This commit is contained in:
parent
3ce4aa08f2
commit
39b691c24a
|
@ -6,7 +6,6 @@ using CloudNative.CloudEvents.Core;
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Net.Mime;
|
||||
|
@ -36,7 +35,7 @@ namespace CloudNative.CloudEvents.Http
|
|||
{
|
||||
Validation.CheckNotNull(httpRequestMessage, nameof(httpRequestMessage));
|
||||
return HasCloudEventsContentType(httpRequestMessage.Content) ||
|
||||
httpRequestMessage.Headers.Contains(HttpUtilities.SpecVersionHttpHeader);
|
||||
(MaybeGetVersionId(httpRequestMessage.Headers) ?? MaybeGetVersionId(httpRequestMessage.Content?.Headers)) is not null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -48,7 +47,7 @@ namespace CloudNative.CloudEvents.Http
|
|||
{
|
||||
Validation.CheckNotNull(httpResponseMessage, nameof(httpResponseMessage));
|
||||
return HasCloudEventsContentType(httpResponseMessage.Content) ||
|
||||
httpResponseMessage.Headers.Contains(HttpUtilities.SpecVersionHttpHeader);
|
||||
(MaybeGetVersionId(httpResponseMessage.Headers) ?? MaybeGetVersionId(httpResponseMessage.Content?.Headers)) is not null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -143,9 +142,7 @@ namespace CloudNative.CloudEvents.Http
|
|||
}
|
||||
else
|
||||
{
|
||||
string? versionId = headers.Contains(HttpUtilities.SpecVersionHttpHeader)
|
||||
? headers.GetValues(HttpUtilities.SpecVersionHttpHeader).First()
|
||||
: null;
|
||||
string? versionId = MaybeGetVersionId(headers) ?? MaybeGetVersionId(content.Headers);
|
||||
if (versionId is null)
|
||||
{
|
||||
throw new ArgumentException($"Request does not represent a CloudEvent. It has neither a {HttpUtilities.SpecVersionHttpHeader} header, nor a suitable content type.", nameof(paramName));
|
||||
|
@ -154,7 +151,7 @@ namespace CloudNative.CloudEvents.Http
|
|||
?? throw new ArgumentException($"Unknown CloudEvents spec version '{versionId}'", paramName);
|
||||
|
||||
var cloudEvent = new CloudEvent(version, extensionAttributes);
|
||||
foreach (var header in headers)
|
||||
foreach (var header in headers.Concat(content.Headers))
|
||||
{
|
||||
string? attributeName = HttpUtilities.GetAttributeNameFromHeaderName(header.Key);
|
||||
if (attributeName is null || attributeName == CloudEventsSpecVersion.SpecVersionAttribute.Name)
|
||||
|
@ -345,5 +342,10 @@ namespace CloudNative.CloudEvents.Http
|
|||
|
||||
private static bool HasCloudEventsBatchContentType(HttpContent content) =>
|
||||
MimeUtilities.IsCloudEventsBatchContentType(content?.Headers?.ContentType?.MediaType);
|
||||
|
||||
private static string? MaybeGetVersionId(HttpHeaders? headers) =>
|
||||
headers is not null && headers.Contains(HttpUtilities.SpecVersionHttpHeader)
|
||||
? headers.GetValues(HttpUtilities.SpecVersionHttpHeader).First()
|
||||
: null;
|
||||
}
|
||||
}
|
|
@ -8,7 +8,6 @@ using CloudNative.CloudEvents.UnitTests;
|
|||
using Newtonsoft.Json.Linq;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
|
@ -40,6 +39,20 @@ namespace CloudNative.CloudEvents.Http.UnitTests
|
|||
"Structured",
|
||||
new StringContent("content is ignored", Encoding.UTF8, "application/cloudevents+json"),
|
||||
null
|
||||
},
|
||||
{
|
||||
"Binary with header in content",
|
||||
new StringContent("header is in the content", Encoding.UTF8, "application/json")
|
||||
{
|
||||
Headers =
|
||||
{
|
||||
{ "ce-specversion", "1.0" },
|
||||
{ "ce-type", "test-type" },
|
||||
{ "ce-id", "test-id" },
|
||||
{ "ce-source", "//test" }
|
||||
}
|
||||
},
|
||||
null
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -438,6 +451,32 @@ namespace CloudNative.CloudEvents.Http.UnitTests
|
|||
AssertBatchesEqual(batch, parsedBatch);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(ContentMode.Binary)]
|
||||
[InlineData(ContentMode.Structured)]
|
||||
public async Task RoundtripRequest(ContentMode contentMode)
|
||||
{
|
||||
var cloudEvent = new CloudEvent().PopulateRequiredAttributes();
|
||||
var formatter = new JsonEventFormatter();
|
||||
var content = cloudEvent.ToHttpContent(contentMode, formatter);
|
||||
var request = new HttpRequestMessage { Content = content };
|
||||
var parsed = await request.ToCloudEventAsync(formatter);
|
||||
AssertCloudEventsEqual(cloudEvent, parsed);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(ContentMode.Binary)]
|
||||
[InlineData(ContentMode.Structured)]
|
||||
public async Task RoundtripResponse(ContentMode contentMode)
|
||||
{
|
||||
var cloudEvent = new CloudEvent().PopulateRequiredAttributes();
|
||||
var formatter = new JsonEventFormatter();
|
||||
var content = cloudEvent.ToHttpContent(contentMode, formatter);
|
||||
var request = new HttpResponseMessage { Content = content };
|
||||
var parsed = await request.ToCloudEventAsync(formatter);
|
||||
AssertCloudEventsEqual(cloudEvent, parsed);
|
||||
}
|
||||
|
||||
internal static void CopyHeaders(IDictionary<string, string>? source, HttpHeaders target)
|
||||
{
|
||||
if (source is null)
|
||||
|
|
Loading…
Reference in New Issue