http server options, remove old

This commit is contained in:
2024-11-15 14:18:49 +03:00
parent cdde340efe
commit ee137b2820
5 changed files with 70 additions and 52 deletions

View File

@@ -1,8 +1,7 @@
#include "microhttpd_server_p.h"
#include "pidir.h"
#include "pifile.h"
#include "piliterals_string.h"
#include "piliterals_time.h"
#include <microhttpd.h>
@@ -29,29 +28,21 @@ bool MicrohttpdServerConnection::ready() {
done = true;
MicrohttpdServer::Reply rep;
if (method == MicrohttpdServer::Method::Get) {
PIByteArray file = server->getFile(path);
if (!file.isEmpty()) {
rep.addHeader(MHD_HTTP_HEADER_CACHE_CONTROL, "public");
rep.addHeader(MHD_HTTP_HEADER_CONTENT_TYPE, "application/octet-stream");
rep.setBody(file);
send_reply(rep);
return true;
}
if (path == "/favicon.ico"_a) {
piCout << "send favicon" << server->favicon.size() << "bytes";
// piCout << "send favicon" << server->favicon.size() << "bytes";
rep.setBody(server->favicon);
send_reply(rep);
return true;
}
}
piCout << "ready" << (int)method << path;
// piCout << "ready" << (int)method << path;
MicrohttpdServer::Request req;
req.method = method;
req.path = path;
req.body = body;
req.headers = headers;
req.args = args;
// rep.headers = headers;
rep.setCode(MHD_HTTP_BAD_REQUEST);
if (server->callback) rep = server->callback(req);
rep.addFixedHeaders();
send_reply(rep);
@@ -62,13 +53,13 @@ bool MicrohttpdServerConnection::ready() {
int MicrohttpdServerConnection::send_reply(const MicrohttpdServer::Reply & r) {
MHD_Response * response = MHD_create_response_from_buffer(r.body.size(), (void *)r.body.data(), MHD_RESPMEM_MUST_COPY);
if (!response) {
piCout << "null response" << r.body.size() << (void *)r.body.data();
// piCout << "null response" << r.body.size() << (void *)r.body.data();
return MHD_NO;
}
auto it = r.headers.makeIterator();
while (it.next())
MHD_add_response_header(response, it.key().dataAscii(), it.value().dataUTF8());
piCout << "status" << r.code;
// piCout << "status" << r.code;
int ret = MHD_queue_response(connection, r.code, response);
MHD_destroy_response(response);
return ret;
@@ -80,6 +71,14 @@ int MicrohttpdServerConnection::send_error() {
}
void log_callback(void * cls, const char * fm, va_list ap) {
MicrohttpdServer * server = (MicrohttpdServer *)cls;
piCout << "log" << server;
if (!server) return;
piCout << server << fm << ap;
}
int iterate_post(void * conn_cls,
MHD_ValueKind kind,
const char * key,
@@ -98,13 +97,14 @@ int iterate_post(void * conn_cls,
void request_completed(void * cls, MHD_Connection * connection, void ** con_cls, MHD_RequestTerminationCode toe) {
MicrohttpdServerConnection *& conn((MicrohttpdServerConnection *&)(*con_cls));
// qDebug() << "request_completed" << conn << conn->headers << conn->post << '"' << conn->body << '"';
// piCout << "request_completed" << conn << conn->headers << conn->post << '"' << conn->body << '"';
if (!conn) return;
if (conn->method == MicrohttpdServer::Method::Post && conn->postprocessor) MHD_destroy_post_processor(conn->postprocessor);
conn->ready();
piDeleteSafety(conn);
}
int header_iterate(void * cls, MHD_ValueKind kind, const char * key, const char * value) {
MicrohttpdServerConnection * conn = (MicrohttpdServerConnection *)cls;
if (!conn) return MHD_NO;
@@ -112,6 +112,7 @@ int header_iterate(void * cls, MHD_ValueKind kind, const char * key, const char
return MHD_YES;
}
int args_iterate(void * cls, MHD_ValueKind kind, const char * key, const char * value) {
MicrohttpdServerConnection * conn = (MicrohttpdServerConnection *)cls;
if (!conn) return MHD_NO;
@@ -152,7 +153,9 @@ int answer_to_connection(void * cls,
m = MicrohttpdServer::Method::Patch;
if (m == MicrohttpdServer::Method::Unknown) {
piCout << "[MicrohttpdServer] Unknown method!";
piCout << "[MicrohttpdServer]"
<< "Warning:"
<< "Unknown method!";
return MHD_NO;
}
@@ -205,6 +208,8 @@ PRIVATE_DEFINITION_END(MicrohttpdServer)
MicrohttpdServer::MicrohttpdServer() {
PRIVATE->daemon = nullptr;
opts[Option::ConnectionLimit] = FD_SETSIZE - 4;
opts[Option::ConnectionTimeout] = 0_s;
}
@@ -213,10 +218,8 @@ MicrohttpdServer::~MicrohttpdServer() {
}
void MicrohttpdServer::setWWWRoot(const PIString & path) {
www_root = path;
if (www_root.isEmpty()) return;
www_root = PIDir(www_root).absolutePath();
void MicrohttpdServer::setOption(Option o, PIVariant v) {
opts[o] = std::move(v);
}
@@ -229,26 +232,42 @@ bool MicrohttpdServer::listen(PINetworkAddress addr) {
stop();
uint flags = 0;
#if MHD_VERSION <= 0x00095100
flags = MHD_USE_POLL_INTERNALLY;
flags |= MHD_USE_POLL_INTERNALLY;
#else
flags = MHD_USE_AUTO | MHD_USE_INTERNAL_POLLING_THREAD;
flags |= MHD_USE_AUTO | MHD_USE_INTERNAL_POLLING_THREAD;
#endif
if (opts.value(Option::HTTPSEnabled).toBool()) flags |= MHD_USE_TLS;
mem_key = opts.value(Option::HTTPSMemKey).toByteArray();
if (mem_key.isNotEmpty()) mem_key.append(0);
mem_cert = opts.value(Option::HTTPSMemCert).toByteArray();
if (mem_cert.isNotEmpty()) mem_cert.append(0);
key_pass = opts.value(Option::HTTPSKeyPassword).toByteArray();
if (key_pass.isNotEmpty()) key_pass.append(0);
sockaddr_in sa_addr;
memset(&sa_addr, 0, sizeof(sa_addr));
sa_addr.sin_port = htons(addr.port());
sa_addr.sin_addr.s_addr = addr.ip();
sa_addr.sin_family = AF_INET;
PIVector<MHD_OptionItem> options;
options.append({MHD_OPTION_EXTERNAL_LOGGER, (intptr_t)log_callback, this});
options.append({MHD_OPTION_NOTIFY_COMPLETED, (intptr_t)request_completed, nullptr});
options.append({MHD_OPTION_CONNECTION_LIMIT, opts.value(Option::ConnectionLimit).toInt(), nullptr});
options.append({MHD_OPTION_CONNECTION_TIMEOUT, piRound(opts.value(Option::ConnectionTimeout).toSystemTime().toSeconds()), nullptr});
options.append({MHD_OPTION_SOCK_ADDR, 0, &sa_addr});
if (opts.value(Option::HTTPSEnabled).toBool()) {
options.append({MHD_OPTION_HTTPS_MEM_KEY, 0, mem_key.data()});
options.append({MHD_OPTION_HTTPS_MEM_CERT, 0, mem_cert.data()});
options.append({MHD_OPTION_HTTPS_KEY_PASSWORD, 0, key_pass.data()});
}
options.append({MHD_OPTION_END, 0, nullptr});
PRIVATE->daemon = MHD_start_daemon(flags,
addr.port(),
nullptr,
nullptr,
(MHD_AccessHandlerCallback)answer_to_connection,
this,
MHD_OPTION_NOTIFY_COMPLETED,
request_completed,
nullptr,
MHD_OPTION_SOCK_ADDR,
&sa_addr,
MHD_OPTION_ARRAY,
options.data(),
MHD_OPTION_END);
return isListen();
}
@@ -259,16 +278,6 @@ bool MicrohttpdServer::isListen() const {
}
PIByteArray MicrohttpdServer::getFile(PIString name) {
if (www_root.isEmpty()) return PIByteArray();
if (name == "/") name += "index.html";
PIString path = PIDir(www_root).relative(name);
// qDebug() << "getFile" << path;
if (path.isEmpty() || !path.startsWith(www_root)) return PIByteArray();
return PIFile::readAll(PIDir(www_root).absolute(name));
}
void MicrohttpdServer::stop() {
if (PRIVATE->daemon) {
MHD_stop_daemon(PRIVATE->daemon);
@@ -299,10 +308,12 @@ void MicrohttpdServer::Reply::setCode(int c) {
void MicrohttpdServer::Reply::addFixedHeaders() {
if (!headers.contains(MHD_HTTP_HEADER_CONTENT_TYPE)) {
if (body.isNotEmpty()) {
if (body.startsWith(PIByteArray::fromAscii("<!DOCTYPE html>")))
addHeader(MHD_HTTP_HEADER_CONTENT_TYPE, "text/html; charset=utf-8");
else
else if (body[0] == '[' || body[0] == '{')
addHeader(MHD_HTTP_HEADER_CONTENT_TYPE, "application/json; charset=utf-8");
}
}
addHeader(MHD_HTTP_HEADER_ACCESS_CONTROL_ALLOW_ORIGIN, "*");
}

View File

@@ -13,7 +13,6 @@ PIHTTPServer::PIHTTPServer() {
while (it.next()) {
if (it.value().function) {
if (it.value().match(in_path)) {
rep.setCode(200);
rep = it.value().function(r);
break;
}

View File

@@ -132,9 +132,7 @@ inline void piSwapBinary(const void *& f, const void *& s) {
//! \~english Example:\n \snippet piincludes.cpp compareBinary
//! \~russian Пример:\n \snippet piincludes.cpp compareBinary
inline bool piCompareBinary(const void * f, const void * s, size_t size) {
for (size_t i = 0; i < size; ++i)
if (((const uchar *)f)[i] != ((const uchar *)s)[i]) return false;
return true;
return 0 == memcmp(f, s, size);
}
//! \~\brief

View File

@@ -27,6 +27,14 @@ public:
Trace,
Patch
};
enum class Option {
ConnectionLimit, // uint
ConnectionTimeout, // uint, sec
HTTPSEnabled, // bool
HTTPSMemKey, // const char * to key.pem data
HTTPSMemCert, // const char * to cert.pem data
HTTPSKeyPassword // const char * to passwd for key.pem
};
struct PIP_HTTP_SERVER_EXPORT Request {
MicrohttpdServer::Method method;
@@ -52,7 +60,7 @@ public:
PIMap<PIString, PIString> headers;
};
void setWWWRoot(const PIString & path);
void setOption(Option o, PIVariant v);
void setFavicon(const PIByteArray & im);
bool listen(PINetworkAddress addr);
@@ -63,12 +71,12 @@ public:
void setRequestCallback(std::function<Reply(Request)> c) { callback = c; }
private:
PIByteArray getFile(PIString name);
PRIVATE_DECLARATION(PIP_HTTP_SERVER_EXPORT)
PIString www_root;
PIByteArray favicon;
PIMap<Option, PIVariant> opts;
std::function<Reply(Request)> callback;
PIByteArray mem_key, mem_cert, key_pass;
};

View File

@@ -18,7 +18,9 @@ int main(int argc, char * argv[]) {
PIHTTPServer server;
server.setFavicon(PIFile::readAll("logo.png", false));
// server.setOption(MicrohttpdServer::Option::HTTPSEnabled, true);
server.listen({"127.0.0.1", 7777});
// server.listen({"192.168.1.10", 7778});
server.registerPath("/", [](const MicrohttpdServer::Request & r) -> MicrohttpdServer::Reply {
MicrohttpdServer::Reply ret;