]> git.ipfire.org Git - thirdparty/openssl.git/blob - demos/http3/ossl-nghttp3-demo.c
b1cbd1abf9d250b88aab218d1515547f11501c62
[thirdparty/openssl.git] / demos / http3 / ossl-nghttp3-demo.c
1 /*
2 * Copyright 2023 The OpenSSL Project Authors. All Rights Reserved.
3 *
4 * Licensed under the Apache License 2.0 (the "License"). You may not use
5 * this file except in compliance with the License. You can obtain a copy
6 * in the file LICENSE in the source distribution or at
7 * https://www.openssl.org/source/license.html
8 */
9 #include "ossl-nghttp3.h"
10 #include <openssl/err.h>
11
12 static int done;
13
14 static void make_nv(nghttp3_nv *nv, const char *name, const char *value)
15 {
16 nv->name = (uint8_t *)name;
17 nv->value = (uint8_t *)value;
18 nv->namelen = strlen(name);
19 nv->valuelen = strlen(value);
20 nv->flags = NGHTTP3_NV_FLAG_NONE;
21 }
22
23 static int on_recv_header(nghttp3_conn *h3conn, int64_t stream_id,
24 int32_t token,
25 nghttp3_rcbuf *name, nghttp3_rcbuf *value,
26 uint8_t flags,
27 void *conn_user_data,
28 void *stream_user_data)
29 {
30 nghttp3_vec vname, vvalue;
31
32 /* Received a single HTTP header. */
33 vname = nghttp3_rcbuf_get_buf(name);
34 vvalue = nghttp3_rcbuf_get_buf(value);
35
36 fwrite(vname.base, vname.len, 1, stderr);
37 fprintf(stderr, ": ");
38 fwrite(vvalue.base, vvalue.len, 1, stderr);
39 fprintf(stderr, "\n");
40
41 return 0;
42 }
43
44 static int on_end_headers(nghttp3_conn *h3conn, int64_t stream_id,
45 int fin,
46 void *conn_user_data, void *stream_user_data)
47 {
48 fprintf(stderr, "\n");
49 return 0;
50 }
51
52 static int on_recv_data(nghttp3_conn *h3conn, int64_t stream_id,
53 const uint8_t *data, size_t datalen,
54 void *conn_user_data, void *stream_user_data)
55 {
56 ssize_t wr;
57
58 /* HTTP response body data - write it to stdout. */
59 while (datalen > 0) {
60 wr = fwrite(data, 1, datalen, stdout);
61 if (wr < 0)
62 return 1;
63
64 data += wr;
65 datalen -= wr;
66 }
67
68 return 0;
69 }
70
71 static int on_end_stream(nghttp3_conn *h3conn, int64_t stream_id,
72 void *conn_user_data, void *stream_user_data)
73 {
74 /* HTTP transaction is done - set done flag so that we stop looping. */
75 done = 1;
76 return 0;
77 }
78
79 int main(int argc, char **argv)
80 {
81 int ret = 1;
82 SSL_CTX *ctx = NULL;
83 OSSL_DEMO_H3_CONN *conn = NULL;
84 nghttp3_nv nva[16];
85 nghttp3_callbacks callbacks = {0};
86 size_t num_nv = 0;
87 const char *addr;
88
89 /* Check arguments. */
90 if (argc < 2) {
91 fprintf(stderr, "usage: %s <host:port>\n", argv[0]);
92 goto err;
93 }
94
95 addr = argv[1];
96
97 /* Setup SSL_CTX. */
98 if ((ctx = SSL_CTX_new(OSSL_QUIC_client_method())) == NULL)
99 goto err;
100
101 SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);
102
103 if (SSL_CTX_set_default_verify_paths(ctx) == 0)
104 goto err;
105
106 /* Setup callbacks. */
107 callbacks.recv_header = on_recv_header;
108 callbacks.end_headers = on_end_headers;
109 callbacks.recv_data = on_recv_data;
110 callbacks.end_stream = on_end_stream;
111
112 /* Create connection. */
113 if ((conn = OSSL_DEMO_H3_CONN_new_for_addr(ctx, addr, &callbacks,
114 NULL, NULL)) == NULL) {
115 ERR_raise_data(ERR_LIB_USER, ERR_R_OPERATION_FAIL,
116 "cannot create HTTP/3 connection");
117 goto err;
118 }
119
120 /* Build HTTP headers. */
121 make_nv(&nva[num_nv++], ":method", "GET");
122 make_nv(&nva[num_nv++], ":scheme", "https");
123 make_nv(&nva[num_nv++], ":authority", addr);
124 make_nv(&nva[num_nv++], ":path", "/");
125 make_nv(&nva[num_nv++], "user-agent", "OpenSSL-Demo/nghttp3");
126
127 /* Submit request. */
128 if (!OSSL_DEMO_H3_CONN_submit_request(conn, nva, num_nv, NULL, NULL)) {
129 ERR_raise_data(ERR_LIB_USER, ERR_R_OPERATION_FAIL,
130 "cannot submit HTTP/3 request");
131 goto err;
132 }
133
134 /* Wait for request to complete. */
135 while (!done)
136 if (!OSSL_DEMO_H3_CONN_handle_events(conn)) {
137 ERR_raise_data(ERR_LIB_USER, ERR_R_OPERATION_FAIL,
138 "cannot handle events");
139 goto err;
140 }
141
142 ret = 0;
143 err:
144 if (ret != 0)
145 ERR_print_errors_fp(stderr);
146
147 OSSL_DEMO_H3_CONN_free(conn);
148 SSL_CTX_free(ctx);
149 return ret;
150 }