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