* [RFC 7540] 6.2 HEADERS Frame * * NOTE: HEADERS Frame and CONTINUATION Frame * 1. A HEADERS frame with the END_STREAM flag set can be followed by * CONTINUATION frames on the same stream. * 2. A HEADERS frame without the END_HEADERS flag set MUST be followed by a * CONTINUATION frame */
| 290 | * CONTINUATION frame |
| 291 | */ |
| 292 | Http2Error |
| 293 | Http2ConnectionState::rcv_headers_frame(const Http2Frame &frame) |
| 294 | { |
| 295 | const Http2StreamId stream_id = frame.header().streamid; |
| 296 | const uint32_t payload_length = frame.header().length; |
| 297 | |
| 298 | Http2StreamDebug(this->session, stream_id, "Received HEADERS frame"); |
| 299 | |
| 300 | if (!http2_is_client_streamid(stream_id)) { |
| 301 | return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_CONNECTION, Http2ErrorCode::HTTP2_ERROR_PROTOCOL_ERROR, |
| 302 | "recv headers bad client id"); |
| 303 | } |
| 304 | |
| 305 | Http2Stream *stream = nullptr; |
| 306 | bool new_stream = false; |
| 307 | bool reset_header_after_decoding = false; |
| 308 | bool free_stream_after_decoding = false; |
| 309 | |
| 310 | if (this->is_valid_streamid(stream_id)) { |
| 311 | stream = this->find_stream(stream_id); |
| 312 | if (!this->session->is_outbound() && (stream == nullptr || !stream->trailing_header_is_possible())) { |
| 313 | return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_CONNECTION, Http2ErrorCode::HTTP2_ERROR_STREAM_CLOSED, |
| 314 | "stream not expecting trailer header"); |
| 315 | } else if (stream == nullptr || stream->get_state() == Http2StreamState::HTTP2_STREAM_STATE_CLOSED) { |
| 316 | if (this->session->is_outbound()) { |
| 317 | reset_header_after_decoding = true; |
| 318 | // return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_NONE); |
| 319 | // return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_STREAM, Http2ErrorCode::HTTP2_ERROR_STREAM_CLOSED, |
| 320 | // "recv_header to closed stream"); |
| 321 | } else { |
| 322 | return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_CONNECTION, Http2ErrorCode::HTTP2_ERROR_STREAM_CLOSED, |
| 323 | "recv_header to closed stream"); |
| 324 | } |
| 325 | } |
| 326 | } |
| 327 | |
| 328 | if (!http2_is_client_streamid(stream_id)) { |
| 329 | return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_CONNECTION, Http2ErrorCode::HTTP2_ERROR_PROTOCOL_ERROR, |
| 330 | "recv headers bad client id"); |
| 331 | } |
| 332 | |
| 333 | if (!stream) { |
| 334 | if (reset_header_after_decoding) { |
| 335 | free_stream_after_decoding = true; |
| 336 | uint32_t const initial_local_stream_window = this->acknowledged_local_settings.get(HTTP2_SETTINGS_INITIAL_WINDOW_SIZE); |
| 337 | ink_assert(dynamic_cast<Http2CommonSession *>(this->session->get_proxy_session())); |
| 338 | ink_assert(this->session->is_outbound() == true); |
| 339 | stream = THREAD_ALLOC_INIT(http2StreamAllocator, this_ethread(), this->session->get_proxy_session(), stream_id, |
| 340 | this->peer_settings.get(HTTP2_SETTINGS_INITIAL_WINDOW_SIZE), initial_local_stream_window, |
| 341 | !STREAM_IS_REGISTERED); |
| 342 | } else { |
| 343 | // Create new stream |
| 344 | Http2Error error(Http2ErrorClass::HTTP2_ERROR_CLASS_NONE); |
| 345 | stream = this->create_stream(stream_id, error); |
| 346 | new_stream = true; |
| 347 | if (!stream) { |
| 348 | // Terminate the connection with COMPRESSION_ERROR because we don't decompress the field block in this HEADERS frame. |
| 349 | // TODO: try to decompress to keep HPACK Dynamic Table in sync. |
nothing calls this directly
no test coverage detected