cocoon/http3.c
xfy911 bf9787e6e9 feat(phase4): 实现 Phase 4 全部生态扩展模块
新增 4 个核心模块,12 个新文件,约 8832 行源代码 + 测试:

1. 扩展内置中间件 (middleware_ext.c/h)
   - JWT 认证:HS256 (HMAC-SHA256) 签名验证,Base64Url 解码
   - Security Headers:HSTS / X-Frame-Options / CSP / X-XSS-Protection
   - Request ID:32 字符 hex 唯一追踪 ID 生成与透传
   - IP 过滤:IPv4 / CIDR 黑名单与白名单,X-Forwarded-For 解析

2. 分布式负载均衡 (load_balance.c/h)
   - 一致性哈希:MurmurHash3 x86 32-bit + 512 虚拟节点/后端
   - 最少连接:实时活跃连接数跟踪
   - 加权响应时间:EWMA 指数加权移动平均
   - 随机算法

3. gRPC 支持 (grpc.c/h)
   - gRPC over HTTP/2,LEB128 消息帧编解码
   - 四种 RPC 模式:Unary / Server Streaming / Client Streaming / Bidirectional
   - gRPC-Web 兼容,17 个 gRPC 状态码完整支持

4. HTTP/3 (QUIC) (http3.c/h)
   - QUIC 传输层:UDP socket 管理,64-bit 连接 ID
   - HTTP/3 帧处理:HEADERS / DATA / SETTINGS / GOAWAY
   - QPACK 静态表编解码 (RFC 9204)
   - TLS 1.3 集成接口

新增单元测试:
- test_middleware_ext.c: 53 项测试
- test_load_balance.c: 56 项测试
- test_grpc.c: 88 项测试
- test_http3.c: 64 项测试
- 新增合计:261 项,累计 451 项

同时替换 coco 子模块为内联 stub 头文件,
确保无需外部依赖即可编译。
2026-06-10 11:36:45 +08:00

1672 lines
52 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* @file http3.c
* @brief HTTP/3 (QUIC) 支持模块实现
*
* 包含:
* - QUIC Variable-Length Integer 编解码
* - HTTP/3 帧处理HEADERS / DATA / SETTINGS / GOAWAY
* - QPACK 静态表头部压缩RFC 9204 Appendix A
* - QUIC 流管理创建、数据读写、FIN 控制)
* - QUIC 连接管理ID 分配、超时、关闭)
* - HTTP/3 会话管理
* - TLS 1.3 集成接口(条件编译)
*
* @author Cocoon Team
*/
#include "http3.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <errno.h>
/* ===== TLS 条件编译 ===== */
#if defined(OPENSSL_HAS_QUIC) && defined(OPENSSL_VERSION_NUMBER)
#include <openssl/ssl.h>
#endif
/* ===== 全局连接链表 ===== */
static quic_connection_t *g_connections = NULL;
static size_t g_connection_count = 0;
/* ===== QPACK 静态表RFC 9204 Appendix A ===== */
static const qpack_static_entry_t s_qpack_static_table[QPACK_STATIC_TABLE_SIZE] = {
/* 0 */ {":authority", ""},
/* 1 */ {":path", "/"},
/* 2 */ {":method", "GET"},
/* 3 */ {":method", "POST"},
/* 4 */ {":scheme", "https"},
/* 5 */ {":scheme", "http"},
/* 6 */ {":status", "200"},
/* 7 */ {":status", "204"},
/* 8 */ {":status", "206"},
/* 9 */ {":status", "304"},
/* 10 */ {":status", "400"},
/* 11 */ {":status", "404"},
/* 12 */ {":status", "500"},
/* 13 */ {"accept-charset", ""},
/* 14 */ {"accept-encoding", "gzip, deflate, br"},
/* 15 */ {"accept-language", ""},
/* 16 */ {"accept-ranges", ""},
/* 17 */ {"accept", ""},
/* 18 */ {"access-control-allow-origin", ""},
/* 19 */ {"age", ""},
/* 20 */ {"allow", ""},
/* 21 */ {"authorization", ""},
/* 22 */ {"cache-control", ""},
/* 23 */ {"content-disposition", ""},
/* 24 */ {"content-encoding", ""},
/* 25 */ {"content-language", ""},
/* 26 */ {"content-length", ""},
/* 27 */ {"content-location", ""},
/* 28 */ {"content-range", ""},
/* 29 */ {"content-type", ""},
/* 30 */ {"cookie", ""},
/* 31 */ {"date", ""},
/* 32 */ {"etag", ""},
/* 33 */ {"expect", ""},
/* 34 */ {"expires", ""},
/* 35 */ {"from", ""},
/* 36 */ {"host", ""},
/* 37 */ {"if-match", ""},
/* 38 */ {"if-modified-since", ""},
/* 39 */ {"if-none-match", ""},
/* 40 */ {"if-range", ""},
/* 41 */ {"if-unmodified-since", ""},
/* 42 */ {"last-modified", ""},
/* 43 */ {"link", ""},
/* 44 */ {"location", ""},
/* 45 */ {"max-forwards", ""},
/* 46 */ {"proxy-authenticate", ""},
/* 47 */ {"proxy-authorization", ""},
/* 48 */ {"range", ""},
/* 49 */ {"referer", ""},
/* 50 */ {"refresh", ""},
/* 51 */ {"retry-after", ""},
/* 52 */ {"server", ""},
/* 53 */ {"set-cookie", ""},
/* 54 */ {"strict-transport-security", ""},
/* 55 */ {"transfer-encoding", ""},
/* 56 */ {"user-agent", ""},
/* 57 */ {"vary", ""},
/* 58 */ {"via", ""},
/* 59 */ {"www-authenticate", ""},
/* 60 */ {":status", "100"},
/* 61 */ {":status", "103"},
/* 62 */ {"accept-encoding", ""},
/* 63 */ {":path", ""},
/* 64 */ {"content-type", "application/json"},
/* 65 */ {"content-type", "text/html"},
/* 66 */ {"content-type", "text/plain"},
/* 67 */ {":authority", ""},
/* 68 */ {":method", "CONNECT"},
/* 69 */ {":method", "DELETE"},
/* 70 */ {":method", "HEAD"},
/* 71 */ {":method", "OPTIONS"},
/* 72 */ {":method", "PUT"},
/* 73 */ {":scheme", "https"},
/* 74 */ {":scheme", "http"},
/* 75 */ {":status", "100"},
/* 76 */ {":status", "101"},
/* 77 */ {":status", "103"},
/* 78 */ {":status", "201"},
/* 79 */ {":status", "301"},
/* 80 */ {":status", "302"},
/* 81 */ {":status", "304"},
/* 82 */ {":status", "400"},
/* 83 */ {":status", "401"},
/* 84 */ {":status", "403"},
/* 85 */ {":status", "404"},
/* 86 */ {":status", "405"},
/* 87 */ {":status", "406"},
/* 88 */ {":status", "407"},
/* 89 */ {":status", "408"},
/* 90 */ {":status", "409"},
/* 91 */ {":status", "410"},
/* 92 */ {":status", "411"},
/* 93 */ {":status", "412"},
/* 94 */ {":status", "413"},
/* 95 */ {":status", "414"},
/* 96 */ {":status", "415"},
/* 97 */ {":status", "416"},
/* 98 */ {":status", "421"},
};
/* ===== Variable-Length Integer 编解码 ===== */
/**
* @brief 编码 QUIC variable-length integer
*/
size_t http3_encode_varint(uint64_t value, uint8_t *buf) {
if (!buf) return 0;
if (value <= 63ULL) {
buf[0] = (uint8_t)value;
return 1;
} else if (value <= 16383ULL) {
buf[0] = (uint8_t)(((value >> 8) & 0x3F) | 0x40);
buf[1] = (uint8_t)(value & 0xFF);
return 2;
} else if (value <= 1073741823ULL) {
buf[0] = (uint8_t)(((value >> 24) & 0x3F) | 0x80);
buf[1] = (uint8_t)((value >> 16) & 0xFF);
buf[2] = (uint8_t)((value >> 8) & 0xFF);
buf[3] = (uint8_t)(value & 0xFF);
return 4;
} else {
buf[0] = (uint8_t)(((value >> 56) & 0x3F) | 0xC0);
buf[1] = (uint8_t)((value >> 48) & 0xFF);
buf[2] = (uint8_t)((value >> 40) & 0xFF);
buf[3] = (uint8_t)((value >> 32) & 0xFF);
buf[4] = (uint8_t)((value >> 24) & 0xFF);
buf[5] = (uint8_t)((value >> 16) & 0xFF);
buf[6] = (uint8_t)((value >> 8) & 0xFF);
buf[7] = (uint8_t)(value & 0xFF);
return 8;
}
}
/**
* @brief 解码 QUIC variable-length integer
*/
int http3_decode_varint(const uint8_t *buf, size_t len, uint64_t *value) {
if (!buf || !value || len == 0) return -1;
uint8_t prefix = (buf[0] & 0xC0) >> 6;
size_t need = 1;
uint64_t result = 0;
switch (prefix) {
case 0:
need = 1;
result = buf[0] & 0x3F;
break;
case 1:
need = 2;
if (len < need) return -1;
result = (((uint64_t)(buf[0] & 0x3F)) << 8) | buf[1];
break;
case 2:
need = 4;
if (len < need) return -1;
result = (((uint64_t)(buf[0] & 0x3F)) << 24) |
(((uint64_t)buf[1]) << 16) |
(((uint64_t)buf[2]) << 8) |
(uint64_t)buf[3];
break;
case 3:
need = 8;
if (len < need) return -1;
result = (((uint64_t)(buf[0] & 0x3F)) << 56) |
(((uint64_t)buf[1]) << 48) |
(((uint64_t)buf[2]) << 40) |
(((uint64_t)buf[3]) << 32) |
(((uint64_t)buf[4]) << 24) |
(((uint64_t)buf[5]) << 16) |
(((uint64_t)buf[6]) << 8) |
(uint64_t)buf[7];
break;
}
*value = result;
return (int)need;
}
/**
* @brief 计算帧头编码后的大小
*/
size_t http3_frame_header_size(uint64_t frame_type, uint64_t length) {
uint8_t dummy[16];
return http3_encode_varint(frame_type, dummy) +
http3_encode_varint(length, dummy + 8);
}
/* ===== HTTP/3 帧处理 ===== */
/**
* @brief 编码 HTTP/3 帧头
*/
size_t http3_encode_frame_header(uint64_t frame_type, uint64_t length,
uint8_t *buf) {
if (!buf) return 0;
size_t n = 0;
n += http3_encode_varint(frame_type, buf);
n += http3_encode_varint(length, buf + n);
return n;
}
/**
* @brief 解码 HTTP/3 帧头
*/
int http3_decode_frame_header(const uint8_t *buf, size_t len,
uint64_t *frame_type, uint64_t *length) {
if (!buf || !frame_type || !length || len == 0) return -1;
uint64_t ft = 0, flen = 0;
int n1 = http3_decode_varint(buf, len, &ft);
if (n1 < 0) return -1;
int n2 = http3_decode_varint(buf + n1, len - (size_t)n1, &flen);
if (n2 < 0) return -1;
*frame_type = ft;
*length = flen;
return n1 + n2;
}
/**
* @brief 编码完整 HTTP/3 帧
*/
int http3_encode_frame(uint64_t frame_type,
const uint8_t *payload, size_t payload_len,
uint8_t *buf, size_t buf_cap) {
if (!buf) return -1;
size_t header_len = http3_frame_header_size(frame_type, payload_len);
if (header_len + payload_len > buf_cap) return -1;
size_t n = 0;
n += http3_encode_varint(frame_type, buf);
n += http3_encode_varint(payload_len, buf + n);
if (payload && payload_len > 0) {
memcpy(buf + n, payload, payload_len);
n += payload_len;
}
return (int)n;
}
/**
* @brief 从 QUIC 流接收缓冲区解析完整帧
*/
int http3_parse_frame(quic_stream_t *stream,
uint64_t *frame_type,
const uint8_t **payload,
size_t *payload_len) {
if (!stream || !frame_type || !payload || !payload_len) return -1;
if (stream->recv_buf_len == 0) return 1; /* 数据不足 */
uint64_t ft = 0, flen = 0;
int header_len = http3_decode_frame_header(stream->recv_buf,
stream->recv_buf_len,
&ft, &flen);
if (header_len < 0) return 1; /* 数据不足 */
if ((size_t)header_len + flen > stream->recv_buf_len) return 1; /* 数据不足 */
*frame_type = ft;
*payload = stream->recv_buf + header_len;
*payload_len = (size_t)flen;
/* 消费已解析的帧 */
size_t total = (size_t)header_len + (size_t)flen;
if (total < stream->recv_buf_len) {
memmove(stream->recv_buf, stream->recv_buf + total,
stream->recv_buf_len - total);
}
stream->recv_buf_len -= total;
return 0;
}
/* ===== QPACK 编码/解码 ===== */
/**
* @brief 在静态表中查找完全匹配的条目
*
* @param name 字段名
* @param value 字段值
* @return 索引(>= 0未找到返回 -1
*/
static int qpack_find_static_index(const char *name, const char *value) {
if (!name) return -1;
for (int i = 0; i < QPACK_STATIC_TABLE_SIZE; i++) {
if (strcmp(s_qpack_static_table[i].name, name) == 0) {
if (!value || strcmp(s_qpack_static_table[i].value, value) == 0) {
return i;
}
}
}
return -1;
}
/**
* @brief 在静态表中查找名称匹配的条目
*
* @param name 字段名
* @return 索引(>= 0未找到返回 -1
*/
static int qpack_find_static_name_index(const char *name) {
if (!name) return -1;
for (int i = 0; i < QPACK_STATIC_TABLE_SIZE; i++) {
if (strcmp(s_qpack_static_table[i].name, name) == 0) {
return i;
}
}
return -1;
}
/**
* @brief 编码字面量字符串(带长度前缀)
*
* @param str 字符串
* @param out 输出缓冲区
* @param out_cap 缓冲区容量
* @return 编码后字节数,< 0 错误
*/
static int qpack_encode_literal(const char *str, uint8_t *out, size_t out_cap) {
if (!str || !out) return -1;
size_t len = strlen(str);
uint8_t len_buf[8];
size_t len_bytes = http3_encode_varint(len, len_buf);
if (len_bytes + len > out_cap) return -1;
memcpy(out, len_buf, len_bytes);
memcpy(out + len_bytes, str, len);
return (int)(len_bytes + len);
}
/**
* @brief 解码字面量字符串(带长度前缀)
*
* @param in 输入缓冲区
* @param in_len 输入长度
* @param out 输出字符串缓冲区
* @param out_cap 输出缓冲区容量
* @param consumed 消耗字节数
* @return 解码后字符串长度,< 0 错误
*/
static int qpack_decode_literal(const uint8_t *in, size_t in_len,
char *out, size_t out_cap,
size_t *consumed) {
if (!in || !out || !consumed || in_len == 0) return -1;
uint64_t len = 0;
int n = http3_decode_varint(in, in_len, &len);
if (n < 0) return -1;
if ((size_t)n + len > in_len) return -1;
size_t copy_len = (len < (uint64_t)out_cap) ? (size_t)len : out_cap - 1;
memcpy(out, in + n, copy_len);
out[copy_len] = '\0';
*consumed = (size_t)n + (size_t)len;
return (int)copy_len;
}
/**
* @brief QPACK 编码头部字段
*
* 编码策略:
* 1. 静态表完全匹配 → 索引编码0b11XXXXXX...
* 2. 静态表名称匹配 → 字面量编码,引用名称索引
* 3. 完全不匹配 → 字面量编码,原始名称+值
*/
int qpack_encode_header(const char *name, const char *value,
uint8_t *out, size_t out_cap) {
if (!name || !value || !out || out_cap == 0) return -1;
/* 策略1静态表完全匹配 */
int idx = qpack_find_static_index(name, value);
if (idx >= 0) {
/* Indexed Field Line: 0b1TXXXXXX ... (T=1 for static table) */
/* QPACK 静态表索引是 0-based */
uint64_t encoded_idx = (uint64_t)idx;
if (encoded_idx < 63) {
if (out_cap < 1) return -1;
out[0] = (uint8_t)(0xC0 | (encoded_idx & 0x3F));
return 1;
} else {
/* 多字节编码 */
if (out_cap < 2) return -1;
out[0] = (uint8_t)(0xC0 | 0x3F); /* 0b111111 = multi-byte marker */
out[1] = (uint8_t)(encoded_idx - 63);
return 2;
}
}
/* 策略2静态表名称匹配字面量值 */
int name_idx = qpack_find_static_name_index(name);
if (name_idx >= 0) {
/* Literal Field Line with Name Reference: 0b0101XXXX ... */
/* QPACK 静态表索引是 0-based */
uint64_t encoded_idx = (uint64_t)name_idx;
size_t n = 0;
if (encoded_idx < 15) {
if (out_cap < 2) return -1;
out[n++] = (uint8_t)(0x50 | (encoded_idx & 0x0F));
} else {
/* 多字节编码 */
if (out_cap < 3) return -1;
out[n++] = (uint8_t)(0x5F); /* 0b1111 = multi-byte marker */
out[n++] = (uint8_t)(encoded_idx - 15);
}
int val_n = qpack_encode_literal(value, out + n, out_cap - n);
if (val_n < 0) return -1;
return (int)(n + (size_t)val_n);
}
/* 策略3完全字面量编码 */
/* Literal Field Line with Literal Name: 0b001XXXXX [name] [value] */
if (out_cap < 1) return -1;
size_t n = 0;
out[n++] = 0x20; /* 0b00100000 */
int name_n = qpack_encode_literal(name, out + n, out_cap - n);
if (name_n < 0) return -1;
n += (size_t)name_n;
int val_n = qpack_encode_literal(value, out + n, out_cap - n);
if (val_n < 0) return -1;
return (int)(n + (size_t)val_n);
}
/**
* @brief QPACK 解码 prefix 整数RFC 9204 Section 4.1.1
*
* QPACK 使用前缀编码:前 N 位表示值的一部分。
* 如果值超出前缀位数,则后续字节使用 base-128 延续格式。
*
* @param in 输入缓冲区
* @param in_len 输入长度
* @param prefix_bits 前缀位数6 或 4
* @param out_value 输出值
* @return 消耗字节数,< 0 错误
*/
static int qpack_decode_prefix_int(const uint8_t *in, size_t in_len,
int prefix_bits, uint64_t *out_value) {
if (!in || !out_value || in_len == 0) return -1;
uint8_t prefix_mask = (uint8_t)((1U << prefix_bits) - 1);
uint64_t value = (uint64_t)(in[0] & prefix_mask);
if (value < (uint64_t)prefix_mask) {
*out_value = value;
return 1;
}
/* Multi-byte: following bytes use base-128 continuation (RFC 9204) */
size_t pos = 1;
uint64_t m = 0;
while (pos < in_len) {
uint8_t byte = in[pos];
pos++;
value += ((uint64_t)(byte & 0x7F)) << m;
m += 7;
if ((byte & 0x80) == 0) break;
if (pos > 8) return -1; /* Too many bytes */
}
*out_value = value;
return (int)pos;
}
/**
* @brief QPACK 解码头部字段
*/
int qpack_decode_header(const uint8_t *in, size_t in_len,
qpack_decoded_t *out, size_t *consumed) {
if (!in || !out || !consumed || in_len == 0) return -1;
memset(out, 0, sizeof(*out));
size_t pos = 0;
uint8_t first = in[pos];
/* 判断编码类型 */
if ((first & 0x80) != 0) {
/* Indexed Field Line: 1TXXXXXX ... */
/* T bit: 1=static table, 0=dynamic table */
bool is_static = (first & 0x40) != 0;
if (!is_static) {
/* Dynamic table not implemented */
return -1;
}
uint64_t idx = 0;
int n = qpack_decode_prefix_int(in + pos, in_len - pos, 6, &idx);
if (n < 0) return -1;
pos += (size_t)n;
/* Static table index is 1-based */
if (idx >= (uint64_t)QPACK_STATIC_TABLE_SIZE) return -1;
const qpack_static_entry_t *entry = &s_qpack_static_table[(size_t)idx];
size_t nlen = strlen(entry->name);
size_t vlen = strlen(entry->value);
memcpy(out->name, entry->name, nlen + 1);
memcpy(out->value, entry->value, vlen + 1);
out->valid = true;
*consumed = pos;
return 0;
} else if ((first & 0x40) != 0) {
/* Literal Field Line with Name Reference: 01NTXXXX ... */
/* N bit = 0x20 (post-base), T bit = 0x10 (1=static, 0=dynamic) */
bool is_static_name = (first & 0x10) != 0;
if (!is_static_name) {
/* Dynamic table not implemented */
return -1;
}
bool value_is_huffman = (first & 0x08) != 0;
(void)value_is_huffman; /* Huffman decoding not implemented */
uint64_t idx = 0;
int n = qpack_decode_prefix_int(in + pos, in_len - pos, 4, &idx);
if (n < 0) return -1;
pos += (size_t)n;
if (idx >= (uint64_t)QPACK_STATIC_TABLE_SIZE) return -1;
const qpack_static_entry_t *entry = &s_qpack_static_table[(size_t)idx];
memcpy(out->name, entry->name, strlen(entry->name) + 1);
/* Decode value literal */
size_t val_consumed = 0;
int val_len = qpack_decode_literal(in + pos, in_len - pos,
out->value, sizeof(out->value),
&val_consumed);
if (val_len < 0) return -1;
pos += val_consumed;
out->valid = true;
*consumed = pos;
return 0;
} else if ((first & 0x20) != 0) {
/* Literal Field Line with Literal Name: 001XXXXX [H|name_len] [name] [value] */
bool name_is_huffman = (first & 0x10) != 0;
(void)name_is_huffman;
pos++;
/* Decode name */
size_t name_consumed = 0;
int name_len = qpack_decode_literal(in + pos, in_len - pos,
out->name, sizeof(out->name),
&name_consumed);
if (name_len < 0) return -1;
pos += name_consumed;
/* Decode value */
size_t val_consumed = 0;
int val_len = qpack_decode_literal(in + pos, in_len - pos,
out->value, sizeof(out->value),
&val_consumed);
if (val_len < 0) return -1;
pos += val_consumed;
out->valid = true;
*consumed = pos;
return 0;
} else {
/* 其他类型(动态表更新等)未实现 */
return -1;
}
}
/**
* @brief QPACK 编码完整请求头
*/
int qpack_encode_request_headers(const http_request_t *req,
uint8_t *out, size_t out_cap) {
if (!req || !out || out_cap == 0) return -1;
size_t total = 0;
/* Required pseudo-headers for request:
* :method, :scheme, :authority, :path
*/
int n;
/* :method */
const char *method_str = http_method_str(req->method);
n = qpack_encode_header(":method", method_str, out + total, out_cap - total);
if (n < 0) return -1;
total += (size_t)n;
/* :scheme (always https for HTTP/3) */
n = qpack_encode_header(":scheme", "https", out + total, out_cap - total);
if (n < 0) return -1;
total += (size_t)n;
/* :authority (from Host header) */
const char *authority = "";
for (int i = 0; i < req->num_headers; i++) {
if (strcasecmp(req->headers[i].name, "host") == 0) {
authority = req->headers[i].value;
break;
}
}
n = qpack_encode_header(":authority", authority, out + total, out_cap - total);
if (n < 0) return -1;
total += (size_t)n;
/* :path */
n = qpack_encode_header(":path", req->path, out + total, out_cap - total);
if (n < 0) return -1;
total += (size_t)n;
/* Regular headers */
for (int i = 0; i < req->num_headers; i++) {
n = qpack_encode_header(req->headers[i].name, req->headers[i].value,
out + total, out_cap - total);
if (n < 0) return -1;
total += (size_t)n;
}
return (int)total;
}
/**
* @brief QPACK 解码完整请求头
*/
int qpack_decode_request_headers(const uint8_t *in, size_t in_len,
http_request_t *req) {
if (!in || !req) return -1;
memset(req, 0, sizeof(*req));
req->method = HTTP_UNKNOWN;
req->content_length = -1;
size_t pos = 0;
while (pos < in_len) {
qpack_decoded_t decoded;
size_t consumed = 0;
if (qpack_decode_header(in + pos, in_len - pos, &decoded, &consumed) != 0) {
return -1;
}
pos += consumed;
if (decoded.valid) {
if (strcmp(decoded.name, ":method") == 0) {
if (strcmp(decoded.value, "GET") == 0) req->method = HTTP_GET;
else if (strcmp(decoded.value, "HEAD") == 0) req->method = HTTP_HEAD;
else if (strcmp(decoded.value, "POST") == 0) req->method = HTTP_POST;
else if (strcmp(decoded.value, "PUT") == 0) req->method = HTTP_PUT;
else if (strcmp(decoded.value, "DELETE") == 0) req->method = HTTP_DELETE;
else if (strcmp(decoded.value, "OPTIONS") == 0) req->method = HTTP_OPTIONS;
else req->method = HTTP_UNKNOWN;
} else if (strcmp(decoded.name, ":path") == 0) {
size_t plen = strlen(decoded.value);
if (plen > sizeof(req->path) - 1) plen = sizeof(req->path) - 1;
memcpy(req->path, decoded.value, plen);
req->path[plen] = '\0';
} else if (strcmp(decoded.name, ":authority") == 0) {
if (req->num_headers < HTTP_MAX_HEADERS) {
memcpy(req->headers[req->num_headers].name, "Host", 5);
size_t vcopy = strlen(decoded.value);
if (vcopy > sizeof(req->headers[0].value) - 1)
vcopy = sizeof(req->headers[0].value) - 1;
memcpy(req->headers[req->num_headers].value, decoded.value, vcopy);
req->headers[req->num_headers].value[vcopy] = '\0';
req->num_headers++;
}
} else if (decoded.name[0] != ':') {
/* Regular header (skip pseudo-headers starting with ":") */
if (req->num_headers < HTTP_MAX_HEADERS) {
size_t ncopy = strlen(decoded.name);
if (ncopy > sizeof(req->headers[0].name) - 1)
ncopy = sizeof(req->headers[0].name) - 1;
memcpy(req->headers[req->num_headers].name, decoded.name, ncopy);
req->headers[req->num_headers].name[ncopy] = '\0';
size_t vcopy = strlen(decoded.value);
if (vcopy > sizeof(req->headers[0].value) - 1)
vcopy = sizeof(req->headers[0].value) - 1;
memcpy(req->headers[req->num_headers].value, decoded.value, vcopy);
req->headers[req->num_headers].value[vcopy] = '\0';
if (strcmp(decoded.name, "content-length") == 0) {
req->content_length = atoll(decoded.value);
}
req->num_headers++;
}
}
}
}
return 0;
}
/**
* @brief QPACK 编码响应头
*/
int qpack_encode_response_headers(const http_response_t *resp,
uint8_t *out, size_t out_cap) {
if (!resp || !out || out_cap == 0) return -1;
size_t total = 0;
int n;
char status_str[16];
/* :status pseudo-header */
snprintf(status_str, sizeof(status_str), "%d", resp->status_code);
n = qpack_encode_header(":status", status_str, out + total, out_cap - total);
if (n < 0) return -1;
total += (size_t)n;
/* Content-Type */
if (resp->content_type && resp->content_type[0]) {
n = qpack_encode_header("content-type", resp->content_type,
out + total, out_cap - total);
if (n < 0) return -1;
total += (size_t)n;
}
/* Content-Length */
if (resp->content_length >= 0) {
char clen_str[32];
snprintf(clen_str, sizeof(clen_str), "%ld", (long)resp->content_length);
n = qpack_encode_header("content-length", clen_str,
out + total, out_cap - total);
if (n < 0) return -1;
total += (size_t)n;
}
/* Server */
n = qpack_encode_header("server", "Cocoon/1.0 (HTTP/3)",
out + total, out_cap - total);
if (n < 0) return -1;
total += (size_t)n;
return (int)total;
}
/**
* @brief QPACK 解码响应头
*/
int qpack_decode_response_headers(const uint8_t *in, size_t in_len,
http_response_t *resp) {
if (!in || !resp) return -1;
memset(resp, 0, sizeof(*resp));
resp->status_code = 0;
resp->content_length = -1;
size_t pos = 0;
while (pos < in_len) {
qpack_decoded_t decoded;
size_t consumed = 0;
if (qpack_decode_header(in + pos, in_len - pos, &decoded, &consumed) != 0) {
return -1;
}
pos += consumed;
if (decoded.valid) {
if (strcmp(decoded.name, ":status") == 0) {
resp->status_code = atoi(decoded.value);
} else if (strcmp(decoded.name, "content-type") == 0) {
resp->content_type = strdup(decoded.value);
} else if (strcmp(decoded.name, "content-length") == 0) {
resp->content_length = atoll(decoded.value);
}
}
}
return 0;
}
/* ===== QUIC 连接管理 ===== */
/**
* @brief 获取当前时间戳(毫秒)
*/
uint64_t quic_current_time_ms(void) {
struct timespec ts;
if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0) {
return (uint64_t)(time(NULL) * 1000ULL);
}
return (uint64_t)(ts.tv_sec * 1000ULL + ts.tv_nsec / 1000000ULL);
}
/**
* @brief 生成 64-bit 随机连接 ID
*/
uint64_t quic_generate_conn_id(void) {
/* 简单的伪随机生成器,使用当前时间作为种子 */
static unsigned int seed = 0;
if (seed == 0) {
seed = (unsigned int)time(NULL);
}
uint64_t id = 0;
id |= ((uint64_t)rand_r(&seed) << 48) & 0xFFFF000000000000ULL;
id |= ((uint64_t)rand_r(&seed) << 32) & 0x0000FFFF00000000ULL;
id |= ((uint64_t)rand_r(&seed) << 16) & 0x00000000FFFF0000ULL;
id |= ((uint64_t)rand_r(&seed)) & 0x000000000000FFFFULL;
return id;
}
/**
* @brief 创建 QUIC 连接
*/
quic_connection_t *quic_connection_create(uint64_t conn_id,
cocoon_socket_t udp_fd, const struct sockaddr_storage *peer_addr) {
quic_connection_t *conn = (quic_connection_t *)calloc(1, sizeof(quic_connection_t));
if (!conn) return NULL;
conn->conn_id = conn_id;
conn->udp_fd = udp_fd;
conn->handshake_complete = false;
conn->tls_conn = NULL;
conn->max_streams_bidi = QUIC_MAX_STREAMS_PER_CONN;
conn->next_stream_id = 0; /* 客户端 bidirectional 从 0 开始 */
conn->streams = NULL;
conn->streams_tail = NULL;
conn->bytes_received = 0;
conn->bytes_sent = 0;
conn->idle_timeout_ms = QUIC_DEFAULT_IDLE_TIMEOUT;
conn->last_activity = quic_current_time_ms();
conn->closed = false;
conn->closing = false;
conn->next = NULL;
if (peer_addr) {
memcpy(&conn->peer_addr, peer_addr, sizeof(*peer_addr));
conn->peer_addr_len = sizeof(*peer_addr);
}
/* 插入全局链表头部 */
conn->next = g_connections;
g_connections = conn;
g_connection_count++;
return conn;
}
/**
* @brief 销毁 QUIC 连接
*/
void quic_connection_destroy(quic_connection_t *conn) {
if (!conn) return;
/* 释放所有流 */
quic_stream_t *stream = conn->streams;
while (stream) {
quic_stream_t *next = stream->next;
if (stream->recv_buf) {
free(stream->recv_buf);
}
free(stream);
stream = next;
}
conn->streams = NULL;
conn->streams_tail = NULL;
/* 释放 TLS 连接 */
if (conn->tls_conn) {
#if defined(OPENSSL_HAS_QUIC) && defined(OPENSSL_VERSION_NUMBER)
/* 使用 OpenSSL QUIC-TLS 接口 */
SSL_free((SSL *)conn->tls_conn);
#else
free(conn->tls_conn);
#endif
conn->tls_conn = NULL;
}
/* 从全局链表中移除 */
quic_connection_t **pp = &g_connections;
while (*pp) {
if (*pp == conn) {
*pp = conn->next;
g_connection_count--;
break;
}
pp = &(*pp)->next;
}
free(conn);
}
/**
* @brief 在全局链表中查找 QUIC 连接
*/
quic_connection_t *quic_find_connection(uint64_t conn_id) {
quic_connection_t *conn = g_connections;
while (conn) {
if (conn->conn_id == conn_id && !conn->closed) {
return conn;
}
conn = conn->next;
}
return NULL;
}
/**
* @brief 移除并清理超时连接
*/
void quic_cleanup_timeout_connections(uint64_t timeout_ms) {
uint64_t now = quic_current_time_ms();
quic_connection_t *conn = g_connections;
quic_connection_t *prev = NULL;
while (conn) {
quic_connection_t *next = conn->next;
if (!conn->closed && (now - conn->last_activity) > timeout_ms) {
/* 超时,移除连接 */
if (prev) {
prev->next = next;
} else {
g_connections = next;
}
g_connection_count--;
/* 清理连接 */
quic_stream_t *stream = conn->streams;
while (stream) {
quic_stream_t *snext = stream->next;
if (stream->recv_buf) free(stream->recv_buf);
free(stream);
stream = snext;
}
if (conn->tls_conn) {
#if defined(OPENSSL_HAS_QUIC) && defined(OPENSSL_VERSION_NUMBER)
SSL_free((SSL *)conn->tls_conn);
#else
free(conn->tls_conn);
#endif
}
free(conn);
} else {
prev = conn;
}
conn = next;
}
}
/**
* @brief 获取活跃 QUIC 连接数
*/
size_t quic_get_connection_count(void) {
return g_connection_count;
}
/**
* @brief 发送 QUIC 数据报
*/
int quic_send_datagram(quic_connection_t *conn, const uint8_t *data, size_t len) {
if (!conn || !data || len == 0) return -1;
if (conn->udp_fd == COCOON_INVALID_SOCKET) return -1;
ssize_t sent = sendto(conn->udp_fd, (const char *)data, len, 0,
(const struct sockaddr *)&conn->peer_addr,
conn->peer_addr_len);
if (sent < 0) return -1;
conn->bytes_sent += (uint64_t)sent;
conn->last_activity = quic_current_time_ms();
return 0;
}
/* ===== QUIC 流管理 ===== */
/**
* @brief 获取或创建 QUIC 流
*/
quic_stream_t *quic_stream_get_or_create(quic_connection_t *conn, uint64_t stream_id) {
if (!conn) return NULL;
/* 查找现有流 */
quic_stream_t *stream = conn->streams;
while (stream) {
if (stream->stream_id == stream_id) {
return stream;
}
stream = stream->next;
}
/* 创建新流 */
stream = (quic_stream_t *)calloc(1, sizeof(quic_stream_t));
if (!stream) return NULL;
stream->stream_id = stream_id;
stream->offset = 0;
stream->recv_offset = 0;
stream->peer_fin = false;
stream->local_fin = false;
stream->reset = false;
stream->recv_buf = NULL;
stream->recv_buf_len = 0;
stream->recv_buf_cap = 0;
stream->conn = conn;
stream->next = NULL;
/* 插入链表尾部 */
if (conn->streams_tail) {
conn->streams_tail->next = stream;
} else {
conn->streams = stream;
}
conn->streams_tail = stream;
return stream;
}
/**
* @brief 销毁 QUIC 流
*/
void quic_stream_destroy(quic_connection_t *conn, quic_stream_t *stream) {
if (!conn || !stream) return;
/* 从链表中移除 */
quic_stream_t **pp = &conn->streams;
while (*pp) {
if (*pp == stream) {
*pp = stream->next;
if (conn->streams_tail == stream) {
conn->streams_tail = (*pp == NULL) ? NULL : conn->streams;
/* Fix tail pointer */
if (conn->streams_tail == NULL && conn->streams != NULL) {
quic_stream_t *s = conn->streams;
while (s->next) s = s->next;
conn->streams_tail = s;
}
}
break;
}
pp = &(*pp)->next;
}
if (stream->recv_buf) {
free(stream->recv_buf);
}
free(stream);
}
/**
* @brief 查找 QUIC 流
*/
quic_stream_t *quic_stream_find(quic_connection_t *conn, uint64_t stream_id) {
if (!conn) return NULL;
quic_stream_t *stream = conn->streams;
while (stream) {
if (stream->stream_id == stream_id) {
return stream;
}
stream = stream->next;
}
return NULL;
}
/**
* @brief 向 QUIC 流写入数据(追加到流的接收缓冲区)
*/
int quic_stream_write(quic_stream_t *stream, const uint8_t *data, size_t len) {
if (!stream || !data) return -1;
/* 确保缓冲区容量足够 */
size_t need = stream->recv_buf_len + len;
if (need > stream->recv_buf_cap) {
size_t new_cap = stream->recv_buf_cap * 2;
if (new_cap == 0) new_cap = 4096;
while (new_cap < need) new_cap *= 2;
uint8_t *new_buf = (uint8_t *)realloc(stream->recv_buf, new_cap);
if (!new_buf) return -1;
stream->recv_buf = new_buf;
stream->recv_buf_cap = new_cap;
}
memcpy(stream->recv_buf + stream->recv_buf_len, data, len);
stream->recv_buf_len += len;
stream->recv_offset += len;
if (stream->conn) {
stream->conn->last_activity = quic_current_time_ms();
}
return 0;
}
/**
* @brief 从 QUIC 流读取数据
*/
ssize_t quic_stream_read(quic_stream_t *stream, uint8_t *buf, size_t len) {
if (!stream || !buf) return -1;
size_t to_read = stream->recv_buf_len < len ? stream->recv_buf_len : len;
if (to_read == 0) return 0;
memcpy(buf, stream->recv_buf, to_read);
/* 消费已读取的数据 */
if (to_read < stream->recv_buf_len) {
memmove(stream->recv_buf, stream->recv_buf + to_read,
stream->recv_buf_len - to_read);
}
stream->recv_buf_len -= to_read;
return (ssize_t)to_read;
}
/**
* @brief 设置 QUIC 流 FIN 标志
*/
void quic_stream_set_fin(quic_stream_t *stream) {
if (!stream) return;
stream->local_fin = true;
}
/* ===== HTTP/3 会话管理 ===== */
/**
* @brief 全局 HTTP/3 初始化
*/
bool http3_init(void) {
/* 重置全局状态 */
g_connections = NULL;
g_connection_count = 0;
/* 初始化随机种子 */
srand((unsigned int)time(NULL));
return true;
}
/**
* @brief 全局 HTTP/3 清理
*/
void http3_cleanup(void) {
/* 销毁所有连接 */
while (g_connections) {
quic_connection_t *conn = g_connections;
g_connections = conn->next;
quic_stream_t *stream = conn->streams;
while (stream) {
quic_stream_t *next = stream->next;
if (stream->recv_buf) free(stream->recv_buf);
free(stream);
stream = next;
}
if (conn->tls_conn) {
#if defined(OPENSSL_HAS_QUIC) && defined(OPENSSL_VERSION_NUMBER)
SSL_free((SSL *)conn->tls_conn);
#else
free(conn->tls_conn);
#endif
}
free(conn);
}
g_connection_count = 0;
}
/**
* @brief 创建 HTTP/3 会话
*/
http3_session_t *http3_session_create(quic_connection_t *conn) {
if (!conn) return NULL;
http3_session_t *session = (http3_session_t *)calloc(1, sizeof(http3_session_t));
if (!session) return NULL;
session->conn = conn;
session->max_field_section_size = HTTP3_DEFAULT_MAX_FIELD_SECTION_SIZE;
session->qpack_encoder_max_capacity = 0; /* 不使用动态表 */
session->qpack_decoder_max_capacity = 0;
session->goaway_stream_id = UINT64_MAX;
session->settings_received = false;
session->settings_sent = false;
/* 发送服务端 SETTINGS */
http3_send_settings(session);
return session;
}
/**
* @brief 销毁 HTTP/3 会话
*/
void http3_session_destroy(http3_session_t *session) {
if (!session) return;
/* 释放所有 HTTP/3 流 */
for (int i = 0; i < QUIC_MAX_STREAMS_PER_CONN; i++) {
if (session->h3_streams[i]) {
/* 不销毁底层 QUIC 流,只释放 HTTP/3 包装 */
free(session->h3_streams[i]);
session->h3_streams[i] = NULL;
}
}
free(session);
}
/**
* @brief 发送 SETTINGS 帧
*/
int http3_send_settings(http3_session_t *session) {
if (!session || !session->conn) return -1;
uint8_t payload[64];
size_t pos = 0;
/* 编码 SETTINGS 参数(键值对 varint */
pos += http3_encode_varint(HTTP3_SETTING_MAX_FIELD_SECTION_SIZE,
payload + pos);
pos += http3_encode_varint(session->max_field_section_size,
payload + pos);
pos += http3_encode_varint(HTTP3_SETTING_QPACK_MAX_TABLE_CAPACITY,
payload + pos);
pos += http3_encode_varint(0, payload + pos); /* 0 capacity = no dynamic table */
/* 编码完整帧 */
uint8_t frame[128];
int frame_len = http3_encode_frame(HTTP3_FRAME_SETTINGS, payload, pos,
frame, sizeof(frame));
if (frame_len < 0) return -1;
/* 通过流 ID 2服务器控制流发送 */
/* 简化:直接发送数据报 */
if (quic_send_datagram(session->conn, frame, (size_t)frame_len) != 0) {
return -1;
}
session->settings_sent = true;
return 0;
}
/**
* @brief 处理 HTTP/3 控制流
*/
int http3_handle_control_stream(http3_session_t *session, quic_stream_t *stream,
const uint8_t *data, size_t len) {
if (!session || !stream || !data || len == 0) return -1;
/* 将数据追加到流的接收缓冲区 */
if (quic_stream_write(stream, data, len) != 0) {
return -1;
}
/* 尝试解析帧 */
uint64_t frame_type = 0;
const uint8_t *payload = NULL;
size_t payload_len = 0;
while (http3_parse_frame(stream, &frame_type, &payload, &payload_len) == 0) {
switch (frame_type) {
case HTTP3_FRAME_SETTINGS: {
/* 解析 SETTINGS 帧 */
size_t pos = 0;
while (pos + 2 <= payload_len) {
uint64_t setting_id = 0, setting_value = 0;
int n1 = http3_decode_varint(payload + pos, payload_len - pos,
&setting_id);
if (n1 < 0) break;
pos += (size_t)n1;
int n2 = http3_decode_varint(payload + pos, payload_len - pos,
&setting_value);
if (n2 < 0) break;
pos += (size_t)n2;
if (setting_id == HTTP3_SETTING_MAX_FIELD_SECTION_SIZE) {
session->max_field_section_size = setting_value;
}
}
session->settings_received = true;
break;
}
case HTTP3_FRAME_GOAWAY: {
/* 解析 GOAWAY 帧 */
uint64_t stream_id = 0;
if (payload_len >= 1) {
http3_decode_varint(payload, payload_len, &stream_id);
session->goaway_stream_id = stream_id;
session->conn->closing = true;
}
break;
}
default:
/* 忽略未知帧 */
break;
}
}
return 0;
}
/* ===== HTTP/3 请求/响应处理 ===== */
/**
* @brief 查找或创建 HTTP/3 流
*/
static http3_stream_t *h3_stream_get_or_create(http3_session_t *session,
uint64_t stream_id) {
if (!session) return NULL;
/* 查找流在数组中的索引 */
size_t idx = (size_t)(stream_id / 4);
if (idx >= QUIC_MAX_STREAMS_PER_CONN) return NULL;
if (session->h3_streams[idx]) {
return session->h3_streams[idx];
}
/* 创建新的 HTTP/3 流 */
http3_stream_t *h3s = (http3_stream_t *)calloc(1, sizeof(http3_stream_t));
if (!h3s) return NULL;
/* 获取或创建底层 QUIC 流 */
h3s->qstream = quic_stream_get_or_create(session->conn, stream_id);
if (!h3s->qstream) {
free(h3s);
return NULL;
}
h3s->headers_received = false;
h3s->data_received = false;
h3s->headers_sent = false;
h3s->trailers_sent = false;
h3s->error_code = HTTP3_NO_ERROR;
h3s->request_complete = false;
h3s->response_complete = false;
session->h3_streams[idx] = h3s;
return h3s;
}
/**
* @brief 从 HTTP/3 流读取请求
*/
int64_t http3_read_request(http3_session_t *session, http_request_t *req) {
if (!session || !req || !session->conn) return -1;
/* 遍历所有 HTTP/3 流,寻找有完整请求的 */
for (int i = 0; i < QUIC_MAX_STREAMS_PER_CONN; i++) {
http3_stream_t *h3s = session->h3_streams[i];
if (!h3s || !h3s->qstream) continue;
quic_stream_t *qstream = h3s->qstream;
if (qstream->recv_buf_len == 0) continue;
/* 尝试解析帧 */
uint64_t frame_type = 0;
const uint8_t *payload = NULL;
size_t payload_len = 0;
/* 保存缓冲区状态,以便回滚 */
size_t saved_len = qstream->recv_buf_len;
uint8_t *saved_buf = NULL;
if (saved_len > 0) {
saved_buf = (uint8_t *)malloc(saved_len);
if (saved_buf) memcpy(saved_buf, qstream->recv_buf, saved_len);
}
int parse_result = http3_parse_frame(qstream, &frame_type, &payload, &payload_len);
if (parse_result != 0 || frame_type != HTTP3_FRAME_HEADERS) {
/* 恢复缓冲区 */
if (saved_buf) {
if (qstream->recv_buf_cap < saved_len) {
uint8_t *new_buf = (uint8_t *)realloc(qstream->recv_buf, saved_len);
if (new_buf) {
qstream->recv_buf = new_buf;
qstream->recv_buf_cap = saved_len;
}
}
if (qstream->recv_buf) {
memcpy(qstream->recv_buf, saved_buf, saved_len);
qstream->recv_buf_len = saved_len;
}
free(saved_buf);
}
continue;
}
free(saved_buf);
/* 解码 HEADERS */
if (qpack_decode_request_headers(payload, payload_len, req) != 0) {
continue;
}
h3s->headers_received = true;
/* 检查是否有 DATA 帧跟随 */
if (qstream->recv_buf_len > 0) {
size_t saved_len2 = qstream->recv_buf_len;
uint8_t *saved_buf2 = (uint8_t *)malloc(saved_len2);
if (saved_buf2) memcpy(saved_buf2, qstream->recv_buf, saved_len2);
uint64_t data_frame_type = 0;
const uint8_t *data_payload = NULL;
size_t data_payload_len = 0;
if (http3_parse_frame(qstream, &data_frame_type,
&data_payload, &data_payload_len) == 0 &&
data_frame_type == HTTP3_FRAME_DATA) {
/* 有 DATA 帧 */
if (data_payload_len > 0) {
req->body = (char *)malloc(data_payload_len + 1);
if (req->body) {
memcpy(req->body, data_payload, data_payload_len);
req->body[data_payload_len] = '\0';
req->body_len = data_payload_len;
}
}
h3s->data_received = true;
} else {
/* 恢复缓冲区 */
if (saved_buf2) {
if (qstream->recv_buf_cap < saved_len2) {
uint8_t *nb = realloc(qstream->recv_buf, saved_len2);
if (nb) {
qstream->recv_buf = nb;
qstream->recv_buf_cap = saved_len2;
}
}
if (qstream->recv_buf) {
memcpy(qstream->recv_buf, saved_buf2, saved_len2);
qstream->recv_buf_len = saved_len2;
}
}
}
free(saved_buf2);
}
/* 如果 HEADERS 帧已收到,检查 FIN */
if (qstream->peer_fin || !h3s->data_received) {
h3s->request_complete = true;
}
return (int64_t)qstream->stream_id;
}
return -1; /* 没有完整请求 */
}
/**
* @brief 发送 HTTP/3 响应
*/
int http3_send_response(http3_session_t *session, uint64_t stream_id,
const http_response_t *resp,
const uint8_t *body, size_t body_len) {
if (!session || !session->conn) return -1;
http3_stream_t *h3s = h3_stream_get_or_create(session, stream_id);
if (!h3s) return -1;
/* 编码响应头 */
uint8_t headers_buf[4096];
int headers_len = qpack_encode_response_headers(resp, headers_buf,
sizeof(headers_buf));
if (headers_len < 0) return -1;
/* 编码 HEADERS 帧 */
uint8_t headers_frame[8192];
int headers_frame_len = http3_encode_frame(HTTP3_FRAME_HEADERS,
headers_buf, (size_t)headers_len,
headers_frame, sizeof(headers_frame));
if (headers_frame_len < 0) return -1;
/* 发送 HEADERS 帧 */
if (quic_send_datagram(session->conn, headers_frame,
(size_t)headers_frame_len) != 0) {
return -1;
}
h3s->headers_sent = true;
/* 发送 DATA 帧(如果有 body */
if (body && body_len > 0) {
uint8_t data_frame_buf[16384];
int data_frame_len = http3_encode_frame(HTTP3_FRAME_DATA,
body, body_len,
data_frame_buf,
sizeof(data_frame_buf));
if (data_frame_len < 0) return -1;
if (quic_send_datagram(session->conn, data_frame_buf,
(size_t)data_frame_len) != 0) {
return -1;
}
}
h3s->response_complete = true;
return 0;
}
/**
* @brief 发送 HTTP/3 错误响应
*/
void http3_send_error(http3_session_t *session, uint64_t stream_id,
int status_code, const char *message) {
if (!session) return;
http_response_t resp = {0};
resp.status_code = status_code;
resp.content_type = "text/html; charset=utf-8";
/* 构造简单错误页面 */
char body[1024];
int body_len = snprintf(body, sizeof(body),
"<!DOCTYPE html><html><head><title>%d Error</title></head>"
"<body><h1>%d %s</h1><p>%s</p></body></html>",
status_code, status_code,
status_code == 404 ? "Not Found" :
status_code == 500 ? "Internal Server Error" :
status_code == 400 ? "Bad Request" :
status_code == 405 ? "Method Not Allowed" : "Error",
message ? message : "");
resp.content_length = body_len;
http3_send_response(session, stream_id, &resp,
(const uint8_t *)body, (size_t)body_len);
}
/**
* @brief 关闭 QUIC 连接
*/
void http3_close_connection(quic_connection_t *conn, http3_error_t error) {
if (!conn || conn->closed) return;
(void)error; /* 错误码可用于发送 CONNECTION_CLOSE 帧 */
conn->closed = true;
conn->closing = true;
/* 发送 GOAWAY 帧 */
if (conn->udp_fd != COCOON_INVALID_SOCKET) {
uint8_t goaway_payload[16];
size_t pos = 0;
pos += http3_encode_varint(UINT64_MAX, goaway_payload + pos);
uint8_t frame[32];
int frame_len = http3_encode_frame(HTTP3_FRAME_GOAWAY,
goaway_payload, pos,
frame, sizeof(frame));
if (frame_len > 0) {
quic_send_datagram(conn, frame, (size_t)frame_len);
}
}
}
/* ===== UDP 服务器循环 ===== */
/**
* @brief 处理 UDP 数据报
*
* 简化版处理:不实现完整 QUIC 数据报解析,
* 而是将数据直接分发给对应连接的流。
*/
void http3_process_datagram(cocoon_socket_t udp_fd,
const uint8_t *buf, size_t len,
const struct sockaddr_storage *peer_addr) {
if (!buf || len == 0 || !peer_addr) return;
/* 简化处理:假设数据报前 8 字节是连接 ID */
uint64_t conn_id = 0;
if (len >= 8) {
conn_id = ((uint64_t)buf[0] << 56) |
((uint64_t)buf[1] << 48) |
((uint64_t)buf[2] << 40) |
((uint64_t)buf[3] << 32) |
((uint64_t)buf[4] << 24) |
((uint64_t)buf[5] << 16) |
((uint64_t)buf[6] << 8) |
(uint64_t)buf[7];
}
/* 查找或创建连接 */
quic_connection_t *conn = quic_find_connection(conn_id);
if (!conn) {
conn = quic_connection_create(conn_id, udp_fd, peer_addr);
if (!conn) return;
}
/* 更新活动时间 */
conn->last_activity = quic_current_time_ms();
conn->bytes_received += len;
/* 简化:假设剩余数据包含 [stream_id:8][data...]
* 在实际完整实现中,这里需要解析 QUIC 数据包头、包号、帧等
*/
if (len > 16) {
uint64_t stream_id = ((uint64_t)buf[8] << 56) |
((uint64_t)buf[9] << 48) |
((uint64_t)buf[10] << 40) |
((uint64_t)buf[11] << 32) |
((uint64_t)buf[12] << 24) |
((uint64_t)buf[13] << 16) |
((uint64_t)buf[14] << 8) |
(uint64_t)buf[15];
quic_stream_t *stream = quic_stream_get_or_create(conn, stream_id);
if (stream) {
quic_stream_write(stream, buf + 16, len - 16);
}
}
}
/**
* @brief 接受新的 QUIC 连接
*
* 从 UDP socket 接收数据报并处理。
*/
quic_connection_t *http3_accept(cocoon_socket_t udp_fd) {
if (udp_fd == COCOON_INVALID_SOCKET) return NULL;
uint8_t buf[QUIC_MAX_DATAGRAM_SIZE];
struct sockaddr_storage peer_addr;
socklen_t peer_addr_len = sizeof(peer_addr);
ssize_t n = recvfrom(udp_fd, (char *)buf, sizeof(buf), 0,
(struct sockaddr *)&peer_addr, &peer_addr_len);
if (n <= 0) return NULL;
http3_process_datagram(udp_fd, buf, (size_t)n, &peer_addr);
/* 返回新创建或找到的连接 */
if (n >= 8) {
uint64_t conn_id = ((uint64_t)buf[0] << 56) |
((uint64_t)buf[1] << 48) |
((uint64_t)buf[2] << 40) |
((uint64_t)buf[3] << 32) |
((uint64_t)buf[4] << 24) |
((uint64_t)buf[5] << 16) |
((uint64_t)buf[6] << 8) |
(uint64_t)buf[7];
return quic_find_connection(conn_id);
}
return NULL;
}