-
-
Save sergnechaev/7193dfcfa8ab7dc7d292a88eb19e84f6 to your computer and use it in GitHub Desktop.
libmicrohttpd
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// #include <sys/socket.h> | |
#include <Winsock2.h> | |
#include <sys/types.h> | |
#include <sys/stat.h> | |
#include <fcntl.h> | |
#include <iostream> | |
#include <cstdio> | |
#include <algorithm> | |
#include "sqlite3.h" | |
#include <microhttpd.h> | |
#include "tinyfiledialogs.h" | |
#include "file_utils.h" | |
#include "db_utils.h" | |
#include "utils.h" | |
#include "html_template_engine.h" | |
#define PAGE_404 "Page not found" | |
int print_out_key(void *cls, enum MHD_ValueKind kind, const char *key, const char *value) { | |
printf("%s: %s\n", key, value); | |
return MHD_YES; | |
} | |
void set_headers(MHD_Response *response, const std::string& content_type) { | |
MHD_add_response_header(response, "Content-Type", content_type.c_str()); | |
MHD_add_response_header(response, "Cache-Control", "no-cache, no-store, must-revalidate"); | |
MHD_add_response_header(response, "Pragma", "no-cache"); | |
MHD_add_response_header(response, "Expires", "0"); | |
} | |
std::string add_folder() { | |
auto folder = tinyfd_selectFolderDialog("title", // "" | |
"c:/tmp"); // "" | |
// returns NULL on cancel | |
if (folder) { | |
std::cout << "Selected folder: " << folder << std::endl; | |
std::string str(folder); | |
return str; | |
} | |
return "operation cancelled"; | |
} | |
std::string action(std::string& action) { | |
std::cout << "Action: " << action << std::endl; | |
if ("action/addFolder" == action) { | |
return add_folder(); | |
} | |
return "OK"; | |
} | |
static int serve(void* not_used, struct MHD_Connection* connection, const char* url, const char* method, const char* version, const char* upload_data, size_t* upload_data_size, void** ptr) { | |
//printf("New %s request for %s using version %s\n", method, url, version); | |
//MHD_get_connection_values(connection, MHD_HEADER_KIND, &print_out_key, NULL); | |
static auto dummy = 0; | |
// unexpected method | |
if (0 != strcmp(method, "GET")) { | |
return MHD_NO; | |
} | |
// The first time only the headers are valid, do not respond in the first round... | |
if (&dummy != *ptr) { | |
*ptr = &dummy; | |
return MHD_YES; | |
} | |
// upload data in a GET!? | |
if (0 != *upload_data_size) { | |
return MHD_NO; | |
} | |
// remove forward slash | |
if (strlen(url) > 0) { | |
url++; | |
} | |
std::string request_url(url); | |
if (request_url.length() == 0 || request_url == "/") { | |
request_url = "index.html"; | |
} | |
std::cout << "Request url:" << request_url << std::endl; | |
unsigned char *buffer = nullptr; | |
MHD_Response *response = nullptr; | |
// clear context pointer | |
*ptr = nullptr; | |
// Read resource | |
auto ret = 0; | |
auto fd = 0; | |
struct stat sbuf; | |
std::string file_name = "site/" + request_url; | |
std::cout << "File: " << file_name << std::endl; | |
// re-route backend actions | |
std::string action_url = "action/"; | |
if (std::equal(action_url.begin(), action_url.end(), request_url.begin())) { | |
std::cout << "Got action: " << request_url << std::endl; | |
auto response_message = action(request_url); | |
response = MHD_create_response_from_buffer(response_message.size(), (void*) response_message.c_str(), MHD_RESPMEM_MUST_COPY); | |
set_headers(response, "text/plain"); | |
if (response) { | |
ret = MHD_queue_response(connection, MHD_HTTP_OK, response); | |
MHD_destroy_response(response); | |
return MHD_YES; | |
} | |
} | |
auto file_name_extension = pn::file::get_extension(file_name); | |
if (file_name_extension == "html") { | |
std::string html = pn::html::process(file_name); | |
response = MHD_create_response_from_buffer(html.size(), (void *) html.c_str(), MHD_RESPMEM_MUST_COPY); | |
} else { | |
if ((-1 == (fd = open(file_name.c_str(), _O_RDONLY))) || (0 != fstat(fd, &sbuf))) { | |
/* error accessing file */ | |
if (fd != -1) { | |
close(fd); | |
} | |
const char *errorstr = "<html><body>An internal server error has occured!\ | |
</body></html>"; | |
response = MHD_create_response_from_buffer(strlen(errorstr), (void *) errorstr, MHD_RESPMEM_PERSISTENT); | |
MHD_queue_response(connection, MHD_HTTP_INTERNAL_SERVER_ERROR, response); | |
MHD_destroy_response(response); | |
return MHD_YES; | |
} | |
response = MHD_create_response_from_fd_at_offset64(sbuf.st_size, fd, 0); | |
} | |
auto content_type = pn::utils::get_content_type(request_url); | |
std::cout << "content_type: " << content_type << std::endl; | |
set_headers(response, content_type); | |
ret = MHD_queue_response(connection, MHD_HTTP_OK, response); | |
MHD_destroy_response(response); | |
return ret; | |
} | |
int main(int argc, char ** argv) { | |
if (argc != 2) { | |
printf("%s PORT\n", argv[0]); | |
return 1; | |
} | |
auto exists = pn::db::does_db_exist(); | |
if (!exists) { | |
std::cout << "Fresh start\n"; | |
pn::db::create_db(pn::db::get_app_db_file()); | |
} | |
auto d = MHD_start_daemon(MHD_USE_THREAD_PER_CONNECTION, atoi(argv[1]), nullptr, nullptr, &serve, nullptr, MHD_FLAG::MHD_NO_FLAG); | |
if (d == nullptr) | |
return EXIT_FAILURE; | |
(void) getchar(); | |
MHD_stop_daemon(d); | |
return EXIT_SUCCESS; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment