public static async Task WriteContinuation(
            this IWriteAndCloseableByteStream stream,
            Encoder encoder,
            uint streamId,
            IEnumerable <HeaderField> headers,
            bool endOfHeaders = true)
        {
            var outBuf = new byte[Settings.Default.MaxFrameSize];
            var result = encoder.EncodeInto(new ArraySegment <byte>(outBuf), headers);

            // Check if all headers could be encoded
            if (result.FieldCount != headers.Count())
            {
                throw new Exception("Could not encode all headers");
            }

            byte flags = 0;

            if (endOfHeaders)
            {
                flags |= (byte)ContinuationFrameFlags.EndOfHeaders;
            }
            var fh = new FrameHeader
            {
                Type     = FrameType.Continuation,
                Length   = result.UsedBytes,
                Flags    = flags,
                StreamId = streamId,
            };
            await stream.WriteFrameHeader(fh);

            await stream.WriteAsync(
                new ArraySegment <byte>(outBuf, 0, result.UsedBytes));
        }
 public static async Task WriteSettingsAck(
     this IWriteAndCloseableByteStream stream)
 {
     var fh = new FrameHeader
     {
         Type     = FrameType.Settings,
         Length   = 0,
         Flags    = (byte)SettingsFrameFlags.Ack,
         StreamId = 0,
     };
     await stream.WriteFrameHeader(fh);
 }
        public static async Task WritePing(
            this IWriteAndCloseableByteStream stream, byte[] data, bool isAck)
        {
            var pingHeader = new FrameHeader
            {
                Type     = FrameType.Ping,
                Flags    = isAck ? (byte)PingFrameFlags.Ack : (byte)0,
                Length   = 8,
                StreamId = 0,
            };
            await stream.WriteFrameHeader(pingHeader);

            await stream.WriteAsync(new ArraySegment <byte>(data, 0, 8));
        }
        public static async Task WriteFrameHeaderWithTimeout(
            this IWriteAndCloseableByteStream stream,
            FrameHeader fh)
        {
            var writeTask   = stream.WriteFrameHeader(fh);
            var timeoutTask = Task.Delay(WriteTimeout);
            var combined    = Task.WhenAny(new Task[] { writeTask, timeoutTask });
            var done        = await combined;

            if (done == writeTask)
            {
                await writeTask;
                return;
            }
            throw new TimeoutException();
        }
        public static async Task WriteSettings(
            this IWriteAndCloseableByteStream stream, Settings settings)
        {
            var settingsData = new byte[settings.RequiredSize];
            var fh           = new FrameHeader
            {
                Type     = FrameType.Settings,
                Length   = settingsData.Length,
                Flags    = 0,
                StreamId = 0,
            };

            settings.EncodeInto(new ArraySegment <byte>(settingsData));
            await stream.WriteFrameHeader(fh);

            await stream.WriteAsync(new ArraySegment <byte>(settingsData));
        }
        public static async Task WriteData(
            this IWriteAndCloseableByteStream stream,
            uint streamId,
            int length,
            int?padLen       = null,
            bool endOfStream = false)
        {
            byte flags = 0;

            if (endOfStream)
            {
                flags |= (byte)DataFrameFlags.EndOfStream;
            }
            if (padLen.HasValue)
            {
                flags |= (byte)DataFrameFlags.Padded;
            }

            var dataLen = length;

            if (padLen.HasValue)
            {
                dataLen += 1 + padLen.Value;
            }
            var data = new byte[dataLen];

            if (padLen.HasValue)
            {
                data[0] = (byte)padLen.Value;
            }

            var fh = new FrameHeader
            {
                Type     = FrameType.Data,
                Length   = dataLen,
                Flags    = flags,
                StreamId = streamId,
            };
            await stream.WriteFrameHeader(fh);

            if (dataLen != 0)
            {
                await stream.WriteWithTimeout(new ArraySegment <byte>(data));
            }
        }
        public static async Task WritePriority(
            this IWriteAndCloseableByteStream stream,
            uint streamId, PriorityData prioData)
        {
            var fh = new FrameHeader
            {
                Type     = FrameType.Priority,
                Flags    = 0,
                Length   = PriorityData.Size,
                StreamId = streamId,
            };
            await stream.WriteFrameHeader(fh);

            var payload = new byte[PriorityData.Size];

            prioData.EncodeInto(new ArraySegment <byte>(payload));
            await stream.WriteAsync(new ArraySegment <byte>(payload));
        }
        public static async Task WriteResetStream(
            this IWriteAndCloseableByteStream stream, uint streamId, ErrorCode errc)
        {
            var fh = new FrameHeader
            {
                Type     = FrameType.ResetStream,
                Flags    = 0,
                Length   = ResetFrameData.Size,
                StreamId = streamId,
            };
            var data = new ResetFrameData
            {
                ErrorCode = errc,
            };
            var dataBytes = new byte[ResetFrameData.Size];

            data.EncodeInto(new ArraySegment <byte>(dataBytes));
            await stream.WriteFrameHeader(fh);

            await stream.WriteAsync(new ArraySegment <byte>(dataBytes));
        }
        public static async Task WriteWindowUpdate(
            this IWriteAndCloseableByteStream stream, uint streamId, int amount)
        {
            var windowUpdateHeader = new FrameHeader
            {
                Type     = FrameType.WindowUpdate,
                Flags    = 0,
                Length   = WindowUpdateData.Size,
                StreamId = streamId,
            };
            var data = new WindowUpdateData
            {
                WindowSizeIncrement = amount,
            };
            var dataBytes = new byte[WindowUpdateData.Size];

            data.EncodeInto(new ArraySegment <byte>(dataBytes));
            await stream.WriteFrameHeader(windowUpdateHeader);

            await stream.WriteAsync(new ArraySegment <byte>(dataBytes));
        }
        public static async Task WriteGoAway(
            this IWriteAndCloseableByteStream stream,
            uint lastStreamId,
            ErrorCode errc,
            byte[] debugData = null)
        {
            if (debugData == null)
            {
                debugData = new byte[0];
            }

            var goAwayData = new GoAwayFrameData
            {
                Reason = new GoAwayReason
                {
                    LastStreamId = lastStreamId,
                    ErrorCode    = errc,
                    DebugData    = new ArraySegment <byte>(debugData),
                },
            };

            var fh = new FrameHeader
            {
                Type     = FrameType.GoAway,
                Flags    = 0,
                StreamId = 0,
                Length   = goAwayData.RequiredSize,
            };

            var dataBytes = new byte[goAwayData.RequiredSize];

            goAwayData.EncodeInto(new ArraySegment <byte>(dataBytes));
            await stream.WriteFrameHeader(fh);

            await stream.WriteAsync(new ArraySegment <byte>(dataBytes));
        }