| 907 | } |
| 908 | |
| 909 | Http2Error |
| 910 | Http2ConnectionState::rcv_window_update_frame(const Http2Frame &frame) |
| 911 | { |
| 912 | char buf[HTTP2_WINDOW_UPDATE_LEN]; |
| 913 | uint32_t size; |
| 914 | const Http2StreamId stream_id = frame.header().streamid; |
| 915 | |
| 916 | // A WINDOW_UPDATE frame with a length other than 4 octets MUST be |
| 917 | // treated as a connection error of type FRAME_SIZE_ERROR. |
| 918 | if (frame.header().length != HTTP2_WINDOW_UPDATE_LEN) { |
| 919 | Http2StreamDebug(this->session, stream_id, "Received WINDOW_UPDATE frame - length incorrect"); |
| 920 | return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_CONNECTION, Http2ErrorCode::HTTP2_ERROR_FRAME_SIZE_ERROR, |
| 921 | "window update bad length"); |
| 922 | } |
| 923 | |
| 924 | frame.reader()->memcpy(buf, sizeof(buf), 0); |
| 925 | http2_parse_window_update(make_iovec(buf, sizeof(buf)), size); |
| 926 | |
| 927 | // A receiver MUST treat the receipt of a WINDOW_UPDATE frame with a flow |
| 928 | // control window increment of 0 as a connection error of type PROTOCOL_ERROR; |
| 929 | if (size == 0) { |
| 930 | if (stream_id == HTTP2_CONNECTION_CONTROL_STREAM) { |
| 931 | return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_CONNECTION, Http2ErrorCode::HTTP2_ERROR_PROTOCOL_ERROR, |
| 932 | "window update length=0 and id=0"); |
| 933 | } else { |
| 934 | return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_STREAM, Http2ErrorCode::HTTP2_ERROR_PROTOCOL_ERROR, |
| 935 | "window update length=0"); |
| 936 | } |
| 937 | } |
| 938 | |
| 939 | if (stream_id == HTTP2_CONNECTION_CONTROL_STREAM) { |
| 940 | // Connection level window update |
| 941 | Http2StreamDebug(this->session, stream_id, "Received WINDOW_UPDATE frame - updated to: %zd delta: %u", |
| 942 | (this->get_peer_rwnd() + size), size); |
| 943 | |
| 944 | // A sender MUST NOT allow a flow-control window to exceed 2^31-1 |
| 945 | // octets. If a sender receives a WINDOW_UPDATE that causes a flow- |
| 946 | // control window to exceed this maximum, it MUST terminate either the |
| 947 | // stream or the connection, as appropriate. For streams, the sender |
| 948 | // sends a RST_STREAM with an error code of FLOW_CONTROL_ERROR; for the |
| 949 | // connection, a GOAWAY frame with an error code of FLOW_CONTROL_ERROR |
| 950 | // is sent. |
| 951 | if (size > HTTP2_MAX_WINDOW_SIZE - this->get_peer_rwnd()) { |
| 952 | return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_CONNECTION, Http2ErrorCode::HTTP2_ERROR_FLOW_CONTROL_ERROR, |
| 953 | "window update too big"); |
| 954 | } |
| 955 | |
| 956 | auto error = this->increment_peer_rwnd(size); |
| 957 | if (error != Http2ErrorCode::HTTP2_ERROR_NO_ERROR) { |
| 958 | return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_CONNECTION, error, "Erroneous client window update"); |
| 959 | } |
| 960 | this->restart_streams(); |
| 961 | } else { |
| 962 | // Stream level window update |
| 963 | Http2Stream *stream = this->find_stream(stream_id); |
| 964 | |
| 965 | if (stream == nullptr) { |
| 966 | if (this->is_valid_streamid(stream_id)) { |
nothing calls this directly
no test coverage detected