| 94 | } // end anonymous namespace |
| 95 | |
| 96 | Http2Error |
| 97 | Http2ConnectionState::rcv_data_frame(const Http2Frame &frame) |
| 98 | { |
| 99 | unsigned nbytes = 0; |
| 100 | Http2StreamId id = frame.header().streamid; |
| 101 | uint8_t pad_length = 0; |
| 102 | const uint32_t payload_length = frame.header().length; |
| 103 | |
| 104 | Http2StreamDebug(this->session, id, "Received DATA frame, flags: %d", frame.header().flags); |
| 105 | |
| 106 | // Update connection window size, before any stream specific handling |
| 107 | this->decrement_local_rwnd(payload_length); |
| 108 | |
| 109 | if (this->get_zombie_event()) { |
| 110 | Warning("Data frame for zombied session %" PRId64, this->session->get_connection_id()); |
| 111 | } |
| 112 | |
| 113 | // If a DATA frame is received whose stream identifier field is 0x0, the |
| 114 | // recipient MUST |
| 115 | // respond with a connection error of type PROTOCOL_ERROR. |
| 116 | if (!http2_is_client_streamid(id)) { |
| 117 | return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_CONNECTION, Http2ErrorCode::HTTP2_ERROR_PROTOCOL_ERROR, |
| 118 | "recv data bad frame client id"); |
| 119 | } |
| 120 | |
| 121 | Http2Stream *stream = this->find_stream(id); |
| 122 | if (stream == nullptr) { |
| 123 | if (this->is_valid_streamid(id)) { |
| 124 | // This error occurs fairly often, and is probably innocuous (SM initiates the shutdown) |
| 125 | if (this->session->is_outbound()) { |
| 126 | this->send_rst_stream_frame(id, Http2ErrorCode::HTTP2_ERROR_NO_ERROR); |
| 127 | return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_NONE); |
| 128 | } else { |
| 129 | return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_STREAM, Http2ErrorCode::HTTP2_ERROR_STREAM_CLOSED, nullptr); |
| 130 | } |
| 131 | } else { |
| 132 | return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_CONNECTION, Http2ErrorCode::HTTP2_ERROR_PROTOCOL_ERROR, |
| 133 | "recv data stream freed with invalid id"); |
| 134 | } |
| 135 | } |
| 136 | |
| 137 | if (stream->get_state() == Http2StreamState::HTTP2_STREAM_STATE_CLOSED || |
| 138 | stream->get_state() == Http2StreamState::HTTP2_STREAM_STATE_HALF_CLOSED_REMOTE) { |
| 139 | this->send_rst_stream_frame(id, Http2ErrorCode::HTTP2_ERROR_STREAM_CLOSED); |
| 140 | return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_NONE); |
| 141 | } |
| 142 | |
| 143 | // If a DATA frame is received whose stream is not in "open" or "half closed |
| 144 | // (local)" state, |
| 145 | // the recipient MUST respond with a stream error of type STREAM_CLOSED. |
| 146 | if (stream->get_state() != Http2StreamState::HTTP2_STREAM_STATE_OPEN && |
| 147 | stream->get_state() != Http2StreamState::HTTP2_STREAM_STATE_HALF_CLOSED_LOCAL) { |
| 148 | return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_STREAM, Http2ErrorCode::HTTP2_ERROR_STREAM_CLOSED, |
| 149 | "recv data stream closed"); |
| 150 | } |
| 151 | |
| 152 | if (frame.header().flags & HTTP2_FLAGS_DATA_PADDED) { |
| 153 | frame.reader()->memcpy(&pad_length, HTTP2_DATA_PADLEN_LEN, nbytes); |
nothing calls this directly
no test coverage detected