1 /*
2 * Copyright (c) 2019 Antmicro Ltd
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr.h>
8 #include <posix/pthread.h>
9 #include <data/json.h>
10
11 #include "civetweb.h"
12
13 #define HTTP_PORT 8080
14 #define HTTPS_PORT 4443
15
16 #define CIVETWEB_MAIN_THREAD_STACK_SIZE CONFIG_MAIN_STACK_SIZE
17
18 /* Use samllest possible value of 1024 (see the line 18619 of civetweb.c) */
19 #define MAX_REQUEST_SIZE_BYTES 1024
20
21 K_THREAD_STACK_DEFINE(civetweb_stack, CIVETWEB_MAIN_THREAD_STACK_SIZE);
22
23 struct civetweb_info {
24 const char *version;
25 const char *os;
26 uint32_t features;
27 const char *feature_list;
28 const char *build;
29 const char *compiler;
30 const char *data_model;
31 };
32
33 #define FIELD(struct_, member_, type_) { \
34 .field_name = #member_, \
35 .field_name_len = sizeof(#member_) - 1, \
36 .offset = offsetof(struct_, member_), \
37 .type = type_ \
38 }
39
send_ok(struct mg_connection * conn)40 void send_ok(struct mg_connection *conn)
41 {
42 mg_printf(conn,
43 "HTTP/1.1 200 OK\r\n"
44 "Content-Type: text/html\r\n"
45 "Connection: close\r\n\r\n");
46 }
47
hello_world_handler(struct mg_connection * conn,void * cbdata)48 int hello_world_handler(struct mg_connection *conn, void *cbdata)
49 {
50 send_ok(conn);
51 mg_printf(conn, "<html><body>");
52 mg_printf(conn, "<h3>Hello World from Zephyr!</h3>");
53 mg_printf(conn, "See also:\n");
54 mg_printf(conn, "<ul>\n");
55 mg_printf(conn, "<li><a href=/info>system info</a></li>\n");
56 mg_printf(conn, "<li><a href=/history>cookie demo</a></li>\n");
57 mg_printf(conn, "</ul>\n");
58 mg_printf(conn, "</body></html>\n");
59
60 return 200;
61 }
62
system_info_handler(struct mg_connection * conn,void * cbdata)63 int system_info_handler(struct mg_connection *conn, void *cbdata)
64 {
65 static const struct json_obj_descr descr[] = {
66 FIELD(struct civetweb_info, version, JSON_TOK_STRING),
67 FIELD(struct civetweb_info, os, JSON_TOK_STRING),
68 FIELD(struct civetweb_info, feature_list, JSON_TOK_STRING),
69 FIELD(struct civetweb_info, build, JSON_TOK_STRING),
70 FIELD(struct civetweb_info, compiler, JSON_TOK_STRING),
71 FIELD(struct civetweb_info, data_model, JSON_TOK_STRING),
72 };
73
74 struct civetweb_info info = {};
75 char info_str[1024] = {};
76 int ret;
77 int size;
78
79 size = mg_get_system_info(info_str, sizeof(info_str));
80
81 ret = json_obj_parse(info_str, size, descr, ARRAY_SIZE(descr), &info);
82
83 send_ok(conn);
84
85 if (ret < 0) {
86 mg_printf(conn, "Could not retrieve: %d\n", ret);
87 return 500;
88 }
89
90
91 mg_printf(conn, "<html><body>");
92
93 mg_printf(conn, "<h3>Server info</h3>");
94 mg_printf(conn, "<ul>\n");
95 mg_printf(conn, "<li>host os - %s</li>\n", info.os);
96 mg_printf(conn, "<li>server - civetweb %s</li>\n", info.version);
97 mg_printf(conn, "<li>compiler - %s</li>\n", info.compiler);
98 mg_printf(conn, "<li>board - %s</li>\n", CONFIG_BOARD);
99 mg_printf(conn, "</ul>\n");
100
101 mg_printf(conn, "</body></html>\n");
102
103 return 200;
104 }
105
history_handler(struct mg_connection * conn,void * cbdata)106 int history_handler(struct mg_connection *conn, void *cbdata)
107 {
108 const struct mg_request_info *req_info = mg_get_request_info(conn);
109 const char *cookie = mg_get_header(conn, "Cookie");
110 char history_str[64];
111
112 mg_get_cookie(cookie, "history", history_str, sizeof(history_str));
113
114 mg_printf(conn, "HTTP/1.1 200 OK\r\n");
115 mg_printf(conn, "Connection: close\r\n");
116 mg_printf(conn, "Set-Cookie: history='%s'\r\n", req_info->local_uri);
117 mg_printf(conn, "Content-Type: text/html\r\n\r\n");
118
119 mg_printf(conn, "<html><body>");
120
121 mg_printf(conn, "<h3>Your URI is: %s<h3>\n", req_info->local_uri);
122
123 if (history_str[0] == 0) {
124 mg_printf(conn, "<h5>This is your first visit.</h5>\n");
125 } else {
126 mg_printf(conn, "<h5>your last /history visit was: %s</h5>\n",
127 history_str);
128 }
129
130 mg_printf(conn, "Some cookie-saving links to try:\n");
131 mg_printf(conn, "<ul>\n");
132 mg_printf(conn, "<li><a href=/history/first>first</a></li>\n");
133 mg_printf(conn, "<li><a href=/history/second>second</a></li>\n");
134 mg_printf(conn, "<li><a href=/history/third>third</a></li>\n");
135 mg_printf(conn, "<li><a href=/history/fourth>fourth</a></li>\n");
136 mg_printf(conn, "<li><a href=/history/fifth>fifth</a></li>\n");
137 mg_printf(conn, "</ul>\n");
138
139 mg_printf(conn, "</body></html>\n");
140
141 return 200;
142 }
143
main_pthread(void * arg)144 void *main_pthread(void *arg)
145 {
146 static const char * const options[] = {
147 "listening_ports",
148 STRINGIFY(HTTP_PORT),
149 "num_threads",
150 "1",
151 "max_request_size",
152 STRINGIFY(MAX_REQUEST_SIZE_BYTES),
153 NULL
154 };
155
156 struct mg_callbacks callbacks;
157 struct mg_context *ctx;
158
159 (void)arg;
160
161 memset(&callbacks, 0, sizeof(callbacks));
162 ctx = mg_start(&callbacks, 0, (const char **)options);
163
164 if (ctx == NULL) {
165 printf("Unable to start the server.");
166 return 0;
167 }
168
169 mg_set_request_handler(ctx, "/$", hello_world_handler, 0);
170 mg_set_request_handler(ctx, "/info$", system_info_handler, 0);
171 mg_set_request_handler(ctx, "/history", history_handler, 0);
172
173 return 0;
174 }
175
main(void)176 void main(void)
177 {
178 pthread_attr_t civetweb_attr;
179 pthread_t civetweb_thread;
180
181 (void)pthread_attr_init(&civetweb_attr);
182 (void)pthread_attr_setstack(&civetweb_attr, &civetweb_stack,
183 CIVETWEB_MAIN_THREAD_STACK_SIZE);
184
185 (void)pthread_create(&civetweb_thread, &civetweb_attr,
186 &main_pthread, 0);
187 }
188