/// <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, ICloudEventFormatter 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 async Task <CloudEvent> ToCloudEventInternalAsync(HttpHeaders headers, HttpContent content, ICloudEventFormatter formatter, IEnumerable <CloudEventAttribute> extensionAttributes) { if (HasCloudEventsContentType(content)) { // FIXME: Handle no formatter being specified. var stream = await content.ReadAsStreamAsync().ConfigureAwait(false); return(await formatter.DecodeStructuredEventAsync(stream, extensionAttributes).ConfigureAwait(false)); } else { CloudEventsSpecVersion version = CloudEventsSpecVersion.Default; if (headers.Contains(HttpUtilities.SpecVersionHttpHeader)) { string versionId = headers.GetValues(HttpUtilities.SpecVersionHttpHeader).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); } if (content is object) { // TODO: Should this just be the media type? We probably need to take a full audit of this... cloudEvent.DataContentType = content.Headers?.ContentType?.ToString(); var data = await content.ReadAsByteArrayAsync().ConfigureAwait(false); cloudEvent.Data = formatter.DecodeData(data, cloudEvent.DataContentType); } return(cloudEvent); } }
/// <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 async ValueTask <CloudEvent> ReadCloudEventAsync(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 var contentType = httpRequest.ContentType.Split(';')[0].Trim(); if (contentType.EndsWith(JsonEventFormatter.MediaTypeSuffix, StringComparison.InvariantCultureIgnoreCase)) { formatter = jsonFormatter; } else { throw new InvalidOperationException("Unsupported CloudEvents encoding"); } } return(await formatter.DecodeStructuredEventAsync(httpRequest.Body, extensions)); } else { CloudEventsSpecVersion version = CloudEventsSpecVersion.Default; if (httpRequest.Headers[SpecVersionHttpHeader1] != StringValues.Empty) { version = CloudEventsSpecVersion.V0_1; } if (httpRequest.Headers[SpecVersionHttpHeader2] != StringValues.Empty) { switch (httpRequest.Headers[SpecVersionHttpHeader2]) { case "0.2": version = CloudEventsSpecVersion.V0_2; break; case "0.3": version = CloudEventsSpecVersion.V0_3; break; default: version = CloudEventsSpecVersion.Default; break; } } 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 = WebUtility.UrlDecode(httpRequest.Headers[httpRequestHeader]); // maps in headers have been abolished in 1.0 if (version != CloudEventsSpecVersion.V1_0 && headerValue.StartsWith("{") && headerValue.EndsWith("}") || headerValue.StartsWith("[") && headerValue.EndsWith("]")) { attributes[httpRequestHeader.Substring(3)] = JsonConvert.DeserializeObject(headerValue); } else { attributes[httpRequestHeader.Substring(3)] = headerValue; } } } cloudEvent.DataContentType = httpRequest.ContentType != null ? new ContentType(httpRequest.ContentType) : null; cloudEvent.Data = await new StreamReader(httpRequest.Body, Encoding.UTF8).ReadToEndAsync(); return(cloudEvent); } }