PIProtectedVariable - user now can`t mistake
PIHTTPServer improvements
This commit is contained in:
@@ -1,5 +1,4 @@
|
|||||||
#include "microhttpd_server_p.h"
|
#include "microhttpd_server.h"
|
||||||
|
|
||||||
#include "piliterals_string.h"
|
#include "piliterals_string.h"
|
||||||
#include "piliterals_time.h"
|
#include "piliterals_time.h"
|
||||||
|
|
||||||
@@ -126,7 +125,10 @@ void request_completed(void * cls, MHD_Connection * connection, void ** con_cls,
|
|||||||
MicrohttpdServerConnection *& conn((MicrohttpdServerConnection *&)(*con_cls));
|
MicrohttpdServerConnection *& conn((MicrohttpdServerConnection *&)(*con_cls));
|
||||||
// piCout << "request_completed" << conn << conn->headers << conn->post << '"' << conn->body << '"';
|
// piCout << "request_completed" << conn << conn->headers << conn->post << '"' << conn->body << '"';
|
||||||
if (!conn) return;
|
if (!conn) return;
|
||||||
if (conn->method == MicrohttpdServer::Method::Post && conn->postprocessor) MHD_destroy_post_processor(conn->postprocessor);
|
if (conn->postprocessor) {
|
||||||
|
MHD_destroy_post_processor(conn->postprocessor);
|
||||||
|
conn->postprocessor = nullptr;
|
||||||
|
}
|
||||||
conn->ready();
|
conn->ready();
|
||||||
piDeleteSafety(conn);
|
piDeleteSafety(conn);
|
||||||
}
|
}
|
||||||
@@ -186,7 +188,7 @@ int answer_to_connection(void * cls,
|
|||||||
return MHD_NO;
|
return MHD_NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
// piCout << "answer" << url << method << server;
|
piCout << "answer" << url << method << (int)m << server;
|
||||||
MicrohttpdServerConnection *& conn((MicrohttpdServerConnection *&)(*con_cls));
|
MicrohttpdServerConnection *& conn((MicrohttpdServerConnection *&)(*con_cls));
|
||||||
if (!conn) {
|
if (!conn) {
|
||||||
conn = new MicrohttpdServerConnection();
|
conn = new MicrohttpdServerConnection();
|
||||||
@@ -196,35 +198,25 @@ int answer_to_connection(void * cls,
|
|||||||
conn->method = m;
|
conn->method = m;
|
||||||
MHD_get_connection_values(connection, MHD_HEADER_KIND, (MHD_KeyValueIterator)header_iterate, *con_cls);
|
MHD_get_connection_values(connection, MHD_HEADER_KIND, (MHD_KeyValueIterator)header_iterate, *con_cls);
|
||||||
MHD_get_connection_values(connection, MHD_GET_ARGUMENT_KIND, (MHD_KeyValueIterator)args_iterate, *con_cls);
|
MHD_get_connection_values(connection, MHD_GET_ARGUMENT_KIND, (MHD_KeyValueIterator)args_iterate, *con_cls);
|
||||||
|
return MHD_YES;
|
||||||
|
}
|
||||||
|
|
||||||
if (m == MicrohttpdServer::Method::Post) {
|
if (m == MicrohttpdServer::Method::Unknown) {
|
||||||
// qDebug() << "new POST" << *upload_data_size;
|
return conn->send_error();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*upload_data_size) {
|
||||||
|
if (!conn->postprocessor) {
|
||||||
conn->postprocessor = MHD_create_post_processor(connection, 65536, (MHD_PostDataIterator)iterate_post, (void *)conn);
|
conn->postprocessor = MHD_create_post_processor(connection, 65536, (MHD_PostDataIterator)iterate_post, (void *)conn);
|
||||||
}
|
}
|
||||||
return MHD_YES;
|
conn->body.append(upload_data, *upload_data_size);
|
||||||
}
|
MHD_post_process(conn->postprocessor, upload_data, *upload_data_size);
|
||||||
|
*upload_data_size = 0;
|
||||||
switch (m) {
|
} else {
|
||||||
case MicrohttpdServer::Method::Get:
|
// qDebug() << "answer ok";
|
||||||
if (!conn->ready()) return conn->send_error();
|
if (!conn->ready()) return conn->send_error();
|
||||||
return MHD_YES;
|
|
||||||
case MicrohttpdServer::Method::Post:
|
|
||||||
// qDebug() << "add POST" << *upload_data_size << PIString::fromUtf8(upload_data, *upload_data_size);
|
|
||||||
if (*upload_data_size) {
|
|
||||||
conn->body.append(upload_data, *upload_data_size);
|
|
||||||
if (conn->postprocessor) MHD_post_process(conn->postprocessor, upload_data, *upload_data_size);
|
|
||||||
*upload_data_size = 0;
|
|
||||||
return MHD_YES;
|
|
||||||
} else {
|
|
||||||
// qDebug() << "answer ok";
|
|
||||||
if (!conn->ready()) return conn->send_error();
|
|
||||||
return MHD_YES;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default: break;
|
|
||||||
}
|
}
|
||||||
|
return MHD_YES;
|
||||||
return conn->send_error();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -9,15 +9,20 @@ PIHTTPServer::PIHTTPServer() {
|
|||||||
rep.setCode(404);
|
rep.setCode(404);
|
||||||
auto in_path = r.path.split("/");
|
auto in_path = r.path.split("/");
|
||||||
in_path.removeAll("");
|
in_path.removeAll("");
|
||||||
auto it = functions.makeReverseIterator();
|
auto it = functions.makeReverseIterator();
|
||||||
|
bool found = false;
|
||||||
while (it.next()) {
|
while (it.next()) {
|
||||||
if (it.value().function) {
|
if (it.value().function) {
|
||||||
if (it.value().match(in_path)) {
|
if (it.value().method == r.method) {
|
||||||
rep = it.value().function(r);
|
if (it.value().match(in_path)) {
|
||||||
break;
|
rep = it.value().function(r);
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!found && unhandled) rep = unhandled(r);
|
||||||
auto hit = reply_headers.makeIterator();
|
auto hit = reply_headers.makeIterator();
|
||||||
while (hit.next())
|
while (hit.next())
|
||||||
rep.addHeader(hit.key(), hit.value());
|
rep.addHeader(hit.key(), hit.value());
|
||||||
@@ -31,14 +36,50 @@ PIHTTPServer::~PIHTTPServer() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void PIHTTPServer::registerPath(const PIString & path, RequestFunction functor) {
|
void PIHTTPServer::registerPath(const PIString & path, Method method, RequestFunction functor) {
|
||||||
auto & ep(functions[path]);
|
auto & ep(functions[path + PIString::fromNumber((int)method)]);
|
||||||
ep.path = path.split("/");
|
ep.path = path.split("/");
|
||||||
|
ep.method = method;
|
||||||
ep.function = functor;
|
ep.function = functor;
|
||||||
ep.path.removeAll("");
|
ep.path.removeAll("");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void PIHTTPServer::registerUnhandled(RequestFunction functor) {
|
||||||
|
unhandled = functor;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void PIHTTPServer::unregisterPath(const PIString & path, Method method) {
|
||||||
|
auto pl = path.split("/");
|
||||||
|
pl.removeAll("");
|
||||||
|
auto it = functions.makeIterator();
|
||||||
|
while (it.next()) {
|
||||||
|
if (it.value().method == method) {
|
||||||
|
if (it.value().path == pl) {
|
||||||
|
functions.remove(it.key());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void PIHTTPServer::unregisterPath(const PIString & path) {
|
||||||
|
auto pl = path.split("/");
|
||||||
|
pl.removeAll("");
|
||||||
|
auto it = functions.makeIterator();
|
||||||
|
PIStringList keys;
|
||||||
|
while (it.next()) {
|
||||||
|
if (it.value().path == pl) {
|
||||||
|
keys << it.key();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (const auto & k: keys)
|
||||||
|
functions.remove(k);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool PIHTTPServer::Endpoint::match(const PIStringList & in_path) const {
|
bool PIHTTPServer::Endpoint::match(const PIStringList & in_path) const {
|
||||||
if (in_path.size() != path.size()) return false;
|
if (in_path.size() != path.size()) return false;
|
||||||
for (int i = 0; i < path.size_s(); ++i) {
|
for (int i = 0; i < path.size_s(); ++i) {
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
#ifndef PIHTTPSERVER_H
|
#ifndef PIHTTPSERVER_H
|
||||||
#define PIHTTPSERVER_H
|
#define PIHTTPSERVER_H
|
||||||
|
|
||||||
#include "microhttpd_server_p.h"
|
#include "microhttpd_server.h"
|
||||||
#include "pip_http_server_export.h"
|
|
||||||
|
|
||||||
class PIP_HTTP_SERVER_EXPORT PIHTTPServer: public MicrohttpdServer {
|
class PIP_HTTP_SERVER_EXPORT PIHTTPServer: public MicrohttpdServer {
|
||||||
PIOBJECT_SUBCLASS(PIHTTPServer, MicrohttpdServer)
|
PIOBJECT_SUBCLASS(PIHTTPServer, MicrohttpdServer)
|
||||||
@@ -13,7 +12,10 @@ public:
|
|||||||
|
|
||||||
using RequestFunction = std::function<MicrohttpdServer::Reply(const MicrohttpdServer::Request &)>;
|
using RequestFunction = std::function<MicrohttpdServer::Reply(const MicrohttpdServer::Request &)>;
|
||||||
|
|
||||||
void registerPath(const PIString & path, RequestFunction functor);
|
void registerPath(const PIString & path, MicrohttpdServer::Method method, RequestFunction functor);
|
||||||
|
void registerUnhandled(RequestFunction functor);
|
||||||
|
void unregisterPath(const PIString & path, MicrohttpdServer::Method method);
|
||||||
|
void unregisterPath(const PIString & path);
|
||||||
|
|
||||||
void addReplyHeader(const PIString & name, const PIString & value) { reply_headers[name] = value; }
|
void addReplyHeader(const PIString & name, const PIString & value) { reply_headers[name] = value; }
|
||||||
void removeReplyHeader(const PIString & name) { reply_headers.remove(name); }
|
void removeReplyHeader(const PIString & name) { reply_headers.remove(name); }
|
||||||
@@ -23,10 +25,12 @@ private:
|
|||||||
struct Endpoint {
|
struct Endpoint {
|
||||||
bool match(const PIStringList & in_path) const;
|
bool match(const PIStringList & in_path) const;
|
||||||
PIStringList path;
|
PIStringList path;
|
||||||
|
MicrohttpdServer::Method method = MicrohttpdServer::Method::Unknown;
|
||||||
RequestFunction function;
|
RequestFunction function;
|
||||||
};
|
};
|
||||||
PIMap<PIString, PIString> reply_headers;
|
PIMap<PIString, PIString> reply_headers;
|
||||||
PIMap<PIString, Endpoint> functions;
|
PIMap<PIString, Endpoint> functions;
|
||||||
|
RequestFunction unhandled;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
54
libs/main/http_server/pihttpservermodule.h
Normal file
54
libs/main/http_server/pihttpservermodule.h
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
/*
|
||||||
|
PIP - Platform Independent Primitives
|
||||||
|
Module includes
|
||||||
|
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
//! \defgroup HTTPServer HTTPServer
|
||||||
|
//! \~\brief
|
||||||
|
//! \~english HTTP server
|
||||||
|
//! \~russian HTTP сервер
|
||||||
|
//!
|
||||||
|
//! \~\details
|
||||||
|
//! \~english \section cmake_module_HTTPServer Building with CMake
|
||||||
|
//! \~russian \section cmake_module_HTTPServer Сборка с использованием CMake
|
||||||
|
//!
|
||||||
|
//! \~\code
|
||||||
|
//! find_package(PIP REQUIRED)
|
||||||
|
//! target_link_libraries([target] PIP::HTTPServer)
|
||||||
|
//! \endcode
|
||||||
|
//!
|
||||||
|
//! \~english \par Common
|
||||||
|
//! \~russian \par Общее
|
||||||
|
//!
|
||||||
|
//! \~english
|
||||||
|
//! These files provides HTTP server based on libmicrohttpd
|
||||||
|
//!
|
||||||
|
//! \~russian
|
||||||
|
//! Эти файлы обеспечивают HTTP сервер, основанный на libmicrohttpd
|
||||||
|
//!
|
||||||
|
//! \~\authors
|
||||||
|
//! \~english
|
||||||
|
//! Ivan Pelipenko peri4ko@yandex.ru;
|
||||||
|
//! \~russian
|
||||||
|
//! Иван Пелипенко peri4ko@yandex.ru;
|
||||||
|
//!
|
||||||
|
|
||||||
|
#ifndef pihttpservermodule_H
|
||||||
|
#define pihttpservermodule_H
|
||||||
|
|
||||||
|
#include "pihttpserver.h"
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -27,6 +27,7 @@
|
|||||||
#include "picoremodule.h"
|
#include "picoremodule.h"
|
||||||
#include "picryptmodule.h"
|
#include "picryptmodule.h"
|
||||||
#include "pigeomodule.h"
|
#include "pigeomodule.h"
|
||||||
|
#include "pihttpservermodule.h"
|
||||||
#include "piiodevicesmodule.h"
|
#include "piiodevicesmodule.h"
|
||||||
#include "piioutilsmodule.h"
|
#include "piioutilsmodule.h"
|
||||||
#include "piliterals.h"
|
#include "piliterals.h"
|
||||||
|
|||||||
@@ -32,6 +32,28 @@
|
|||||||
template<typename T>
|
template<typename T>
|
||||||
class PIP_EXPORT PIProtectedVariable {
|
class PIP_EXPORT PIProtectedVariable {
|
||||||
public:
|
public:
|
||||||
|
//! \~english
|
||||||
|
//! \~russian
|
||||||
|
class PIP_EXPORT Pointer {
|
||||||
|
friend class PIProtectedVariable<T>;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Pointer(const Pointer & v): pv(v.pv), counter(v.counter + 1) {}
|
||||||
|
~Pointer() {
|
||||||
|
if (counter == 0) pv.mutex.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
T * operator->() { return &pv.var; }
|
||||||
|
T & operator*() { return pv.var; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
Pointer() = delete;
|
||||||
|
Pointer(PIProtectedVariable<T> & v): pv(v) {}
|
||||||
|
|
||||||
|
PIProtectedVariable<T> & pv;
|
||||||
|
int counter = 0;
|
||||||
|
};
|
||||||
|
|
||||||
//! \~english Sets value to \"v\"
|
//! \~english Sets value to \"v\"
|
||||||
//! \~russian Устанавливает значение как \"v\"
|
//! \~russian Устанавливает значение как \"v\"
|
||||||
void set(T v) {
|
void set(T v) {
|
||||||
@@ -39,6 +61,13 @@ public:
|
|||||||
var = std::move(v);
|
var = std::move(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//! \~english Lock mutex and returns reference wrapper of value. Unlock on variable destructor.
|
||||||
|
//! \~russian Блокирует мьютекс и возвращает класс-обертку на значение. Разблокирует в деструкторе переменной.
|
||||||
|
Pointer getRef() {
|
||||||
|
mutex.lock();
|
||||||
|
return Pointer(*this);
|
||||||
|
}
|
||||||
|
|
||||||
//! \~english Returns copy of value
|
//! \~english Returns copy of value
|
||||||
//! \~russian Возвращает копию значения
|
//! \~russian Возвращает копию значения
|
||||||
T get() const {
|
T get() const {
|
||||||
@@ -46,17 +75,6 @@ public:
|
|||||||
return var;
|
return var;
|
||||||
}
|
}
|
||||||
|
|
||||||
//! \~english Lock mutex and returns reference of value
|
|
||||||
//! \~russian Блокирует мьютекс и возвращает ссылку на значение
|
|
||||||
T & lock() {
|
|
||||||
mutex.lock();
|
|
||||||
return var;
|
|
||||||
}
|
|
||||||
|
|
||||||
//! \~english Unlock mutex
|
|
||||||
//! \~russian Разблокирует мьютекс
|
|
||||||
void unlock() { mutex.unlock(); }
|
|
||||||
|
|
||||||
//! \~english Sets value to \"v\"
|
//! \~english Sets value to \"v\"
|
||||||
//! \~russian Устанавливает значение как \"v\"
|
//! \~russian Устанавливает значение как \"v\"
|
||||||
PIProtectedVariable<T> & operator=(T v) {
|
PIProtectedVariable<T> & operator=(T v) {
|
||||||
|
|||||||
16
main.cpp
16
main.cpp
@@ -1,4 +1,3 @@
|
|||||||
#include "pihttpserver.h"
|
|
||||||
#include "pip.h"
|
#include "pip.h"
|
||||||
|
|
||||||
using namespace PICoutManipulators;
|
using namespace PICoutManipulators;
|
||||||
@@ -22,31 +21,38 @@ int main(int argc, char * argv[]) {
|
|||||||
server.listen({"127.0.0.1", 7777});
|
server.listen({"127.0.0.1", 7777});
|
||||||
// server.listen({"192.168.1.10", 7778});
|
// server.listen({"192.168.1.10", 7778});
|
||||||
|
|
||||||
server.registerPath("/", [](const MicrohttpdServer::Request & r) -> MicrohttpdServer::Reply {
|
server.registerPath("/", MicrohttpdServer::Method::Get, [](const MicrohttpdServer::Request & r) -> MicrohttpdServer::Reply {
|
||||||
MicrohttpdServer::Reply ret;
|
MicrohttpdServer::Reply ret;
|
||||||
ret.setBody(PIByteArray::fromAscii(pageTitle));
|
ret.setBody(PIByteArray::fromAscii(pageTitle));
|
||||||
return ret;
|
return ret;
|
||||||
});
|
});
|
||||||
|
|
||||||
server.registerPath("/html", [](const MicrohttpdServer::Request & r) -> MicrohttpdServer::Reply {
|
server.registerPath("/html", MicrohttpdServer::Method::Get, [](const MicrohttpdServer::Request & r) -> MicrohttpdServer::Reply {
|
||||||
MicrohttpdServer::Reply ret;
|
MicrohttpdServer::Reply ret;
|
||||||
ret.setBody("<!DOCTYPE html><html><body><p>arg=%1</p></body></html>"_a.arg(r.args.value("a0")).toUTF8());
|
ret.setBody("<!DOCTYPE html><html><body><p>arg=%1</p></body></html>"_a.arg(r.args.value("a0")).toUTF8());
|
||||||
return ret;
|
return ret;
|
||||||
});
|
});
|
||||||
|
|
||||||
server.registerPath("/api", [](const MicrohttpdServer::Request & r) -> MicrohttpdServer::Reply {
|
server.registerPath("/api", MicrohttpdServer::Method::Put, [](const MicrohttpdServer::Request & r) -> MicrohttpdServer::Reply {
|
||||||
MicrohttpdServer::Reply ret;
|
MicrohttpdServer::Reply ret;
|
||||||
ret.setBody(PIByteArray::fromAscii("<!DOCTYPE html><html><body>API</body></html>"));
|
ret.setBody(PIByteArray::fromAscii("<!DOCTYPE html><html><body>API</body></html>"));
|
||||||
return ret;
|
return ret;
|
||||||
});
|
});
|
||||||
|
|
||||||
server.registerPath("/api/*", [](const MicrohttpdServer::Request & r) -> MicrohttpdServer::Reply {
|
server.registerPath("/api/*", MicrohttpdServer::Method::Post, [](const MicrohttpdServer::Request & r) -> MicrohttpdServer::Reply {
|
||||||
MicrohttpdServer::Reply ret;
|
MicrohttpdServer::Reply ret;
|
||||||
ret.setBody("<!DOCTYPE html><html><body>API etry %1</body></html>"_a.arg(r.path).toUTF8());
|
ret.setBody("<!DOCTYPE html><html><body>API etry %1</body></html>"_a.arg(r.path).toUTF8());
|
||||||
ret.setCode(405);
|
ret.setCode(405);
|
||||||
return ret;
|
return ret;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
server.registerUnhandled([](const MicrohttpdServer::Request & r) -> MicrohttpdServer::Reply {
|
||||||
|
MicrohttpdServer::Reply ret;
|
||||||
|
ret.setBody("<!DOCTYPE html><html><body>Unknown</body></html>"_a.arg(r.path).toUTF8());
|
||||||
|
ret.setCode(404);
|
||||||
|
return ret;
|
||||||
|
});
|
||||||
|
|
||||||
/*server.setRequestCallback([](MicrohttpdServer::Request r) -> MicrohttpdServer::Reply {
|
/*server.setRequestCallback([](MicrohttpdServer::Request r) -> MicrohttpdServer::Reply {
|
||||||
MicrohttpdServer::Reply rep;
|
MicrohttpdServer::Reply rep;
|
||||||
piCout << "request" << r.path;
|
piCout << "request" << r.path;
|
||||||
|
|||||||
Reference in New Issue
Block a user