| 1753 | } |
| 1754 | |
| 1755 | Http2Stream * |
| 1756 | Http2ConnectionState::create_stream(Http2StreamId new_id, Http2Error &error) |
| 1757 | { |
| 1758 | // first check if we've hit the active connection limit |
| 1759 | if (!session->get_netvc()->add_to_active_queue()) { |
| 1760 | error = Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_CONNECTION, Http2ErrorCode::HTTP2_ERROR_NO_ERROR, |
| 1761 | "refused to create new stream, maxed out active connections"); |
| 1762 | return nullptr; |
| 1763 | } |
| 1764 | |
| 1765 | // In half_close state, TS doesn't create new stream. Because GOAWAY frame is sent to client |
| 1766 | if (session->get_half_close_local_flag()) { |
| 1767 | error = Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_STREAM, Http2ErrorCode::HTTP2_ERROR_REFUSED_STREAM, |
| 1768 | "refused to create new stream, because session is in half_close state"); |
| 1769 | return nullptr; |
| 1770 | } |
| 1771 | |
| 1772 | bool is_client_streamid = http2_is_client_streamid(new_id); |
| 1773 | |
| 1774 | // 5.1.1 The identifier of a newly established stream MUST be numerically |
| 1775 | // greater than all streams that the initiating endpoint has opened or |
| 1776 | // reserved. This governs streams that are opened using a HEADERS frame |
| 1777 | // and streams that are reserved using PUSH_PROMISE. An endpoint that |
| 1778 | // receives an unexpected stream identifier MUST respond with a |
| 1779 | // connection error (Section 5.4.1) of type PROTOCOL_ERROR. |
| 1780 | if (is_client_streamid) { |
| 1781 | if (new_id <= latest_streamid_in) { |
| 1782 | error = Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_CONNECTION, Http2ErrorCode::HTTP2_ERROR_PROTOCOL_ERROR, |
| 1783 | "recv headers new client id less than latest stream id"); |
| 1784 | return nullptr; |
| 1785 | } |
| 1786 | } else { |
| 1787 | if (new_id <= latest_streamid_out) { |
| 1788 | error = Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_CONNECTION, Http2ErrorCode::HTTP2_ERROR_PROTOCOL_ERROR, |
| 1789 | "recv headers new server id less than latest stream id"); |
| 1790 | return nullptr; |
| 1791 | } |
| 1792 | } |
| 1793 | |
| 1794 | // Endpoints MUST NOT exceed the limit set by their peer. An endpoint |
| 1795 | // that receives a HEADERS frame that causes their advertised concurrent |
| 1796 | // stream limit to be exceeded MUST treat this as a stream error. |
| 1797 | int check_max_concurrent_limit = 0; |
| 1798 | int check_count = 0; |
| 1799 | if (is_client_streamid) { |
| 1800 | check_count = peer_streams_count_in; |
| 1801 | // If this is an outbound client stream, must check against the peer's max_concurrent |
| 1802 | if (session->is_outbound()) { |
| 1803 | check_max_concurrent_limit = peer_settings.get(HTTP2_SETTINGS_MAX_CONCURRENT_STREAMS); |
| 1804 | } else { // Inbound client streamm check against our own max_connecurent limits |
| 1805 | check_max_concurrent_limit = acknowledged_local_settings.get(HTTP2_SETTINGS_MAX_CONCURRENT_STREAMS); |
| 1806 | } |
| 1807 | } else { // Not a client stream (i.e. a push) |
| 1808 | check_count = peer_streams_count_out; |
| 1809 | // If this is an outbound non-client stream, must check against the local max_concurrent |
| 1810 | if (session->is_outbound()) { |
| 1811 | check_max_concurrent_limit = acknowledged_local_settings.get(HTTP2_SETTINGS_MAX_CONCURRENT_STREAMS); |
| 1812 | } else { // Inbound non-client streamm check against the peer's max_connecurent limits |
no test coverage detected