1 /* 2 * Copyright 2023-2024 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 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 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 } 151