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

                byte[] data = async
                    ? await BinaryDataUtilities.ToByteArrayAsync(stream).ConfigureAwait(false)
                    : BinaryDataUtilities.ToByteArray(stream);

                formatter.DecodeBinaryModeEventData(data, cloudEvent);
                return(Validation.CheckCloudEventArgument(cloudEvent, nameof(httpListenerRequest)));
            }
        }
        /// <summary>
        /// Converts this listener request into a CloudEvent object, with the given extension attributes.
        /// </summary>
        /// <param name="httpListenerRequest">Listener request</param>
        /// <param name="formatter"></param>
        /// <param name="extensions">List of extension instances</param>
        /// <returns>The CloudEvent corresponding to the given request.</returns>
        /// <exception cref="ArgumentException">The request does not represent a CloudEvent,
        /// or the event's specification version is not supported,
        /// or the event formatter cannot interpret it.</exception>
        public static CloudEvent ToCloudEvent(this HttpListenerRequest httpListenerRequest,
                                              CloudEventFormatter formatter, params CloudEventAttribute[] extensionAttributes)
        {
            if (HasCloudEventsContentType(httpListenerRequest))
            {
                return(formatter.DecodeStructuredModeMessage(httpListenerRequest.InputStream, MimeUtilities.CreateContentTypeOrNull(httpListenerRequest.ContentType), extensionAttributes));
            }
            else
            {
                string versionId = httpListenerRequest.Headers[HttpUtilities.SpecVersionHttpHeader];
                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);
                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;

                formatter.DecodeBinaryModeEventData(BinaryDataUtilities.ToByteArray(httpListenerRequest.InputStream), cloudEvent);
                return(cloudEvent);
            }
        }