Ejemplo n.º 1
0
        public void WriteRst(ResetStatusCode code)
        {
            if (Closed)
                return;

            var frame = new RstStreamFrame(_id, code);
            
            _writeQueue.WriteFrame(frame);

            if (OnFrameSent != null)
            {
                OnFrameSent(this, new FrameSentEventArgs(frame));
            }
        }
        private void HandleRstFrame(RstStreamFrame resetFrame, out Http2Stream stream)
        {
            stream = GetStream(resetFrame.StreamId);

            //Spec 06 tells that impl MUST not answer with rst on rst to avoid loop.
            if (stream != null)
            {
                Http2Logger.LogDebug("RST frame with code {0} for id {1}", resetFrame.StatusCode,
                                        resetFrame.StreamId);
                stream.Dispose(ResetStatusCode.None);
            }
            //Do not signal an error because (06)
            //WINDOW_UPDATE [WINDOW_UPDATE], PRIORITY [PRIORITY], or RST_STREAM
            //[RST_STREAM] frames can be received in this state for a short
            //period after a frame containing an END_STREAM flag is sent.
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Dispatches the incoming frame.
        /// </summary>
        /// <param name="frame">The frame.</param>
        /// <exception cref="System.NotImplementedException"></exception>
        private void DispatchIncomingFrame(Frame frame)
        {
            Http2Stream stream = null;
            
            try
            {
                if (frame.PayloadLength > Constants.MaxFramePayloadSize)
                {
                    throw new ProtocolError(ResetStatusCode.FrameSizeError,
                                            String.Format("Frame too large: Type: {0} {1}", frame.FrameType,
                                                          frame.PayloadLength));
                }

                /* 12 -> 6.5
                A SETTINGS frame MUST be sent by both endpoints at the start of a
                connection, and MAY be sent at any other time by either endpoint over
                the lifetime of the connection.*/
                if (frame.FrameType != FrameType.Settings && !_wasSettingsReceived)
                {
                    throw new ProtocolError(ResetStatusCode.ProtocolError,
                                            "Settings frame was not the first frame in the session");
                }

                Http2Logger.LogDebug("Incoming frame: " + frame.FrameType);

                switch (frame.FrameType)
                {
                    case FrameType.Headers:
                        HandleHeaders(frame as HeadersFrame, out stream);
                        break;
                    case FrameType.Continuation:
                        HandleContinuation(frame as ContinuationFrame, out stream);
                        break;
                    case FrameType.Priority:
                        HandlePriority(frame as PriorityFrame, out stream);
                        break;
                    case FrameType.RstStream:
                        HandleRstFrame(frame as RstStreamFrame, out stream);
                        break;
                    case FrameType.Data:
                        HandleDataFrame(frame as DataFrame, out stream);
                        break;
                    case FrameType.Ping:
                        HandlePingFrame(frame as PingFrame);
                        break;
                    case FrameType.Settings:
                        HandleSettingsFrame(frame as SettingsFrame);
                        if (!(frame as SettingsFrame).IsAck)
                        {
                            // sending ACK settings
                            WriteSettings(new SettingsPair[0], true);
                        }
                        break;
                    case FrameType.WindowUpdate:
                        HandleWindowUpdateFrame(frame as WindowUpdateFrame, out stream);
                        break;
                    case FrameType.GoAway:
                        HandleGoAwayFrame(frame as GoAwayFrame);
                        break;
                    case FrameType.PushPromise:
                        HandlePushPromiseFrame(frame as PushPromiseFrame, out stream);
                        if (stream != null) //This means that sequence is complete
                        {
                            _promisedResources.Add(stream.Id, stream.Headers.GetValue(CommonHeaders.Path));
                        }
                        break;
                    case FrameType.AltSvc:
                        HandleAltSvcFrame(frame);
                        break;                  
                    case FrameType.Blocked:
                        HandleBlockedFrame(frame);
                        break;
                    default:
                        /* 12 -> 4.1
                        Implementations MUST treat the receipt of an unknown frame type
                        (any frame types not defined in this document) as a connection
                        error of type PROTOCOL_ERROR. */
                        throw new ProtocolError(ResetStatusCode.ProtocolError, "Unknown frame type detected");
                }

                _lastFrame = frame;

                if (frame is IEndStreamFrame && ((IEndStreamFrame) frame).IsEndStream)
                {
                    //Tell the stream that it was the last frame
                    Http2Logger.LogDebug("Final frame received for stream id=" + stream.Id);
                    stream.HalfClosedRemote = true;

                    //Promised resource has been pushed
                    if (_promisedResources.ContainsKey(stream.Id))
                        _promisedResources.Remove(stream.Id);
                }

                if (stream == null || OnFrameReceived == null) 
                    return;

                OnFrameReceived(this, new FrameReceivedEventArgs(stream, frame));
                stream.FramesReceived++;
            }

            //09
            //5.1.  Stream States
            //An endpoint MUST NOT send frames on a closed stream.  An endpoint
            //that receives a frame after receiving a RST_STREAM [RST_STREAM] or
            //a frame containing a END_STREAM flag on that stream MUST treat
            //that as a stream error (Section 5.4.2) of type STREAM_CLOSED
            //[STREAM_CLOSED].
            catch (Http2StreamNotFoundException ex)
            {
                Http2Logger.LogDebug("Frame for already Closed stream with stream id={0}", ex.Id);
                var rstFrame = new RstStreamFrame(ex.Id, ResetStatusCode.StreamClosed);

                Http2Logger.LogDebug("Sending RST_STREAM frame: stream id={0}, status code={1}",
                    rstFrame.StreamId, rstFrame.StatusCode);

                _writeQueue.WriteFrame(rstFrame);
                stream.WasRstSent = true;
            }
            catch (CompressionError ex)
            {
                //The endpoint is unable to maintain the compression context for the connection.
                Http2Logger.LogError("Compression error occurred: " + ex.Message);
                Close(ResetStatusCode.CompressionError);
            }
            catch (ProtocolError pEx)
            {
                Http2Logger.LogError("Protocol error occurred: " + pEx.Message);
                Close(pEx.Code);
            }
            catch (MaxConcurrentStreamsLimitException)
            {
                //Remote side tries to open more streams than allowed
                Dispose();
            }
            catch (Exception ex)
            {
                Http2Logger.LogError("Unknown error occurred: " + ex.Message);
                Close(ResetStatusCode.InternalError);
            }
        }
        private void HandleRstFrame(RstStreamFrame resetFrame, out Http2Stream stream)
        {
            //spec 09
            //6.4.  RST_STREAM
            //RST_STREAM frames MUST be associated with a stream.  If a RST_STREAM
            //frame is received with a stream identifier of 0x0, the recipient MUST
            //treat this as a connection error (Section 5.4.1) of type
            //PROTOCOL_ERROR.
            if (resetFrame.StreamId == 0)
            {
                throw new ProtocolError(ResetStatusCode.ProtocolError, "resetFrame with id = 0");
            }

            stream = GetStream(resetFrame.StreamId);

            //09 -> 5.4.2.  Stream Error Handling
            //An endpoint MUST NOT send a RST_STREAM in response to an RST_STREAM
            //frame, to avoid looping.
            if (stream == null)
                return;

            Http2Logger.LogDebug("RST frame with code {0} for id {1}", resetFrame.StatusCode,
                                 resetFrame.StreamId);
            stream.Dispose(ResetStatusCode.None);
            //09 -> 5.1.  Stream States
            //WINDOW_UPDATE, PRIORITY, or RST_STREAM frames can be received in
            //this state for a short period after a DATA or HEADERS frame
            //containing an END_STREAM flag is sent.  Until the remote peer
            //receives and processes the frame bearing the END_STREAM flag, it
            //might send frame of any of these types.  Endpoints MUST ignore
            //WINDOW_UPDATE, PRIORITY, or RST_STREAM frames received in this
            //state, though endpoints MAY choose to treat frames that arrive a
            //significant time after sending END_STREAM as a connection error
            //(Section 5.4.1) of type PROTOCOL_ERROR.
        }
        private void HandleRstFrame(RstStreamFrame resetFrame, out Http2Stream stream)
        {
            Http2Logger.LogDebug("RST_STREAM frame: stream id={0}, status code={1}",
               resetFrame.StreamId, resetFrame.StatusCode);

            /* 12 -> 6.4
            RST_STREAM frames MUST be associated with a stream.  If a RST_STREAM
            frame is received with a stream identifier of 0x0, the recipient MUST
            treat this as a connection error of type PROTOCOL_ERROR. */
            if (resetFrame.StreamId == 0)
                throw new ProtocolError(ResetStatusCode.ProtocolError, "Rst frame with stream id=0");

            stream = GetStream(resetFrame.StreamId);
            
            if (stream.Closed)
            {
                /* 12 -> 5.4.2
                An endpoint MUST NOT send a RST_STREAM in response to an RST_STREAM
                frame, to avoid looping. */
                if (!stream.WasRstSent)
                {
                    throw new Http2StreamNotFoundException(resetFrame.StreamId);
                }
                return;
            }

            if (!(stream.ReservedRemote || stream.Opened || stream.HalfClosedLocal))
                throw new ProtocolError(ResetStatusCode.ProtocolError, "Rst for non opened or reserved stream");

            stream.Close(ResetStatusCode.None);
        }