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 "log.h"
|
||||||
#include "multipart.h"
|
#include "multipart.h"
|
||||||
#include "tls.h"
|
#include "tls.h"
|
||||||
|
#include "http2.h"
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@ -510,12 +511,72 @@ static void conn_cancel_timer(connection_t *conn) {
|
|||||||
*
|
*
|
||||||
* @param arg 连接上下文指针(connection_t*)
|
* @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) {
|
static void client_handler(void *arg) {
|
||||||
connection_t *conn = (connection_t *)arg;
|
connection_t *conn = (connection_t *)arg;
|
||||||
if (!conn) return;
|
if (!conn) return;
|
||||||
|
|
||||||
conn->coro = coco_self();
|
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;
|
uint32_t timeout_ms = conn->timeout_ms > 0 ? conn->timeout_ms : CONN_TIMEOUT_MS;
|
||||||
conn->timer = coco_timer(timeout_ms, conn_timeout_handler, conn);
|
conn->timer = coco_timer(timeout_ms, conn_timeout_handler, conn);
|
||||||
@ -631,11 +692,22 @@ static void accept_loop(void *arg) {
|
|||||||
close(client_fd);
|
close(client_fd);
|
||||||
continue;
|
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));
|
connection_t *conn = (connection_t *)calloc(1, sizeof(connection_t));
|
||||||
if (!conn) {
|
if (!conn) {
|
||||||
|
http2_session_t *h2 = http2_session_get(client_fd);
|
||||||
|
if (h2) http2_session_destroy(h2);
|
||||||
close(client_fd);
|
close(client_fd);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|||||||
14
tls.c
14
tls.c
@ -323,3 +323,17 @@ void tls_close(int fd) {
|
|||||||
bool tls_has_connection(int fd) {
|
bool tls_has_connection(int fd) {
|
||||||
return tls_lookup(fd) != NULL;
|
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;
|
||||||
|
}
|
||||||
|
|||||||
10
tls.h
10
tls.h
@ -89,4 +89,14 @@ void tls_close(int fd);
|
|||||||
*/
|
*/
|
||||||
bool tls_has_connection(int fd);
|
bool tls_has_connection(int fd);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* tls_negotiated_http2 - 检查 ALPN 是否协商为 HTTP/2
|
||||||
|
*
|
||||||
|
* 在 TLS 握手成功后调用。
|
||||||
|
*
|
||||||
|
* @param fd 客户端 socket
|
||||||
|
* @return true 协商为 h2
|
||||||
|
*/
|
||||||
|
bool tls_negotiated_http2(int fd);
|
||||||
|
|
||||||
#endif /* COCOON_TLS_H */
|
#endif /* COCOON_TLS_H */
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user