mirror of
				https://gitea.invidious.io/iv-org/litespeed-quic.git
				synced 2024-08-15 00:53:43 +00:00 
			
		
		
		
	Release 2.28.0
- [API] lsquic_ssl_sess_to_resume_info() is the new way to get session info. - [API] Add user pointer to ea_generate_scid callback. - [API] Add lsquic_dcid_from_packet() -- a fast function to parse out DCID. - [API] Add es_max_batch_size to control outgoing packet batch size. - [BUGFIX] Disallow sending of header while promise is being written. - [BUGFIX] Flush stream when buffered bytes exhaust stream cap. - [BUGFIX] Deactivate HQ frame if writing push promise fails. - Perform sanity check on peer transport parameters and fail the handshake if some flow control limits are too low. This can be turned off, see es_check_tp_sanity. - http_server: fix how requests are read in "hq" mode.
This commit is contained in:
		
							parent
							
								
									9a7f663e1a
								
							
						
					
					
						commit
						c2faf03244
					
				
					 19 changed files with 440 additions and 54 deletions
				
			
		| 
						 | 
				
			
			@ -426,6 +426,7 @@ http_client_on_hsk_done (lsquic_conn_t *conn, enum lsquic_hsk_status status)
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Now only used for gQUIC and will be going away after that */
 | 
			
		||||
static void
 | 
			
		||||
http_client_on_sess_resume_info (lsquic_conn_t *conn, const unsigned char *buf,
 | 
			
		||||
                                                                size_t bufsz)
 | 
			
		||||
| 
						 | 
				
			
			@ -1011,7 +1012,6 @@ usage (const char *prog)
 | 
			
		|||
"   -I          Abort on incomplete reponse from server\n"
 | 
			
		||||
"   -4          Prefer IPv4 when resolving hostname\n"
 | 
			
		||||
"   -6          Prefer IPv6 when resolving hostname\n"
 | 
			
		||||
"   -0 FILE     Provide RTT info file (reading or writing)\n"
 | 
			
		||||
#ifndef WIN32
 | 
			
		||||
"   -C DIR      Certificate store.  If specified, server certificate will\n"
 | 
			
		||||
"                 be verified.\n"
 | 
			
		||||
| 
						 | 
				
			
			@ -1736,7 +1736,7 @@ main (int argc, char **argv)
 | 
			
		|||
        case '0':
 | 
			
		||||
            http_client_if.on_sess_resume_info = http_client_on_sess_resume_info;
 | 
			
		||||
            client_ctx.hcc_sess_resume_file_name = optarg;
 | 
			
		||||
            break;
 | 
			
		||||
            goto common_opts;
 | 
			
		||||
        case '3':
 | 
			
		||||
            s_abandon_early = strtol(optarg, NULL, 10);
 | 
			
		||||
            break;
 | 
			
		||||
| 
						 | 
				
			
			@ -1788,6 +1788,7 @@ main (int argc, char **argv)
 | 
			
		|||
            prog.prog_api.ea_alpn      = optarg;
 | 
			
		||||
            prog.prog_api.ea_stream_if = &hq_client_if;
 | 
			
		||||
            break;
 | 
			
		||||
        common_opts:
 | 
			
		||||
        default:
 | 
			
		||||
            if (0 != prog_set_opt(&prog, opt, optarg))
 | 
			
		||||
                exit(1);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1066,30 +1066,36 @@ const struct lsquic_stream_if http_server_if = {
 | 
			
		|||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* XXX Assume we can always read the request in one shot.  This is not a
 | 
			
		||||
 * good assumption to make in a real product.
 | 
			
		||||
 */
 | 
			
		||||
#if HAVE_OPEN_MEMSTREAM
 | 
			
		||||
static void
 | 
			
		||||
hq_server_on_read (struct lsquic_stream *stream, lsquic_stream_ctx_t *st_h)
 | 
			
		||||
{
 | 
			
		||||
    char buf[0x400];
 | 
			
		||||
    char tbuf[0x100], *buf;
 | 
			
		||||
    ssize_t nread;
 | 
			
		||||
    char *path, *end, *filename;
 | 
			
		||||
 | 
			
		||||
    nread = lsquic_stream_read(stream, buf, sizeof(buf));
 | 
			
		||||
    if (nread >= (ssize_t) sizeof(buf))
 | 
			
		||||
    if (!st_h->req_fh)
 | 
			
		||||
        st_h->req_fh = open_memstream(&st_h->req_buf, &st_h->req_sz);
 | 
			
		||||
 | 
			
		||||
    nread = lsquic_stream_read(stream, tbuf, sizeof(tbuf));
 | 
			
		||||
    if (nread > 0)
 | 
			
		||||
    {
 | 
			
		||||
        LSQ_WARN("request too large, at least %zd bytes", sizeof(buf));
 | 
			
		||||
        lsquic_stream_close(stream);
 | 
			
		||||
        fwrite(tbuf, 1, nread, st_h->req_fh);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    else if (nread < 0)
 | 
			
		||||
 | 
			
		||||
    if (nread < 0)
 | 
			
		||||
    {
 | 
			
		||||
        LSQ_WARN("error reading request from stream: %s", strerror(errno));
 | 
			
		||||
        lsquic_stream_close(stream);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    buf[nread] = '\0';
 | 
			
		||||
 | 
			
		||||
    fwrite("", 1, 1, st_h->req_fh);
 | 
			
		||||
    fclose(st_h->req_fh);
 | 
			
		||||
    LSQ_INFO("got request: `%.*s'", (int) st_h->req_sz, st_h->req_buf);
 | 
			
		||||
 | 
			
		||||
    buf = st_h->req_buf;
 | 
			
		||||
    path = strchr(buf, ' ');
 | 
			
		||||
    if (!path)
 | 
			
		||||
    {
 | 
			
		||||
| 
						 | 
				
			
			@ -1104,8 +1110,8 @@ hq_server_on_read (struct lsquic_stream *stream, lsquic_stream_ctx_t *st_h)
 | 
			
		|||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    ++path;
 | 
			
		||||
    for (end = path + nread - 5; end > path
 | 
			
		||||
                                    && (*end == '\r' || *end == '\n'); --end)
 | 
			
		||||
    for (end = buf + st_h->req_sz - 1; end > path
 | 
			
		||||
                && (*end == '\0' || *end == '\r' || *end == '\n'); --end)
 | 
			
		||||
        *end = '\0';
 | 
			
		||||
    LSQ_NOTICE("parsed out request path: %s", path);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1174,6 +1180,7 @@ const struct lsquic_stream_if hq_server_if = {
 | 
			
		|||
    .on_write               = hq_server_on_write,
 | 
			
		||||
    .on_close               = http_server_on_close,
 | 
			
		||||
};
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#if HAVE_REGEX
 | 
			
		||||
| 
						 | 
				
			
			@ -1922,7 +1929,11 @@ main (int argc, char **argv)
 | 
			
		|||
    prog_init(&prog, LSENG_SERVER|LSENG_HTTP, &server_ctx.sports,
 | 
			
		||||
                                            &http_server_if, &server_ctx);
 | 
			
		||||
 | 
			
		||||
    while (-1 != (opt = getopt(argc, argv, PROG_OPTS "y:Y:n:p:r:w:P:hQ:")))
 | 
			
		||||
    while (-1 != (opt = getopt(argc, argv, PROG_OPTS "y:Y:n:p:r:w:P:h"
 | 
			
		||||
#if HAVE_OPEN_MEMSTREAM
 | 
			
		||||
                                                    "Q:"
 | 
			
		||||
#endif
 | 
			
		||||
                                                                        )))
 | 
			
		||||
    {
 | 
			
		||||
        switch (opt) {
 | 
			
		||||
        case 'n':
 | 
			
		||||
| 
						 | 
				
			
			@ -1965,12 +1976,14 @@ main (int argc, char **argv)
 | 
			
		|||
            usage(argv[0]);
 | 
			
		||||
            prog_print_common_options(&prog, stdout);
 | 
			
		||||
            exit(0);
 | 
			
		||||
#if HAVE_OPEN_MEMSTREAM
 | 
			
		||||
        case 'Q':
 | 
			
		||||
            /* XXX A bit hacky, as `prog' has already been initialized... */
 | 
			
		||||
            prog.prog_engine_flags &= ~LSENG_HTTP;
 | 
			
		||||
            prog.prog_api.ea_stream_if = &hq_server_if;
 | 
			
		||||
            add_alpn(optarg);
 | 
			
		||||
            break;
 | 
			
		||||
#endif
 | 
			
		||||
        default:
 | 
			
		||||
            if (0 != prog_set_opt(&prog, opt, optarg))
 | 
			
		||||
                exit(1);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										60
									
								
								bin/prog.c
									
										
									
									
									
								
							
							
						
						
									
										60
									
								
								bin/prog.c
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -39,6 +39,7 @@
 | 
			
		|||
 | 
			
		||||
static int prog_stopped;
 | 
			
		||||
static const char *s_keylog_dir;
 | 
			
		||||
static const char *s_sess_resume_file;
 | 
			
		||||
 | 
			
		||||
static SSL_CTX * get_ssl_ctx (void *, const struct sockaddr *);
 | 
			
		||||
static void keylog_log_line (const SSL *, const char *);
 | 
			
		||||
| 
						 | 
				
			
			@ -118,6 +119,7 @@ void
 | 
			
		|||
prog_print_common_options (const struct prog *prog, FILE *out)
 | 
			
		||||
{
 | 
			
		||||
    fprintf(out,
 | 
			
		||||
"   -0 FILE     Provide session resumption file (reading or writing)\n"
 | 
			
		||||
#if HAVE_REGEX
 | 
			
		||||
"   -s SVCPORT  Service port.  Takes on the form of host:port, host,\n"
 | 
			
		||||
"                 or port.  If host is not an IPv4 or IPv6 address, it is\n"
 | 
			
		||||
| 
						 | 
				
			
			@ -338,6 +340,9 @@ prog_set_opt (struct prog *prog, int opt, const char *arg)
 | 
			
		|||
            sport->sp_flags |= SPORT_CONNECT;
 | 
			
		||||
        }
 | 
			
		||||
        return 0;
 | 
			
		||||
    case '0':
 | 
			
		||||
        s_sess_resume_file = optarg;
 | 
			
		||||
        return 0;
 | 
			
		||||
    case 'G':
 | 
			
		||||
#ifndef WIN32
 | 
			
		||||
        if (0 == stat(optarg, &st))
 | 
			
		||||
| 
						 | 
				
			
			@ -426,6 +431,53 @@ get_ssl_ctx (void *peer_ctx, const struct sockaddr *unused)
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
prog_new_session_cb (SSL *ssl, SSL_SESSION *session)
 | 
			
		||||
{
 | 
			
		||||
    unsigned char *buf;
 | 
			
		||||
    size_t bufsz, nw;
 | 
			
		||||
    FILE *file;
 | 
			
		||||
 | 
			
		||||
    /* Our client is rather limited: only one file and only one ticket
 | 
			
		||||
     * can be saved.  A more flexible client implementation would call
 | 
			
		||||
     * lsquic_ssl_to_conn() and maybe save more tickets based on its
 | 
			
		||||
     * own configuration.
 | 
			
		||||
     */
 | 
			
		||||
    if (!s_sess_resume_file)
 | 
			
		||||
        return 0;
 | 
			
		||||
 | 
			
		||||
    if (0 != lsquic_ssl_sess_to_resume_info(ssl, session, &buf, &bufsz))
 | 
			
		||||
    {
 | 
			
		||||
        LSQ_NOTICE("lsquic_ssl_sess_to_resume_info failed");
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    file = fopen(s_sess_resume_file, "wb");
 | 
			
		||||
    if (!file)
 | 
			
		||||
    {
 | 
			
		||||
        LSQ_WARN("cannot open %s for writing: %s",
 | 
			
		||||
            s_sess_resume_file, strerror(errno));
 | 
			
		||||
        free(buf);
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    nw = fwrite(buf, 1, bufsz, file);
 | 
			
		||||
    if (nw == bufsz)
 | 
			
		||||
    {
 | 
			
		||||
        LSQ_INFO("wrote %zd bytes of session resumption information to %s",
 | 
			
		||||
            nw, s_sess_resume_file);
 | 
			
		||||
        s_sess_resume_file = NULL;  /* Save just one ticket */
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
        LSQ_WARN("error: fwrite(%s) returns %zd instead of %zd: %s",
 | 
			
		||||
            s_sess_resume_file, nw, bufsz, strerror(errno));
 | 
			
		||||
 | 
			
		||||
    fclose(file);
 | 
			
		||||
    free(buf);
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
prog_init_ssl_ctx (struct prog *prog)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -454,6 +506,14 @@ prog_init_ssl_ctx (struct prog *prog)
 | 
			
		|||
    if (s_keylog_dir)
 | 
			
		||||
        SSL_CTX_set_keylog_callback(prog->prog_ssl_ctx, keylog_log_line);
 | 
			
		||||
 | 
			
		||||
    if (s_sess_resume_file)
 | 
			
		||||
    {
 | 
			
		||||
        SSL_CTX_set_session_cache_mode(prog->prog_ssl_ctx,
 | 
			
		||||
                                                    SSL_SESS_CACHE_CLIENT);
 | 
			
		||||
        SSL_CTX_set_early_data_enabled(prog->prog_ssl_ctx, 1);
 | 
			
		||||
        SSL_CTX_sess_set_new_cb(prog->prog_ssl_ctx, prog_new_session_cb);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -158,6 +158,8 @@ static void getExtensionPtrs()
 | 
			
		|||
#endif
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static struct packets_in *
 | 
			
		||||
allocate_packets_in (SOCKET_TYPE fd)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue