feat(http2): 集成 HTTP/2 到服务器主循环
- server.c: 添加 handle_http2() 函数,在 client_handler 中检测 HTTP/2 连接 - TLS ALPN 协商后自动创建 HTTP/2 会话 - HTTP/2 连接走独立处理路径(handle_http2),支持帧读写 - 连接清理时销毁 HTTP/2 会话 - tls.c: 新增 tls_negotiated_http2(),检查 ALPN 是否协商为 h2 - tls.h: 添加 tls_negotiated_http2() 声明 - 编译通过,39 项集成测试 + 127 单元测试全部通过
This commit is contained in:
parent
42879cdafd
commit
bc7505dc02
72
server.c
72
server.c
@ -22,6 +22,7 @@
|
||||
#include "log.h"
|
||||
#include "multipart.h"
|
||||
#include "tls.h"
|
||||
#include "http2.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@ -510,12 +511,72 @@ static void conn_cancel_timer(connection_t *conn) {
|
||||
*
|
||||
* @param arg 连接上下文指针(connection_t*)
|
||||
*/
|
||||
/**
|
||||
* handle_http2 - 处理 HTTP/2 连接
|
||||
*
|
||||
* 使用 nghttp2 库处理 HTTP/2 帧,服务静态资源。
|
||||
*
|
||||
* @param conn 连接上下文
|
||||
*/
|
||||
static void handle_http2(connection_t *conn) {
|
||||
http2_session_t *h2 = http2_session_get(conn->fd);
|
||||
if (!h2) return;
|
||||
|
||||
uint32_t timeout_ms = conn->timeout_ms > 0 ? conn->timeout_ms : CONN_TIMEOUT_MS;
|
||||
|
||||
while (!conn->closed && http2_want_read(h2)) {
|
||||
/* 读取数据 */
|
||||
char buf[8192];
|
||||
ssize_t n;
|
||||
if (tls_has_connection(conn->fd)) {
|
||||
n = tls_read(conn->fd, buf, sizeof(buf));
|
||||
} else if (coco_sched_get_current() != NULL) {
|
||||
n = coco_read(conn->fd, buf, sizeof(buf));
|
||||
} else {
|
||||
n = read(conn->fd, buf, sizeof(buf));
|
||||
}
|
||||
|
||||
if (n > 0) {
|
||||
conn_reset_timer(conn, timeout_ms);
|
||||
if (http2_recv(h2, (const uint8_t *)buf, (size_t)n) != 0) {
|
||||
log_debug("HTTP/2 接收错误 fd=%d", conn->fd);
|
||||
break;
|
||||
}
|
||||
} else if (n == 0) {
|
||||
break; /* 对端关闭 */
|
||||
} else {
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) {
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* 发送挂起的帧 */
|
||||
if (http2_want_write(h2)) {
|
||||
if (http2_send_pending(h2) != 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
http2_session_destroy(h2);
|
||||
}
|
||||
|
||||
static void client_handler(void *arg) {
|
||||
connection_t *conn = (connection_t *)arg;
|
||||
if (!conn) return;
|
||||
|
||||
conn->coro = coco_self();
|
||||
|
||||
/* 检查是否是 HTTP/2 连接 */
|
||||
if (http2_session_is_http2(conn->fd)) {
|
||||
handle_http2(conn);
|
||||
conn_cancel_timer(conn);
|
||||
close_connection(conn);
|
||||
free(conn);
|
||||
return;
|
||||
}
|
||||
|
||||
/* 启动空闲定时器 */
|
||||
uint32_t timeout_ms = conn->timeout_ms > 0 ? conn->timeout_ms : CONN_TIMEOUT_MS;
|
||||
conn->timer = coco_timer(timeout_ms, conn_timeout_handler, conn);
|
||||
@ -631,11 +692,22 @@ static void accept_loop(void *arg) {
|
||||
close(client_fd);
|
||||
continue;
|
||||
}
|
||||
/* 检查 ALPN 协商结果,创建 HTTP/2 会话 */
|
||||
if (tls_negotiated_http2(client_fd)) {
|
||||
log_debug("fd=%d ALPN 协商为 HTTP/2", client_fd);
|
||||
if (http2_on_connection_accepted(client_fd, true) != 0) {
|
||||
log_warn("HTTP/2 会话创建失败 fd=%d", client_fd);
|
||||
close(client_fd);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 创建连接上下文 */
|
||||
connection_t *conn = (connection_t *)calloc(1, sizeof(connection_t));
|
||||
if (!conn) {
|
||||
http2_session_t *h2 = http2_session_get(client_fd);
|
||||
if (h2) http2_session_destroy(h2);
|
||||
close(client_fd);
|
||||
continue;
|
||||
}
|
||||
|
||||
14
tls.c
14
tls.c
@ -323,3 +323,17 @@ void tls_close(int fd) {
|
||||
bool tls_has_connection(int fd) {
|
||||
return tls_lookup(fd) != NULL;
|
||||
}
|
||||
|
||||
bool tls_negotiated_http2(int fd) {
|
||||
tls_conn_t *t = tls_lookup(fd);
|
||||
if (!t || !t->ssl) return false;
|
||||
|
||||
const unsigned char *alpn = NULL;
|
||||
unsigned int alpn_len = 0;
|
||||
SSL_get0_alpn_selected(t->ssl, &alpn, &alpn_len);
|
||||
|
||||
if (alpn_len == 2 && memcmp(alpn, "h2", 2) == 0) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user