Skip to content

Commit

Permalink
QUIC: Add HTTP/3 demo using nghttp3
Browse files Browse the repository at this point in the history
Reviewed-by: Matt Caswell <matt@openssl.org>
Reviewed-by: Tim Hudson <tjh@openssl.org>
(Merged from #22369)
  • Loading branch information
hlandau committed Oct 19, 2023
1 parent e62097f commit e33af80
Show file tree
Hide file tree
Showing 4 changed files with 855 additions and 0 deletions.
14 changes: 14 additions & 0 deletions demos/http3/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
CFLAGS = -I../../include -g -Wall
LDFLAGS = -L../..
LDLIBS = -lcrypto -lssl -lnghttp3

all: ossl-nghttp3-demo

clean:
$(RM) -f ossl-nghttp3-demo *.o

ossl-nghttp3-demo: ossl-nghttp3-demo.o ossl-nghttp3.o
$(CC) $(CFLAGS) -o "$@" $^ $(LDFLAGS) $(LDLIBS)

%.o: %.c
$(CC) $(CFLAGS) -c -o "$@" "$<"
142 changes: 142 additions & 0 deletions demos/http3/ossl-nghttp3-demo.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
#include "ossl-nghttp3.h"
#include <openssl/err.h>

static int done;

static void make_nv(nghttp3_nv *nv, const char *name, const char *value)
{
nv->name = (uint8_t *)name;
nv->value = (uint8_t *)value;
nv->namelen = strlen(name);
nv->valuelen = strlen(value);
nv->flags = NGHTTP3_NV_FLAG_NONE;
}

static int on_recv_header(nghttp3_conn *h3conn, int64_t stream_id,
int32_t token,
nghttp3_rcbuf *name, nghttp3_rcbuf *value,
uint8_t flags,
void *conn_user_data,
void *stream_user_data)
{
nghttp3_vec vname, vvalue;

/* Received a single HTTP header. */
vname = nghttp3_rcbuf_get_buf(name);
vvalue = nghttp3_rcbuf_get_buf(value);

fwrite(vname.base, vname.len, 1, stderr);
fprintf(stderr, ": ");
fwrite(vvalue.base, vvalue.len, 1, stderr);
fprintf(stderr, "\n");

return 0;
}

static int on_end_headers(nghttp3_conn *h3conn, int64_t stream_id,
int fin,
void *conn_user_data, void *stream_user_data)
{
fprintf(stderr, "\n");
return 0;
}

static int on_recv_data(nghttp3_conn *h3conn, int64_t stream_id,
const uint8_t *data, size_t datalen,
void *conn_user_data, void *stream_user_data)
{
ssize_t wr;

/* HTTP response body data - write it to stdout. */
while (datalen > 0) {
wr = fwrite(data, 1, datalen, stdout);
if (wr < 0)
return 1;

data += wr;
datalen -= wr;
}

return 0;
}

static int on_end_stream(nghttp3_conn *h3conn, int64_t stream_id,
void *conn_user_data, void *stream_user_data)
{
/* HTTP transaction is done - set done flag so that we stop looping. */
done = 1;
return 0;
}

int main(int argc, char **argv)
{
int ret = 1;
SSL_CTX *ctx = NULL;
H3_CONN *conn = NULL;
nghttp3_nv nva[16];
nghttp3_callbacks callbacks = {0};
size_t num_nv = 0;
const char *addr;

/* Check arguments. */
if (argc < 2) {
fprintf(stderr, "usage: %s <host:port>\n", argv[0]);
goto err;
}

addr = argv[1];

/* Setup SSL_CTX. */
if ((ctx = SSL_CTX_new(OSSL_QUIC_client_method())) == NULL)
goto err;

SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);

if (SSL_CTX_set_default_verify_paths(ctx) == 0)
goto err;

/* Setup callbacks. */
callbacks.recv_header = on_recv_header;
callbacks.end_headers = on_end_headers;
callbacks.recv_data = on_recv_data;
callbacks.end_stream = on_end_stream;

/* Create connection. */
if ((conn = H3_CONN_new_for_addr(ctx, addr, &callbacks,
NULL, NULL)) == NULL) {
ERR_raise_data(ERR_LIB_USER, ERR_R_OPERATION_FAIL,
"cannot create HTTP/3 connection");
goto err;
}

/* Build HTTP headers. */
make_nv(&nva[num_nv++], ":method", "GET");
make_nv(&nva[num_nv++], ":scheme", "https");
make_nv(&nva[num_nv++], ":authority", addr);
make_nv(&nva[num_nv++], ":path", "/");
make_nv(&nva[num_nv++], "user-agent", "OpenSSL-Demo/nghttp3");

/* Submit request. */
if (!H3_CONN_submit_request(conn, nva, num_nv, NULL, NULL)) {
ERR_raise_data(ERR_LIB_USER, ERR_R_OPERATION_FAIL,
"cannot submit HTTP/3 request");
goto err;
}

/* Wait for request to complete. */
while (!done)
if (!H3_CONN_handle_events(conn)) {
ERR_raise_data(ERR_LIB_USER, ERR_R_OPERATION_FAIL,
"cannot handle events");
goto err;
}

ret = 0;
err:
if (ret != 0)
ERR_print_errors_fp(stderr);

H3_CONN_free(conn);
SSL_CTX_free(ctx);
return ret;
}

0 comments on commit e33af80

Please sign in to comment.