Skip to content

Commit 62da9c0

Browse files
committed
Fix case sensitivity issues
- Web hook method must be exactly "OPTIONS" - Kafka header keys are case sensitive Fixes #90 Signed-off-by: Jon Skeet <[email protected]>
1 parent e197ef0 commit 62da9c0

File tree

4 files changed

+31
-17
lines changed

4 files changed

+31
-17
lines changed

src/CloudNative.CloudEvents.Kafka/KafkaClientExtensions.cs

Lines changed: 10 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,6 @@ public static class KafkaClientExtensions
2323
private const string KafkaContentTypeAttributeName = "content-type";
2424
private const string SpecVersionKafkaHeader = KafkaHeaderPrefix + "specversion";
2525

26-
// TODO: Avoid all the byte[] -> string conversions? If we didn't care about case-sensitivity, we could prepare byte arrays to perform comparisons with.
27-
2826
/// <summary>
2927
/// Indicates whether this message holds a single CloudEvent.
3028
/// </summary>
@@ -35,7 +33,7 @@ public static class KafkaClientExtensions
3533
/// <returns>true, if the request is a CloudEvent</returns>
3634
public static bool IsCloudEvent(this Message<string, byte[]> message) =>
3735
GetHeaderValue(message, SpecVersionKafkaHeader) is object ||
38-
MimeUtilities.IsCloudEventsContentType(ExtractContentType(message));
36+
MimeUtilities.IsCloudEventsContentType(GetHeaderValue(message, KafkaContentTypeAttributeName));
3937

4038
/// <summary>
4139
/// Converts this Kafka message into a CloudEvent object.
@@ -66,7 +64,7 @@ public static CloudEvent ToCloudEvent(this Message<string, byte[]> message,
6664
throw new InvalidOperationException();
6765
}
6866

69-
var contentType = ExtractContentType(message);
67+
var contentType = GetHeaderValue(message, KafkaContentTypeAttributeName);
7068

7169
CloudEvent cloudEvent;
7270

@@ -78,11 +76,10 @@ public static CloudEvent ToCloudEvent(this Message<string, byte[]> message,
7876
else
7977
{
8078
// Binary mode
81-
if (!(GetHeaderValue(message, SpecVersionKafkaHeader) is byte[] versionIdBytes))
79+
if (!(GetHeaderValue(message, SpecVersionKafkaHeader) is string versionId))
8280
{
8381
throw new ArgumentException("Request is not a CloudEvent");
8482
}
85-
string versionId = Encoding.UTF8.GetString(versionIdBytes);
8683
CloudEventsSpecVersion version = CloudEventsSpecVersion.FromVersionId(versionId)
8784
?? throw new ArgumentException($"Unknown CloudEvents spec version '{versionId}'", nameof(message));
8885

@@ -115,12 +112,6 @@ public static CloudEvent ToCloudEvent(this Message<string, byte[]> message,
115112
return Validation.CheckCloudEventArgument(cloudEvent, nameof(message));
116113
}
117114

118-
private static string ExtractContentType(Message<string, byte[]> message)
119-
{
120-
var headerValue = GetHeaderValue(message, KafkaContentTypeAttributeName);
121-
return headerValue is null ? null : Encoding.UTF8.GetString(headerValue);
122-
}
123-
124115
private static void InitPartitioningKey(Message<string, byte[]> message, CloudEvent cloudEvent)
125116
{
126117
if (!string.IsNullOrEmpty(message.Key))
@@ -129,9 +120,13 @@ private static void InitPartitioningKey(Message<string, byte[]> message, CloudEv
129120
}
130121
}
131122

132-
private static byte[] GetHeaderValue(MessageMetadata message, string headerName) =>
133-
message.Headers.FirstOrDefault(x => string.Equals(x.Key, headerName, StringComparison.InvariantCultureIgnoreCase))
134-
?.GetValueBytes();
123+
/// <summary>
124+
/// Returns the last header value with the given name, decoded using UTF-8, or null if there is no such header.
125+
/// </summary>
126+
private static string GetHeaderValue(MessageMetadata message, string headerName) =>
127+
Validation.CheckNotNull(message, nameof(message)).Headers is null
128+
? null
129+
: message.Headers.TryGetLastBytes(headerName, out var bytes) ? Encoding.UTF8.GetString(bytes) : null;
135130

136131
/// <summary>
137132
/// Converts a CloudEvent to a Kafka message.

src/CloudNative.CloudEvents/Http/HttpClientExtensions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ public static bool IsCloudEventBatch(this HttpResponseMessage httpResponseMessag
108108
/// Indicates whether this HttpListenerRequest is a web hook validation request
109109
/// </summary>
110110
public static bool IsWebHookValidationRequest(this HttpRequestMessage httpRequestMessage) =>
111-
httpRequestMessage.Method.Method.Equals("options", StringComparison.InvariantCultureIgnoreCase) &&
111+
httpRequestMessage.Method.Method == "OPTIONS" &&
112112
httpRequestMessage.Headers.Contains("WebHook-Request-Origin");
113113

114114
/// <summary>

src/CloudNative.CloudEvents/Http/HttpListenerExtensions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ public static bool IsCloudEvent(this HttpListenerRequest httpListenerRequest) =>
140140
/// Indicates whether this HttpListenerRequest is a web hook validation request
141141
/// </summary>
142142
public static bool IsWebHookValidationRequest(this HttpListenerRequest httpRequestMessage) =>
143-
httpRequestMessage.HttpMethod.Equals("options", StringComparison.InvariantCultureIgnoreCase) &&
143+
httpRequestMessage.HttpMethod == "OPTIONS" &&
144144
httpRequestMessage.Headers["WebHook-Request-Origin"] is object;
145145

146146
/// <summary>

test/CloudNative.CloudEvents.UnitTests/Kafka/KafkaTest.cs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,25 @@ namespace CloudNative.CloudEvents.Kafka.UnitTests
1717
{
1818
public class KafkaTest
1919
{
20+
[Theory]
21+
[InlineData("content-type", "application/cloudevents", true)]
22+
[InlineData("content-type", "APPLICATION/CLOUDEVENTS", true)]
23+
[InlineData("CONTENT-TYPE", "application/cloudevents", false)]
24+
[InlineData("ce_specversion", "1.0", true)]
25+
[InlineData("CE_SPECVERSION", "1.0", false)]
26+
public void IsCloudEvent(string headerName, string headerValue, bool expectedResult)
27+
{
28+
var message = new Message<string, byte[]>
29+
{
30+
Headers = new Headers { { headerName, Encoding.UTF8.GetBytes(headerValue) } }
31+
};
32+
Assert.Equal(expectedResult, message.IsCloudEvent());
33+
}
34+
35+
[Fact]
36+
public void IsCloudEvent_NoHeaders() =>
37+
Assert.False(new Message<string, byte[]>().IsCloudEvent());
38+
2039
[Fact]
2140
public void KafkaStructuredMessageTest()
2241
{

0 commit comments

Comments
 (0)