/// <inheritdoc /> public async Task SendResponseAsync(HttpResponse response) { manager.ServerConfiguration.AddServerHeaders(response); var frames = HeaderHelper.GenerateFrames(response, frameIdentifier, manager.MaximumFrameSize, response.DataStream == null); foreach (var frame in frames) { manager.SendFrame(frame); } frames = GenerateDataFrames(response); foreach (var frame in frames) { manager.SendFrame(frame); } }
private void ReadHeadersFrame([NotNull] Frame frame) { if (frame.Identifier == 0) { throw new ConnectionException(frame.Identifier, ErrorCode.Protocol); } var endStream = frame.Flags.HasFlag(FrameFlags.EndStream); var endHeaders = frame.Flags.HasFlag(FrameFlags.EndHeaders); var padded = frame.Flags.HasFlag(FrameFlags.Padded); var priority = frame.Flags.HasFlag(FrameFlags.Priority); var stream = GetStream(frame.Identifier); switch (stream.State) { case StreamState.Idle: break; case StreamState.HeadersExpectingContinuation: throw new ConnectionException(frame.Identifier, ErrorCode.Protocol); case StreamState.Open: if (!endStream) { throw new ConnectionException(frame.Identifier, ErrorCode.Protocol); } if (!endHeaders) { throw new NotImplementedException(); } stream.State = StreamState.HalfClosedRemote; stream.TwoWayStream.CloseRead(); // TODO: Read chunked headers return; case StreamState.HalfClosedRemote: case StreamState.Reset: case StreamState.Closed: throw new ConnectionException(frame.Identifier, ErrorCode.Protocol); default: throw new ArgumentOutOfRangeException(); } byte paddingLength = 0; StreamState nextState; if (endStream) { nextState = StreamState.HalfClosedRemote; } else if (endHeaders) { nextState = StreamState.Open; } else { nextState = StreamState.HeadersExpectingContinuation; } if (padded) { paddingLength = frame.ReadByte(); } if (priority) { var streamDependancy = frame.ReadUInt32(); var exclusive = streamDependancy & 0x80000000; streamDependancy &= 0x7FFFFFFF; var weight = frame.ReadByte(); // TODO } if (paddingLength + frame.Pointer > frame.Length) { throw new ConnectionException(frame.Identifier, ErrorCode.Protocol); } try { var headerHelper = new HeaderHelper(frame); var readAllStatus = false; while (frame.Pointer < frame.Length - paddingLength) { var(headerName, headerValue) = headerHelper.ReadValue(); switch (headerName) { case ":authority": if (readAllStatus) { throw new StreamException(frame.Identifier, ErrorCode.Protocol); } stream.Authority = headerValue; break; case ":method": if (readAllStatus) { throw new StreamException(frame.Identifier, ErrorCode.Protocol); } stream.Method = headerValue; break; case ":path": if (readAllStatus) { throw new StreamException(frame.Identifier, ErrorCode.Protocol); } stream.Path = headerValue; break; case ":scheme": if (readAllStatus) { throw new StreamException(frame.Identifier, ErrorCode.Protocol); } stream.Scheme = headerValue; break; case ":status": throw new StreamException(frame.Identifier, ErrorCode.Protocol); default: if (headerName.StartsWith(":", StringComparison.InvariantCulture)) { throw new StreamException(frame.Identifier, ErrorCode.Protocol); } readAllStatus = true; stream.Headers.Add((headerName, headerValue)); break; } } } catch (CompressionException e) { throw new ConnectionException(frame.Identifier, ErrorCode.Compression, e); } stream.State = nextState; if (endHeaders) { taskFactory.StartNew(() => stream.SendHeaders(processClient)); } }