mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2025-08-07 07:37:02 +02:00
MINOR: mux-h1: Move all stuff to detach a stream in an internal function
All code from h1_detach() function was moved in a internal function, h1s_finish_detach(). It will be used to defer the detach and be able to drain the requests payload.
This commit is contained in:
parent
7ae280d091
commit
14db433db9
209
src/mux_h1.c
209
src/mux_h1.c
@ -335,6 +335,8 @@ DECLARE_STATIC_POOL(pool_head_h1s, "h1s", sizeof(struct h1s));
|
|||||||
static int h1_recv(struct h1c *h1c);
|
static int h1_recv(struct h1c *h1c);
|
||||||
static int h1_send(struct h1c *h1c);
|
static int h1_send(struct h1c *h1c);
|
||||||
static int h1_process(struct h1c *h1c);
|
static int h1_process(struct h1c *h1c);
|
||||||
|
static void h1_release(struct h1c *h1c);
|
||||||
|
|
||||||
/* h1_io_cb is exported to see it resolved in "show fd" */
|
/* h1_io_cb is exported to see it resolved in "show fd" */
|
||||||
struct task *h1_io_cb(struct task *t, void *ctx, unsigned int state);
|
struct task *h1_io_cb(struct task *t, void *ctx, unsigned int state);
|
||||||
struct task *h1_timeout_task(struct task *t, void *context, unsigned int state);
|
struct task *h1_timeout_task(struct task *t, void *context, unsigned int state);
|
||||||
@ -963,6 +965,116 @@ static int h1s_must_shut_conn(struct h1s *h1s)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Really detach the H1S. Most of time of it called from h1_detach() when the
|
||||||
|
* stream is detached from the connection. But if the request message must be
|
||||||
|
* drained first, the detach is deferred.
|
||||||
|
*/
|
||||||
|
static void h1s_finish_detach(struct h1s *h1s)
|
||||||
|
{
|
||||||
|
struct h1c *h1c;
|
||||||
|
struct session *sess;
|
||||||
|
int is_not_first;
|
||||||
|
|
||||||
|
TRACE_ENTER(H1_EV_STRM_END, h1s ? h1s->h1c->conn : NULL, h1s);
|
||||||
|
|
||||||
|
sess = h1s->sess;
|
||||||
|
h1c = h1s->h1c;
|
||||||
|
|
||||||
|
sess->accept_date = date;
|
||||||
|
sess->accept_ts = now_ns;
|
||||||
|
sess->t_handshake = 0;
|
||||||
|
sess->t_idle = -1;
|
||||||
|
|
||||||
|
is_not_first = h1s->flags & H1S_F_NOT_FIRST;
|
||||||
|
h1s_destroy(h1s);
|
||||||
|
|
||||||
|
if (h1c->state == H1_CS_IDLE && (h1c->flags & H1C_F_IS_BACK)) {
|
||||||
|
/* this connection may be killed at any moment, we want it to
|
||||||
|
* die "cleanly" (i.e. only an RST).
|
||||||
|
*/
|
||||||
|
h1c->flags |= H1C_F_SILENT_SHUT;
|
||||||
|
|
||||||
|
/* If there are any excess server data in the input buffer,
|
||||||
|
* release it and close the connection ASAP (some data may
|
||||||
|
* remain in the output buffer). This happens if a server sends
|
||||||
|
* invalid responses. So in such case, we don't want to reuse
|
||||||
|
* the connection
|
||||||
|
*/
|
||||||
|
if (b_data(&h1c->ibuf)) {
|
||||||
|
h1_release_buf(h1c, &h1c->ibuf);
|
||||||
|
h1_close(h1c);
|
||||||
|
TRACE_DEVEL("remaining data on detach, kill connection", H1_EV_STRM_END|H1_EV_H1C_END);
|
||||||
|
goto release;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (h1c->conn->flags & CO_FL_PRIVATE) {
|
||||||
|
/* Add the connection in the session server list, if not already done */
|
||||||
|
if (!session_add_conn(sess, h1c->conn, h1c->conn->target)) {
|
||||||
|
h1c->conn->owner = NULL;
|
||||||
|
h1c->conn->mux->destroy(h1c);
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
/* Always idle at this step */
|
||||||
|
if (session_check_idle_conn(sess, h1c->conn)) {
|
||||||
|
/* The connection got destroyed, let's leave */
|
||||||
|
TRACE_DEVEL("outgoing connection killed", H1_EV_STRM_END|H1_EV_H1C_END);
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (h1c->conn->owner == sess)
|
||||||
|
h1c->conn->owner = NULL;
|
||||||
|
|
||||||
|
/* mark that the tasklet may lose its context to another thread and
|
||||||
|
* that the handler needs to check it under the idle conns lock.
|
||||||
|
*/
|
||||||
|
HA_ATOMIC_OR(&h1c->wait_event.tasklet->state, TASK_F_USR1);
|
||||||
|
h1c->conn->xprt->subscribe(h1c->conn, h1c->conn->xprt_ctx, SUB_RETRY_RECV, &h1c->wait_event);
|
||||||
|
xprt_set_idle(h1c->conn, h1c->conn->xprt, h1c->conn->xprt_ctx);
|
||||||
|
|
||||||
|
if (!srv_add_to_idle_list(objt_server(h1c->conn->target), h1c->conn, is_not_first)) {
|
||||||
|
/* The server doesn't want it, let's kill the connection right away */
|
||||||
|
h1c->conn->mux->destroy(h1c);
|
||||||
|
TRACE_DEVEL("outgoing connection killed", H1_EV_STRM_END|H1_EV_H1C_END);
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
/* At this point, the connection has been added to the
|
||||||
|
* server idle list, so another thread may already have
|
||||||
|
* hijacked it, so we can't do anything with it.
|
||||||
|
*/
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
release:
|
||||||
|
/* We don't want to close right now unless the connection is in error or shut down for writes */
|
||||||
|
if ((h1c->flags & H1C_F_ERROR) ||
|
||||||
|
(h1c->state == H1_CS_CLOSED) ||
|
||||||
|
(h1c->state == H1_CS_CLOSING && !b_data(&h1c->obuf)) ||
|
||||||
|
!h1c->conn->owner) {
|
||||||
|
TRACE_DEVEL("killing dead connection", H1_EV_STRM_END, h1c->conn);
|
||||||
|
h1_release(h1c);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (h1c->state == H1_CS_IDLE) {
|
||||||
|
/* If we have a new request, process it immediately or
|
||||||
|
* subscribe for reads waiting for new data
|
||||||
|
*/
|
||||||
|
if (unlikely(b_data(&h1c->ibuf))) {
|
||||||
|
if (h1_process(h1c) == -1)
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
h1c->conn->xprt->subscribe(h1c->conn, h1c->conn->xprt_ctx, SUB_RETRY_RECV, &h1c->wait_event);
|
||||||
|
}
|
||||||
|
h1_set_idle_expiration(h1c);
|
||||||
|
h1_refresh_timeout(h1c);
|
||||||
|
}
|
||||||
|
end:
|
||||||
|
TRACE_LEAVE(H1_EV_STRM_END);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initialize the mux once it's attached. It is expected that conn->ctx points
|
* Initialize the mux once it's attached. It is expected that conn->ctx points
|
||||||
* to the existing stream connector (for outgoing connections or for incoming
|
* to the existing stream connector (for outgoing connections or for incoming
|
||||||
@ -4106,9 +4218,6 @@ static void h1_destroy(void *ctx)
|
|||||||
static void h1_detach(struct sedesc *sd)
|
static void h1_detach(struct sedesc *sd)
|
||||||
{
|
{
|
||||||
struct h1s *h1s = sd->se;
|
struct h1s *h1s = sd->se;
|
||||||
struct h1c *h1c;
|
|
||||||
struct session *sess;
|
|
||||||
int is_not_first;
|
|
||||||
|
|
||||||
TRACE_ENTER(H1_EV_STRM_END, h1s ? h1s->h1c->conn : NULL, h1s);
|
TRACE_ENTER(H1_EV_STRM_END, h1s ? h1s->h1c->conn : NULL, h1s);
|
||||||
|
|
||||||
@ -4116,100 +4225,8 @@ static void h1_detach(struct sedesc *sd)
|
|||||||
TRACE_LEAVE(H1_EV_STRM_END);
|
TRACE_LEAVE(H1_EV_STRM_END);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
h1s_finish_detach(h1s);
|
||||||
|
|
||||||
sess = h1s->sess;
|
|
||||||
h1c = h1s->h1c;
|
|
||||||
|
|
||||||
sess->accept_date = date;
|
|
||||||
sess->accept_ts = now_ns;
|
|
||||||
sess->t_handshake = 0;
|
|
||||||
sess->t_idle = -1;
|
|
||||||
|
|
||||||
is_not_first = h1s->flags & H1S_F_NOT_FIRST;
|
|
||||||
h1s_destroy(h1s);
|
|
||||||
|
|
||||||
if (h1c->state == H1_CS_IDLE && (h1c->flags & H1C_F_IS_BACK)) {
|
|
||||||
/* this connection may be killed at any moment, we want it to
|
|
||||||
* die "cleanly" (i.e. only an RST).
|
|
||||||
*/
|
|
||||||
h1c->flags |= H1C_F_SILENT_SHUT;
|
|
||||||
|
|
||||||
/* If there are any excess server data in the input buffer,
|
|
||||||
* release it and close the connection ASAP (some data may
|
|
||||||
* remain in the output buffer). This happens if a server sends
|
|
||||||
* invalid responses. So in such case, we don't want to reuse
|
|
||||||
* the connection
|
|
||||||
*/
|
|
||||||
if (b_data(&h1c->ibuf)) {
|
|
||||||
h1_release_buf(h1c, &h1c->ibuf);
|
|
||||||
h1_close(h1c);
|
|
||||||
TRACE_DEVEL("remaining data on detach, kill connection", H1_EV_STRM_END|H1_EV_H1C_END);
|
|
||||||
goto release;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (h1c->conn->flags & CO_FL_PRIVATE) {
|
|
||||||
/* Add the connection in the session server list, if not already done */
|
|
||||||
if (!session_add_conn(sess, h1c->conn, h1c->conn->target)) {
|
|
||||||
h1c->conn->owner = NULL;
|
|
||||||
h1c->conn->mux->destroy(h1c);
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
/* Always idle at this step */
|
|
||||||
if (session_check_idle_conn(sess, h1c->conn)) {
|
|
||||||
/* The connection got destroyed, let's leave */
|
|
||||||
TRACE_DEVEL("outgoing connection killed", H1_EV_STRM_END|H1_EV_H1C_END);
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (h1c->conn->owner == sess)
|
|
||||||
h1c->conn->owner = NULL;
|
|
||||||
|
|
||||||
/* mark that the tasklet may lose its context to another thread and
|
|
||||||
* that the handler needs to check it under the idle conns lock.
|
|
||||||
*/
|
|
||||||
HA_ATOMIC_OR(&h1c->wait_event.tasklet->state, TASK_F_USR1);
|
|
||||||
h1c->conn->xprt->subscribe(h1c->conn, h1c->conn->xprt_ctx, SUB_RETRY_RECV, &h1c->wait_event);
|
|
||||||
xprt_set_idle(h1c->conn, h1c->conn->xprt, h1c->conn->xprt_ctx);
|
|
||||||
|
|
||||||
if (!srv_add_to_idle_list(objt_server(h1c->conn->target), h1c->conn, is_not_first)) {
|
|
||||||
/* The server doesn't want it, let's kill the connection right away */
|
|
||||||
h1c->conn->mux->destroy(h1c);
|
|
||||||
TRACE_DEVEL("outgoing connection killed", H1_EV_STRM_END|H1_EV_H1C_END);
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
/* At this point, the connection has been added to the
|
|
||||||
* server idle list, so another thread may already have
|
|
||||||
* hijacked it, so we can't do anything with it.
|
|
||||||
*/
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
release:
|
|
||||||
/* We don't want to close right now unless the connection is in error or shut down for writes */
|
|
||||||
if ((h1c->flags & H1C_F_ERROR) ||
|
|
||||||
(h1c->state == H1_CS_CLOSED) ||
|
|
||||||
(h1c->state == H1_CS_CLOSING && !b_data(&h1c->obuf)) ||
|
|
||||||
!h1c->conn->owner) {
|
|
||||||
TRACE_DEVEL("killing dead connection", H1_EV_STRM_END, h1c->conn);
|
|
||||||
h1_release(h1c);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (h1c->state == H1_CS_IDLE) {
|
|
||||||
/* If we have a new request, process it immediately or
|
|
||||||
* subscribe for reads waiting for new data
|
|
||||||
*/
|
|
||||||
if (unlikely(b_data(&h1c->ibuf))) {
|
|
||||||
if (h1_process(h1c) == -1)
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
h1c->conn->xprt->subscribe(h1c->conn, h1c->conn->xprt_ctx, SUB_RETRY_RECV, &h1c->wait_event);
|
|
||||||
}
|
|
||||||
h1_set_idle_expiration(h1c);
|
|
||||||
h1_refresh_timeout(h1c);
|
|
||||||
}
|
|
||||||
end:
|
end:
|
||||||
TRACE_LEAVE(H1_EV_STRM_END);
|
TRACE_LEAVE(H1_EV_STRM_END);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user