2020-03-13 13:36:33 -03:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Copyright (C) Roman Arutyunyan
|
|
|
|
* Copyright (C) Nginx, Inc.
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
#include <ngx_config.h>
|
|
|
|
#include <ngx_core.h>
|
|
|
|
#include <ngx_http.h>
|
|
|
|
|
|
|
|
|
2020-03-18 07:46:35 -03:00
|
|
|
typedef ngx_int_t (*ngx_http_v3_handler_pt)(ngx_connection_t *c, void *data,
|
|
|
|
u_char ch);
|
2020-03-13 13:36:33 -03:00
|
|
|
|
|
|
|
|
|
|
|
typedef struct {
|
2020-03-18 07:46:35 -03:00
|
|
|
ngx_http_v3_handler_pt handler;
|
|
|
|
void *data;
|
2020-03-25 06:14:24 -03:00
|
|
|
ngx_int_t index;
|
2020-03-13 13:36:33 -03:00
|
|
|
} ngx_http_v3_uni_stream_t;
|
|
|
|
|
|
|
|
|
|
|
|
static void ngx_http_v3_close_uni_stream(ngx_connection_t *c);
|
|
|
|
static void ngx_http_v3_read_uni_stream_type(ngx_event_t *rev);
|
2020-03-18 07:46:35 -03:00
|
|
|
static void ngx_http_v3_uni_read_handler(ngx_event_t *rev);
|
2020-03-24 12:05:45 -03:00
|
|
|
static void ngx_http_v3_dummy_write_handler(ngx_event_t *wev);
|
2020-03-25 06:14:24 -03:00
|
|
|
static ngx_connection_t *ngx_http_v3_get_uni_stream(ngx_connection_t *c,
|
2020-03-13 13:36:33 -03:00
|
|
|
ngx_uint_t type);
|
2020-07-21 16:09:22 -04:00
|
|
|
static ngx_int_t ngx_http_v3_send_settings(ngx_connection_t *c);
|
2020-03-13 13:36:33 -03:00
|
|
|
|
|
|
|
|
2020-07-21 16:09:22 -04:00
|
|
|
ngx_int_t
|
|
|
|
ngx_http_v3_init_connection(ngx_connection_t *c)
|
2020-03-13 13:36:33 -03:00
|
|
|
{
|
2020-07-21 16:09:22 -04:00
|
|
|
ngx_http_connection_t *hc;
|
2020-03-13 13:36:33 -03:00
|
|
|
ngx_http_v3_uni_stream_t *us;
|
2020-07-21 16:09:22 -04:00
|
|
|
ngx_http_v3_connection_t *h3c;
|
2020-03-13 13:36:33 -03:00
|
|
|
|
2020-07-21 16:09:22 -04:00
|
|
|
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 init connection");
|
|
|
|
|
|
|
|
hc = c->data;
|
|
|
|
|
|
|
|
if (c->qs == NULL) {
|
|
|
|
h3c = ngx_pcalloc(c->pool, sizeof(ngx_http_v3_connection_t));
|
|
|
|
if (h3c == NULL) {
|
|
|
|
return NGX_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
h3c->hc = *hc;
|
|
|
|
|
|
|
|
ngx_queue_init(&h3c->blocked);
|
|
|
|
|
|
|
|
c->data = h3c;
|
|
|
|
return NGX_OK;
|
|
|
|
}
|
|
|
|
|
2020-07-27 11:51:42 -04:00
|
|
|
if (ngx_http_v3_send_settings(c) == NGX_ERROR) {
|
|
|
|
return NGX_ERROR;
|
2020-07-21 16:09:22 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
if ((c->qs->id & NGX_QUIC_STREAM_UNIDIRECTIONAL) == 0) {
|
|
|
|
return NGX_OK;
|
|
|
|
}
|
2020-03-13 13:36:33 -03:00
|
|
|
|
|
|
|
us = ngx_pcalloc(c->pool, sizeof(ngx_http_v3_uni_stream_t));
|
|
|
|
if (us == NULL) {
|
2020-07-02 09:47:51 -04:00
|
|
|
ngx_http_v3_finalize_connection(c, NGX_HTTP_V3_ERR_INTERNAL_ERROR,
|
|
|
|
NULL);
|
2020-07-21 16:09:22 -04:00
|
|
|
return NGX_ERROR;
|
2020-03-13 13:36:33 -03:00
|
|
|
}
|
|
|
|
|
2020-03-25 06:14:24 -03:00
|
|
|
us->index = -1;
|
2020-03-13 13:36:33 -03:00
|
|
|
|
|
|
|
c->data = us;
|
|
|
|
|
|
|
|
c->read->handler = ngx_http_v3_read_uni_stream_type;
|
2020-03-24 12:05:45 -03:00
|
|
|
c->write->handler = ngx_http_v3_dummy_write_handler;
|
|
|
|
|
2020-03-18 07:46:35 -03:00
|
|
|
ngx_http_v3_read_uni_stream_type(c->read);
|
2020-07-21 16:09:22 -04:00
|
|
|
|
|
|
|
return NGX_DONE;
|
2020-03-13 13:36:33 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
ngx_http_v3_close_uni_stream(ngx_connection_t *c)
|
|
|
|
{
|
2020-03-25 06:14:24 -03:00
|
|
|
ngx_pool_t *pool;
|
2020-03-13 13:36:33 -03:00
|
|
|
ngx_http_v3_connection_t *h3c;
|
|
|
|
ngx_http_v3_uni_stream_t *us;
|
|
|
|
|
|
|
|
us = c->data;
|
|
|
|
h3c = c->qs->parent->data;
|
|
|
|
|
|
|
|
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 close stream");
|
|
|
|
|
2020-03-25 06:14:24 -03:00
|
|
|
if (us->index >= 0) {
|
|
|
|
h3c->known_streams[us->index] = NULL;
|
|
|
|
}
|
2020-03-13 13:36:33 -03:00
|
|
|
|
2020-03-25 06:14:24 -03:00
|
|
|
c->destroyed = 1;
|
2020-03-13 13:36:33 -03:00
|
|
|
|
2020-03-25 06:14:24 -03:00
|
|
|
pool = c->pool;
|
2020-03-13 13:36:33 -03:00
|
|
|
|
2020-03-25 06:14:24 -03:00
|
|
|
ngx_close_connection(c);
|
2020-03-13 13:36:33 -03:00
|
|
|
|
2020-03-25 06:14:24 -03:00
|
|
|
ngx_destroy_pool(pool);
|
2020-03-13 13:36:33 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
2020-03-18 07:46:35 -03:00
|
|
|
ngx_http_v3_read_uni_stream_type(ngx_event_t *rev)
|
2020-03-13 13:36:33 -03:00
|
|
|
{
|
2020-03-18 07:46:35 -03:00
|
|
|
u_char ch;
|
2020-03-13 13:36:33 -03:00
|
|
|
ssize_t n;
|
2020-07-02 09:47:51 -04:00
|
|
|
ngx_int_t index, rc;
|
2020-03-18 07:46:35 -03:00
|
|
|
ngx_connection_t *c;
|
|
|
|
ngx_http_v3_connection_t *h3c;
|
2020-03-25 06:14:24 -03:00
|
|
|
ngx_http_v3_uni_stream_t *us;
|
2020-03-13 13:36:33 -03:00
|
|
|
|
|
|
|
c = rev->data;
|
2020-03-25 06:14:24 -03:00
|
|
|
us = c->data;
|
2020-03-18 07:46:35 -03:00
|
|
|
h3c = c->qs->parent->data;
|
2020-03-13 13:36:33 -03:00
|
|
|
|
2020-03-18 07:46:35 -03:00
|
|
|
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 read stream type");
|
2020-03-13 13:36:33 -03:00
|
|
|
|
|
|
|
while (rev->ready) {
|
|
|
|
|
2020-03-18 07:46:35 -03:00
|
|
|
n = c->recv(c, &ch, 1);
|
2020-03-13 13:36:33 -03:00
|
|
|
|
2020-07-02 09:47:51 -04:00
|
|
|
if (n == NGX_AGAIN) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (n == 0) {
|
|
|
|
rc = NGX_HTTP_V3_ERR_GENERAL_PROTOCOL_ERROR;
|
2020-03-13 13:36:33 -03:00
|
|
|
goto failed;
|
|
|
|
}
|
|
|
|
|
2020-07-02 09:47:51 -04:00
|
|
|
if (n != 1) {
|
|
|
|
rc = NGX_HTTP_V3_ERR_INTERNAL_ERROR;
|
|
|
|
goto failed;
|
2020-03-13 13:36:33 -03:00
|
|
|
}
|
|
|
|
|
2020-03-25 06:14:24 -03:00
|
|
|
switch (ch) {
|
2020-03-13 13:36:33 -03:00
|
|
|
|
2020-03-18 07:46:35 -03:00
|
|
|
case NGX_HTTP_V3_STREAM_ENCODER:
|
2020-03-13 13:36:33 -03:00
|
|
|
|
2020-03-18 07:46:35 -03:00
|
|
|
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
|
|
|
|
"http3 encoder stream");
|
2020-03-13 13:36:33 -03:00
|
|
|
|
2020-03-25 06:14:24 -03:00
|
|
|
index = NGX_HTTP_V3_STREAM_CLIENT_ENCODER;
|
|
|
|
us->handler = ngx_http_v3_parse_encoder;
|
2020-03-18 07:46:35 -03:00
|
|
|
n = sizeof(ngx_http_v3_parse_encoder_t);
|
2020-03-13 13:36:33 -03:00
|
|
|
|
|
|
|
break;
|
|
|
|
|
2020-03-18 07:46:35 -03:00
|
|
|
case NGX_HTTP_V3_STREAM_DECODER:
|
2020-03-13 13:36:33 -03:00
|
|
|
|
2020-03-18 07:46:35 -03:00
|
|
|
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
|
|
|
|
"http3 decoder stream");
|
2020-03-13 13:36:33 -03:00
|
|
|
|
2020-03-25 06:14:24 -03:00
|
|
|
index = NGX_HTTP_V3_STREAM_CLIENT_DECODER;
|
|
|
|
us->handler = ngx_http_v3_parse_decoder;
|
2020-03-18 07:46:35 -03:00
|
|
|
n = sizeof(ngx_http_v3_parse_decoder_t);
|
2020-03-13 13:36:33 -03:00
|
|
|
|
|
|
|
break;
|
|
|
|
|
2020-03-18 07:46:35 -03:00
|
|
|
case NGX_HTTP_V3_STREAM_CONTROL:
|
2020-03-13 13:36:33 -03:00
|
|
|
|
2020-03-18 07:46:35 -03:00
|
|
|
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
|
|
|
|
"http3 control stream");
|
2020-03-13 13:36:33 -03:00
|
|
|
|
2020-03-25 06:14:24 -03:00
|
|
|
index = NGX_HTTP_V3_STREAM_CLIENT_CONTROL;
|
|
|
|
us->handler = ngx_http_v3_parse_control;
|
2020-03-18 07:46:35 -03:00
|
|
|
n = sizeof(ngx_http_v3_parse_control_t);
|
2020-03-13 13:36:33 -03:00
|
|
|
|
|
|
|
break;
|
|
|
|
|
2020-03-18 07:46:35 -03:00
|
|
|
default:
|
2020-03-13 13:36:33 -03:00
|
|
|
|
2020-03-18 07:46:35 -03:00
|
|
|
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
|
2020-03-25 06:14:24 -03:00
|
|
|
"http3 stream 0x%02xi", (ngx_int_t) ch);
|
|
|
|
index = -1;
|
2020-03-18 07:46:35 -03:00
|
|
|
n = 0;
|
|
|
|
}
|
2020-03-13 13:36:33 -03:00
|
|
|
|
2020-03-25 06:14:24 -03:00
|
|
|
if (index >= 0) {
|
|
|
|
if (h3c->known_streams[index]) {
|
|
|
|
ngx_log_error(NGX_LOG_INFO, c->log, 0, "stream exists");
|
2020-07-02 09:47:51 -04:00
|
|
|
rc = NGX_HTTP_V3_ERR_STREAM_CREATION_ERROR;
|
2020-03-25 06:14:24 -03:00
|
|
|
goto failed;
|
|
|
|
}
|
|
|
|
|
|
|
|
us->index = index;
|
|
|
|
h3c->known_streams[index] = c;
|
|
|
|
}
|
|
|
|
|
2020-03-18 07:46:35 -03:00
|
|
|
if (n) {
|
2020-03-25 06:14:24 -03:00
|
|
|
us->data = ngx_pcalloc(c->pool, n);
|
|
|
|
if (us->data == NULL) {
|
2020-07-02 09:47:51 -04:00
|
|
|
rc = NGX_HTTP_V3_ERR_INTERNAL_ERROR;
|
2020-03-13 13:36:33 -03:00
|
|
|
goto failed;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-18 07:46:35 -03:00
|
|
|
rev->handler = ngx_http_v3_uni_read_handler;
|
|
|
|
ngx_http_v3_uni_read_handler(rev);
|
|
|
|
return;
|
|
|
|
}
|
2020-03-13 13:36:33 -03:00
|
|
|
|
|
|
|
if (ngx_handle_read_event(rev, 0) != NGX_OK) {
|
2020-07-02 09:47:51 -04:00
|
|
|
rc = NGX_HTTP_V3_ERR_INTERNAL_ERROR;
|
2020-03-13 13:36:33 -03:00
|
|
|
goto failed;
|
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
failed:
|
|
|
|
|
2020-07-02 09:47:51 -04:00
|
|
|
ngx_http_v3_finalize_connection(c, rc, "could not read stream type");
|
2020-03-13 13:36:33 -03:00
|
|
|
ngx_http_v3_close_uni_stream(c);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
2020-03-18 07:46:35 -03:00
|
|
|
ngx_http_v3_uni_read_handler(ngx_event_t *rev)
|
2020-03-13 13:36:33 -03:00
|
|
|
{
|
2020-03-18 07:46:35 -03:00
|
|
|
u_char buf[128];
|
2020-03-13 13:36:33 -03:00
|
|
|
ssize_t n;
|
2020-03-18 07:46:35 -03:00
|
|
|
ngx_int_t rc, i;
|
2020-03-13 13:36:33 -03:00
|
|
|
ngx_connection_t *c;
|
2020-03-25 06:14:24 -03:00
|
|
|
ngx_http_v3_uni_stream_t *us;
|
2020-03-13 13:36:33 -03:00
|
|
|
|
|
|
|
c = rev->data;
|
2020-03-25 06:14:24 -03:00
|
|
|
us = c->data;
|
2020-03-13 13:36:33 -03:00
|
|
|
|
2020-03-18 07:46:35 -03:00
|
|
|
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 read handler");
|
2020-03-13 13:36:33 -03:00
|
|
|
|
|
|
|
while (rev->ready) {
|
|
|
|
|
2020-03-18 07:46:35 -03:00
|
|
|
n = c->recv(c, buf, sizeof(buf));
|
2020-03-13 13:36:33 -03:00
|
|
|
|
2020-07-02 09:47:51 -04:00
|
|
|
if (n == NGX_ERROR) {
|
|
|
|
rc = NGX_HTTP_V3_ERR_INTERNAL_ERROR;
|
2020-03-13 13:36:33 -03:00
|
|
|
goto failed;
|
|
|
|
}
|
|
|
|
|
2020-07-02 09:47:51 -04:00
|
|
|
if (n == 0) {
|
|
|
|
if (us->index >= 0) {
|
|
|
|
rc = NGX_HTTP_V3_ERR_CLOSED_CRITICAL_STREAM;
|
|
|
|
goto failed;
|
|
|
|
}
|
|
|
|
|
|
|
|
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 read eof");
|
|
|
|
ngx_http_v3_close_uni_stream(c);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-03-18 07:46:35 -03:00
|
|
|
if (n == NGX_AGAIN) {
|
2020-03-13 13:36:33 -03:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2020-03-25 06:14:24 -03:00
|
|
|
if (us->handler == NULL) {
|
2020-03-18 07:46:35 -03:00
|
|
|
continue;
|
|
|
|
}
|
2020-03-13 13:36:33 -03:00
|
|
|
|
2020-03-18 07:46:35 -03:00
|
|
|
for (i = 0; i < n; i++) {
|
2020-03-13 13:36:33 -03:00
|
|
|
|
2020-03-25 06:14:24 -03:00
|
|
|
rc = us->handler(c, us->data, buf[i]);
|
2020-03-13 13:36:33 -03:00
|
|
|
|
2020-07-02 09:47:51 -04:00
|
|
|
if (rc == NGX_DONE) {
|
|
|
|
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
|
|
|
|
"http3 read done");
|
|
|
|
ngx_http_v3_close_uni_stream(c);
|
|
|
|
return;
|
2020-03-13 13:36:33 -03:00
|
|
|
}
|
|
|
|
|
2020-07-02 09:47:51 -04:00
|
|
|
if (rc > 0) {
|
|
|
|
goto failed;
|
2020-03-13 13:36:33 -03:00
|
|
|
}
|
|
|
|
|
2020-07-02 09:47:51 -04:00
|
|
|
if (rc != NGX_AGAIN) {
|
|
|
|
rc = NGX_HTTP_V3_ERR_GENERAL_PROTOCOL_ERROR;
|
|
|
|
goto failed;
|
|
|
|
}
|
2020-03-13 13:36:33 -03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ngx_handle_read_event(rev, 0) != NGX_OK) {
|
2020-07-02 09:47:51 -04:00
|
|
|
rc = NGX_HTTP_V3_ERR_INTERNAL_ERROR;
|
2020-03-13 13:36:33 -03:00
|
|
|
goto failed;
|
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
failed:
|
|
|
|
|
2020-07-02 09:47:51 -04:00
|
|
|
ngx_http_v3_finalize_connection(c, rc, "stream error");
|
2020-03-13 13:36:33 -03:00
|
|
|
ngx_http_v3_close_uni_stream(c);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-03-24 12:05:45 -03:00
|
|
|
static void
|
|
|
|
ngx_http_v3_dummy_write_handler(ngx_event_t *wev)
|
|
|
|
{
|
|
|
|
ngx_connection_t *c;
|
|
|
|
|
|
|
|
c = wev->data;
|
|
|
|
|
|
|
|
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 dummy write handler");
|
|
|
|
|
|
|
|
if (ngx_handle_write_event(wev, 0) != NGX_OK) {
|
2020-07-02 09:47:51 -04:00
|
|
|
ngx_http_v3_finalize_connection(c, NGX_HTTP_V3_ERR_INTERNAL_ERROR,
|
|
|
|
NULL);
|
2020-03-24 12:05:45 -03:00
|
|
|
ngx_http_v3_close_uni_stream(c);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-03-13 13:36:33 -03:00
|
|
|
/* XXX async & buffered stream writes */
|
|
|
|
|
|
|
|
static ngx_connection_t *
|
2020-03-25 06:14:24 -03:00
|
|
|
ngx_http_v3_get_uni_stream(ngx_connection_t *c, ngx_uint_t type)
|
2020-03-13 13:36:33 -03:00
|
|
|
{
|
|
|
|
u_char buf[NGX_HTTP_V3_VARLEN_INT_LEN];
|
|
|
|
size_t n;
|
2020-03-25 06:14:24 -03:00
|
|
|
ngx_int_t index;
|
2020-03-13 13:36:33 -03:00
|
|
|
ngx_connection_t *sc;
|
2020-03-25 06:14:24 -03:00
|
|
|
ngx_http_v3_connection_t *h3c;
|
2020-03-13 13:36:33 -03:00
|
|
|
ngx_http_v3_uni_stream_t *us;
|
|
|
|
|
2020-03-25 06:14:24 -03:00
|
|
|
switch (type) {
|
|
|
|
case NGX_HTTP_V3_STREAM_ENCODER:
|
|
|
|
index = NGX_HTTP_V3_STREAM_SERVER_ENCODER;
|
|
|
|
break;
|
|
|
|
case NGX_HTTP_V3_STREAM_DECODER:
|
|
|
|
index = NGX_HTTP_V3_STREAM_SERVER_DECODER;
|
|
|
|
break;
|
|
|
|
case NGX_HTTP_V3_STREAM_CONTROL:
|
|
|
|
index = NGX_HTTP_V3_STREAM_SERVER_CONTROL;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
index = -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
h3c = c->qs->parent->data;
|
|
|
|
|
|
|
|
if (index >= 0) {
|
|
|
|
if (h3c->known_streams[index]) {
|
|
|
|
return h3c->known_streams[index];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-27 11:51:42 -04:00
|
|
|
sc = ngx_quic_open_stream(c, 0);
|
2020-03-13 13:36:33 -03:00
|
|
|
if (sc == NULL) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
|
|
|
|
"http3 create uni stream, type:%ui", type);
|
|
|
|
|
|
|
|
us = ngx_pcalloc(sc->pool, sizeof(ngx_http_v3_uni_stream_t));
|
|
|
|
if (us == NULL) {
|
|
|
|
goto failed;
|
|
|
|
}
|
|
|
|
|
2020-03-25 06:14:24 -03:00
|
|
|
us->index = index;
|
|
|
|
|
2020-03-13 13:36:33 -03:00
|
|
|
sc->data = us;
|
|
|
|
|
2020-03-24 12:05:45 -03:00
|
|
|
sc->read->handler = ngx_http_v3_uni_read_handler;
|
|
|
|
sc->write->handler = ngx_http_v3_dummy_write_handler;
|
|
|
|
|
2020-05-19 08:41:41 -04:00
|
|
|
if (index >= 0) {
|
|
|
|
h3c->known_streams[index] = sc;
|
|
|
|
}
|
2020-03-13 13:36:33 -03:00
|
|
|
|
|
|
|
n = (u_char *) ngx_http_v3_encode_varlen_int(buf, type) - buf;
|
|
|
|
|
|
|
|
if (sc->send(sc, buf, n) != (ssize_t) n) {
|
|
|
|
goto failed;
|
|
|
|
}
|
|
|
|
|
|
|
|
return sc;
|
|
|
|
|
|
|
|
failed:
|
|
|
|
|
|
|
|
ngx_http_v3_close_uni_stream(sc);
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-07-21 16:09:22 -04:00
|
|
|
static ngx_int_t
|
2020-07-02 08:34:05 -04:00
|
|
|
ngx_http_v3_send_settings(ngx_connection_t *c)
|
|
|
|
{
|
|
|
|
u_char *p, buf[NGX_HTTP_V3_VARLEN_INT_LEN * 6];
|
|
|
|
size_t n;
|
|
|
|
ngx_connection_t *cc;
|
2020-07-23 06:12:01 -04:00
|
|
|
ngx_http_v3_srv_conf_t *h3scf;
|
2020-07-02 08:34:05 -04:00
|
|
|
ngx_http_v3_connection_t *h3c;
|
|
|
|
|
2020-07-27 11:51:42 -04:00
|
|
|
h3c = c->qs->parent->data;
|
|
|
|
|
|
|
|
if (h3c->settings_sent) {
|
|
|
|
return NGX_OK;
|
|
|
|
}
|
|
|
|
|
2020-07-02 08:34:05 -04:00
|
|
|
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 send settings");
|
|
|
|
|
|
|
|
cc = ngx_http_v3_get_uni_stream(c, NGX_HTTP_V3_STREAM_CONTROL);
|
|
|
|
if (cc == NULL) {
|
2020-07-27 11:51:42 -04:00
|
|
|
return NGX_DECLINED;
|
2020-07-02 08:34:05 -04:00
|
|
|
}
|
|
|
|
|
2020-07-23 06:12:01 -04:00
|
|
|
h3scf = ngx_http_get_module_srv_conf(h3c->hc.conf_ctx, ngx_http_v3_module);
|
2020-07-02 08:34:05 -04:00
|
|
|
|
|
|
|
n = ngx_http_v3_encode_varlen_int(NULL,
|
|
|
|
NGX_HTTP_V3_PARAM_MAX_TABLE_CAPACITY);
|
2020-07-23 06:12:01 -04:00
|
|
|
n += ngx_http_v3_encode_varlen_int(NULL, h3scf->max_table_capacity);
|
2020-07-02 08:34:05 -04:00
|
|
|
n += ngx_http_v3_encode_varlen_int(NULL, NGX_HTTP_V3_PARAM_BLOCKED_STREAMS);
|
2020-07-23 06:12:01 -04:00
|
|
|
n += ngx_http_v3_encode_varlen_int(NULL, h3scf->max_blocked_streams);
|
2020-07-02 08:34:05 -04:00
|
|
|
|
|
|
|
p = (u_char *) ngx_http_v3_encode_varlen_int(buf,
|
|
|
|
NGX_HTTP_V3_FRAME_SETTINGS);
|
|
|
|
p = (u_char *) ngx_http_v3_encode_varlen_int(p, n);
|
|
|
|
p = (u_char *) ngx_http_v3_encode_varlen_int(p,
|
|
|
|
NGX_HTTP_V3_PARAM_MAX_TABLE_CAPACITY);
|
2020-07-23 06:12:01 -04:00
|
|
|
p = (u_char *) ngx_http_v3_encode_varlen_int(p, h3scf->max_table_capacity);
|
2020-07-02 08:34:05 -04:00
|
|
|
p = (u_char *) ngx_http_v3_encode_varlen_int(p,
|
|
|
|
NGX_HTTP_V3_PARAM_BLOCKED_STREAMS);
|
2020-07-23 06:12:01 -04:00
|
|
|
p = (u_char *) ngx_http_v3_encode_varlen_int(p, h3scf->max_blocked_streams);
|
2020-07-02 08:34:05 -04:00
|
|
|
n = p - buf;
|
|
|
|
|
|
|
|
if (cc->send(cc, buf, n) != (ssize_t) n) {
|
|
|
|
goto failed;
|
|
|
|
}
|
|
|
|
|
2020-07-27 11:51:42 -04:00
|
|
|
h3c->settings_sent = 1;
|
|
|
|
|
2020-07-02 08:34:05 -04:00
|
|
|
return NGX_OK;
|
|
|
|
|
|
|
|
failed:
|
|
|
|
|
|
|
|
ngx_http_v3_close_uni_stream(cc);
|
|
|
|
|
2020-07-27 11:51:42 -04:00
|
|
|
ngx_http_v3_finalize_connection(c, NGX_HTTP_V3_ERR_INTERNAL_ERROR,
|
|
|
|
"could not send settings");
|
|
|
|
|
2020-07-02 08:34:05 -04:00
|
|
|
return NGX_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-03-13 13:36:33 -03:00
|
|
|
ngx_int_t
|
|
|
|
ngx_http_v3_client_ref_insert(ngx_connection_t *c, ngx_uint_t dynamic,
|
|
|
|
ngx_uint_t index, ngx_str_t *value)
|
|
|
|
{
|
|
|
|
u_char *p, buf[NGX_HTTP_V3_PREFIX_INT_LEN * 2];
|
|
|
|
size_t n;
|
|
|
|
ngx_connection_t *ec;
|
|
|
|
|
|
|
|
ngx_log_debug3(NGX_LOG_DEBUG_HTTP, c->log, 0,
|
|
|
|
"http3 client ref insert, %s[%ui] \"%V\"",
|
|
|
|
dynamic ? "dynamic" : "static", index, value);
|
|
|
|
|
2020-03-25 06:14:24 -03:00
|
|
|
ec = ngx_http_v3_get_uni_stream(c, NGX_HTTP_V3_STREAM_ENCODER);
|
2020-03-13 13:36:33 -03:00
|
|
|
if (ec == NULL) {
|
|
|
|
return NGX_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
p = buf;
|
|
|
|
|
|
|
|
*p = (dynamic ? 0x80 : 0xc0);
|
|
|
|
p = (u_char *) ngx_http_v3_encode_prefix_int(p, index, 6);
|
|
|
|
|
|
|
|
/* XXX option for huffman? */
|
|
|
|
*p = 0;
|
|
|
|
p = (u_char *) ngx_http_v3_encode_prefix_int(p, value->len, 7);
|
|
|
|
|
|
|
|
n = p - buf;
|
|
|
|
|
|
|
|
if (ec->send(ec, buf, n) != (ssize_t) n) {
|
|
|
|
goto failed;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ec->send(ec, value->data, value->len) != (ssize_t) value->len) {
|
|
|
|
goto failed;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NGX_OK;
|
|
|
|
|
|
|
|
failed:
|
|
|
|
|
|
|
|
ngx_http_v3_close_uni_stream(ec);
|
|
|
|
|
|
|
|
return NGX_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
ngx_int_t
|
|
|
|
ngx_http_v3_client_insert(ngx_connection_t *c, ngx_str_t *name,
|
|
|
|
ngx_str_t *value)
|
|
|
|
{
|
|
|
|
u_char buf[NGX_HTTP_V3_PREFIX_INT_LEN];
|
|
|
|
size_t n;
|
|
|
|
ngx_connection_t *ec;
|
|
|
|
|
|
|
|
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0,
|
|
|
|
"http3 client insert \"%V\":\"%V\"", name, value);
|
|
|
|
|
2020-03-25 06:14:24 -03:00
|
|
|
ec = ngx_http_v3_get_uni_stream(c, NGX_HTTP_V3_STREAM_ENCODER);
|
2020-03-13 13:36:33 -03:00
|
|
|
if (ec == NULL) {
|
|
|
|
return NGX_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* XXX option for huffman? */
|
|
|
|
buf[0] = 0x40;
|
|
|
|
n = (u_char *) ngx_http_v3_encode_prefix_int(buf, name->len, 5) - buf;
|
|
|
|
|
|
|
|
if (ec->send(ec, buf, n) != (ssize_t) n) {
|
|
|
|
goto failed;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ec->send(ec, name->data, name->len) != (ssize_t) name->len) {
|
|
|
|
goto failed;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* XXX option for huffman? */
|
|
|
|
buf[0] = 0;
|
|
|
|
n = (u_char *) ngx_http_v3_encode_prefix_int(buf, value->len, 7) - buf;
|
|
|
|
|
|
|
|
if (ec->send(ec, buf, n) != (ssize_t) n) {
|
|
|
|
goto failed;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ec->send(ec, value->data, value->len) != (ssize_t) value->len) {
|
|
|
|
goto failed;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NGX_OK;
|
|
|
|
|
|
|
|
failed:
|
|
|
|
|
|
|
|
ngx_http_v3_close_uni_stream(ec);
|
|
|
|
|
|
|
|
return NGX_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
ngx_int_t
|
|
|
|
ngx_http_v3_client_set_capacity(ngx_connection_t *c, ngx_uint_t capacity)
|
|
|
|
{
|
|
|
|
u_char buf[NGX_HTTP_V3_PREFIX_INT_LEN];
|
|
|
|
size_t n;
|
|
|
|
ngx_connection_t *ec;
|
|
|
|
|
|
|
|
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
|
|
|
|
"http3 client set capacity %ui", capacity);
|
|
|
|
|
2020-03-25 06:14:24 -03:00
|
|
|
ec = ngx_http_v3_get_uni_stream(c, NGX_HTTP_V3_STREAM_ENCODER);
|
2020-03-13 13:36:33 -03:00
|
|
|
if (ec == NULL) {
|
|
|
|
return NGX_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
buf[0] = 0x20;
|
|
|
|
n = (u_char *) ngx_http_v3_encode_prefix_int(buf, capacity, 5) - buf;
|
|
|
|
|
|
|
|
if (ec->send(ec, buf, n) != (ssize_t) n) {
|
|
|
|
ngx_http_v3_close_uni_stream(ec);
|
|
|
|
return NGX_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NGX_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
ngx_int_t
|
|
|
|
ngx_http_v3_client_duplicate(ngx_connection_t *c, ngx_uint_t index)
|
|
|
|
{
|
|
|
|
u_char buf[NGX_HTTP_V3_PREFIX_INT_LEN];
|
|
|
|
size_t n;
|
|
|
|
ngx_connection_t *ec;
|
|
|
|
|
|
|
|
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
|
|
|
|
"http3 client duplicate %ui", index);
|
|
|
|
|
2020-03-25 06:14:24 -03:00
|
|
|
ec = ngx_http_v3_get_uni_stream(c, NGX_HTTP_V3_STREAM_ENCODER);
|
2020-03-13 13:36:33 -03:00
|
|
|
if (ec == NULL) {
|
|
|
|
return NGX_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
buf[0] = 0;
|
|
|
|
n = (u_char *) ngx_http_v3_encode_prefix_int(buf, index, 5) - buf;
|
|
|
|
|
|
|
|
if (ec->send(ec, buf, n) != (ssize_t) n) {
|
|
|
|
ngx_http_v3_close_uni_stream(ec);
|
|
|
|
return NGX_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NGX_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
ngx_int_t
|
|
|
|
ngx_http_v3_client_ack_header(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;
|
|
|
|
|
|
|
|
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
|
|
|
|
"http3 client ack header %ui", stream_id);
|
|
|
|
|
2020-03-25 06:14:24 -03:00
|
|
|
dc = ngx_http_v3_get_uni_stream(c, NGX_HTTP_V3_STREAM_DECODER);
|
2020-03-13 13:36:33 -03:00
|
|
|
if (dc == NULL) {
|
|
|
|
return NGX_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
buf[0] = 0x80;
|
|
|
|
n = (u_char *) ngx_http_v3_encode_prefix_int(buf, stream_id, 7) - buf;
|
|
|
|
|
|
|
|
if (dc->send(dc, buf, n) != (ssize_t) n) {
|
|
|
|
ngx_http_v3_close_uni_stream(dc);
|
|
|
|
return NGX_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NGX_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
ngx_int_t
|
|
|
|
ngx_http_v3_client_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;
|
|
|
|
|
|
|
|
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
|
|
|
|
"http3 client cancel stream %ui", stream_id);
|
|
|
|
|
2020-03-25 06:14:24 -03:00
|
|
|
dc = ngx_http_v3_get_uni_stream(c, NGX_HTTP_V3_STREAM_DECODER);
|
2020-03-13 13:36:33 -03:00
|
|
|
if (dc == NULL) {
|
|
|
|
return NGX_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
buf[0] = 0x40;
|
|
|
|
n = (u_char *) ngx_http_v3_encode_prefix_int(buf, stream_id, 6) - buf;
|
|
|
|
|
|
|
|
if (dc->send(dc, buf, n) != (ssize_t) n) {
|
|
|
|
ngx_http_v3_close_uni_stream(dc);
|
|
|
|
return NGX_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NGX_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
ngx_int_t
|
|
|
|
ngx_http_v3_client_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;
|
|
|
|
|
|
|
|
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
|
|
|
|
"http3 client increment insert count %ui", inc);
|
|
|
|
|
2020-03-25 06:14:24 -03:00
|
|
|
dc = ngx_http_v3_get_uni_stream(c, NGX_HTTP_V3_STREAM_DECODER);
|
2020-03-13 13:36:33 -03:00
|
|
|
if (dc == NULL) {
|
|
|
|
return NGX_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
buf[0] = 0;
|
|
|
|
n = (u_char *) ngx_http_v3_encode_prefix_int(buf, inc, 6) - buf;
|
|
|
|
|
|
|
|
if (dc->send(dc, buf, n) != (ssize_t) n) {
|
|
|
|
ngx_http_v3_close_uni_stream(dc);
|
|
|
|
return NGX_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NGX_OK;
|
|
|
|
}
|