xref: /openssl/demos/http3/ossl-nghttp3-demo.c (revision 2000281d)
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 
make_nv(nghttp3_nv * nv,const char * name,const char * value)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 
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 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 
on_end_headers(nghttp3_conn * h3conn,int64_t stream_id,int fin,void * conn_user_data,void * stream_user_data)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 
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 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     size_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 (ferror(stdout))
62             return 1;
63 
64         data    += wr;
65         datalen -= wr;
66     }
67 
68     return 0;
69 }
70 
on_end_stream(nghttp3_conn * h3conn,int64_t stream_id,void * conn_user_data,void * stream_user_data)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 
main(int argc,char ** argv)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 }
151