Skip to content

Commit ff3fa6d

Browse files
feat: initial h2 support code
Signed-off-by: Ar Rakin <rakinar2@onesoftnet.eu.org>
1 parent 71ab64c commit ff3fa6d

10 files changed

Lines changed: 406 additions & 89 deletions

File tree

build-aux/valgrind

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,12 @@
1212
# it under the terms of the GNU Affero General Public License as published by
1313
# the Free Software Foundation, either version 3 of the License, or
1414
# (at your option) any later version.
15-
#
15+
#
1616
# OSN freehttpd is distributed in the hope that it will be useful,
1717
# but WITHOUT ANY WARRANTY; without even the implied warranty of
1818
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1919
# GNU Affero General Public License for more details.
20-
#
20+
#
2121
# You should have received a copy of the GNU Affero General Public License
2222
# along with OSN freehttpd. If not, see <https://www.gnu.org/licenses/>.
2323

src/core/conn.c

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include <stdio.h>
2323
#include <stdlib.h>
2424
#include <string.h>
25+
#include <sys/socket.h>
2526
#include <unistd.h>
2627

2728
#define FH_LOG_MODULE_NAME "conn"
@@ -30,6 +31,8 @@
3031
#include "http/http1_response.h"
3132
#include "http/protocol.h"
3233
#include "log/log.h"
34+
#include "compat.h"
35+
#include "macros.h"
3336

3437
#ifdef HAVE_RESOURCES
3538
#include "resources.h"
@@ -61,6 +64,7 @@ fh_conn_create (fd_t client_sockfd, const struct sockaddr_in *client_addr,
6164
conn->server_addr = server_addr;
6265
conn->io_ctx.h1.req_ctx = NULL;
6366
conn->io_ctx.h1.res_ctx = NULL;
67+
conn->io_ctx.proto_det_buf.off = 0;
6468
conn->requests = (struct fh_requests *) (conn->stream + 1);
6569
conn->extra = (struct fh_conn_extra *) (conn->requests + 1);
6670

@@ -166,3 +170,46 @@ fh_conn_send_err_response (struct fh_conn *conn, enum fh_status code)
166170

167171
return rc >= 0;
168172
}
173+
174+
int
175+
fh_conn_detect_protocol (struct fh_conn *conn)
176+
{
177+
fd_t sockfd = conn->client_sockfd;
178+
179+
if (conn->io_ctx.proto_det_buf.off == 0)
180+
{
181+
conn->io_ctx.proto_det_buf.buf = fh_pool_alloc (conn->pool, H2_PREFACE_SIZE);
182+
183+
if (!conn->io_ctx.proto_det_buf.buf)
184+
return -1;
185+
}
186+
187+
if (conn->io_ctx.proto_det_buf.off >= H2_PREFACE_SIZE - 1)
188+
return 1;
189+
190+
ssize_t bytes_read = recv (
191+
sockfd, conn->io_ctx.proto_det_buf.buf + conn->io_ctx.proto_det_buf.off,
192+
H2_PREFACE_SIZE - conn->io_ctx.proto_det_buf.off, 0);
193+
194+
if (bytes_read <= 0)
195+
{
196+
if (would_block ())
197+
return 0;
198+
199+
return -1;
200+
}
201+
202+
conn->io_ctx.proto_det_buf.off += (size_t) bytes_read;
203+
204+
if (conn->io_ctx.proto_det_buf.off >= H2_PREFACE_SIZE - 1)
205+
{
206+
if (memcmp (conn->io_ctx.proto_det_buf.buf, H2_PREFACE, H2_PREFACE_SIZE) == 0)
207+
conn->protocol = FH_PROTOCOL_H2;
208+
else
209+
conn->protocol = FH_PROTOCOL_HTTP_1_1;
210+
211+
return 1;
212+
}
213+
214+
return 0;
215+
}

src/core/conn.h

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
11
/*
22
* This file is part of OSN freehttpd.
3-
*
3+
*
44
* Copyright (C) 2025 OSN Developers.
55
*
66
* OSN freehttpd is free software: you can redistribute it and/or modify
77
* it under the terms of the GNU Affero General Public License as published by
88
* the Free Software Foundation, either version 3 of the License, or
99
* (at your option) any later version.
10-
*
10+
*
1111
* OSN freehttpd is distributed in the hope that it will be useful,
1212
* but WITHOUT ANY WARRANTY; without even the implied warranty of
1313
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1414
* GNU Affero General Public License for more details.
15-
*
15+
*
1616
* You should have received a copy of the GNU Affero General Public License
1717
* along with OSN freehttpd. If not, see <https://www.gnu.org/licenses/>.
1818
*/
@@ -48,6 +48,7 @@ struct fh_conn
4848
{
4949
object_id_t id;
5050
fd_t client_sockfd;
51+
protocol_t protocol;
5152
struct sockaddr_in *client_addr;
5253
const struct sockaddr_in *server_addr;
5354
pool_t *pool;
@@ -57,6 +58,11 @@ struct fh_conn
5758
const struct fh_config_host *config;
5859

5960
union {
61+
struct {
62+
char *buf;
63+
size_t off;
64+
} proto_det_buf;
65+
6066
struct {
6167
struct fh_http1_req_ctx *req_ctx;
6268
struct fh_http1_res_ctx *res_ctx;
@@ -69,5 +75,6 @@ void fh_conn_destroy (struct fh_conn *conn);
6975
void fh_conn_push_request (struct fh_requests *requests, struct fh_request *request);
7076
struct fh_request *fh_conn_pop_request (struct fh_requests *requests);
7177
bool fh_conn_send_err_response (struct fh_conn *conn, enum fh_status code);
78+
int fh_conn_detect_protocol (struct fh_conn *conn);
7279

7380
#endif /* FH_CORE_CONN_H */

src/core/stream.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,8 @@ fh_stream_print (struct fh_stream *stream)
136136
fh_pr_debug ("Start: %u", l->is_start);
137137
fh_pr_debug ("EOS: %u", l->is_eos);
138138
fh_pr_debug ("Readonly: %u", l->buf->attrs.mem.rd_only);
139-
fh_pr_debug ("Data: |%.*s|", (int) l->buf->attrs.mem.len, l->buf->attrs.mem.data);
139+
fh_pr_debug ("DATA:");
140+
fh_pr_debug ("|%.*s|", (int) l->buf->attrs.mem.len, l->buf->attrs.mem.data);
140141
fh_pr_debug ("=======");
141142
l = l->next;
142143
}

src/event/recv.c

Lines changed: 100 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -31,20 +31,22 @@
3131
#include "log/log.h"
3232
#include "recv.h"
3333

34-
bool
35-
event_recv (struct fh_server *server, const xevent_t *event)
34+
static bool
35+
event_recv_h2 (struct fh_server *server, struct fh_conn *conn,
36+
char *proto_det_buf, size_t proto_det_off)
3637
{
37-
struct fh_conn *conn = itable_get (server->connections, event->data.fd);
38+
(void) proto_det_buf;
39+
(void) proto_det_off;
3840

39-
if (!conn)
40-
{
41-
fh_pr_err ("Socket %d does not have an associated connection object", event->data.fd);
42-
xpoll_del (server->xpoll_fd, event->data.fd, XPOLLIN);
43-
close (event->data.fd);
44-
return false;
45-
}
41+
fh_pr_err ("Not implemented: h2");
42+
fh_server_close_conn (server, conn);
43+
return false;
44+
}
4645

47-
fh_pr_info ("connection %lu: recv called", conn->id);
46+
static bool
47+
event_recv_http1 (struct fh_server *server, struct fh_conn *conn,
48+
char *proto_det_buf, size_t proto_det_off)
49+
{
4850
pool_t *child_pool = NULL;
4951

5052
if (!conn->io_ctx.h1.req_ctx)
@@ -59,24 +61,40 @@ event_recv (struct fh_server *server, const xevent_t *event)
5961
}
6062

6163
fh_stream_init (conn->stream, child_pool);
64+
65+
if (fh_stream_add_buf_data (conn->stream, (uint8_t *) proto_det_buf,
66+
proto_det_off, proto_det_off)
67+
&& conn->stream->head)
68+
{
69+
conn->stream->head->buf->attrs.mem.rd_only = true;
70+
}
6271
}
6372

64-
struct fh_http1_req_ctx *ctx = conn->io_ctx.h1.req_ctx ? conn->io_ctx.h1.req_ctx : fh_http1_ctx_create (server, conn, conn->stream);
73+
struct fh_http1_req_ctx *ctx
74+
= conn->io_ctx.h1.req_ctx
75+
? conn->io_ctx.h1.req_ctx
76+
: fh_http1_ctx_create (server, conn, conn->stream);
6577

6678
if (!conn->io_ctx.h1.req_ctx)
79+
{
6780
conn->io_ctx.h1.req_ctx = ctx;
81+
ctx->cur.link = ctx->arg_cur.link = conn->stream->head;
82+
ctx->cur.off = ctx->arg_cur.off = 0;
83+
conn->stream->head->is_start = true;
84+
}
6885

6986
if (!fh_http1_parse (ctx, conn))
7087
{
7188
if (ctx->state == H1_REQ_STATE_ERROR)
7289
{
7390
fh_pr_err ("HTTP/1.x parsing failed");
74-
fh_conn_send_err_response (conn, ctx->suggested_code == 0 ? 500 : ctx->suggested_code);
91+
fh_conn_send_err_response (
92+
conn, ctx->suggested_code == 0 ? 500 : ctx->suggested_code);
7593
fh_server_close_conn (server, conn);
7694

7795
if (child_pool)
7896
fh_pool_destroy (child_pool);
79-
97+
8098
return true;
8199
}
82100

@@ -91,8 +109,10 @@ event_recv (struct fh_server *server, const xevent_t *event)
91109
fh_conn_push_request (conn->requests, request);
92110

93111
fh_pr_info ("Method: |%s|", fh_method_to_string (ctx->request.method));
94-
fh_pr_info ("URI: |%.*s|", (int) ctx->request.uri_len, ctx->request.uri);
95-
fh_pr_info ("Protocol: %s", fh_protocol_to_string (ctx->request.protocol));
112+
fh_pr_info ("URI: |%.*s|", (int) ctx->request.uri_len,
113+
ctx->request.uri);
114+
fh_pr_info ("Protocol: %s",
115+
fh_protocol_to_string (ctx->request.protocol));
96116

97117
if (!xpoll_mod (server->xpoll_fd, conn->client_sockfd, XPOLLOUT))
98118
{
@@ -107,3 +127,67 @@ event_recv (struct fh_server *server, const xevent_t *event)
107127

108128
return true;
109129
}
130+
131+
bool
132+
event_recv (struct fh_server *server, const xevent_t *event)
133+
{
134+
struct fh_conn *conn = itable_get (server->connections, event->data.fd);
135+
136+
if (!conn)
137+
{
138+
fh_pr_err ("Socket %d does not have an associated connection object",
139+
event->data.fd);
140+
xpoll_del (server->xpoll_fd, event->data.fd, XPOLLIN);
141+
close (event->data.fd);
142+
return false;
143+
}
144+
145+
fh_pr_info ("connection %lu: recv called", conn->id);
146+
147+
char *proto_det_buf = NULL;
148+
size_t proto_det_off = 0;
149+
150+
if (conn->protocol == FH_PROTOCOL_UNKNOWN)
151+
{
152+
/* Detect the connection protocol */
153+
154+
int rc = fh_conn_detect_protocol (conn);
155+
156+
switch (rc)
157+
{
158+
case 0:
159+
fh_pr_debug ("EAGAIN while detecting protocol");
160+
return true;
161+
162+
case -1:
163+
fh_pr_debug ("I/O error while detecting protocol");
164+
fh_server_close_conn (server, conn);
165+
return true;
166+
}
167+
168+
proto_det_buf = conn->io_ctx.proto_det_buf.buf;
169+
proto_det_off = conn->io_ctx.proto_det_buf.off;
170+
171+
conn->io_ctx.h1.req_ctx = NULL;
172+
conn->io_ctx.h1.res_ctx = NULL;
173+
174+
fh_pr_debug ("Detected protocol: %s",
175+
fh_protocol_to_string (conn->protocol));
176+
}
177+
178+
switch (conn->protocol)
179+
{
180+
case FH_PROTOCOL_HTTP_1_0:
181+
case FH_PROTOCOL_HTTP_1_1:
182+
return event_recv_http1 (server, conn, proto_det_buf,
183+
proto_det_off);
184+
185+
case FH_PROTOCOL_H2:
186+
return event_recv_h2 (server, conn, proto_det_buf, proto_det_off);
187+
188+
default:
189+
fh_pr_debug ("Unsupported protocol");
190+
fh_server_close_conn (server, conn);
191+
return true;
192+
}
193+
}

src/http/h2.c

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/*
2+
* This file is part of OSN freehttpd.
3+
*
4+
* Copyright (C) 2025 OSN Developers.
5+
*
6+
* OSN freehttpd is free software: you can redistribute it and/or modify
7+
* it under the terms of the GNU Affero General Public License as published by
8+
* the Free Software Foundation, either version 3 of the License, or
9+
* (at your option) any later version.
10+
*
11+
* OSN freehttpd is distributed in the hope that it will be useful,
12+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
* GNU Affero General Public License for more details.
15+
*
16+
* You should have received a copy of the GNU Affero General Public License
17+
* along with OSN freehttpd. If not, see <https://www.gnu.org/licenses/>.
18+
*/
19+
20+
#include "h2.h"

0 commit comments

Comments
 (0)