| 1433 | } |
| 1434 | |
| 1435 | void |
| 1436 | Http2ConnectionState::rcv_frame(const Http2Frame *frame) |
| 1437 | { |
| 1438 | REMEMBER(NO_EVENT, this->recursion); |
| 1439 | const Http2StreamId stream_id = frame->header().streamid; |
| 1440 | Http2Error error; |
| 1441 | |
| 1442 | // [RFC 7540] 5.5. Extending HTTP/2 |
| 1443 | // Implementations MUST discard frames that have unknown or unsupported types. |
| 1444 | if (frame->header().type >= HTTP2_FRAME_TYPE_MAX) { |
| 1445 | Http2StreamDebug(session, stream_id, "Discard a frame which has unknown type, type=%x", frame->header().type); |
| 1446 | return; |
| 1447 | } |
| 1448 | |
| 1449 | // We need to be careful here, certain frame types are not safe over 0-rtt, tentative for now. |
| 1450 | // DATA: NO |
| 1451 | // HEADERS: YES (safe http methods only, can only be checked after parsing the payload). |
| 1452 | // PRIORITY: YES |
| 1453 | // RST_STREAM: NO |
| 1454 | // SETTINGS: YES |
| 1455 | // PUSH_PROMISE: NO |
| 1456 | // PING: YES |
| 1457 | // GOAWAY: NO |
| 1458 | // WINDOW_UPDATE: YES |
| 1459 | // CONTINUATION: YES (safe http methods only, same as HEADERS frame). |
| 1460 | if (frame->is_from_early_data() && |
| 1461 | (frame->header().type == HTTP2_FRAME_TYPE_DATA || frame->header().type == HTTP2_FRAME_TYPE_RST_STREAM || |
| 1462 | frame->header().type == HTTP2_FRAME_TYPE_PUSH_PROMISE || frame->header().type == HTTP2_FRAME_TYPE_GOAWAY)) { |
| 1463 | Http2StreamDebug(session, stream_id, "Discard a frame which is received from early data and has type=%x", frame->header().type); |
| 1464 | return; |
| 1465 | } |
| 1466 | |
| 1467 | if (this->_frame_handlers[frame->header().type]) { |
| 1468 | error = (this->*_frame_handlers[frame->header().type])(*frame); |
| 1469 | } else { |
| 1470 | error = Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_CONNECTION, Http2ErrorCode::HTTP2_ERROR_INTERNAL_ERROR, "no handler"); |
| 1471 | } |
| 1472 | |
| 1473 | if (error.cls != Http2ErrorClass::HTTP2_ERROR_CLASS_NONE) { |
| 1474 | ip_port_text_buffer ipb; |
| 1475 | const char *client_ip = ats_ip_ntop(session->get_proxy_session()->get_remote_addr(), ipb, sizeof(ipb)); |
| 1476 | if (error.cls == Http2ErrorClass::HTTP2_ERROR_CLASS_CONNECTION) { |
| 1477 | if (error.msg) { |
| 1478 | Error("HTTP/2 connection error code=0x%02x client_ip=%s session_id=%" PRId64 " stream_id=%u %s", |
| 1479 | static_cast<int>(error.code), client_ip, session->get_connection_id(), stream_id, error.msg); |
| 1480 | } |
| 1481 | this->send_goaway_frame(this->latest_streamid_in, error.code); |
| 1482 | this->session->set_half_close_local_flag(true); |
| 1483 | if (fini_event == nullptr) { |
| 1484 | fini_event = this_ethread()->schedule_imm_local(static_cast<Continuation *>(this), HTTP2_SESSION_EVENT_FINI); |
| 1485 | } |
| 1486 | |
| 1487 | // The streams will be cleaned up by the HTTP2_SESSION_EVENT_FINI event |
| 1488 | // The Http2ClientSession will shutdown because connection_state.is_state_closed() will be true |
| 1489 | } else if (error.cls == Http2ErrorClass::HTTP2_ERROR_CLASS_STREAM) { |
| 1490 | if (error.msg) { |
| 1491 | Error("HTTP/2 stream error code=0x%02x client_ip=%s session_id=%" PRId64 " stream_id=%u %s", static_cast<int>(error.code), |
| 1492 | client_ip, session->get_connection_id(), stream_id, error.msg); |
no test coverage detected