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 | }
|
---|