public void Removed() { if (this.uploadStreamInfo.Stream != null) { this.uploadStreamInfo.Stream.Dispose(); this.uploadStreamInfo = new HTTPRequest.UploadStreamInfo(); } this.outgoing.Clear(); HTTPManager.Logger.Information("HTTP2Stream", "Stream removed: " + this.Id.ToString()); }
private void ProcessState(List <HTTP2FrameHeaderAndPayload> outgoingFrames) { switch (this.State) { case HTTP2StreamStates.Idle: UInt32 initiatedInitialWindowSize = this.settings.InitiatedMySettings[HTTP2Settings.INITIAL_WINDOW_SIZE]; this.localWindow = initiatedInitialWindowSize; // window update with a zero increment would be an error (https://httpwg.org/specs/rfc7540.html#WINDOW_UPDATE) //if (HTTP2Connection.MaxValueFor31Bits > initiatedInitialWindowSize) // this.outgoing.Enqueue(HTTP2FrameHelper.CreateWindowUpdateFrame(this.Id, HTTP2Connection.MaxValueFor31Bits - initiatedInitialWindowSize)); //this.localWindow = HTTP2Connection.MaxValueFor31Bits; #if !BESTHTTP_DISABLE_CACHING // Setup cache control headers before we send out the request if (!this.AssignedRequest.DisableCache) { HTTPCacheService.SetHeaders(this.AssignedRequest); } #endif // hpack encode the request's header this.encoder.Encode(this, this.AssignedRequest, this.outgoing, this.Id); // HTTP/2 uses DATA frames to carry message payloads. // The chunked transfer encoding defined in Section 4.1 of [RFC7230] MUST NOT be used in HTTP/2. this.uploadStreamInfo = this.AssignedRequest.GetUpStream(); //this.State = HTTP2StreamStates.Open; if (this.uploadStreamInfo.Stream == null) { this.State = HTTP2StreamStates.HalfClosedLocal; } else { this.State = HTTP2StreamStates.Open; } break; case HTTP2StreamStates.Open: // remote Window can be negative! See https://httpwg.org/specs/rfc7540.html#InitialWindowSize if (this.remoteWindow <= 0) { HTTPManager.Logger.Warning("HTTP2Stream", string.Format("[{0}] Skipping data sending as remote Window is {1}!", this.Id, this.remoteWindow)); return; } // This step will send one frame per OpenState call. Int64 maxFrameSize = Math.Min(this.remoteWindow, this.settings.RemoteSettings[HTTP2Settings.MAX_FRAME_SIZE]); HTTP2FrameHeaderAndPayload frame = new HTTP2FrameHeaderAndPayload(); frame.Type = HTTP2FrameTypes.DATA; frame.StreamId = this.Id; frame.Payload = BufferPool.Get(maxFrameSize, true); int readCount = this.uploadStreamInfo.Stream.Read(frame.Payload, 0, (int)Math.Min(maxFrameSize, int.MaxValue)); if (readCount <= 0) { BufferPool.Release(frame.Payload); frame.Payload = null; frame.PayloadLength = 0; } else { frame.PayloadLength = (UInt32)readCount; } frame.PayloadOffset = 0; frame.DontUseMemPool = false; if (readCount <= 0) { this.uploadStreamInfo.Stream.Dispose(); this.uploadStreamInfo = new HTTPRequest.UploadStreamInfo(); frame.Flags = (byte)(HTTP2DataFlags.END_STREAM); this.State = HTTP2StreamStates.HalfClosedLocal; } this.outgoing.Enqueue(frame); this.remoteWindow -= frame.PayloadLength; this.sentData += frame.PayloadLength; if (this.AssignedRequest.OnUploadProgress != null) { RequestEventHelper.EnqueueRequestEvent(new RequestEventInfo(this.AssignedRequest, RequestEvents.UploadProgress, this.sentData, this.uploadStreamInfo.Length)); } //HTTPManager.Logger.Information("HTTP2Stream", string.Format("[{0}] New DATA frame created! remoteWindow: {1:N0}", this.Id, this.remoteWindow)); break; case HTTP2StreamStates.HalfClosedLocal: if (this.TimeSpentInCurrentState >= CloseStreamAfter && !this.isStreamedDownload) { this.State = HTTP2StreamStates.Closed; } break; case HTTP2StreamStates.HalfClosedRemote: break; case HTTP2StreamStates.Closed: break; } }