1 /* This is a barebone keep-alive HTTP server */
2 #include <libusockets.h>
3 /* Compiling with LIBUS_NO_SSL will ignore SSL */
4 const int SSL = 1;
5 
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <string.h>
9 
10 struct http_socket {
11 	/* How far we have streamed our response */
12 	int offset;
13 };
14 
15 struct http_context {
16 	/* The shared response */
17 	char *response;
18 	int length;
19 };
20 
21 /* We don't need any of these */
on_wakeup(struct us_loop_t * loop)22 void on_wakeup(struct us_loop_t *loop) {
23 
24 }
25 
on_pre(struct us_loop_t * loop)26 void on_pre(struct us_loop_t *loop) {
27 
28 }
29 
30 /* This is not HTTP POST, it is merely an event emitted post loop iteration */
on_post(struct us_loop_t * loop)31 void on_post(struct us_loop_t *loop) {
32 
33 }
34 
on_http_socket_writable(struct us_socket_t * s)35 struct us_socket_t *on_http_socket_writable(struct us_socket_t *s) {
36 	struct http_socket *http_socket = (struct http_socket *) us_socket_ext(SSL, s);
37 	struct http_context *http_context = (struct http_context *) us_socket_context_ext(SSL, us_socket_context(SSL, s));
38 
39 	/* Stream whatever is remaining of the response */
40 	http_socket->offset += us_socket_write(SSL, s, http_context->response + http_socket->offset, http_context->length - http_socket->offset, 0);
41 
42 	return s;
43 }
44 
on_http_socket_close(struct us_socket_t * s,int code,void * reason)45 struct us_socket_t *on_http_socket_close(struct us_socket_t *s, int code, void *reason) {
46 	printf("Client disconnected\n");
47 
48 	return s;
49 }
50 
on_http_socket_end(struct us_socket_t * s)51 struct us_socket_t *on_http_socket_end(struct us_socket_t *s) {
52 	/* HTTP does not support half-closed sockets */
53 	us_socket_shutdown(SSL, s);
54 	return us_socket_close(SSL, s, 0, NULL);
55 }
56 
on_http_socket_data(struct us_socket_t * s,char * data,int length)57 struct us_socket_t *on_http_socket_data(struct us_socket_t *s, char *data, int length) {
58 	/* Get socket extension and the socket's context's extension */
59 	struct http_socket *http_socket = (struct http_socket *) us_socket_ext(SSL, s);
60 	struct http_context *http_context = (struct http_context *) us_socket_context_ext(SSL, us_socket_context(SSL, s));
61 
62 	/* We treat all data events as a request */
63 	http_socket->offset = us_socket_write(SSL, s, http_context->response, http_context->length, 0);
64 
65 	/* Reset idle timer */
66 	us_socket_timeout(SSL, s, 30);
67 
68 	return s;
69 }
70 
on_http_socket_open(struct us_socket_t * s,int is_client,char * ip,int ip_length)71 struct us_socket_t *on_http_socket_open(struct us_socket_t *s, int is_client, char *ip, int ip_length) {
72 	struct http_socket *http_socket = (struct http_socket *) us_socket_ext(SSL, s);
73 
74 	/* Reset offset */
75 	http_socket->offset = 0;
76 
77 	/* Timeout idle HTTP connections */
78 	us_socket_timeout(SSL, s, 30);
79 
80 	printf("Client connected\n");
81 
82 	return s;
83 }
84 
on_http_socket_timeout(struct us_socket_t * s)85 struct us_socket_t *on_http_socket_timeout(struct us_socket_t *s) {
86 	/* Close idle HTTP sockets */
87 	return us_socket_close(SSL, s, 0, NULL);
88 }
89 
main()90 int main() {
91 	/* Create the event loop */
92 	struct us_loop_t *loop = us_create_loop(0, on_wakeup, on_pre, on_post, 0);
93 
94 	/* Create a socket context for HTTP */
95 	struct us_socket_context_options_t options = {};
96 	options.key_file_name = "/home/alexhultman/uWebSockets.js/misc/key.pem";
97 	options.cert_file_name = "/home/alexhultman/uWebSockets.js/misc/cert.pem";
98 	options.passphrase = "1234";
99 
100 	struct us_socket_context_t *http_context = us_create_socket_context(SSL, loop, sizeof(struct http_context), options);
101 
102 
103 	/* Generate the shared response */
104 	const char body[] = "<html><body><h1>Why hello there!</h1></body></html>";
105 
106 	struct http_context *http_context_ext = (struct http_context *) us_socket_context_ext(SSL, http_context);
107 	http_context_ext->response = (char *) malloc(128 + sizeof(body) - 1);
108 	http_context_ext->length = snprintf(http_context_ext->response, 128 + sizeof(body) - 1, "HTTP/1.1 200 OK\r\nContent-Length: %ld\r\n\r\n%s", sizeof(body) - 1, body);
109 
110 	/* Set up event handlers */
111 	us_socket_context_on_open(SSL, http_context, on_http_socket_open);
112 	us_socket_context_on_data(SSL, http_context, on_http_socket_data);
113 	us_socket_context_on_writable(SSL, http_context, on_http_socket_writable);
114 	us_socket_context_on_close(SSL, http_context, on_http_socket_close);
115 	us_socket_context_on_timeout(SSL, http_context, on_http_socket_timeout);
116 	us_socket_context_on_end(SSL, http_context, on_http_socket_end);
117 
118 	/* Start serving HTTP connections */
119 	struct us_listen_socket_t *listen_socket = us_socket_context_listen(SSL, http_context, 0, 3000, 0, sizeof(struct http_socket));
120 
121 	if (listen_socket) {
122 		printf("Listening on port 3000...\n");
123 		us_loop_run(loop);
124 	} else {
125 		printf("Failed to listen!\n");
126 	}
127 }
128