:ts:cv:`proxy.config.http2.min_concurrent_streams_in`.
To disable, set to zero (``0``).
-.. ts:cv:: CONFIG proxy.config.http2.initial_window_size_in INT 1048576
+.. ts:cv:: CONFIG proxy.config.http2.initial_window_size_in INT 65535
:reloadable:
The initial window size for inbound connections.
,
{RECT_CONFIG, "proxy.config.http2.max_active_streams_in", RECD_INT, "0", RECU_DYNAMIC, RR_NULL, RECC_STR, "^[0-9]+$", RECA_NULL}
,
- {RECT_CONFIG, "proxy.config.http2.initial_window_size_in", RECD_INT, "1048576", RECU_DYNAMIC, RR_NULL, RECC_STR, "^[0-9]+$", RECA_NULL}
+ {RECT_CONFIG, "proxy.config.http2.initial_window_size_in", RECD_INT, "65535", RECU_DYNAMIC, RR_NULL, RECC_STR, "^[0-9]+$", RECA_NULL}
,
{RECT_CONFIG, "proxy.config.http2.max_frame_size", RECD_INT, "16384", RECU_DYNAMIC, RR_NULL, RECC_STR, "^[0-9]+$", RECA_NULL}
,
uint32_t Http2::max_active_streams_in = 0;
bool Http2::throttling = false;
uint32_t Http2::stream_priority_enabled = 0;
-uint32_t Http2::initial_window_size = 1048576;
+uint32_t Http2::initial_window_size = 65535;
uint32_t Http2::max_frame_size = 16384;
uint32_t Http2::header_table_size = 4096;
uint32_t Http2::max_header_list_size = 4294967295;
break;
case VC_EVENT_WRITE_READY:
- retval = 0;
- break;
-
case VC_EVENT_WRITE_COMPLETE:
- // Seems as this is being closed already
+ this->connection_state.restart_streams();
+
retval = 0;
break;
// Do something else every 128 incoming frames
return (this->_n_frame_read & 0x7F) == 0;
}
+
+int64_t
+Http2ClientSession::write_avail()
+{
+ return this->write_buffer->write_avail();
+}
return write_buffer->max_read_avail();
}
+ int64_t write_avail();
+
// noncopyable
Http2ClientSession(Http2ClientSession &) = delete;
Http2ClientSession &operator=(const Http2ClientSession &) = delete;
cstate.decrement_server_rwnd(payload_length);
stream->decrement_server_rwnd(payload_length);
+ if (is_debug_tag_set("http2_con")) {
+ uint32_t rwnd = cstate.server_settings.get(HTTP2_SETTINGS_INITIAL_WINDOW_SIZE);
+ Http2StreamDebug(cstate.ua_session, stream->get_id(), "Received DATA frame: rwnd con=%zd/%" PRId32 " stream=%zd/%" PRId32,
+ cstate.server_rwnd(), rwnd, stream->server_rwnd(), rwnd);
+ }
+
const uint32_t unpadded_length = payload_length - pad_length;
// If we call write() multiple times, we must keep the same reader, so we can
// update its offset via consume. Otherwise, we will read the same data on the
}
myreader->writer()->dealloc_reader(myreader);
- uint32_t initial_rwnd = cstate.server_settings.get(HTTP2_SETTINGS_INITIAL_WINDOW_SIZE);
- uint32_t min_rwnd = std::min(initial_rwnd, cstate.server_settings.get(HTTP2_SETTINGS_MAX_FRAME_SIZE));
- // Connection level WINDOW UPDATE
- if (cstate.server_rwnd() <= min_rwnd) {
- Http2WindowSize diff_size = initial_rwnd - cstate.server_rwnd();
- cstate.increment_server_rwnd(diff_size);
- cstate.send_window_update_frame(0, diff_size);
- }
- // Stream level WINDOW UPDATE
- if (stream->server_rwnd() <= min_rwnd) {
- Http2WindowSize diff_size = initial_rwnd - stream->server_rwnd();
- stream->increment_server_rwnd(diff_size);
- cstate.send_window_update_frame(stream->get_id(), diff_size);
- }
-
return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_NONE);
}
}
}
+void
+Http2ConnectionState::restart_receiving(Http2Stream *stream)
+{
+ uint32_t initial_rwnd = this->server_settings.get(HTTP2_SETTINGS_INITIAL_WINDOW_SIZE);
+ uint32_t min_rwnd = std::min(initial_rwnd, this->server_settings.get(HTTP2_SETTINGS_MAX_FRAME_SIZE));
+
+ // Connection level WINDOW UPDATE
+ if (this->server_rwnd() < min_rwnd) {
+ Http2WindowSize diff_size = initial_rwnd - this->server_rwnd();
+ this->increment_server_rwnd(diff_size);
+ this->send_window_update_frame(0, diff_size);
+ }
+
+ // Stream level WINDOW UPDATE
+ if (stream == nullptr || stream->server_rwnd() >= min_rwnd) {
+ return;
+ }
+
+ // If read_vio is buffering data, do not fully update window
+ int64_t data_size = stream->read_vio_read_avail();
+ if (data_size >= initial_rwnd) {
+ return;
+ }
+
+ Http2WindowSize diff_size = initial_rwnd - std::max(static_cast<int64_t>(stream->server_rwnd()), data_size);
+ stream->increment_server_rwnd(diff_size);
+ this->send_window_update_frame(stream->get_id(), diff_size);
+}
+
void
Http2ConnectionState::cleanup_streams()
{
return Http2SendDataFrameResult::ERROR;
}
+ SCOPED_MUTEX_LOCK(lock, this->ua_session->mutex, this_ethread());
+ if (this->ua_session->write_avail() == 0) {
+ Http2StreamDebug(this->ua_session, stream->get_id(), "Not write avail");
+ return Http2SendDataFrameResult::NOT_WRITE_AVAIL;
+ }
+
// Select appropriate payload length
if (read_available_size > 0) {
// We only need to check for window size when there is a payload
current_reader->consume(payload_length);
// xmit event
- SCOPED_MUTEX_LOCK(lock, this->ua_session->mutex, this_ethread());
this->ua_session->handleEvent(HTTP2_SESSION_EVENT_XMIT, &data);
if (flags & HTTP2_FLAGS_DATA_END_STREAM) {
void
Http2ConnectionState::send_window_update_frame(Http2StreamId id, uint32_t size)
{
- Http2StreamDebug(ua_session, id, "Send WINDOW_UPDATE frame");
+ Http2StreamDebug(ua_session, id, "Send WINDOW_UPDATE frame: size=%" PRIu32, size);
// Create WINDOW_UPDATE frame
Http2Frame window_update(HTTP2_FRAME_TYPE_WINDOW_UPDATE, id, 0x0);
NO_ERROR = 0,
NO_WINDOW,
NO_PAYLOAD,
+ NOT_WRITE_AVAIL,
ERROR,
DONE,
};
void
init()
{
+ this->_server_rwnd = Http2::initial_window_size;
+
local_hpack_handle = new HpackHandle(HTTP2_HEADER_TABLE_SIZE);
remote_hpack_handle = new HpackHandle(HTTP2_HEADER_TABLE_SIZE);
dependency_tree = new DependencyTree(Http2::max_concurrent_streams_in);
void release_stream(Http2Stream *stream);
void cleanup_streams();
+ void restart_receiving(Http2Stream *stream);
void update_initial_rwnd(Http2WindowSize new_size);
Http2StreamId
// Connection level window size
ssize_t _client_rwnd = HTTP2_INITIAL_WINDOW_SIZE;
- ssize_t _server_rwnd = Http2::initial_window_size;
+ ssize_t _server_rwnd = 0;
std::vector<size_t> _recent_rwnd_increment = {SIZE_MAX, SIZE_MAX, SIZE_MAX, SIZE_MAX, SIZE_MAX};
int _recent_rwnd_increment_index = 0;
void
Http2Stream::restart_sending()
{
+ if (!this->response_header_done) {
+ return;
+ }
+
+ IOBufferReader *reader = this->response_get_data_reader();
+ if (reader && !reader->is_read_avail_more_than(0)) {
+ return;
+ }
+
+ if (this->write_vio.mutex && this->write_vio.ntodo() == 0) {
+ return;
+ }
+
this->send_response_body(true);
}
SCOPED_MUTEX_LOCK(lock, this->mutex, this_ethread());
update_write_request(vio->get_reader(), INT64_MAX, true);
} else if (vio->op == VIO::READ) {
+ Http2ClientSession *h2_proxy_ssn = static_cast<Http2ClientSession *>(this->get_parent());
+ {
+ SCOPED_MUTEX_LOCK(lock, h2_proxy_ssn->connection_state.mutex, this_ethread());
+ h2_proxy_ssn->connection_state.restart_receiving(this);
+ }
+
SCOPED_MUTEX_LOCK(lock, this->mutex, this_ethread());
update_read_request(INT64_MAX, true);
}
current_reader = nullptr; // State machine is on its own way down.
this->do_io_close();
}
+
+int64_t
+Http2Stream::read_vio_read_avail()
+{
+ MIOBuffer *writer = this->read_vio.get_writer();
+ if (writer) {
+ return writer->max_read_avail();
+ }
+
+ return 0;
+}
{
public:
typedef ProxyClientTransaction super; ///< Parent type.
- Http2Stream(Http2StreamId sid = 0, ssize_t initial_rwnd = Http2::initial_window_size) : _id(sid), _client_rwnd(initial_rwnd)
- {
- SET_HANDLER(&Http2Stream::main_event_handler);
- }
+ Http2Stream() { SET_HANDLER(&Http2Stream::main_event_handler); }
void
init(Http2StreamId sid, ssize_t initial_rwnd)
_start_time = Thread::get_hrtime();
_thread = this_ethread();
this->_client_rwnd = initial_rwnd;
+ this->_server_rwnd = Http2::initial_window_size;
HTTP2_INCREMENT_THREAD_DYN_STAT(HTTP2_STAT_CURRENT_CLIENT_STREAM_COUNT, _thread);
HTTP2_INCREMENT_THREAD_DYN_STAT(HTTP2_STAT_TOTAL_CLIENT_STREAM_COUNT, _thread);
sm_reader = request_reader = request_buffer.alloc_reader();
ssize_t server_rwnd() const;
Http2ErrorCode increment_server_rwnd(size_t amount);
Http2ErrorCode decrement_server_rwnd(size_t amount);
+ int64_t read_vio_read_avail();
uint8_t *header_blocks = nullptr;
uint32_t header_blocks_length = 0; // total length of header blocks (not include
uint64_t data_length = 0;
uint64_t bytes_sent = 0;
- ssize_t _client_rwnd;
- ssize_t _server_rwnd = Http2::initial_window_size;
+ ssize_t _client_rwnd = 0;
+ ssize_t _server_rwnd = 0;
std::vector<size_t> _recent_rwnd_increment = {SIZE_MAX, SIZE_MAX, SIZE_MAX, SIZE_MAX, SIZE_MAX};
int _recent_rwnd_increment_index = 0;