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