src/http/v3/ngx_http_v3_uni.c - nginx-1.31.3 nginx/ @ 42f8df65b

Data types defined

Functions defined

Source code


  1. /*
  2. * Copyright (C) Roman Arutyunyan
  3. * Copyright (C) Nginx, Inc.
  4. */


  5. #include <ngx_config.h>
  6. #include <ngx_core.h>
  7. #include <ngx_http.h>


  8. typedef struct {
  9.     ngx_http_v3_parse_uni_t         parse;
  10.     ngx_int_t                       index;
  11. } ngx_http_v3_uni_stream_t;


  12. static void ngx_http_v3_close_uni_stream(ngx_connection_t *c);
  13. static void ngx_http_v3_uni_read_handler(ngx_event_t *rev);
  14. static void ngx_http_v3_uni_dummy_read_handler(ngx_event_t *wev);
  15. static void ngx_http_v3_uni_dummy_write_handler(ngx_event_t *wev);


  16. void
  17. ngx_http_v3_init_uni_stream(ngx_connection_t *c)
  18. {
  19.     uint64_t                   n;
  20.     ngx_http_v3_session_t     *h3c;
  21.     ngx_http_v3_uni_stream_t  *us;

  22.     h3c = ngx_http_v3_get_session(c);
  23.     if (h3c->hq) {
  24.         ngx_http_v3_finalize_connection(c,
  25.                                         NGX_HTTP_V3_ERR_STREAM_CREATION_ERROR,
  26.                                         "uni stream in hq mode");
  27.         c->data = NULL;
  28.         ngx_http_v3_close_uni_stream(c);
  29.         return;
  30.     }

  31.     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 init uni stream");

  32.     n = c->quic->id >> 2;

  33.     if (n >= NGX_HTTP_V3_MAX_UNI_STREAMS) {
  34.         ngx_http_v3_finalize_connection(c,
  35.                                       NGX_HTTP_V3_ERR_STREAM_CREATION_ERROR,
  36.                                       "reached maximum number of uni streams");
  37.         c->data = NULL;
  38.         ngx_http_v3_close_uni_stream(c);
  39.         return;
  40.     }

  41.     ngx_quic_cancelable_stream(c);

  42.     us = ngx_pcalloc(c->pool, sizeof(ngx_http_v3_uni_stream_t));
  43.     if (us == NULL) {
  44.         ngx_http_v3_finalize_connection(c,
  45.                                         NGX_HTTP_V3_ERR_INTERNAL_ERROR,
  46.                                         "memory allocation error");
  47.         c->data = NULL;
  48.         ngx_http_v3_close_uni_stream(c);
  49.         return;
  50.     }

  51.     us->index = -1;

  52.     c->data = us;

  53.     c->read->handler = ngx_http_v3_uni_read_handler;
  54.     c->write->handler = ngx_http_v3_uni_dummy_write_handler;

  55.     ngx_http_v3_uni_read_handler(c->read);
  56. }


  57. static void
  58. ngx_http_v3_close_uni_stream(ngx_connection_t *c)
  59. {
  60.     ngx_pool_t                *pool;
  61.     ngx_http_v3_session_t     *h3c;
  62.     ngx_http_v3_uni_stream_t  *us;

  63.     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 close stream");

  64.     us = c->data;

  65.     if (us && us->index >= 0) {
  66.         h3c = ngx_http_v3_get_session(c);
  67.         h3c->known_streams[us->index] = NULL;
  68.     }

  69.     c->destroyed = 1;

  70.     pool = c->pool;

  71.     ngx_close_connection(c);

  72.     ngx_destroy_pool(pool);
  73. }


  74. ngx_int_t
  75. ngx_http_v3_register_uni_stream(ngx_connection_t *c, uint64_t type)
  76. {
  77.     ngx_int_t                  index;
  78.     ngx_uint_t                 streams;
  79.     ngx_http_v3_session_t     *h3c;
  80.     ngx_http_v3_uni_stream_t  *us;

  81.     h3c = ngx_http_v3_get_session(c);

  82.     switch (type) {

  83.     case NGX_HTTP_V3_STREAM_ENCODER:

  84.         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
  85.                        "http3 encoder stream");
  86.         index = NGX_HTTP_V3_STREAM_CLIENT_ENCODER;
  87.         break;

  88.     case NGX_HTTP_V3_STREAM_DECODER:

  89.         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
  90.                        "http3 decoder stream");
  91.         index = NGX_HTTP_V3_STREAM_CLIENT_DECODER;
  92.         break;

  93.     case NGX_HTTP_V3_STREAM_CONTROL:

  94.         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
  95.                        "http3 control stream");
  96.         index = NGX_HTTP_V3_STREAM_CLIENT_CONTROL;

  97.         break;

  98.     default:

  99.         ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
  100.                        "http3 stream 0x%02xL", type);

  101.         streams = (1 << NGX_HTTP_V3_STREAM_CLIENT_ENCODER)
  102.                   | (1 << NGX_HTTP_V3_STREAM_CLIENT_DECODER)
  103.                   | (1 << NGX_HTTP_V3_STREAM_CLIENT_CONTROL);

  104.         if ((h3c->created_streams & streams) != streams) {
  105.             ngx_log_error(NGX_LOG_INFO, c->log, 0, "missing mandatory stream");
  106.             return NGX_HTTP_V3_ERR_STREAM_CREATION_ERROR;
  107.         }

  108.         index = -1;
  109.     }

  110.     if (index >= 0) {
  111.         if (h3c->created_streams & (1 << index)) {
  112.             ngx_log_error(NGX_LOG_INFO, c->log, 0, "stream already created");
  113.             return NGX_HTTP_V3_ERR_STREAM_CREATION_ERROR;
  114.         }

  115.         h3c->known_streams[index] = c;
  116.         h3c->created_streams |= 1 << index;

  117.         us = c->data;
  118.         us->index = index;
  119.     }

  120.     return NGX_OK;
  121. }


  122. static void
  123. ngx_http_v3_uni_read_handler(ngx_event_t *rev)
  124. {
  125.     u_char                     buf[128];
  126.     ssize_t                    n;
  127.     ngx_buf_t                  b;
  128.     ngx_int_t                  rc;
  129.     ngx_connection_t          *c;
  130.     ngx_http_v3_session_t     *h3c;
  131.     ngx_http_v3_uni_stream_t  *us;

  132.     c = rev->data;
  133.     us = c->data;

  134.     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 read handler");

  135.     if (c->close) {
  136.         ngx_http_v3_close_uni_stream(c);
  137.         return;
  138.     }

  139.     ngx_memzero(&b, sizeof(ngx_buf_t));

  140.     while (rev->ready) {

  141.         n = c->recv(c, buf, sizeof(buf));

  142.         if (n == NGX_ERROR) {
  143.             rc = NGX_HTTP_V3_ERR_INTERNAL_ERROR;
  144.             goto failed;
  145.         }

  146.         if (n == 0) {
  147.             if (us->index >= 0) {
  148.                 rc = NGX_HTTP_V3_ERR_CLOSED_CRITICAL_STREAM;
  149.                 goto failed;
  150.             }

  151.             ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 read eof");
  152.             ngx_http_v3_close_uni_stream(c);
  153.             return;
  154.         }

  155.         if (n == NGX_AGAIN) {
  156.             break;
  157.         }

  158.         b.pos = buf;
  159.         b.last = buf + n;

  160.         h3c = ngx_http_v3_get_session(c);
  161.         h3c->total_bytes += n;

  162.         if (ngx_http_v3_check_flood(c) != NGX_OK) {
  163.             ngx_http_v3_close_uni_stream(c);
  164.             return;
  165.         }

  166.         rc = ngx_http_v3_parse_uni(c, &us->parse, &b);

  167.         if (rc == NGX_DONE) {
  168.             ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
  169.                            "http3 read done");
  170.             ngx_http_v3_close_uni_stream(c);
  171.             return;
  172.         }

  173.         if (rc > 0) {
  174.             goto failed;
  175.         }

  176.         if (rc != NGX_AGAIN) {
  177.             rc = NGX_HTTP_V3_ERR_GENERAL_PROTOCOL_ERROR;
  178.             goto failed;
  179.         }
  180.     }

  181.     if (ngx_handle_read_event(rev, 0) != NGX_OK) {
  182.         rc = NGX_HTTP_V3_ERR_INTERNAL_ERROR;
  183.         goto failed;
  184.     }

  185.     return;

  186. failed:

  187.     ngx_http_v3_finalize_connection(c, rc, "stream error");
  188.     ngx_http_v3_close_uni_stream(c);
  189. }


  190. static void
  191. ngx_http_v3_uni_dummy_read_handler(ngx_event_t *rev)
  192. {
  193.     u_char             ch;
  194.     ngx_connection_t  *c;

  195.     c = rev->data;

  196.     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 dummy read handler");

  197.     if (c->close) {
  198.         ngx_http_v3_close_uni_stream(c);
  199.         return;
  200.     }

  201.     if (rev->ready) {
  202.         if (c->recv(c, &ch, 1) != 0) {
  203.             ngx_http_v3_finalize_connection(c, NGX_HTTP_V3_ERR_NO_ERROR, NULL);
  204.             ngx_http_v3_close_uni_stream(c);
  205.             return;
  206.         }
  207.     }

  208.     if (ngx_handle_read_event(rev, 0) != NGX_OK) {
  209.         ngx_http_v3_finalize_connection(c, NGX_HTTP_V3_ERR_INTERNAL_ERROR,
  210.                                         NULL);
  211.         ngx_http_v3_close_uni_stream(c);
  212.     }
  213. }


  214. static void
  215. ngx_http_v3_uni_dummy_write_handler(ngx_event_t *wev)
  216. {
  217.     ngx_connection_t  *c;

  218.     c = wev->data;

  219.     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 dummy write handler");

  220.     if (ngx_handle_write_event(wev, 0) != NGX_OK) {
  221.         ngx_http_v3_finalize_connection(c, NGX_HTTP_V3_ERR_INTERNAL_ERROR,
  222.                                         NULL);
  223.         ngx_http_v3_close_uni_stream(c);
  224.     }
  225. }


  226. ngx_connection_t *
  227. ngx_http_v3_get_uni_stream(ngx_connection_t *c, ngx_uint_t type)
  228. {
  229.     u_char                     buf[NGX_HTTP_V3_VARLEN_INT_LEN];
  230.     size_t                     n;
  231.     ngx_int_t                  index;
  232.     ngx_connection_t          *sc;
  233.     ngx_http_v3_session_t     *h3c;
  234.     ngx_http_v3_uni_stream_t  *us;

  235.     switch (type) {
  236.     case NGX_HTTP_V3_STREAM_ENCODER:
  237.         index = NGX_HTTP_V3_STREAM_SERVER_ENCODER;
  238.         break;
  239.     case NGX_HTTP_V3_STREAM_DECODER:
  240.         index = NGX_HTTP_V3_STREAM_SERVER_DECODER;
  241.         break;
  242.     case NGX_HTTP_V3_STREAM_CONTROL:
  243.         index = NGX_HTTP_V3_STREAM_SERVER_CONTROL;
  244.         break;
  245.     default:
  246.         index = -1;
  247.     }

  248.     h3c = ngx_http_v3_get_session(c);

  249.     if (index >= 0) {
  250.         if (h3c->known_streams[index]) {
  251.             return h3c->known_streams[index];
  252.         }
  253.     }

  254.     sc = ngx_quic_open_stream(c, 0);
  255.     if (sc == NULL) {
  256.         goto failed;
  257.     }

  258.     ngx_quic_cancelable_stream(sc);

  259.     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
  260.                    "http3 create uni stream, type:%ui", type);

  261.     us = ngx_pcalloc(sc->pool, sizeof(ngx_http_v3_uni_stream_t));
  262.     if (us == NULL) {
  263.         goto failed;
  264.     }

  265.     us->index = index;

  266.     sc->data = us;

  267.     sc->read->handler = ngx_http_v3_uni_dummy_read_handler;
  268.     sc->write->handler = ngx_http_v3_uni_dummy_write_handler;

  269.     if (index >= 0) {
  270.         h3c->known_streams[index] = sc;
  271.     }

  272.     n = (u_char *) ngx_http_v3_encode_varlen_int(buf, type) - buf;

  273.     h3c = ngx_http_v3_get_session(c);
  274.     h3c->total_bytes += n;

  275.     if (sc->send(sc, buf, n) != (ssize_t) n) {
  276.         goto failed;
  277.     }

  278.     ngx_post_event(sc->read, &ngx_posted_events);

  279.     return sc;

  280. failed:

  281.     ngx_log_error(NGX_LOG_ERR, c->log, 0, "failed to create server stream");

  282.     ngx_http_v3_finalize_connection(c, NGX_HTTP_V3_ERR_STREAM_CREATION_ERROR,
  283.                                     "failed to create server stream");
  284.     if (sc) {
  285.         ngx_http_v3_close_uni_stream(sc);
  286.     }

  287.     return NULL;
  288. }


  289. ngx_int_t
  290. ngx_http_v3_send_settings(ngx_connection_t *c)
  291. {
  292.     u_char                  *p, buf[NGX_HTTP_V3_VARLEN_INT_LEN * 6];
  293.     size_t                   n;
  294.     ngx_connection_t        *cc;
  295.     ngx_http_v3_session_t   *h3c;
  296.     ngx_http_v3_srv_conf_t  *h3scf;

  297.     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 send settings");

  298.     cc = ngx_http_v3_get_uni_stream(c, NGX_HTTP_V3_STREAM_CONTROL);
  299.     if (cc == NULL) {
  300.         return NGX_ERROR;
  301.     }

  302.     h3scf = ngx_http_v3_get_module_srv_conf(c, ngx_http_v3_module);

  303.     n = ngx_http_v3_encode_varlen_int(NULL,
  304.                                       NGX_HTTP_V3_PARAM_MAX_TABLE_CAPACITY);
  305.     n += ngx_http_v3_encode_varlen_int(NULL, h3scf->max_table_capacity);
  306.     n += ngx_http_v3_encode_varlen_int(NULL, NGX_HTTP_V3_PARAM_BLOCKED_STREAMS);
  307.     n += ngx_http_v3_encode_varlen_int(NULL, h3scf->max_blocked_streams);

  308.     p = (u_char *) ngx_http_v3_encode_varlen_int(buf,
  309.                                                  NGX_HTTP_V3_FRAME_SETTINGS);
  310.     p = (u_char *) ngx_http_v3_encode_varlen_int(p, n);
  311.     p = (u_char *) ngx_http_v3_encode_varlen_int(p,
  312.                                          NGX_HTTP_V3_PARAM_MAX_TABLE_CAPACITY);
  313.     p = (u_char *) ngx_http_v3_encode_varlen_int(p, h3scf->max_table_capacity);
  314.     p = (u_char *) ngx_http_v3_encode_varlen_int(p,
  315.                                             NGX_HTTP_V3_PARAM_BLOCKED_STREAMS);
  316.     p = (u_char *) ngx_http_v3_encode_varlen_int(p, h3scf->max_blocked_streams);
  317.     n = p - buf;

  318.     h3c = ngx_http_v3_get_session(c);
  319.     h3c->total_bytes += n;

  320.     if (cc->send(cc, buf, n) != (ssize_t) n) {
  321.         goto failed;
  322.     }

  323.     return NGX_OK;

  324. failed:

  325.     ngx_log_error(NGX_LOG_ERR, c->log, 0, "failed to send settings");

  326.     ngx_http_v3_finalize_connection(c, NGX_HTTP_V3_ERR_EXCESSIVE_LOAD,
  327.                                     "failed to send settings");
  328.     ngx_http_v3_close_uni_stream(cc);

  329.     return NGX_ERROR;
  330. }


  331. ngx_int_t
  332. ngx_http_v3_send_goaway(ngx_connection_t *c, uint64_t id)
  333. {
  334.     u_char                 *p, buf[NGX_HTTP_V3_VARLEN_INT_LEN * 3];
  335.     size_t                  n;
  336.     ngx_connection_t       *cc;
  337.     ngx_http_v3_session_t  *h3c;

  338.     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 send goaway %uL", id);

  339.     cc = ngx_http_v3_get_uni_stream(c, NGX_HTTP_V3_STREAM_CONTROL);
  340.     if (cc == NULL) {
  341.         return NGX_ERROR;
  342.     }

  343.     n = ngx_http_v3_encode_varlen_int(NULL, id);
  344.     p = (u_char *) ngx_http_v3_encode_varlen_int(buf, NGX_HTTP_V3_FRAME_GOAWAY);
  345.     p = (u_char *) ngx_http_v3_encode_varlen_int(p, n);
  346.     p = (u_char *) ngx_http_v3_encode_varlen_int(p, id);
  347.     n = p - buf;

  348.     h3c = ngx_http_v3_get_session(c);
  349.     h3c->total_bytes += n;

  350.     if (cc->send(cc, buf, n) != (ssize_t) n) {
  351.         goto failed;
  352.     }

  353.     return NGX_OK;

  354. failed:

  355.     ngx_log_error(NGX_LOG_ERR, c->log, 0, "failed to send goaway");

  356.     ngx_http_v3_finalize_connection(c, NGX_HTTP_V3_ERR_EXCESSIVE_LOAD,
  357.                                     "failed to send goaway");
  358.     ngx_http_v3_close_uni_stream(cc);

  359.     return NGX_ERROR;
  360. }


  361. ngx_int_t
  362. ngx_http_v3_send_ack_section(ngx_connection_t *c, ngx_uint_t stream_id)
  363. {
  364.     u_char                  buf[NGX_HTTP_V3_PREFIX_INT_LEN];
  365.     size_t                  n;
  366.     ngx_connection_t       *dc;
  367.     ngx_http_v3_session_t  *h3c;

  368.     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
  369.                    "http3 send section acknowledgement %ui", stream_id);

  370.     dc = ngx_http_v3_get_uni_stream(c, NGX_HTTP_V3_STREAM_DECODER);
  371.     if (dc == NULL) {
  372.         return NGX_ERROR;
  373.     }

  374.     buf[0] = 0x80;
  375.     n = (u_char *) ngx_http_v3_encode_prefix_int(buf, stream_id, 7) - buf;

  376.     h3c = ngx_http_v3_get_session(c);
  377.     h3c->total_bytes += n;

  378.     if (dc->send(dc, buf, n) != (ssize_t) n) {
  379.         goto failed;
  380.     }

  381.     return NGX_OK;

  382. failed:

  383.     ngx_log_error(NGX_LOG_ERR, c->log, 0,
  384.                   "failed to send section acknowledgement");

  385.     ngx_http_v3_finalize_connection(c, NGX_HTTP_V3_ERR_EXCESSIVE_LOAD,
  386.                                     "failed to send section acknowledgement");
  387.     ngx_http_v3_close_uni_stream(dc);

  388.     return NGX_ERROR;
  389. }


  390. ngx_int_t
  391. ngx_http_v3_send_cancel_stream(ngx_connection_t *c, ngx_uint_t stream_id)
  392. {
  393.     u_char                  buf[NGX_HTTP_V3_PREFIX_INT_LEN];
  394.     size_t                  n;
  395.     ngx_connection_t       *dc;
  396.     ngx_http_v3_session_t  *h3c;

  397.     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
  398.                    "http3 send stream cancellation %ui", stream_id);

  399.     dc = ngx_http_v3_get_uni_stream(c, NGX_HTTP_V3_STREAM_DECODER);
  400.     if (dc == NULL) {
  401.         return NGX_ERROR;
  402.     }

  403.     buf[0] = 0x40;
  404.     n = (u_char *) ngx_http_v3_encode_prefix_int(buf, stream_id, 6) - buf;

  405.     h3c = ngx_http_v3_get_session(c);
  406.     h3c->total_bytes += n;

  407.     if (dc->send(dc, buf, n) != (ssize_t) n) {
  408.         goto failed;
  409.     }

  410.     return NGX_OK;

  411. failed:

  412.     ngx_log_error(NGX_LOG_ERR, c->log, 0, "failed to send stream cancellation");

  413.     ngx_http_v3_finalize_connection(c, NGX_HTTP_V3_ERR_EXCESSIVE_LOAD,
  414.                                     "failed to send stream cancellation");
  415.     ngx_http_v3_close_uni_stream(dc);

  416.     return NGX_ERROR;
  417. }


  418. ngx_int_t
  419. ngx_http_v3_send_inc_insert_count(ngx_connection_t *c, ngx_uint_t inc)
  420. {
  421.     u_char                  buf[NGX_HTTP_V3_PREFIX_INT_LEN];
  422.     size_t                  n;
  423.     ngx_connection_t       *dc;
  424.     ngx_http_v3_session_t  *h3c;

  425.     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
  426.                    "http3 send insert count increment %ui", inc);

  427.     dc = ngx_http_v3_get_uni_stream(c, NGX_HTTP_V3_STREAM_DECODER);
  428.     if (dc == NULL) {
  429.         return NGX_ERROR;
  430.     }

  431.     buf[0] = 0;
  432.     n = (u_char *) ngx_http_v3_encode_prefix_int(buf, inc, 6) - buf;

  433.     h3c = ngx_http_v3_get_session(c);
  434.     h3c->total_bytes += n;

  435.     if (dc->send(dc, buf, n) != (ssize_t) n) {
  436.         goto failed;
  437.     }

  438.     return NGX_OK;

  439. failed:

  440.     ngx_log_error(NGX_LOG_ERR, c->log, 0,
  441.                   "failed to send insert count increment");

  442.     ngx_http_v3_finalize_connection(c, NGX_HTTP_V3_ERR_EXCESSIVE_LOAD,
  443.                                     "failed to send insert count increment");
  444.     ngx_http_v3_close_uni_stream(dc);

  445.     return NGX_ERROR;
  446. }


  447. ngx_int_t
  448. ngx_http_v3_cancel_stream(ngx_connection_t *c, ngx_uint_t stream_id)
  449. {
  450.     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
  451.                    "http3 cancel stream %ui", stream_id);

  452.     /* we do not use dynamic tables */

  453.     return NGX_OK;
  454. }