public override async Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
        {
            if (_response.IsFinished)
            {
                throw new InvalidOperationException("The response is already finished and no new data can be written");
            }

            CancellationTokenSource linkedToken = null;

            if (cancellationToken != CancellationToken.None)
            {
                linkedToken =
                    CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, _requestCancellationToken);
                cancellationToken = linkedToken.Token;
            }

            using (linkedToken)
            {
                cancellationToken.ThrowIfCancellationRequested();

                if (!_response.HasStarted)
                {
                    if (!_response.IsCompleted && !_isCompressionEnabled && !_isFinalPackage)
                    {
                        if (_request.GetTypedHeaders().AcceptEncoding
                            ?.Contains(new StringWithQualityHeaderValue("gzip")) == true)
                        {
                            _isCompressionEnabled = true;
                            _response.Headers.Add("Content-Encoding", "gzip");

                            //if the response has not been completed, we compress the body
                            var bodyStream         = (BufferingWriteStream)_response.Body;
                            var newPackagingStream = new BufferingWriteStream(this, _packageBufferSize);

                            var gzipStream = new GZipStream(newPackagingStream, CompressionLevel.Fastest, false);
                            bodyStream.SetInnerStream(gzipStream);

                            bodyStream.FlushCallback = () => newPackagingStream.FlushAsync();

                            await gzipStream.WriteAsync(buffer, offset, count, cancellationToken);

                            return;
                        }
                    }

                    _response.StartResponse();

                    if (!_response.Headers.ContainsKey(MazeHeaders.MazeSocketRequestIdHeader)) //automatically set
                    {
                        throw new InvalidOperationException(
                                  $"Response must have the header {MazeHeaders.MazeSocketRequestIdHeader}");
                    }

                    var sendBuffer = ArrayPool <byte> .Shared.Rent(count + _maxHeaderSize);

                    var headerOffset = HttpFormatter.FormatResponse(_response, new ArraySegment <byte>(sendBuffer));
                    if (headerOffset > _maxHeaderSize)
                    {
                        throw new InvalidOperationException(
                                  $"The header size {headerOffset}B exceeds the maximum allowed header size ({_maxHeaderSize}B)");
                    }

                    if (count > 0)
                    {
                        Buffer.BlockCopy(buffer, offset, sendBuffer, headerOffset, count);
                    }

                    Logger.LogDataPackage("Send HTTP Response", sendBuffer, 0, headerOffset + count);
                    await SendData(new ArraySegment <byte>(sendBuffer, 0, headerOffset + count));
                }
                else
                {
                    var sendBuffer = ArrayPool <byte> .Shared.Rent(count + 4);

                    Buffer.BlockCopy(buffer, offset, sendBuffer, 4, count);
                    BinaryUtils.WriteInt32(ref sendBuffer, 0, _response.RequestId);

                    await SendData(new ArraySegment <byte>(sendBuffer, 0, count + 4));
                }
            }
        }
Exemple #2
0
 public PackagingBufferStreamTests()
 {
     _stream = new BufferingWriteStream(new DelegatingWriteStream(SendPackageDelegate), DataSize, ArrayPool <byte> .Shared);
 }