ngx_del_timer(&h3c->keepalive);
}
}
+
+
+ngx_int_t
+ngx_http_v3_check_flood(ngx_connection_t *c)
+{
+ ngx_http_v3_session_t *h3c;
+
+ h3c = ngx_http_v3_get_session(c);
+
+ if (h3c->total_bytes / 8 > h3c->payload_bytes + 1048576) {
+ ngx_log_error(NGX_LOG_INFO, c->log, 0, "http3 flood detected");
+
+ ngx_http_v3_finalize_connection(c, NGX_HTTP_V3_ERR_NO_ERROR,
+ "HTTP/3 flood detected");
+ return NGX_ERROR;
+ }
+
+ return NGX_OK;
+}
uint64_t max_push_id;
uint64_t goaway_push_id;
+ off_t total_bytes;
+ off_t payload_bytes;
+
ngx_uint_t goaway; /* unsigned goaway:1; */
ngx_connection_t *known_streams[NGX_HTTP_V3_MAX_KNOWN_STREAM];
void ngx_http_v3_init(ngx_connection_t *c);
ngx_int_t ngx_http_v3_init_session(ngx_connection_t *c);
+ngx_int_t ngx_http_v3_check_flood(ngx_connection_t *c);
ngx_int_t ngx_http_v3_read_request_body(ngx_http_request_t *r);
ngx_int_t ngx_http_v3_read_unbuffered_request_body(ngx_http_request_t *r);
ngx_list_part_t *part;
ngx_table_elt_t *header;
ngx_connection_t *c;
+ ngx_http_v3_session_t *h3c;
ngx_http_v3_filter_ctx_t *ctx;
ngx_http_core_loc_conf_t *clcf;
ngx_http_core_srv_conf_t *cscf;
return NGX_OK;
}
+ h3c = ngx_http_v3_get_session(r->connection);
+
if (r->method == NGX_HTTP_HEAD) {
r->header_only = 1;
}
n = b->last - b->pos;
+ h3c->payload_bytes += n;
+
len = ngx_http_v3_encode_varlen_int(NULL, NGX_HTTP_V3_FRAME_HEADERS)
+ ngx_http_v3_encode_varlen_int(NULL, n);
b->last = (u_char *) ngx_http_v3_encode_varlen_int(b->last,
r->headers_out.content_length_n);
+ h3c->payload_bytes += r->headers_out.content_length_n;
+ h3c->total_bytes += r->headers_out.content_length_n;
+
cl = ngx_alloc_chain_link(r->pool);
if (cl == NULL) {
return NGX_ERROR;
ngx_http_set_ctx(r, ctx, ngx_http_v3_filter_module);
}
+ for (cl = out; cl; cl = cl->next) {
+ h3c->total_bytes += cl->buf->last - cl->buf->pos;
+ }
+
return ngx_http_write_filter(r, out);
}
ngx_http_v3_create_push_promise(ngx_http_request_t *r, ngx_str_t *path,
uint64_t push_id)
{
- size_t n, len;
- ngx_buf_t *b;
- ngx_chain_t *hl, *cl;
+ size_t n, len;
+ ngx_buf_t *b;
+ ngx_chain_t *hl, *cl;
+ ngx_http_v3_session_t *h3c;
+
+ h3c = ngx_http_v3_get_session(r->connection);
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"http3 create push promise id:%uL", push_id);
n = b->last - b->pos;
+ h3c->payload_bytes += n;
+
len = ngx_http_v3_encode_varlen_int(NULL, NGX_HTTP_V3_FRAME_PUSH_PROMISE)
+ ngx_http_v3_encode_varlen_int(NULL, n);
ngx_int_t rc;
ngx_buf_t *b;
ngx_chain_t *out, *cl, *tl, **ll;
+ ngx_http_v3_session_t *h3c;
ngx_http_v3_filter_ctx_t *ctx;
if (in == NULL) {
return ngx_http_next_body_filter(r, in);
}
+ h3c = ngx_http_v3_get_session(r->connection);
+
out = NULL;
ll = &out;
tl->next = out;
out = tl;
+
+ h3c->payload_bytes += size;
}
if (cl->buf->last_buf) {
*ll = NULL;
}
+ for (cl = out; cl; cl = cl->next) {
+ h3c->total_bytes += cl->buf->last - cl->buf->pos;
+ }
+
rc = ngx_http_next_body_filter(r, out);
ngx_chain_update_chains(r->pool, &ctx->free, &ctx->busy, &out,
ngx_http_v3_create_trailers(ngx_http_request_t *r,
ngx_http_v3_filter_ctx_t *ctx)
{
- size_t len, n;
- u_char *p;
- ngx_buf_t *b;
- ngx_uint_t i;
- ngx_chain_t *cl, *hl;
- ngx_list_part_t *part;
- ngx_table_elt_t *header;
+ size_t len, n;
+ u_char *p;
+ ngx_buf_t *b;
+ ngx_uint_t i;
+ ngx_chain_t *cl, *hl;
+ ngx_list_part_t *part;
+ ngx_table_elt_t *header;
+ ngx_http_v3_session_t *h3c;
+
+ h3c = ngx_http_v3_get_session(r->connection);
len = 0;
n = b->last - b->pos;
+ h3c->payload_bytes += n;
+
hl = ngx_chain_get_free_buf(r->pool, &ctx->free);
if (hl == NULL) {
return NULL;
ngx_int_t rc;
ngx_connection_t *c;
ngx_http_request_t *r;
+ ngx_http_v3_session_t *h3c;
ngx_http_core_srv_conf_t *cscf;
ngx_http_v3_parse_headers_t *st;
return;
}
+ h3c = ngx_http_v3_get_session(c);
+
st = &r->v3_parse->headers;
b = r->header_in;
}
r->request_length += b->pos - p;
+ h3c->total_bytes += b->pos - p;
+
+ if (ngx_http_v3_check_flood(c) != NGX_OK) {
+ ngx_http_close_request(r, NGX_HTTP_CLOSE);
+ break;
+ }
if (rc == NGX_BUSY) {
if (rev->error) {
/* rc == NGX_OK || rc == NGX_DONE */
+ h3c->payload_bytes += ngx_http_v3_encode_field_l(NULL,
+ &st->field_rep.field.name,
+ &st->field_rep.field.value);
+
if (ngx_http_v3_process_header(r, &st->field_rep.field.name,
&st->field_rep.field.value)
!= NGX_OK)
ngx_buf_t *b;
ngx_uint_t last;
ngx_chain_t *cl, *out, *tl, **ll;
+ ngx_http_v3_session_t *h3c;
ngx_http_request_body_t *rb;
ngx_http_core_loc_conf_t *clcf;
ngx_http_core_srv_conf_t *cscf;
rb = r->request_body;
st = &r->v3_parse->body;
+ h3c = ngx_http_v3_get_session(r->connection);
+
if (rb->rest == -1) {
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
rc = ngx_http_v3_parse_data(r->connection, st, cl->buf);
r->request_length += cl->buf->pos - p;
+ h3c->total_bytes += cl->buf->pos - p;
+
+ if (ngx_http_v3_check_flood(r->connection) != NGX_OK) {
+ return NGX_HTTP_CLOSE;
+ }
if (rc == NGX_AGAIN) {
continue;
{
rb->received += st->length;
r->request_length += st->length;
+ h3c->total_bytes += st->length;
+ h3c->payload_bytes += st->length;
if (st->length < 8) {
cl->buf->pos += (size_t) st->length;
rb->received += st->length;
r->request_length += st->length;
+ h3c->total_bytes += st->length;
+ h3c->payload_bytes += st->length;
st->length = 0;
} else {
st->length -= size;
rb->received += size;
r->request_length += size;
+ h3c->total_bytes += size;
+ h3c->payload_bytes += size;
cl->buf->pos = cl->buf->last;
}
ngx_buf_t b;
ngx_int_t rc;
ngx_connection_t *c;
+ ngx_http_v3_session_t *h3c;
ngx_http_v3_uni_stream_t *us;
c = rev->data;
b.pos = buf;
b.last = buf + n;
+ h3c = ngx_http_v3_get_session(c);
+ h3c->total_bytes += n;
+
+ if (ngx_http_v3_check_flood(c) != NGX_OK) {
+ ngx_http_v3_close_uni_stream(c);
+ return;
+ }
+
rc = ngx_http_v3_parse_uni(c, &us->parse, &b);
if (rc == NGX_DONE) {
p = (u_char *) ngx_http_v3_encode_varlen_int(p, push_id);
n = p - buf;
+ h3c = ngx_http_v3_get_session(c);
+ h3c->total_bytes += n;
+
if (sc->send(sc, buf, n) != (ssize_t) n) {
goto failed;
}
goto failed;
}
- h3c = ngx_http_v3_get_session(c);
h3c->npushing++;
cln->handler = ngx_http_v3_push_cleanup;
n = (u_char *) ngx_http_v3_encode_varlen_int(buf, type) - buf;
+ h3c = ngx_http_v3_get_session(c);
+ h3c->total_bytes += n;
+
if (sc->send(sc, buf, n) != (ssize_t) n) {
goto failed;
}
u_char *p, buf[NGX_HTTP_V3_VARLEN_INT_LEN * 6];
size_t n;
ngx_connection_t *cc;
+ ngx_http_v3_session_t *h3c;
ngx_http_v3_srv_conf_t *h3scf;
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 send settings");
p = (u_char *) ngx_http_v3_encode_varlen_int(p, h3scf->max_blocked_streams);
n = p - buf;
+ h3c = ngx_http_v3_get_session(c);
+ h3c->total_bytes += n;
+
if (cc->send(cc, buf, n) != (ssize_t) n) {
goto failed;
}
ngx_int_t
ngx_http_v3_send_goaway(ngx_connection_t *c, uint64_t id)
{
- u_char *p, buf[NGX_HTTP_V3_VARLEN_INT_LEN * 3];
- size_t n;
- ngx_connection_t *cc;
+ u_char *p, buf[NGX_HTTP_V3_VARLEN_INT_LEN * 3];
+ size_t n;
+ ngx_connection_t *cc;
+ ngx_http_v3_session_t *h3c;
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 send goaway %uL", id);
p = (u_char *) ngx_http_v3_encode_varlen_int(p, id);
n = p - buf;
+ h3c = ngx_http_v3_get_session(c);
+ h3c->total_bytes += n;
+
if (cc->send(cc, buf, n) != (ssize_t) n) {
goto failed;
}
ngx_int_t
ngx_http_v3_send_ack_section(ngx_connection_t *c, ngx_uint_t stream_id)
{
- u_char buf[NGX_HTTP_V3_PREFIX_INT_LEN];
- size_t n;
- ngx_connection_t *dc;
+ u_char buf[NGX_HTTP_V3_PREFIX_INT_LEN];
+ size_t n;
+ ngx_connection_t *dc;
+ ngx_http_v3_session_t *h3c;
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
"http3 client ack section %ui", stream_id);
buf[0] = 0x80;
n = (u_char *) ngx_http_v3_encode_prefix_int(buf, stream_id, 7) - buf;
+ h3c = ngx_http_v3_get_session(c);
+ h3c->total_bytes += n;
+
if (dc->send(dc, buf, n) != (ssize_t) n) {
ngx_http_v3_close_uni_stream(dc);
return NGX_ERROR;
ngx_int_t
ngx_http_v3_send_cancel_stream(ngx_connection_t *c, ngx_uint_t stream_id)
{
- u_char buf[NGX_HTTP_V3_PREFIX_INT_LEN];
- size_t n;
- ngx_connection_t *dc;
+ u_char buf[NGX_HTTP_V3_PREFIX_INT_LEN];
+ size_t n;
+ ngx_connection_t *dc;
+ ngx_http_v3_session_t *h3c;
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
"http3 client cancel stream %ui", stream_id);
buf[0] = 0x40;
n = (u_char *) ngx_http_v3_encode_prefix_int(buf, stream_id, 6) - buf;
+ h3c = ngx_http_v3_get_session(c);
+ h3c->total_bytes += n;
+
if (dc->send(dc, buf, n) != (ssize_t) n) {
ngx_http_v3_close_uni_stream(dc);
return NGX_ERROR;
ngx_int_t
ngx_http_v3_send_inc_insert_count(ngx_connection_t *c, ngx_uint_t inc)
{
- u_char buf[NGX_HTTP_V3_PREFIX_INT_LEN];
- size_t n;
- ngx_connection_t *dc;
+ u_char buf[NGX_HTTP_V3_PREFIX_INT_LEN];
+ size_t n;
+ ngx_connection_t *dc;
+ ngx_http_v3_session_t *h3c;
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
"http3 client increment insert count %ui", inc);
buf[0] = 0;
n = (u_char *) ngx_http_v3_encode_prefix_int(buf, inc, 6) - buf;
+ h3c = ngx_http_v3_get_session(c);
+ h3c->total_bytes += n;
+
if (dc->send(dc, buf, n) != (ssize_t) n) {
ngx_http_v3_close_uni_stream(dc);
return NGX_ERROR;