diff --git a/App/Server/clsAPIObject.cpp b/App/Server/clsAPIObject.cpp index a68be370..ddac0165 100644 --- a/App/Server/clsAPIObject.cpp +++ b/App/Server/clsAPIObject.cpp @@ -317,8 +317,11 @@ void clsAPIObject::invokeMethod( QObject *parent = this->parent(); intfPureModule* pureModule = dynamic_cast(parent); Conn_addResponseHeader = QObject::connect(pureModule, &intfPureModule::addResponseHeader, - [&_responseHeaders](const QString &_header, const QString &_value) { - _responseHeaders.insert(_header, _value); + [&_responseHeaders](const QString &_header, const QString &_value, bool _multiValue) { + if (_multiValue && _responseHeaders.contains(_header)) + _responseHeaders[_header] = _responseHeaders[_header].toString() + "," + _value; + else + _responseHeaders.insert(_header, _value); } ); diff --git a/App/Server/clsRequestHandler.cpp b/App/Server/clsRequestHandler.cpp index a86d4288..117befc0 100644 --- a/App/Server/clsRequestHandler.cpp +++ b/App/Server/clsRequestHandler.cpp @@ -554,10 +554,9 @@ void clsRequestHandler::findAndCallAPI(QString _api) run(APIObject, Queries, ExtraAPIPath); } -void clsRequestHandler::sendError( - qhttp::TStatusCode _code, +void clsRequestHandler::sendError(qhttp::TStatusCode _code, const QString& _message, - const QVariantMap &_responseHeaders, + QVariantMap _responseHeaders, bool _closeConnection ) { @@ -597,7 +596,10 @@ void clsRequestHandler::sendFile(const QString& _basePath, const QString _path) this->Response->setStatusCode(qhttp::ESTATUS_OK); +#ifdef QT_DEBUG + this->Response->addHeaderValue("Access-Control-Expose-Headers", QStringLiteral("X-DEBUG-TIME-ELAPSED")); this->Response->addHeaderValue("X-DEBUG-TIME-ELAPSED", QString::number(this->ElapsedTimer.elapsed()) + " ms"); +#endif QTimer::singleShot(10, this, &clsRequestHandler::slotSendFileData); } @@ -628,10 +630,9 @@ void clsRequestHandler::addHeaderValues(const QVariantMap &_responseHeaders) } } -void clsRequestHandler::sendResponse( - qhttp::TStatusCode _code, +void clsRequestHandler::sendResponse(qhttp::TStatusCode _code, const QVariant &_response, - const QVariantMap &_responseHeaders + QVariantMap _responseHeaders ) { gServerStats.Success.inc(); @@ -660,13 +661,26 @@ void clsRequestHandler::sendResponse( this->Response->addHeaderValue("content-length", RawData.data().length()); this->Response->addHeaderValue("content-type", QString(RawData.mime())); - this->Response->addHeaderValue("Access-Control-Allow-Origin", QString("*")); - this->Response->addHeaderValue("Connection", QString("keep-alive")); + this->Response->addHeaderValue("Access-Control-Allow-Origin", QStringLiteral("*")); + this->Response->addHeaderValue("Connection", QStringLiteral("keep-alive")); - this->addHeaderValues(_responseHeaders); + auto funcAddToHeaderArray = [&_responseHeaders](const QString &_header) { + if (_responseHeaders.contains("Access-Control-Expose-Headers")) + _responseHeaders["Access-Control-Expose-Headers"] = _responseHeaders["Access-Control-Expose-Headers"].toString() + "," + _header; + else + _responseHeaders["Access-Control-Expose-Headers"] = _header; + }; + +#ifdef QT_DEBUG + funcAddToHeaderArray("X-DEBUG-TIME-ELAPSED"); if (_responseHeaders.contains("X-DEBUG-TIME-ELAPSED") == false) - this->Response->addHeaderValue("X-DEBUG-TIME-ELAPSED", QString::number(this->ElapsedTimer.elapsed()) + " ms"); + _responseHeaders["X-DEBUG-TIME-ELAPSED"] = QString::number(this->ElapsedTimer.elapsed()) + " ms"; +#endif + + funcAddToHeaderArray("X-AUTH-NEW-TOKEN"); + + this->addHeaderValues(_responseHeaders); this->Response->end(RawData.data()); @@ -679,11 +693,11 @@ void clsRequestHandler::sendResponse( void clsRequestHandler::sendCORSOptions() { this->Response->addHeaderValue("Access-Control-Allow-Origin", ServerConfigs::AccessControl.value()); - this->Response->addHeaderValue("Access-Control-Allow-Credentials", QString("true")); + this->Response->addHeaderValue("Access-Control-Allow-Credentials", QStringLiteral("true")); this->Response->addHeaderValue("Access-Control-Allow-Methods", - QString("GET, POST, PUT, PATCH, DELETE")); + QStringLiteral("GET, POST, PUT, PATCH, DELETE")); this->Response->addHeaderValue("Access-Control-Allow-Headers", - QString("authorization," + QStringLiteral("authorization," "access-control-allow-origin," "Access-Control-Allow-Headers," "DNT,X-CustomHeader," @@ -695,12 +709,15 @@ void clsRequestHandler::sendCORSOptions() "Content-Type")); this->Response->addHeaderValue("Access-Control-Max-Age", 1728000); this->Response->addHeaderValue("content-length", 0); - this->Response->addHeaderValue("content-type", QString("application/json; charset=utf-8")); - this->Response->addHeaderValue("Connection", QString("keep-alive")); + this->Response->addHeaderValue("content-type", QStringLiteral("application/json; charset=utf-8")); + this->Response->addHeaderValue("Connection", QStringLiteral("keep-alive")); this->Response->setStatusCode(qhttp::ESTATUS_NO_CONTENT); +#ifdef QT_DEBUG + this->Response->addHeaderValue("Access-Control-Expose-Headers", QStringLiteral("X-DEBUG-TIME-ELAPSED")); this->Response->addHeaderValue("X-DEBUG-TIME-ELAPSED", QString::number(this->ElapsedTimer.elapsed()) + " ms"); +#endif this->Response->end(); @@ -721,10 +738,9 @@ void clsRequestHandler::redirect(const QString _path, bool _appendBase, bool _pe this->deleteLater(); } -void clsRequestHandler::sendResponseBase( - qhttp::TStatusCode _code, +void clsRequestHandler::sendResponseBase(qhttp::TStatusCode _code, QJsonObject _dataObject, - const QVariantMap &_responseHeaders, + QVariantMap _responseHeaders, bool _closeConnection ) { @@ -751,14 +767,27 @@ void clsRequestHandler::sendResponseBase( this->Response->addHeader("connection", "close"); this->Response->addHeaderValue("content-length", Data.length()); - this->Response->addHeaderValue("content-type", QString("application/json; charset=utf-8")); - this->Response->addHeaderValue("Access-Control-Allow-Origin", QString("*")); - this->Response->addHeaderValue("Connection", QString("keep-alive")); + this->Response->addHeaderValue("content-type", QStringLiteral("application/json; charset=utf-8")); + this->Response->addHeaderValue("Access-Control-Allow-Origin", QStringLiteral("*")); + this->Response->addHeaderValue("Connection", QStringLiteral("keep-alive")); - this->addHeaderValues(_responseHeaders); + auto funcAddToHeaderArray = [&_responseHeaders](const QString &_header) { + if (_responseHeaders.contains("Access-Control-Expose-Headers")) + _responseHeaders["Access-Control-Expose-Headers"] = _responseHeaders["Access-Control-Expose-Headers"].toString() + "," + _header; + else + _responseHeaders["Access-Control-Expose-Headers"] = _header; + }; + +#ifdef QT_DEBUG + funcAddToHeaderArray("X-DEBUG-TIME-ELAPSED"); if (_responseHeaders.contains("X-DEBUG-TIME-ELAPSED") == false) - this->Response->addHeaderValue("X-DEBUG-TIME-ELAPSED", QString::number(this->ElapsedTimer.elapsed()) + " ms"); + _responseHeaders["X-DEBUG-TIME-ELAPSED"] = QString::number(this->ElapsedTimer.elapsed()) + " ms"; +#endif + + funcAddToHeaderArray("X-AUTH-NEW-TOKEN"); + + this->addHeaderValues(_responseHeaders); this->Response->end(Data.constData()); diff --git a/App/Server/clsRequestHandler.h b/App/Server/clsRequestHandler.h index 267779e5..197e730a 100644 --- a/App/Server/clsRequestHandler.h +++ b/App/Server/clsRequestHandler.h @@ -117,13 +117,20 @@ class clsRequestHandler : public QObject public: void findAndCallAPI(QString _api); + void sendError(qhttp::TStatusCode _code, - const QString& _message, - const QVariantMap &_responseHeaders = {}, - bool _closeConnection = false); + const QString& _message, + QVariantMap _responseHeaders = {}, + bool _closeConnection = false + ); void sendFile(const QString& _basePath, const QString _path); - void sendResponse(qhttp::TStatusCode _code, const QVariant &_response, const QVariantMap &_responseHeaders); + void sendResponse( + qhttp::TStatusCode _code, + const QVariant &_response, + QVariantMap _responseHeaders = {} + ); void sendCORSOptions(); + void redirect(const QString _path, bool _appendBase = true, bool _permananet = true); QString host() const; @@ -131,7 +138,12 @@ class clsRequestHandler : public QObject private: void addHeaderValues(const QVariantMap &_responseHeaders); - void sendResponseBase(qhttp::TStatusCode _code, QJsonObject _dataObject, const QVariantMap &_responseHeaders = {}, bool _closeConnection = false); + void sendResponseBase( + qhttp::TStatusCode _code, + QJsonObject _dataObject, + QVariantMap _responseHeaders = {}, + bool _closeConnection = false + ); stuResult run(clsAPIObject* _apiObject, QStringList& _queries, const QString& _pksByPath); QString toIPv4(const QString _ip); diff --git a/Interfaces/API/intfPureModule.cpp b/Interfaces/API/intfPureModule.cpp index 8e937998..3556068a 100644 --- a/Interfaces/API/intfPureModule.cpp +++ b/Interfaces/API/intfPureModule.cpp @@ -98,6 +98,11 @@ intfPureModule::intfPureModule( //intfPureModule::~intfPureModule(){} +void intfPureModule::addResponseHeaderNameToExpose(const QString &_header) +{ + addResponseHeader("Access-Control-Expose-Headers", _header, true); +} + /***************************************************************/ intfPureModule::stuDBInfo::stuDBInfo(QString _schema, quint16 _port, QString _host, QString _user, QString _pass) : Host(_host), diff --git a/Interfaces/API/intfPureModule.h b/Interfaces/API/intfPureModule.h index a1c05159..efb06915 100644 --- a/Interfaces/API/intfPureModule.h +++ b/Interfaces/API/intfPureModule.h @@ -339,8 +339,9 @@ class intfPureModule : public Targoman::Common::Configuration::intfModule virtual ModuleMethods_t listOfMethods() = 0; + void addResponseHeaderNameToExpose(const QString &_header); signals: - void addResponseHeader(const QString &_header, const QString &_value); + void addResponseHeader(const QString &_header, const QString &_value, bool _multiValue = false); protected: ModuleMethods_t Methods; diff --git a/Interfaces/API/intfSQLBasedModule.cpp b/Interfaces/API/intfSQLBasedModule.cpp index 7099d86c..92bd8469 100644 --- a/Interfaces/API/intfSQLBasedModule.cpp +++ b/Interfaces/API/intfSQLBasedModule.cpp @@ -106,6 +106,11 @@ QVariantMap intfSQLBasedModule::SelectOne( QVariantMap Result = Query.one(); + this->addResponseHeaderNameToExpose(RESPONSE_HEADER_X_PAGINATION_TOTAL_COUNT); + this->addResponseHeaderNameToExpose(RESPONSE_HEADER_X_PAGINATION_PAGE_COUNT); + this->addResponseHeaderNameToExpose(RESPONSE_HEADER_X_PAGINATION_CURRENT_PAGE); + this->addResponseHeaderNameToExpose(RESPONSE_HEADER_X_PAGINATION_PER_PAGE); + this->addResponseHeader(RESPONSE_HEADER_X_PAGINATION_TOTAL_COUNT, QString::number(Result.count())); this->addResponseHeader(RESPONSE_HEADER_X_PAGINATION_PAGE_COUNT, QString::number(ceil((double)Result.count() / _pageSize))); this->addResponseHeader(RESPONSE_HEADER_X_PAGINATION_CURRENT_PAGE, QString::number(_pageIndex)); @@ -144,6 +149,11 @@ QVariantList intfSQLBasedModule::SelectAll( QVariantList Result = Query.all(); + this->addResponseHeaderNameToExpose(RESPONSE_HEADER_X_PAGINATION_TOTAL_COUNT); + this->addResponseHeaderNameToExpose(RESPONSE_HEADER_X_PAGINATION_PAGE_COUNT); + this->addResponseHeaderNameToExpose(RESPONSE_HEADER_X_PAGINATION_CURRENT_PAGE); + this->addResponseHeaderNameToExpose(RESPONSE_HEADER_X_PAGINATION_PER_PAGE); + this->addResponseHeader(RESPONSE_HEADER_X_PAGINATION_TOTAL_COUNT, QString::number(Result.count())); this->addResponseHeader(RESPONSE_HEADER_X_PAGINATION_PAGE_COUNT, QString::number(ceil((double)Result.count() / _pageSize))); this->addResponseHeader(RESPONSE_HEADER_X_PAGINATION_CURRENT_PAGE, QString::number(_pageIndex)); @@ -181,6 +191,11 @@ TAPI::stuTable intfSQLBasedModule::SelectAllWithCount( TAPI::stuTable Result = Query.allWithCount(); + this->addResponseHeaderNameToExpose(RESPONSE_HEADER_X_PAGINATION_TOTAL_COUNT); + this->addResponseHeaderNameToExpose(RESPONSE_HEADER_X_PAGINATION_PAGE_COUNT); + this->addResponseHeaderNameToExpose(RESPONSE_HEADER_X_PAGINATION_CURRENT_PAGE); + this->addResponseHeaderNameToExpose(RESPONSE_HEADER_X_PAGINATION_PER_PAGE); + this->addResponseHeader(RESPONSE_HEADER_X_PAGINATION_TOTAL_COUNT, QString::number(Result.TotalRows)); this->addResponseHeader(RESPONSE_HEADER_X_PAGINATION_PAGE_COUNT, QString::number(ceil((double)Result.TotalRows / _pageSize))); this->addResponseHeader(RESPONSE_HEADER_X_PAGINATION_CURRENT_PAGE, QString::number(_pageIndex)); @@ -193,15 +208,12 @@ QVariant intfSQLBasedModule::Select(clsTable& _table, GET_METHOD_ARGS_IMPL_INTER { if (_pksByPath.isEmpty()) { - _reportCount = true; - -// if (_reportCount) + if (_reportCount) return this->SelectAllWithCount(_table, GET_METHOD_CALL_ARGS_INTERNAL_CALL_RAW, _extraFilters, _cacheTime, _lambda_TouchQuery) - .Rows -// .toVariant() - ; + .toVariant() + ; -// return this->SelectAll(_table, GET_METHOD_CALL_ARGS_INTERNAL_CALL_RAW, _extraFilters, _cacheTime, _lambda_TouchQuery); + return this->SelectAll(_table, GET_METHOD_CALL_ARGS_INTERNAL_CALL_RAW, _extraFilters, _cacheTime, _lambda_TouchQuery); } return this->SelectOne(_table, GET_METHOD_CALL_ARGS_INTERNAL_CALL_RAW, _extraFilters, _cacheTime, _lambda_TouchQuery); diff --git a/Interfaces/Common/intfAPIArgManipulator.h b/Interfaces/Common/intfAPIArgManipulator.h index 49bdaea5..2af61022 100644 --- a/Interfaces/Common/intfAPIArgManipulator.h +++ b/Interfaces/Common/intfAPIArgManipulator.h @@ -56,18 +56,8 @@ class intfAPIObject { virtual void invokeMethod( const QVariantList& _arguments, QGenericReturnArgument _returnArg, - /*OUT*/ QVariantMap &_responseHeaders) const = 0; - -// std::function _addResponseHeader, -// auto addResponseHeader = [&ResponseHeaders](const QString &_header, const QString &_value) -// { -// ResponseHeaders.insert(_header, _value); -// }; -//protected: -// QVariantMap responseHeaders; -//public: -// const QVariantMap getResponseHeaders() const { return this->responseHeaders; } -// void addResponseHeader(const QString &_header, const QString &_value) { this->responseHeaders.insert(_header, _value); } + /*OUT*/ QVariantMap &_responseHeaders + ) const = 0; }; /**********************************************************************/