Skip to content

Commit

Permalink
fix: Use content headers when parsing HTTP requests/responses
Browse files Browse the repository at this point in the history
Fixes #221

Signed-off-by: Jon Skeet <jonskeet@google.com>
  • Loading branch information
jskeet committed Jul 11, 2022
1 parent 3ce4aa0 commit 06fc13c
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 8 deletions.
18 changes: 11 additions & 7 deletions src/CloudNative.CloudEvents/Http/HttpClientExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
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;
Expand Down Expand Up @@ -36,7 +35,7 @@ public static bool IsCloudEvent(this HttpRequestMessage httpRequestMessage)
{
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>
Expand All @@ -48,7 +47,7 @@ public static bool IsCloudEvent(this HttpResponseMessage httpResponseMessage)
{
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>
Expand Down Expand Up @@ -143,9 +142,7 @@ public static bool IsCloudEventBatch(this HttpResponseMessage httpResponseMessag
}
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));
Expand All @@ -154,7 +151,7 @@ public static bool IsCloudEventBatch(this HttpResponseMessage httpResponseMessag
?? 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)
Expand All @@ -174,6 +171,8 @@ public static bool IsCloudEventBatch(this HttpResponseMessage httpResponseMessag
}
return Validation.CheckCloudEventArgument(cloudEvent, paramName);
}


}

/// <summary>
Expand Down Expand Up @@ -345,5 +344,10 @@ public static HttpContent ToHttpContent(this IReadOnlyList<CloudEvent> cloudEven

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;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Net;
using System.Net.Http;
Expand Down Expand Up @@ -40,6 +39,20 @@ public class HttpClientExtensionsTest : HttpTestBase
"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
}
};

Expand Down Expand Up @@ -438,6 +451,32 @@ public async Task ToHttpContent_Batch()
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)
Expand Down

0 comments on commit 06fc13c

Please sign in to comment.