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;
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;
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