server.cpp
Go to the documentation of this file.
00001 #include "server.h"
00002 
00003 #include <chrono>
00004 #include <condition_variable>
00005 #include <cstdio>
00006 #include <mutex>
00007 #include <sstream>
00008 #include <thread>
00009 
00010 #include "mongoose.h"
00011 
00012 #include <time.h>
00013 
00014 #define SERVER_PORT "8080"
00015 
00016 
00017 std::mutex shutdown_mutex;
00018 std::mutex server_mutex;
00019 std::condition_variable server_cv;
00020 
00021 static const std::string base64_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
00022                                         "abcdefghijklmnopqrstuvwxyz"
00023                                         "0123456789+/";
00024 
00025 static inline bool is_base64(unsigned char c);
00026 std::string base64_decode(std::string const& encoded_string);
00027 static int lowercase(const char *s);
00028 static int mg_strncasecmp(const char *s1, const char *s2, size_t len);
00029 
00030 static int options(struct mg_connection* conn) {
00031     if (std::string{conn->request_method} == std::string{"OPTIONS"}) {
00032         auto response = std::string{""};
00033         mg_send_status(conn, 200);
00034         mg_send_header(conn, "content-type", "text/html");
00035         mg_send_header(conn, "Access-Control-Allow-Origin", "*");
00036         mg_send_header(conn, "Access-Control-Allow-Credentials", "true");
00037         mg_send_header(conn, "Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, PATCH, OPTIONS");
00038         mg_send_header(conn, "Access-Control-Max-Age", "3600");
00039         mg_send_data(conn, response.data(), response.length());
00040     } else {
00041         auto response = std::string{"Method unallowed"};
00042         mg_send_status(conn, 405);
00043         mg_send_header(conn, "content-type", "text/html");
00044         mg_send_data(conn, response.data(), response.length());
00045     }
00046     return MG_TRUE;
00047 }
00048 
00049 static int hello(struct mg_connection* conn) {
00050     if (std::string{conn->request_method} == std::string{"OPTIONS"}) {
00051         auto response = std::string{""};
00052         mg_send_status(conn, 200);
00053         mg_send_header(conn, "content-type", "text/html");
00054         mg_send_header(conn, "Access-Control-Allow-Origin", "*");
00055         mg_send_header(conn, "Access-Control-Allow-Credentials", "true");
00056         mg_send_header(conn, "Access-Control-Allow-Methods", "GET, OPTIONS");
00057         mg_send_header(conn, "Access-Control-Max-Age", "3600");
00058         mg_send_data(conn, response.data(), response.length());
00059     } else {
00060         auto response = std::string{"Hello world!"};
00061         mg_send_status(conn, 200);
00062         mg_send_header(conn, "content-type", "text/html");
00063         mg_send_data(conn, response.data(), response.length());
00064     }
00065     return MG_TRUE;
00066 }
00067 
00068 static int timeout(struct mg_connection* conn) {
00069     std::this_thread::sleep_for(std::chrono::milliseconds(10));
00070     auto response = std::string{"Hello world!"};
00071     mg_send_status(conn, 200);
00072     mg_send_header(conn, "content-type", "text/html");
00073     mg_send_data(conn, response.data(), response.length());
00074     return MG_TRUE;
00075 }
00076 
00077 static int lowSpeed(struct mg_connection* conn) {
00078     auto response = std::string{"Hello world!"};
00079     mg_send_status(conn, 200);
00080     mg_send_header(conn, "content-type", "text/html");
00081     std::this_thread::sleep_for(std::chrono::seconds(2));
00082     mg_send_data(conn, response.data(), response.length());
00083     return MG_TRUE;
00084 }
00085 
00086 static int lowSpeedBytes(struct mg_connection* conn) {
00087     auto response = std::string{"a"};
00088     mg_send_status(conn, 200);
00089     mg_send_header(conn, "content-type", "text/html");
00090     for (auto i = 0; i < 20; ++i) {
00091         std::this_thread::sleep_for(std::chrono::milliseconds(100));
00092         mg_send_data(conn, response.data(), response.length());
00093     }
00094     return MG_TRUE;
00095 }
00096 
00097 static int basicCookies(struct mg_connection* conn) {
00098     auto response = std::string{"Hello world!"};
00099     mg_send_status(conn, 200);
00100     mg_send_header(conn, "content-type", "text/html");
00101     time_t t = time(NULL) + 5;  // Valid for 1 hour
00102     char expire[100], expire_epoch[100];
00103     snprintf(expire_epoch, sizeof(expire_epoch), "%lu", (unsigned long) t);
00104     strftime(expire, sizeof(expire), "%a, %d %b %Y %H:%M:%S GMT", gmtime(&t));
00105     std::string cookie{"cookie=chocolate; expires=\"" + std::string{expire} + "\"; http-only;"};
00106     std::string cookie2{"icecream=vanilla; expires=\"" + std::string{expire} + "\"; http-only;"};
00107     mg_send_header(conn, "Set-Cookie", cookie.data());
00108     mg_send_header(conn, "Set-Cookie", cookie2.data());
00109     mg_send_data(conn, response.data(), response.length());
00110     return MG_TRUE;
00111 }
00112 
00113 static int v1Cookies(struct mg_connection* conn) {
00114     auto response = std::string{"Hello world!"};
00115     mg_send_status(conn, 200);
00116     mg_send_header(conn, "content-type", "text/html");
00117     time_t t = time(NULL) + 5; // Valid for 1 hour
00118     char expire[100], expire_epoch[100];
00119     snprintf(expire_epoch, sizeof(expire_epoch), "%lu", (unsigned long) t);
00120     strftime(expire, sizeof(expire), "%a, %d %b %Y %H:%M:%S GMT", gmtime(&t));
00121     std::string v1cookie{"cookie=\"value with spaces (v1 cookie)\"; expires=\"" +
00122                          std::string{expire} + "\"; http-only;"};
00123     mg_send_header(conn, "Set-Cookie", v1cookie.data());
00124     mg_send_data(conn, response.data(), response.length());
00125     return MG_TRUE;
00126 }
00127 
00128 static int checkBasicCookies(struct mg_connection* conn) {
00129     const char* request_cookies;
00130     if ((request_cookies = mg_get_header(conn, "Cookie")) == NULL)
00131         return MG_FALSE;
00132     std::string cookie_str{request_cookies};
00133 
00134     if (cookie_str.find("cookie=chocolate;") == cookie_str.npos ||
00135         cookie_str.find("icecream=vanilla;") == cookie_str.npos) {
00136         return MG_FALSE;
00137     }
00138 
00139     auto response = std::string{"Hello world!"};
00140     mg_send_status(conn, 200);
00141     mg_send_header(conn, "content-type", "text/html");
00142     mg_send_data(conn, response.data(), response.length());
00143     return MG_TRUE;
00144 }
00145 
00146 static int checkV1Cookies(struct mg_connection* conn) {
00147     const char* request_cookies;
00148     if ((request_cookies = mg_get_header(conn, "Cookie")) == NULL)
00149         return MG_FALSE;
00150     std::string cookie_str{request_cookies};
00151 
00152     if (cookie_str.find("cookie=\"value with spaces (v1 cookie)\";") == cookie_str.npos) {
00153         return MG_FALSE;
00154     }
00155 
00156     auto response = std::string{"Hello world!"};
00157     mg_send_status(conn, 200);
00158     mg_send_header(conn, "content-type", "text/html");
00159     mg_send_data(conn, response.data(), response.length());
00160     return MG_TRUE;
00161 }
00162 
00163 static int basicAuth(struct mg_connection* conn) {
00164     auto response = std::string{"Hello world!"};
00165     const char* requested_auth;
00166     auto auth = std::string{"Basic"};
00167     if ((requested_auth = mg_get_header(conn, "Authorization")) == NULL ||
00168         mg_strncasecmp(requested_auth, auth.data(), auth.length()) != 0) {
00169         return MG_FALSE;
00170     }
00171     auto auth_string = std::string{requested_auth};
00172     auto basic_token = auth_string.find(' ') + 1;
00173     auth_string = auth_string.substr(basic_token, auth_string.length() - basic_token);
00174     auth_string = base64_decode(auth_string);
00175     auto colon = auth_string.find(':');
00176     auto username = auth_string.substr(0, colon);
00177     auto password = auth_string.substr(colon + 1, auth_string.length() - colon - 1);
00178     if (username == "user" && password == "password") {
00179         return MG_TRUE;
00180     }
00181 
00182     return MG_FALSE;
00183 }
00184 
00185 static int digestAuth(struct mg_connection* conn) {
00186     int result = MG_FALSE;
00187     {
00188         FILE *fp;
00189         if ((fp = fopen("digest.txt", "w")) != NULL) {
00190             fprintf(fp, "user:mydomain.com:0cf722ef3dd136b48da83758c5d855f8\n");
00191             fclose(fp);
00192         }
00193     }
00194 
00195     {
00196         FILE *fp;
00197         if ((fp = fopen("digest.txt", "r")) != NULL) {
00198             result = mg_authorize_digest(conn, fp);
00199             fclose(fp);
00200         }
00201     }
00202 
00203     return result;
00204 }
00205 
00206 static int basicJson(struct mg_connection* conn) {
00207     auto response = std::string{"[\n"
00208                                 "  {\n"
00209                                 "    \"first_key\": \"first_value\",\n"
00210                                 "    \"second_key\": \"second_value\"\n"
00211                                 "  }\n"
00212                                 "]"};
00213     mg_send_status(conn, 200);
00214     auto raw_header = mg_get_header(conn, "Content-type");
00215     std::string header;
00216     if (raw_header != NULL) {
00217         header = raw_header;
00218     }
00219     if (!header.empty() && header == "application/json") {
00220         mg_send_header(conn, "content-type", "application/json");
00221     } else {
00222         mg_send_header(conn, "content-type", "application/octet-stream");
00223     }
00224     mg_send_data(conn, response.data(), response.length());
00225     return MG_TRUE;
00226 }
00227 
00228 static int headerReflect(struct mg_connection* conn) {
00229     auto response = std::string{"Header reflect "} +
00230                     std::string{conn->request_method};
00231     mg_send_status(conn, 200);
00232     mg_send_header(conn, "content-type", "text/html");
00233     auto num_headers = conn->num_headers;
00234     auto headers = conn->http_headers;
00235     for (int i = 0; i < num_headers; ++i) {
00236         auto name = headers[i].name;
00237         if (std::string{"User-Agent"} != name &&
00238                 std::string{"Host"} != name &&
00239                 std::string{"Accept"} != name) {
00240             mg_send_header(conn, name, headers[i].value);
00241         }
00242     }
00243     mg_send_data(conn, response.data(), response.length());
00244     return MG_TRUE;
00245 }
00246 
00247 static int temporaryRedirect(struct mg_connection* conn) {
00248     auto response = std::string{"Found"};
00249     mg_send_status(conn, 302);
00250     mg_send_header(conn, "Location", "hello.html");
00251     mg_send_data(conn, response.data(), response.length());
00252     return MG_TRUE;
00253 }
00254 
00255 static int permanentRedirect(struct mg_connection* conn) {
00256     auto response = std::string{"Moved Permanently"};
00257     mg_send_status(conn, 301);
00258     mg_send_header(conn, "Location", "hello.html");
00259     mg_send_data(conn, response.data(), response.length());
00260     return MG_TRUE;
00261 }
00262 
00263 static int twoRedirects(struct mg_connection* conn) {
00264     auto response = std::string{"Moved Permanently"};
00265     mg_send_status(conn, 301);
00266     mg_send_header(conn, "Location", "permanent_redirect.html");
00267     mg_send_data(conn, response.data(), response.length());
00268     return MG_TRUE;
00269 }
00270 
00271 static int urlPost(struct mg_connection* conn) {
00272     mg_send_status(conn, 201);
00273     mg_send_header(conn, "content-type", "application/json");
00274     char x[100];
00275     char y[100];
00276     mg_get_var(conn, "x", x, sizeof(x));
00277     mg_get_var(conn, "y", y, sizeof(y));
00278     auto x_string = std::string{x};
00279     auto y_string = std::string{y};
00280     if (y_string.empty()) {
00281         auto response = std::string{"{\n"
00282                                     "  \"x\": " + x_string + "\n"
00283                                     "}"};
00284         mg_send_data(conn, response.data(), response.length());
00285     } else {
00286         std::ostringstream s;
00287         s << (atoi(x) + atoi(y));
00288         auto response = std::string{"{\n"
00289                                     "  \"x\": " + x_string + ",\n"
00290                                     "  \"y\": " + y_string + ",\n"
00291                                     "  \"sum\": " + s.str() + "\n"
00292                                     "}"};
00293         mg_send_data(conn, response.data(), response.length());
00294     }
00295     return MG_TRUE;
00296 }
00297 
00298 static int jsonPost(struct mg_connection* conn) {
00299     auto num_headers = conn->num_headers;
00300     auto headers = conn->http_headers;
00301     auto has_json_header = false;
00302     for (int i = 0; i < num_headers; ++i) {
00303         if (std::string{"Content-Type"} == headers[i].name &&
00304                 std::string{"application/json"} == headers[i].value) {
00305             has_json_header = true;
00306         }
00307     }
00308     if (!has_json_header) {
00309         auto response = std::string{"Unsupported Media Type"};
00310         mg_send_status(conn, 415);
00311         mg_send_header(conn, "content-type", "text/html");
00312         mg_send_data(conn, response.data(), response.length());
00313         return MG_TRUE;
00314     }
00315     mg_send_status(conn, 201);
00316     mg_send_header(conn, "content-type", "application/json");
00317     auto response = std::string{conn->content, conn->content_len};
00318     mg_send_data(conn, response.data(), response.length());
00319     return MG_TRUE;
00320 }
00321 
00322 static int formPost(struct mg_connection* conn) {
00323     auto content = conn->content;
00324     auto content_len = conn->content_len;
00325 
00326     std::map<std::string, std::string> forms;
00327 
00328     while (true) {
00329         char* data = new char[10000];
00330         int data_len;
00331         char name[100];
00332         char filename[100];
00333         content += mg_parse_multipart(content, content_len,
00334                                       name, sizeof(name),
00335                                       filename, sizeof(filename),
00336                                       (const char**) &data, &data_len);
00337         if (strlen(data) == 0) {
00338             delete[] data;
00339             break;
00340         }
00341 
00342         forms[name] = std::string{data, (unsigned long) data_len};
00343     }
00344 
00345     mg_send_status(conn, 201);
00346     mg_send_header(conn, "content-type", "application/json");
00347     if (forms.find("y") == forms.end()) {
00348         auto response = std::string{"{\n"
00349                                     "  \"x\": " + forms["x"] + "\n"
00350                                     "}"};
00351         mg_send_data(conn, response.data(), response.length());
00352     } else {
00353         std::ostringstream s;
00354         s << (atoi(forms["x"].data()) + atoi(forms["y"].data()));
00355         auto response = std::string{"{\n"
00356                                     "  \"x\": " + forms["x"] + ",\n"
00357                                     "  \"y\": " + forms["y"] + ",\n"
00358                                     "  \"sum\": " + s.str() + "\n"
00359                                     "}"};
00360         mg_send_data(conn, response.data(), response.length());
00361     }
00362     return MG_TRUE;
00363 }
00364 
00365 static int deleteRequest(struct mg_connection* conn) {
00366     auto num_headers = conn->num_headers;
00367     auto headers = conn->http_headers;
00368     auto has_json_header = false;
00369     for (int i = 0; i < num_headers; ++i) {
00370         if (std::string{"Content-Type"} == headers[i].name &&
00371                 std::string{"application/json"} == headers[i].value) {
00372             has_json_header = true;
00373         }
00374     }
00375     if (std::string{conn->request_method} == std::string{"DELETE"}) {
00376       if (!has_json_header) {
00377           auto response = std::string{"Delete success"};
00378           mg_send_status(conn, 200);
00379           mg_send_header(conn, "content-type", "text/html");
00380           mg_send_data(conn, response.data(), response.length());
00381       } else {
00382           auto response = std::string{conn->content, conn->content_len};
00383           mg_send_status(conn, 200);
00384           mg_send_header(conn, "content-type", "application/json");
00385           mg_send_data(conn, response.data(), response.length());
00386       }
00387     } else {
00388         auto response = std::string{"Method unallowed"};
00389         mg_send_status(conn, 405);
00390         mg_send_header(conn, "content-type", "text/html");
00391         mg_send_data(conn, response.data(), response.length());
00392     }
00393     return MG_TRUE;
00394 }
00395 
00396 static int deleteUnallowedRequest(struct mg_connection* conn) {
00397     if (std::string{conn->request_method} == std::string{"DELETE"}) {
00398         auto response = std::string{"Method unallowed"};
00399         mg_send_status(conn, 405);
00400         mg_send_header(conn, "content-type", "text/html");
00401         mg_send_data(conn, response.data(), response.length());
00402     } else {
00403         auto response = std::string{"Delete success"};
00404         mg_send_status(conn, 200);
00405         mg_send_header(conn, "content-type", "text/html");
00406         mg_send_data(conn, response.data(), response.length());
00407     }
00408     return MG_TRUE;
00409 }
00410 
00411 static int patch(struct mg_connection* conn) {
00412     if (std::string{conn->request_method} == std::string{"PATCH"}) {
00413         mg_send_status(conn, 200);
00414         mg_send_header(conn, "content-type", "application/json");
00415         char x[100];
00416         char y[100];
00417         mg_get_var(conn, "x", x, sizeof(x));
00418         mg_get_var(conn, "y", y, sizeof(y));
00419         auto x_string = std::string{x};
00420         auto y_string = std::string{y};
00421         if (y_string.empty()) {
00422             auto response = std::string{"{\n"
00423                                         "  \"x\": " + x_string + "\n"
00424                                         "}"};
00425             mg_send_data(conn, response.data(), response.length());
00426         } else {
00427             std::ostringstream s;
00428             s << (atoi(x) + atoi(y));
00429             auto response = std::string{"{\n"
00430                                         "  \"x\": " + x_string + ",\n"
00431                                         "  \"y\": " + y_string + ",\n"
00432                                         "  \"sum\": " + s.str() + "\n"
00433                                         "}"};
00434             mg_send_data(conn, response.data(), response.length());
00435         }
00436     } else {
00437         auto response = std::string{"Method unallowed"};
00438         mg_send_status(conn, 405);
00439         mg_send_header(conn, "content-type", "text/html");
00440         mg_send_data(conn, response.data(), response.length());
00441     }
00442     return MG_TRUE;
00443 }
00444 
00445 static int patchUnallowed(struct mg_connection* conn) {
00446     if (std::string{conn->request_method} == std::string{"PATCH"}) {
00447         auto response = std::string{"Method unallowed"};
00448         mg_send_status(conn, 405);
00449         mg_send_header(conn, "content-type", "text/html");
00450         mg_send_data(conn, response.data(), response.length());
00451     } else {
00452         auto response = std::string{"Patch success"};
00453         mg_send_status(conn, 200);
00454         mg_send_header(conn, "content-type", "text/html");
00455         mg_send_data(conn, response.data(), response.length());
00456     }
00457     return MG_TRUE;
00458 }
00459 
00460 static int put(struct mg_connection* conn) {
00461     if (std::string{conn->request_method} == std::string{"PUT"}) {
00462         mg_send_status(conn, 200);
00463         mg_send_header(conn, "content-type", "application/json");
00464         char x[100];
00465         char y[100];
00466         mg_get_var(conn, "x", x, sizeof(x));
00467         mg_get_var(conn, "y", y, sizeof(y));
00468         auto x_string = std::string{x};
00469         auto y_string = std::string{y};
00470         if (y_string.empty()) {
00471             auto response = std::string{"{\n"
00472                                         "  \"x\": " + x_string + "\n"
00473                                         "}"};
00474             mg_send_data(conn, response.data(), response.length());
00475         } else {
00476             std::ostringstream s;
00477             s << (atoi(x) + atoi(y));
00478             auto response = std::string{"{\n"
00479                                         "  \"x\": " + x_string + ",\n"
00480                                         "  \"y\": " + y_string + ",\n"
00481                                         "  \"sum\": " + s.str() + "\n"
00482                                         "}"};
00483             mg_send_data(conn, response.data(), response.length());
00484         }
00485     } else {
00486         auto response = std::string{"Method unallowed"};
00487         mg_send_status(conn, 405);
00488         mg_send_header(conn, "content-type", "text/html");
00489         mg_send_data(conn, response.data(), response.length());
00490     }
00491     return MG_TRUE;
00492 }
00493 
00494 static int putUnallowed(struct mg_connection* conn) {
00495     if (std::string{conn->request_method} == std::string{"PUT"}) {
00496         auto response = std::string{"Method unallowed"};
00497         mg_send_status(conn, 405);
00498         mg_send_header(conn, "content-type", "text/html");
00499         mg_send_data(conn, response.data(), response.length());
00500     } else {
00501         auto response = std::string{"Put success"};
00502         mg_send_status(conn, 200);
00503         mg_send_header(conn, "content-type", "text/html");
00504         mg_send_data(conn, response.data(), response.length());
00505     }
00506     return MG_TRUE;
00507 }
00508 
00509 static int evHandler(struct mg_connection* conn, enum mg_event ev) {
00510     switch (ev) {
00511         case MG_AUTH:
00512             if (Url{conn->uri} == "/basic_auth.html") {
00513                 return basicAuth(conn);
00514             } else if (Url{conn->uri} == "/digest_auth.html") {
00515                 return digestAuth(conn);
00516             }
00517             return MG_TRUE;
00518         case MG_REQUEST:
00519             if (Url{conn->uri} == "/") {
00520                 return options(conn);
00521             } else if (Url{conn->uri} == "/hello.html") {
00522                 return hello(conn);
00523             } else if (Url{conn->uri} == "/timeout.html") {
00524                 return timeout(conn);
00525             } else if (Url{conn->uri} == "/low_speed.html") {
00526                 return lowSpeed(conn);                          
00527             } else if (Url{conn->uri} == "/low_speed_bytes.html") {
00528                 return lowSpeedBytes(conn);                             
00529             } else if (Url{conn->uri} == "/basic_cookies.html") {
00530                 return basicCookies(conn);
00531             } else if (Url{conn->uri} == "/check_cookies.html") {
00532                 return checkBasicCookies(conn);
00533             } else if (Url{conn->uri} == "/v1_cookies.html") {
00534                 return v1Cookies(conn);
00535             } else if (Url{conn->uri} == "/check_v1_cookies.html") {
00536                 return checkV1Cookies(conn);
00537             } else if (Url{conn->uri} == "/basic_auth.html") {
00538                 return headerReflect(conn);
00539             } else if (Url{conn->uri} == "/digest_auth.html") {
00540                 return headerReflect(conn);
00541             } else if (Url{conn->uri} == "/basic.json") {
00542                 return basicJson(conn);
00543             } else if (Url{conn->uri} == "/header_reflect.html") {
00544                 return headerReflect(conn);
00545             } else if (Url{conn->uri} == "/temporary_redirect.html") {
00546                 return temporaryRedirect(conn);
00547             } else if (Url{conn->uri} == "/permanent_redirect.html") {
00548                 return permanentRedirect(conn);
00549             } else if (Url{conn->uri} == "/two_redirects.html") {
00550                 return twoRedirects(conn);
00551             } else if (Url{conn->uri} == "/url_post.html") {
00552                 return urlPost(conn);
00553             } else if (Url{conn->uri} == "/json_post.html") {
00554                 return jsonPost(conn);
00555             } else if (Url{conn->uri} == "/form_post.html") {
00556                 return formPost(conn);
00557             } else if (Url{conn->uri} == "/delete.html") {
00558                 return deleteRequest(conn);
00559             } else if (Url{conn->uri} == "/delete_unallowed.html") {
00560                 return deleteUnallowedRequest(conn);
00561             } else if (Url{conn->uri} == "/put.html") {
00562                 return put(conn);
00563             } else if (Url{conn->uri} == "/put_unallowed.html") {
00564                 return putUnallowed(conn);
00565             } else if (Url{conn->uri} == "/patch.html") {
00566                 return patch(conn);
00567             } else if (Url{conn->uri} == "/patch_unallowed.html") {
00568                 return patchUnallowed(conn);
00569             }
00570             return MG_FALSE;
00571         default:
00572             return MG_FALSE;
00573     }
00574 }
00575 
00576 void runServer(struct mg_server* server) {
00577     {
00578         std::lock_guard<std::mutex> server_lock(server_mutex);
00579         mg_set_option(server, "listening_port", SERVER_PORT);
00580         server_cv.notify_one();
00581     }
00582 
00583     do {
00584         mg_poll_server(server, 1000);
00585     } while (!shutdown_mutex.try_lock());
00586 
00587     std::lock_guard<std::mutex> server_lock(server_mutex);
00588     mg_destroy_server(&server);
00589     server_cv.notify_one();
00590 }
00591 
00592 void Server::SetUp() {
00593     shutdown_mutex.lock();
00594     struct mg_server* server;
00595     server = mg_create_server(NULL, evHandler);
00596     std::unique_lock<std::mutex> server_lock(server_mutex);
00597     std::thread(runServer, server).detach();
00598     server_cv.wait(server_lock);
00599 }
00600 
00601 void Server::TearDown() {
00602     std::unique_lock<std::mutex> server_lock(server_mutex);
00603     shutdown_mutex.unlock();
00604     server_cv.wait(server_lock);
00605 }
00606 
00607 Url Server::GetBaseUrl() {
00608     return Url{"http://127.0.0.1:"}.append(SERVER_PORT);
00609 }
00610 
00611 Url Server::GetBaseUrlSSL() {
00612     return Url{"https://127.0.0.1:"}.append(SERVER_PORT);
00613 }
00614 
00615 static inline bool is_base64(unsigned char c) {
00616     return (isalnum(c) || (c == '+') || (c == '/'));
00617 }
00618 
00619 std::string base64_decode(std::string const& encoded_string) {
00620     int in_len = encoded_string.size();
00621     int i = 0;
00622     int j = 0;
00623     int in_ = 0;
00624     unsigned char char_array_4[4], char_array_3[3];
00625     std::string ret;
00626 
00627     while (in_len-- && ( encoded_string[in_] != '=') && is_base64(encoded_string[in_])) {
00628         char_array_4[i++] = encoded_string[in_]; in_++;
00629         if (i ==4) {
00630             for (i = 0; i <4; i++) {
00631                 char_array_4[i] = base64_chars.find(char_array_4[i]);
00632             }
00633 
00634             char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
00635             char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
00636             char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
00637 
00638             for (i = 0; (i < 3); i++) {
00639                 ret += char_array_3[i];
00640             }
00641 
00642             i = 0;
00643         }
00644     }
00645 
00646     if (i) {
00647         for (j = i; j <4; j++) {
00648             char_array_4[j] = 0;
00649         }
00650 
00651         for (j = 0; j <4; j++) {
00652             char_array_4[j] = base64_chars.find(char_array_4[j]);
00653         }
00654 
00655         char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
00656         char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
00657         char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
00658 
00659         for (j = 0; (j < i - 1); j++) {
00660             ret += char_array_3[j];
00661         }
00662     }
00663 
00664     return ret;
00665 }
00666 
00667 static int lowercase(const char *s) {
00668     return tolower(* (const unsigned char *) s);
00669 }
00670 
00671 static int mg_strncasecmp(const char *s1, const char *s2, size_t len) {
00672     int diff = 0;
00673 
00674     if (len > 0) {
00675         do {
00676             diff = lowercase(s1++) - lowercase(s2++);
00677         } while (diff == 0 && s1[-1] != '\0' && --len > 0);
00678     }
00679 
00680     return diff;
00681 }
00682 


rc_visard_driver
Author(s): Heiko Hirschmueller , Christian Emmerich , Felix Ruess
autogenerated on Thu Jun 6 2019 20:43:06