public async Task WriteTrailersAsync(IEnumerable <HeaderField> headers) { HeaderValidationResult hvr = HeaderValidator.ValidateTrailingHeaders(headers); if (hvr != HeaderValidationResult.Ok) { throw new Exception(hvr.ToString()); } var removeStream = false; await writeMutex.WaitAsync(); try { lock (stateMutex) { if (!dataSent) { throw new Exception("试图在没有数据的情况下写入"); } switch (state) { case StreamState.Open: state = StreamState.HalfClosedLocal; break; case StreamState.HalfClosedRemote: state = StreamState.HalfClosedRemote; state = StreamState.Closed; removeStream = true; break; case StreamState.Idle: case StreamState.ReservedRemote: case StreamState.HalfClosedLocal: case StreamState.Closed: throw new Exception("发送的状态无效"); case StreamState.Reset: throw new StreamResetException(); case StreamState.ReservedLocal: throw new Exception("意外状态:发送数据后保留本地"); } } await SendHeaders(headers, true); // TODO: Use result } finally { writeMutex.Release(); if (removeStream) { connection.UnregisterStream(this); } } }
/// <summary> /// ServerUpgradeRequest /// </summary> /// <returns></returns> public ServerUpgradeRequest Build() { bool valid = true; if (settings == null) { valid = false; } var headers = this.headers; if (headers == null) { valid = false; } else { var hvr = HeaderValidator.ValidateRequestHeaders(headers); if (hvr != HeaderValidationResult.Ok) { headers = null; valid = false; } } long declaredContentLength = -1; if (headers != null) { declaredContentLength = headers.GetContentLength(); } byte[] payload = null; if (this.payload != null && this.payload.Count > 0) { if (declaredContentLength != this.payload.Count) { valid = false; } else { payload = new byte[this.payload.Count]; Array.Copy( this.payload.Array, this.payload.Offset, payload, 0, this.payload.Count); } } else if (declaredContentLength > 0) { valid = false; } return(new ServerUpgradeRequest( settings: settings ?? Settings.Default, headers: headers, payload: payload, valid: valid)); }
public Task WriteHeadersAsync( IEnumerable <HeaderField> headers, bool endOfStream) { HeaderValidationResult hvr; if (connection.IsServer) { hvr = HeaderValidator.ValidateResponseHeaders(headers); } else { hvr = HeaderValidator.ValidateRequestHeaders(headers); } if (hvr != HeaderValidationResult.Ok) { throw new Exception(hvr.ToString()); } return(WriteValidatedHeadersAsync(headers, endOfStream)); }
/// <summary> /// 在连接顶部创建新流。 /// </summary> /// <param name="headers"></param> /// <param name="endOfStream"></param> /// <returns></returns> public async Task <IStream> CreateStreamAsync(IEnumerable <HeaderField> headers, bool endOfStream = false) { if (config.IsServer) { throw new NotSupportedException("只能为客户端创建流"); } var hvr = HeaderValidator.ValidateRequestHeaders(headers); if (hvr != HeaderValidationResult.Ok) { throw new Exception(hvr.ToString()); } await clientState.CreateStreamMutex.WaitAsync(); try { uint streamId = 0u; StreamImpl stream = null; lock (shared.Mutex) { if (shared.Closed) { throw new ConnectionClosedException(); } if (shared.LastOutgoingStreamId == 0) { shared.LastOutgoingStreamId = 1; } else if (shared.LastOutgoingStreamId <= int.MaxValue - 2) { shared.LastOutgoingStreamId += 2; } else { throw new ConnectionExhaustedException(); } streamId = shared.LastOutgoingStreamId; stream = new StreamImpl( this, streamId, StreamState.Idle, (int)localSettings.InitialWindowSize); shared.streamMap[streamId] = stream; } if (!writer.RegisterStream(streamId)) { throw new ConnectionClosedException(); } try { await stream.WriteValidatedHeadersAsync(headers, endOfStream); } catch (Exception) { throw new ConnectionClosedException(); } return(stream); } finally { clientState.CreateStreamMutex.Release(); } }
/// <summary> /// 处理传入头的接收 /// </summary> public Http2Error?ProcessHeaders( CompleteHeadersFrameData headers) { var wakeupDataWaiter = false; var wakeupHeaderWaiter = false; var wakeupTrailerWaiter = false; var removeStream = false; lock (stateMutex) { switch (state) { case StreamState.ReservedLocal: case StreamState.ReservedRemote: return(new Http2Error { StreamId = Id, Code = ErrorCode.InternalError, Message = "接收到的头帧处于未覆盖的推送约定状态", }); case StreamState.Idle: case StreamState.Open: case StreamState.HalfClosedLocal: if (headersReceived != HeaderReceptionState.ReceivedAllHeaders) { HeaderValidationResult hvr; if (connection.IsServer) { hvr = HeaderValidator.ValidateRequestHeaders(headers.Headers); } else { hvr = HeaderValidator.ValidateResponseHeaders(headers.Headers); } if (hvr != HeaderValidationResult.Ok) { return(new Http2Error { StreamId = Id, Code = ErrorCode.ProtocolError, Message = "Received invalid headers", }); } if (!connection.config.IsServer && headers.Headers.IsInformationalHeaders()) { headersReceived = HeaderReceptionState.ReceivedInformationalHeaders; } else { headersReceived = HeaderReceptionState.ReceivedAllHeaders; } wakeupHeaderWaiter = true; declaredInContentLength = headers.Headers.GetContentLength(); inHeaders = headers.Headers; } else if (!dataReceived) { return(new Http2Error { StreamId = Id, Code = ErrorCode.ProtocolError, Message = "接收的无标题", }); } else { if (!headers.EndOfStream) { return(new Http2Error { StreamId = Id, Code = ErrorCode.ProtocolError, Message = "接收到没有endofstream标志", }); } var hvr = HeaderValidator.ValidateTrailingHeaders(headers.Headers); if (hvr != HeaderValidationResult.Ok) { return(new Http2Error { StreamId = Id, Code = ErrorCode.ProtocolError, Message = "接收到无效", }); } if (declaredInContentLength >= 0 && declaredInContentLength != totalInData) { return(new Http2Error { StreamId = Id, Code = ErrorCode.ProtocolError, Message = "数据帧的长度与内容长度不匹配", }); } wakeupTrailerWaiter = true; inTrailers = headers.Headers; } if (state == StreamState.Idle) { state = StreamState.Open; } if (headers.EndOfStream) { if (state == StreamState.HalfClosedLocal) { state = StreamState.Closed; removeStream = true; } else { state = StreamState.HalfClosedRemote; } wakeupTrailerWaiter = true; wakeupDataWaiter = true; } break; case StreamState.HalfClosedRemote: case StreamState.Closed: return(new Http2Error { Code = ErrorCode.StreamClosed, StreamId = Id, Message = "已接收封闭流的头", }); case StreamState.Reset: break; default: throw new Exception("未处理的流状态"); } } if (wakeupHeaderWaiter) { readHeadersPossible.Set(); } if (wakeupDataWaiter) { readDataPossible.Set(); } if (wakeupTrailerWaiter) { readTrailersPossible.Set(); } if (removeStream) { connection.UnregisterStream(this); } return(null); }