return 0;
}
-
-static void
-http_transport_close (u32 rh, clib_thread_index_t thread_index)
+static_always_inline void
+http_app_close (u32 rh, clib_thread_index_t thread_index, u8 is_shutdown)
{
http_conn_t *hc;
u32 hc_index;
hc_index = http_vfts[hr_handle.version].hc_index_get_by_req_index (
hr_handle.req_index, thread_index);
- HTTP_DBG (1, "App disconnecting [%u]%x", thread_index, hc_index);
+ HTTP_DBG (1, "App disconnecting [%u]%x is_shutdown=%u", thread_index,
+ hc_index, is_shutdown);
hc = http_conn_get_w_thread (hc_index, thread_index);
if (hc->state == HTTP_CONN_STATE_CONNECTING)
}
http_vfts[hc->version].app_close_callback (hc, hr_handle.req_index,
- thread_index);
+ thread_index, is_shutdown);
+}
+
+static void
+http_transport_shutdown (u32 rh, clib_thread_index_t thread_index)
+{
+ http_app_close (rh, thread_index, 1);
+}
+
+static void
+http_transport_close (u32 rh, clib_thread_index_t thread_index)
+{
+ http_app_close (rh, thread_index, 0);
}
static void
if (hc->state == HTTP_CONN_STATE_APP_CLOSED)
http_vfts[hc->version].app_close_callback (hc, hr_handle.req_index,
- as->thread_index);
+ as->thread_index, 0);
sent = max_burst_sz - sp->max_burst_size;
.connect = http_transport_connect,
.start_listen = http_start_listen,
.stop_listen = http_stop_listen,
+ .half_close = http_transport_shutdown,
.close = http_transport_close,
.reset = http_transport_reset,
.cleanup_ho = http_transport_cleanup_ho,
static void
http1_app_close_callback (http_conn_t *hc, u32 req_index,
- clib_thread_index_t thread_index)
+ clib_thread_index_t thread_index, u8 is_shutdown)
{
http_req_t *req;
#define foreach_http2_req_flags \
_ (APP_CLOSED, "app-closed") \
+ _ (SHUTDOWN_TUNNEL, "shutdown-tunnel") \
_ (NEED_WINDOW_UPDATE, "need-window-update") \
_ (IS_PARENT, "is-parent")
h2c->req_num++;
if (is_parent)
{
+ HTTP_DBG (1, "is parent");
+ ASSERT (h2c->parent_req_index == SESSION_INVALID_INDEX);
req->flags |= HTTP2_REQ_F_IS_PARENT;
h2c->parent_req_index = req_index;
}
u32 max_enq;
HTTP_DBG (1, "tunnel received data from peer %lu", req->payload_len);
- if (req->flags & HTTP2_REQ_F_APP_CLOSED)
+ if (req->flags & HTTP2_REQ_F_APP_CLOSED &&
+ !(req->flags & HTTP2_REQ_F_SHUTDOWN_TUNNEL))
{
HTTP_DBG (1, "proxy app closed, going to reset stream");
http2_stream_error (hc, req, HTTP2_ERROR_CONNECT_ERROR, sp);
static void
http2_app_close_callback (http_conn_t *hc, u32 req_index,
- clib_thread_index_t thread_index)
+ clib_thread_index_t thread_index, u8 is_shutdown)
{
http2_req_t *req;
req->stream_state == HTTP2_STREAM_STATE_IDLE ||
hc->state == HTTP_CONN_STATE_CLOSED)
{
+ u8 is_parent = req->flags & HTTP2_REQ_F_IS_PARENT;
HTTP_DBG (1, "nothing more to send, confirm close");
http2_stream_close (req, hc);
- if (req->flags & HTTP2_REQ_F_IS_PARENT)
+ if (is_parent)
{
HTTP_DBG (1, "client app closed parent, closing connection");
ASSERT (!(hc->flags & HTTP_CONN_F_IS_SERVER));
}
else if (req->base.is_tunnel)
{
+ req->flags |= is_shutdown ? HTTP2_REQ_F_SHUTDOWN_TUNNEL : 0;
switch (req->stream_state)
{
case HTTP2_STREAM_STATE_OPEN:
HTTP_DBG (1, "wait for all data to be written to ts");
return;
}
- if (req->our_window == 0)
+ if (req->our_window == 0 && !is_shutdown)
{
HTTP_DBG (1, "app has unread data, going to reset stream");
http2_stream_error (hc, req, HTTP2_ERROR_CONNECT_ERROR, 0);
void (*app_rx_evt_callback) (http_conn_t *hc, u32 req_index,
clib_thread_index_t thread_index);
void (*app_close_callback) (http_conn_t *hc, u32 req_index,
- clib_thread_index_t thread_index);
+ clib_thread_index_t thread_index,
+ u8 is_shutdown);
void (*app_reset_callback) (http_conn_t *hc, u32 req_index,
clib_thread_index_t thread_index);
int (*transport_connected_callback) (http_conn_t *hc);