Skip to content

Instantly share code, notes, and snippets.

@sergnechaev
Created October 29, 2018 12:12
Show Gist options
  • Save sergnechaev/7193dfcfa8ab7dc7d292a88eb19e84f6 to your computer and use it in GitHub Desktop.
Save sergnechaev/7193dfcfa8ab7dc7d292a88eb19e84f6 to your computer and use it in GitHub Desktop.
libmicrohttpd
// #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