MEDIUM: h2: produce some logs on early errors that prevent streams from being created
The h2 mux currently lacks some basic transparency. Some errors cause the
connection to be aborted but they couldn't be reported. With this patch,
almost all situations where an error will cause a stream or connection to
be aborted without the ability for an existing stream to report it will be
reported in the logs. This at least provides a solution to monitor the
activity and abnormal traffic.
diff --git a/src/mux_h2.c b/src/mux_h2.c
index f7e327e..70a1421 100644
--- a/src/mux_h2.c
+++ b/src/mux_h2.c
@@ -705,6 +705,7 @@
out_close:
h2s_destroy(h2s);
h2s = NULL;
+ sess_log(sess);
out:
return h2s;
}
@@ -802,6 +803,9 @@
ret1 = b_isteq(&h2c->dbuf, 0, b_data(&h2c->dbuf), ist(H2_CONN_PREFACE));
if (unlikely(ret1 <= 0)) {
+ if (ret1 < 0)
+ sess_log(h2c->conn->owner);
+
if (ret1 < 0 || conn_xprt_read0_pending(h2c->conn))
h2c_error(h2c, H2_ERR_PROTOCOL_ERROR);
return 0;
@@ -1192,6 +1196,7 @@
h2c->st0 = H2_CS_FRAME_A;
return 1;
fail:
+ sess_log(h2c->conn->owner);
h2c_error(h2c, error);
return 0;
}
@@ -1588,6 +1593,7 @@
if (!h2c->dfl) {
error = H2_ERR_PROTOCOL_ERROR; // empty headers frame!
+ sess_log(h2c->conn->owner);
goto strm_err;
}
@@ -1606,14 +1612,20 @@
* trailers (not supported for now).
*/
error = H2_ERR_PROTOCOL_ERROR;
+ sess_log(h2c->conn->owner);
goto conn_err;
}
else if (h2c->dsi <= h2c->max_id || !(h2c->dsi & 1)) {
/* RFC7540#5.1.1 stream id > prev ones, and must be odd here */
error = H2_ERR_PROTOCOL_ERROR;
+ sess_log(h2c->conn->owner);
goto conn_err;
}
+ /* Note: we don't emit any other logs below because ff we return
+ * positively from h2c_stream_new(), the stream will report the error,
+ * and if we return in error, h2c_stream_new() will emit the error.
+ */
h2s = h2c_stream_new(h2c, h2c->dsi);
if (!h2s) {
error = H2_ERR_INTERNAL_ERROR;
@@ -1752,8 +1764,10 @@
if (h2c->st0 == H2_CS_PREFACE) {
if (unlikely(h2c_frt_recv_preface(h2c) <= 0)) {
/* RFC7540#3.5: a GOAWAY frame MAY be omitted */
- if (h2c->st0 == H2_CS_ERROR)
+ if (h2c->st0 == H2_CS_ERROR) {
h2c->st0 = H2_CS_ERROR2;
+ sess_log(h2c->conn->owner);
+ }
goto fail;
}
@@ -1769,8 +1783,10 @@
*/
if (!h2_get_frame_hdr(&h2c->dbuf, &hdr)) {
/* RFC7540#3.5: a GOAWAY frame MAY be omitted */
- if (h2c->st0 == H2_CS_ERROR)
+ if (h2c->st0 == H2_CS_ERROR) {
h2c->st0 = H2_CS_ERROR2;
+ sess_log(h2c->conn->owner);
+ }
goto fail;
}
@@ -1778,6 +1794,7 @@
/* RFC7540#3.5: a GOAWAY frame MAY be omitted */
h2c_error(h2c, H2_ERR_PROTOCOL_ERROR);
h2c->st0 = H2_CS_ERROR2;
+ sess_log(h2c->conn->owner);
goto fail;
}
@@ -1785,6 +1802,7 @@
/* RFC7540#3.5: a GOAWAY frame MAY be omitted */
h2c_error(h2c, H2_ERR_FRAME_SIZE_ERROR);
h2c->st0 = H2_CS_ERROR2;
+ sess_log(h2c->conn->owner);
goto fail;
}
@@ -1814,6 +1832,10 @@
if ((int)hdr.len < 0 || (int)hdr.len > global.tune.bufsize) {
h2c_error(h2c, H2_ERR_FRAME_SIZE_ERROR);
h2c->st0 = H2_CS_ERROR;
+ if (!h2c->nb_streams) {
+ /* only log if no other stream can report the error */
+ sess_log(h2c->conn->owner);
+ }
break;
}
@@ -1858,6 +1880,10 @@
*/
h2c_error(h2c, H2_ERR_PROTOCOL_ERROR);
h2c->st0 = H2_CS_ERROR;
+ if (!h2c->nb_streams) {
+ /* only log if no other stream can report the error */
+ sess_log(h2c->conn->owner);
+ }
break;
}
@@ -2026,6 +2052,10 @@
case H2_FT_PUSH_PROMISE:
/* not permitted here, RFC7540#5.1 */
h2c_error(h2c, H2_ERR_PROTOCOL_ERROR);
+ if (!h2c->nb_streams) {
+ /* only log if no other stream can report the error */
+ sess_log(h2c->conn->owner);
+ }
break;
/* implement all extra frame types here */