/// <summary>
        /// Checks if a new compressor object is needed for the stream identified by <c>streamId</c>. This method will
        /// modify the <c>content-encoding</c> header contained in <paramref name="headers"/>.
        /// </summary>
        /// <param name="ctx">the context.</param>
        /// <param name="headers">Object representing headers which are to be written</param>
        /// <param name="endOfStream">Indicates if the stream has ended</param>
        /// <exception cref="Http2Exception">if any problems occur during initialization.</exception>
        /// <returns>The channel used to compress data.</returns>
        private EmbeddedChannel NewCompressor(IChannelHandlerContext ctx, IHttp2Headers headers, bool endOfStream)
        {
            if (endOfStream)
            {
                return(null);
            }


            if (!headers.TryGet(HttpHeaderNames.ContentEncoding, out var encoding))
            {
                encoding = HttpHeaderValues.Identity;
            }
            var compressor = NewContentCompressor(ctx, encoding);

            if (compressor is object)
            {
                var targetContentEncoding = GetTargetContentEncoding(encoding);
                if (HttpHeaderValues.Identity.ContentEqualsIgnoreCase(targetContentEncoding))
                {
                    _ = headers.Remove(HttpHeaderNames.ContentEncoding);
                }
                else
                {
                    _ = headers.Set(HttpHeaderNames.ContentEncoding, targetContentEncoding);
                }

                // The content length will be for the decompressed data. Since we will compress the data
                // this content-length will not be correct. Instead of queuing messages or delaying sending
                // header frames...just remove the content-length header
                _ = headers.Remove(HttpHeaderNames.ContentLength);
            }

            return(compressor);
        }
Exemple #2
0
        /// <summary>
        /// Checks if a new decompressor object is needed for the stream identified by <paramref name="streamId"/>.
        /// This method will modify the <c>content-encoding</c> header contained in <paramref name="headers"/>.
        /// </summary>
        /// <param name="ctx">The context</param>
        /// <param name="streamId">The identifier for the headers inside <paramref name="headers"/></param>
        /// <param name="headers">Object representing headers which have been read</param>
        /// <param name="endOfStream">Indicates if the stream has ended</param>
        /// <exception cref="Http2Exception">If the <c>content-encoding</c> is not supported</exception>
        private void InitDecompressor(IChannelHandlerContext ctx, int streamId, IHttp2Headers headers, bool endOfStream)
        {
            var stream = _connection.Stream(streamId);

            if (stream is null)
            {
                return;
            }

            Http2Decompressor decompressor = Decompressor(stream);

            if (decompressor is null && !endOfStream)
            {
                // Determine the content encoding.
                if (!headers.TryGet(HttpHeaderNames.ContentEncoding, out var contentEncoding))
                {
                    contentEncoding = HttpHeaderValues.Identity;
                }
                EmbeddedChannel channel = NewContentDecompressor(ctx, contentEncoding);
                if (channel is object)
                {
                    decompressor = new Http2Decompressor(channel);
                    _            = stream.SetProperty(_propertyKey, decompressor);
                    // Decode the content and remove or replace the existing headers
                    // so that the message looks like a decoded message.
                    var targetContentEncoding = GetTargetContentEncoding(contentEncoding);
                    if (HttpHeaderValues.Identity.ContentEqualsIgnoreCase(targetContentEncoding))
                    {
                        _ = headers.Remove(HttpHeaderNames.ContentEncoding);
                    }
                    else
                    {
                        _ = headers.Set(HttpHeaderNames.ContentEncoding, targetContentEncoding);
                    }
                }
            }

            if (decompressor is object)
            {
                // The content length will be for the compressed data. Since we will decompress the data
                // this content-length will not be correct. Instead of queuing messages or delaying sending
                // header frames...just remove the content-length header
                _ = headers.Remove(HttpHeaderNames.ContentLength);

                // The first time that we initialize a decompressor, decorate the local flow controller to
                // properly convert consumed bytes.
                if (!_flowControllerInitialized)
                {
                    _flowControllerInitialized = true;
                    var localEndpoint = _connection.Local;
                    localEndpoint.FlowController = new ConsumedBytesConverter(this, localEndpoint.FlowController);
                }
            }
        }