Skip to content

Commit 73c9262

Browse files
committed
Hook up h3 router and callbacks
1 parent 7da868a commit 73c9262

9 files changed

Lines changed: 196 additions & 79 deletions

File tree

examples/Http3Server.cpp

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,18 +6,20 @@
66

77
/* Tentative example of simple Http3 server */
88
int main() {
9-
uWS::QuicApp({
9+
uWS::H3App({
1010
.key_file_name = "../misc/key.pem",
1111
.cert_file_name = "../misc/cert.pem",
1212
.passphrase = "1234"
1313
}).get("/*", [](auto *res, auto *req) {
1414

15-
std::cout << req->getHeader(":path") << std::endl;
15+
/* Printing these should obviously be disabled if doing benchmarking */
16+
//std::cout << req->getHeader(":path") << std::endl;
17+
//std::cout << req->getHeader(":method") << std::endl;
1618

17-
res->end("Hello quic!");
18-
}).listen(3000, [](auto *listen_socket) {
19+
res->end("Hello H3 from uWS!");
20+
}).listen(9004, [](auto *listen_socket) {
1921
if (listen_socket) {
20-
std::cout << "Listening on port " << 3000 << std::endl;
22+
std::cout << "Listening on port " << 9004 << std::endl;
2123
}
2224
}).run();
2325

src/Http3App.h

Lines changed: 84 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,28 +6,103 @@
66

77
namespace uWS {
88

9-
struct QuicApp {
9+
struct H3App {
1010
Http3Context *http3Context;
1111

12-
QuicApp(SocketContextOptions options = {}) {
12+
H3App(SocketContextOptions options = {}) {
1313
/* Create the http3 context */
1414
http3Context = Http3Context::create((us_loop_t *)Loop::get(), {});
15+
16+
http3Context->init();
17+
}
18+
19+
/* Disallow copying, only move */
20+
H3App(const H3App &other) = delete;
21+
22+
H3App(H3App &&other) {
23+
/* Move HttpContext */
24+
http3Context = other.http3Context;
25+
other.http3Context = nullptr;
26+
}
27+
28+
H3App &&listen(int port, std::function<void(void *)> cb) {
29+
http3Context->listen();
30+
return std::move(*this);
1531
}
1632

17-
QuicApp &listen(int port, std::function<void(void *)> cb) {
18-
return *this;
33+
H3App &&get(std::string pattern, MoveOnlyFunction<void(Http3Response *, Http3Request *)> &&handler) {
34+
if (http3Context) {
35+
http3Context->onHttp("GET", pattern, std::move(handler));
36+
}
37+
return std::move(*this);
1938
}
2039

21-
QuicApp &get(std::string path, std::function<void(Http3Response *, Http3Request *)> cb) {
22-
// http3Context->onHttp, internally using httprouter
40+
H3App &&post(std::string pattern, MoveOnlyFunction<void(Http3Response *, Http3Request *)> &&handler) {
41+
if (http3Context) {
42+
http3Context->onHttp("POST", pattern, std::move(handler));
43+
}
44+
return std::move(*this);
45+
}
46+
47+
H3App &&options(std::string pattern, MoveOnlyFunction<void(Http3Response *, Http3Request *)> &&handler) {
48+
if (http3Context) {
49+
http3Context->onHttp("OPTIONS", pattern, std::move(handler));
50+
}
51+
return std::move(*this);
52+
}
2353

24-
return *this;
54+
H3App &&del(std::string pattern, MoveOnlyFunction<void(Http3Response *, Http3Request *)> &&handler) {
55+
if (http3Context) {
56+
http3Context->onHttp("DELETE", pattern, std::move(handler));
57+
}
58+
return std::move(*this);
59+
}
60+
61+
H3App &&patch(std::string pattern, MoveOnlyFunction<void(Http3Response *, Http3Request *)> &&handler) {
62+
if (http3Context) {
63+
http3Context->onHttp("PATCH", pattern, std::move(handler));
64+
}
65+
return std::move(*this);
66+
}
67+
68+
H3App &&put(std::string pattern, MoveOnlyFunction<void(Http3Response *, Http3Request *)> &&handler) {
69+
if (http3Context) {
70+
http3Context->onHttp("PUT", pattern, std::move(handler));
71+
}
72+
return std::move(*this);
73+
}
74+
75+
H3App &&head(std::string pattern, MoveOnlyFunction<void(Http3Response *, Http3Request *)> &&handler) {
76+
if (http3Context) {
77+
http3Context->onHttp("HEAD", pattern, std::move(handler));
78+
}
79+
return std::move(*this);
80+
}
81+
82+
H3App &&connect(std::string pattern, MoveOnlyFunction<void(Http3Response *, Http3Request *)> &&handler) {
83+
if (http3Context) {
84+
http3Context->onHttp("CONNECT", pattern, std::move(handler));
85+
}
86+
return std::move(*this);
87+
}
88+
89+
H3App &&trace(std::string pattern, MoveOnlyFunction<void(Http3Response *, Http3Request *)> &&handler) {
90+
if (http3Context) {
91+
http3Context->onHttp("TRACE", pattern, std::move(handler));
92+
}
93+
return std::move(*this);
94+
}
95+
96+
/* This one catches any method */
97+
H3App &&any(std::string pattern, MoveOnlyFunction<void(Http3Response *, Http3Request *)> &&handler) {
98+
if (http3Context) {
99+
http3Context->onHttp("*", pattern, std::move(handler));
100+
}
101+
return std::move(*this);
25102
}
26103

27104
void run() {
28105
uWS::Loop::get()->run();
29106
}
30107
};
31-
32-
33108
}

src/Http3Context.h

Lines changed: 76 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -6,93 +6,111 @@ extern "C" {
66
#include "Http3ContextData.h"
77
#include "Http3ResponseData.h"
88

9-
/* Let's just have this one here for now */
10-
us_quic_socket_context_t *context;
9+
namespace uWS {
10+
struct Http3Context {
11+
static Http3Context *create(us_loop_t *loop, us_quic_socket_context_options_t options) {
12+
//return nullptr;
1113

12-
/* This would be a request */
13-
void on_stream_headers(us_quic_stream_t *s) {
14+
printf("Creating context now\n");
1415

15-
Http3ContextData *contextData = (Http3ContextData *) us_quic_socket_context_ext(us_quic_socket_context(us_quic_stream_socket(s)));
16+
/* Create quic socket context (assumes h3 for now) */
17+
auto *context = us_create_quic_socket_context(loop, options, sizeof(Http3ContextData)); // sizeof(Http3ContextData)
1618

17-
contextData->router.route();
19+
/* Specify application callbacks */
20+
us_quic_socket_context_on_stream_data(context, [](us_quic_stream_t *s, char *data, int length) {
1821

22+
// Http3ResponseData *responseData = us_quic_stream_ext(s);
23+
// responseData->onData(data, length);
1924

20-
}
25+
printf("Body length is: %d\n", length);
26+
});
27+
us_quic_socket_context_on_stream_open(context, [](us_quic_stream_t *s, int is_client) {
28+
//printf("Stream opened!\n");
2129

22-
/* And this would be the body of the request */
23-
void on_stream_data(us_quic_stream_t *s, char *data, int length) {
30+
// inplace initialize Http3ResponseData here
31+
});
32+
us_quic_socket_context_on_close(context, [](us_quic_socket_t *s) {
33+
printf("Disconnected!\n");
34+
});
35+
us_quic_socket_context_on_stream_writable(context, [](us_quic_stream_t *s) {
36+
// Http3ResponseData *responseData = us_quic_stream_ext(s);
37+
// responseData->onWritable();
38+
});
39+
us_quic_socket_context_on_stream_headers(context, [](us_quic_stream_t *s) {
2440

25-
// Http3ResponseData *responseData = us_quic_stream_ext(s);
26-
// responseData->onData(data, length);
41+
Http3ContextData *contextData = (Http3ContextData *) us_quic_socket_context_ext(us_quic_socket_context(us_quic_stream_socket(s)));
2742

28-
printf("Body length is: %d\n", length);
29-
}
43+
Http3Request *req = nullptr;
3044

31-
void on_stream_writable(us_quic_stream_t *s) {
32-
// Http3ResponseData *responseData = us_quic_stream_ext(s);
33-
// responseData->onWritable();
34-
}
45+
std::string_view upperCasedMethod = req->getHeader(":method");
46+
//std::transform(lowerCasedMethod.begin(), lowerCasedMethod.end(), lowerCasedMethod.begin(), ::tolower);
3547

36-
void on_stream_close(us_quic_stream_t *s) {
48+
contextData->router.getUserData() = {(Http3Response *) s, (Http3Request *) nullptr};
49+
contextData->router.route(upperCasedMethod, "/");
3750

38-
// Http3ResponseData *responseData = us_quic_stream_ext(s);
39-
// responseData->onAborted();
4051

41-
//printf("Stream closed\n");
52+
});
53+
us_quic_socket_context_on_open(context, [](us_quic_socket_t *s, int is_client) {
54+
printf("Connection established!\n");
55+
});
56+
us_quic_socket_context_on_stream_close(context, [](us_quic_stream_t *s) {
4257

43-
// inplace destruct Http3ResponseData here
44-
}
58+
// Http3ResponseData *responseData = us_quic_stream_ext(s);
59+
// responseData->onAborted();
4560

46-
/* On new connection */
47-
void on_open(us_quic_socket_t *s, int is_client) {
48-
printf("Connection established!\n");
49-
}
61+
//printf("Stream closed\n");
5062

51-
/* On new stream */
52-
void on_stream_open(us_quic_stream_t *s, int is_client) {
53-
//printf("Stream opened!\n");
63+
// inplace destruct Http3ResponseData here
64+
});
5465

55-
// inplace initialize Http3ResponseData here
56-
}
66+
return (Http3Context *) context;
5767

58-
void on_close(us_quic_socket_t *s) {
59-
printf("Disconnected!\n");
60-
}
68+
// call init here after setting the ext to Http3ContextData
69+
}
6170

62-
namespace uWS {
63-
struct Http3Context {
64-
static Http3Context *create(us_loop_t *loop, us_quic_socket_context_options_t options) {
65-
//return nullptr;
71+
us_quic_listen_socket_t *listen() {
72+
/* The listening socket is the actual UDP socket used */
73+
us_quic_listen_socket_t *listen_socket = us_quic_socket_context_listen((us_quic_socket_context_t *) this, "::1", 9004, sizeof(Http3ResponseData)); // sizeof(Http3ResponseData)
6674

67-
printf("Creating context now\n");
75+
return listen_socket;
76+
}
6877

69-
/* Create quic socket context (assumes h3 for now) */
70-
context = us_create_quic_socket_context(loop, options); // sizeof(Http3ContextData)
78+
void init() {
79+
// set all callbacks here
7180

72-
/* Specify application callbacks */
73-
us_quic_socket_context_on_stream_data(context, on_stream_data);
74-
us_quic_socket_context_on_stream_open(context, on_stream_open);
75-
us_quic_socket_context_on_stream_close(context, on_stream_close);
76-
us_quic_socket_context_on_stream_writable(context, on_stream_writable);
77-
us_quic_socket_context_on_stream_headers(context, on_stream_headers);
78-
us_quic_socket_context_on_open(context, on_open);
79-
us_quic_socket_context_on_close(context, on_close);
8081

81-
/* The listening socket is the actual UDP socket used */
82-
us_quic_listen_socket_t *listen_socket = us_quic_socket_context_listen(context, "::1", 9004); // sizeof(Http3ResponseData)
8382

83+
Http3ContextData *contextData = (Http3ContextData *) us_quic_socket_context_ext((us_quic_socket_context_t *) this);
8484

85-
return nullptr;
85+
printf("init: %p\n", contextData);
8686

87-
// call init here after setting the ext to Http3ContextData
88-
}
87+
new (contextData) Http3ContextData();
8988

90-
void init() {
91-
// set all callbacks here
9289
}
9390

94-
void onHttp() {
91+
// generic for get, post, any, etc
92+
void onHttp(std::string method, std::string path, MoveOnlyFunction<void(Http3Response *, Http3Request *)> &&cb) {
9593
// modifies the router we own as part of Http3ContextData, used in callbacks set in init
94+
95+
Http3ContextData *contextData = (Http3ContextData *) us_quic_socket_context_ext((us_quic_socket_context_t *) this);
96+
97+
/* Todo: This is ugly, fix */
98+
std::vector<std::string> methods;
99+
if (method == "*") {
100+
methods = contextData->router.upperCasedMethods; //bug! needs to be upper cased!
101+
// router.upperCasedMethods;
102+
} else {
103+
methods = {method};
104+
}
105+
106+
contextData->router.add(methods, path, [handler = std::move(cb)](HttpRouter<Http3ContextData::RouterData> *router) mutable {
107+
108+
Http3ContextData::RouterData &routerData = router->getUserData();
109+
110+
handler(routerData.res, routerData.req);
111+
112+
return true;
113+
});
96114
}
97115
};
98116
}

src/Http3ContextData.h

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,21 @@
11
#include "HttpRouter.h"
22

3+
struct Http3Response;
4+
struct Http3Request;
5+
36
namespace uWS {
47

58
struct Http3ContextData {
6-
HttpRouter<int> router;
9+
struct RouterData {
10+
Http3Response *res;
11+
Http3Request *req;
12+
};
13+
14+
HttpRouter<RouterData> router;
15+
16+
Http3ContextData() {
17+
printf("Constructing http3contextdata: %p\n", this);
18+
}
719
};
820

921
}

src/Http3Request.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ namespace uWS {
1515
return {value, value_length};
1616
}
1717
}
18-
return {nullptr, 0};
1918
}
19+
return {nullptr, 0};
2020
}
2121
};
2222
}

src/Http3Response.h

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
extern "C" {
2+
#include "quic.h"
3+
}
4+
15
namespace uWS {
26

37
/* Is a quic stream */
@@ -14,16 +18,16 @@ namespace uWS {
1418
// if not already written status then write status
1519

1620
/* Write headers */
17-
us_quic_socket_context_set_header(context, 0, ":status", 7, "200", 3);
21+
us_quic_socket_context_set_header(nullptr, 0, (char *) ":status", 7, "200", 3);
1822
//us_quic_socket_context_set_header(context, 1, "content-length", 14, "11", 2);
1923
//us_quic_socket_context_set_header(context, 2, "content-type", 12, "text/html", 9);
20-
us_quic_socket_context_send_headers(context, this, 1, 1);
24+
us_quic_socket_context_send_headers(nullptr, (us_quic_stream_t *) this, 1, 1);
2125

2226
/* Write body and shutdown (unknown if content-length must be present?) */
23-
us_quic_stream_write(this, "Hello quic!", 11);
27+
us_quic_stream_write((us_quic_stream_t *) this, (char *) data.data(), data.length());
2428

2529
/* Every request has its own stream, so we conceptually serve requests like in HTTP 1.0 */
26-
us_quic_stream_shutdown(this);
30+
us_quic_stream_shutdown((us_quic_stream_t *) this);
2731
}
2832
};
2933

src/Http3ResponseData.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
namespace uWS {
2+
struct Http3ResponseData {
3+
4+
};
5+
}

src/HttpRouter.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ template <class USERDATA>
3535
struct HttpRouter {
3636
/* These are public for now */
3737
std::vector<std::string> methods = {"get", "post", "head", "put", "delete", "connect", "options", "trace", "patch"};
38+
std::vector<std::string> upperCasedMethods = {"GET", "POST", "HEAD", "PUT", "DELETE", "CONNECT", "OPTIONS", "TRACE", "PATCH"};
3839
static const uint32_t HIGH_PRIORITY = 0xd0000000, MEDIUM_PRIORITY = 0xe0000000, LOW_PRIORITY = 0xf0000000;
3940

4041
private:

uSockets

0 commit comments

Comments
 (0)