/// <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);
            }
        }
Example #2
0
        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);
            }
        }