examples/ex_http3.c
n_http3 example + self-test: parse a URL (always) and, when built with HAVE_HTTP3, optionally fetch a live https URL over HTTP/3. More...
Functions
| Name | |
|---|---|
| void | test_request_guards(void ) exercise the request entry points' guards + delegation (deterministic, no network) |
| void | test_parse_url(void ) exercise the pure URL parser (runs in every build) |
| int | main(int argc, char ** argv) |
Attributes
| Name | |
|---|---|
| int | g_fails test counter |
Defines
| Name | |
|---|---|
| CHECK(cond) tiny assert that keeps going and tallies failures |
Detailed Description
n_http3 example + self-test: parse a URL (always) and, when built with HAVE_HTTP3, optionally fetch a live https URL over HTTP/3.
Author: Castagnier Mickael
Version: 1.0
Usage: ex_http3 [https://host/path]
The URL-parser checks run in every build and make this double as a unit test (a non-zero exit signals a failure). A live fetch is attempted only when a URL argument is given and the library was built with HAVE_HTTP3; against an authorized, reachable HTTP/3 host it prints the status, headers, and body size.
Functions Documentation
function test_request_guards
static void test_request_guards(
void
)
exercise the request entry points' guards + delegation (deterministic, no network)
function test_parse_url
static void test_parse_url(
void
)
exercise the pure URL parser (runs in every build)
function main
int main(
int argc,
char ** argv
)
Attributes Documentation
variable g_fails
static int g_fails = 0;
test counter
Macros Documentation
define CHECK
#define CHECK(
cond
)
do { \
if (!(cond)) { \
n_log(LOG_ERR, "CHECK failed: %s (%s:%d)", #cond, __FILE__, __LINE__); \
g_fails++; \
} \
} while (0)
tiny assert that keeps going and tallies failures
Source code
/*
* Nilorea Library
* Copyright (C) 2005-2026 Castagnier Mickael
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
* implied. See the License for the specific language governing
* permissions and limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "nilorea/n_http3.h"
#include "nilorea/n_log.h"
#include <stdio.h>
#include <string.h>
static int g_fails = 0;
#define CHECK(cond) \
do { \
if (!(cond)) { \
n_log(LOG_ERR, "CHECK failed: %s (%s:%d)", #cond, __FILE__, __LINE__); \
g_fails++; \
} \
} while (0)
static void test_parse_url(void) {
char host[128];
char port[16];
char path[256];
CHECK(n_http3_parse_url("https://example.com/a/b?c=d", host, sizeof(host), port, sizeof(port), path, sizeof(path)) == 0);
CHECK(strcmp(host, "example.com") == 0);
CHECK(strcmp(port, "443") == 0);
CHECK(strcmp(path, "/a/b?c=d") == 0);
CHECK(n_http3_parse_url("https://host.test:8443/", host, sizeof(host), port, sizeof(port), path, sizeof(path)) == 0);
CHECK(strcmp(host, "host.test") == 0);
CHECK(strcmp(port, "8443") == 0);
CHECK(strcmp(path, "/") == 0);
CHECK(n_http3_parse_url("https://[::1]:443/x", host, sizeof(host), port, sizeof(port), path, sizeof(path)) == 0);
CHECK(strcmp(host, "::1") == 0);
CHECK(strcmp(port, "443") == 0);
/* a bare host with no path defaults the path to "/" */
CHECK(n_http3_parse_url("https://only.host", host, sizeof(host), NULL, 0, path, sizeof(path)) == 0);
CHECK(strcmp(path, "/") == 0);
/* non-https and NULL are rejected */
CHECK(n_http3_parse_url("http://insecure/", host, sizeof(host), port, sizeof(port), path, sizeof(path)) == -1);
CHECK(n_http3_parse_url(NULL, host, sizeof(host), port, sizeof(port), path, sizeof(path)) == -1);
}
static void test_request_guards(void) {
N_HTTP3_RESPONSE r;
/* a NULL out is rejected by both entry points */
CHECK(n_http3_request("GET", "https://x/", NULL, NULL, 0, 100, NULL) == -1);
CHECK(n_http3_request_ex("GET", "https://x/", NULL, NULL, 0, 100, N_HTTP3_REQ_ALLOW_ILLEGAL_HEADERS, NULL) == -1);
/* an empty URL is rejected identically through the _ex entry (n_http3_request delegates
to n_http3_request_ex, so the two agree); the response error is set */
memset(&r, 0, sizeof(r));
CHECK(n_http3_request_ex("GET", "", NULL, NULL, 0, 100, 0u, &r) == -1);
CHECK(r.error != NULL);
n_http3_response_free(&r);
}
int main(int argc, char** argv) {
set_log_level(LOG_NOTICE);
test_parse_url();
test_request_guards();
n_log(LOG_NOTICE, "n_http3_available() = %d", n_http3_available());
if (argc > 1) {
N_HTTP3_RESPONSE resp;
int rv = n_http3_get(argv[1], 15000, &resp);
if (rv == 0) {
n_log(LOG_NOTICE, "HTTP/3 %d, %zu body bytes", resp.status, resp.body_len);
if (resp.headers) {
printf("%s", resp.headers);
}
printf("\n[%zu body bytes]\n", resp.body_len);
} else {
n_log(LOG_ERR, "HTTP/3 request failed: %s", resp.error ? resp.error : "(unknown)");
if (!n_http3_available()) {
n_log(LOG_NOTICE, "rebuild the library with HAVE_HTTP3 (ngtcp2 + nghttp3 + OpenSSL QUIC) to enable HTTP/3");
}
}
n_http3_response_free(&resp);
/* a second "illegal" argument demonstrates the security-testing mode: send a
normally-forbidden transfer-encoding header on the HTTP/3 request (a compliant
endpoint rejects it) via n_http3_request_ex with N_HTTP3_REQ_ALLOW_ILLEGAL_HEADERS */
if (argc > 2 && strcmp(argv[2], "illegal") == 0) {
N_HTTP3_RESPONSE r2;
int rv2 = n_http3_request_ex("GET", argv[1], "transfer-encoding: chunked\r\n", NULL, 0, 15000, N_HTTP3_REQ_ALLOW_ILLEGAL_HEADERS, &r2);
n_log(LOG_NOTICE, "HTTP/3 + illegal transfer-encoding header -> rv=%d status=%d%s%s",
rv2, r2.status, r2.error ? " error=" : "", r2.error ? r2.error : "");
n_http3_response_free(&r2);
}
} else {
n_log(LOG_NOTICE, "pass an https URL to fetch it over HTTP/3, e.g. ex_http3 https://cloudflare-quic.com/ (add 'illegal' to also send a forbidden framing header)");
}
if (g_fails == 0) {
n_log(LOG_NOTICE, "ex_http3: ALL PARSE TESTS PASSED");
} else {
n_log(LOG_ERR, "ex_http3: %d CHECK(s) FAILED", g_fails);
}
return g_fails ? 1 : 0;
}
Modules
- AABB3D
- ACCEPT_POOL
- ALLEGRO4
- ALLEGRO5
- ANIM_LIB
- ASTAR
- ATLAS_LIB
- AVRO
- CLOCK_SYNC
- COMMONS
- CONFIGFILE
- CYPHER_BASE64
- CYPHER_VIGENERE
- DEAD_RECKONING
- ENUMS
- EXCEPTIONS
- GAME_ENV
- GIT
- GUI
- HASH_TABLE
- ISOMETRIC_ENGINE
- LIST
- LOG
- LOGNODUP
- LZ4
- NETWORKING
- NETWORK_MSG
- N_COOKIES
- N_DIFF
- N_DIGEST
- N_DISK_CACHE
- N_DNS
- N_ECC
- N_ENTROPY
- N_FILES
- N_FLUIDS
- N_GUI_COLOR
- N_GUI_COLORWHEEL
- N_GUI_CURVE
- N_GUI_GRID
- N_GUI_POPUP
- N_HEX
- N_HTTP3
- N_HTTP_COOKIE
- N_HTTP_FORM
- N_HTTP_MIME
- N_HTTP_REQ
- N_HTTP_RESP
- N_HTTP_ROUTER
- N_HTTP_SERVER
- N_ICC
- N_JSON
- N_KAFKA
- N_LINALG
- N_MODULE
- N_OPENSSL_COMPAT
- N_PRETTY
- N_PTH
- N_QUERY
- N_RANDOM
- N_SHA256
- N_STR
- N_TIFF
- N_TIME
- N_USER
- N_X509
- N_ZIP
- PARTICLES
- PCRE
- PHYSICS
- SIGNALS
- STACK
- THREADS
- TRAJECTORY
- TREE
- ZLIB