#define H2_CF_RCVD_SHUT 0x00020000 // a recv() attempt already failed on a shutdown
#define H2_CF_END_REACHED 0x00040000 // pending data too short with RCVD_SHUT present
+#define H2_CF_SETTINGS_NEEDED 0x00080000 // can't proceed without knowing settings (frontend or extensions)
#define H2_CF_RCVD_RFC8441 0x00100000 // settings from RFC8441 has been received indicating support for Extended CONNECT
#define H2_CF_SHTS_UPDATED 0x00200000 // SETTINGS_HEADER_TABLE_SIZE updated
#define H2_CF_DTSU_EMITTED 0x00400000 // HPACK Dynamic Table Size Update opcode emitted
&h2_stats_module);
} else {
h2c->flags = H2_CF_NONE;
+ h2c->flags |= H2_CF_SETTINGS_NEEDED;
h2c->shut_timeout = h2c->timeout = prx->timeout.client;
if (tick_isset(prx->timeout.clientfin))
h2c->shut_timeout = prx->timeout.clientfin;
/* need to ACK this frame now */
h2c->st0 = H2_CS_FRAME_A;
+ h2c->flags &= ~H2_CF_SETTINGS_NEEDED;
done:
TRACE_LEAVE(H2_EV_RX_FRAME|H2_EV_RX_SETTINGS, h2c->conn);
return 1;
{
TRACE_ENTER(H2_EV_H2C_WAKE, h2c->conn);
- if (unlikely(h2c->st0 < H2_CS_FRAME_H)) {
+ if (unlikely(h2c->st0 < (h2c->flags & H2_CF_SETTINGS_NEEDED ? H2_CS_FRAME_H : H2_CS_SETTINGS1))) {
if (unlikely(h2c->st0 == H2_CS_PREFACE && (h2c->flags & H2_CF_IS_BACK))) {
if (unlikely(h2c_bck_send_preface(h2c) <= 0)) {
/* RFC7540#3.5: a GOAWAY frame MAY be omitted */
h2c->st0 = H2_CS_SETTINGS1;
}
/* need to wait for the other side */
- if (h2c->st0 < H2_CS_FRAME_H)
+ if (h2c->st0 < (h2c->flags & H2_CF_SETTINGS_NEEDED ? H2_CS_FRAME_H : H2_CS_SETTINGS1))
goto done;
}
/* rfc 7230 #6.1 Connection = list of tokens */
struct ist connection_ist = list[hdr].v;
+ if (h2c->st0 < H2_CS_FRAME_H) {
+ /* this feature is negotiated, can't proceed without
+ * the server's settings.
+ */
+ h2c->flags |= H2_CF_SETTINGS_NEEDED;
+ goto end;
+ }
+
if (!(sl->flags & HTX_SL_F_BODYLESS)) {
TRACE_STATE("cannot convert upgrade for request with payload", H2_EV_TX_FRAME|H2_EV_TX_HDR, h2c->conn, h2s);
goto fail;
}
h2s->flags &= ~H2_SF_NOTIFIED;
- if (h2s->h2c->st0 < H2_CS_FRAME_H) {
+ if (h2s->h2c->st0 < ((h2s->h2c->flags & H2_CF_SETTINGS_NEEDED) ? H2_CS_FRAME_H : H2_CS_SETTINGS1)) {
TRACE_DEVEL("connection not ready, leaving", H2_EV_H2S_SEND|H2_EV_H2S_BLK, h2s->h2c->conn, h2s);
return 0;
}
if (ret < bsize)
goto done;
}
+ else if ((h2s->h2c->flags & H2_CF_SETTINGS_NEEDED) && h2s->h2c->st0 < H2_CS_FRAME_H) {
+ /* cannot proceed further */
+ goto done;
+ }
break;
case HTX_BLK_RES_SL: