Merge pull request #154 from an-tao/dev

Add .clang-format
This commit is contained in:
An Tao 2019-05-17 23:14:36 +08:00 committed by GitHub
commit d98a2ca519
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
144 changed files with 4923 additions and 4700 deletions

20
.clang-format Normal file
View File

@ -0,0 +1,20 @@
---
BasedOnStyle: Google
BreakBeforeBraces: Allman
AllowAllParametersOfDeclarationOnNextLine: false
IndentWidth: '4'
Language: Cpp
UseTab: Never
ColumnLimit: 128
SortIncludes: false
AllowShortFunctionsOnASingleLine: None
AllowShortBlocksOnASingleLine: false
AllowShortIfStatementsOnASingleLine: false
AllowShortLoopsOnASingleLine: false
BinPackArguments: false
BinPackParameters: false
ExperimentalAutoDetectBinPacking: false
BreakConstructorInitializersBeforeComma: false
ConstructorInitializerAllOnOneLineOrOnePerLine: true
AccessModifierOffset: -2
...

3
format.sh Executable file
View File

@ -0,0 +1,3 @@
#!/bin/sh
find lib orm_lib -name *.h -o -name *.cc|xargs clang-format -i -style=file

37
lib/inc/drogon/CacheMap.h Executable file → Normal file
View File

@ -14,17 +14,17 @@
#pragma once
#include <trantor/net/EventLoop.h>
#include <trantor/utils/Logger.h>
#include <assert.h>
#include <atomic>
#include <deque>
#include <map>
#include <mutex>
#include <deque>
#include <vector>
#include <set>
#include <trantor/net/EventLoop.h>
#include <trantor/utils/Logger.h>
#include <unordered_map>
#include <unordered_set>
#include <atomic>
#include <assert.h>
#include <vector>
#define WHEELS_NUM 4
#define BUCKET_NUM_PER_WHEEL 200
@ -35,11 +35,12 @@
namespace drogon
{
class CallbackEntry
{
public:
CallbackEntry(std::function<void()> cb) : cb_(std::move(cb)) {}
CallbackEntry(std::function<void()> cb) : cb_(std::move(cb))
{
}
~CallbackEntry()
{
cb_();
@ -69,25 +70,21 @@ class CacheMap
* number of wheels
* @param bucketsNumPerWheel
* buckets number per wheel
* The max delay of the CacheMap is about tickInterval*(bucketsNumPerWheel^wheelsNum) seconds.
* The max delay of the CacheMap is about
* tickInterval*(bucketsNumPerWheel^wheelsNum) seconds.
*/
CacheMap(trantor::EventLoop *loop,
float tickInterval = TICK_INTERVAL,
size_t wheelsNum = WHEELS_NUM,
size_t bucketsNumPerWheel = BUCKET_NUM_PER_WHEEL)
: _loop(loop),
_tickInterval(tickInterval),
_wheelsNum(wheelsNum),
_bucketsNumPerWheel(bucketsNumPerWheel)
: _loop(loop), _tickInterval(tickInterval), _wheelsNum(wheelsNum), _bucketsNumPerWheel(bucketsNumPerWheel)
{
_wheels.resize(_wheelsNum);
for (size_t i = 0; i < _wheelsNum; i++)
{
_wheels[i].resize(_bucketsNumPerWheel);
}
if (_tickInterval > 0 &&
_wheelsNum > 0 &&
_bucketsNumPerWheel > 0)
if (_tickInterval > 0 && _wheelsNum > 0 && _bucketsNumPerWheel > 0)
{
_timerId = _loop->runEvery(_tickInterval, [=]() {
_ticksCounter++;
@ -167,7 +164,10 @@ class CacheMap
}
}
void insert(const T1 &key, const T2 &value, size_t timeout = 0, std::function<void()> timeoutCallback = std::function<void()>())
void insert(const T1 &key,
const T2 &value,
size_t timeout = 0,
std::function<void()> timeoutCallback = std::function<void()>())
{
if (timeout > 0)
{
@ -338,8 +338,7 @@ class CacheMap
auto &value = _map[key];
auto entryPtr = value._weakEntryPtr.lock();
// entryPtr is used to avoid race conditions
if (value.timeout > 0 &&
!entryPtr)
if (value.timeout > 0 && !entryPtr)
{
if (value._timeoutCallback)
{

116
lib/inc/drogon/Cookie.h Executable file → Normal file
View File

@ -13,51 +13,113 @@
*/
#pragma once
#include <trantor/utils/Date.h>
#include <string>
#include <trantor/utils/Date.h>
namespace drogon
{
class Cookie
{
public:
Cookie(const std::string &key, const std::string &value)
: _key(key),
_value(value)
Cookie(const std::string &key, const std::string &value) : _key(key), _value(value)
{
}
Cookie() = default;
~Cookie() {}
void setExpiresDate(const trantor::Date &date) { _expiresDate = date; }
void setHttpOnly(bool only) { _httpOnly = only; }
void setSecure(bool secure) { _secure = secure; }
void setDomain(const std::string &domain) { _domain = domain; }
void setPath(const std::string &path) { _path = path; }
void setKey(const std::string &key) { _key = key; }
void setValue(const std::string &value) { _value = value; }
~Cookie()
{
}
void setExpiresDate(const trantor::Date &date)
{
_expiresDate = date;
}
void setHttpOnly(bool only)
{
_httpOnly = only;
}
void setSecure(bool secure)
{
_secure = secure;
}
void setDomain(const std::string &domain)
{
_domain = domain;
}
void setPath(const std::string &path)
{
_path = path;
}
void setKey(const std::string &key)
{
_key = key;
}
void setValue(const std::string &value)
{
_value = value;
}
std::string cookieString() const;
std::string getCookieString() const { return cookieString(); }
std::string getCookieString() const
{
return cookieString();
}
const trantor::Date &expiresDate() const { return _expiresDate; }
const trantor::Date &getExpiresDate() const { return _expiresDate; }
const trantor::Date &expiresDate() const
{
return _expiresDate;
}
const trantor::Date &getExpiresDate() const
{
return _expiresDate;
}
const std::string &domain() const { return _domain; }
const std::string &getDomain() const { return _domain; }
const std::string &domain() const
{
return _domain;
}
const std::string &getDomain() const
{
return _domain;
}
const std::string &path() const { return _path; }
const std::string &getPath() const { return _path; }
const std::string &path() const
{
return _path;
}
const std::string &getPath() const
{
return _path;
}
const std::string &key() const { return _key; }
const std::string &getKey() const { return _key; }
const std::string &key() const
{
return _key;
}
const std::string &getKey() const
{
return _key;
}
const std::string &value() const { return _value; }
const std::string &getValue() const { return _value; }
const std::string &value() const
{
return _value;
}
const std::string &getValue() const
{
return _value;
}
operator bool() const { return (!_key.empty()) && (!_value.empty()); }
bool isHttpOnly() const { return _httpOnly; }
bool isSecure() const { return _secure; }
operator bool() const
{
return (!_key.empty()) && (!_value.empty());
}
bool isHttpOnly() const
{
return _httpOnly;
}
bool isSecure() const
{
return _secure;
}
private:
trantor::Date _expiresDate;

23
lib/inc/drogon/DrClassMap.h Executable file → Normal file
View File

@ -14,20 +14,19 @@
#pragma once
#include <drogon/utils/ClassTraits.h>
#include <trantor/utils/Logger.h>
#include <stdio.h>
#include <unordered_map>
#include <memory>
#include <functional>
#include <thread>
#include <mutex>
#include <vector>
#include <cxxabi.h>
#include <drogon/utils/ClassTraits.h>
#include <functional>
#include <memory>
#include <mutex>
#include <stdio.h>
#include <thread>
#include <trantor/utils/Logger.h>
#include <unordered_map>
#include <vector>
namespace drogon
{
class DrObjectBase;
typedef std::function<DrObjectBase *()> DrAllocFunc;
class DrClassMap
@ -48,8 +47,8 @@ public:
{
std::size_t len = 0;
int status = 0;
std::unique_ptr<char, decltype(&std::free)> ptr(
__cxxabiv1::__cxa_demangle(mangled_name, nullptr, &len, &status), &std::free);
std::unique_ptr<char, decltype(&std::free)> ptr(__cxxabiv1::__cxa_demangle(mangled_name, nullptr, &len, &status),
&std::free);
if (status == 0)
{
return std::string(ptr.get());

12
lib/inc/drogon/DrObject.h Executable file → Normal file
View File

@ -33,7 +33,9 @@ class DrObjectBase
{
return (className() == class_name);
}
virtual ~DrObjectBase() {}
virtual ~DrObjectBase()
{
}
};
/**
@ -60,7 +62,9 @@ class DrObject : public virtual DrObjectBase
protected:
// protect constructor to make this class only inheritable
DrObject() {}
DrObject()
{
}
private:
class DrAllocator
@ -78,9 +82,7 @@ class DrObject : public virtual DrObjectBase
template <typename D>
typename std::enable_if<std::is_default_constructible<D>::value, void>::type registerClass()
{
DrClassMap::registerClass(className(), []() -> DrObjectBase * {
return new T;
});
DrClassMap::registerClass(className(), []() -> DrObjectBase * { return new T; });
}
template <typename D>
typename std::enable_if<!std::is_default_constructible<D>::value, void>::type registerClass()

5
lib/inc/drogon/DrTemplate.h Executable file → Normal file
View File

@ -18,12 +18,13 @@
#include <drogon/DrTemplateBase.h>
namespace drogon
{
template <typename T>
class DrTemplate : public DrObject<T>, public DrTemplateBase
{
protected:
DrTemplate() {}
DrTemplate()
{
}
};
} // namespace drogon

12
lib/inc/drogon/DrTemplateBase.h Executable file → Normal file
View File

@ -16,17 +16,17 @@
#include <drogon/DrObject.h>
#include <drogon/HttpViewData.h>
#include <string>
#include <memory>
#include <string>
namespace drogon
{
typedef HttpViewData DrTemplateData;
/// The templating engine class
/**
* This class can generate a text string from the template file and template data.
* This class can generate a text string from the template file and template
* data.
* For more details on the template file, see the wiki site (the 'View' section)
*/
class DrTemplateBase : public virtual DrObjectBase
@ -35,7 +35,8 @@ class DrTemplateBase : public virtual DrObjectBase
/// Create an object of the implementation class
/**
* The @param templateName represents the name of the template file.
* A template file is a description file with a special format. Its extension is
* A template file is a description file with a special format. Its extension
* is
* usually .csp. The user should preprocess the template file
* with the drogon_ctl tool to create c++ source files.
*/
@ -43,7 +44,8 @@ class DrTemplateBase : public virtual DrObjectBase
/// Generate the text string
/**
* The @param data represents data rendered in the string in a format according to the template file.
* The @param data represents data rendered in the string in a format
* according to the template file.
*/
virtual std::string genText(const DrTemplateData &data = DrTemplateData()) = 0;

258
lib/inc/drogon/HttpAppFramework.h Executable file → Normal file
View File

@ -18,34 +18,35 @@
#if USE_ORM
#include <drogon/orm/DbClient.h>
#endif
#include <drogon/utils/Utilities.h>
#include <drogon/utils/ClassTraits.h>
#include <drogon/HttpBinder.h>
#include <trantor/utils/NonCopyable.h>
#include <chrono>
#include <drogon/CacheMap.h>
#include <drogon/DrObject.h>
#include <drogon/HttpBinder.h>
#include <drogon/HttpClient.h>
#include <drogon/HttpFilter.h>
#include <drogon/HttpRequest.h>
#include <drogon/HttpResponse.h>
#include <drogon/HttpFilter.h>
#include <drogon/LocalHostFilter.h>
#include <drogon/IntranetIpFilter.h>
#include <drogon/version.h>
#include <drogon/NotFound.h>
#include <drogon/HttpClient.h>
#include <drogon/LocalHostFilter.h>
#include <drogon/MultiPart.h>
#include <drogon/NotFound.h>
#include <drogon/plugins/Plugin.h>
#include <trantor/net/EventLoop.h>
#include <drogon/CacheMap.h>
#include <drogon/utils/ClassTraits.h>
#include <drogon/utils/Utilities.h>
#include <drogon/version.h>
#include <functional>
#include <memory>
#include <string>
#include <functional>
#include <vector>
#include <trantor/net/EventLoop.h>
#include <trantor/utils/NonCopyable.h>
#include <type_traits>
#include <chrono>
#include <vector>
namespace drogon
{
// the drogon banner
const char banner[] = " _ \n"
const char banner[] =
" _ \n"
" __| |_ __ ___ __ _ ___ _ __ \n"
" / _` | '__/ _ \\ / _` |/ _ \\| '_ \\ \n"
"| (_| | | | (_) | (_| | (_) | | | |\n"
@ -81,7 +82,8 @@ public:
/// Run the event loop
/**
* Calling this method starts the IO event loops and the main loop of the application;
* Calling this method starts the IO event loops and the main loop of the
* application;
* This method MUST be called in the main thread.
* This method blocks the main thread until the main event loop exits.
*/
@ -148,19 +150,25 @@ public:
/// The @param advice is called immediately after the main event loop runs.
virtual void registerBeginningAdvice(const std::function<void()> &advice) = 0;
///The @param advice is called immediately when a new connection is established.
/// The @param advice is called immediately when a new connection is
/// established.
/**
* The first parameter of the @param advice is the remote address of the new connection, the second one
* The first parameter of the @param advice is the remote address of the new
* connection, the second one
* is the local address of it.
* If the @param advice returns a false value, drogon closes the connection.
* Users can use this advice to implement some security policies.
*/
virtual void registerNewConnectionAdvice(const std::function<bool(const trantor::InetAddress &, const trantor::InetAddress &)> &advice) = 0;
virtual void registerNewConnectionAdvice(
const std::function<bool(const trantor::InetAddress &, const trantor::InetAddress &)> &advice) = 0;
///The @param advice is called immediately after the request is created and before it matches any handler paths.
/// The @param advice is called immediately after the request is created and
/// before it matches any handler paths.
/**
* The parameters of the @param advice are same as those of the doFilter method of the Filter class.
* The following diagram shows the location of the AOP join points during http request processing.
* The parameters of the @param advice are same as those of the doFilter
* method of the Filter class.
* The following diagram shows the location of the AOP join points during http
* request processing.
*
*
* +-----------+ +------------+
@ -195,50 +203,62 @@ public:
* Post-handling join point o---------------------------------------->+
*
*/
virtual void registerPreRoutingAdvice(const std::function<void(const HttpRequestPtr &,
AdviceCallback &&,
AdviceChainCallback &&)> &advice) = 0;
virtual void registerPreRoutingAdvice(
const std::function<void(const HttpRequestPtr &, AdviceCallback &&, AdviceChainCallback &&)> &advice) = 0;
///The @param advice is called at the same time as the above advice. It can be thought of as an observer who cannot respond to http requests.
/// The @param advice is called at the same time as the above advice. It can
/// be thought of as an observer who cannot respond
/// to http requests.
/**
* This advice has less overhead than the above one.
* If one does not intend to intercept the http request, please use this interface.
* If one does not intend to intercept the http request, please use this
* interface.
*/
virtual void registerPreRoutingAdvice(const std::function<void(const HttpRequestPtr &)> &advice) = 0;
///The @param advice is called immediately after the request matchs a handler path
/// The @param advice is called immediately after the request matchs a handler
/// path
/// and before any 'doFilter' method of filters applies.
/**
* The parameters of the @param advice are same as those of the doFilter method of the Filter class.
* The parameters of the @param advice are same as those of the doFilter
* method of the Filter class.
*/
virtual void registerPostRoutingAdvice(const std::function<void(const HttpRequestPtr &,
AdviceCallback &&,
AdviceChainCallback &&)> &advice) = 0;
virtual void registerPostRoutingAdvice(
const std::function<void(const HttpRequestPtr &, AdviceCallback &&, AdviceChainCallback &&)> &advice) = 0;
///The @param advice is called at the same time as the above advice. It can be thought of as an observer who cannot respond to http requests.
/// The @param advice is called at the same time as the above advice. It can
/// be thought of as an observer who cannot respond
/// to http requests.
/**
* This advice has less overhead than the above one.
* If one does not intend to intercept the http request, please use this interface.
* If one does not intend to intercept the http request, please use this
* interface.
*/
virtual void registerPostRoutingAdvice(const std::function<void(const HttpRequestPtr &)> &advice) = 0;
///The @param advice is called immediately after the request is approved by all filters and before it is handled.
/// The @param advice is called immediately after the request is approved by
/// all filters and before it is handled.
/**
* The parameters of the @param advice are same as those of the doFilter method of the Filter class.
* The parameters of the @param advice are same as those of the doFilter
* method of the Filter class.
*/
virtual void registerPreHandlingAdvice(const std::function<void(const HttpRequestPtr &,
AdviceCallback &&,
AdviceChainCallback &&)> &advice) = 0;
virtual void registerPreHandlingAdvice(
const std::function<void(const HttpRequestPtr &, AdviceCallback &&, AdviceChainCallback &&)> &advice) = 0;
///The @param advice is called at the same time as the above advice. It can be thought of as an observer who cannot respond to http requests.
/// The @param advice is called at the same time as the above advice. It can
/// be thought of as an observer who cannot respond
/// to http requests.
/**
* This advice has less overhead than the above one.
* If one does not intend to intercept the http request, please use this interface.
* If one does not intend to intercept the http request, please use this
* interface.
*/
virtual void registerPreHandlingAdvice(const std::function<void(const HttpRequestPtr &)> &advice) = 0;
///The @param advice is called immediately after the request is handled and a response object is created by handlers.
virtual void registerPostHandlingAdvice(const std::function<void(const HttpRequestPtr &, const HttpResponsePtr &)> &advice) = 0;
/// The @param advice is called immediately after the request is handled and a
/// response object is created by handlers.
virtual void registerPostHandlingAdvice(
const std::function<void(const HttpRequestPtr &, const HttpResponsePtr &)> &advice) = 0;
/// End of AOP methods
@ -247,16 +267,20 @@ public:
/// Register a HttpSimpleController object into the framework.
/**
* @param pathName: When the path of a http request is equal to the @param pathName, the asyncHandleHttpRequest() method
* @param pathName: When the path of a http request is equal to the @param
* pathName, the asyncHandleHttpRequest() method
* of the controller is called.
* @param ctrlName is the name of the controller. It includes the namespace to which the controller belongs.
* @param filtersAndMethods is a vector containing Http methods or filter name constraints.
* @param ctrlName is the name of the controller. It includes the namespace to
* which the controller belongs.
* @param filtersAndMethods is a vector containing Http methods or filter name
* constraints.
*
* FOR EXAMPLE:
* app.registerHttpSimpleController("/userinfo","UserInfoCtrl",{Get,"LoginFilter"});
*
* NOTE:
* Users can perform the same operation through the configuration file or a macro in the header file.
* Users can perform the same operation through the configuration file or a
* macro in the header file.
*/
virtual void registerHttpSimpleController(const std::string &pathName,
const std::string &ctrlName,
@ -264,27 +288,33 @@ public:
/// Register a handler into the framework.
/**
* @param pathPattern: When the path of a http request matches the @param pathPattern, the handler indicated by
* @param pathPattern: When the path of a http request matches the @param
* pathPattern, the handler indicated by
* the @param function is called.
* @param function indicates any type of callable object with a valid processing interface.
* @param filtersAndMethods is the same as the third parameter in the above method.
* @param function indicates any type of callable object with a valid
* processing interface.
* @param filtersAndMethods is the same as the third parameter in the above
* method.
*
* FOR EXAMPLE:
* app.registerHandler("/hello?username={1}",
* [](const HttpRequestPtr& req,
* const std::function<void (const HttpResponsePtr &)> & callback,
* const std::function<void (const HttpResponsePtr &)>
* & callback,
* const std::string &name)
* {
* Json::Value json;
* json["result"]="ok";
* json["message"]=std::string("hello,")+name;
* auto resp=HttpResponse::newHttpJsonResponse(json);
* auto
* resp=HttpResponse::newHttpJsonResponse(json);
* callback(resp);
* },
* {Get,"LoginFilter"});
*
* NOTE:
* As you can see in the above example, this method supports parameters mapping.
* As you can see in the above example, this method supports parameters
* mapping.
*/
template <typename FUNCTION>
void registerHandler(const std::string &pathPattern,
@ -295,8 +325,7 @@ public:
LOG_TRACE << "pathPattern:" << pathPattern;
internal::HttpBinderBasePtr binder;
binder = std::make_shared<
internal::HttpBinder<FUNCTION>>(std::forward<FUNCTION>(function));
binder = std::make_shared<internal::HttpBinder<FUNCTION>>(std::forward<FUNCTION>(function));
std::vector<HttpMethod> validMethods;
std::vector<std::string> filters;
@ -325,19 +354,23 @@ public:
}
/// Register a WebSocketController into the framework.
/// The parameters of this method are the same as those in the registerHttpSimpleController() method.
/// The parameters of this method are the same as those in the
/// registerHttpSimpleController() method.
virtual void registerWebSocketController(const std::string &pathName,
const std::string &crtlName,
const std::vector<std::string> &filters =
std::vector<std::string>()) = 0;
const std::vector<std::string> &filters = std::vector<std::string>()) = 0;
/// Register controller objects created and initialized by the user
/**
* Drogon can only automatically create controllers using the default constructor.
* Sometimes users want to be able to create controllers using constructors with
* parameters. Controllers created by user in this way should be registered to the framework
* Drogon can only automatically create controllers using the default
* constructor.
* Sometimes users want to be able to create controllers using constructors
* with
* parameters. Controllers created by user in this way should be registered to
* the framework
* via this method.
* The macro or configuration file is still valid for the path routing configuration
* The macro or configuration file is still valid for the path routing
* configuration
* of the controller created by users.
*
* NOTE:
@ -348,7 +381,8 @@ public:
* ApiTest(const std::string &str);
* ...
* };
* The second template parameter must be explicitly set to false to disable automatic creation.
* The second template parameter must be explicitly set to false to disable
* automatic creation.
* And then user can create and register it somewhere as follows:
* auto ctrlPtr=std::make_shared<ApiTest>("hello world");
* drogon::app().registerController(ctrlPtr);
@ -361,7 +395,10 @@ public:
internal::IsSubClass<T, HttpSimpleControllerBase>::value ||
internal::IsSubClass<T, WebSocketControllerBase>::value,
"Error! Only controller objects can be registered here");
static_assert(!T::isAutoCreation, "Controllers created and initialized automatically by drogon cannot be registered here");
static_assert(!T::isAutoCreation,
"Controllers created and initialized "
"automatically by drogon cannot be "
"registered here");
DrClassMap::setSingleInstance(ctrlPtr);
T::initPathRouting();
}
@ -373,15 +410,18 @@ public:
template <typename T>
void registerFilter(const std::shared_ptr<T> &filterPtr)
{
static_assert(internal::IsSubClass<T, HttpFilterBase>::value,
"Error! Only fitler objects can be registered here");
static_assert(!T::isAutoCreation, "Filters created and initialized automatically by drogon cannot be registered here");
static_assert(internal::IsSubClass<T, HttpFilterBase>::value, "Error! Only fitler objects can be registered here");
static_assert(!T::isAutoCreation,
"Filters created and initialized "
"automatically by drogon cannot be "
"registered here");
DrClassMap::setSingleInstance(filterPtr);
}
/// Forward the http request
/**
* The @param hostString is the address where the request is forwarded. The following strings are
* The @param hostString is the address where the request is forwarded. The
* following strings are
* valid for the @param hostString:
*
* https://www.baidu.com
@ -391,16 +431,22 @@ public:
* http://[::1]:8080/
*
* NOTE:
* If the @param hostString is empty, the request is handled by the same application, so in this condition
* one should modify the path of the @param req before forwarding to avoid infinite loop processing.
* If the @param hostString is empty, the request is handled by the same
* application, so in this condition
* one should modify the path of the @param req before forwarding to avoid
* infinite loop processing.
*
* This method can be used to implement reverse proxy or redirection on the server side.
* This method can be used to implement reverse proxy or redirection on the
* server side.
*/
virtual void forward(const HttpRequestPtr &req, std::function<void(const HttpResponsePtr &)> &&callback, const std::string &hostString = "") = 0;
virtual void forward(const HttpRequestPtr &req,
std::function<void(const HttpResponsePtr &)> &&callback,
const std::string &hostString = "") = 0;
/// Get information about the handlers registered to drogon
/**
* The first item of std::tuple in the return value represents the path pattern of the handler;
* The first item of std::tuple in the return value represents the path
* pattern of the handler;
* The last item in std::tuple is the description of the handler.
*/
virtual std::vector<std::tuple<std::string, HttpMethod, std::string>> getHandlersInfo() const = 0;
@ -410,7 +456,8 @@ public:
/// Set the number of threads for IO event loops
/**
* The default value is 1, if @param threadNum is 0, the number is equal to the number of CPU cores.
* The default value is 1, if @param threadNum is 0, the number is equal to
* the number of CPU cores.
*
* NOTE:
* This number is usually less than or equal to the number of CPU cores.
@ -423,15 +470,15 @@ public:
/// Set the global cert file and private key file for https
/// These options can be configured in the configuration file.
virtual void setSSLFiles(const std::string &certPath,
const std::string &keyPath) = 0;
virtual void setSSLFiles(const std::string &certPath, const std::string &keyPath) = 0;
/// Add a listener for http or https service
/**
* @param ip is the ip that the listener listens on.
* @param port is the port that the listener listens on.
* If @param useSSL is true, the listener is used for the https service.
* @param certFile and @param keyFile specify the cert file and the private key file for this listener. If
* @param certFile and @param keyFile specify the cert file and the private
* key file for this listener. If
* they are empty, the global configuration set by the above method is used.
*
* NOTE:
@ -485,7 +532,8 @@ public:
/// Set the path to store uploaded files.
/**
* If the @param uploadPath isn't prefixed with /, ./ or ../, it is relative path of document_root path,
* If the @param uploadPath isn't prefixed with /, ./ or ../, it is relative
* path of document_root path,
* The default value is 'uploads'.
*
* NOTE:
@ -565,25 +613,30 @@ public:
/// Set the log level
/**
* The @param level is one of TRACE, DEBUG, INFO, WARN. The Default value is DEBUG.
* The @param level is one of TRACE, DEBUG, INFO, WARN. The Default value is
* DEBUG.
*
* NOTE:
* This operation can be performed by an option in the configuration file.
*/
virtual void setLogLevel(trantor::Logger::LogLevel level) = 0;
///If @param sendFile is true, sendfile() system-call is used to send static files to clients;
/// If @param sendFile is true, sendfile() system-call is used to send static
/// files to clients;
/**
* The default value is true.
*
* NOTE:
* This operation can be performed by an option in the configuration file.
* Even though sendfile() is enabled, only files larger than 200k are sent this way,
* because the advantages of sendfile() can only be reflected in sending large files.
* Even though sendfile() is enabled, only files larger than 200k are sent
* this way,
* because the advantages of sendfile() can only be reflected in sending large
* files.
*/
virtual void enableSendfile(bool sendFile) = 0;
///If @param useGzip is true, use gzip to compress the response body's content;
/// If @param useGzip is true, use gzip to compress the response body's
/// content;
/**
* The default value is true.
*
@ -600,7 +653,8 @@ public:
/// Set the time in which the static file response is cached in memory.
/**
* @param cacheTime: in seconds. 0 means always cached, negative means no cache
* @param cacheTime: in seconds. 0 means always cached, negative means no
* cache
*
* NOTE:
* This operation can be performed by an option in the configuration file.
@ -612,7 +666,8 @@ public:
/// Set the lifetime of the connection without read or write
/**
* @param timeout: in seconds. 60 by default. Setting the timeout to 0 means that drogon does not close idle connections.
* @param timeout: in seconds. 60 by default. Setting the timeout to 0 means
* that drogon does not close idle connections.
*
* NOTE:
* This operation can be performed by an option in the configuration file.
@ -632,7 +687,8 @@ public:
/// Set the 'server' header field in each response sent by drogon.
/**
* @param server: empty string by default with which the 'server' header field is
* @param server: empty string by default with which the 'server' header field
* is
* set to "Server: drogon/version string\r\n"
*
* NOTE:
@ -640,9 +696,11 @@ public:
*/
virtual void setServerHeaderField(const std::string &server) = 0;
///Set the maximum number of requests that can be served through one keep-alive connection.
/// Set the maximum number of requests that can be served through one
/// keep-alive connection.
/**
* After the maximum number of requests are made, the connection is closed. The default value is
* After the maximum number of requests are made, the connection is closed.
* The default value is
* 0 which means no limit.
*
* NOTE:
@ -650,10 +708,12 @@ public:
*/
virtual void setKeepaliveRequestsNumber(const size_t number) = 0;
///Set the maximum number of unhandled requests that can be cached in pipelining buffer.
/// Set the maximum number of unhandled requests that can be cached in
/// pipelining buffer.
/**
* The default value of 0 means no limit.
* After the maximum number of requests cached in pipelining buffer are made, the connection is closed.
* After the maximum number of requests cached in pipelining buffer are made,
* the connection is closed.
*
* NOTE:
* This operation can be performed by an option in the configuration file.
@ -662,8 +722,10 @@ public:
/// Set the gzip_static option.
/**
* If it is set to true, when the client requests a static file, drogon first finds the compressed
* file with the extension ".gz" in the same path and send the compressed file to the client.
* If it is set to true, when the client requests a static file, drogon first
* finds the compressed
* file with the extension ".gz" in the same path and send the compressed file
* to the client.
* The default value is true.
*
* NOTE:
@ -671,14 +733,16 @@ public:
*/
virtual void setGzipStatic(bool useGzipStatic) = 0;
///Set the max body size of the requests received by drogon. The default value is 1M.
/// Set the max body size of the requests received by drogon. The default
/// value is 1M.
/**
* NOTE:
* This operation can be performed by an option in the configuration file.
*/
virtual void setClientMaxBodySize(size_t maxSize) = 0;
///Set the max size of messages sent by WebSocket client. The default value is 128K.
/// Set the max size of messages sent by WebSocket client. The default value
/// is 128K.
/**
* NOTE:
* This operation can be performed by an option in the configuration file.
@ -687,7 +751,8 @@ public:
// Set the HTML file of the home page, the default value is "index.html"
/**
* If there isn't any handler registered to the path "/", the home page file in the "document_root"
* If there isn't any handler registered to the path "/", the home page file
* in the "document_root"
* is send to clients as a response to the request for "/".
* NOTE:
* This operation can be performed by an option in the configuration file.
@ -715,7 +780,8 @@ public:
* @param host: IP or host name.
* @param port: The port on which the database server is listening.
* @databaseName, @param userName, @param password: ...
* @connectionNum: The number of connections to the database server. It's valid only if @param isFast is false.
* @connectionNum: The number of connections to the database server. It's
* valid only if @param isFast is false.
* @filename: The file name of sqlite3 database file.
* @name: The client name.
* @isFast: Indicates if the client is a fast database client.

67
lib/inc/drogon/HttpBinder.h Executable file → Normal file
View File

@ -14,15 +14,15 @@
#pragma once
#include <drogon/DrClassMap.h>
#include <drogon/DrObject.h>
#include <drogon/HttpRequest.h>
#include <drogon/HttpResponse.h>
#include <drogon/utils/FunctionTraits.h>
#include <drogon/DrClassMap.h>
#include <drogon/DrObject.h>
#include <list>
#include <string>
#include <sstream>
#include <memory>
#include <sstream>
#include <string>
/// The classes in the file are internal tool classes. Do not include this
/// file directly and use any of these classes directly.
@ -31,8 +31,8 @@ namespace drogon
{
namespace internal
{
//we only accept value type or const lreference type or right reference type as the handle method parameters type
// we only accept value type or const lreference type or right reference type as
// the handle method parameters type
template <typename T>
struct BinderArgTypeTraits
{
@ -68,17 +68,22 @@ class HttpBinderBase
{
public:
virtual void handleHttpRequest(std::list<std::string> &pathParameter,
const HttpRequestPtr &req, std::function<void(const HttpResponsePtr &)> &&callback) = 0;
const HttpRequestPtr &req,
std::function<void(const HttpResponsePtr &)> &&callback) = 0;
virtual size_t paramCount() = 0;
virtual const std::string &handlerName() const = 0;
virtual ~HttpBinderBase() {}
virtual ~HttpBinderBase()
{
}
};
template <typename T>
T &getControllerObj()
{
//Initialization of function-local statics is guaranteed to occur only once even when
//called from multiple threads, and may be more efficient than the equivalent code using std::call_once.
// Initialization of function-local statics is guaranteed to occur only once
// even when
// called from multiple threads, and may be more efficient than the equivalent
// code using std::call_once.
static T obj;
return obj;
}
@ -90,7 +95,8 @@ class HttpBinder : public HttpBinderBase
public:
typedef FUNCTION FunctionType;
virtual void handleHttpRequest(std::list<std::string> &pathParameter,
const HttpRequestPtr &req, std::function<void(const HttpResponsePtr &)> &&callback) override
const HttpRequestPtr &req,
std::function<void(const HttpResponsePtr &)> &&callback) override
{
run(pathParameter, req, std::move(callback));
}
@ -121,17 +127,20 @@ private:
static const size_t argument_count = traits::arity;
std::string _handlerName;
template <typename... Values,
std::size_t Boundary = argument_count>
template <typename... Values, std::size_t Boundary = argument_count>
typename std::enable_if<(sizeof...(Values) < Boundary), void>::type run(
std::list<std::string> &pathParameter,
const HttpRequestPtr &req, std::function<void(const HttpResponsePtr &)> &&callback,
const HttpRequestPtr &req,
std::function<void(const HttpResponsePtr &)> &&callback,
Values &&... values)
{
//call this function recursively until parameter's count equals to the count of target function parameters
// call this function recursively until parameter's count equals to the
// count of target function parameters
static_assert(BinderArgTypeTraits<nth_argument_type<sizeof...(Values)>>::isValid,
"your handler argument type must be value type or const left reference type or right reference type");
typedef typename std::remove_cv<typename std::remove_reference<nth_argument_type<sizeof...(Values)>>::type>::type ValueType;
"your handler argument type must be value type or const left reference "
"type or right reference type");
typedef
typename std::remove_cv<typename std::remove_reference<nth_argument_type<sizeof...(Values)>>::type>::type ValueType;
ValueType value = ValueType();
if (!pathParameter.empty())
{
@ -146,12 +155,11 @@ private:
run(pathParameter, req, std::move(callback), std::forward<Values>(values)..., std::move(value));
}
template <
typename... Values,
std::size_t Boundary = argument_count>
template <typename... Values, std::size_t Boundary = argument_count>
typename std::enable_if<(sizeof...(Values) == Boundary), void>::type run(
std::list<std::string> &pathParameter,
const HttpRequestPtr &req, std::function<void(const HttpResponsePtr &)> &&callback,
const HttpRequestPtr &req,
std::function<void(const HttpResponsePtr &)> &&callback,
Values &&... values)
{
callFunction(req, std::move(callback), std::move(values)...);
@ -159,9 +167,8 @@ private:
template <typename... Values,
bool isClassFunction = traits::isClassFunction,
bool isDrObjectClass = traits::isDrObjectClass>
typename std::enable_if<isClassFunction && !isDrObjectClass, void>::type callFunction(
const HttpRequestPtr &req, std::function<void(const HttpResponsePtr &)> &&callback,
Values &&... values)
typename std::enable_if<isClassFunction && !isDrObjectClass, void>::type
callFunction(const HttpRequestPtr &req, std::function<void(const HttpResponsePtr &)> &&callback, Values &&... values)
{
static auto &obj = getControllerObj<typename traits::class_type>();
(obj.*_func)(req, std::move(callback), std::move(values)...);
@ -169,17 +176,15 @@ private:
template <typename... Values,
bool isClassFunction = traits::isClassFunction,
bool isDrObjectClass = traits::isDrObjectClass>
typename std::enable_if<isClassFunction && isDrObjectClass, void>::type callFunction(
const HttpRequestPtr &req, std::function<void(const HttpResponsePtr &)> &&callback,
Values &&... values)
typename std::enable_if<isClassFunction && isDrObjectClass, void>::type
callFunction(const HttpRequestPtr &req, std::function<void(const HttpResponsePtr &)> &&callback, Values &&... values)
{
static auto objPtr = DrClassMap::getSingleInstance<typename traits::class_type>();
(*objPtr.*_func)(req, std::move(callback), std::move(values)...);
};
template <typename... Values,
bool isClassFunction = traits::isClassFunction>
typename std::enable_if<!isClassFunction, void>::type callFunction(
const HttpRequestPtr &req, std::function<void(const HttpResponsePtr &)> &&callback,
template <typename... Values, bool isClassFunction = traits::isClassFunction>
typename std::enable_if<!isClassFunction, void>::type callFunction(const HttpRequestPtr &req,
std::function<void(const HttpResponsePtr &)> &&callback,
Values &&... values)
{
_func(req, std::move(callback), std::move(values)...);

View File

@ -17,13 +17,12 @@
#include <drogon/HttpRequest.h>
#include <drogon/HttpResponse.h>
#include <drogon/HttpTypes.h>
#include <trantor/utils/NonCopyable.h>
#include <trantor/net/EventLoop.h>
#include <functional>
#include <memory>
#include <trantor/net/EventLoop.h>
#include <trantor/utils/NonCopyable.h>
namespace drogon
{
class HttpClient;
typedef std::shared_ptr<HttpClient> HttpClientPtr;
@ -31,14 +30,17 @@ typedef std::function<void(ReqResult, const HttpResponsePtr &)> HttpReqCallback;
/// Asynchronous http client
/**
* HttpClient implementation object uses the HttpAppFramework's event loop by default,
* HttpClient implementation object uses the HttpAppFramework's event loop by
* default,
* so you should call app().run() to make the client work.
* Each HttpClient object establishes a persistent connection with the server.
* If the connection is broken, the client attempts to reconnect
* when calling the sendRequest method.
*
* Using the static mathod newHttpClient(...) to get shared_ptr of the object implementing
* the class, the shared_ptr is retained in the framework until all response callbacks
* Using the static mathod newHttpClient(...) to get shared_ptr of the object
* implementing
* the class, the shared_ptr is retained in the framework until all response
* callbacks
* are invoked without fear of accidental deconstruction.
*
* TODO:SSL server verification
@ -54,9 +56,11 @@ class HttpClient : public trantor::NonCopyable
virtual void sendRequest(const HttpRequestPtr &req, const HttpReqCallback &callback) = 0;
virtual void sendRequest(const HttpRequestPtr &req, HttpReqCallback &&callback) = 0;
/// Set the pipelining depth, which is the number of requests that are not responding.
/// Set the pipelining depth, which is the number of requests that are not
/// responding.
/**
* If this method is not called, the default depth value is 0 which means the pipelining is disabled.
* If this method is not called, the default depth value is 0 which means the
* pipelining is disabled.
* For details about pipelining, see rfc2616-8.1.2.2
*/
virtual void setPipeliningDepth(size_t depth) = 0;
@ -101,10 +105,11 @@ class HttpClient : public trantor::NonCopyable
* the sendRequest() method.
*
*/
static HttpClientPtr newHttpClient(const std::string &hostString,
trantor::EventLoop *loop = nullptr);
static HttpClientPtr newHttpClient(const std::string &hostString, trantor::EventLoop *loop = nullptr);
virtual ~HttpClient() {}
virtual ~HttpClient()
{
}
protected:
HttpClient() = default;

32
lib/inc/drogon/HttpController.h Executable file → Normal file
View File

@ -16,22 +16,20 @@
#include <drogon/DrObject.h>
#include <drogon/HttpAppFramework.h>
#include <trantor/utils/Logger.h>
#include <string>
#include <vector>
#include <iostream>
#include <string>
#include <trantor/utils/Logger.h>
#include <vector>
/// For more details on the class, see the wiki site (the 'HttpController' section)
/// For more details on the class, see the wiki site (the 'HttpController'
/// section)
#define METHOD_LIST_BEGIN \
static void initPathRouting() \
{
#define METHOD_ADD(method, pattern, filters...) registerMethod(&method, pattern, {filters}, true, #method)
#define METHOD_ADD(method, pattern, filters...) \
registerMethod(&method, pattern, {filters}, true, #method)
#define ADD_METHOD_TO(method, path_pattern, filters...) \
registerMethod(&method, path_pattern, {filters}, false, #method)
#define ADD_METHOD_TO(method, path_pattern, filters...) registerMethod(&method, path_pattern, {filters}, false, #method)
#define METHOD_LIST_END \
return; \
@ -39,7 +37,6 @@
namespace drogon
{
class HttpControllerBase
{
};
@ -71,15 +68,9 @@ class HttpController : public DrObject<T>, public HttpControllerBase
path.replace(pos, 2, "/");
}
if (pattern.empty() || pattern[0] == '/')
app().registerHandler(path + pattern,
std::forward<FUNCTION>(function),
filtersAndMethods,
handlerName);
app().registerHandler(path + pattern, std::forward<FUNCTION>(function), filtersAndMethods, handlerName);
else
app().registerHandler(path + "/" + pattern,
std::forward<FUNCTION>(function),
filtersAndMethods,
handlerName);
app().registerHandler(path + "/" + pattern, std::forward<FUNCTION>(function), filtersAndMethods, handlerName);
}
else
{
@ -88,10 +79,7 @@ class HttpController : public DrObject<T>, public HttpControllerBase
{
path = "/" + path;
}
app().registerHandler(path,
std::forward<FUNCTION>(function),
filtersAndMethods,
handlerName);
app().registerHandler(path, std::forward<FUNCTION>(function), filtersAndMethods, handlerName);
}
}

23
lib/inc/drogon/HttpFilter.h Executable file → Normal file
View File

@ -15,8 +15,8 @@
#pragma once
#include <drogon/DrObject.h>
#include <drogon/HttpResponse.h>
#include <drogon/HttpRequest.h>
#include <drogon/HttpResponse.h>
#include <memory>
/// For more details on the class, see the wiki site (the 'Filter' section)
@ -30,23 +30,28 @@ class HttpFilterBase : public virtual DrObjectBase
public:
/// This virtual function should be overrided in subclasses.
/**
* This method is an asynchronous interface, user should return the result via 'FilterCallback'
* This method is an asynchronous interface, user should return the result via
* 'FilterCallback'
* or 'FilterChainCallback'.
* If @param fcb is called, the response object is send to the client by the callback,
* and doFilter methods of next filters and the handler registed on the path are not called anymore.
* If @param fcb is called, the response object is send to the client by the
* callback,
* and doFilter methods of next filters and the handler registed on the path
* are not called anymore.
* If @param fccb is called, the next filter's doFilter method or the handler
* registered on the path is called.
*/
virtual void doFilter(const HttpRequestPtr &req,
FilterCallback &&fcb,
FilterChainCallback &&fccb) = 0;
virtual ~HttpFilterBase() {}
virtual void doFilter(const HttpRequestPtr &req, FilterCallback &&fcb, FilterChainCallback &&fccb) = 0;
virtual ~HttpFilterBase()
{
}
};
template <typename T, bool AutoCreation = true>
class HttpFilter : public DrObject<T>, public HttpFilterBase
{
public:
static const bool isAutoCreation = AutoCreation;
virtual ~HttpFilter() {}
virtual ~HttpFilter()
{
}
};
} // namespace drogon

109
lib/inc/drogon/HttpRequest.h Executable file → Normal file
View File

@ -17,16 +17,15 @@
#include <drogon/HttpTypes.h>
#include <drogon/Session.h>
#include <drogon/UploadFile.h>
#include <json/json.h>
#include <memory>
#include <string>
#include <trantor/net/InetAddress.h>
#include <trantor/utils/Date.h>
#include <json/json.h>
#include <unordered_map>
#include <string>
#include <memory>
namespace drogon
{
class HttpRequest;
typedef std::shared_ptr<HttpRequest> HttpRequestPtr;
@ -42,11 +41,17 @@ public:
};
/// Return the method string of the request, such as GET, POST, etc.
virtual const char *methodString() const = 0;
const char *getMethodString() const { return methodString(); }
const char *getMethodString() const
{
return methodString();
}
/// Return the enum type method of the request.
virtual HttpMethod method() const = 0;
HttpMethod getMethod() const { return method(); }
HttpMethod getMethod() const
{
return method();
}
/// Get the header string identified by the @param field
virtual const std::string &getHeader(const std::string &field, const std::string &defaultVal = std::string()) const = 0;
@ -60,31 +65,52 @@ public:
/// Get all headers of the request
virtual const std::unordered_map<std::string, std::string> &headers() const = 0;
const std::unordered_map<std::string, std::string> &getHeaders() const { return headers(); }
const std::unordered_map<std::string, std::string> &getHeaders() const
{
return headers();
}
/// Get all cookies of the request
virtual const std::unordered_map<std::string, std::string> &cookies() const = 0;
const std::unordered_map<std::string, std::string> &getCookies() const { return cookies(); }
const std::unordered_map<std::string, std::string> &getCookies() const
{
return cookies();
}
/// Get the query string of the request.
/**
* If the http method is GET, the query string is the substring after the '?' in the URL string.
* If the http method is POST, the query string is the content(body) string of the HTTP request.
* If the http method is GET, the query string is the substring after the '?'
* in the URL string.
* If the http method is POST, the query string is the content(body) string of
* the HTTP request.
*/
virtual const std::string &query() const = 0;
const std::string &getQuery() const { return query(); }
const std::string &getQuery() const
{
return query();
}
/// Get the content string of the request, which is the body part of the request.
/// Get the content string of the request, which is the body part of the
/// request.
virtual const std::string &body() const = 0;
const std::string &getBody() const { return body(); }
const std::string &getBody() const
{
return body();
}
/// Get the path of the request.
virtual const std::string &path() const = 0;
const std::string &getPath() const { return path(); }
const std::string &getPath() const
{
return path();
}
/// Get the matched path pattern after routing
virtual const string_view &matchedPathPattern() const = 0;
const string_view &getMatchedPathPattern() const { return matchedPathPattern(); }
const string_view &getMatchedPathPattern() const
{
return matchedPathPattern();
}
/// Return the enum type version of the request.
/**
@ -92,30 +118,48 @@ public:
* kHttp11 means Http verison is 1.1
*/
virtual Version version() const = 0;
Version getVersion() const { return version(); }
Version getVersion() const
{
return version();
}
/// Get the session to which the request belongs.
virtual SessionPtr session() const = 0;
SessionPtr getSession() const { return session(); }
SessionPtr getSession() const
{
return session();
}
/// Get parameters of the request.
virtual const std::unordered_map<std::string, std::string> &parameters() const = 0;
const std::unordered_map<std::string, std::string> &getParameters() const { return parameters(); }
const std::unordered_map<std::string, std::string> &getParameters() const
{
return parameters();
}
/// Get a parameter identified by the @param key
virtual const std::string &getParameter(const std::string &key, const std::string &defaultVal = std::string()) const = 0;
/// Return the remote IP address and port
virtual const trantor::InetAddress &peerAddr() const = 0;
const trantor::InetAddress &getPeerAddr() const { return peerAddr(); }
const trantor::InetAddress &getPeerAddr() const
{
return peerAddr();
}
/// Return the local IP address and port
virtual const trantor::InetAddress &localAddr() const = 0;
const trantor::InetAddress &getLocalAddr() const { return localAddr(); }
const trantor::InetAddress &getLocalAddr() const
{
return localAddr();
}
/// Return the creation timestamp set by the framework.
virtual const trantor::Date &creationDate() const = 0;
const trantor::Date &getCreationDate() const { return creationDate(); }
const trantor::Date &getCreationDate() const
{
return creationDate();
}
/// Get the Json object of the request
/**
@ -123,11 +167,17 @@ public:
* the method returns an empty object.
*/
virtual const std::shared_ptr<Json::Value> jsonObject() const = 0;
const std::shared_ptr<Json::Value> getJsonObject() const { return jsonObject(); }
const std::shared_ptr<Json::Value> getJsonObject() const
{
return jsonObject();
}
/// Get the content type
virtual ContentType contentType() const = 0;
ContentType getContentType() const { return contentType(); }
ContentType getContentType() const
{
return contentType();
}
/// Set the Http method
virtual void setMethod(const HttpMethod method) = 0;
@ -141,7 +191,8 @@ public:
/// Set or get the content type
virtual void setContentTypeCode(const ContentType type) = 0;
/// The following methods are a series of factory methods that help users create request objects.
/// The following methods are a series of factory methods that help users
/// create request objects.
/// Create a normal request with http method Get and version Http1.1.
static HttpRequestPtr newHttpRequest();
@ -149,7 +200,8 @@ public:
/// Create a http request with:
/// Method: Get
/// Version: Http1.1
/// Content type: application/json, the @param data is serialized into the content of the request.
/// Content type: application/json, the @param data is serialized into the
/// content of the request.
static HttpRequestPtr newHttpJsonRequest(const Json::Value &data);
/// Create a http request with:
@ -162,10 +214,13 @@ public:
/// Method: Post
/// Version: Http1.1
/// Content type: multipart/form-data
/// The @param files represents pload files which are transferred to the server via the multipart/form-data format
/// The @param files represents pload files which are transferred to the
/// server via the multipart/form-data format
static HttpRequestPtr newFileUploadRequest(const std::vector<UploadFile> &files);
virtual ~HttpRequest() {}
virtual ~HttpRequest()
{
}
};
} // namespace drogon

93
lib/inc/drogon/HttpResponse.h Executable file → Normal file
View File

@ -13,12 +13,12 @@
#pragma once
#include <drogon/HttpViewData.h>
#include <drogon/Cookie.h>
#include <drogon/HttpTypes.h>
#include <drogon/HttpViewData.h>
#include <json/json.h>
#include <string>
#include <memory>
#include <string>
namespace drogon
{
@ -33,36 +33,49 @@ public:
}
/// Get the status code such as 200, 404
virtual HttpStatusCode statusCode() const = 0;
HttpStatusCode getStatusCode() const { return statusCode(); }
HttpStatusCode getStatusCode() const
{
return statusCode();
}
/// Set the status code of the response.
virtual void setStatusCode(HttpStatusCode code) = 0;
/// Get the creation timestamp of the response.
virtual const trantor::Date &creationDate() const = 0;
const trantor::Date &getCreationDate() const { return creationDate(); }
const trantor::Date &getCreationDate() const
{
return creationDate();
}
/// Set the http version, http1.0 or http1.1
virtual void setVersion(const Version v) = 0;
/// If @param on is false, the connection keeps alive on the condition that the client request has a
// 'keep-alive' head, otherwise it is closed immediately after sending the last byte of the response.
/// If @param on is false, the connection keeps alive on the condition that
/// the client request has a
// 'keep-alive' head, otherwise it is closed immediately after sending the
// last byte of the response.
// It's false by default when the response is created.
virtual void setCloseConnection(bool on) = 0;
/// Get the status set by the setCloseConnetion() method.
virtual bool ifCloseConnection() const = 0;
/// Set the reponse content type, such as text/html, text/plaint, image/png and so on. If the content type
/// Set the reponse content type, such as text/html, text/plaint, image/png
/// and so on. If the content type
/// is a text type, the character set is utf8.
virtual void setContentTypeCode(ContentType type) = 0;
/// Set the reponse content type and the character set.
/// virtual void setContentTypeCodeAndCharacterSet(ContentType type, const std::string &charSet = "utf-8") = 0;
/// virtual void setContentTypeCodeAndCharacterSet(ContentType type, const
/// std::string &charSet = "utf-8") = 0;
/// Get the response content type.
virtual ContentType contentType() const = 0;
ContentType getContentType() const { return contentType(); }
ContentType getContentType() const
{
return contentType();
}
/// Get the header string identified by the @param key.
/// If there is no the header, the @param defaultVal is retured.
@ -76,7 +89,10 @@ public:
/// Get all headers of the response
virtual const std::unordered_map<std::string, std::string> &headers() const = 0;
const std::unordered_map<std::string, std::string> &getHeaders() const { return headers(); }
const std::unordered_map<std::string, std::string> &getHeaders() const
{
return headers();
}
/// Add a header.
virtual void addHeader(const std::string &key, const std::string &value) = 0;
@ -92,20 +108,30 @@ public:
/// Get all cookies.
virtual const std::unordered_map<std::string, Cookie> &cookies() const = 0;
const std::unordered_map<std::string, Cookie> &getCookies() const { return cookies(); }
const std::unordered_map<std::string, Cookie> &getCookies() const
{
return cookies();
}
/// Remove the cookie identified by the @param key.
virtual void removeCookie(const std::string &key) = 0;
/// Set the response body(content). The @param body must match the content type
/// Set the response body(content). The @param body must match the content
/// type
virtual void setBody(const std::string &body) = 0;
virtual void setBody(std::string &&body) = 0;
/// Get the response body.
virtual const std::string &body() const = 0;
const std::string &getBody() const { return body(); }
const std::string &getBody() const
{
return body();
}
virtual std::string &body() = 0;
std::string &getBody() { return body(); }
std::string &getBody()
{
return body();
}
/// Reset the reponse object to its initial state
virtual void clear() = 0;
@ -116,36 +142,53 @@ public:
/// Get the expiration time of the response.
virtual ssize_t expiredTime() const = 0;
ssize_t getExpiredTime() const { return expiredTime(); }
ssize_t getExpiredTime() const
{
return expiredTime();
}
/// Get the json object from the server response.
/// If the response is not in json format, then a empty shared_ptr is retured.
virtual const std::shared_ptr<Json::Value> jsonObject() const = 0;
const std::shared_ptr<Json::Value> getJsonObject() const { return jsonObject(); }
const std::shared_ptr<Json::Value> getJsonObject() const
{
return jsonObject();
}
/// The following methods are a series of factory methods that help users create response objects.
/// The following methods are a series of factory methods that help users
/// create response objects.
/// Create a normal response with a status code of 200ok and a content type of text/html.
/// Create a normal response with a status code of 200ok and a content type of
/// text/html.
static HttpResponsePtr newHttpResponse();
/// Create a response which returns a 404 page.
static HttpResponsePtr newNotFoundResponse();
/// Create a response which returns a json object. Its content type is set to set/json.
/// Create a response which returns a json object. Its content type is set to
/// set/json.
static HttpResponsePtr newHttpJsonResponse(const Json::Value &data);
/// Create a response that returns a page rendered by a view named @param viewName.
/// Create a response that returns a page rendered by a view named @param
/// viewName.
/// @param data is the data displayed on the page.
/// For more details, see the wiki pages, the "View" section.
static HttpResponsePtr newHttpViewResponse(const std::string &viewName, const HttpViewData &data = HttpViewData());
/// Create a response that returns a 302 Found page, redirecting to another page located in the @param location.
/// Create a response that returns a 302 Found page, redirecting to another
/// page located in the @param location.
static HttpResponsePtr newRedirectionResponse(const std::string &location);
/// Create a response that returns a file to the client.
/**
* @param fullPath is the full path to the file.
* If @param attachmentFileName is not empty, the browser does not open the file, but saves it as an attachment.
* If the @param type is CT_NONE, the content type is set by drogon based on the file extension.
* If @param attachmentFileName is not empty, the browser does not open the
* file, but saves it as an attachment.
* If the @param type is CT_NONE, the content type is set by drogon based on
* the file extension.
*/
static HttpResponsePtr newFileResponse(const std::string &fullPath, const std::string &attachmentFileName = "", ContentType type = CT_NONE);
static HttpResponsePtr newFileResponse(const std::string &fullPath,
const std::string &attachmentFileName = "",
ContentType type = CT_NONE);
virtual ~HttpResponse() {}
virtual ~HttpResponse()
{
}
};
} // namespace drogon

26
lib/inc/drogon/HttpSimpleController.h Executable file → Normal file
View File

@ -16,26 +16,25 @@
#include <drogon/DrObject.h>
#include <drogon/HttpAppFramework.h>
#include <trantor/utils/Logger.h>
#include <string>
#include <vector>
#include <iostream>
#include <string>
#include <trantor/utils/Logger.h>
#include <vector>
#define PATH_LIST_BEGIN \
static void initPathRouting() \
{
#define PATH_ADD(path, filters...) __registerSelf(path, {filters});
#define PATH_LIST_END \
}
#define PATH_LIST_END }
namespace drogon
{
class HttpSimpleControllerBase : public virtual DrObjectBase
{
public:
virtual void asyncHandleHttpRequest(const HttpRequestPtr &req, std::function<void(const HttpResponsePtr &)> &&callback) = 0;
virtual ~HttpSimpleControllerBase() {}
virtual ~HttpSimpleControllerBase()
{
}
};
template <typename T, bool AutoCreation = true>
@ -43,14 +42,19 @@ class HttpSimpleController : public DrObject<T>, public HttpSimpleControllerBase
{
public:
static const bool isAutoCreation = AutoCreation;
virtual ~HttpSimpleController() {}
virtual ~HttpSimpleController()
{
}
protected:
HttpSimpleController() {}
HttpSimpleController()
{
}
static void __registerSelf(const std::string &path, const std::vector<any> &filtersAndMethods)
{
LOG_TRACE << "register simple controller(" << HttpSimpleController<T>::classTypeName() << ") on path:" << path;
HttpAppFramework::instance().registerHttpSimpleController(path, HttpSimpleController<T>::classTypeName(), filtersAndMethods);
HttpAppFramework::instance().registerHttpSimpleController(
path, HttpSimpleController<T>::classTypeName(), filtersAndMethods);
}
private:

View File

@ -12,13 +12,12 @@
*/
#pragma once
#include <drogon/config.h>
#include <atomic>
#include <drogon/config.h>
#include <thread>
namespace drogon
{
enum HttpStatusCode
{
// rfc2616-6.1.1

3
lib/inc/drogon/HttpViewBase.h Executable file → Normal file
View File

@ -15,14 +15,13 @@
#pragma once
#include <drogon/DrObject.h>
#include <drogon/HttpViewData.h>
#include <drogon/HttpResponse.h>
#include <drogon/HttpViewData.h>
#include <map>
#include <string>
namespace drogon
{
class HttpViewBase : virtual public DrObjectBase
{
public:

18
lib/inc/drogon/HttpViewData.h Executable file → Normal file
View File

@ -14,24 +14,24 @@
#pragma once
#include <trantor/utils/Logger.h>
#include <drogon/config.h>
#include <trantor/utils/Logger.h>
#include <trantor/utils/MsgBuffer.h>
#include <unordered_map>
#include <string>
#include <sstream>
#include <stdio.h>
#include <stdarg.h>
#include <stdio.h>
#include <string>
#include <unordered_map>
namespace drogon
{
/// This class represents the data set displayed in views.
class HttpViewData
{
public:
/// The function template is used to get an item in the data set by the @param key.
/// The function template is used to get an item in the data set by the @param
/// key.
template <typename T>
const T &get(const std::string &key, T &&nullVal = T()) const
{
@ -60,7 +60,8 @@ class HttpViewData
_viewData[key] = obj;
}
/// Insert an item identified by the @param key into the data set; The item is converted to a string.
/// Insert an item identified by the @param key into the data set; The item is
/// converted to a string.
template <typename T>
void insertAsString(const std::string &key, T &&val)
{
@ -70,8 +71,7 @@ class HttpViewData
}
/// Insert a formated string identified by the @param key.
void insertFormattedString(const std::string &key,
const char *format, ...)
void insertFormattedString(const std::string &key, const char *format, ...)
{
std::string strBuffer;
strBuffer.resize(128);

View File

@ -21,9 +21,9 @@ namespace drogon
class IntranetIpFilter : public HttpFilter<IntranetIpFilter>
{
public:
IntranetIpFilter() {}
virtual void doFilter(const HttpRequestPtr &req,
FilterCallback &&fcb,
FilterChainCallback &&fccb) override;
IntranetIpFilter()
{
}
virtual void doFilter(const HttpRequestPtr &req, FilterCallback &&fcb, FilterChainCallback &&fccb) override;
};
} // namespace drogon

View File

@ -21,9 +21,9 @@ namespace drogon
class LocalHostFilter : public HttpFilter<LocalHostFilter>
{
public:
LocalHostFilter() {}
virtual void doFilter(const HttpRequestPtr &req,
FilterCallback &&fcb,
FilterChainCallback &&fccb) override;
LocalHostFilter()
{
}
virtual void doFilter(const HttpRequestPtr &req, FilterCallback &&fcb, FilterChainCallback &&fccb) override;
};
} // namespace drogon

46
lib/inc/drogon/MultiPart.h Executable file → Normal file
View File

@ -16,25 +16,36 @@
#include <drogon/HttpRequest.h>
#include <drogon/HttpResponse.h>
#include <string>
#include <map>
#include <string>
#include <vector>
namespace drogon
{
class HttpFile
{
public:
/// Return the file name;
const std::string &getFileName() const { return _fileName; };
const std::string &getFileName() const
{
return _fileName;
};
/// Set the file name
void setFileName(const std::string &filename) { _fileName = filename; };
void setFileName(const std::string &filename)
{
_fileName = filename;
};
/// Set the contents of the file, usually called by the FileUpload parser.
void setFile(const std::string &file) { _fileContent = file; };
void setFile(std::string &&file) { _fileContent = std::move(file); }
void setFile(const std::string &file)
{
_fileContent = file;
};
void setFile(std::string &&file)
{
_fileContent = std::move(file);
}
/// Save the file to the file system.
/**
@ -45,22 +56,29 @@ class HttpFile
/// Save the file to @param path
/**
* If the @param path is prefixed with "/", "./" or "../", or the @param path is
* "." or "..", the full path is @param path+"/"+this->getFileName(), otherwise
* the file is saved as app().getUploadPath()+"/"+@param path+"/"+this->getFileName()
* If the @param path is prefixed with "/", "./" or "../", or the @param path
* is
* "." or "..", the full path is @param path+"/"+this->getFileName(),
* otherwise
* the file is saved as app().getUploadPath()+"/"+@param
* path+"/"+this->getFileName()
*/
int save(const std::string &path) const;
/// Save the file to file system with a new name
/**
* If the @param filename isn't prefixed with "/", "./" or "../", the full path is
* If the @param filename isn't prefixed with "/", "./" or "../", the full
* path is
* app().getUploadPath()+"/"+@param filename, otherwise
* the file is saved as @param filename
*/
int saveAs(const std::string &filename) const;
/// Return the file length.
int64_t fileLength() const { return _fileContent.length(); };
int64_t fileLength() const
{
return _fileContent.length();
};
/// Return the md5 string of the file
const std::string getMd5() const;
@ -71,7 +89,8 @@ class HttpFile
std::string _fileContent;
};
/// A parser class which help the user to get the files and the parameters in the multipart format request.
/// A parser class which help the user to get the files and the parameters in
/// the multipart format request.
class MultiPartParser
{
public:
@ -80,7 +99,8 @@ class MultiPartParser
/// Get files, This method should be called after calling the parse() method.
const std::vector<HttpFile> &getFiles();
/// Get parameters, This method should be called after calling the parse () method.
/// Get parameters, This method should be called after calling the parse ()
/// method.
const std::map<std::string, std::string> &getParameters() const;
/// Parse the http request stream to get files and parameters.

0
lib/inc/drogon/NotFound.h Executable file → Normal file
View File

5
lib/inc/drogon/Session.h Executable file → Normal file
View File

@ -14,15 +14,14 @@
#pragma once
#include <memory>
#include <drogon/config.h>
#include <map>
#include <memory>
#include <mutex>
#include <thread>
#include <drogon/config.h>
namespace drogon
{
class Session
{
public:

View File

@ -20,16 +20,17 @@ namespace drogon
class UploadFile
{
public:
/// This class represents an upload file which will be transferred to the server via the multipart/form-data format
/// This class represents an upload file which will be transferred to the
/// server via the multipart/form-data format
/**
* @param filePath: The file location on local host, including file name.
* @param fileName: The file name provided to the server. If it is empty by default, the file name in the @param filePath
* @param fileName: The file name provided to the server. If it is empty by
* default, the file name in the @param filePath
* is provided to the server.
* @param itemName: The item name on the browser form.
*/
explicit UploadFile(const std::string &filePath, const std::string &fileName = "", const std::string &itemName = "file")
: _path(filePath),
_itemName(itemName)
: _path(filePath), _itemName(itemName)
{
if (!fileName.empty())
{
@ -48,9 +49,18 @@ class UploadFile
}
}
}
const std::string &path() const { return _path; }
const std::string &fileName() const { return _fileName; }
const std::string &itemName() const { return _itemName; }
const std::string &path() const
{
return _path;
}
const std::string &fileName() const
{
return _fileName;
}
const std::string &itemName() const
{
return _itemName;
}
private:
std::string _path;

View File

@ -17,14 +17,13 @@
#include <drogon/HttpRequest.h>
#include <drogon/HttpResponse.h>
#include <drogon/WebSocketConnection.h>
#include <trantor/net/EventLoop.h>
#include <string>
#include <functional>
#include <memory>
#include <string>
#include <trantor/net/EventLoop.h>
namespace drogon
{
class WebSocketClient;
typedef std::shared_ptr<WebSocketClient> WebSocketClientPtr;
typedef std::function<void(ReqResult, const HttpResponsePtr &, const WebSocketClientPtr &)> WebSocketRequestCallback;
@ -36,10 +35,14 @@ class WebSocketClient
/// Get the WebSocket connection that is typically used to send messages.
virtual WebSocketConnectionPtr getConnection() = 0;
/// Set messages handler. When a message is recieved from the server, the @param callback is called.
virtual void setMessageHandler(const std::function<void(std::string &&message, const WebSocketClientPtr &, const WebSocketMessageType &)> &callback) = 0;
/// Set messages handler. When a message is recieved from the server, the
/// @param callback is called.
virtual void setMessageHandler(
const std::function<void(std::string &&message, const WebSocketClientPtr &, const WebSocketMessageType &)>
&callback) = 0;
/// Set the connection handler. When the connection is established or closed, the @param callback is called with a bool
/// Set the connection handler. When the connection is established or closed,
/// the @param callback is called with a bool
/// parameter.
virtual void setConnectionClosedHandler(const std::function<void(const WebSocketClientPtr &)> &callback) = 0;
@ -86,10 +89,11 @@ class WebSocketClient
* the connectToServer() method.
*
*/
static WebSocketClientPtr newWebSocketClient(const std::string &hostString,
trantor::EventLoop *loop = nullptr);
static WebSocketClientPtr newWebSocketClient(const std::string &hostString, trantor::EventLoop *loop = nullptr);
virtual ~WebSocketClient() {}
virtual ~WebSocketClient()
{
}
};
} // namespace drogon

View File

@ -15,13 +15,12 @@
#pragma once
#include <drogon/config.h>
#include <trantor/utils/NonCopyable.h>
#include <trantor/net/InetAddress.h>
#include <string>
#include <memory>
#include <string>
#include <trantor/net/InetAddress.h>
#include <trantor/utils/NonCopyable.h>
namespace drogon
{
enum class WebSocketMessageType
{
Text,
@ -56,7 +55,8 @@ class WebSocketConnection
/// Set the heartbeat(ping) message sent to the server.
/**
* NOTE:
* Both the server and the client in Drogon automatically send the pong message after receiving the ping message.
* Both the server and the client in Drogon automatically send the pong
* message after receiving the ping message.
*/
virtual void setPingMessage(const std::string &message, const std::chrono::duration<long double> &interval) = 0;
};

View File

@ -17,19 +17,18 @@
#include <drogon/DrObject.h>
#include <drogon/HttpAppFramework.h>
#include <drogon/WebSocketConnection.h>
#include <trantor/utils/Logger.h>
#include <trantor/net/TcpConnection.h>
#include <string>
#include <vector>
#include <iostream>
#include <memory>
#include <string>
#include <trantor/net/TcpConnection.h>
#include <trantor/utils/Logger.h>
#include <vector>
#define WS_PATH_LIST_BEGIN \
static std::vector<std::pair<std::string, std::vector<std::string>>> __paths() \
{ \
std::vector<std::pair<std::string, std::vector<std::string>>> vet;
#define WS_PATH_ADD(path, filters...) \
vet.push_back({path, {filters}})
#define WS_PATH_ADD(path, filters...) vet.push_back({path, {filters}})
#define WS_PATH_LIST_END \
return vet; \
@ -37,23 +36,21 @@
namespace drogon
{
class WebSocketControllerBase : public virtual DrObjectBase
{
public:
// This function is called when a new message is received
virtual void handleNewMessage(const WebSocketConnectionPtr &,
std::string &&,
const WebSocketMessageType &) = 0;
virtual void handleNewMessage(const WebSocketConnectionPtr &, std::string &&, const WebSocketMessageType &) = 0;
// This function is called after a new connection of WebSocket is established.
virtual void handleNewConnection(const HttpRequestPtr &,
const WebSocketConnectionPtr &) = 0;
virtual void handleNewConnection(const HttpRequestPtr &, const WebSocketConnectionPtr &) = 0;
// This function is called after a WebSocket connection is closed
virtual void handleConnectionClosed(const WebSocketConnectionPtr &) = 0;
virtual ~WebSocketControllerBase() {}
virtual ~WebSocketControllerBase()
{
}
};
typedef std::shared_ptr<WebSocketControllerBase> WebSocketControllerBasePtr;
@ -63,21 +60,25 @@ class WebSocketController : public DrObject<T>, public WebSocketControllerBase
{
public:
static const bool isAutoCreation = AutoCreation;
virtual ~WebSocketController() {}
virtual ~WebSocketController()
{
}
static void initPathRouting()
{
auto vPaths = T::__paths();
for (auto const &path : vPaths)
{
LOG_TRACE << "register websocket controller (" << WebSocketController<T>::classTypeName() << ") on path:" << path.first;
HttpAppFramework::instance().registerWebSocketController(path.first,
WebSocketController<T>::classTypeName(),
path.second);
LOG_TRACE << "register websocket controller (" << WebSocketController<T>::classTypeName()
<< ") on path:" << path.first;
HttpAppFramework::instance().registerWebSocketController(
path.first, WebSocketController<T>::classTypeName(), path.second);
}
}
protected:
WebSocketController() {}
WebSocketController()
{
}
private:
class pathRegister

View File

@ -16,14 +16,14 @@
#include <drogon/config.h>
#include <trantor/utils/Logger.h>
#include <trantor/net/EventLoop.h>
#include <trantor/utils/Date.h>
#include <trantor/net/InetAddress.h>
#include <trantor/utils/Date.h>
#include <trantor/utils/Logger.h>
#include <drogon/CacheMap.h>
#include <drogon/HttpAppFramework.h>
#include <drogon/HttpClient.h>
#include <drogon/HttpController.h>
#include <drogon/HttpSimpleController.h>
#include <drogon/CacheMap.h>
#include <drogon/HttpClient.h>
#include <drogon/utils/Utilities.h>

View File

@ -14,14 +14,13 @@
#pragma once
#include <drogon/DrObject.h>
#include <trantor/utils/NonCopyable.h>
#include <trantor/utils/Logger.h>
#include <json/json.h>
#include <memory>
#include <trantor/utils/Logger.h>
#include <trantor/utils/NonCopyable.h>
namespace drogon
{
enum class PluginState
{
None,
@ -34,7 +33,10 @@ class PluginBase : public virtual DrObjectBase, public trantor::NonCopyable
public:
/// This method is usually called by drogon.
/// It always returns PlugiinState::Initialized if the user calls it.
PluginState stat() const { return _stat; }
PluginState stat() const
{
return _stat;
}
/// This method must be called by drogon.
void initialize()
@ -70,17 +72,30 @@ class PluginBase : public virtual DrObjectBase, public trantor::NonCopyable
/// It must be implemented by the user.
virtual void shutdown() = 0;
virtual ~PluginBase() {}
virtual ~PluginBase()
{
}
protected:
PluginBase() {}
PluginBase()
{
}
private:
PluginState _stat = PluginState::None;
friend class PluginsManager;
void setConfig(const Json::Value &config) { _config = config; }
void addDependency(PluginBase *dp) { _dependencies.push_back(dp); }
void setInitializedCallback(const std::function<void(PluginBase *)> &cb) { _initializedCallback = cb; }
void setConfig(const Json::Value &config)
{
_config = config;
}
void addDependency(PluginBase *dp)
{
_dependencies.push_back(dp);
}
void setInitializedCallback(const std::function<void(PluginBase *)> &cb)
{
_initializedCallback = cb;
}
Json::Value _config;
std::vector<PluginBase *> _dependencies;
std::function<void(PluginBase *)> _initializedCallback;
@ -91,8 +106,14 @@ struct IsPlugin
{
typedef typename std::remove_cv<typename std::remove_reference<T>::type>::type TYPE;
static int test(void *p) { return 0; }
static char test(PluginBase *p) { return 0; }
static int test(void *p)
{
return 0;
}
static char test(PluginBase *p)
{
return 0;
}
static constexpr bool value = (sizeof(test((TYPE *)nullptr)) == sizeof(int));
};
@ -100,10 +121,14 @@ template <typename T>
class Plugin : public PluginBase, public DrObject<T>
{
public:
virtual ~Plugin() {}
virtual ~Plugin()
{
}
protected:
Plugin() {}
Plugin()
{
}
};
} // namespace drogon

View File

@ -18,15 +18,20 @@ namespace drogon
{
namespace internal
{
/// This template is used to check whether S is a subclass of B.
template <typename S, typename B>
struct IsSubClass
{
typedef typename std::remove_cv<typename std::remove_reference<S>::type>::type SubType;
typedef typename std::remove_cv<typename std::remove_reference<B>::type>::type BaseType;
static char test(void *) { return 0; }
static int test(BaseType *) { return 0; }
static char test(void *)
{
return 0;
}
static int test(BaseType *)
{
return 0;
}
static const bool value = (sizeof(test((SubType *)nullptr)) == sizeof(int));
};

50
lib/inc/drogon/utils/FunctionTraits.h Executable file → Normal file
View File

@ -16,10 +16,10 @@
#include <drogon/DrObject.h>
#include <drogon/utils/ClassTraits.h>
#include <functional>
#include <memory>
#include <tuple>
#include <type_traits>
#include <memory>
#include <functional>
namespace drogon
{
@ -30,14 +30,12 @@ typedef std::shared_ptr<HttpResponse> HttpResponsePtr;
namespace internal
{
template <typename>
struct FunctionTraits;
// functor,lambda,std::function...
template <typename Function>
struct FunctionTraits : public FunctionTraits<
decltype(&std::remove_reference<Function>::type::operator())>
struct FunctionTraits : public FunctionTraits<decltype(&std::remove_reference<Function>::type::operator())>
{
static const bool isClassFunction = false;
static const bool isDrObjectClass = false;
@ -49,61 +47,59 @@ struct FunctionTraits : public FunctionTraits<
};
// class instance method of const object
template <typename ClassType,
typename ReturnType,
typename... Arguments>
template <typename ClassType, typename ReturnType, typename... Arguments>
struct FunctionTraits<ReturnType (ClassType::*)(Arguments...) const> : FunctionTraits<ReturnType (*)(Arguments...)>
{
static const bool isClassFunction = true;
static const bool isDrObjectClass = IsSubClass<ClassType, DrObject<ClassType>>::value;
typedef ClassType class_type;
static const std::string name() { return std::string("Class Function"); }
static const std::string name()
{
return std::string("Class Function");
}
};
// class instance method of non-const object
template <
typename ClassType,
typename ReturnType,
typename... Arguments>
template <typename ClassType, typename ReturnType, typename... Arguments>
struct FunctionTraits<ReturnType (ClassType::*)(Arguments...)> : FunctionTraits<ReturnType (*)(Arguments...)>
{
static const bool isClassFunction = true;
static const bool isDrObjectClass = IsSubClass<ClassType, DrObject<ClassType>>::value;
typedef ClassType class_type;
static const std::string name() { return std::string("Class Function"); }
static const std::string name()
{
return std::string("Class Function");
}
};
// normal function for HTTP handling
template <
typename ReturnType,
typename... Arguments>
template <typename ReturnType, typename... Arguments>
struct FunctionTraits<
ReturnType (*)(const HttpRequestPtr &req, std::function<void(const HttpResponsePtr &)> &&callback, Arguments...)> : FunctionTraits<ReturnType (*)(Arguments...)>
ReturnType (*)(const HttpRequestPtr &req, std::function<void(const HttpResponsePtr &)> &&callback, Arguments...)>
: FunctionTraits<ReturnType (*)(Arguments...)>
{
static const bool isHTTPFunction = true;
typedef void class_type;
};
// normal function
template <
typename ReturnType,
typename... Arguments>
struct FunctionTraits<
ReturnType (*)(Arguments...)>
template <typename ReturnType, typename... Arguments>
struct FunctionTraits<ReturnType (*)(Arguments...)>
{
typedef ReturnType result_type;
template <std::size_t Index>
using argument = typename std::tuple_element<
Index,
std::tuple<Arguments...>>::type;
using argument = typename std::tuple_element<Index, std::tuple<Arguments...>>::type;
static const std::size_t arity = sizeof...(Arguments);
typedef void class_type;
static const bool isHTTPFunction = false;
static const bool isClassFunction = false;
static const bool isDrObjectClass = false;
static const std::string name() { return std::string("Normal or Static Function"); }
static const std::string name()
{
return std::string("Normal or Static Function");
}
};
} // namespace internal

7
lib/inc/drogon/utils/Utilities.h Executable file → Normal file
View File

@ -15,16 +15,15 @@
#pragma once
#include <drogon/config.h>
#include <trantor/utils/Date.h>
#include <string>
#include <vector>
#include <memory>
#include <string>
#include <trantor/utils/Date.h>
#include <vector>
namespace drogon
{
namespace utils
{
/// Determine if the string is an integer
bool isInteger(const std::string &str);

View File

@ -3,10 +3,8 @@
namespace drogon
{
void doAdvicesChain(const std::vector<std::function<void(const HttpRequestPtr &,
AdviceCallback &&,
AdviceChainCallback &&)>> &advices,
void doAdvicesChain(
const std::vector<std::function<void(const HttpRequestPtr &, AdviceCallback &&, AdviceChainCallback &&)>> &advices,
size_t index,
const HttpRequestImplPtr &req,
const std::shared_ptr<const std::function<void(const HttpResponsePtr &)>> &callbackPtr,
@ -27,9 +25,8 @@ void doAdvicesChain(const std::vector<std::function<void(const HttpRequestPtr &,
}
}
void doAdvicesChain(const std::deque<std::function<void(const HttpRequestPtr &,
AdviceCallback &&,
AdviceChainCallback &&)>> &advices,
void doAdvicesChain(
const std::deque<std::function<void(const HttpRequestPtr &, AdviceCallback &&, AdviceChainCallback &&)>> &advices,
size_t index,
const HttpRequestImplPtr &req,
const std::shared_ptr<const std::function<void(const HttpResponsePtr &)>> &callbackPtr,

View File

@ -18,16 +18,14 @@
namespace drogon
{
void doAdvicesChain(const std::vector<std::function<void(const HttpRequestPtr &,
AdviceCallback &&,
AdviceChainCallback &&)>> &advices,
void doAdvicesChain(
const std::vector<std::function<void(const HttpRequestPtr &, AdviceCallback &&, AdviceChainCallback &&)>> &advices,
size_t index,
const HttpRequestImplPtr &req,
const std::shared_ptr<const std::function<void(const HttpResponsePtr &)>> &callbackPtr,
std::function<void()> &&missCallback);
void doAdvicesChain(const std::deque<std::function<void(const HttpRequestPtr &,
AdviceCallback &&,
AdviceChainCallback &&)>> &advices,
void doAdvicesChain(
const std::deque<std::function<void(const HttpRequestPtr &, AdviceCallback &&, AdviceChainCallback &&)>> &advices,
size_t index,
const HttpRequestImplPtr &req,
const std::shared_ptr<const std::function<void(const HttpResponsePtr &)>> &callbackPtr,

View File

@ -14,13 +14,13 @@
#include "ConfigLoader.h"
#include <trantor/utils/Logger.h>
#include <drogon/HttpAppFramework.h>
#include <iostream>
#include <fstream>
#include <unistd.h>
#include <thread>
#include <iostream>
#include <sstream>
#include <thread>
#include <trantor/utils/Logger.h>
#include <unistd.h>
using namespace drogon;
static bool bytesSize(std::string &sizeStr, size_t &size)
@ -350,7 +350,9 @@ static void loadDbClients(const Json::Value &dbClients)
drogon::app().createDbClient(type, host, (u_short)port, dbname, user, password, connNum, filename, name, isFast);
}
#else
std::cout << "No database is supported by drogon, please install the database development library first." << std::endl;
std::cout << "No database is supported by drogon, please install the "
"database development library first."
<< std::endl;
exit(1);
#endif
}

View File

@ -14,9 +14,9 @@
#pragma once
#include <trantor/utils/NonCopyable.h>
#include <json/json.h>
#include <string>
#include <trantor/utils/NonCopyable.h>
namespace drogon
{
@ -25,7 +25,10 @@ class ConfigLoader : public trantor::NonCopyable
public:
explicit ConfigLoader(const std::string &configFile);
~ConfigLoader();
const Json::Value &jsonValue() const { return _configJsonRoot; }
const Json::Value &jsonValue() const
{
return _configJsonRoot;
}
void load();
private:

0
lib/src/Cookie.cc Executable file → Normal file
View File

1
lib/src/DrClassMap.cc Executable file → Normal file
View File

@ -22,7 +22,6 @@ namespace drogon
{
namespace internal
{
static std::unordered_map<std::string, std::shared_ptr<DrObjectBase>> &getObjsMap()
{
static std::unordered_map<std::string, std::shared_ptr<DrObjectBase>> singleInstanceMap;

4
lib/src/DrTemplateBase.cc Executable file → Normal file
View File

@ -12,10 +12,10 @@
*
*/
#include <drogon/DrTemplateBase.h>
#include <drogon/DrClassMap.h>
#include <trantor/utils/Logger.h>
#include <drogon/DrTemplateBase.h>
#include <memory>
#include <trantor/utils/Logger.h>
using namespace drogon;

View File

@ -22,7 +22,6 @@ namespace drogon
{
namespace FiltersFunction
{
static void doFilterChains(const std::vector<std::shared_ptr<HttpFilterBase>> &filters,
size_t index,
const HttpRequestImplPtr &req,
@ -34,7 +33,8 @@ static void doFilterChains(const std::vector<std::shared_ptr<HttpFilterBase>> &f
if (index < filters.size())
{
auto &filter = filters[index];
filter->doFilter(req,
filter->doFilter(
req,
[needSetJsessionid, callbackPtr, sessionIdPtr](const HttpResponsePtr &res) {
if (needSetJsessionid && res->statusCode() != k404NotFound)
res->addCookie("JSESSIONID", *sessionIdPtr);
@ -74,7 +74,6 @@ void doFilters(const std::vector<std::shared_ptr<HttpFilterBase>> &filters,
const std::shared_ptr<std::string> &sessionIdPtr,
std::function<void()> &&missCallback)
{
doFilterChains(filters, 0, req, callbackPtr, needSetJsessionid, sessionIdPtr, std::move(missCallback));
}

View File

@ -16,15 +16,14 @@
#include "HttpRequestImpl.h"
#include <drogon/HttpFilter.h>
#include <memory>
#include <string>
#include <vector>
#include <memory>
namespace drogon
{
namespace FiltersFunction
{
std::vector<std::shared_ptr<HttpFilterBase>> createFilters(const std::vector<std::string> &filterNames);
void doFilters(const std::vector<std::shared_ptr<HttpFilterBase>> &filters,
const HttpRequestImplPtr &req,

150
lib/src/HttpAppFrameworkImpl.cc Executable file → Normal file
View File

@ -13,48 +13,46 @@
*/
#include "HttpAppFrameworkImpl.h"
#include "AOPAdvice.h"
#include "ConfigLoader.h"
#include "HttpServer.h"
#include "AOPAdvice.h"
#if USE_ORM
#include "../../orm_lib/src/DbClientLockFree.h"
#endif
#include <drogon/HttpTypes.h>
#include <drogon/utils/Utilities.h>
#include <algorithm>
#include <drogon/CacheMap.h>
#include <drogon/DrClassMap.h>
#include <drogon/HttpRequest.h>
#include <drogon/HttpResponse.h>
#include <drogon/CacheMap.h>
#include <drogon/HttpTypes.h>
#include <drogon/Session.h>
#include <trantor/utils/AsyncFileLogger.h>
#include <drogon/utils/Utilities.h>
#include <fcntl.h>
#include <fstream>
#include <iostream>
#include <json/json.h>
#include <memory>
#include <sys/file.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <iostream>
#include <fstream>
#include <uuid.h>
#include <unordered_map>
#include <algorithm>
#include <memory>
#include <trantor/utils/AsyncFileLogger.h>
#include <tuple>
#include <utility>
#include <unistd.h>
#include <fcntl.h>
#include <sys/file.h>
#include <unordered_map>
#include <utility>
#include <uuid.h>
using namespace drogon;
using namespace std::placeholders;
/// Make sure that the main event loop is initialized in the main thread.
drogon::InitBeforeMainFunction drogon::HttpAppFrameworkImpl::_initFirst([]() {
HttpAppFrameworkImpl::instance().getLoop()->runInLoop([]() {
LOG_TRACE << "Initialize the main event loop in the main thread";
});
HttpAppFrameworkImpl::instance().getLoop()->runInLoop(
[]() { LOG_TRACE << "Initialize the main event loop in the main thread"; });
});
namespace drogon
{
class DrogonFileLocker : public trantor::NonCopyable
{
public:
@ -113,10 +111,9 @@ void HttpAppFrameworkImpl::enableDynamicViewsLoading(const std::vector<std::stri
for (auto const &libpath : libPaths)
{
if (libpath[0] == '/' ||
(libpath.length() >= 2 && libpath[0] == '.' && libpath[1] == '/') ||
(libpath.length() >= 3 && libpath[0] == '.' && libpath[1] == '.' && libpath[2] == '/') ||
libpath == "." || libpath == "..")
if (libpath[0] == '/' || (libpath.length() >= 2 && libpath[0] == '.' && libpath[1] == '/') ||
(libpath.length() >= 3 && libpath[0] == '.' && libpath[1] == '.' && libpath[2] == '/') || libpath == "." ||
libpath == "..")
{
_libFilePaths.push_back(libpath);
}
@ -182,9 +179,7 @@ void HttpAppFrameworkImpl::loadConfigFile(const std::string &fileName)
loader.load();
_jsonConfig = loader.jsonValue();
}
void HttpAppFrameworkImpl::setLogPath(const std::string &logPath,
const std::string &logfileBaseName,
size_t logfileSize)
void HttpAppFrameworkImpl::setLogPath(const std::string &logPath, const std::string &logfileBaseName, size_t logfileSize)
{
if (logPath == "")
return;
@ -206,8 +201,7 @@ void HttpAppFrameworkImpl::setLogLevel(trantor::Logger::LogLevel level)
{
trantor::Logger::setLogLevel(level);
}
void HttpAppFrameworkImpl::setSSLFiles(const std::string &certPath,
const std::string &keyPath)
void HttpAppFrameworkImpl::setSSLFiles(const std::string &certPath, const std::string &keyPath)
{
_sslCertPath = certPath;
_sslKeyPath = keyPath;
@ -281,7 +275,8 @@ void HttpAppFrameworkImpl::run()
}
asyncFileLogger.setFileName(baseName, ".log", _logPath);
asyncFileLogger.startLogging();
trantor::Logger::setOutputFunction([&](const char *msg, const uint64_t len) { asyncFileLogger.output(msg, len); }, [&]() { asyncFileLogger.flush(); });
trantor::Logger::setOutputFunction([&](const char *msg, const uint64_t len) { asyncFileLogger.output(msg, len); },
[&]() { asyncFileLogger.flush(); });
asyncFileLogger.setFileSizeLimit(_logfileSize);
}
else
@ -323,20 +318,14 @@ void HttpAppFrameworkImpl::run()
{
DrogonFileLocker lock;
// Check whether the port is in use.
TcpServer server(getLoop(),
InetAddress(ip, std::get<1>(listener), isIpv6),
"drogonPortTest",
true,
false);
serverPtr = std::make_shared<HttpServer>(loopThreadPtr->getLoop(),
InetAddress(ip, std::get<1>(listener), isIpv6),
"drogon");
TcpServer server(getLoop(), InetAddress(ip, std::get<1>(listener), isIpv6), "drogonPortTest", true, false);
serverPtr = std::make_shared<HttpServer>(
loopThreadPtr->getLoop(), InetAddress(ip, std::get<1>(listener), isIpv6), "drogon");
}
else
{
serverPtr = std::make_shared<HttpServer>(loopThreadPtr->getLoop(),
InetAddress(ip, std::get<1>(listener), isIpv6),
"drogon");
serverPtr = std::make_shared<HttpServer>(
loopThreadPtr->getLoop(), InetAddress(ip, std::get<1>(listener), isIpv6), "drogon");
}
if (std::get<2>(listener))
@ -372,9 +361,8 @@ void HttpAppFrameworkImpl::run()
loopThreads.push_back(loopThreadPtr);
auto ip = std::get<0>(listener);
bool isIpv6 = ip.find(":") == std::string::npos ? false : true;
auto serverPtr = std::make_shared<HttpServer>(loopThreadPtr->getLoop(),
InetAddress(ip, std::get<1>(listener), isIpv6),
"drogon");
auto serverPtr =
std::make_shared<HttpServer>(loopThreadPtr->getLoop(), InetAddress(ip, std::get<1>(listener), isIpv6), "drogon");
if (std::get<2>(listener))
{
#ifdef USE_OPENSSL
@ -408,7 +396,8 @@ void HttpAppFrameworkImpl::run()
#endif
#if USE_ORM
// A fast database client instance should be created in the main event loop, so put the main loop into ioLoops.
// A fast database client instance should be created in the main event loop,
// so put the main loop into ioLoops.
ioLoops.push_back(getLoop());
createDbClients(ioLoops);
ioLoops.pop_back();
@ -437,21 +426,23 @@ void HttpAppFrameworkImpl::run()
tmpTimeout = tmpTimeout / 100;
}
}
_sessionMapPtr = std::unique_ptr<CacheMap<std::string, SessionPtr>>(new CacheMap<std::string, SessionPtr>(getLoop(), 1.0, wheelNum, bucketNum));
_sessionMapPtr = std::unique_ptr<CacheMap<std::string, SessionPtr>>(
new CacheMap<std::string, SessionPtr>(getLoop(), 1.0, wheelNum, bucketNum));
}
else if (_sessionTimeout == 0)
{
_sessionMapPtr = std::unique_ptr<CacheMap<std::string, SessionPtr>>(new CacheMap<std::string, SessionPtr>(getLoop(), 0, 0, 0));
_sessionMapPtr =
std::unique_ptr<CacheMap<std::string, SessionPtr>>(new CacheMap<std::string, SessionPtr>(getLoop(), 0, 0, 0));
}
}
_responseCachingMap = std::unique_ptr<CacheMap<std::string, HttpResponsePtr>>(new CacheMap<std::string, HttpResponsePtr>(getLoop(), 1.0, 4, 50)); //Max timeout up to about 70 days;
_responseCachingMap = std::unique_ptr<CacheMap<std::string, HttpResponsePtr>>(
new CacheMap<std::string, HttpResponsePtr>(getLoop(), 1.0, 4, 50)); // Max timeout up to about 70 days;
// Initialize plugins
const auto &pluginConfig = _jsonConfig["plugins"];
if (!pluginConfig.isNull())
{
_pluginsManager.initializeAllPlugins(pluginConfig,
[](PluginBase *plugin) {
_pluginsManager.initializeAllPlugins(pluginConfig, [](PluginBase *plugin) {
// TODO: new plugin
});
}
@ -481,7 +472,8 @@ void HttpAppFrameworkImpl::createDbClients(const std::vector<trantor::EventLoop
}
if (dbInfo._dbType == drogon::orm::ClientType::PostgreSQL || dbInfo._dbType == drogon::orm::ClientType::Mysql)
{
_dbFastClientsMap[dbInfo._name][loop] = std::shared_ptr<drogon::orm::DbClient>(new drogon::orm::DbClientLockFree(dbInfo._connectionInfo, loop, dbInfo._dbType));
_dbFastClientsMap[dbInfo._name][loop] = std::shared_ptr<drogon::orm::DbClient>(
new drogon::orm::DbClientLockFree(dbInfo._connectionInfo, loop, dbInfo._dbType));
}
}
}
@ -490,19 +482,22 @@ void HttpAppFrameworkImpl::createDbClients(const std::vector<trantor::EventLoop
if (dbInfo._dbType == drogon::orm::ClientType::PostgreSQL)
{
#if USE_POSTGRESQL
_dbClientsMap[dbInfo._name] = drogon::orm::DbClient::newPgClient(dbInfo._connectionInfo, dbInfo._connectionNumber);
_dbClientsMap[dbInfo._name] =
drogon::orm::DbClient::newPgClient(dbInfo._connectionInfo, dbInfo._connectionNumber);
#endif
}
else if (dbInfo._dbType == drogon::orm::ClientType::Mysql)
{
#if USE_MYSQL
_dbClientsMap[dbInfo._name] = drogon::orm::DbClient::newMysqlClient(dbInfo._connectionInfo, dbInfo._connectionNumber);
_dbClientsMap[dbInfo._name] =
drogon::orm::DbClient::newMysqlClient(dbInfo._connectionInfo, dbInfo._connectionNumber);
#endif
}
else if (dbInfo._dbType == drogon::orm::ClientType::Sqlite3)
{
#if USE_SQLITE3
_dbClientsMap[dbInfo._name] = drogon::orm::DbClient::newSqlite3Client(dbInfo._connectionInfo, dbInfo._connectionNumber);
_dbClientsMap[dbInfo._name] =
drogon::orm::DbClient::newSqlite3Client(dbInfo._connectionInfo, dbInfo._connectionNumber);
#endif
}
}
@ -533,9 +528,7 @@ void HttpAppFrameworkImpl::onConnection(const TcpConnectionPtr &conn)
}
else if (iter->second++ > _maxConnectionNumPerIP)
{
conn->getLoop()->queueInLoop([conn]() {
conn->forceClose();
});
conn->getLoop()->queueInLoop([conn]() { conn->forceClose(); });
return;
}
}
@ -557,7 +550,8 @@ void HttpAppFrameworkImpl::onConnection(const TcpConnectionPtr &conn)
if (conn->getContext().empty())
#endif
{
//If the connection is connected to the SSL port and then disconnected before the SSL handshake.
// If the connection is connected to the SSL port and then disconnected
// before the SSL handshake.
return;
}
_connectionNum--;
@ -580,8 +574,7 @@ void HttpAppFrameworkImpl::onConnection(const TcpConnectionPtr &conn)
void HttpAppFrameworkImpl::setUploadPath(const std::string &uploadPath)
{
assert(!uploadPath.empty());
if (uploadPath[0] == '/' ||
(uploadPath.length() >= 2 && uploadPath[0] == '.' && uploadPath[1] == '/') ||
if (uploadPath[0] == '/' || (uploadPath.length() >= 2 && uploadPath[0] == '.' && uploadPath[1] == '/') ||
(uploadPath.length() >= 3 && uploadPath[0] == '.' && uploadPath[1] == '.' && uploadPath[2] == '/') ||
uploadPath == "." || uploadPath == "..")
{
@ -612,7 +605,8 @@ std::vector<std::tuple<std::string, HttpMethod, std::string>> HttpAppFrameworkIm
return ret;
}
void HttpAppFrameworkImpl::onAsyncRequest(const HttpRequestImplPtr &req, std::function<void(const HttpResponsePtr &)> &&callback)
void HttpAppFrameworkImpl::onAsyncRequest(const HttpRequestImplPtr &req,
std::function<void(const HttpResponsePtr &)> &&callback)
{
LOG_TRACE << "new request:" << req->peerAddr().toIpPort() << "->" << req->localAddr().toIpPort();
LOG_TRACE << "Headers " << req->methodString() << " " << req->path();
@ -688,7 +682,8 @@ void HttpAppFrameworkImpl::onAsyncRequest(const HttpRequestImplPtr &req, std::fu
{
if (cachedResp)
{
if (std::dynamic_pointer_cast<HttpResponseImpl>(cachedResp)->getHeaderBy("last-modified") == req->getHeaderBy("if-modified-since"))
if (std::dynamic_pointer_cast<HttpResponseImpl>(cachedResp)->getHeaderBy("last-modified") ==
req->getHeaderBy("if-modified-since"))
{
std::shared_ptr<HttpResponseImpl> resp = std::make_shared<HttpResponseImpl>();
resp->setStatusCode(k304NotModified);
@ -734,7 +729,8 @@ void HttpAppFrameworkImpl::onAsyncRequest(const HttpRequestImplPtr &req, std::fu
if (needSetJsessionid)
{
// make a copy
auto newCachedResp = std::make_shared<HttpResponseImpl>(*std::dynamic_pointer_cast<HttpResponseImpl>(cachedResp));
auto newCachedResp =
std::make_shared<HttpResponseImpl>(*std::dynamic_pointer_cast<HttpResponseImpl>(cachedResp));
newCachedResp->addCookie("JSESSIONID", sessionId);
newCachedResp->setExpiredTime(-1);
callback(newCachedResp);
@ -816,7 +812,8 @@ void HttpAppFrameworkImpl::onAsyncRequest(const HttpRequestImplPtr &req, std::fu
doAdvicesChain(_preRoutingAdvices,
0,
req,
std::make_shared<std::function<void(const HttpResponsePtr &)>>([callbackPtr, needSetJsessionid, sessionIdPtr](const HttpResponsePtr &resp) {
std::make_shared<std::function<void(const HttpResponsePtr &)>>(
[callbackPtr, needSetJsessionid, sessionIdPtr](const HttpResponsePtr &resp) {
if (!needSetJsessionid || resp->statusCode() == k404NotFound)
(*callbackPtr)(resp);
else
@ -826,7 +823,8 @@ void HttpAppFrameworkImpl::onAsyncRequest(const HttpRequestImplPtr &req, std::fu
}
}),
[this, callbackPtr, req, needSetJsessionid, sessionIdPtr]() {
_httpSimpleCtrlsRouter.route(req, std::move(*callbackPtr), needSetJsessionid, std::move(*sessionIdPtr));
_httpSimpleCtrlsRouter.route(
req, std::move(*callbackPtr), needSetJsessionid, std::move(*sessionIdPtr));
});
}
}
@ -854,8 +852,7 @@ orm::DbClientPtr HttpAppFrameworkImpl::getDbClient(const std::string &name)
}
orm::DbClientPtr HttpAppFrameworkImpl::getFastDbClient(const std::string &name)
{
assert(_dbFastClientsMap[name].find(trantor::EventLoop::getEventLoopOfCurrentThread()) !=
_dbFastClientsMap[name].end());
assert(_dbFastClientsMap[name].find(trantor::EventLoop::getEventLoopOfCurrentThread()) != _dbFastClientsMap[name].end());
return _dbFastClientsMap[name][trantor::EventLoop::getEventLoopOfCurrentThread()];
}
void HttpAppFrameworkImpl::createDbClient(const std::string &dbType,
@ -870,7 +867,8 @@ void HttpAppFrameworkImpl::createDbClient(const std::string &dbType,
const bool isFast)
{
assert(!_running);
auto connStr = utils::formattedString("host=%s port=%u dbname=%s user=%s", host.c_str(), port, databaseName.c_str(), userName.c_str());
auto connStr =
utils::formattedString("host=%s port=%u dbname=%s user=%s", host.c_str(), port, databaseName.c_str(), userName.c_str());
if (!password.empty())
{
connStr += " password=";
@ -890,7 +888,9 @@ void HttpAppFrameworkImpl::createDbClient(const std::string &dbType,
info._dbType = orm::ClientType::PostgreSQL;
_dbInfos.push_back(info);
#else
std::cout << "The PostgreSQL is not supported by drogon, please install the development library first." << std::endl;
std::cout << "The PostgreSQL is not supported by drogon, please install "
"the development library first."
<< std::endl;
exit(1);
#endif
}
@ -900,7 +900,9 @@ void HttpAppFrameworkImpl::createDbClient(const std::string &dbType,
info._dbType = orm::ClientType::Mysql;
_dbInfos.push_back(info);
#else
std::cout << "The Mysql is not supported by drogon, please install the development library first." << std::endl;
std::cout << "The Mysql is not supported by drogon, please install the "
"development library first."
<< std::endl;
exit(1);
#endif
}
@ -912,14 +914,18 @@ void HttpAppFrameworkImpl::createDbClient(const std::string &dbType,
info._dbType = orm::ClientType::Sqlite3;
_dbInfos.push_back(info);
#else
std::cout << "The Sqlite3 is not supported by drogon, please install the development library first." << std::endl;
std::cout << "The Sqlite3 is not supported by drogon, please install the "
"development library first."
<< std::endl;
exit(1);
#endif
}
}
#endif
void HttpAppFrameworkImpl::forward(const HttpRequestImplPtr &req, std::function<void(const HttpResponsePtr &)> &&callback, const std::string &hostString)
void HttpAppFrameworkImpl::forward(const HttpRequestImplPtr &req,
std::function<void(const HttpResponsePtr &)> &&callback,
const std::string &hostString)
{
if (hostString.empty())
{
@ -940,7 +946,9 @@ void HttpAppFrameworkImpl::forward(const HttpRequestImplPtr &req, std::function<
}
else
{
clientPtr = std::make_shared<HttpClientImpl>(trantor::EventLoop::getEventLoopOfCurrentThread() ? trantor::EventLoop::getEventLoopOfCurrentThread() : getLoop(),
clientPtr = std::make_shared<HttpClientImpl>(trantor::EventLoop::getEventLoopOfCurrentThread()
? trantor::EventLoop::getEventLoopOfCurrentThread()
: getLoop(),
hostString);
clientsMap[hostString] = clientPtr;
}

View File

@ -14,15 +14,15 @@
#pragma once
#include "HttpClientImpl.h"
#include "HttpControllersRouter.h"
#include "HttpRequestImpl.h"
#include "HttpResponseImpl.h"
#include "HttpClientImpl.h"
#include "SharedLibManager.h"
#include "HttpControllersRouter.h"
#include "HttpSimpleControllersRouter.h"
#include "PluginsManager.h"
#include "SharedLibManager.h"
#include "WebSocketConnectionImpl.h"
#include "WebsocketControllersRouter.h"
#include "PluginsManager.h"
#include <drogon/HttpAppFramework.h>
#include <drogon/HttpSimpleController.h>
@ -30,11 +30,11 @@
#include <trantor/net/EventLoop.h>
#include <trantor/net/EventLoopThread.h>
#include <string>
#include <vector>
#include <memory>
#include <mutex>
#include <regex>
#include <string>
#include <vector>
namespace drogon
{
@ -49,8 +49,17 @@ class HttpAppFrameworkImpl : public HttpAppFramework
{
public:
HttpAppFrameworkImpl()
: _httpCtrlsRouter(_postRoutingAdvices, _postRoutingObservers, _preHandlingAdvices, _preHandlingObservers, _postHandlingAdvices),
_httpSimpleCtrlsRouter(_httpCtrlsRouter, _postRoutingAdvices, _postRoutingObservers, _preHandlingAdvices, _preHandlingObservers, _postHandlingAdvices),
: _httpCtrlsRouter(_postRoutingAdvices,
_postRoutingObservers,
_preHandlingAdvices,
_preHandlingObservers,
_postHandlingAdvices),
_httpSimpleCtrlsRouter(_httpCtrlsRouter,
_postRoutingAdvices,
_postRoutingObservers,
_preHandlingAdvices,
_preHandlingObservers,
_postHandlingAdvices),
_uploadPath(_rootPath + "uploads"),
_connectionNum(0)
{
@ -72,18 +81,18 @@ public:
const std::string &certFile = "",
const std::string &keyFile = "") override;
virtual void setThreadNum(size_t threadNum) override;
virtual size_t getThreadNum() const override { return _threadNum; }
virtual void setSSLFiles(const std::string &certPath,
const std::string &keyPath) override;
virtual size_t getThreadNum() const override
{
return _threadNum;
}
virtual void setSSLFiles(const std::string &certPath, const std::string &keyPath) override;
virtual void run() override;
virtual void registerWebSocketController(const std::string &pathName,
const std::string &crtlName,
const std::vector<std::string> &filters =
std::vector<std::string>()) override;
const std::vector<std::string> &filters = std::vector<std::string>()) override;
virtual void registerHttpSimpleController(const std::string &pathName,
const std::string &crtlName,
const std::vector<any> &filtersAndMethods =
std::vector<any>()) override;
const std::vector<any> &filtersAndMethods = std::vector<any>()) override;
virtual void setCustom404Page(const HttpResponsePtr &resp) override
{
@ -96,38 +105,40 @@ public:
return _custom404;
}
virtual void forward(const HttpRequestPtr &req, std::function<void(const HttpResponsePtr &)> &&callback, const std::string &hostString = "") override
virtual void forward(const HttpRequestPtr &req,
std::function<void(const HttpResponsePtr &)> &&callback,
const std::string &hostString = "") override
{
forward(std::dynamic_pointer_cast<HttpRequestImpl>(req), std::move(callback), hostString);
}
void forward(const HttpRequestImplPtr &req, std::function<void(const HttpResponsePtr &)> &&callback, const std::string &hostString);
void forward(const HttpRequestImplPtr &req,
std::function<void(const HttpResponsePtr &)> &&callback,
const std::string &hostString);
virtual void registerBeginningAdvice(const std::function<void()> &advice) override
{
getLoop()->runInLoop(advice);
}
virtual void registerNewConnectionAdvice(const std::function<bool(const trantor::InetAddress &, const trantor::InetAddress &)> &advice) override
virtual void registerNewConnectionAdvice(
const std::function<bool(const trantor::InetAddress &, const trantor::InetAddress &)> &advice) override
{
_newConnectionAdvices.emplace_back(advice);
}
virtual void registerPreRoutingAdvice(const std::function<void(const HttpRequestPtr &,
AdviceCallback &&,
AdviceChainCallback &&)> &advice) override
virtual void registerPreRoutingAdvice(
const std::function<void(const HttpRequestPtr &, AdviceCallback &&, AdviceChainCallback &&)> &advice) override
{
_preRoutingAdvices.emplace_back(advice);
}
virtual void registerPostRoutingAdvice(const std::function<void(const HttpRequestPtr &,
AdviceCallback &&,
AdviceChainCallback &&)> &advice) override
virtual void registerPostRoutingAdvice(
const std::function<void(const HttpRequestPtr &, AdviceCallback &&, AdviceChainCallback &&)> &advice) override
{
_postRoutingAdvices.emplace_front(advice);
}
virtual void registerPreHandlingAdvice(const std::function<void(const HttpRequestPtr &,
AdviceCallback &&,
AdviceChainCallback &&)> &advice) override
virtual void registerPreHandlingAdvice(
const std::function<void(const HttpRequestPtr &, AdviceCallback &&, AdviceChainCallback &&)> &advice) override
{
_preHandlingAdvices.emplace_back(advice);
}
@ -144,7 +155,8 @@ public:
{
_preHandlingObservers.emplace_back(advice);
}
virtual void registerPostHandlingAdvice(const std::function<void(const HttpRequestPtr &, const HttpResponsePtr &)> &advice) override
virtual void registerPostHandlingAdvice(
const std::function<void(const HttpRequestPtr &, const HttpResponsePtr &)> &advice) override
{
_postHandlingAdvices.emplace_front(advice);
}
@ -154,42 +166,114 @@ public:
_useSession = true;
_sessionTimeout = timeout;
}
virtual void disableSession() override { _useSession = false; }
virtual const std::string &getDocumentRoot() const override { return _rootPath; }
virtual void setDocumentRoot(const std::string &rootPath) override { _rootPath = rootPath; }
virtual const std::string &getUploadPath() const override { return _uploadPath; }
virtual void disableSession() override
{
_useSession = false;
}
virtual const std::string &getDocumentRoot() const override
{
return _rootPath;
}
virtual void setDocumentRoot(const std::string &rootPath) override
{
_rootPath = rootPath;
}
virtual const std::string &getUploadPath() const override
{
return _uploadPath;
}
virtual void setUploadPath(const std::string &uploadPath) override;
virtual void setFileTypes(const std::vector<std::string> &types) override;
virtual void enableDynamicViewsLoading(const std::vector<std::string> &libPaths) override;
virtual void setMaxConnectionNum(size_t maxConnections) override;
virtual void setMaxConnectionNumPerIP(size_t maxConnectionsPerIP) override;
virtual void loadConfigFile(const std::string &fileName) override;
virtual void enableRunAsDaemon() override { _runAsDaemon = true; }
virtual void enableRelaunchOnError() override { _relaunchOnError = true; }
virtual void enableRunAsDaemon() override
{
_runAsDaemon = true;
}
virtual void enableRelaunchOnError() override
{
_relaunchOnError = true;
}
virtual void setLogPath(const std::string &logPath,
const std::string &logfileBaseName = "",
size_t logfileSize = 100000000) override;
virtual void setLogLevel(trantor::Logger::LogLevel level) override;
virtual void enableSendfile(bool sendFile) override { _useSendfile = sendFile; }
virtual void enableGzip(bool useGzip) override { _useGzip = useGzip; }
virtual bool isGzipEnabled() const override { return _useGzip; }
virtual void setStaticFilesCacheTime(int cacheTime) override { _staticFilesCacheTime = cacheTime; }
virtual int staticFilesCacheTime() const override { return _staticFilesCacheTime; }
virtual void setIdleConnectionTimeout(size_t timeout) override { _idleConnectionTimeout = timeout; }
virtual void setKeepaliveRequestsNumber(const size_t number) override { _keepaliveRequestsNumber = number; }
virtual void setPipeliningRequestsNumber(const size_t number) override { _pipeliningRequestsNumber = number; }
virtual void setGzipStatic(bool useGzipStatic) override { _gzipStaticFlag = useGzipStatic; }
bool getGzipStatic() const { return _gzipStaticFlag; }
virtual void setClientMaxBodySize(size_t maxSize) override { _clientMaxBodySize = maxSize; }
virtual void setClientMaxWebSocketMessageSize(size_t maxSize) override { _clientMaxWebSocketMessageSize = maxSize; }
virtual void setHomePage(const std::string &homePageFile) override { _homePageFile = homePageFile; }
const std::string &getHomePage() const { return _homePageFile; }
size_t getClientMaxBodySize() const { return _clientMaxBodySize; }
size_t getClientMaxWebSocketMessageSize() const { return _clientMaxWebSocketMessageSize; }
virtual void enableSendfile(bool sendFile) override
{
_useSendfile = sendFile;
}
virtual void enableGzip(bool useGzip) override
{
_useGzip = useGzip;
}
virtual bool isGzipEnabled() const override
{
return _useGzip;
}
virtual void setStaticFilesCacheTime(int cacheTime) override
{
_staticFilesCacheTime = cacheTime;
}
virtual int staticFilesCacheTime() const override
{
return _staticFilesCacheTime;
}
virtual void setIdleConnectionTimeout(size_t timeout) override
{
_idleConnectionTimeout = timeout;
}
virtual void setKeepaliveRequestsNumber(const size_t number) override
{
_keepaliveRequestsNumber = number;
}
virtual void setPipeliningRequestsNumber(const size_t number) override
{
_pipeliningRequestsNumber = number;
}
virtual void setGzipStatic(bool useGzipStatic) override
{
_gzipStaticFlag = useGzipStatic;
}
bool getGzipStatic() const
{
return _gzipStaticFlag;
}
virtual void setClientMaxBodySize(size_t maxSize) override
{
_clientMaxBodySize = maxSize;
}
virtual void setClientMaxWebSocketMessageSize(size_t maxSize) override
{
_clientMaxWebSocketMessageSize = maxSize;
}
virtual void setHomePage(const std::string &homePageFile) override
{
_homePageFile = homePageFile;
}
const std::string &getHomePage() const
{
return _homePageFile;
}
size_t getClientMaxBodySize() const
{
return _clientMaxBodySize;
}
size_t getClientMaxWebSocketMessageSize() const
{
return _clientMaxWebSocketMessageSize;
}
virtual std::vector<std::tuple<std::string, HttpMethod, std::string>> getHandlersInfo() const override;
size_t keepaliveRequestsNumber() const { return _keepaliveRequestsNumber; }
size_t pipeliningRequestsNumber() const { return _pipeliningRequestsNumber; }
size_t keepaliveRequestsNumber() const
{
return _keepaliveRequestsNumber;
}
size_t pipeliningRequestsNumber() const
{
return _pipeliningRequestsNumber;
}
virtual ~HttpAppFrameworkImpl() noexcept
{
@ -243,7 +327,10 @@ public:
static HttpAppFrameworkImpl _instance;
return _instance;
}
bool useSendfile() { return _useSendfile; }
bool useSendfile()
{
return _useSendfile;
}
private:
virtual void registerHttpController(const std::string &pathPattern,
@ -262,7 +349,8 @@ private:
const std::vector<std::string> &filters);
// We use a uuid string as session id;
//set _sessionTimeout=0 to make location session valid forever based on cookies;
// set _sessionTimeout=0 to make location session valid forever based on
// cookies;
size_t _sessionTimeout = 0;
size_t _idleConnectionTimeout = 60;
bool _useSession = false;
@ -279,9 +367,25 @@ private:
WebsocketControllersRouter _websockCtrlsRouter;
bool _enableLastModify = true;
std::set<std::string> _fileTypeSet = {"html", "js", "css", "xml", "xsl", "txt", "svg", "ttf",
"otf", "woff2", "woff", "eot", "png", "jpg", "jpeg",
"gif", "bmp", "ico", "icns"};
std::set<std::string> _fileTypeSet = {"html",
"js",
"css",
"xml",
"xsl",
"txt",
"svg",
"ttf",
"otf",
"woff2",
"woff",
"eot",
"png",
"jpg",
"jpeg",
"gif",
"bmp",
"ico",
"icns"};
std::string _rootPath = "./";
std::string _uploadPath;
std::atomic_bool _running;
@ -336,21 +440,10 @@ private:
#endif
static InitBeforeMainFunction _initFirst;
std::vector<std::function<bool(const trantor::InetAddress &, const trantor::InetAddress &)>> _newConnectionAdvices;
std::vector<std::function<void(const HttpRequestPtr &,
AdviceCallback &&,
AdviceChainCallback &&)>>
_preRoutingAdvices;
std::deque<std::function<void(const HttpRequestPtr &,
AdviceCallback &&,
AdviceChainCallback &&)>>
_postRoutingAdvices;
std::vector<std::function<void(const HttpRequestPtr &,
AdviceCallback &&,
AdviceChainCallback &&)>>
_preHandlingAdvices;
std::deque<std::function<void(const HttpRequestPtr &,
const HttpResponsePtr &)>>
_postHandlingAdvices;
std::vector<std::function<void(const HttpRequestPtr &, AdviceCallback &&, AdviceChainCallback &&)>> _preRoutingAdvices;
std::deque<std::function<void(const HttpRequestPtr &, AdviceCallback &&, AdviceChainCallback &&)>> _postRoutingAdvices;
std::vector<std::function<void(const HttpRequestPtr &, AdviceCallback &&, AdviceChainCallback &&)>> _preHandlingAdvices;
std::deque<std::function<void(const HttpRequestPtr &, const HttpResponsePtr &)>> _postHandlingAdvices;
std::vector<std::function<void(const HttpRequestPtr &)>> _preRoutingObservers;
std::deque<std::function<void(const HttpRequestPtr &)>> _postRoutingObservers;

View File

@ -13,27 +13,21 @@
*/
#include "HttpClientImpl.h"
#include "HttpAppFrameworkImpl.h"
#include "HttpRequestImpl.h"
#include "HttpResponseParser.h"
#include "HttpAppFrameworkImpl.h"
#include <stdlib.h>
#include <algorithm>
#include <stdlib.h>
using namespace drogon;
using namespace std::placeholders;
HttpClientImpl::HttpClientImpl(trantor::EventLoop *loop,
const trantor::InetAddress &addr,
bool useSSL)
: _loop(loop),
_server(addr),
_useSSL(useSSL)
HttpClientImpl::HttpClientImpl(trantor::EventLoop *loop, const trantor::InetAddress &addr, bool useSSL)
: _loop(loop), _server(addr), _useSSL(useSSL)
{
}
HttpClientImpl::HttpClientImpl(trantor::EventLoop *loop,
const std::string &hostString)
: _loop(loop)
HttpClientImpl::HttpClientImpl(trantor::EventLoop *loop, const std::string &hostString) : _loop(loop)
{
auto lowerHost = hostString;
std::transform(lowerHost.begin(), lowerHost.end(), lowerHost.begin(), tolower);
@ -129,21 +123,16 @@ HttpClientImpl::~HttpClientImpl()
void HttpClientImpl::sendRequest(const drogon::HttpRequestPtr &req, const drogon::HttpReqCallback &callback)
{
auto thisPtr = shared_from_this();
_loop->runInLoop([thisPtr, req, callback]() {
thisPtr->sendRequestInLoop(req, callback);
});
_loop->runInLoop([thisPtr, req, callback]() { thisPtr->sendRequestInLoop(req, callback); });
}
void HttpClientImpl::sendRequest(const drogon::HttpRequestPtr &req, drogon::HttpReqCallback &&callback)
{
auto thisPtr = shared_from_this();
_loop->runInLoop([thisPtr, req, callback = std::move(callback)]() {
thisPtr->sendRequestInLoop(req, callback);
});
_loop->runInLoop([ thisPtr, req, callback = std::move(callback) ]() { thisPtr->sendRequestInLoop(req, callback); });
}
void HttpClientImpl::sendRequestInLoop(const drogon::HttpRequestPtr &req,
const drogon::HttpReqCallback &callback)
void HttpClientImpl::sendRequestInLoop(const drogon::HttpRequestPtr &req, const drogon::HttpReqCallback &callback)
{
_loop->assertInLoopThread();
req->addHeader("Connection", "Keep-Alive");
@ -170,16 +159,13 @@ void HttpClientImpl::sendRequestInLoop(const drogon::HttpRequestPtr &req,
}
}
if (_server.ipNetEndian() == 0 && !hasIpv6Address &&
!_domain.empty() &&
_server.portNetEndian() != 0)
if (_server.ipNetEndian() == 0 && !hasIpv6Address && !_domain.empty() && _server.portNetEndian() != 0)
{
// dns
// TODO: timeout should be set by user
if (InetAddress::resolve(_domain, &_server) == false)
{
callback(ReqResult::BadServerAddress,
HttpResponse::newHttpResponse());
callback(ReqResult::BadServerAddress, HttpResponse::newHttpResponse());
return;
}
LOG_TRACE << "dns:domain=" << _domain << ";ip=" << _server.toIp();
@ -199,9 +185,8 @@ void HttpClientImpl::sendRequestInLoop(const drogon::HttpRequestPtr &req,
auto thisPtr = shared_from_this();
std::weak_ptr<HttpClientImpl> weakPtr = thisPtr;
assert(_requestsBuffer.empty());
_requestsBuffer.push({req, [thisPtr, callback](ReqResult result, const HttpResponsePtr &response) {
callback(result, response);
}});
_requestsBuffer.push(
{req, [thisPtr, callback](ReqResult result, const HttpResponsePtr &response) { callback(result, response); }});
_tcpClient->setConnectionCallback([weakPtr](const trantor::TcpConnectionPtr &connPtr) {
auto thisPtr = weakPtr.lock();
if (!thisPtr)
@ -243,8 +228,7 @@ void HttpClientImpl::sendRequestInLoop(const drogon::HttpRequestPtr &req,
}
else
{
callback(ReqResult::BadServerAddress,
HttpResponse::newHttpResponse());
callback(ReqResult::BadServerAddress, HttpResponse::newHttpResponse());
return;
}
}
@ -258,9 +242,8 @@ void HttpClientImpl::sendRequestInLoop(const drogon::HttpRequestPtr &req,
if (_pipeliningCallbacks.size() <= _pipeliningDepth && _requestsBuffer.empty())
{
sendReq(connPtr, req);
_pipeliningCallbacks.push([thisPtr, callback](ReqResult result, const HttpResponsePtr &response) {
callback(result, response);
});
_pipeliningCallbacks.push(
[thisPtr, callback](ReqResult result, const HttpResponsePtr &response) { callback(result, response); });
}
else
{
@ -271,16 +254,14 @@ void HttpClientImpl::sendRequestInLoop(const drogon::HttpRequestPtr &req,
}
else
{
_requestsBuffer.push({req, [thisPtr, callback](ReqResult result, const HttpResponsePtr &response) {
callback(result, response);
}});
_requestsBuffer.push(
{req, [thisPtr, callback](ReqResult result, const HttpResponsePtr &response) { callback(result, response); }});
}
}
}
void HttpClientImpl::sendReq(const trantor::TcpConnectionPtr &connPtr, const HttpRequestPtr &req)
{
trantor::MsgBuffer buffer;
auto implPtr = std::dynamic_pointer_cast<HttpRequestImpl>(req);
assert(implPtr);
@ -348,7 +329,8 @@ void HttpClientImpl::onRecvMessage(const trantor::TcpConnectionPtr &connPtr, tra
HttpClientPtr HttpClient::newHttpClient(const std::string &ip, uint16_t port, bool useSSL, trantor::EventLoop *loop)
{
bool isIpv6 = ip.find(":") == std::string::npos ? false : true;
return std::make_shared<HttpClientImpl>(loop == nullptr ? app().getLoop() : loop, trantor::InetAddress(ip, port, isIpv6), useSSL);
return std::make_shared<HttpClientImpl>(
loop == nullptr ? app().getLoop() : loop, trantor::InetAddress(ip, port, isIpv6), useSSL);
}
HttpClientPtr HttpClient::newHttpClient(const std::string &hostString, trantor::EventLoop *loop)

View File

@ -15,10 +15,10 @@
#pragma once
#include <drogon/HttpClient.h>
#include <trantor/net/EventLoop.h>
#include <trantor/net/TcpClient.h>
#include <mutex>
#include <queue>
#include <trantor/net/EventLoop.h>
#include <trantor/net/TcpClient.h>
namespace drogon
{
@ -29,7 +29,10 @@ class HttpClientImpl : public HttpClient, public std::enable_shared_from_this<Ht
HttpClientImpl(trantor::EventLoop *loop, const std::string &hostString);
virtual void sendRequest(const HttpRequestPtr &req, const HttpReqCallback &callback) override;
virtual void sendRequest(const HttpRequestPtr &req, HttpReqCallback &&callback) override;
virtual trantor::EventLoop *getLoop() override { return _loop; }
virtual trantor::EventLoop *getLoop() override
{
return _loop;
}
virtual void setPipeliningDepth(size_t depth) override
{
_pipeliningDepth = depth;

View File

@ -12,23 +12,22 @@
*
*/
#include "FiltersFunction.h"
#include "HttpControllersRouter.h"
#include "FiltersFunction.h"
#include "HttpAppFrameworkImpl.h"
#include "HttpRequestImpl.h"
#include "HttpResponseImpl.h"
#include "HttpAppFrameworkImpl.h"
using namespace drogon;
namespace drogon
{
static void doWhenNoHandlerFound(const HttpRequestImplPtr &req,
std::function<void(const HttpResponsePtr &)> &&callback)
static void doWhenNoHandlerFound(const HttpRequestImplPtr &req, std::function<void(const HttpResponsePtr &)> &&callback)
{
if (req->path() == "/" && !HttpAppFrameworkImpl::instance().getHomePage().empty())
{
// auto resp = drogon::HttpResponse::newRedirectionResponse("/" + HttpAppFrameworkImpl::instance().getHomePage());
// auto resp = drogon::HttpResponse::newRedirectionResponse("/" +
// HttpAppFrameworkImpl::instance().getHomePage());
// callback(resp);
// Redirect on the server side
req->setPath("/" + HttpAppFrameworkImpl::instance().getHomePage());
@ -76,10 +75,11 @@ std::vector<std::tuple<std::string, HttpMethod, std::string>> HttpControllersRou
{
if (item._binders[i])
{
auto description = item._binders[i]->_handlerName.empty() ? std::string("Handler: ") + item._binders[i]->_binderPtr->handlerName() : std::string("HttpController: ") + item._binders[i]->_handlerName;
auto info = std::tuple<std::string, HttpMethod, std::string>(item._pathPattern,
(HttpMethod)i,
std::move(description));
auto description = item._binders[i]->_handlerName.empty()
? std::string("Handler: ") + item._binders[i]->_binderPtr->handlerName()
: std::string("HttpController: ") + item._binders[i]->_handlerName;
auto info =
std::tuple<std::string, HttpMethod, std::string>(item._pathPattern, (HttpMethod)i, std::move(description));
ret.emplace_back(std::move(info));
}
}
@ -112,8 +112,7 @@ void HttpControllersRouter::addHttpPath(const std::string &path,
size_t place = (size_t)std::stoi(results[1].str());
if (place > binder->paramCount() || place == 0)
{
LOG_ERROR << "parameter placeholder(value=" << place << ") out of range (1 to "
<< binder->paramCount() << ")";
LOG_ERROR << "parameter placeholder(value=" << place << ") out of range (1 to " << binder->paramCount() << ")";
exit(0);
}
places.push_back(place);
@ -131,8 +130,8 @@ void HttpControllersRouter::addHttpPath(const std::string &path,
size_t place = (size_t)std::stoi(results[2].str());
if (place > binder->paramCount() || place == 0)
{
LOG_ERROR << "parameter placeholder(value=" << place << ") out of range (1 to "
<< binder->paramCount() << ")";
LOG_ERROR << "parameter placeholder(value=" << place << ") out of range (1 to " << binder->paramCount()
<< ")";
exit(0);
}
parametersPlaces[results[1].str()] = place;
@ -209,7 +208,8 @@ void HttpControllersRouter::route(const HttpRequestImplPtr &req,
{
for (size_t i = 1; i < result.size(); i++)
{
//TODO: Is there any better way to find the sub-match index without using loop?
// TODO: Is there any better way to find the sub-match index without
// using loop?
if (!result[i].matched)
continue;
if (i <= _ctrlVector.size())
@ -247,35 +247,54 @@ void HttpControllersRouter::route(const HttpRequestImplPtr &req,
{
auto &filters = binder->_filters;
auto sessionIdPtr = std::make_shared<std::string>(std::move(sessionId));
auto callbackPtr = std::make_shared<std::function<void(const HttpResponsePtr &)>>(std::move(callback));
FiltersFunction::doFilters(filters, req, callbackPtr, needSetJsessionid, sessionIdPtr, [=, &binder, &routerItem]() {
doPreHandlingAdvices(binder, routerItem, req, std::move(*callbackPtr), needSetJsessionid, std::move(*sessionIdPtr));
auto callbackPtr =
std::make_shared<std::function<void(const HttpResponsePtr &)>>(std::move(callback));
FiltersFunction::doFilters(
filters, req, callbackPtr, needSetJsessionid, sessionIdPtr, [=, &binder, &routerItem]() {
doPreHandlingAdvices(binder,
routerItem,
req,
std::move(*callbackPtr),
needSetJsessionid,
std::move(*sessionIdPtr));
});
}
else
{
doPreHandlingAdvices(binder, routerItem, req, std::move(callback), needSetJsessionid, std::move(sessionId));
doPreHandlingAdvices(
binder, routerItem, req, std::move(callback), needSetJsessionid, std::move(sessionId));
}
}
else
{
auto callbackPtr = std::make_shared<std::function<void(const HttpResponsePtr &)>>(std::move(callback));
doAdvicesChain(_postRoutingAdvices,
0,
req,
doAdvicesChain(_postRoutingAdvices, 0, req, callbackPtr, [
&binder,
sessionId = std::move(sessionId),
callbackPtr,
[&binder, sessionId = std::move(sessionId), callbackPtr, req, needSetJsessionid, this, &routerItem]() mutable {
req,
needSetJsessionid,
this,
&routerItem
]() mutable {
if (!binder->_filters.empty())
{
auto &filters = binder->_filters;
auto sessionIdPtr = std::make_shared<std::string>(std::move(sessionId));
FiltersFunction::doFilters(filters, req, callbackPtr, needSetJsessionid, sessionIdPtr, [=, &binder, &routerItem]() {
doPreHandlingAdvices(binder, routerItem, req, std::move(*callbackPtr), needSetJsessionid, std::move(*sessionIdPtr));
FiltersFunction::doFilters(
filters, req, callbackPtr, needSetJsessionid, sessionIdPtr, [=, &binder, &routerItem]() {
doPreHandlingAdvices(binder,
routerItem,
req,
std::move(*callbackPtr),
needSetJsessionid,
std::move(*sessionIdPtr));
});
}
else
{
doPreHandlingAdvices(binder, routerItem, req, std::move(*callbackPtr), needSetJsessionid, std::move(sessionId));
doPreHandlingAdvices(
binder, routerItem, req, std::move(*callbackPtr), needSetJsessionid, std::move(sessionId));
}
});
}
@ -303,7 +322,8 @@ void HttpControllersRouter::doControllerHandler(const CtrlBinderPtr &ctrlBinderP
std::string &&sessionId)
{
HttpResponsePtr &responsePtr = ctrlBinderPtr->_responsePtrMap[req->getLoop()];
if (responsePtr && (responsePtr->expiredTime() == 0 || (trantor::Date::now() < responsePtr->creationDate().after(responsePtr->expiredTime()))))
if (responsePtr && (responsePtr->expiredTime() == 0 ||
(trantor::Date::now() < responsePtr->creationDate().after(responsePtr->expiredTime()))))
{
// use cached response!
LOG_TRACE << "Use cached response";
@ -339,8 +359,7 @@ void HttpControllersRouter::doControllerHandler(const CtrlBinderPtr &ctrlBinderP
auto qureyPara = req->getParameters();
for (auto const &parameter : qureyPara)
{
if (ctrlBinderPtr->_queryParametersPlaces.find(parameter.first) !=
ctrlBinderPtr->_queryParametersPlaces.end())
if (ctrlBinderPtr->_queryParametersPlaces.find(parameter.first) != ctrlBinderPtr->_queryParametersPlaces.end())
{
auto place = ctrlBinderPtr->_queryParametersPlaces.find(parameter.first)->second;
if (place > params.size())
@ -355,7 +374,8 @@ void HttpControllersRouter::doControllerHandler(const CtrlBinderPtr &ctrlBinderP
LOG_TRACE << p;
paraList.push_back(std::move(p));
}
ctrlBinderPtr->_binderPtr->handleHttpRequest(paraList, req, [=, callback = std::move(callback), sessionId = std::move(sessionId)](const HttpResponsePtr &resp) {
ctrlBinderPtr->_binderPtr->handleHttpRequest(
paraList, req, [ =, callback = std::move(callback), sessionId = std::move(sessionId) ](const HttpResponsePtr &resp) {
LOG_TRACE << "http resp:needSetJsessionid=" << needSetJsessionid << ";JSESSIONID=" << sessionId;
auto newResp = resp;
if (resp->expiredTime() >= 0)
@ -369,9 +389,7 @@ void HttpControllersRouter::doControllerHandler(const CtrlBinderPtr &ctrlBinderP
}
else
{
req->getLoop()->queueInLoop([loop, resp, ctrlBinderPtr]() {
ctrlBinderPtr->_responsePtrMap[loop] = resp;
});
req->getLoop()->queueInLoop([loop, resp, ctrlBinderPtr]() { ctrlBinderPtr->_responsePtrMap[loop] = resp; });
}
}
if (needSetJsessionid && resp->statusCode() != k404NotFound)
@ -437,10 +455,12 @@ void HttpControllersRouter::doPreHandlingAdvices(const CtrlBinderPtr &ctrlBinder
{
auto callbackPtr = std::make_shared<std::function<void(const HttpResponsePtr &)>>(std::move(callback));
auto sessionIdPtr = std::make_shared<std::string>(std::move(sessionId));
doAdvicesChain(_preHandlingAdvices,
doAdvicesChain(
_preHandlingAdvices,
0,
req,
std::make_shared<std::function<void(const HttpResponsePtr &)>>([callbackPtr, needSetJsessionid, sessionIdPtr](const HttpResponsePtr &resp) {
std::make_shared<std::function<void(const HttpResponsePtr &)>>(
[callbackPtr, needSetJsessionid, sessionIdPtr](const HttpResponsePtr &resp) {
if (!needSetJsessionid || resp->statusCode() == k404NotFound)
(*callbackPtr)(resp);
else
@ -450,7 +470,8 @@ void HttpControllersRouter::doPreHandlingAdvices(const CtrlBinderPtr &ctrlBinder
}
}),
[this, ctrlBinderPtr, &routerItem, req, callbackPtr, needSetJsessionid, sessionIdPtr]() {
doControllerHandler(ctrlBinderPtr, routerItem, req, std::move(*callbackPtr), needSetJsessionid, std::move(*sessionIdPtr));
doControllerHandler(
ctrlBinderPtr, routerItem, req, std::move(*callbackPtr), needSetJsessionid, std::move(*sessionIdPtr));
});
}
}

View File

@ -13,39 +13,32 @@
*/
#pragma once
#include "AOPAdvice.h"
#include "HttpRequestImpl.h"
#include "HttpResponseImpl.h"
#include "AOPAdvice.h"
#include <trantor/utils/NonCopyable.h>
#include <atomic>
#include <drogon/HttpBinder.h>
#include <drogon/HttpFilter.h>
#include <vector>
#include <memory>
#include <mutex>
#include <regex>
#include <string>
#include <mutex>
#include <memory>
#include <atomic>
#include <trantor/utils/NonCopyable.h>
#include <vector>
namespace drogon
{
class HttpControllersRouter : public trantor::NonCopyable
{
public:
HttpControllersRouter(const std::deque<std::function<void(const HttpRequestPtr &,
AdviceCallback &&,
AdviceChainCallback &&)>>
HttpControllersRouter(
const std::deque<std::function<void(const HttpRequestPtr &, AdviceCallback &&, AdviceChainCallback &&)>>
&postRoutingAdvices,
const std::deque<std::function<void(const HttpRequestPtr &)>>
&postRoutingObservers,
const std::vector<std::function<void(const HttpRequestPtr &,
AdviceCallback &&,
AdviceChainCallback &&)>>
const std::deque<std::function<void(const HttpRequestPtr &)>> &postRoutingObservers,
const std::vector<std::function<void(const HttpRequestPtr &, AdviceCallback &&, AdviceChainCallback &&)>>
&preHandlingAdvices,
const std::vector<std::function<void(const HttpRequestPtr &)>>
&preHandlingObservers,
const std::deque<std::function<void(const HttpRequestPtr &,
const HttpResponsePtr &)>>
&postHandlingAdvices)
const std::vector<std::function<void(const HttpRequestPtr &)>> &preHandlingObservers,
const std::deque<std::function<void(const HttpRequestPtr &, const HttpResponsePtr &)>> &postHandlingAdvices)
: _postRoutingAdvices(postRoutingAdvices),
_preHandlingAdvices(preHandlingAdvices),
_postRoutingObservers(postRoutingObservers),
@ -89,19 +82,13 @@ private:
std::mutex _ctrlMutex;
std::regex _ctrlRegex;
const std::deque<std::function<void(const HttpRequestPtr &,
AdviceCallback &&,
AdviceChainCallback &&)>> &_postRoutingAdvices;
const std::vector<std::function<void(const HttpRequestPtr &,
AdviceCallback &&,
AdviceChainCallback &&)>> &_preHandlingAdvices;
const std::deque<std::function<void(const HttpRequestPtr &)>>
&_postRoutingObservers;
const std::vector<std::function<void(const HttpRequestPtr &)>>
&_preHandlingObservers;
const std::deque<std::function<void(const HttpRequestPtr &,
const HttpResponsePtr &)>>
&_postHandlingAdvices;
const std::deque<std::function<void(const HttpRequestPtr &, AdviceCallback &&, AdviceChainCallback &&)>>
&_postRoutingAdvices;
const std::vector<std::function<void(const HttpRequestPtr &, AdviceCallback &&, AdviceChainCallback &&)>>
&_preHandlingAdvices;
const std::deque<std::function<void(const HttpRequestPtr &)>> &_postRoutingObservers;
const std::vector<std::function<void(const HttpRequestPtr &)>> &_preHandlingObservers;
const std::deque<std::function<void(const HttpRequestPtr &, const HttpResponsePtr &)>> &_postHandlingAdvices;
void doPreHandlingAdvices(const CtrlBinderPtr &ctrlBinderPtr,
const HttpControllerRouterItem &routerItem,

View File

@ -18,9 +18,7 @@
using namespace drogon;
HttpFileUploadRequest::HttpFileUploadRequest(const std::vector<UploadFile> &files)
: HttpRequestImpl(nullptr),
_boundary(utils::genRandomString(32)),
_files(files)
: HttpRequestImpl(nullptr), _boundary(utils::genRandomString(32)), _files(files)
{
setMethod(drogon::Post);
setVersion(drogon::HttpRequest::kHttp11);

View File

@ -19,12 +19,17 @@
namespace drogon
{
class HttpFileUploadRequest : public HttpRequestImpl
{
public:
const std::string &boundary() const { return _boundary; }
const std::vector<UploadFile> &files() const { return _files; }
const std::string &boundary() const
{
return _boundary;
}
const std::vector<UploadFile> &files() const
{
return _files;
}
explicit HttpFileUploadRequest(const std::vector<UploadFile> &files);
private:

17
lib/src/HttpRequestImpl.cc Executable file → Normal file
View File

@ -15,8 +15,8 @@
#include "HttpRequestImpl.h"
#include "HttpFileUploadRequest.h"
#include <drogon/utils/Utilities.h>
#include <iostream>
#include <fstream>
#include <iostream>
#include <unistd.h>
using namespace drogon;
@ -28,9 +28,9 @@ void HttpRequestImpl::parseParameters() const
return;
std::string type = getHeaderBy("content-type");
std::transform(type.begin(), type.end(), type.begin(), tolower);
if (_method == Get || (_method == Post && (type == "" || type.find("application/x-www-form-urlencoded") != std::string::npos)))
if (_method == Get ||
(_method == Post && (type == "" || type.find("application/x-www-form-urlencoded") != std::string::npos)))
{
std::string::size_type pos = 0;
while ((input[pos] == '?' || isspace(input[pos])) && pos < input.length())
{
@ -153,7 +153,6 @@ void HttpRequestImpl::appendToBuffer(MsgBuffer *output) const
}
else
{
output->append("?");
}
output->append(content);
@ -162,8 +161,11 @@ void HttpRequestImpl::appendToBuffer(MsgBuffer *output) const
else if (_contentType == CT_APPLICATION_JSON)
{
/// Can't set parameters in content in this case
LOG_ERROR << "You can't set parameters in the query string when the request content type is JSON and http method is POST or PUT";
LOG_ERROR << "Please put these parameters into the path or into the json string";
LOG_ERROR << "You can't set parameters in the query string when the "
"request content type is JSON and http method "
"is POST or PUT";
LOG_ERROR << "Please put these parameters into the path or into the json "
"string";
content.clear();
}
}
@ -234,7 +236,8 @@ void HttpRequestImpl::appendToBuffer(MsgBuffer *output) const
if (!content.empty() || !_content.empty())
{
char buf[64];
auto len = snprintf(buf, sizeof(buf), "Content-Length: %lu\r\n", static_cast<long unsigned int>(content.length() + _content.length()));
auto len = snprintf(
buf, sizeof(buf), "Content-Length: %lu\r\n", static_cast<long unsigned int>(content.length() + _content.length()));
output->append(buf, len);
if (_contentTypeString.empty())
{

34
lib/src/HttpRequestImpl.h Executable file → Normal file
View File

@ -15,44 +15,42 @@
#pragma once
#include "HttpUtils.h"
#include <drogon/utils/Utilities.h>
#include <drogon/HttpRequest.h>
#include <drogon/HttpResponse.h>
#include <drogon/utils/Utilities.h>
#include <trantor/utils/NonCopyable.h>
#include <trantor/net/EventLoop.h>
#include <trantor/net/InetAddress.h>
#include <trantor/utils/Logger.h>
#include <trantor/utils/MsgBuffer.h>
#include <trantor/net/InetAddress.h>
#include <trantor/net/EventLoop.h>
#include <trantor/utils/NonCopyable.h>
#include <unordered_map>
#include <algorithm>
#include <assert.h>
#include <stdio.h>
#include <algorithm>
#include <string>
#include <thread>
#include <unordered_map>
using std::string;
using namespace trantor;
namespace drogon
{
class HttpRequestImpl : public HttpRequest
{
public:
friend class HttpRequestParser;
explicit HttpRequestImpl(trantor::EventLoop *loop)
: _method(Invalid),
_version(kUnknown),
_date(trantor::Date::now()),
_contentLen(0),
_loop(loop)
: _method(Invalid), _version(kUnknown), _date(trantor::Date::now()), _contentLen(0), _loop(loop)
{
}
trantor::EventLoop *getLoop() { return _loop; }
trantor::EventLoop *getLoop()
{
return _loop;
}
void setVersion(Version v)
{
@ -66,7 +64,6 @@ public:
bool setMethod(const char *start, const char *end)
{
assert(_method == Invalid);
string_view m(start, end - start);
switch (m.length())
@ -196,7 +193,8 @@ public:
return _parameters;
}
virtual const std::string &getParameter(const std::string &key, const std::string &defaultVal = std::string()) const override
virtual const std::string &getParameter(const std::string &key,
const std::string &defaultVal = std::string()) const override
{
parseParametersOnce();
auto iter = _parameters.find(key);
@ -386,7 +384,8 @@ public:
setContentType(std::string(typeStr.data(), typeStr.length()));
}
// virtual void setContentTypeCodeAndCharacterSet(ContentType type, const std::string &charSet = "utf-8") override
// virtual void setContentTypeCodeAndCharacterSet(ContentType type, const
// std::string &charSet = "utf-8") override
// {
// _contentType = type;
// setContentType(webContentTypeAndCharsetToString(type, charSet));
@ -422,7 +421,8 @@ private:
void parseParameters() const;
void parseParametersOnce() const
{
//Not multi-thread safe but good, because we basically call this function in a single thread
// Not multi-thread safe but good, because we basically call this function
// in a single thread
if (!_flagForParsingParameters)
{
_flagForParsingParameters = true;

17
lib/src/HttpRequestParser.cc Executable file → Normal file
View File

@ -12,14 +12,14 @@
*
*/
#include <drogon/HttpTypes.h>
#include <trantor/utils/MsgBuffer.h>
#include <trantor/utils/Logger.h>
#include "HttpAppFrameworkImpl.h"
#include "HttpRequestParser.h"
#include "HttpAppFrameworkImpl.h"
#include "HttpResponseImpl.h"
#include "HttpUtils.h"
#include <drogon/HttpTypes.h>
#include <iostream>
#include <trantor/utils/Logger.h>
#include <trantor/utils/MsgBuffer.h>
using namespace trantor;
using namespace drogon;
@ -139,7 +139,8 @@ bool HttpRequestParser::parseRequest(MsgBuffer *buf)
{
if (buf->readableBytes() >= 64 * 1024)
{
/// The limit for request line is 64K bytes. respone k414RequestURITooLarge
/// The limit for request line is 64K bytes. respone
/// k414RequestURITooLarge
/// TODO: Make this configurable?
buf->retrieveAll();
shutdownConnection(k414RequestURITooLarge);
@ -168,8 +169,7 @@ bool HttpRequestParser::parseRequest(MsgBuffer *buf)
_request->_contentLen = atoi(len.c_str());
_state = HttpRequestParseState_ExpectBody;
auto &expect = _request->getHeaderBy("expect");
if (expect == "100-continue" &&
_request->getVersion() >= HttpRequest::kHttp11)
if (expect == "100-continue" && _request->getVersion() >= HttpRequest::kHttp11)
{
if (_request->_contentLen == 0)
{
@ -330,8 +330,7 @@ void HttpRequestParser::popFirstRequest()
_requestPipelining.pop_front();
}
void HttpRequestParser::pushResponseToPipelining(const HttpRequestPtr &req,
const HttpResponsePtr &resp)
void HttpRequestParser::pushResponseToPipelining(const HttpRequestPtr &req, const HttpResponsePtr &resp)
{
#ifndef NDEBUG
auto conn = _conn.lock();

24
lib/src/HttpRequestParser.h Executable file → Normal file
View File

@ -16,11 +16,11 @@
#include "HttpRequestImpl.h"
#include "WebSocketConnectionImpl.h"
#include <trantor/utils/MsgBuffer.h>
#include <drogon/HttpResponse.h>
#include <deque>
#include <drogon/HttpResponse.h>
#include <mutex>
#include <trantor/net/TcpConnection.h>
#include <trantor/utils/MsgBuffer.h>
using namespace trantor;
namespace drogon
@ -86,10 +86,22 @@ class HttpRequestParser
HttpResponsePtr getFirstResponse() const;
void popFirstRequest();
void pushResponseToPipelining(const HttpRequestPtr &req, const HttpResponsePtr &resp);
size_t numberOfRequestsInPipelining() const { return _requestPipelining.size(); }
bool isStop() const { return _stopWorking; }
void stop() { _stopWorking = true; }
size_t numberOfRequestsParsed() const { return _requestsCounter; }
size_t numberOfRequestsInPipelining() const
{
return _requestPipelining.size();
}
bool isStop() const
{
return _stopWorking;
}
void stop()
{
_stopWorking = true;
}
size_t numberOfRequestsParsed() const
{
return _requestsCounter;
}
private:
void shutdownConnection(HttpStatusCode code);

22
lib/src/HttpResponseImpl.cc Executable file → Normal file
View File

@ -12,17 +12,17 @@
*
*/
#include "HttpAppFrameworkImpl.h"
#include "HttpResponseImpl.h"
#include "HttpAppFrameworkImpl.h"
#include "HttpUtils.h"
#include <drogon/HttpAppFramework.h>
#include <drogon/HttpViewBase.h>
#include <drogon/HttpViewData.h>
#include <drogon/HttpAppFramework.h>
#include <trantor/utils/Logger.h>
#include <memory>
#include <fstream>
#include <memory>
#include <stdio.h>
#include <sys/stat.h>
#include <trantor/utils/Logger.h>
using namespace trantor;
using namespace drogon;
@ -79,9 +79,10 @@ HttpResponsePtr HttpResponse::newHttpViewResponse(const std::string &viewName, c
return HttpViewBase::genHttpResponse(viewName, data);
}
HttpResponsePtr HttpResponse::newFileResponse(const std::string &fullPath, const std::string &attachmentFileName, ContentType type)
HttpResponsePtr HttpResponse::newFileResponse(const std::string &fullPath,
const std::string &attachmentFileName,
ContentType type)
{
std::ifstream infile(fullPath, std::ifstream::binary);
LOG_TRACE << "send http file:" << fullPath;
if (!infile)
@ -93,11 +94,11 @@ HttpResponsePtr HttpResponse::newFileResponse(const std::string &fullPath, const
std::streambuf *pbuf = infile.rdbuf();
std::streamsize filesize = pbuf->pubseekoff(0, infile.end);
pbuf->pubseekoff(0, infile.beg); // rewind
if (HttpAppFrameworkImpl::instance().useSendfile() &&
filesize > 1024 * 200)
if (HttpAppFrameworkImpl::instance().useSendfile() && filesize > 1024 * 200)
// TODO : Is 200k an appropriate value? Or set it to be configurable
{
//The advantages of sendfile() can only be reflected in sending large files.
// The advantages of sendfile() can only be reflected in sending large
// files.
resp->setSendfile(fullPath);
}
else
@ -166,7 +167,6 @@ void HttpResponseImpl::makeHeaderString(const std::shared_ptr<std::string> &head
}
else
{
// output->append("Connection: Keep-Alive\r\n");
}
}
@ -219,7 +219,6 @@ std::shared_ptr<std::string> HttpResponseImpl::renderToString() const
{
for (auto it = _cookies.begin(); it != _cookies.end(); ++it)
{
httpString->append(it->second.cookieString());
}
}
@ -258,7 +257,6 @@ std::shared_ptr<std::string> HttpResponseImpl::renderHeaderForHeadMethod() const
{
for (auto it = _cookies.begin(); it != _cookies.end(); ++it)
{
httpString->append(it->second.cookieString());
}
}

23
lib/src/HttpResponseImpl.h Executable file → Normal file
View File

@ -15,16 +15,16 @@
#pragma once
#include "HttpUtils.h"
#include <atomic>
#include <drogon/HttpResponse.h>
#include <trantor/utils/MsgBuffer.h>
#include <trantor/net/InetAddress.h>
#include <trantor/utils/Date.h>
#include <drogon/utils/Utilities.h>
#include <unordered_map>
#include <string>
#include <memory>
#include <mutex>
#include <atomic>
#include <string>
#include <trantor/net/InetAddress.h>
#include <trantor/utils/Date.h>
#include <trantor/utils/MsgBuffer.h>
#include <unordered_map>
using namespace trantor;
namespace drogon
@ -71,7 +71,8 @@ public:
setStatusMessage(statusCodeToString(code));
}
// virtual void setStatusCode(HttpStatusCode code, const std::string &status_message) override
// virtual void setStatusCode(HttpStatusCode code, const std::string
// &status_message) override
// {
// _statusCode = code;
// setStatusMessage(status_message);
@ -98,7 +99,8 @@ public:
setContentType(webContentTypeToString(type));
}
// virtual void setContentTypeCodeAndCharacterSet(ContentType type, const std::string &charSet = "utf-8") override
// virtual void setContentTypeCodeAndCharacterSet(ContentType type, const
// std::string &charSet = "utf-8") override
// {
// _contentType = type;
// setContentType(webContentTypeAndCharsetToString(type, charSet));
@ -320,7 +322,10 @@ public:
_expriedTime = expiredTime;
}
virtual ssize_t expiredTime() const override { return _expriedTime; }
virtual ssize_t expiredTime() const override
{
return _expriedTime;
}
// void setReceiveTime(trantor::Date t)
// {

10
lib/src/HttpResponseParser.cc Executable file → Normal file
View File

@ -12,15 +12,14 @@
*
*/
#include <trantor/utils/MsgBuffer.h>
#include <trantor/utils/Logger.h>
#include "HttpResponseParser.h"
#include <iostream>
#include <trantor/utils/Logger.h>
#include <trantor/utils/MsgBuffer.h>
using namespace trantor;
using namespace drogon;
HttpResponseParser::HttpResponseParser(const trantor::TcpConnectionPtr &connPtr)
: _state(HttpResponseParseState::kExpectResponseLine),
_response(new HttpResponseImpl)
: _state(HttpResponseParseState::kExpectResponseLine), _response(new HttpResponseImpl)
{
}
@ -118,7 +117,8 @@ bool HttpResponseParser::parseResponse(MsgBuffer *buf)
}
else
{
if (_response->statusCode() == k204NoContent || (_response->statusCode() == k101SwitchingProtocols &&
if (_response->statusCode() == k204NoContent ||
(_response->statusCode() == k101SwitchingProtocols &&
_response->getHeaderBy("upgrade") == "websocket"))
{
// The Websocket response may not have a content-length header.

2
lib/src/HttpResponseParser.h Executable file → Normal file
View File

@ -15,11 +15,11 @@
#pragma once
#include "HttpResponseImpl.h"
#include <trantor/utils/MsgBuffer.h>
#include <drogon/WebSocketConnection.h>
#include <list>
#include <mutex>
#include <trantor/net/TcpConnection.h>
#include <trantor/utils/MsgBuffer.h>
using namespace trantor;
namespace drogon

46
lib/src/HttpServer.cc Executable file → Normal file
View File

@ -14,14 +14,14 @@
#include "HttpServer.h"
#include <trantor/utils/Logger.h>
#include "HttpAppFrameworkImpl.h"
#include "HttpRequestParser.h"
#include "HttpResponseImpl.h"
#include "HttpAppFrameworkImpl.h"
#include <drogon/HttpRequest.h>
#include <drogon/HttpResponse.h>
#include <drogon/utils/Utilities.h>
#include <functional>
#include <trantor/utils/Logger.h>
using namespace std::placeholders;
using namespace drogon;
@ -32,8 +32,7 @@ static bool isWebSocket(const HttpRequestImplPtr &req)
auto &headers = req->headers();
if (headers.find("upgrade") == headers.end() || headers.find("connection") == headers.end())
return false;
if (req->getHeaderBy("connection").find("Upgrade") != std::string::npos &&
req->getHeaderBy("upgrade") == "websocket")
if (req->getHeaderBy("connection").find("Upgrade") != std::string::npos && req->getHeaderBy("upgrade") == "websocket")
{
LOG_TRACE << "new websocket request";
@ -63,9 +62,7 @@ static void defaultConnectionCallback(const trantor::TcpConnectionPtr &conn)
return;
}
HttpServer::HttpServer(EventLoop *loop,
const InetAddress &listenAddr,
const std::string &name)
HttpServer::HttpServer(EventLoop *loop, const InetAddress &listenAddr, const std::string &name)
#ifdef __linux__
: _server(loop, listenAddr, name.c_str()),
#else
@ -75,10 +72,8 @@ HttpServer::HttpServer(EventLoop *loop,
_newWebsocketCallback(defaultWebSockAsyncCallback),
_connectionCallback(defaultConnectionCallback)
{
_server.setConnectionCallback(
std::bind(&HttpServer::onConnection, this, _1));
_server.setRecvMessageCallback(
std::bind(&HttpServer::onMessage, this, _1, _2));
_server.setConnectionCallback(std::bind(&HttpServer::onConnection, this, _1));
_server.setRecvMessageCallback(std::bind(&HttpServer::onMessage, this, _1, _2));
}
HttpServer::~HttpServer()
@ -87,8 +82,7 @@ HttpServer::~HttpServer()
void HttpServer::start()
{
LOG_TRACE << "HttpServer[" << _server.name()
<< "] starts listenning on " << _server.ipPort();
LOG_TRACE << "HttpServer[" << _server.name() << "] starts listenning on " << _server.ipPort();
_server.start();
}
@ -119,11 +113,11 @@ void HttpServer::onConnection(const TcpConnectionPtr &conn)
}
}
void HttpServer::onMessage(const TcpConnectionPtr &conn,
MsgBuffer *buf)
void HttpServer::onMessage(const TcpConnectionPtr &conn, MsgBuffer *buf)
{
HttpRequestParser *requestParser = any_cast<HttpRequestParser>(conn->getMutableContext());
// With the pipelining feature or web socket, it is possible to receice multiple messages at once, so
// With the pipelining feature or web socket, it is possible to receice
// multiple messages at once, so
// the while loop is necessary
if (requestParser->webSocketConn())
{
@ -134,7 +128,6 @@ void HttpServer::onMessage(const TcpConnectionPtr &conn,
{
while (buf->readableBytes() > 0)
{
if (requestParser->isStop())
{
// The number of requests has reached the limit.
@ -160,7 +153,8 @@ void HttpServer::onMessage(const TcpConnectionPtr &conn,
{
requestParser->setWebsockConnection(wsConn);
}
auto httpString = std::dynamic_pointer_cast<HttpResponseImpl>(resp)->renderToString();
auto httpString =
std::dynamic_pointer_cast<HttpResponseImpl>(resp)->renderToString();
conn->send(httpString);
},
wsConn);
@ -180,8 +174,7 @@ void HttpServer::onMessage(const TcpConnectionPtr &conn,
void HttpServer::onRequest(const TcpConnectionPtr &conn, const HttpRequestImplPtr &req)
{
const std::string &connection = req->getHeaderBy("connection");
bool _close = connection == "close" ||
(req->getVersion() == HttpRequestImpl::kHttp10 && connection != "Keep-Alive");
bool _close = connection == "close" || (req->getVersion() == HttpRequestImpl::kHttp10 && connection != "Keep-Alive");
bool isHeadMethod = (req->method() == Head);
if (isHeadMethod)
@ -210,18 +203,15 @@ void HttpServer::onRequest(const TcpConnectionPtr &conn, const HttpRequestImplPt
auto newResp = response;
auto &sendfileName = std::dynamic_pointer_cast<HttpResponseImpl>(newResp)->sendfileName();
if (HttpAppFramework::instance().isGzipEnabled() &&
sendfileName.empty() &&
if (HttpAppFramework::instance().isGzipEnabled() && sendfileName.empty() &&
req->getHeaderBy("accept-encoding").find("gzip") != std::string::npos &&
std::dynamic_pointer_cast<HttpResponseImpl>(response)->getHeaderBy("content-encoding").empty() &&
response->getContentType() < CT_APPLICATION_OCTET_STREAM &&
response->getBody().length() > 1024)
response->getContentType() < CT_APPLICATION_OCTET_STREAM && response->getBody().length() > 1024)
{
// use gzip
LOG_TRACE << "Use gzip to compress the body";
size_t zlen = response->getBody().length();
auto strCompress = utils::gzipCompress(response->getBody().data(),
response->getBody().length());
auto strCompress = utils::gzipCompress(response->getBody().data(), response->getBody().length());
if (strCompress)
{
if (zlen > 0)
@ -316,9 +306,7 @@ void HttpServer::onRequest(const TcpConnectionPtr &conn, const HttpRequestImplPt
});
}
void HttpServer::sendResponse(const TcpConnectionPtr &conn,
const HttpResponsePtr &response,
bool isHeadMethod)
void HttpServer::sendResponse(const TcpConnectionPtr &conn, const HttpResponsePtr &response, bool isHeadMethod)
{
conn->getLoop()->assertInLoopThread();
auto respImplPtr = std::dynamic_pointer_cast<HttpResponseImpl>(response);

25
lib/src/HttpServer.h Executable file → Normal file
View File

@ -14,15 +14,15 @@
#pragma once
#include "WebSocketConnectionImpl.h"
#include "HttpRequestImpl.h"
#include <drogon/config.h>
#include "WebSocketConnectionImpl.h"
#include <drogon/WebSocketController.h>
#include <drogon/config.h>
#include <functional>
#include <string>
#include <trantor/net/TcpServer.h>
#include <trantor/net/callbacks.h>
#include <trantor/utils/NonCopyable.h>
#include <functional>
#include <string>
using namespace trantor;
namespace drogon
@ -34,18 +34,18 @@ class HttpServer : trantor::NonCopyable
{
public:
typedef std::function<void(const HttpRequestImplPtr &, std::function<void(const HttpResponsePtr &)> &&)> HttpAsyncCallback;
typedef std::function<void(const HttpRequestImplPtr &,
std::function<void(const HttpResponsePtr &)> &&,
const WebSocketConnectionImplPtr &)>
typedef std::function<
void(const HttpRequestImplPtr &, std::function<void(const HttpResponsePtr &)> &&, const WebSocketConnectionImplPtr &)>
WebSocketNewAsyncCallback;
HttpServer(EventLoop *loop,
const InetAddress &listenAddr,
const std::string &name);
HttpServer(EventLoop *loop, const InetAddress &listenAddr, const std::string &name);
~HttpServer();
EventLoop *getLoop() const { return _server.getLoop(); }
EventLoop *getLoop() const
{
return _server.getLoop();
}
void setHttpAsyncCallback(const HttpAsyncCallback &cb)
{
@ -86,8 +86,7 @@ class HttpServer : trantor::NonCopyable
private:
void onConnection(const TcpConnectionPtr &conn);
void onMessage(const TcpConnectionPtr &,
MsgBuffer *);
void onMessage(const TcpConnectionPtr &, MsgBuffer *);
void onRequest(const TcpConnectionPtr &, const HttpRequestImplPtr &);
void sendResponse(const TcpConnectionPtr &, const HttpResponsePtr &, bool isHeadMethod);
trantor::TcpServer _server;

View File

@ -12,10 +12,10 @@
*
*/
#include "FiltersFunction.h"
#include "HttpSimpleControllersRouter.h"
#include "HttpAppFrameworkImpl.h"
#include "AOPAdvice.h"
#include "FiltersFunction.h"
#include "HttpAppFrameworkImpl.h"
using namespace drogon;
@ -125,7 +125,8 @@ void HttpSimpleControllersRouter::route(const HttpRequestImplPtr &req,
auto sessionIdPtr = std::make_shared<std::string>(std::move(sessionId));
auto callbackPtr = std::make_shared<std::function<void(const HttpResponsePtr &)>>(std::move(callback));
FiltersFunction::doFilters(filters, req, callbackPtr, needSetJsessionid, sessionIdPtr, [=, &binder]() mutable {
doPreHandlingAdvices(binder, ctrlInfo, req, std::move(*callbackPtr), needSetJsessionid, std::move(*sessionIdPtr));
doPreHandlingAdvices(
binder, ctrlInfo, req, std::move(*callbackPtr), needSetJsessionid, std::move(*sessionIdPtr));
});
}
else
@ -136,23 +137,30 @@ void HttpSimpleControllersRouter::route(const HttpRequestImplPtr &req,
}
else
{
auto callbackPtr = std::make_shared<std::function<void(const HttpResponsePtr &)>>(std::move(callback));
doAdvicesChain(_postRoutingAdvices,
0,
req,
doAdvicesChain(_postRoutingAdvices, 0, req, callbackPtr, [
callbackPtr,
[callbackPtr, &filters, sessionId = std::move(sessionId), req, needSetJsessionid, &ctrlInfo, this, &binder]() mutable {
&filters,
sessionId = std::move(sessionId),
req,
needSetJsessionid,
&ctrlInfo,
this,
&binder
]() mutable {
if (!filters.empty())
{
auto sessionIdPtr = std::make_shared<std::string>(std::move(sessionId));
FiltersFunction::doFilters(filters, req, callbackPtr, needSetJsessionid, sessionIdPtr, [=, &binder]() mutable {
doPreHandlingAdvices(binder, ctrlInfo, req, std::move(*callbackPtr), needSetJsessionid, std::move(*sessionIdPtr));
FiltersFunction::doFilters(
filters, req, callbackPtr, needSetJsessionid, sessionIdPtr, [=, &binder]() mutable {
doPreHandlingAdvices(
binder, ctrlInfo, req, std::move(*callbackPtr), needSetJsessionid, std::move(*sessionIdPtr));
});
}
else
{
doPreHandlingAdvices(binder, ctrlInfo, req, std::move(*callbackPtr), needSetJsessionid, std::move(sessionId));
doPreHandlingAdvices(
binder, ctrlInfo, req, std::move(*callbackPtr), needSetJsessionid, std::move(sessionId));
}
});
}
@ -172,7 +180,8 @@ void HttpSimpleControllersRouter::doControllerHandler(const CtrlBinderPtr &ctrlB
if (controller)
{
HttpResponsePtr &responsePtr = ctrlBinderPtr->_responsePtrMap[req->getLoop()];
if (responsePtr && (responsePtr->expiredTime() == 0 || (trantor::Date::now() < responsePtr->creationDate().after(responsePtr->expiredTime()))))
if (responsePtr && (responsePtr->expiredTime() == 0 ||
(trantor::Date::now() < responsePtr->creationDate().after(responsePtr->expiredTime()))))
{
// use cached response!
LOG_TRACE << "Use cached response";
@ -190,7 +199,10 @@ void HttpSimpleControllersRouter::doControllerHandler(const CtrlBinderPtr &ctrlB
}
else
{
controller->asyncHandleHttpRequest(req, [=, callback = std::move(callback), &ctrlBinderPtr, sessionId = std::move(sessionId)](const HttpResponsePtr &resp) {
controller->asyncHandleHttpRequest(
req,
[ =, callback = std::move(callback), &ctrlBinderPtr, sessionId = std::move(sessionId) ](
const HttpResponsePtr &resp) {
auto newResp = resp;
if (resp->expiredTime() >= 0)
{
@ -203,9 +215,7 @@ void HttpSimpleControllersRouter::doControllerHandler(const CtrlBinderPtr &ctrlB
}
else
{
loop->queueInLoop([loop, resp, &ctrlBinderPtr]() {
ctrlBinderPtr->_responsePtrMap[loop] = resp;
});
loop->queueInLoop([loop, resp, &ctrlBinderPtr]() { ctrlBinderPtr->_responsePtrMap[loop] = resp; });
}
}
if (needSetJsessionid && resp->statusCode() != k404NotFound)
@ -242,7 +252,8 @@ std::vector<std::tuple<std::string, HttpMethod, std::string>> HttpSimpleControll
{
if (item.second._binders[i])
{
auto info = std::tuple<std::string, HttpMethod, std::string>(item.first,
auto info = std::tuple<std::string, HttpMethod, std::string>(
item.first,
(HttpMethod)i,
std::string("HttpSimpleController: ") + item.second._binders[i]->_controllerName);
ret.emplace_back(std::move(info));
@ -320,10 +331,12 @@ void HttpSimpleControllersRouter::doPreHandlingAdvices(const CtrlBinderPtr &ctrl
{
auto callbackPtr = std::make_shared<std::function<void(const HttpResponsePtr &)>>(std::move(callback));
auto sessionIdPtr = std::make_shared<std::string>(std::move(sessionId));
doAdvicesChain(_preHandlingAdvices,
doAdvicesChain(
_preHandlingAdvices,
0,
req,
std::make_shared<std::function<void(const HttpResponsePtr &)>>([callbackPtr, needSetJsessionid, sessionIdPtr](const HttpResponsePtr &resp) {
std::make_shared<std::function<void(const HttpResponsePtr &)>>(
[callbackPtr, needSetJsessionid, sessionIdPtr](const HttpResponsePtr &resp) {
if (!needSetJsessionid || resp->statusCode() == k404NotFound)
(*callbackPtr)(resp);
else
@ -333,7 +346,8 @@ void HttpSimpleControllersRouter::doPreHandlingAdvices(const CtrlBinderPtr &ctrl
}
}),
[this, ctrlBinderPtr, &routerItem, req, callbackPtr, needSetJsessionid, sessionIdPtr]() {
doControllerHandler(ctrlBinderPtr, routerItem, req, std::move(*callbackPtr), needSetJsessionid, std::move(*sessionIdPtr));
doControllerHandler(
ctrlBinderPtr, routerItem, req, std::move(*callbackPtr), needSetJsessionid, std::move(*sessionIdPtr));
});
}
}

View File

@ -13,43 +13,35 @@
*/
#pragma once
#include "HttpControllersRouter.h"
#include "HttpRequestImpl.h"
#include "HttpResponseImpl.h"
#include "HttpControllersRouter.h"
#include <drogon/HttpSimpleController.h>
#include <trantor/utils/NonCopyable.h>
#include <atomic>
#include <drogon/HttpBinder.h>
#include <drogon/HttpFilter.h>
#include <vector>
#include <regex>
#include <string>
#include <mutex>
#include <drogon/HttpSimpleController.h>
#include <memory>
#include <mutex>
#include <regex>
#include <shared_mutex>
#include <atomic>
#include <string>
#include <trantor/utils/NonCopyable.h>
#include <vector>
namespace drogon
{
class HttpSimpleControllersRouter : public trantor::NonCopyable
{
public:
HttpSimpleControllersRouter(HttpControllersRouter &httpCtrlRouter,
const std::deque<std::function<void(const HttpRequestPtr &,
AdviceCallback &&,
AdviceChainCallback &&)>>
HttpSimpleControllersRouter(
HttpControllersRouter &httpCtrlRouter,
const std::deque<std::function<void(const HttpRequestPtr &, AdviceCallback &&, AdviceChainCallback &&)>>
&postRoutingAdvices,
const std::deque<std::function<void(const HttpRequestPtr &)>>
&postRoutingObservers,
const std::vector<std::function<void(const HttpRequestPtr &,
AdviceCallback &&,
AdviceChainCallback &&)>>
const std::deque<std::function<void(const HttpRequestPtr &)>> &postRoutingObservers,
const std::vector<std::function<void(const HttpRequestPtr &, AdviceCallback &&, AdviceChainCallback &&)>>
&preHandlingAdvices,
const std::vector<std::function<void(const HttpRequestPtr &)>>
&preHandlingObservers,
const std::deque<std::function<void(const HttpRequestPtr &,
const HttpResponsePtr &)>>
&postHandlingAdvices)
const std::vector<std::function<void(const HttpRequestPtr &)>> &preHandlingObservers,
const std::deque<std::function<void(const HttpRequestPtr &, const HttpResponsePtr &)>> &postHandlingAdvices)
: _httpCtrlsRouter(httpCtrlRouter),
_postRoutingAdvices(postRoutingAdvices),
_preHandlingAdvices(preHandlingAdvices),
@ -72,22 +64,14 @@ class HttpSimpleControllersRouter : public trantor::NonCopyable
private:
HttpControllersRouter &_httpCtrlsRouter;
const std::deque<std::function<void(const HttpRequestPtr &,
AdviceCallback &&,
AdviceChainCallback &&)>>
const std::deque<std::function<void(const HttpRequestPtr &, AdviceCallback &&, AdviceChainCallback &&)>>
&_postRoutingAdvices;
const std::vector<std::function<void(const HttpRequestPtr &,
AdviceCallback &&,
AdviceChainCallback &&)>>
const std::vector<std::function<void(const HttpRequestPtr &, AdviceCallback &&, AdviceChainCallback &&)>>
&_preHandlingAdvices;
const std::deque<std::function<void(const HttpRequestPtr &)>>
&_postRoutingObservers;
const std::vector<std::function<void(const HttpRequestPtr &)>>
&_preHandlingObservers;
const std::deque<std::function<void(const HttpRequestPtr &)>> &_postRoutingObservers;
const std::vector<std::function<void(const HttpRequestPtr &)>> &_preHandlingObservers;
const std::deque<std::function<void(const HttpRequestPtr &,
const HttpResponsePtr &)>>
&_postHandlingAdvices;
const std::deque<std::function<void(const HttpRequestPtr &, const HttpResponsePtr &)>> &_postHandlingAdvices;
struct CtrlBinder
{
std::shared_ptr<HttpSimpleControllerBase> _controller;

View File

@ -18,7 +18,6 @@
namespace drogon
{
const string_view &webContentTypeToString(ContentType contenttype)
{
switch (contenttype)

View File

@ -13,15 +13,14 @@
*/
#pragma once
#include <string>
#include <drogon/HttpTypes.h>
#include <drogon/config.h>
#include <trantor/utils/MsgBuffer.h>
#include <drogon/WebSocketConnection.h>
#include <drogon/config.h>
#include <string>
#include <trantor/utils/MsgBuffer.h>
namespace drogon
{
const string_view &webContentTypeToString(ContentType contenttype);
const string_view &statusCodeToString(int code);
ContentType getContentType(const std::string &extName);

4
lib/src/HttpViewBase.cc Executable file → Normal file
View File

@ -12,12 +12,12 @@
*
*/
#include <drogon/HttpViewBase.h>
#include <drogon/DrClassMap.h>
#include <drogon/HttpViewBase.h>
#include <drogon/DrTemplateBase.h>
#include <trantor/utils/Logger.h>
#include <memory>
#include <trantor/utils/Logger.h>
using namespace drogon;
HttpResponsePtr HttpViewBase::genHttpResponse(std::string viewName, const HttpViewData &data)
{

View File

@ -12,12 +12,10 @@
*
*/
#include <drogon/IntranetIpFilter.h>
#include "HttpResponseImpl.h"
#include <drogon/IntranetIpFilter.h>
using namespace drogon;
void IntranetIpFilter::doFilter(const HttpRequestPtr &req,
FilterCallback &&fcb,
FilterChainCallback &&fccb)
void IntranetIpFilter::doFilter(const HttpRequestPtr &req, FilterCallback &&fcb, FilterChainCallback &&fccb)
{
if (req->peerAddr().isIntranetIp())
{

View File

@ -12,14 +12,11 @@
*
*/
#include <drogon/LocalHostFilter.h>
#include "HttpResponseImpl.h"
#include <drogon/LocalHostFilter.h>
using namespace drogon;
void LocalHostFilter::doFilter(const HttpRequestPtr &req,
FilterCallback &&fcb,
FilterChainCallback &&fccb)
void LocalHostFilter::doFilter(const HttpRequestPtr &req, FilterCallback &&fcb, FilterChainCallback &&fccb)
{
if (req->peerAddr().isLoopbackIp())
{
fccb();

19
lib/src/MultiPart.cc Executable file → Normal file
View File

@ -14,20 +14,20 @@
#include "HttpRequestImpl.h"
#include "HttpUtils.h"
#include <drogon/utils/Utilities.h>
#include <drogon/MultiPart.h>
#include <drogon/HttpAppFramework.h>
#include <drogon/MultiPart.h>
#include <drogon/utils/Utilities.h>
#ifdef USE_OPENSSL
#include <openssl/md5.h>
#else
#include "ssl_funcs/Md5.h"
#endif
#include <iostream>
#include <algorithm>
#include <fcntl.h>
#include <fstream>
#include <iostream>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <algorithm>
using namespace drogon;
@ -147,10 +147,8 @@ int HttpFile::save(const std::string &path) const
return -1;
std::string filename;
auto tmpPath = path;
if (path[0] == '/' ||
(path.length() >= 2 && path[0] == '.' && path[1] == '/') ||
(path.length() >= 3 && path[0] == '.' && path[1] == '.' && path[2] == '/') ||
path == "." || path == "..")
if (path[0] == '/' || (path.length() >= 2 && path[0] == '.' && path[1] == '/') ||
(path.length() >= 3 && path[0] == '.' && path[1] == '.' && path[2] == '/') || path == "." || path == "..")
{
// Absolute or relative path
}
@ -183,8 +181,7 @@ int HttpFile::saveAs(const std::string &filename) const
{
assert(!filename.empty());
auto pathAndFileName = filename;
if (filename[0] == '/' ||
(filename.length() >= 2 && filename[0] == '.' && filename[1] == '/') ||
if (filename[0] == '/' || (filename.length() >= 2 && filename[0] == '.' && filename[1] == '/') ||
(filename.length() >= 3 && filename[0] == '.' && filename[1] == '.' && filename[2] == '/'))
{
// Absolute or relative path

6
lib/src/NotFound.cc Executable file → Normal file
View File

@ -15,11 +15,11 @@
*/
#include <drogon/NotFound.h>
#include <string>
#include <sstream>
#include <map>
#include <vector>
#include <set>
#include <sstream>
#include <string>
#include <vector>
using namespace std;
using namespace drogon;

View File

@ -26,8 +26,7 @@ PluginsManager::~PluginsManager()
}
}
void PluginsManager::initializeAllPlugins(const Json::Value &configs,
const std::function<void(PluginBase *)> &forEachCallback)
void PluginsManager::initializeAllPlugins(const Json::Value &configs, const std::function<void(PluginBase *)> &forEachCallback)
{
assert(configs.isArray());
std::vector<PluginBase *> plugins;

View File

@ -18,14 +18,12 @@
namespace drogon
{
typedef std::unique_ptr<PluginBase> PluginBasePtr;
class PluginsManager : trantor::NonCopyable
{
public:
void initializeAllPlugins(const Json::Value &configs,
const std::function<void(PluginBase *)> &forEachCallback);
void initializeAllPlugins(const Json::Value &configs, const std::function<void(PluginBase *)> &forEachCallback);
PluginBase *getPlugin(const std::string &pluginName);
~PluginsManager();

21
lib/src/SharedLibManager.cc Executable file → Normal file
View File

@ -13,14 +13,14 @@
*/
#include "SharedLibManager.h"
#include <trantor/utils/Logger.h>
#include <drogon/config.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <dirent.h>
#include <dlfcn.h>
#include <drogon/config.h>
#include <fstream>
#include <sys/stat.h>
#include <sys/types.h>
#include <trantor/utils/Logger.h>
#include <unistd.h>
static void forEachFileIn(const std::string &path, const std::function<void(const std::string &, const struct stat &)> &cb)
{
DIR *dp;
@ -64,12 +64,10 @@ static void forEachFileIn(const std::string &path, const std::function<void(cons
}
using namespace drogon;
SharedLibManager::SharedLibManager(trantor::EventLoop *loop, const std::vector<std::string> &libPaths) : _loop(loop),
_libPaths(libPaths)
SharedLibManager::SharedLibManager(trantor::EventLoop *loop, const std::vector<std::string> &libPaths)
: _loop(loop), _libPaths(libPaths)
{
_timeId = _loop->runEvery(5.0, [=]() {
managerLibs();
});
_timeId = _loop->runEvery(5.0, [=]() { managerLibs(); });
}
SharedLibManager::~SharedLibManager()
{
@ -100,7 +98,8 @@ void SharedLibManager::managerLibs()
#ifdef __linux__
if (st.st_mtim.tv_sec > _dlMap[filename].mTime.tv_sec)
#else
if(st.st_mtimespec.tv_sec>_dlMap[filename].mTime.tv_sec)
if (st.st_mtimespec.tv_sec >
_dlMap[filename].mTime.tv_sec)
#endif
{
LOG_TRACE << "new csp file:" << filename;

2
lib/src/SharedLibManager.h Executable file → Normal file
View File

@ -14,8 +14,8 @@
#pragma once
#include <trantor/utils/NonCopyable.h>
#include <trantor/net/EventLoop.h>
#include <trantor/utils/NonCopyable.h>
#include <unordered_map>
#include <vector>
namespace drogon

View File

@ -13,19 +13,17 @@
#pragma once
#include <atomic>
#include <thread>
#include <emmintrin.h>
#include <thread>
#define LOCK_SPIN 2048
namespace drogon
{
class SpinLock
{
public:
inline SpinLock(std::atomic<bool> &flag)
: _flag(flag)
inline SpinLock(std::atomic<bool> &flag) : _flag(flag)
{
const static int cpu = std::thread::hardware_concurrency();
int n, i;
@ -65,8 +63,7 @@ class SpinLock
class SimpleSpinLock
{
public:
inline SimpleSpinLock(std::atomic_flag &flag)
: _flag(flag)
inline SimpleSpinLock(std::atomic_flag &flag) : _flag(flag)
{
while (_flag.test_and_set(std::memory_order_acquire))
{

47
lib/src/Utilities.cc Executable file → Normal file
View File

@ -12,31 +12,30 @@
*
*/
#include <drogon/utils/Utilities.h>
#include <drogon/config.h>
#include <trantor/utils/Logger.h>
#include <string.h>
#include <zlib.h>
#include <uuid.h>
#include <stdio.h>
#include <stdarg.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <thread>
#include <mutex>
#include <cstdlib>
#include <stack>
#include <cctype>
#include <cstdlib>
#include <drogon/config.h>
#include <drogon/utils/Utilities.h>
#include <fcntl.h>
#include <iomanip>
#include <mutex>
#include <sstream>
#include <stack>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <string>
#include <sys/stat.h>
#include <thread>
#include <trantor/utils/Logger.h>
#include <unistd.h>
#include <uuid.h>
#include <zlib.h>
namespace drogon
{
namespace utils
{
static const std::string base64Chars =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
@ -63,9 +62,7 @@ std::string genRandomString(int length)
static std::once_flag once;
static const int len = strlen(char_space);
static const int randMax = RAND_MAX - (RAND_MAX % len);
std::call_once(once, []() {
std::srand(time(nullptr));
});
std::call_once(once, []() { std::srand(time(nullptr)); });
int i;
std::string str;
@ -494,13 +491,17 @@ std::string urlDecode(const char *begin, const char *end)
x2 = x2 - 'A' + 10;
}
hex = x1 * 16 + x2;
//字母和数字[0-9a-zA-Z]、一些特殊符号[$-_.+!*'(),] 、以及某些保留字[$&+,/:;=?@]
//字母和数字[0-9a-zA-Z]、一些特殊符号[$-_.+!*'(),]
//、以及某些保留字[$&+,/:;=?@]
//可以不经过编码直接用于URL
if (!((hex >= 48 && hex <= 57) || // 0-9
(hex >= 97 && hex <= 122) || // a-z
(hex >= 65 && hex <= 90) || // A-Z
//一些特殊符号及保留字[$-_.+!*'(),] [$&+,/:;?@]
hex == 0x21 || hex == 0x24 || hex == 0x26 || hex == 0x27 || hex == 0x28 || hex == 0x29 || hex == 0x2a || hex == 0x2b || hex == 0x2c || hex == 0x2d || hex == 0x2e || hex == 0x2f || hex == 0x3A || hex == 0x3B || hex == 0x3f || hex == 0x40 || hex == 0x5f))
hex == 0x21 ||
hex == 0x24 || hex == 0x26 || hex == 0x27 || hex == 0x28 || hex == 0x29 || hex == 0x2a ||
hex == 0x2b || hex == 0x2c || hex == 0x2d || hex == 0x2e || hex == 0x2f || hex == 0x3A ||
hex == 0x3B || hex == 0x3f || hex == 0x40 || hex == 0x5f))
{
result += char(hex);
i += 2;
@ -527,8 +528,7 @@ std::shared_ptr<std::string> gzipCompress(const char *data, const size_t ndata)
z_stream strm = {0};
if (data && ndata > 0)
{
if (deflateInit2(&strm, Z_DEFAULT_COMPRESSION, Z_DEFLATED,
MAX_WBITS + 16, 8, Z_DEFAULT_STRATEGY) != Z_OK)
if (deflateInit2(&strm, Z_DEFAULT_COMPRESSION, Z_DEFLATED, MAX_WBITS + 16, 8, Z_DEFAULT_STRATEGY) != Z_OK)
return nullptr;
auto outstr = std::make_shared<std::string>();
outstr->resize(compressBound(ndata));
@ -548,7 +548,6 @@ std::shared_ptr<std::string> gzipCompress(const char *data, const size_t ndata)
std::shared_ptr<std::string> gzipDecompress(const std::shared_ptr<std::string> &compressedData)
{
if (compressedData->length() == 0)
return compressedData;

View File

@ -14,11 +14,11 @@
#include "WebSocketClientImpl.h"
#include "HttpRequestImpl.h"
#include "HttpUtils.h"
#include "HttpResponseParser.h"
#include "HttpUtils.h"
#include <drogon/HttpAppFramework.h>
#include <trantor/net/InetAddress.h>
#include <drogon/utils/Utilities.h>
#include <trantor/net/InetAddress.h>
#ifdef USE_OPENSSL
#include <openssl/sha.h>
#else
@ -65,9 +65,7 @@ void WebSocketClientImpl::connectToServerInLoop()
}
}
if (_server.ipNetEndian() == 0 && !hasIpv6Address &&
!_domain.empty() &&
_server.portNetEndian() != 0)
if (_server.ipNetEndian() == 0 && !hasIpv6Address && !_domain.empty() && _server.portNetEndian() != 0)
{
// dns
// TODO: timeout should be set by user
@ -109,9 +107,7 @@ void WebSocketClientImpl::connectToServerInLoop()
LOG_TRACE << "connection disconnect";
thisPtr->_connectionClosedCallback(thisPtr);
thisPtr->_websockConnPtr.reset();
thisPtr->_loop->runAfter(1.0, [thisPtr]() {
thisPtr->reconnect();
});
thisPtr->_loop->runAfter(1.0, [thisPtr]() { thisPtr->reconnect(); });
}
});
_tcpClient->setConnectionErrorCallback([weakPtr]() {
@ -120,9 +116,7 @@ void WebSocketClientImpl::connectToServerInLoop()
return;
// can't connect to server
thisPtr->_requestCallback(ReqResult::NetworkFailure, nullptr, thisPtr);
thisPtr->_loop->runAfter(1.0, [thisPtr]() {
thisPtr->reconnect();
});
thisPtr->_loop->runAfter(1.0, [thisPtr]() { thisPtr->reconnect(); });
});
_tcpClient->setMessageCallback([weakPtr](const trantor::TcpConnectionPtr &connPtr, trantor::MsgBuffer *msg) {
auto thisPtr = weakPtr.lock();
@ -195,9 +189,8 @@ void WebSocketClientImpl::onRecvMessage(const trantor::TcpConnectionPtr &connPtr
_upgraded = true;
_websockConnPtr = std::make_shared<WebSocketConnectionImpl>(connPtr, false);
auto thisPtr = shared_from_this();
_websockConnPtr->setMessageCallback([thisPtr](std::string &&message,
const WebSocketConnectionImplPtr &connPtr,
const WebSocketMessageType &type) {
_websockConnPtr->setMessageCallback(
[thisPtr](std::string &&message, const WebSocketConnectionImplPtr &connPtr, const WebSocketMessageType &type) {
thisPtr->_messageCallback(std::move(message), thisPtr, type);
});
_requestCallback(ReqResult::Ok, resp, shared_from_this());
@ -221,14 +214,11 @@ void WebSocketClientImpl::reconnect()
}
WebSocketClientImpl::WebSocketClientImpl(trantor::EventLoop *loop, const trantor::InetAddress &addr, bool useSSL)
: _loop(loop),
_server(addr),
_useSSL(useSSL)
: _loop(loop), _server(addr), _useSSL(useSSL)
{
}
WebSocketClientImpl::WebSocketClientImpl(trantor::EventLoop *loop, const std::string &hostString)
: _loop(loop)
WebSocketClientImpl::WebSocketClientImpl(trantor::EventLoop *loop, const std::string &hostString) : _loop(loop)
{
auto lowerHost = hostString;
std::transform(lowerHost.begin(), lowerHost.end(), lowerHost.begin(), tolower);
@ -298,11 +288,11 @@ WebSocketClientPtr WebSocketClient::newWebSocketClient(const std::string &ip,
trantor::EventLoop *loop)
{
bool isIpv6 = ip.find(":") == std::string::npos ? false : true;
return std::make_shared<WebSocketClientImpl>(loop == nullptr ? app().getLoop() : loop, trantor::InetAddress(ip, port, isIpv6), useSSL);
return std::make_shared<WebSocketClientImpl>(
loop == nullptr ? app().getLoop() : loop, trantor::InetAddress(ip, port, isIpv6), useSSL);
}
WebSocketClientPtr WebSocketClient::newWebSocketClient(const std::string &hostString,
trantor::EventLoop *loop)
WebSocketClientPtr WebSocketClient::newWebSocketClient(const std::string &hostString, trantor::EventLoop *loop)
{
return std::make_shared<WebSocketClientImpl>(loop == nullptr ? app().getLoop() : loop, hostString);
}

View File

@ -16,16 +16,15 @@
#include "WebSocketConnectionImpl.h"
#include <drogon/WebSocketClient.h>
#include <trantor/utils/NonCopyable.h>
#include <trantor/net/EventLoop.h>
#include <trantor/net/TcpClient.h>
#include <trantor/utils/NonCopyable.h>
#include <string>
#include <memory>
#include <string>
namespace drogon
{
class WebSocketClientImpl : public WebSocketClient, public std::enable_shared_from_this<WebSocketClientImpl>
{
public:
@ -34,9 +33,9 @@ class WebSocketClientImpl : public WebSocketClient, public std::enable_shared_fr
return _websockConnPtr;
}
virtual void setMessageHandler(const std::function<void(std::string &&message,
const WebSocketClientPtr &,
const WebSocketMessageType &)> &callback) override
virtual void setMessageHandler(
const std::function<void(std::string &&message, const WebSocketClientPtr &, const WebSocketMessageType &)> &callback)
override
{
_messageCallback = callback;
}
@ -46,7 +45,6 @@ class WebSocketClientImpl : public WebSocketClient, public std::enable_shared_fr
_connectionClosedCallback = callback;
}
virtual void connectToServer(const HttpRequestPtr &request, const WebSocketRequestCallback &callback) override
{
assert(callback);
@ -67,7 +65,10 @@ class WebSocketClientImpl : public WebSocketClient, public std::enable_shared_fr
}
}
virtual trantor::EventLoop *getLoop() override { return _loop; }
virtual trantor::EventLoop *getLoop() override
{
return _loop;
}
WebSocketClientImpl(trantor::EventLoop *loop, const trantor::InetAddress &addr, bool useSSL = false);
@ -86,7 +87,8 @@ class WebSocketClientImpl : public WebSocketClient, public std::enable_shared_fr
std::string _wsAccept;
HttpRequestPtr _upgradeRequest;
std::function<void(std::string &&message, const WebSocketClientPtr &, const WebSocketMessageType &)> _messageCallback = [](std::string &&message, const WebSocketClientPtr &, const WebSocketMessageType &) {};
std::function<void(std::string &&message, const WebSocketClientPtr &, const WebSocketMessageType &)> _messageCallback =
[](std::string &&message, const WebSocketClientPtr &, const WebSocketMessageType &) {};
std::function<void(const WebSocketClientPtr &)> _connectionClosedCallback = [](const WebSocketClientPtr &) {};
WebSocketRequestCallback _requestCallback;
WebSocketConnectionImplPtr _websockConnPtr;

View File

@ -12,18 +12,15 @@
*
*/
#include "HttpAppFrameworkImpl.h"
#include "WebSocketConnectionImpl.h"
#include "HttpAppFrameworkImpl.h"
#include <thread>
#include <trantor/net/TcpConnection.h>
#include <trantor/net/inner/TcpConnectionImpl.h>
#include <thread>
using namespace drogon;
WebSocketConnectionImpl::WebSocketConnectionImpl(const trantor::TcpConnectionPtr &conn, bool isServer)
: _tcpConn(conn),
_localAddr(conn->localAddr()),
_peerAddr(conn->peerAddr()),
_isServer(isServer)
: _tcpConn(conn), _localAddr(conn->localAddr()), _peerAddr(conn->peerAddr()), _isServer(isServer)
{
}
@ -59,7 +56,6 @@ void WebSocketConnectionImpl::send(const char *msg, uint64_t len, const WebSocke
void WebSocketConnectionImpl::sendWsData(const char *msg, size_t len, unsigned char opcode)
{
LOG_TRACE << "send " << len << " bytes";
// Format the frame
@ -101,9 +97,7 @@ void WebSocketConnectionImpl::sendWsData(const char *msg, size_t len, unsigned c
{
// Add masking key;
static std::once_flag once;
std::call_once(once, []() {
std::srand(time(nullptr));
});
std::call_once(once, []() { std::srand(time(nullptr)); });
int random = std::rand();
bytesFormatted[1] = (bytesFormatted[1] | 0x80);
@ -244,7 +238,8 @@ bool WebSocketMessageParser::parse(trantor::MsgBuffer *buffer)
if (isControlFrame)
{
// rfc6455-5.5
LOG_ERROR << "Bad frame: all control frames MUST have a payload length of 125 bytes or less";
LOG_ERROR << "Bad frame: all control frames MUST have a payload length "
"of 125 bytes or less";
return false;
}
if (indexFirstMask == 4)

View File

@ -20,7 +20,6 @@
namespace drogon
{
class WebSocketConnectionImpl;
typedef std::shared_ptr<WebSocketConnectionImpl> WebSocketConnectionImplPtr;
@ -69,9 +68,8 @@ public:
virtual void setPingMessage(const std::string &message, const std::chrono::duration<long double> &interval) override;
void setMessageCallback(const std::function<void(std::string &&,
const WebSocketConnectionImplPtr &,
const WebSocketMessageType &)> &callback)
void setMessageCallback(
const std::function<void(std::string &&, const WebSocketConnectionImplPtr &, const WebSocketMessageType &)> &callback)
{
_messageCallback = callback;
}
@ -85,7 +83,6 @@ public:
{
while (buffer->readableBytes() > 0)
{
auto success = _parser.parse(buffer);
if (success)
{
@ -140,12 +137,8 @@ private:
WebSocketMessageParser _parser;
trantor::TimerId _pingTimerId = trantor::InvalidTimerId;
std::function<void(std::string &&,
const WebSocketConnectionImplPtr &,
const WebSocketMessageType &)>
_messageCallback = [](std::string &&,
const WebSocketConnectionImplPtr &,
const WebSocketMessageType &) {};
std::function<void(std::string &&, const WebSocketConnectionImplPtr &, const WebSocketMessageType &)> _messageCallback =
[](std::string &&, const WebSocketConnectionImplPtr &, const WebSocketMessageType &) {};
std::function<void(const WebSocketConnectionImplPtr &)> _closeCallback = [](const WebSocketConnectionImplPtr &) {};
void sendWsData(const char *msg, size_t len, unsigned char opcode);
};

View File

@ -12,8 +12,8 @@
*
*/
#include "FiltersFunction.h"
#include "WebsocketControllersRouter.h"
#include "FiltersFunction.h"
#include "HttpAppFrameworkImpl.h"
#ifdef USE_OPENSSL
#include <openssl/sha.h>
@ -82,9 +82,8 @@ std::vector<std::tuple<std::string, HttpMethod, std::string>> WebsocketControlle
std::vector<std::tuple<std::string, HttpMethod, std::string>> ret;
for (auto &item : _websockCtrlMap)
{
auto info = std::tuple<std::string, HttpMethod, std::string>(item.first,
Get,
std::string("WebsocketController: ") + item.second._controller->className());
auto info = std::tuple<std::string, HttpMethod, std::string>(
item.first, Get, std::string("WebsocketController: ") + item.second._controller->className());
ret.emplace_back(std::move(info));
}
return ret;
@ -106,14 +105,12 @@ void WebsocketControllersRouter::doControllerHandler(const WebSocketControllerBa
resp->addHeader("Connection", "Upgrade");
resp->addHeader("Sec-WebSocket-Accept", base64Key);
callback(resp);
wsConnPtr->setMessageCallback([ctrlPtr](std::string &&message,
const WebSocketConnectionImplPtr &connPtr,
const WebSocketMessageType &type) {
wsConnPtr->setMessageCallback(
[ctrlPtr](std::string &&message, const WebSocketConnectionImplPtr &connPtr, const WebSocketMessageType &type) {
ctrlPtr->handleNewMessage(connPtr, std::move(message), type);
});
wsConnPtr->setCloseCallback([ctrlPtr](const WebSocketConnectionImplPtr &connPtr) {
ctrlPtr->handleConnectionClosed(connPtr);
});
wsConnPtr->setCloseCallback(
[ctrlPtr](const WebSocketConnectionImplPtr &connPtr) { ctrlPtr->handleConnectionClosed(connPtr); });
ctrlPtr->handleNewConnection(req, wsConnPtr);
return;
}

View File

@ -16,14 +16,14 @@
#include "HttpRequestImpl.h"
#include "HttpResponseImpl.h"
#include "WebSocketConnectionImpl.h"
#include <trantor/utils/NonCopyable.h>
#include <drogon/WebSocketController.h>
#include <drogon/HttpFilter.h>
#include <vector>
#include <drogon/WebSocketController.h>
#include <memory>
#include <mutex>
#include <regex>
#include <string>
#include <mutex>
#include <memory>
#include <trantor/utils/NonCopyable.h>
#include <vector>
namespace drogon
{
@ -31,7 +31,9 @@ class HttpAppFrameworkImpl;
class WebsocketControllersRouter : public trantor::NonCopyable
{
public:
WebsocketControllersRouter() {}
WebsocketControllersRouter()
{
}
void registerWebSocketController(const std::string &pathName,
const std::string &ctrlName,
const std::vector<std::string> &filters);

View File

@ -13,9 +13,9 @@
*/
#include "Md5.h"
#include <iostream>
#include <math.h>
#include <string.h>
#include <iostream>
const int Md5Encode::kA = 0x67452301;
const int Md5Encode::kB = 0xefcdab89;

View File

@ -60,7 +60,6 @@ class Md5Encode
};
public:
static std::string encode(const std::string &src_info);
protected:

View File

@ -17,8 +17,7 @@
static unsigned int FromBigEndian(unsigned int v)
{
return ((v & 0xff) << 24) | ((v & 0xff00) << 8) | ((v & 0xff0000) >> 8) |
((v & 0xff000000) >> 24);
return ((v & 0xff) << 24) | ((v & 0xff00) << 8) | ((v & 0xff0000) >> 8) | ((v & 0xff000000) >> 24);
}
static void WriteBigEndian64(unsigned char *p, unsigned int v)

12
lib/tests/CacheMapTest.cc Executable file → Normal file
View File

@ -1,11 +1,11 @@
#include <drogon/CacheMap.h>
#include <trantor/utils/Logger.h>
#include <trantor/net/EventLoopThread.h>
#include <drogon/utils/Utilities.h>
#include <unistd.h>
#include <iostream>
#include <string>
#include <thread>
#include <iostream>
#include <trantor/net/EventLoopThread.h>
#include <trantor/utils/Logger.h>
#include <unistd.h>
int main()
{
@ -21,9 +21,7 @@ int main()
std::cout << i << " cache item erased!" << std::endl;
});
}
cache.insert("1", "first", 20, [=] {
LOG_DEBUG << "first item in cache timeout,erase!";
});
cache.insert("1", "first", 20, [=] { LOG_DEBUG << "first item in cache timeout,erase!"; });
cache.insert("2", "second", 5);
cache.insert("3", "third", 5);
std::thread thread1([&] {

26
lib/tests/CacheMapTest2.cc Executable file → Normal file
View File

@ -1,16 +1,15 @@
#include <drogon/CacheMap.h>
#include <trantor/utils/Logger.h>
#include <trantor/net/EventLoopThread.h>
#include <drogon/utils/Utilities.h>
#include <unistd.h>
#include <string>
#include <thread>
#include <iostream>
#include <memory>
#include <string>
#include <thread>
#include <trantor/net/EventLoopThread.h>
#include <trantor/utils/Logger.h>
#include <unistd.h>
int main()
{
trantor::Logger::setLogLevel(trantor::Logger::TRACE);
trantor::EventLoopThread loopThread;
loopThread.run();
@ -19,15 +18,12 @@ int main()
std::shared_ptr<drogon::CacheMap<std::string, std::string>> main_cachePtr;
auto now = trantor::Date::date();
loop->runAt(now.after(1).roundSecond(), [=, &main_cachePtr]() {
std::shared_ptr<drogon::CacheMap<std::string, std::string>> cachePtr = std::make_shared<drogon::CacheMap<std::string, std::string>>(loop, 0.1, 3, 50);
std::shared_ptr<drogon::CacheMap<std::string, std::string>> cachePtr =
std::make_shared<drogon::CacheMap<std::string, std::string>>(loop, 0.1, 3, 50);
main_cachePtr = cachePtr;
LOG_DEBUG << "insert :usecount=" << main_cachePtr.use_count();
cachePtr->insert("1", "1", 3, [=]() {
LOG_DEBUG << "timeout!erase 1!";
});
cachePtr->insert("2", "2", 10, []() {
LOG_DEBUG << "2 timeout";
});
cachePtr->insert("1", "1", 3, [=]() { LOG_DEBUG << "timeout!erase 1!"; });
cachePtr->insert("2", "2", 10, []() { LOG_DEBUG << "2 timeout"; });
});
trantor::EventLoop mainLoop;
mainLoop.runAt(now.after(3).roundSecond().after(0.0013), [&]() {
@ -43,8 +39,6 @@ int main()
LOG_DEBUG << "can't find item 1";
}
});
mainLoop.runAfter(8, [&]() {
mainLoop.quit();
});
mainLoop.runAfter(8, [&]() { mainLoop.quit(); });
mainLoop.loop();
}

0
lib/tests/CookiesTest.cc Executable file → Normal file
View File

View File

@ -5,7 +5,8 @@ using namespace drogon;
int main()
{
const std::string inStr = "Applications\n"
const std::string inStr =
"Applications\n"
"Developer\n"
"Library\n"
"Network\n"
@ -168,24 +169,30 @@ int main()
"Resources\n"
"_CodeSignature\n"
"\n"
"/Applications/Adobe Photoshop CC/Adobe Photoshop CC.app/Contents/Application Data:\n"
"/Applications/Adobe Photoshop CC/Adobe Photoshop "
"CC.app/Contents/Application Data:\n"
"Custom File Info Panels\n"
"\n"
"/Applications/Adobe Photoshop CC/Adobe Photoshop CC.app/Contents/Application Data/Custom File Info Panels:\n"
"/Applications/Adobe Photoshop CC/Adobe Photoshop "
"CC.app/Contents/Application Data/Custom File Info Panels:\n"
"4.0\n"
"\n"
"/Applications/Adobe Photoshop CC/Adobe Photoshop CC.app/Contents/Application Data/Custom File Info Panels/4.0:\n"
"/Applications/Adobe Photoshop CC/Adobe Photoshop "
"CC.app/Contents/Application Data/Custom File Info Panels/4.0:\n"
"bin\n"
"custom\n"
"panels\n"
"\n"
"/Applications/Adobe Photoshop CC/Adobe Photoshop CC.app/Contents/Application Data/Custom File Info Panels/4.0/bin:\n"
"/Applications/Adobe Photoshop CC/Adobe Photoshop "
"CC.app/Contents/Application Data/Custom File Info Panels/4.0/bin:\n"
"FileInfoFoundation.swf\n"
"FileInfoUI.swf\n"
"framework.swf\n"
"loc\n"
"\n"
"/Applications/Adobe Photoshop CC/Adobe Photoshop CC.app/Contents/Application Data/Custom File Info Panels/4.0/bin/loc:\n"
"/Applications/Adobe Photoshop CC/Adobe Photoshop "
"CC.app/Contents/Application Data/Custom File Info "
"Panels/4.0/bin/loc:\n"
"FileInfo_ar_AE.dat\n"
"FileInfo_bg_BG.dat\n"
"FileInfo_cs_CZ.dat\n"
@ -219,12 +226,16 @@ int main()
"FileInfo_zh_CN.dat\n"
"FileInfo_zh_TW.dat\n"
"\n"
"/Applications/Adobe Photoshop CC/Adobe Photoshop CC.app/Contents/Application Data/Custom File Info Panels/4.0/custom:\n"
"/Applications/Adobe Photoshop CC/Adobe Photoshop "
"CC.app/Contents/Application Data/Custom File Info "
"Panels/4.0/custom:\n"
"DICOM.xml\n"
"Mobile.xml\n"
"loc\n"
"\n"
"/Applications/Adobe Photoshop CC/Adobe Photoshop CC.app/Contents/Application Data/Custom File Info Panels/4.0/custom/loc:\n"
"/Applications/Adobe Photoshop CC/Adobe Photoshop "
"CC.app/Contents/Application Data/Custom File Info "
"Panels/4.0/custom/loc:\n"
"DICOM_ar_AE.dat\n"
"DICOM_bg_BG.dat\n"
"DICOM_cs_CZ.dat\n"
@ -290,7 +301,9 @@ int main()
"Mobile_zh_CN.dat\n"
"Mobile_zh_TW.dat\n"
"\n"
"/Applications/Adobe Photoshop CC/Adobe Photoshop CC.app/Contents/Application Data/Custom File Info Panels/4.0/panels:\n"
"/Applications/Adobe Photoshop CC/Adobe Photoshop "
"CC.app/Contents/Application Data/Custom File Info "
"Panels/4.0/panels:\n"
"IPTC\n"
"IPTCExt\n"
"advanced\n"

View File

@ -5,8 +5,6 @@ int main()
drogon::HttpViewData data;
std::cout << (data.insert("1", 1), data.get<int>("1")) << std::endl;
std::cout << (data.insertAsString("2", 2.0), data.get<std::string>("2")) << std::endl;
std::cout << (data.insertFormattedString("3", "third value is %d", 3),
data.get<std::string>("3"))
<< std::endl;
std::cout << (data.insertFormattedString("3", "third value is %d", 3), data.get<std::string>("3")) << std::endl;
std::cout << (data.insertAsString("4", "4"), data.get<std::string>("4")) << std::endl;
}

View File

@ -4,11 +4,6 @@
int main()
{
std::thread([]() {
drogon::app().getLoop()->runEvery(1, []() {
std::cout << "!" << std::endl;
});
})
.detach();
std::thread([]() { drogon::app().getLoop()->runEvery(1, []() { std::cout << "!" << std::endl; }); }).detach();
drogon::app().run();
}

View File

@ -2,5 +2,9 @@
#include <iostream>
int main()
{
std::cout << Md5Encode::encode("1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890") << std::endl;
std::cout << Md5Encode::encode(
"123456789012345678901234567890123456789012345"
"678901234567890123456789012345678901234567890"
"1234567890")
<< std::endl;
}

View File

@ -9,7 +9,9 @@
int main()
{
unsigned char in[] = "1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890";
unsigned char in[] =
"1234567890123456789012345678901234567890123456789012345"
"678901234567890123456789012345678901234567890";
unsigned char out[SHA_DIGEST_LENGTH] = {0};
SHA1(in, strlen((const char *)in), out);
/// fecfd28bbc9345891a66d7c1b8ff46e60192d284

View File

@ -17,17 +17,16 @@
#include <drogon/config.h>
#include <drogon/orm/SqlBinder.h>
#include <assert.h>
#include <memory>
#include <string>
#include <tuple>
#include <memory>
#include <type_traits>
#include <assert.h>
namespace drogon
{
namespace orm
{
enum class CompareOperator
{
EQ,
@ -43,13 +42,18 @@ enum class CompareOperator
class Criteria
{
public:
explicit operator bool() const { return !_condString.empty(); }
std::string criteriaString() const { return _condString; }
explicit operator bool() const
{
return !_condString.empty();
}
std::string criteriaString() const
{
return _condString;
}
template <typename T>
Criteria(const std::string &colName, const CompareOperator &opera, T &&arg)
{
assert(opera != CompareOperator::IsNotNull &&
opera != CompareOperator::IsNull);
assert(opera != CompareOperator::IsNotNull && opera != CompareOperator::IsNull);
_condString = colName;
switch (opera)
{
@ -79,21 +83,17 @@ class Criteria
default:
break;
}
_outputArgumentsFunc = [=](internal::SqlBinder &binder) {
binder << arg;
};
_outputArgumentsFunc = [=](internal::SqlBinder &binder) { binder << arg; };
}
template <typename T>
Criteria(const std::string &colName, T &&arg)
: Criteria(colName, CompareOperator::EQ, arg)
Criteria(const std::string &colName, T &&arg) : Criteria(colName, CompareOperator::EQ, arg)
{
}
Criteria(const std::string &colName, const CompareOperator &opera)
{
assert(opera == CompareOperator::IsNotNull ||
opera == CompareOperator::IsNull);
assert(opera == CompareOperator::IsNotNull || opera == CompareOperator::IsNull);
_condString = colName;
switch (opera)
{
@ -107,7 +107,9 @@ class Criteria
break;
}
}
Criteria() {}
Criteria()
{
}
void outputArgs(internal::SqlBinder &binder) const
{
if (_outputArgumentsFunc)

View File

@ -15,24 +15,23 @@
#pragma once
#include <drogon/config.h>
#include <drogon/orm/Exception.h>
#include <drogon/orm/Field.h>
#include <drogon/orm/Result.h>
#include <drogon/orm/ResultIterator.h>
#include <drogon/orm/Row.h>
#include <drogon/orm/RowIterator.h>
#include <drogon/orm/SqlBinder.h>
#include <exception>
#include <functional>
#include <future>
#include <string>
#include <trantor/utils/Logger.h>
#include <trantor/utils/NonCopyable.h>
#include <drogon/orm/SqlBinder.h>
#include <drogon/orm/Result.h>
#include <drogon/orm/Row.h>
#include <drogon/orm/Field.h>
#include <drogon/orm/ResultIterator.h>
#include <drogon/orm/RowIterator.h>
#include <string>
#include <functional>
#include <exception>
#include <future>
namespace drogon
{
namespace orm
{
typedef std::function<void(const Result &)> ResultCallback;
typedef std::function<void(const DrogonDbException &)> ExceptionCallback;
@ -46,9 +45,12 @@ class DbClient : public trantor::NonCopyable
/// Create new database client with multiple connections;
/**
* @param connInfo: Connection string with some parameters,
* each parameter setting is in the form keyword = value. Spaces around the equal sign are optional.
* To write an empty value, or a value containing spaces, surround it with single quotes, e.g.,
* keyword = 'a value'. Single quotes and backslashes within the value must be escaped with a backslash,
* each parameter setting is in the form keyword = value. Spaces around the
* equal sign are optional.
* To write an empty value, or a value containing spaces, surround it with
* single quotes, e.g.,
* keyword = 'a value'. Single quotes and backslashes within the value must be
* escaped with a backslash,
* i.e., \' and \\.
* Example:
* host=localhost port=5432 dbname=mydb connect_timeout=10 password=''
@ -58,10 +60,12 @@ class DbClient : public trantor::NonCopyable
* - dbname: The database name. Defaults to be the same as the user name.
* - user: user name to connect as. With PostgreSQL defaults to be the same as
* the operating system name of the user running the application.
* - password: Password to be used if the server demands password authentication.
* - password: Password to be used if the server demands password
* authentication.
*
* For other key words on PostgreSQL, see the PostgreSQL documentation.
* Only a pair of key values is valid for Sqlite3, and its keyword is 'filename'.
* Only a pair of key values is valid for Sqlite3, and its keyword is
* 'filename'.
*
* @param connNum: The number of connections to database server;
*/
@ -79,29 +83,30 @@ class DbClient : public trantor::NonCopyable
/**
* FUNCTION1 is usually the ResultCallback type;
* FUNCTION2 is usually the ExceptionCallback type;
* @param args are parameters that are bound to placeholders in the @param sql.
* @param args are parameters that are bound to placeholders in the @param
* sql.
* NOTE:
*
* If the number of @param args is not zero, make sure that all criteria
* in @param sql are set by bind parameters, for example:
*
* 1. select * from users where user_id > 10 limit 10 offset 10; //Not bad, no bind parameters are used.
* 2. select * from users where user_id > ? limit ? offset ?; //Good, fully use bind parameters.
* 3. select * from users where user_id > ? limit ? offset 10; //Bad, partially use bind parameters.
* 1. select * from users where user_id > 10 limit 10 offset 10; //Not bad,
* no bind parameters are used.
* 2. select * from users where user_id > ? limit ? offset ?; //Good, fully
* use bind parameters.
* 3. select * from users where user_id > ? limit ? offset 10; //Bad,
* partially use bind parameters.
*
* Strictly speaking, try not to splice SQL statements dynamically, Instead, use the constant sql string
* Strictly speaking, try not to splice SQL statements dynamically, Instead,
* use the constant sql string
* with placeholders and the bind parameters to execute sql.
* This rule makes the sql execute faster and more securely, and users should follow this rule when calling
* This rule makes the sql execute faster and more securely, and users should
* follow this rule when calling
* all methods of DbClient.
*
*/
template <typename FUNCTION1,
typename FUNCTION2,
typename... Arguments>
void execSqlAsync(const std::string &sql,
FUNCTION1 &&rCallback,
FUNCTION2 &&exceptCallback,
Arguments &&... args) noexcept
template <typename FUNCTION1, typename FUNCTION2, typename... Arguments>
void execSqlAsync(const std::string &sql, FUNCTION1 &&rCallback, FUNCTION2 &&exceptCallback, Arguments &&... args) noexcept
{
auto binder = *this << sql;
(void)std::initializer_list<int>{(binder << std::forward<Arguments>(args), 0)...};
@ -111,26 +116,20 @@ class DbClient : public trantor::NonCopyable
/// Async and nonblocking method
template <typename... Arguments>
std::future<const Result> execSqlAsyncFuture(const std::string &sql,
Arguments &&... args) noexcept
std::future<const Result> execSqlAsyncFuture(const std::string &sql, Arguments &&... args) noexcept
{
auto binder = *this << sql;
(void)std::initializer_list<int>{(binder << std::forward<Arguments>(args), 0)...};
std::shared_ptr<std::promise<const Result>> prom = std::make_shared<std::promise<const Result>>();
binder >> [=](const Result &r) {
prom->set_value(r);
};
binder >> [=](const std::exception_ptr &e) {
prom->set_exception(e);
};
binder >> [=](const Result &r) { prom->set_value(r); };
binder >> [=](const std::exception_ptr &e) { prom->set_exception(e); };
binder.exec();
return prom->get_future();
}
// Sync and blocking method
template <typename... Arguments>
const Result execSqlSync(const std::string &sql,
Arguments &&... args) noexcept(false)
const Result execSqlSync(const std::string &sql, Arguments &&... args) noexcept(false)
{
Result r(nullptr);
{
@ -139,36 +138,45 @@ class DbClient : public trantor::NonCopyable
// Use blocking mode
binder << Mode::Blocking;
binder >> [&r](const Result &result) {
r = result;
};
binder >> [&r](const Result &result) { r = result; };
binder.exec(); // exec may be throw exception;
}
return r;
}
/// Streaming-like method for sql execution. For more information, see the wiki page.
/// Streaming-like method for sql execution. For more information, see the
/// wiki page.
internal::SqlBinder operator<<(const std::string &sql);
internal::SqlBinder operator<<(std::string &&sql);
/// Create a transaction object.
/**
* @param commitCallback: the callback with which user can get the submitting result,
* @param commitCallback: the callback with which user can get the submitting
* result,
* The Boolean type parameter in the callback function indicates whether the
* transaction was submitted successfully.
* NOTE:
* The callback only indicates the result of the 'commit' command, which is the last
* step of the transaction. If the transaction has been automatically or manually rolled back,
* The callback only indicates the result of the 'commit' command, which is
* the last
* step of the transaction. If the transaction has been automatically or
* manually rolled back,
* the callback will never be executed.
* You can also use the setCommitCallback() method of a transaction object to set the callback.
* You can also use the setCommitCallback() method of a transaction object to
* set the callback.
*/
virtual std::shared_ptr<Transaction> newTransaction(const std::function<void(bool)> &commitCallback = nullptr) = 0;
/// Create a transaction object in asynchronous mode.
virtual void newTransactionAsync(const std::function<void(const std::shared_ptr<Transaction> &)> &callback) = 0;
ClientType type() const { return _type; }
const std::string &connectionInfo() { return _connInfo; }
ClientType type() const
{
return _type;
}
const std::string &connectionInfo()
{
return _connInfo;
}
private:
friend internal::SqlBinder;

View File

@ -25,18 +25,18 @@
#pragma once
#include <functional>
#include <stdexcept>
#include <string>
#include <functional>
namespace drogon
{
namespace orm
{
/// Mixin base class to identify drogon-db-specific exception types
/**
* If you wish to catch all exception types specific to drogon db for some reason,
* If you wish to catch all exception types specific to drogon db for some
* reason,
* catch this type. All of drogon db's exception classes are derived from it
* through multiple-inheritance (they also fit into the standard library's
* exception hierarchy in more fitting places).
@ -70,7 +70,8 @@ class DrogonDbException
* catch (const drogon::orm::DrogonDbException &e)
* {
* std::cerr << e.base().what() << std::endl;
* const drogon::orm::SqlError *s=dynamic_cast<const drogon::orm::SqlError*>(&e.base());
* const drogon::orm::SqlError *s=dynamic_cast<const
* drogon::orm::SqlError*>(&e.base());
* if (s) std::cerr << "Query was: " << s->query() << std::endl;
* }
* @endcode
@ -82,7 +83,8 @@ class DrogonDbException
} //[t00]
};
/// Run-time Failure encountered by drogon orm lib, similar to std::runtime_error
/// Run-time Failure encountered by drogon orm lib, similar to
/// std::runtime_error
class Failure : public DrogonDbException, public std::runtime_error
{
virtual const std::exception &base() const noexcept override
@ -132,10 +134,7 @@ class SqlError : public Failure
const std::string _sqlState;
public:
explicit SqlError(
const std::string &msg = "",
const std::string &Q = "",
const char sqlstate[] = nullptr);
explicit SqlError(const std::string &msg = "", const std::string &Q = "", const char sqlstate[] = nullptr);
virtual ~SqlError() noexcept;
/// The query whose execution triggered the exception
@ -261,108 +260,110 @@ class UnexpectedRows : public RangeError
}
public:
explicit UnexpectedRows(const std::string &msg) : RangeError(msg) {}
explicit UnexpectedRows(const std::string &msg) : RangeError(msg)
{
}
};
/// Database feature not supported in current setup
class FeatureNotSupported : public SqlError
{
public:
explicit FeatureNotSupported(
const std::string &err,
const std::string &Q = "",
const char sqlstate[] = nullptr) : SqlError(err, Q, sqlstate) {}
explicit FeatureNotSupported(const std::string &err, const std::string &Q = "", const char sqlstate[] = nullptr)
: SqlError(err, Q, sqlstate)
{
}
};
/// Error in data provided to SQL statement
class DataException : public SqlError
{
public:
explicit DataException(
const std::string &err,
const std::string &Q = "",
const char sqlstate[] = nullptr) : SqlError(err, Q, sqlstate) {}
explicit DataException(const std::string &err, const std::string &Q = "", const char sqlstate[] = nullptr)
: SqlError(err, Q, sqlstate)
{
}
};
class IntegrityConstraintViolation : public SqlError
{
public:
explicit IntegrityConstraintViolation(
const std::string &err,
const std::string &Q = "",
const char sqlstate[] = nullptr) : SqlError(err, Q, sqlstate) {}
explicit IntegrityConstraintViolation(const std::string &err, const std::string &Q = "", const char sqlstate[] = nullptr)
: SqlError(err, Q, sqlstate)
{
}
};
class RestrictViolation : public IntegrityConstraintViolation
{
public:
explicit RestrictViolation(
const std::string &err,
const std::string &Q = "",
const char sqlstate[] = nullptr) : IntegrityConstraintViolation(err, Q, sqlstate) {}
explicit RestrictViolation(const std::string &err, const std::string &Q = "", const char sqlstate[] = nullptr)
: IntegrityConstraintViolation(err, Q, sqlstate)
{
}
};
class NotNullViolation : public IntegrityConstraintViolation
{
public:
explicit NotNullViolation(
const std::string &err,
const std::string &Q = "",
const char sqlstate[] = nullptr) : IntegrityConstraintViolation(err, Q, sqlstate) {}
explicit NotNullViolation(const std::string &err, const std::string &Q = "", const char sqlstate[] = nullptr)
: IntegrityConstraintViolation(err, Q, sqlstate)
{
}
};
class ForeignKeyViolation : public IntegrityConstraintViolation
{
public:
explicit ForeignKeyViolation(
const std::string &err,
const std::string &Q = "",
const char sqlstate[] = nullptr) : IntegrityConstraintViolation(err, Q, sqlstate) {}
explicit ForeignKeyViolation(const std::string &err, const std::string &Q = "", const char sqlstate[] = nullptr)
: IntegrityConstraintViolation(err, Q, sqlstate)
{
}
};
class UniqueViolation : public IntegrityConstraintViolation
{
public:
explicit UniqueViolation(
const std::string &err,
const std::string &Q = "",
const char sqlstate[] = nullptr) : IntegrityConstraintViolation(err, Q, sqlstate) {}
explicit UniqueViolation(const std::string &err, const std::string &Q = "", const char sqlstate[] = nullptr)
: IntegrityConstraintViolation(err, Q, sqlstate)
{
}
};
class CheckViolation : public IntegrityConstraintViolation
{
public:
explicit CheckViolation(
const std::string &err,
const std::string &Q = "",
const char sqlstate[] = nullptr) : IntegrityConstraintViolation(err, Q, sqlstate) {}
explicit CheckViolation(const std::string &err, const std::string &Q = "", const char sqlstate[] = nullptr)
: IntegrityConstraintViolation(err, Q, sqlstate)
{
}
};
class InvalidCursorState : public SqlError
{
public:
explicit InvalidCursorState(
const std::string &err,
const std::string &Q = "",
const char sqlstate[] = nullptr) : SqlError(err, Q, sqlstate) {}
explicit InvalidCursorState(const std::string &err, const std::string &Q = "", const char sqlstate[] = nullptr)
: SqlError(err, Q, sqlstate)
{
}
};
class InvalidSqlStatementName : public SqlError
{
public:
explicit InvalidSqlStatementName(
const std::string &err,
const std::string &Q = "",
const char sqlstate[] = nullptr) : SqlError(err, Q, sqlstate) {}
explicit InvalidSqlStatementName(const std::string &err, const std::string &Q = "", const char sqlstate[] = nullptr)
: SqlError(err, Q, sqlstate)
{
}
};
class InvalidCursorName : public SqlError
{
public:
explicit InvalidCursorName(
const std::string &err,
const std::string &Q = "",
const char sqlstate[] = nullptr) : SqlError(err, Q, sqlstate) {}
explicit InvalidCursorName(const std::string &err, const std::string &Q = "", const char sqlstate[] = nullptr)
: SqlError(err, Q, sqlstate)
{
}
};
class SyntaxError : public SqlError
@ -371,81 +372,82 @@ class SyntaxError : public SqlError
/// Approximate position in string where error occurred, or -1 if unknown.
const int _errorPosition;
explicit SyntaxError(
const std::string &err,
const std::string &Q = "",
const char sqlstate[] = nullptr,
int pos = -1) : SqlError(err, Q, sqlstate), _errorPosition(pos) {}
explicit SyntaxError(const std::string &err, const std::string &Q = "", const char sqlstate[] = nullptr, int pos = -1)
: SqlError(err, Q, sqlstate), _errorPosition(pos)
{
}
};
class UndefinedColumn : public SyntaxError
{
public:
explicit UndefinedColumn(
const std::string &err,
const std::string &Q = "",
const char sqlstate[] = nullptr) : SyntaxError(err, Q, sqlstate) {}
explicit UndefinedColumn(const std::string &err, const std::string &Q = "", const char sqlstate[] = nullptr)
: SyntaxError(err, Q, sqlstate)
{
}
};
class UndefinedFunction : public SyntaxError
{
public:
explicit UndefinedFunction(
const std::string &err,
const std::string &Q = "",
const char sqlstate[] = nullptr) : SyntaxError(err, Q, sqlstate) {}
explicit UndefinedFunction(const std::string &err, const std::string &Q = "", const char sqlstate[] = nullptr)
: SyntaxError(err, Q, sqlstate)
{
}
};
class UndefinedTable : public SyntaxError
{
public:
explicit UndefinedTable(
const std::string &err,
const std::string &Q = "",
const char sqlstate[] = nullptr) : SyntaxError(err, Q, sqlstate) {}
explicit UndefinedTable(const std::string &err, const std::string &Q = "", const char sqlstate[] = nullptr)
: SyntaxError(err, Q, sqlstate)
{
}
};
class InsufficientPrivilege : public SqlError
{
public:
explicit InsufficientPrivilege(
const std::string &err,
const std::string &Q = "",
const char sqlstate[] = nullptr) : SqlError(err, Q, sqlstate) {}
explicit InsufficientPrivilege(const std::string &err, const std::string &Q = "", const char sqlstate[] = nullptr)
: SqlError(err, Q, sqlstate)
{
}
};
/// Resource shortage on the server
class InsufficientResources : public SqlError
{
public:
explicit InsufficientResources(
const std::string &err,
const std::string &Q = "",
const char sqlstate[] = nullptr) : SqlError(err, Q, sqlstate) {}
explicit InsufficientResources(const std::string &err, const std::string &Q = "", const char sqlstate[] = nullptr)
: SqlError(err, Q, sqlstate)
{
}
};
class DiskFull : public InsufficientResources
{
public:
explicit DiskFull(
const std::string &err,
const std::string &Q = "",
const char sqlstate[] = nullptr) : InsufficientResources(err, Q, sqlstate) {}
explicit DiskFull(const std::string &err, const std::string &Q = "", const char sqlstate[] = nullptr)
: InsufficientResources(err, Q, sqlstate)
{
}
};
class OutOfMemory : public InsufficientResources
{
public:
explicit OutOfMemory(
const std::string &err,
const std::string &Q = "",
const char sqlstate[] = nullptr) : InsufficientResources(err, Q, sqlstate) {}
explicit OutOfMemory(const std::string &err, const std::string &Q = "", const char sqlstate[] = nullptr)
: InsufficientResources(err, Q, sqlstate)
{
}
};
class TooManyConnections : public BrokenConnection
{
public:
explicit TooManyConnections(const std::string &err) : BrokenConnection(err) {}
explicit TooManyConnections(const std::string &err) : BrokenConnection(err)
{
}
};
// /// PL/pgSQL error

View File

@ -17,19 +17,18 @@
#pragma once
#include <trantor/utils/config.h>
#include <drogon/orm/ArrayParser.h>
#include <drogon/orm/Result.h>
#include <drogon/orm/Row.h>
#include <drogon/orm/ArrayParser.h>
#include <vector>
#include <string>
#include <sstream>
#include <memory>
#include <sstream>
#include <string>
#include <trantor/utils/config.h>
#include <vector>
#ifdef __linux__
#include <arpa/inet.h>
inline uint64_t
ntohll(const uint64_t &input)
inline uint64_t ntohll(const uint64_t &input)
{
uint64_t rval;
uint8_t *data = (uint8_t *)&rval;
@ -46,15 +45,13 @@ ntohll(const uint64_t &input)
return rval;
}
inline uint64_t
htonll(const uint64_t &input)
inline uint64_t htonll(const uint64_t &input)
{
return (ntohll(input));
}
#endif
#ifdef _WIN32
inline uint64_t
ntohll(const uint64_t &input)
inline uint64_t ntohll(const uint64_t &input)
{
uint64_t rval;
uint8_t *data = (uint8_t *)&rval;
@ -71,8 +68,7 @@ ntohll(const uint64_t &input)
return rval;
}
inline uint64_t
htonll(const uint64_t &input)
inline uint64_t htonll(const uint64_t &input)
{
return (ntohll(input));
}
@ -81,7 +77,6 @@ namespace drogon
{
namespace orm
{
/// Reference to a field in a result set.
/**
* A field represents one entry in a row. It represents an actual value

View File

@ -13,21 +13,19 @@
*/
#pragma once
#include <exception>
#include <string>
#include <tuple>
#include <type_traits>
#include <string>
#include <exception>
namespace drogon
{
namespace orm
{
class Result;
class DrogonDbException;
namespace internal
{
template <typename>
struct FunctionTraits;
template <>
@ -43,32 +41,22 @@ struct FunctionTraits<void (*)()>
};
// functor,lambda
template <typename Function>
struct FunctionTraits : public FunctionTraits<
decltype(&std::remove_reference<Function>::type::operator())>
struct FunctionTraits : public FunctionTraits<decltype(&std::remove_reference<Function>::type::operator())>
{
};
template <
typename ClassType,
typename ReturnType,
typename... Arguments>
struct FunctionTraits<
ReturnType (ClassType::*)(Arguments...) const> : FunctionTraits<ReturnType (*)(Arguments...)>
template <typename ClassType, typename ReturnType, typename... Arguments>
struct FunctionTraits<ReturnType (ClassType::*)(Arguments...) const> : FunctionTraits<ReturnType (*)(Arguments...)>
{
};
template <
typename ClassType,
typename ReturnType,
typename... Arguments>
struct FunctionTraits<
ReturnType (ClassType::*)(Arguments...)> : FunctionTraits<ReturnType (*)(Arguments...)>
template <typename ClassType, typename ReturnType, typename... Arguments>
struct FunctionTraits<ReturnType (ClassType::*)(Arguments...)> : FunctionTraits<ReturnType (*)(Arguments...)>
{
};
template <>
struct FunctionTraits<void (*)(const Result &)>
: public FunctionTraits<void (*)()>
struct FunctionTraits<void (*)(const Result &)> : public FunctionTraits<void (*)()>
{
static const bool isSqlCallback = true;
static const bool isStepResultCallback = false;
@ -76,8 +64,7 @@ struct FunctionTraits<void (*)(const Result &)>
};
template <>
struct FunctionTraits<void (*)(const DrogonDbException &)>
: public FunctionTraits<void (*)()>
struct FunctionTraits<void (*)(const DrogonDbException &)> : public FunctionTraits<void (*)()>
{
static const bool isExceptCallback = true;
static const bool isSqlCallback = false;
@ -86,8 +73,7 @@ struct FunctionTraits<void (*)(const DrogonDbException &)>
};
template <>
struct FunctionTraits<void (*)(const std::exception_ptr &)>
: public FunctionTraits<void (*)()>
struct FunctionTraits<void (*)(const std::exception_ptr &)> : public FunctionTraits<void (*)()>
{
static const bool isExceptCallback = true;
static const bool isSqlCallback = false;
@ -95,28 +81,20 @@ struct FunctionTraits<void (*)(const std::exception_ptr &)>
static const bool isPtr = true;
};
template <
typename ReturnType,
typename... Arguments>
struct FunctionTraits<
ReturnType (*)(bool, Arguments...)> : FunctionTraits<ReturnType (*)(Arguments...)>
template <typename ReturnType, typename... Arguments>
struct FunctionTraits<ReturnType (*)(bool, Arguments...)> : FunctionTraits<ReturnType (*)(Arguments...)>
{
static const bool isSqlCallback = true;
static const bool isStepResultCallback = true;
};
template <
typename ReturnType,
typename... Arguments>
struct FunctionTraits<
ReturnType (*)(Arguments...)>
template <typename ReturnType, typename... Arguments>
struct FunctionTraits<ReturnType (*)(Arguments...)>
{
typedef ReturnType result_type;
template <std::size_t Index>
using argument = typename std::tuple_element<
Index,
std::tuple<Arguments...>>::type;
using argument = typename std::tuple_element<Index, std::tuple<Arguments...>>::type;
static const std::size_t arity = sizeof...(Arguments);

View File

@ -13,18 +13,17 @@
*/
#pragma once
#include <drogon/orm/DbClient.h>
#include <drogon/orm/Criteria.h>
#include <drogon/orm/DbClient.h>
#include <drogon/utils/Utilities.h>
#include <vector>
#include <string>
#include <type_traits>
#include <vector>
namespace drogon
{
namespace orm
{
enum class SortOrder
{
ASC,
@ -58,63 +57,48 @@ class Mapper
typedef std::function<void(std::vector<T>)> MultipleRowsCallback;
typedef std::function<void(const size_t)> CountCallback;
Mapper(const DbClientPtr &client) : _client(client) {}
Mapper(const DbClientPtr &client) : _client(client)
{
}
typedef typename internal::Traits<T, !std::is_same<typename T::PrimaryKeyType, void>::value>::type TraitsPKType;
T findByPrimaryKey(const TraitsPKType &key) noexcept(false);
void findByPrimaryKey(const TraitsPKType &key,
const SingleRowCallback &rcb,
const ExceptionCallback &ecb) noexcept;
void findByPrimaryKey(const TraitsPKType &key, const SingleRowCallback &rcb, const ExceptionCallback &ecb) noexcept;
std::future<T> findFutureByPrimaryKey(const TraitsPKType &key) noexcept;
std::vector<T> findAll() noexcept(false);
void findAll(const MultipleRowsCallback &rcb,
const ExceptionCallback &ecb) noexcept;
void findAll(const MultipleRowsCallback &rcb, const ExceptionCallback &ecb) noexcept;
std::future<std::vector<T>> findFutureAll() noexcept;
size_t count(const Criteria &criteria = Criteria()) noexcept(false);
void count(const Criteria &criteria,
const CountCallback &rcb,
const ExceptionCallback &ecb) noexcept;
void count(const Criteria &criteria, const CountCallback &rcb, const ExceptionCallback &ecb) noexcept;
std::future<size_t> countFuture(const Criteria &criteria = Criteria()) noexcept;
T findOne(const Criteria &criteria) noexcept(false);
void findOne(const Criteria &criteria,
const SingleRowCallback &rcb,
const ExceptionCallback &ecb) noexcept;
void findOne(const Criteria &criteria, const SingleRowCallback &rcb, const ExceptionCallback &ecb) noexcept;
std::future<T> findFutureOne(const Criteria &criteria) noexcept;
std::vector<T> findBy(const Criteria &criteria) noexcept(false);
void findBy(const Criteria &criteria,
const MultipleRowsCallback &rcb,
const ExceptionCallback &ecb) noexcept;
void findBy(const Criteria &criteria, const MultipleRowsCallback &rcb, const ExceptionCallback &ecb) noexcept;
std::future<std::vector<T>> findFutureBy(const Criteria &criteria) noexcept;
void insert(T &obj) noexcept(false);
void insert(const T &obj,
const SingleRowCallback &rcb,
const ExceptionCallback &ecb) noexcept;
void insert(const T &obj, const SingleRowCallback &rcb, const ExceptionCallback &ecb) noexcept;
std::future<T> insertFuture(const T &) noexcept;
size_t update(const T &obj) noexcept(false);
void update(const T &obj,
const CountCallback &rcb,
const ExceptionCallback &ecb) noexcept;
void update(const T &obj, const CountCallback &rcb, const ExceptionCallback &ecb) noexcept;
std::future<size_t> updateFuture(const T &obj) noexcept;
size_t deleteOne(const T &obj) noexcept(false);
void deleteOne(const T &obj,
const CountCallback &rcb,
const ExceptionCallback &ecb) noexcept;
void deleteOne(const T &obj, const CountCallback &rcb, const ExceptionCallback &ecb) noexcept;
std::future<size_t> deleteFutureOne(const T &obj) noexcept;
size_t deleteBy(const Criteria &criteria) noexcept(false);
void deleteBy(const Criteria &criteria,
const CountCallback &rcb,
const ExceptionCallback &ecb) noexcept;
void deleteBy(const Criteria &criteria, const CountCallback &rcb, const ExceptionCallback &ecb) noexcept;
std::future<size_t> deleteFutureBy(const Criteria &criteria) noexcept;
private:
@ -138,7 +122,8 @@ class Mapper
sql += " = $?";
}
template <typename PKType = decltype(T::primaryKeyName)>
typename std::enable_if<std::is_same<const std::vector<std::string>, PKType>::value, void>::type makePrimaryKeyCriteria(std::string &sql)
typename std::enable_if<std::is_same<const std::vector<std::string>, PKType>::value, void>::type makePrimaryKeyCriteria(
std::string &sql)
{
sql += " where ";
for (size_t i = 0; i < T::primaryKeyName.size(); i++)
@ -152,14 +137,16 @@ class Mapper
}
}
template <typename PKType = decltype(T::primaryKeyName)>
typename std::enable_if<std::is_same<const std::string, PKType>::value, void>::type
outputPrimeryKeyToBinder(const TraitsPKType &pk, internal::SqlBinder &binder)
typename std::enable_if<std::is_same<const std::string, PKType>::value, void>::type outputPrimeryKeyToBinder(
const TraitsPKType &pk,
internal::SqlBinder &binder)
{
binder << pk;
}
template <typename PKType = decltype(T::primaryKeyName)>
typename std::enable_if<std::is_same<const std::vector<std::string>, PKType>::value, void>::type
outputPrimeryKeyToBinder(const TraitsPKType &pk, internal::SqlBinder &binder)
typename std::enable_if<std::is_same<const std::vector<std::string>, PKType>::value, void>::type outputPrimeryKeyToBinder(
const TraitsPKType &pk,
internal::SqlBinder &binder)
{
tupleToBinder<typename T::PrimaryKeyType>(pk, binder);
}
@ -198,9 +185,7 @@ inline T Mapper<T>::findByPrimaryKey(const typename Mapper<T>::TraitsPKType &key
auto binder = *_client << std::move(sql);
outputPrimeryKeyToBinder(key, binder);
binder << Mode::Blocking;
binder >> [&r](const Result &result) {
r = result;
};
binder >> [&r](const Result &result) { r = result; };
binder.exec(); // exec may be throw exception;
}
if (r.size() == 0)
@ -251,8 +236,7 @@ inline void Mapper<T>::findByPrimaryKey(const typename Mapper<T>::TraitsPKType &
}
template <typename T>
inline std::future<T>
Mapper<T>::findFutureByPrimaryKey(const typename Mapper<T>::TraitsPKType &key) noexcept
inline std::future<T> Mapper<T>::findFutureByPrimaryKey(const typename Mapper<T>::TraitsPKType &key) noexcept
{
static_assert(!std::is_same<typename T::PrimaryKeyType, void>::value, "No primary key in the table!");
// return findFutureOne(Criteria(T::primaryKeyName, key));
@ -297,9 +281,7 @@ Mapper<T>::findFutureByPrimaryKey(const typename Mapper<T>::TraitsPKType &key) n
prom->set_value(T(r[0]));
}
};
binder >> [=](const std::exception_ptr &e) {
prom->set_exception(e);
};
binder >> [=](const std::exception_ptr &e) { prom->set_exception(e); };
binder.exec();
return prom->get_future();
}
@ -344,9 +326,7 @@ inline T Mapper<T>::findOne(const Criteria &criteria) noexcept(false)
binder << _offset;
clear();
binder << Mode::Blocking;
binder >> [&r](const Result &result) {
r = result;
};
binder >> [&r](const Result &result) { r = result; };
binder.exec(); // exec may be throw exception;
}
if (r.size() == 0)
@ -362,9 +342,7 @@ inline T Mapper<T>::findOne(const Criteria &criteria) noexcept(false)
}
template <typename T>
inline void Mapper<T>::findOne(const Criteria &criteria,
const SingleRowCallback &rcb,
const ExceptionCallback &ecb) noexcept
inline void Mapper<T>::findOne(const Criteria &criteria, const SingleRowCallback &rcb, const ExceptionCallback &ecb) noexcept
{
std::string sql = "select * from ";
sql += T::tableName;
@ -483,9 +461,7 @@ inline std::future<T> Mapper<T>::findFutureOne(const Criteria &criteria) noexcep
prom->set_value(T(r[0]));
}
};
binder >> [=](const std::exception_ptr &e) {
prom->set_exception(e);
};
binder >> [=](const std::exception_ptr &e) { prom->set_exception(e); };
binder.exec();
return prom->get_future();
}
@ -529,9 +505,7 @@ inline std::vector<T> Mapper<T>::findBy(const Criteria &criteria) noexcept(false
binder << _offset;
clear();
binder << Mode::Blocking;
binder >> [&r](const Result &result) {
r = result;
};
binder >> [&r](const Result &result) { r = result; };
binder.exec(); // exec may be throw exception;
}
std::vector<T> ret;
@ -542,9 +516,7 @@ inline std::vector<T> Mapper<T>::findBy(const Criteria &criteria) noexcept(false
return ret;
}
template <typename T>
inline void Mapper<T>::findBy(const Criteria &criteria,
const MultipleRowsCallback &rcb,
const ExceptionCallback &ecb) noexcept
inline void Mapper<T>::findBy(const Criteria &criteria, const MultipleRowsCallback &rcb, const ExceptionCallback &ecb) noexcept
{
std::string sql = "select * from ";
sql += T::tableName;
@ -636,9 +608,7 @@ inline std::future<std::vector<T>> Mapper<T>::findFutureBy(const Criteria &crite
}
prom->set_value(ret);
};
binder >> [=](const std::exception_ptr &e) {
prom->set_exception(e);
};
binder >> [=](const std::exception_ptr &e) { prom->set_exception(e); };
binder.exec();
return prom->get_future();
}
@ -648,8 +618,7 @@ inline std::vector<T> Mapper<T>::findAll() noexcept(false)
return findBy(Criteria());
}
template <typename T>
inline void Mapper<T>::findAll(const MultipleRowsCallback &rcb,
const ExceptionCallback &ecb) noexcept
inline void Mapper<T>::findAll(const MultipleRowsCallback &rcb, const ExceptionCallback &ecb) noexcept
{
findBy(Criteria(), rcb, ecb);
}
@ -676,18 +645,14 @@ inline size_t Mapper<T>::count(const Criteria &criteria) noexcept(false)
if (criteria)
criteria.outputArgs(binder);
binder << Mode::Blocking;
binder >> [&r](const Result &result) {
r = result;
};
binder >> [&r](const Result &result) { r = result; };
binder.exec(); // exec may be throw exception;
}
assert(r.size() == 1);
return r[0]["count"].as<size_t>();
}
template <typename T>
inline void Mapper<T>::count(const Criteria &criteria,
const CountCallback &rcb,
const ExceptionCallback &ecb) noexcept
inline void Mapper<T>::count(const Criteria &criteria, const CountCallback &rcb, const ExceptionCallback &ecb) noexcept
{
std::string sql = "select count(*) from ";
sql += T::tableName;
@ -728,9 +693,7 @@ inline std::future<size_t> Mapper<T>::countFuture(const Criteria &criteria) noex
assert(r.size() == 1);
prom->set_value(r[0]["count"].as<size_t>());
};
binder >> [=](const std::exception_ptr &e) {
prom->set_exception(e);
};
binder >> [=](const std::exception_ptr &e) { prom->set_exception(e); };
binder.exec();
return prom->get_future();
}
@ -763,9 +726,7 @@ inline void Mapper<T>::insert(T &obj) noexcept(false)
auto binder = *_client << std::move(sql);
obj.outputArgs(binder);
binder << Mode::Blocking;
binder >> [&r](const Result &result) {
r = result;
};
binder >> [&r](const Result &result) { r = result; };
binder.exec(); // Maybe throw exception;
}
if (_client->type() == ClientType::PostgreSQL)
@ -780,9 +741,7 @@ inline void Mapper<T>::insert(T &obj) noexcept(false)
}
}
template <typename T>
inline void Mapper<T>::insert(const T &obj,
const SingleRowCallback &rcb,
const ExceptionCallback &ecb) noexcept
inline void Mapper<T>::insert(const T &obj, const SingleRowCallback &rcb, const ExceptionCallback &ecb) noexcept
{
clear();
std::string sql = "insert into ";
@ -867,9 +826,7 @@ inline std::future<T> Mapper<T>::insertFuture(const T &obj) noexcept
prom->set_value(newObj);
}
};
binder >> [=](const std::exception_ptr &e) {
prom->set_exception(e);
};
binder >> [=](const std::exception_ptr &e) { prom->set_exception(e); };
binder.exec();
return prom->get_future();
}
@ -897,17 +854,13 @@ inline size_t Mapper<T>::update(const T &obj) noexcept(false)
obj.updateArgs(binder);
outputPrimeryKeyToBinder(obj.getPrimaryKey(), binder);
binder << Mode::Blocking;
binder >> [&r](const Result &result) {
r = result;
};
binder >> [&r](const Result &result) { r = result; };
binder.exec(); // Maybe throw exception;
}
return r.affectedRows();
}
template <typename T>
inline void Mapper<T>::update(const T &obj,
const CountCallback &rcb,
const ExceptionCallback &ecb) noexcept
inline void Mapper<T>::update(const T &obj, const CountCallback &rcb, const ExceptionCallback &ecb) noexcept
{
clear();
static_assert(!std::is_same<typename T::PrimaryKeyType, void>::value, "No primary key in the table!");
@ -927,9 +880,7 @@ inline void Mapper<T>::update(const T &obj,
auto binder = *_client << std::move(sql);
obj.updateArgs(binder);
outputPrimeryKeyToBinder(obj.getPrimaryKey(), binder);
binder >> [=](const Result &r) {
rcb(r.affectedRows());
};
binder >> [=](const Result &r) { rcb(r.affectedRows()); };
binder >> ecb;
}
template <typename T>
@ -955,12 +906,8 @@ inline std::future<size_t> Mapper<T>::updateFuture(const T &obj) noexcept
outputPrimeryKeyToBinder(obj.getPrimaryKey(), binder);
std::shared_ptr<std::promise<size_t>> prom = std::make_shared<std::promise<size_t>>();
binder >> [=](const Result &r) {
prom->set_value(r.affectedRows());
};
binder >> [=](const std::exception_ptr &e) {
prom->set_exception(e);
};
binder >> [=](const Result &r) { prom->set_value(r.affectedRows()); };
binder >> [=](const std::exception_ptr &e) { prom->set_exception(e); };
binder.exec();
return prom->get_future();
}
@ -983,17 +930,13 @@ inline size_t Mapper<T>::deleteOne(const T &obj) noexcept(false)
auto binder = *_client << std::move(sql);
outputPrimeryKeyToBinder(obj.getPrimaryKey(), binder);
binder << Mode::Blocking;
binder >> [&r](const Result &result) {
r = result;
};
binder >> [&r](const Result &result) { r = result; };
binder.exec(); // Maybe throw exception;
}
return r.affectedRows();
}
template <typename T>
inline void Mapper<T>::deleteOne(const T &obj,
const CountCallback &rcb,
const ExceptionCallback &ecb) noexcept
inline void Mapper<T>::deleteOne(const T &obj, const CountCallback &rcb, const ExceptionCallback &ecb) noexcept
{
clear();
static_assert(!std::is_same<typename T::PrimaryKeyType, void>::value, "No primary key in the table!");
@ -1006,9 +949,7 @@ inline void Mapper<T>::deleteOne(const T &obj,
sql = replaceSqlPlaceHolder(sql, "$?");
auto binder = *_client << std::move(sql);
outputPrimeryKeyToBinder(obj.getPrimaryKey(), binder);
binder >> [=](const Result &r) {
rcb(r.affectedRows());
};
binder >> [=](const Result &r) { rcb(r.affectedRows()); };
binder >> ecb;
}
template <typename T>
@ -1027,12 +968,8 @@ inline std::future<size_t> Mapper<T>::deleteFutureOne(const T &obj) noexcept
outputPrimeryKeyToBinder(obj.getPrimaryKey(), binder);
std::shared_ptr<std::promise<size_t>> prom = std::make_shared<std::promise<size_t>>();
binder >> [=](const Result &r) {
prom->set_value(r.affectedRows());
};
binder >> [=](const std::exception_ptr &e) {
prom->set_exception(e);
};
binder >> [=](const Result &r) { prom->set_value(r.affectedRows()); };
binder >> [=](const std::exception_ptr &e) { prom->set_exception(e); };
binder.exec();
return prom->get_future();
}
@ -1060,17 +997,13 @@ inline size_t Mapper<T>::deleteBy(const Criteria &criteria) noexcept(false)
criteria.outputArgs(binder);
}
binder << Mode::Blocking;
binder >> [&r](const Result &result) {
r = result;
};
binder >> [&r](const Result &result) { r = result; };
binder.exec(); // Maybe throw exception;
}
return r.affectedRows();
}
template <typename T>
inline void Mapper<T>::deleteBy(const Criteria &criteria,
const CountCallback &rcb,
const ExceptionCallback &ecb) noexcept
inline void Mapper<T>::deleteBy(const Criteria &criteria, const CountCallback &rcb, const ExceptionCallback &ecb) noexcept
{
clear();
static_assert(!std::is_same<typename T::PrimaryKeyType, void>::value, "No primary key in the table!");
@ -1089,9 +1022,7 @@ inline void Mapper<T>::deleteBy(const Criteria &criteria,
{
criteria.outputArgs(binder);
}
binder >> [=](const Result &r) {
rcb(r.affectedRows());
};
binder >> [=](const Result &r) { rcb(r.affectedRows()); };
binder >> ecb;
}
template <typename T>
@ -1114,12 +1045,8 @@ inline std::future<size_t> Mapper<T>::deleteFutureBy(const Criteria &criteria) n
}
std::shared_ptr<std::promise<size_t>> prom = std::make_shared<std::promise<size_t>>();
binder >> [=](const Result &r) {
prom->set_value(r.affectedRows());
};
binder >> [=](const std::exception_ptr &e) {
prom->set_exception(e);
};
binder >> [=](const Result &r) { prom->set_value(r.affectedRows()); };
binder >> [=](const std::exception_ptr &e) { prom->set_exception(e); };
binder.exec();
return prom->get_future();
}

View File

@ -55,8 +55,9 @@ enum class SqlStatus
class Result
{
public:
Result(const ResultImplPtr &ptr)
: _resultPtr(ptr) {}
Result(const ResultImplPtr &ptr) : _resultPtr(ptr)
{
}
using difference_type = long;
using size_type = unsigned long;
using reference = Row;
@ -69,7 +70,10 @@ class Result
using ReverseIterator = ConstReverseIterator;
size_type size() const noexcept;
size_type capacity() const noexcept { return size(); }
size_type capacity() const noexcept
{
return size();
}
ConstIterator begin() const noexcept;
ConstIterator cbegin() const noexcept;
ConstIterator end() const noexcept;
@ -80,7 +84,10 @@ class Result
ConstReverseIterator rend() const;
ConstReverseIterator crend() const;
bool empty() const noexcept { return size() == 0; }
bool empty() const noexcept
{
return size() == 0;
}
reference front() const noexcept;
reference back() const noexcept;
@ -102,7 +109,8 @@ class Result
*/
size_type affectedRows() const noexcept;
/// For Mysql, Sqlite3 databases, return the auto-incrementing primary key after inserting
/// For Mysql, Sqlite3 databases, return the auto-incrementing primary key
/// after inserting
/**
* For postgreSQL databases, this method always returns zero, One can use
* the following sql to get auto-incrementing id:
@ -133,7 +141,9 @@ class Result
field_size_type getLength(size_type row, row_size_type column) const;
protected:
Result() {}
Result()
{
}
};
} // namespace orm
} // namespace drogon

View File

@ -24,12 +24,7 @@ namespace drogon
namespace orm
{
class ConstResultIterator
: public std::iterator<
std::random_access_iterator_tag,
const Row,
Result::difference_type,
ConstResultIterator,
Row>,
: public std::iterator<std::random_access_iterator_tag, const Row, Result::difference_type, ConstResultIterator, Row>,
protected Row
{
public:
@ -39,8 +34,14 @@ class ConstResultIterator
using difference_type = Result::difference_type;
// ConstResultIterator(const Row &t) noexcept : Row(t) {}
pointer operator->() { return this; }
reference operator*() { return Row(*this); }
pointer operator->()
{
return this;
}
reference operator*()
{
return Row(*this);
}
ConstResultIterator operator++(int);
ConstResultIterator &operator++()
@ -92,7 +93,9 @@ class ConstResultIterator
private:
friend class Result;
ConstResultIterator(const Result &r, size_type index) noexcept : Row(r, index) {}
ConstResultIterator(const Result &r, size_type index) noexcept : Row(r, index)
{
}
};
class ConstReverseResultIterator : private ConstResultIterator
@ -106,10 +109,13 @@ class ConstReverseResultIterator : private ConstResultIterator
using value_type = iterator_type::value_type;
using reference = iterator_type::reference;
ConstReverseResultIterator(
const ConstReverseResultIterator &rhs) : ConstResultIterator(rhs) {}
explicit ConstReverseResultIterator(
const ConstResultIterator &rhs) : ConstResultIterator(rhs) { super::operator--(); }
ConstReverseResultIterator(const ConstReverseResultIterator &rhs) : ConstResultIterator(rhs)
{
}
explicit ConstReverseResultIterator(const ConstResultIterator &rhs) : ConstResultIterator(rhs)
{
super::operator--();
}
ConstResultIterator base() const noexcept;

Some files were not shown because too many files have changed in this diff Show More