| 627 | } |
| 628 | |
| 629 | Http2Error |
| 630 | Http2ConnectionState::rcv_rst_stream_frame(const Http2Frame &frame) |
| 631 | { |
| 632 | Http2RstStream rst_stream; |
| 633 | char buf[HTTP2_RST_STREAM_LEN]; |
| 634 | char *end; |
| 635 | const Http2StreamId stream_id = frame.header().streamid; |
| 636 | |
| 637 | Http2StreamDebug(this->session, frame.header().streamid, "Received RST_STREAM frame"); |
| 638 | |
| 639 | // RST_STREAM frames MUST be associated with a stream. If a RST_STREAM |
| 640 | // frame is received with a stream identifier of 0x0, the recipient MUST |
| 641 | // treat this as a connection error (Section 5.4.1) of type |
| 642 | // PROTOCOL_ERROR. |
| 643 | if (stream_id == HTTP2_CONNECTION_CONTROL_STREAM) { |
| 644 | return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_CONNECTION, Http2ErrorCode::HTTP2_ERROR_PROTOCOL_ERROR, |
| 645 | "reset access stream with invalid id"); |
| 646 | } |
| 647 | |
| 648 | // A RST_STREAM frame with a length other than 4 octets MUST be treated |
| 649 | // as a connection error (Section 5.4.1) of type FRAME_SIZE_ERROR. |
| 650 | if (frame.header().length != HTTP2_RST_STREAM_LEN) { |
| 651 | return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_CONNECTION, Http2ErrorCode::HTTP2_ERROR_FRAME_SIZE_ERROR, |
| 652 | "reset frame wrong length"); |
| 653 | } |
| 654 | |
| 655 | Http2Stream *stream = this->find_stream(stream_id); |
| 656 | if (stream == nullptr) { |
| 657 | if (this->is_valid_streamid(stream_id)) { |
| 658 | return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_NONE); |
| 659 | } else { |
| 660 | return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_CONNECTION, Http2ErrorCode::HTTP2_ERROR_PROTOCOL_ERROR, |
| 661 | "reset frame bad id stream not found"); |
| 662 | } |
| 663 | } |
| 664 | |
| 665 | // Update RST_STREAM frame count per minute |
| 666 | this->increment_received_rst_stream_frame_count(); |
| 667 | // Close this connection if its RST_STREAM frame count exceeds a limit |
| 668 | if (configured_max_rst_stream_frames_per_minute >= 0 && |
| 669 | this->get_received_rst_stream_frame_count() > static_cast<uint32_t>(configured_max_rst_stream_frames_per_minute)) { |
| 670 | Metrics::Counter::increment(http2_rsb.max_rst_stream_frames_per_minute_exceeded); |
| 671 | Http2StreamDebug(this->session, stream_id, "Observed too frequent RST_STREAM frames: %u frames within a last minute", |
| 672 | this->get_received_rst_stream_frame_count()); |
| 673 | return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_CONNECTION, Http2ErrorCode::HTTP2_ERROR_ENHANCE_YOUR_CALM, |
| 674 | "reset too frequent RST_STREAM frames"); |
| 675 | } |
| 676 | |
| 677 | if (stream == nullptr || !stream->change_state(frame.header().type, frame.header().flags)) { |
| 678 | // If a RST_STREAM frame identifying an idle stream is received, the |
| 679 | // recipient MUST treat this as a connection error of type PROTOCOL_ERROR. |
| 680 | return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_CONNECTION, Http2ErrorCode::HTTP2_ERROR_PROTOCOL_ERROR, |
| 681 | "reset missing stream or bad stream state"); |
| 682 | } |
| 683 | |
| 684 | end = frame.reader()->memcpy(buf, sizeof(buf), 0); |
| 685 | |
| 686 | if (!http2_parse_rst_stream(make_iovec(buf, end - buf), rst_stream)) { |
nothing calls this directly
no test coverage detected