1 /* Copyright (c) 2013-2018 the Civetweb developers
2 * Copyright (c) 2013 No Face Press, LLC
3 * License http://opensource.org/licenses/mit-license.php MIT License
6 // Simple example program on how to use Embedded C++ interface.
8 #include "CivetServer.h"
17 #define DOCUMENT_ROOT "."
19 #define EXAMPLE_URI "/example"
20 #define EXIT_URI "/exit"
23 /* Exit flag for main loop */
24 volatile bool exitNow
= false;
27 class ExampleHandler
: public CivetHandler
31 handleGet(CivetServer
*server
, struct mg_connection
*conn
)
34 "HTTP/1.1 200 OK\r\nContent-Type: "
35 "text/html\r\nConnection: close\r\n\r\n");
36 mg_printf(conn
, "<html><body>\r\n");
38 "<h2>This is an example text from a C++ handler</h2>\r\n");
40 "<p>To see a page from the A handler <a "
41 "href=\"a\">click here</a></p>\r\n");
43 "<form action=\"a\" method=\"get\">"
44 "To see a page from the A handler with a parameter "
45 "<input type=\"submit\" value=\"click here\" "
46 "name=\"param\" \\> (GET)</form>\r\n");
48 "<form action=\"a\" method=\"post\">"
49 "To see a page from the A handler with a parameter "
50 "<input type=\"submit\" value=\"click here\" "
51 "name=\"param\" \\> (POST)</form>\r\n");
53 "<p>To see a page from the A/B handler <a "
54 "href=\"a/b\">click here</a></p>\r\n");
56 "<p>To see a page from the *.foo handler <a "
57 "href=\"xy.foo\">click here</a></p>\r\n");
59 "<p>To see a page from the WebSocket handler <a "
60 "href=\"ws\">click here</a></p>\r\n");
62 "<p>To exit <a href=\"%s\">click here</a></p>\r\n",
64 mg_printf(conn
, "</body></html>\r\n");
69 class ExitHandler
: public CivetHandler
73 handleGet(CivetServer
*server
, struct mg_connection
*conn
)
76 "HTTP/1.1 200 OK\r\nContent-Type: "
77 "text/plain\r\nConnection: close\r\n\r\n");
78 mg_printf(conn
, "Bye!\n");
84 class AHandler
: public CivetHandler
88 handleAll(const char *method
,
90 struct mg_connection
*conn
)
94 "HTTP/1.1 200 OK\r\nContent-Type: "
95 "text/html\r\nConnection: close\r\n\r\n");
96 mg_printf(conn
, "<html><body>");
97 mg_printf(conn
, "<h2>This is the A handler for \"%s\" !</h2>", method
);
98 if (CivetServer::getParam(conn
, "param", s
)) {
99 mg_printf(conn
, "<p>param set to %s</p>", s
.c_str());
101 mg_printf(conn
, "<p>param not set</p>");
103 mg_printf(conn
, "</body></html>\n");
109 handleGet(CivetServer
*server
, struct mg_connection
*conn
)
111 return handleAll("GET", server
, conn
);
114 handlePost(CivetServer
*server
, struct mg_connection
*conn
)
116 return handleAll("POST", server
, conn
);
120 class ABHandler
: public CivetHandler
124 handleGet(CivetServer
*server
, struct mg_connection
*conn
)
127 "HTTP/1.1 200 OK\r\nContent-Type: "
128 "text/html\r\nConnection: close\r\n\r\n");
129 mg_printf(conn
, "<html><body>");
130 mg_printf(conn
, "<h2>This is the AB handler!!!</h2>");
131 mg_printf(conn
, "</body></html>\n");
136 class FooHandler
: public CivetHandler
140 handleGet(CivetServer
*server
, struct mg_connection
*conn
)
142 /* Handler may access the request info using mg_get_request_info */
143 const struct mg_request_info
*req_info
= mg_get_request_info(conn
);
146 "HTTP/1.1 200 OK\r\nContent-Type: "
147 "text/html\r\nConnection: close\r\n\r\n");
149 mg_printf(conn
, "<html><body>\n");
150 mg_printf(conn
, "<h2>This is the Foo GET handler!!!</h2>\n");
152 "<p>The request was:<br><pre>%s %s HTTP/%s</pre></p>\n",
153 req_info
->request_method
,
154 req_info
->request_uri
,
155 req_info
->http_version
);
156 mg_printf(conn
, "</body></html>\n");
161 handlePost(CivetServer
*server
, struct mg_connection
*conn
)
163 /* Handler may access the request info using mg_get_request_info */
164 const struct mg_request_info
*req_info
= mg_get_request_info(conn
);
165 long long rlen
, wlen
;
167 long long tlen
= req_info
->content_length
;
171 "HTTP/1.1 200 OK\r\nContent-Type: "
172 "text/html\r\nConnection: close\r\n\r\n");
174 mg_printf(conn
, "<html><body>\n");
175 mg_printf(conn
, "<h2>This is the Foo POST handler!!!</h2>\n");
177 "<p>The request was:<br><pre>%s %s HTTP/%s</pre></p>\n",
178 req_info
->request_method
,
179 req_info
->request_uri
,
180 req_info
->http_version
);
181 mg_printf(conn
, "<p>Content Length: %li</p>\n", (long)tlen
);
182 mg_printf(conn
, "<pre>\n");
184 while (nlen
< tlen
) {
186 if (rlen
> sizeof(buf
)) {
189 rlen
= mg_read(conn
, buf
, (size_t)rlen
);
193 wlen
= mg_write(conn
, buf
, (size_t)rlen
);
200 mg_printf(conn
, "\n</pre>\n");
201 mg_printf(conn
, "</body></html>\n");
206 #define fopen_recursive fopen
209 handlePut(CivetServer
*server
, struct mg_connection
*conn
)
211 /* Handler may access the request info using mg_get_request_info */
212 const struct mg_request_info
*req_info
= mg_get_request_info(conn
);
213 long long rlen
, wlen
;
215 long long tlen
= req_info
->content_length
;
221 _snprintf(buf
, sizeof(buf
), "D:\\somewhere\\%s\\%s", req_info
->remote_user
, req_info
->local_uri
);
222 buf
[sizeof(buf
)-1] = 0;
223 if (strlen(buf
)>255) {
224 /* Windows will not work with path > 260 (MAX_PATH), unless we use
225 * the unicode API. However, this is just an example code: A real
226 * code will probably never store anything to D:\\somewhere and
227 * must be adapted to the specific needs anyhow. */
231 f
= fopen_recursive(buf
, "wb");
234 snprintf(buf
, sizeof(buf
), "~/somewhere/%s/%s", req_info
->remote_user
, req_info
->local_uri
);
235 buf
[sizeof(buf
)-1] = 0;
236 if (strlen(buf
)>1020) {
237 /* The string is too long and probably truncated. Make sure an
238 * UTF-8 string is never truncated between the UTF-8 code bytes.
239 * This example code must be adapted to the specific needs. */
243 f
= fopen_recursive(buf
, "w");
250 while (nlen
< tlen
) {
252 if (rlen
> sizeof(buf
)) {
255 rlen
= mg_read(conn
, buf
, (size_t)rlen
);
260 wlen
= fwrite(buf
, 1, (size_t)rlen
, f
);
272 "HTTP/1.1 409 Conflict\r\n"
273 "Content-Type: text/plain\r\n"
274 "Connection: close\r\n\r\n");
277 "HTTP/1.1 201 Created\r\n"
278 "Content-Type: text/plain\r\n"
279 "Connection: close\r\n\r\n");
286 class WsStartHandler
: public CivetHandler
290 handleGet(CivetServer
*server
, struct mg_connection
*conn
)
294 "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nConnection: "
297 mg_printf(conn
, "<!DOCTYPE html>\n");
298 mg_printf(conn
, "<html>\n<head>\n");
299 mg_printf(conn
, "<meta charset=\"UTF-8\">\n");
300 mg_printf(conn
, "<title>Embedded websocket example</title>\n");
303 /* mg_printf(conn, "<script type=\"text/javascript\"><![CDATA[\n"); ...
305 mg_printf(conn
, "<script>\n");
309 "function load() {\n"
310 " var wsproto = (location.protocol === 'https:') ? 'wss:' : 'ws:';\n"
311 " connection = new WebSocket(wsproto + '//' + window.location.host + "
313 " websock_text_field = "
314 "document.getElementById('websock_text_field');\n"
315 " connection.onmessage = function (e) {\n"
316 " websock_text_field.innerHTML=e.data;\n"
318 " connection.send(i);\n"
320 " connection.onerror = function (error) {\n"
321 " alert('WebSocket error');\n"
322 " connection.close();\n"
325 /* mg_printf(conn, "]]></script>\n"); ... xhtml style */
326 mg_printf(conn
, "</script>\n");
327 mg_printf(conn
, "</head>\n<body onload=\"load()\">\n");
330 "<div id='websock_text_field'>No websocket connection yet</div>\n");
332 mg_printf(conn
, "</head>\n<body>\n");
333 mg_printf(conn
, "Example not compiled with USE_WEBSOCKET\n");
335 mg_printf(conn
, "</body>\n</html>\n");
343 class WebSocketHandler
: public CivetWebSocketHandler
{
345 virtual bool handleConnection(CivetServer
*server
,
346 const struct mg_connection
*conn
) {
347 printf("WS connected\n");
351 virtual void handleReadyState(CivetServer
*server
,
352 struct mg_connection
*conn
) {
353 printf("WS ready\n");
355 const char *text
= "Hello from the websocket ready handler";
356 mg_websocket_write(conn
, MG_WEBSOCKET_OPCODE_TEXT
, text
, strlen(text
));
359 virtual bool handleData(CivetServer
*server
,
360 struct mg_connection
*conn
,
364 printf("WS got %lu bytes: ", (long unsigned)data_len
);
365 fwrite(data
, 1, data_len
, stdout
);
368 mg_websocket_write(conn
, MG_WEBSOCKET_OPCODE_TEXT
, data
, data_len
);
372 virtual void handleClose(CivetServer
*server
,
373 const struct mg_connection
*conn
) {
374 printf("WS closed\n");
381 main(int argc
, char *argv
[])
385 const char *options
[] = {
386 "document_root", DOCUMENT_ROOT
, "listening_ports", PORT
, 0};
388 std::vector
<std::string
> cpp_options
;
389 for (int i
=0; i
<(sizeof(options
)/sizeof(options
[0])-1); i
++) {
390 cpp_options
.push_back(options
[i
]);
393 // CivetServer server(options); // <-- C style start
394 CivetServer
server(cpp_options
); // <-- C++ style start
397 server
.addHandler(EXAMPLE_URI
, h_ex
);
400 server
.addHandler(EXIT_URI
, h_exit
);
403 server
.addHandler("/a", h_a
);
406 server
.addHandler("/a/b", h_ab
);
409 server
.addHandler("/ws", h_ws
);
412 /* This handler will handle "everything else", including
413 * requests to files. If this handler is installed,
414 * NO_FILES should be set. */
416 server
.addHandler("", h_foo
);
418 printf("See a page from the \"all\" handler at http://localhost:%s/\n", PORT
);
421 server
.addHandler("**.foo", h_foo
);
422 printf("Browse files at http://localhost:%s/\n", PORT
);
426 WebSocketHandler h_websocket
;
427 server
.addWebSocketHandler("/websocket", h_websocket
);
428 printf("Run websocket example at http://localhost:%s/ws\n", PORT
);
431 printf("Run example at http://localhost:%s%s\n", PORT
, EXAMPLE_URI
);
432 printf("Exit at http://localhost:%s%s\n", PORT
, EXIT_URI
);