mirror of
https://gitee.com/an-tao/drogon.git
synced 2024-12-04 12:47:42 +08:00
commit
d98a2ca519
20
.clang-format
Normal file
20
.clang-format
Normal 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
3
format.sh
Executable 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
37
lib/inc/drogon/CacheMap.h
Executable file → Normal 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
116
lib/inc/drogon/Cookie.h
Executable file → Normal 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
23
lib/inc/drogon/DrClassMap.h
Executable file → Normal 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
12
lib/inc/drogon/DrObject.h
Executable file → Normal 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
5
lib/inc/drogon/DrTemplate.h
Executable file → Normal 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
12
lib/inc/drogon/DrTemplateBase.h
Executable file → Normal 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
258
lib/inc/drogon/HttpAppFramework.h
Executable file → Normal 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
67
lib/inc/drogon/HttpBinder.h
Executable file → Normal 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)...);
|
||||
|
@ -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
32
lib/inc/drogon/HttpController.h
Executable file → Normal 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
23
lib/inc/drogon/HttpFilter.h
Executable file → Normal 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
109
lib/inc/drogon/HttpRequest.h
Executable file → Normal 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> ¶meters() 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
93
lib/inc/drogon/HttpResponse.h
Executable file → Normal 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
26
lib/inc/drogon/HttpSimpleController.h
Executable file → Normal 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:
|
||||
|
@ -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
3
lib/inc/drogon/HttpViewBase.h
Executable file → Normal 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
18
lib/inc/drogon/HttpViewData.h
Executable file → Normal 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);
|
||||
|
@ -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
|
||||
|
@ -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
46
lib/inc/drogon/MultiPart.h
Executable file → Normal 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
0
lib/inc/drogon/NotFound.h
Executable file → Normal file
5
lib/inc/drogon/Session.h
Executable file → Normal file
5
lib/inc/drogon/Session.h
Executable file → Normal 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:
|
||||
|
@ -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;
|
||||
|
@ -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
|
@ -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;
|
||||
};
|
||||
|
@ -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
|
||||
|
@ -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>
|
@ -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
|
@ -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
50
lib/inc/drogon/utils/FunctionTraits.h
Executable file → Normal 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
7
lib/inc/drogon/utils/Utilities.h
Executable file → Normal 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);
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
0
lib/src/Cookie.cc
Executable file → Normal file
1
lib/src/DrClassMap.cc
Executable file → Normal file
1
lib/src/DrClassMap.cc
Executable file → Normal 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
4
lib/src/DrTemplateBase.cc
Executable file → Normal 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;
|
||||
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
|
@ -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
150
lib/src/HttpAppFrameworkImpl.cc
Executable file → Normal 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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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 ¶meter : 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));
|
||||
});
|
||||
}
|
||||
}
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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
17
lib/src/HttpRequestImpl.cc
Executable file → Normal 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
34
lib/src/HttpRequestImpl.h
Executable file → Normal 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
17
lib/src/HttpRequestParser.cc
Executable file → Normal 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
24
lib/src/HttpRequestParser.h
Executable file → Normal 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
22
lib/src/HttpResponseImpl.cc
Executable file → Normal 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
23
lib/src/HttpResponseImpl.h
Executable file → Normal 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
10
lib/src/HttpResponseParser.cc
Executable file → Normal 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
2
lib/src/HttpResponseParser.h
Executable file → Normal 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
46
lib/src/HttpServer.cc
Executable file → Normal 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
25
lib/src/HttpServer.h
Executable file → Normal 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;
|
||||
|
@ -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));
|
||||
});
|
||||
}
|
||||
}
|
@ -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;
|
||||
|
@ -18,7 +18,6 @@
|
||||
|
||||
namespace drogon
|
||||
{
|
||||
|
||||
const string_view &webContentTypeToString(ContentType contenttype)
|
||||
{
|
||||
switch (contenttype)
|
||||
|
@ -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
4
lib/src/HttpViewBase.cc
Executable file → Normal 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)
|
||||
{
|
||||
|
@ -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())
|
||||
{
|
||||
|
@ -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
19
lib/src/MultiPart.cc
Executable file → Normal 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
6
lib/src/NotFound.cc
Executable file → Normal 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;
|
||||
|
@ -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;
|
||||
|
@ -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
21
lib/src/SharedLibManager.cc
Executable file → Normal 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
2
lib/src/SharedLibManager.h
Executable file → Normal 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
|
||||
|
@ -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
47
lib/src/Utilities.cc
Executable file → Normal 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;
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
};
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -60,7 +60,6 @@ class Md5Encode
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
static std::string encode(const std::string &src_info);
|
||||
|
||||
protected:
|
||||
|
@ -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
12
lib/tests/CacheMapTest.cc
Executable file → Normal 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
26
lib/tests/CacheMapTest2.cc
Executable file → Normal 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
0
lib/tests/CookiesTest.cc
Executable file → Normal 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"
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
@ -2,5 +2,9 @@
|
||||
#include <iostream>
|
||||
int main()
|
||||
{
|
||||
std::cout << Md5Encode::encode("1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890") << std::endl;
|
||||
std::cout << Md5Encode::encode(
|
||||
"123456789012345678901234567890123456789012345"
|
||||
"678901234567890123456789012345678901234567890"
|
||||
"1234567890")
|
||||
<< std::endl;
|
||||
}
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
Loading…
Reference in New Issue
Block a user