Beispiel #1
0
        public void AppendToHeaderList(ICharSequence name, ICharSequence value)
        {
            _headersLength     += HpackHeaderField.SizeOf(name, value);
            _exceededMaxLength |= _headersLength > _maxHeaderListSize;

            if (_exceededMaxLength || _validationException is object)
            {
                // We don't store the header since we've already failed validation requirements.
                return;
            }

            if (_validate)
            {
                try
                {
                    _previousType = HpackDecoder.Validate(_streamId, name, _previousType);
                }
                catch (Http2Exception ex)
                {
                    _validationException = ex;
                    return;
                }
            }

            _ = _headers.Add(name, value);
        }
        private IPromise HandleOutstandingControlFrames(IChannelHandlerContext ctx, IPromise promise)
        {
            if (!_limitReached)
            {
                if (_outstandingControlFrames == _maxOutstandingControlFrames)
                {
                    // Let's try to flush once as we may be able to flush some of the control frames.
                    _ = ctx.Flush();
                }
                if (_outstandingControlFrames == _maxOutstandingControlFrames)
                {
                    _limitReached = true;
                    Http2Exception exception = ThrowHelper.GetConnectionError_Maximum_number_of_outstanding_control_frames_reached(_maxOutstandingControlFrames);
                    if (Logger.InfoEnabled)
                    {
                        Logger.Maximum_number_of_outstanding_control_frames_reached(_maxOutstandingControlFrames, ctx, exception);
                    }

                    // First notify the Http2LifecycleManager and then close the connection.
                    _lifecycleManager.OnError(ctx, true, exception);
                    _ = ctx.CloseAsync();
                }
                _outstandingControlFrames++;

                // We did not reach the limit yet, add the listener to decrement the number of outstanding control frames
                // once the promise was completed
                var newPromise = promise is object?promise.Unvoid() : ctx.NewPromise();

                _ = newPromise.Task.ContinueWith(OutstandingControlFramesListenerAction, this, TaskContinuationOptions.ExecuteSynchronously);
                return(newPromise);
            }
            return(promise);
        }
Beispiel #3
0
            /// <summary>
            /// Discards this <see cref="IHttp2RemoteFlowControlled"/>, writing an error. If this frame is in the pending queue,
            /// the unwritten bytes are removed from this branch of the priority tree.
            /// </summary>
            /// <param name="frame"></param>
            /// <param name="cause"></param>
            void WriteError(IHttp2RemoteFlowControlled frame, Http2Exception cause)
            {
                IChannelHandlerContext ctx = _controller._ctx;

                Debug.Assert(ctx is object);
                DecrementPendingBytes(frame.Size, true);
                frame.Error(ctx, cause);
            }
Beispiel #4
0
        public void ReadFrame(IChannelHandlerContext ctx, IByteBuffer input, IHttp2FrameListener listener)
        {
            if (_readError)
            {
                _ = input.SkipBytes(input.ReadableBytes);
                return;
            }

            try
            {
                do
                {
                    if (_readingHeaders)
                    {
                        ProcessHeaderState(input);
                        if (_readingHeaders)
                        {
                            // Wait until the entire header has arrived.
                            return;
                        }
                    }

                    // The header is complete, fall into the next case to process the payload.
                    // This is to ensure the proper handling of zero-length payloads. In this
                    // case, we don't want to loop around because there may be no more data
                    // available, causing us to exit the loop. Instead, we just want to perform
                    // the first pass at payload processing now.
                    ProcessPayloadState(ctx, input, listener);
                    if (!_readingHeaders)
                    {
                        // Wait until the entire payload has arrived.
                        return;
                    }
                }while (input.IsReadable());
            }
            catch (Http2Exception e)
            {
                _readError = !Http2Exception.IsStreamError(e);
                throw;
            }
            catch (Http2RuntimeException)
            {
                _readError = true;
                throw;
            }
            catch (Exception)
            {
                _readError = true;
                throw;
            }
        }
Beispiel #5
0
            /// <summary>
            /// Clears the pending queue and writes errors for each remaining frame.
            /// </summary>
            /// <param name="error">the <see cref="Http2Error"/> to use.</param>
            /// <param name="cause">the <see cref="Exception"/> that caused this method to be invoked.</param>
            internal void Cancel(Http2Error error, Exception cause = null)
            {
                _cancelled = true;
                // Ensure that the queue can't be modified while we are writing.
                if (_writing)
                {
                    return;
                }

                if (_pendingWriteQueue.TryRemoveFromFront(out IHttp2RemoteFlowControlled frame))
                {
                    // Only create exception once and reuse to reduce overhead of filling in the stacktrace.
                    Http2Exception exception = ThrowHelper.GetStreamError_StreamClosedBeforeWriteCouldTakePlace(
                        _stream.Id, error, cause);
                    do
                    {
                        WriteError(frame, exception);
                    } while (_pendingWriteQueue.TryRemoveFromFront(out frame));
                }

                _controller._streamByteDistributor.UpdateStreamableBytes(this);

                _controller._monitor.StateCancelled(this);
            }
Beispiel #6
0
 /// <summary>
 /// Get the stream id associated with an exception.
 /// </summary>
 /// <param name="e">The exception to get the stream id for.</param>
 /// <returns><see cref="Http2CodecUtil.ConnectionStreamId"/> if <paramref name="e"/> is a connection error.
 /// Otherwise the stream id associated with the stream error.</returns>
 public static int GetStreamId(Http2Exception e)
 {
     return(e is StreamException streamException ? streamException.StreamId : Http2CodecUtil.ConnectionStreamId);
 }
Beispiel #7
0
 /// <summary>
 /// Check if an exception is isolated to a single stream or the entire connection.
 /// </summary>
 /// <param name="e">The exception to check.</param>
 /// <returns><c>true</c> if <paramref name="e"/> is an instance of <see cref="StreamException"/>.
 /// <c>false</c> otherwise.</returns>
 public static bool IsStreamError(Http2Exception e)
 {
     return(e is StreamException);
 }
Beispiel #8
0
 /// <summary>
 /// A specific stream error resulting from failing to decode headers that exceeds the max header size list.
 /// If the <paramref name="id"/> is not <see cref="Http2CodecUtil.ConnectionStreamId"/> then a
 /// <see cref="StreamException"/> will be returned. Otherwise the error is considered a
 /// connection error and a <see cref="Http2Exception"/> is returned.
 /// </summary>
 /// <param name="id">The stream id for which the error is isolated to.</param>
 /// <param name="error">The type of error as defined by the HTTP/2 specification.</param>
 /// <param name="onDecode">Whether this error was caught while decoding headers</param>
 /// <param name="fmt">string with the content and format for the additional debug data.</param>
 /// <param name="args">Objects which fit into the format defined by <paramref name="fmt"/>.</param>
 /// <returns>If the <paramref name="id"/> is not
 /// <see cref="Http2CodecUtil.ConnectionStreamId"/> then a <see cref="HeaderListSizeException"/>
 /// will be returned. Otherwise the error is considered a connection error and a <see cref="Http2Exception"/> is
 /// returned.</returns>
 public static Http2Exception HeaderListSizeError(int id, Http2Error error, bool onDecode, string fmt, params object[] args)
 {
     return(Http2CodecUtil.ConnectionStreamId == id?
            Http2Exception.ConnectionError(error, fmt, args) :
                new HeaderListSizeException(id, error, args is object && (uint)args.Length > 0u ? string.Format(fmt, args) : fmt, onDecode));
 }
Beispiel #9
0
 /// <summary>
 /// Use if an error which can be isolated to a single stream has occurred.  If the <paramref name="id"/> is not
 /// <see cref="Http2CodecUtil.ConnectionStreamId"/> then a <see cref="StreamException"/> will be returned.
 /// Otherwise the error is considered a connection error and a <see cref="Http2Exception"/> is returned.
 /// </summary>
 /// <param name="id">The stream id for which the error is isolated to.</param>
 /// <param name="error">The type of error as defined by the HTTP/2 specification.</param>
 /// <param name="cause">The object which caused the error.</param>
 /// <param name="fmt">string with the content and format for the additional debug data.</param>
 /// <param name="args">Objects which fit into the format defined by <paramref name="fmt"/>.</param>
 /// <returns>If the <paramref name="id"/> is not
 /// <see cref="Http2CodecUtil.ConnectionStreamId"/> then a <see cref="StreamException"/> will be returned.
 /// Otherwise the error is considered a connection error and a <see cref="Http2Exception"/> is returned.</returns>
 public static Http2Exception StreamError(int id, Http2Error error, Exception cause, string fmt, params object[] args)
 {
     return(Http2CodecUtil.ConnectionStreamId == id?
            Http2Exception.ConnectionError(error, cause, fmt, args) :
                new StreamException(id, error, args is object && (uint)args.Length > 0u ? string.Format(fmt, args) : fmt, cause));
 }
Beispiel #10
0
 private static Http2Exception GetStreamNeverExistedException(int streamId)
 {
     return(Http2Exception.StreamError(streamId, Http2Error.ProtocolError, "Stream never existed"));
 }
Beispiel #11
0
 public static void HeaderListSizeExceeded(long maxHeaderListSize)
 {
     throw Http2Exception.ConnectionError(Http2Error.ProtocolError,
                                          "Header size exceeded max allowed size ({0})", maxHeaderListSize);
 }
Beispiel #12
0
 public static void HeaderListSizeExceeded(int streamId, long maxHeaderListSize, bool onDecode)
 {
     throw Http2Exception.HeaderListSizeError(streamId, Http2Error.ProtocolError, onDecode,
                                              "Header size exceeded max allowed size ({0})", maxHeaderListSize);
 }
Beispiel #13
0
 public static void Maximum_number_of_outstanding_control_frames_reached(this IInternalLogger logger, int maxOutstandingControlFrames, IChannelHandlerContext ctx, Http2Exception exception)
 {
     logger.Info("Maximum number {} of outstanding control frames reached. Closing channel {}",
                 maxOutstandingControlFrames, ctx.Channel, exception);
 }