/// <summary>
        /// Converts this HTTP request into a CloudEvent object.
        /// </summary>
        /// <param name="httpRequest">The HTTP request to decode. Must not be null.</param>
        /// <param name="formatter">The event formatter to use to process the request body. Must not be null.</param>
        /// <param name="extensionAttributes">The extension attributes to use when populating the CloudEvent. May be null.</param>
        /// <returns>The decoded CloudEvent.</returns>
        /// <exception cref="ArgumentException">The request does not contain a CloudEvent.</exception>
        public static async Task <CloudEvent> ToCloudEventAsync(
            this HttpRequest httpRequest,
            CloudEventFormatter formatter,
            IEnumerable <CloudEventAttribute>?extensionAttributes)
        {
            Validation.CheckNotNull(httpRequest, nameof(httpRequest));
            Validation.CheckNotNull(formatter, nameof(formatter));
            if (HasCloudEventsContentType(httpRequest))
            {
                var contentType = MimeUtilities.CreateContentTypeOrNull(httpRequest.ContentType);
                return(await formatter.DecodeStructuredModeMessageAsync(httpRequest.Body, contentType, extensionAttributes).ConfigureAwait(false));
            }
            else
            {
                var headers = httpRequest.Headers;
                headers.TryGetValue(HttpUtilities.SpecVersionHttpHeader, out var versionId);
                if (versionId.Count == 0)
                {
                    throw new ArgumentException($"Request does not represent a CloudEvent. It has neither a {HttpUtilities.SpecVersionHttpHeader} header, nor a suitable content type.", nameof(httpRequest));
                }
                var version = CloudEventsSpecVersion.FromVersionId(versionId.FirstOrDefault())
                              ?? throw new ArgumentException($"Unknown CloudEvents spec version '{versionId}'", nameof(httpRequest));

                if (version is null)
                {
                    throw new ArgumentException($"Unsupported CloudEvents spec version '{versionId.First()}'");
                }

                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)
                {
                    ReadOnlyMemory <byte> data = await BinaryDataUtilities.ToReadOnlyMemoryAsync(body).ConfigureAwait(false);

                    formatter.DecodeBinaryModeEventData(data, cloudEvent);
                }
                return(Validation.CheckCloudEventArgument(cloudEvent, nameof(httpRequest)));
            }
        }
        private async static Task <CloudEvent> ToCloudEventAsyncImpl(HttpListenerRequest httpListenerRequest,
                                                                     CloudEventFormatter formatter, IEnumerable <CloudEventAttribute>?extensionAttributes, bool async)
        {
            Validation.CheckNotNull(httpListenerRequest, nameof(httpListenerRequest));
            Validation.CheckNotNull(formatter, nameof(formatter));
            var stream = httpListenerRequest.InputStream;

            if (HasCloudEventsContentType(httpListenerRequest))
            {
                var contentType = MimeUtilities.CreateContentTypeOrNull(httpListenerRequest.ContentType);
                return(async
                    ? await formatter.DecodeStructuredModeMessageAsync(stream, contentType, extensionAttributes).ConfigureAwait(false)
                    : formatter.DecodeStructuredModeMessage(stream, contentType, extensionAttributes));
            }
            else
            {
                string versionId = httpListenerRequest.Headers[HttpUtilities.SpecVersionHttpHeader];
                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(httpListenerRequest));
                }
                var version = CloudEventsSpecVersion.FromVersionId(versionId)
                              ?? throw new ArgumentException($"Unknown CloudEvents spec version '{versionId}'", nameof(httpListenerRequest));

                var cloudEvent = new CloudEvent(version, extensionAttributes);
                var headers    = httpListenerRequest.Headers;
                foreach (var key in headers.AllKeys)
                {
                    string?attributeName = HttpUtilities.GetAttributeNameFromHeaderName(key);
                    if (attributeName is null || attributeName == CloudEventsSpecVersion.SpecVersionAttribute.Name)
                    {
                        continue;
                    }
                    string attributeValue = HttpUtilities.DecodeHeaderValue(headers[key]);
                    cloudEvent.SetAttributeFromString(attributeName, attributeValue);
                }

                // The data content type should not have been set via a "ce-" header; instead,
                // it's in the regular content type.
                cloudEvent.DataContentType = httpListenerRequest.ContentType;

                ReadOnlyMemory <byte> data = async
                    ? await BinaryDataUtilities.ToReadOnlyMemoryAsync(stream).ConfigureAwait(false)
                    : BinaryDataUtilities.ToReadOnlyMemory(stream);

                formatter.DecodeBinaryModeEventData(data, cloudEvent);
                return(Validation.CheckCloudEventArgument(cloudEvent, nameof(httpListenerRequest)));
            }
        }
Exemplo n.º 3
0
        private static async Task <CloudEvent> ToCloudEventInternalAsync(HttpHeaders headers, HttpContent content,
                                                                         CloudEventFormatter formatter, IEnumerable <CloudEventAttribute> extensionAttributes)
        {
            if (HasCloudEventsContentType(content))
            {
                // FIXME: Handle no formatter being specified.
                var stream = await content.ReadAsStreamAsync().ConfigureAwait(false);

                return(await formatter.DecodeStructuredModeMessageAsync(stream, content.Headers.ContentType.ToContentType(), extensionAttributes).ConfigureAwait(false));
            }
            else
            {
                string versionId = headers.Contains(HttpUtilities.SpecVersionHttpHeader)
                    ? headers.GetValues(HttpUtilities.SpecVersionHttpHeader).First()
                    : null;
                if (versionId is null)
                {
                    throw new ArgumentException("Request is not a CloudEvent");
                }
                var version = CloudEventsSpecVersion.FromVersionId(versionId);
                if (version is null)
                {
                    throw new ArgumentException($"Unsupported CloudEvents spec version '{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);

                    formatter.DecodeBinaryModeEventData(data, cloudEvent);
                }
                return(cloudEvent);
            }
        }
Exemplo n.º 4
0
        private static async Task <CloudEvent> ToCloudEventInternalAsync(HttpHeaders headers, HttpContent content,
                                                                         CloudEventFormatter formatter, IEnumerable <CloudEventAttribute>?extensionAttributes, string paramName)
        {
            Validation.CheckNotNull(formatter, nameof(formatter));

            if (HasCloudEventsContentType(content))
            {
                var stream = await content.ReadAsStreamAsync().ConfigureAwait(false);

                return(await formatter.DecodeStructuredModeMessageAsync(stream, MimeUtilities.ToContentType(content.Headers.ContentType), extensionAttributes).ConfigureAwait(false));
            }
            else
            {
                string?versionId = headers.Contains(HttpUtilities.SpecVersionHttpHeader)
                    ? headers.GetValues(HttpUtilities.SpecVersionHttpHeader).First()
                    : null;
                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));
                }
                var version = CloudEventsSpecVersion.FromVersionId(versionId)
                              ?? throw new ArgumentException($"Unknown CloudEvents spec version '{versionId}'", paramName);

                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);

                    formatter.DecodeBinaryModeEventData(data, cloudEvent);
                }
                return(Validation.CheckCloudEventArgument(cloudEvent, paramName));
            }
        }