diff --git a/include/haproxy/mux_h1-t.h b/include/haproxy/mux_h1-t.h index dcc547ab6..abe5cb87b 100644 --- a/include/haproxy/mux_h1-t.h +++ b/include/haproxy/mux_h1-t.h @@ -131,5 +131,33 @@ static forceinline char *h1s_show_flags(char *buf, size_t len, const char *delim #undef _ } +/* H1 connection state, in h1c->state */ +enum h1_cs { + H1_CS_IDLE, /* IDLE connection. A freashly open or a reusable connection (H1S is NULL) */ + H1_CS_EMBRYONIC, /* Connection is waiting for the message headers (H1S is not NULL, not attached to a SC - Frontend connection only) */ + H1_CS_UPGRADING, /* TCP>H1 upgrade in-progress (H1S is not NULL and attached to a SC - Frontend connection only) */ + H1_CS_RUNNING, /* Connection fully established and the H1S is processing data (H1S is not NULL and attached to a SC) */ + H1_CS_CLOSING, /* Send pending outgoing data and close the connection ASAP (H1S may be NULL) */ + H1_CS_CLOSED, /* Connection must be closed now and H1C must be released (H1S is NULL) */ + H1_CS_ENTRIES, +} __attribute__((packed)); + + +/**** tiny state decoding functions for debug helpers ****/ + +/* returns a h1c state as an abbreviated 3-letter string, or "???" if unknown */ +static inline const char *h1c_st_to_str(enum h1_cs st) +{ + switch (st) { + case H1_CS_IDLE: return "IDL"; + case H1_CS_EMBRYONIC: return "EMB"; + case H1_CS_UPGRADING: return "UPG"; + case H1_CS_RUNNING: return "RUN"; + case H1_CS_CLOSING: return "CLI"; + case H1_CS_CLOSED: return "CLD"; + default: return "???"; + } +} + #endif /* _HAPROXY_MUX_H1_T_H */ diff --git a/src/mux_h1.c b/src/mux_h1.c index 2d8ef24b7..6fd4836cc 100644 --- a/src/mux_h1.c +++ b/src/mux_h1.c @@ -39,6 +39,8 @@ struct h1c { struct task *task; /* timeout management task */ uint32_t flags; /* Connection flags: H1C_F_* */ + enum h1_cs state; /* Connection state */ + struct buffer ibuf; /* Input buffer to store data before parsing */ struct buffer obuf; /* Output buffer to store data after reformatting */ @@ -331,7 +333,7 @@ static void h1_trace(enum trace_level level, uint64_t mask, const struct trace_s return; /* Display frontend/backend info by default */ - chunk_appendf(&trace_buf, " : [%c]", ((h1c->flags & H1C_F_IS_BACK) ? 'B' : 'F')); + chunk_appendf(&trace_buf, " : [%c,%s]", ((h1c->flags & H1C_F_IS_BACK) ? 'B' : 'F'), h1c_st_to_str(h1c->state)); /* Display request and response states if h1s is defined */ if (h1s) { @@ -518,6 +520,23 @@ static inline void h1_release_buf(struct h1c *h1c, struct buffer *bptr) } } +/* Returns 1 if the H1 connection is alive (IDLE, EMBRYONIC, RUNNING or + * RUNNING). Ortherwise 0 is returned. + */ +static inline int h1_is_alive(const struct h1c *h1c) +{ + return (h1c->state <= H1_CS_RUNNING); +} + +/* Switch the H1 connection to CLOSING or CLOSED mode, depending on the output + * buffer state and if there is still a H1 stream or not. If there are sill + * pending outgoing data or if there is still a H1 stream, it is set to CLOSING + * state. Otherwise it is set to CLOSED mode. */ +static inline void h1_close(struct h1c *h1c) +{ + h1c->state = ((h1c->h1s || b_data(&h1c->obuf)) ? H1_CS_CLOSING : H1_CS_CLOSED); +} + /* returns the number of streams in use on a connection to figure if it's idle * or not. We rely on H1C_F_ST_IDLE to know if the connection is in-use or * not. This flag is only set when no H1S is attached and when the previous @@ -888,6 +907,7 @@ static int h1_init(struct connection *conn, struct proxy *proxy, struct session h1c->conn = conn; h1c->px = proxy; + h1c->state = H1_CS_IDLE; h1c->flags = H1C_F_ST_IDLE; h1c->errcode = 0; h1c->ibuf = *input;