Merge pull request #154 from an-tao/dev

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

20
.clang-format Normal file
View File

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

3
format.sh Executable file
View File

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

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

@ -14,32 +14,33 @@
#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
#define TICK_INTERVAL 1.0
//Four wheels with 200 buckets per wheel means the cache map can work with
//a timeout up to 200^4 seconds,about 50 years;
// Four wheels with 200 buckets per wheel means the cache map can work with
// a timeout up to 200^4 seconds,about 50 years;
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++;
@ -100,7 +97,7 @@ class CacheMap
CallbackBucket tmp;
{
std::lock_guard<std::mutex> lock(bucketMutex_);
//use tmp val to make this critical area as short as possible.
// use tmp val to make this critical area as short as possible.
_wheels[i].front().swap(tmp);
_wheels[i].pop_front();
_wheels[i].push_back(CallbackBucket());
@ -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)
{
@ -231,7 +231,7 @@ class CacheMap
/// Atomically find and get the value of a keyword
/**
* Return true when the value is found, and the value
* is assigned to the @param value
* is assigned to the @param value
*/
bool findAndFetch(const T1 &key, T2 &value)
{
@ -255,7 +255,7 @@ class CacheMap
/// Erases the value of the keyword.
void erase(const T1 &key)
{
//in this case,we don't evoke the timeout callback;
// in this case,we don't evoke the timeout callback;
std::lock_guard<std::mutex> lock(mtx_);
_map.erase(key);
}
@ -280,7 +280,7 @@ class CacheMap
void insertEntry(size_t delay, CallbackEntryPtr entryPtr)
{
//protected by bucketMutex;
// protected by bucketMutex;
if (delay <= 0)
return;
delay = delay / _tickInterval + 1;
@ -304,7 +304,7 @@ class CacheMap
}
else
{
//delay is too long to put entry at valid position in wheels;
// delay is too long to put entry at valid position in wheels;
_wheels[i][_bucketsNumPerWheel - 1].insert(entryPtr);
}
delay = (delay + (t % _bucketsNumPerWheel) - 1) / _bucketsNumPerWheel;
@ -337,9 +337,8 @@ class CacheMap
{
auto &value = _map[key];
auto entryPtr = value._weakEntryPtr.lock();
//entryPtr is used to avoid race conditions
if (value.timeout > 0 &&
!entryPtr)
// entryPtr is used to avoid race conditions
if (value.timeout > 0 && !entryPtr)
{
if (value._timeoutCallback)
{
@ -361,4 +360,4 @@ class CacheMap
}
};
} // namespace drogon
} // namespace drogon

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

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

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

@ -14,25 +14,24 @@
#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
{
public:
public:
static void registerClass(const std::string &className, const DrAllocFunc &func);
static DrObjectBase *newObject(const std::string &className);
static const std::shared_ptr<DrObjectBase> &getSingleInstance(const std::string &className);
@ -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());
@ -58,8 +57,8 @@ public:
return "";
}
protected:
protected:
static std::unordered_map<std::string, DrAllocFunc> &getMap();
};
} // namespace drogon
} // namespace drogon

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

@ -33,7 +33,9 @@ class DrObjectBase
{
return (className() == class_name);
}
virtual ~DrObjectBase() {}
virtual ~DrObjectBase()
{
}
};
/**
@ -59,8 +61,10 @@ class DrObject : public virtual DrObjectBase
}
protected:
//protect constructor to make this class only inheritable
DrObject() {}
// protect constructor to make this class only inheritable
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()
@ -88,10 +90,10 @@ class DrObject : public virtual DrObjectBase
}
};
//use static val to register allocator function for class T;
// use static val to register allocator function for class T;
static DrAllocator _alloc;
};
template <typename T>
typename DrObject<T>::DrAllocator DrObject<T>::_alloc;
} // namespace drogon
} // namespace drogon

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

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

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

@ -16,17 +16,17 @@
#include <drogon/DrObject.h>
#include <drogon/HttpViewData.h>
#include <string>
#include <memory>
#include <string>
namespace drogon
{
typedef HttpViewData DrTemplateData;
/// The templating engine class
/**
* This class can generate a text string from the template file and template data.
* This class can generate a text string from the template file and template
* data.
* For more details on the template file, see the wiki site (the 'View' section)
*/
class DrTemplateBase : public virtual DrObjectBase
@ -35,15 +35,17 @@ 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
* usually .csp. The user should preprocess the template file
* with the drogon_ctl tool to create c++ source files.
* 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.
*/
static std::shared_ptr<DrTemplateBase> newTemplate(std::string templateName);
/// 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;
@ -51,4 +53,4 @@ class DrTemplateBase : public virtual DrObjectBase
DrTemplateBase(){};
};
} // namespace drogon
} // namespace drogon

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

@ -2,7 +2,7 @@
*
* HttpAppFramework.h
* An Tao
*
*
* Copyright 2018, An Tao. All rights reserved.
* https://github.com/an-tao/drogon
* Use of this source code is governed by a MIT license
@ -18,39 +18,40 @@
#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"
" __| |_ __ ___ __ _ ___ _ __ \n"
" / _` | '__/ _ \\ / _` |/ _ \\| '_ \\ \n"
"| (_| | | | (_) | (_| | (_) | | | |\n"
" \\__,_|_| \\___/ \\__, |\\___/|_| |_|\n"
" |___/ \n";
// the drogon banner
const char banner[] =
" _ \n"
" __| |_ __ ___ __ _ ___ _ __ \n"
" / _` | '__/ _ \\ / _` |/ _ \\| '_ \\ \n"
"| (_| | | | (_) | (_| | (_) | | | |\n"
" \\__,_|_| \\___/ \\__, |\\___/|_| |_|\n"
" |___/ \n";
inline std::string getVersion()
{
return VERSION;
@ -68,20 +69,21 @@ typedef std::function<void()> AdviceChainCallback;
class HttpAppFramework : public trantor::NonCopyable
{
public:
public:
virtual ~HttpAppFramework();
///Get the instance of HttpAppFramework
/// Get the instance of HttpAppFramework
/**
* HttpAppFramework works at singleton mode, so any calling of this
* method gets the same instance;
* Calling drogon::HttpAppFramework::instance()
* can be replaced by a simple interface -- drogon::app()
* Calling drogon::HttpAppFramework::instance()
* can be replaced by a simple interface -- drogon::app()
*/
static HttpAppFramework &instance();
///Run the event loop
/// 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.
*/
@ -90,19 +92,19 @@ public:
/// Return true if the framework is running
virtual bool isRunning() = 0;
///Quit the event loop
/// Quit the event loop
/**
* Calling this method results in stopping all network IO in the
* framework and interrupting the blocking of the run() method. Usually,
* framework and interrupting the blocking of the run() method. Usually,
* after calling this method, the application exits.
*
*
* NOTE:
* This method can be called in any thread and anywhere.
* This method should not be called before calling run().
*/
virtual void quit() = 0;
///Get the main event loop of the framework;
/// Get the main event loop of the framework;
/**
* NOTE:
* The event loop is not the network IO loop, but the main event loop
@ -112,18 +114,18 @@ public:
*/
virtual trantor::EventLoop *getLoop() = 0;
///Set custom 404 page
/// Set custom 404 page
/**
* After calling this method, the @param resp object is returned
* After calling this method, the @param resp object is returned
* by the HttpResponse::newNotFoundResponse() method.
*/
virtual void setCustom404Page(const HttpResponsePtr &resp) = 0;
///Get the plugin object registered in the framework
/// Get the plugin object registered in the framework
/**
* NOTE:
* This method is usually called after the framework runs.
* Calling this method in the initAndStart() method of plugins is also valid.
* Calling this method in the initAndStart() method of plugins is also valid.
*/
template <typename T>
T *getPlugin()
@ -133,39 +135,45 @@ public:
return dynamic_cast<T *>(getPlugin(T::classTypeName()));
}
///Get the plugin object registered in the framework
/// Get the plugin object registered in the framework
/**
* @param name: is the class name of the plugin.
*
*
* NOTE:
* This method is usually called after the framework runs.
* Calling this method in the initAndStart() method of plugins is also valid.
* Calling this method in the initAndStart() method of plugins is also valid.
*/
virtual PluginBase *getPlugin(const std::string &name) = 0;
///The following is a series of methods of AOP
/// The following is a series of methods of AOP
///The @param advice is called immediately after the main event loop runs.
/// 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.
*
*
* +-----------+ +------------+
* | Request | | Response |
* +-----------+ +------------+
* 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.
*
*
* +-----------+ +------------+
* | Request | | Response |
* +-----------+ +------------+
* | ^
* v |
* Pre-routing join point o----------->[Advice callback]----------->+
@ -193,98 +201,120 @@ public:
* | |
* v |
* 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.
* This advice has less overhead than the above one.
* 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
///and before any 'doFilter' method of filters applies.
/// 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.
* This advice has less overhead than the above one.
* 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.
* This advice has less overhead than the above one.
* 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
/// End of AOP methods
///Load the configuration file with json format.
/// Load the configuration file with json format.
virtual void loadConfigFile(const std::string &fileName) = 0;
///Register a HttpSimpleController object into the framework.
/// 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,
const std::vector<any> &filtersAndMethods = std::vector<any>()) = 0;
///Register a handler into the framework.
/// Register a handler into the framework.
/**
* @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 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.
*
* 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,21 +354,25 @@ 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
* via this method.
* The macro or configuration file is still valid for the path routing configuration
* 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
* of the controller created by users.
*
*
* NOTE:
* The declaration of the controller class must be as follows:
* class ApiTest : public drogon::HttpController<ApiTest, false>
@ -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,67 +410,77 @@ 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
* http://www.baidu.com
* https://127.0.0.1:8080/
* http://127.0.0.1
* http://[::1]:8080/
*
* 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.
*
* This method can be used to implement reverse proxy or redirection on the server side.
* 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.
*/
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
/// 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 last item in std::tuple is the description 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;
///Get the custom configuration defined by users in the configuration file.
/// Get the custom configuration defined by users in the configuration file.
virtual const Json::Value &getCustomConfig() const = 0;
///Set the number of threads for IO event loops
/// 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.
* This number can be configured in the configuration file.
*/
virtual void setThreadNum(size_t threadNum) = 0;
///Get the number of threads for IO event loops
/// Get the number of threads for IO event loops
virtual size_t getThreadNum() const = 0;
///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;
/// 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;
///Add a listener for http or https service
/// 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:
* This operation can be performed by an option in the configuration file.
*/
@ -443,119 +490,120 @@ public:
const std::string &certFile = "",
const std::string &keyFile = "") = 0;
///Enable sessions supporting.
/// Enable sessions supporting.
/**
* Disabled by default.
* If there isn't any request from a client for @param timeout(>0) seconds,
* the session of the client is destroyed.
* If the @param timeout is equal to 0, sessions will remain permanently
*
*
* NOTE:
* This operation can be performed by an option in the configuration file.
*/
virtual void enableSession(const size_t timeout = 0) = 0;
///A wrapper of the above method.
/// A wrapper of the above method.
/**
* Users can set the timeout value as follows:
* app().enableSession(0.2h);
* app().enableSession(12min);
* app().enableSession(12min);
*/
inline void enableSession(const std::chrono::duration<long double> &timeout)
{
enableSession((size_t)timeout.count());
}
///Disable sessions supporting.
/**
/// Disable sessions supporting.
/**
* NOTE:
* This operation can be performed by an option in the configuration file.
*/
virtual void disableSession() = 0;
///Set the root path of HTTP document, defaut path is ./
/**
/// Set the root path of HTTP document, defaut path is ./
/**
* NOTE:
* This operation can be performed by an option in the configuration file.
*/
virtual void setDocumentRoot(const std::string &rootPath) = 0;
///Get the document root directory.
/// Get the document root directory.
virtual const std::string &getDocumentRoot() const = 0;
///Set the path to store uploaded files.
/**
* If the @param uploadPath isn't prefixed with /, ./ or ../, it is relative path of document_root path,
/// Set the path to store uploaded files.
/**
* If the @param uploadPath isn't prefixed with /, ./ or ../, it is relative
* path of document_root path,
* The default value is 'uploads'.
*
*
* NOTE:
* This operation can be performed by an option in the configuration file.
*/
virtual void setUploadPath(const std::string &uploadPath) = 0;
///Get the path to store uploaded files.
/// Get the path to store uploaded files.
virtual const std::string &getUploadPath() const = 0;
///Set types of files that can be downloaded.
/**
/// Set types of files that can be downloaded.
/**
* FOR EXAMPLE:
* app.setFileTypes({"html","txt","png","jpg"});
*
*
* NOTE:
* This operation can be performed by an option in the configuration file.
*/
virtual void setFileTypes(const std::vector<std::string> &types) = 0;
///Enable supporting for dynamic views loading.
/// Enable supporting for dynamic views loading.
/**
* Disabled by default.
* The @param libPaths is a vactor that contains paths to view files.
*
*
* NOTE:
* This operation can be performed by an option in the configuration file.
*/
virtual void enableDynamicViewsLoading(const std::vector<std::string> &libPaths) = 0;
///Set the maximum number of all connections.
/**
/// Set the maximum number of all connections.
/**
* The default value is 100000.
*
*
* NOTE:
* This operation can be performed by an option in the configuration file.
*/
virtual void setMaxConnectionNum(size_t maxConnections) = 0;
///Set the maximum number of connections per remote IP.
/**
/// Set the maximum number of connections per remote IP.
/**
* The default value is 0 which means no limit.
*
*
* NOTE:
* This operation can be performed by an option in the configuration file.
*/
virtual void setMaxConnectionNumPerIP(size_t maxConnectionsPerIP) = 0;
///Make the application run as a daemon.
/**
/// Make the application run as a daemon.
/**
* Disabled by default.
*
*
* NOTE:
* This operation can be performed by an option in the configuration file.
*/
virtual void enableRunAsDaemon() = 0;
///Make the application restart after crashing.
/**
/// Make the application restart after crashing.
/**
* Disabled by default.
*
*
* NOTE:
* This operation can be performed by an option in the configuration file.
*/
virtual void enableRelaunchOnError() = 0;
///Set the output path of logs.
/// Set the output path of logs.
/**
* @param logSize indicates the maximum size of the log file.
*
*
* NOTE:
* This operation can be performed by an option in the configuration file.
*/
@ -563,30 +611,35 @@ public:
const std::string &logfileBaseName = "",
size_t logSize = 100000000) = 0;
///Set the log level
/**
* The @param level is one of TRACE, DEBUG, INFO, WARN. The Default value is DEBUG.
*
/// Set the log level
/**
* 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.
*
*
* NOTE:
* This operation can be performed by an option in the configuration file.
* After gzip is enabled, gzip is used under the following conditions:
@ -595,99 +648,111 @@ public:
*/
virtual void enableGzip(bool useGzip) = 0;
///Return true if gzip is enabled.
/// Return true if gzip is enabled.
virtual bool isGzipEnabled() const = 0;
///Set the time in which the static file response is cached in memory.
/// 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.
*/
virtual void setStaticFilesCacheTime(int cacheTime) = 0;
///Get the time set by the above method.
/// Get the time set by the above method.
virtual int staticFilesCacheTime() const = 0;
///Set the lifetime of the connection without read or write
/// 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.
*/
virtual void setIdleConnectionTimeout(size_t timeout) = 0;
///A wrapper of the above method.
/// A wrapper of the above method.
/**
* Users can set the timeout value as follows:
* app().setIdleConnectionTimeout(0.5h);
* app().setIdleConnectionTimeout(30min);
* app().setIdleConnectionTimeout(30min);
*/
inline void setIdleConnectionTimeout(const std::chrono::duration<long double> &timeout)
{
setIdleConnectionTimeout((size_t)timeout.count());
}
///Set the 'server' header field in each response sent by drogon.
/// 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:
* This operation can be performed by an option in the configuration file.
*/
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:
* This operation can be performed by an option in the configuration file.
*/
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.
*/
virtual void setPipeliningRequestsNumber(const size_t number) = 0;
///Set the gzip_static option.
/// 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:
* This operation can be performed by an option in the configuration file.
*/
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.
*/
virtual void setClientMaxWebSocketMessageSize(size_t maxSize) = 0;
//Set the HTML file of the home page, the default value is "index.html"
// 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.
@ -695,31 +760,32 @@ public:
virtual void setHomePage(const std::string &homePageFile) = 0;
#if USE_ORM
///Get a database client by @param name
/// Get a database client by @param name
/**
* NOTE:
* This method must be called after the framework has been run.
*/
virtual orm::DbClientPtr getDbClient(const std::string &name = "default") = 0;
///Get a 'fast' database client by @param name
/// Get a 'fast' database client by @param name
/**
* NOTE:
* This method must be called after the framework has been run.
*/
virtual orm::DbClientPtr getFastDbClient(const std::string &name = "default") = 0;
///Create a database client
/// Create a database client
/**
* @param dbType: The database type is one of "postgresql","mysql","sqlite3".
* @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.
*
*
* NOTE:
* This operation can be performed by an option in the configuration file.
*/
@ -735,7 +801,7 @@ public:
const bool isFast = false) = 0;
#endif
private:
private:
virtual void registerHttpController(const std::string &pathPattern,
const internal::HttpBinderBasePtr &binder,
const std::vector<HttpMethod> &validMethods = std::vector<HttpMethod>(),
@ -748,4 +814,4 @@ inline HttpAppFramework &app()
return HttpAppFramework::instance();
}
} // namespace drogon
} // namespace drogon

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

@ -2,7 +2,7 @@
*
* HttpBinder.h
* An Tao
*
*
* Copyright 2018, An Tao. All rights reserved.
* https://github.com/an-tao/drogon
* Use of this source code is governed by a MIT license
@ -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));
}
@ -112,7 +118,7 @@ class HttpBinder : public HttpBinderBase
return _handlerName;
}
private:
private:
FUNCTION _func;
typedef FunctionTraits<FUNCTION> traits;
@ -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,22 +176,20 @@ 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,
Values &&... 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,
Values &&... values)
{
_func(req, std::move(callback), std::move(values)...);
};
};
} // namespace internal
} // namespace drogon
} // namespace internal
} // namespace drogon

View File

@ -1,7 +1,7 @@
/**
*
* HttpClient.h
*
*
* An Tao
*
* Copyright 2018, An Tao. All rights reserved.
@ -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,16 +30,19 @@ 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
* 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
*/
class HttpClient : public trantor::NonCopyable
@ -48,28 +50,30 @@ class HttpClient : public trantor::NonCopyable
public:
/// Send a request asynchronously to the server
/**
* The response from the http server is obtained
* The response from the http server is obtained
* in the callback function.
*/
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;
/// Use ip and port to connect to server
/**
* If useSSL is set to true, the client
/**
* If useSSL is set to true, the client
* connects to the server using https.
*
* If the loop parameter is set to nullptr, the client
*
* If the loop parameter is set to nullptr, the client
* uses the HttpAppFramework's event loop, otherwise it
* runs in the loop identified by the parameter.
*
*
* Note: The @param ip support for both ipv4 and ipv6 address
*/
static HttpClientPtr newHttpClient(const std::string &ip,
@ -81,33 +85,34 @@ class HttpClient : public trantor::NonCopyable
virtual trantor::EventLoop *getLoop() = 0;
/// Use hostString to connect to server
/**
/**
* Examples for hostString:
* https://www.baidu.com
* http://www.baidu.com
* https://127.0.0.1:8080/
* http://127.0.0.1
* http://[::1]:8080/ //IPv6 address must be enclosed in [], rfc2732
*
* The @param hostString must be prefixed by 'http://' or 'https://'
*
* If the loop parameter is set to nullptr, the client
*
* The @param hostString must be prefixed by 'http://' or 'https://'
*
* If the loop parameter is set to nullptr, the client
* uses the HttpAppFramework's event loop, otherwise it
* runs in the loop identified by the parameter.
*
*
* NOTE:
* Don't add path and parameters in hostString, the request path
* and parameters should be set in HttpRequestPtr when calling
* Don't add path and parameters in hostString, the request path
* and parameters should be set in HttpRequestPtr when calling
* 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;
};
} // namespace drogon
} // namespace drogon

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

@ -16,22 +16,20 @@
#include <drogon/DrObject.h>
#include <drogon/HttpAppFramework.h>
#include <trantor/utils/Logger.h>
#include <string>
#include <vector>
#include <iostream>
#include <string>
#include <trantor/utils/Logger.h>
#include <vector>
/// For more details on the class, see the wiki site (the 'HttpController' section)
/// For more details on the class, see the wiki site (the 'HttpController'
/// section)
#define METHOD_LIST_BEGIN \
static void initPathRouting() \
{
#define METHOD_ADD(method, pattern, filters...) registerMethod(&method, pattern, {filters}, true, #method)
#define METHOD_ADD(method, pattern, filters...) \
registerMethod(&method, pattern, {filters}, true, #method)
#define ADD_METHOD_TO(method, path_pattern, filters...) \
registerMethod(&method, path_pattern, {filters}, false, #method)
#define ADD_METHOD_TO(method, path_pattern, filters...) registerMethod(&method, path_pattern, {filters}, false, #method)
#define METHOD_LIST_END \
return; \
@ -39,7 +37,6 @@
namespace drogon
{
class HttpControllerBase
{
};
@ -51,48 +48,39 @@ class HttpController : public DrObject<T>, public HttpControllerBase
static const bool isAutoCreation = AutoCreation;
protected:
template <typename FUNCTION>
static void registerMethod(FUNCTION &&function,
const std::string &pattern,
const std::vector<any> &filtersAndMethods = std::vector<any>(),
bool classNameInPath = true,
const std::string &handlerName = "")
{
if (classNameInPath)
{
std::string path = "/";
path.append(HttpController<T>::classTypeName());
LOG_TRACE << "classname:" << HttpController<T>::classTypeName();
template <typename FUNCTION>
static void registerMethod(FUNCTION &&function,
const std::string &pattern,
const std::vector<any> &filtersAndMethods = std::vector<any>(),
bool classNameInPath = true,
const std::string &handlerName = "")
{
if (classNameInPath)
{
std::string path = "/";
path.append(HttpController<T>::classTypeName());
LOG_TRACE << "classname:" << HttpController<T>::classTypeName();
//transform(path.begin(), path.end(), path.begin(), tolower);
std::string::size_type pos;
while ((pos = path.find("::")) != std::string::npos)
{
path.replace(pos, 2, "/");
}
if (pattern.empty() || pattern[0] == '/')
app().registerHandler(path + pattern,
std::forward<FUNCTION>(function),
filtersAndMethods,
handlerName);
else
app().registerHandler(path + "/" + pattern,
std::forward<FUNCTION>(function),
filtersAndMethods,
handlerName);
}
else
{
std::string path = pattern;
if (path.empty() || path[0] != '/')
{
path = "/" + path;
}
app().registerHandler(path,
std::forward<FUNCTION>(function),
filtersAndMethods,
handlerName);
}
// transform(path.begin(), path.end(), path.begin(), tolower);
std::string::size_type pos;
while ((pos = path.find("::")) != std::string::npos)
{
path.replace(pos, 2, "/");
}
if (pattern.empty() || pattern[0] == '/')
app().registerHandler(path + pattern, std::forward<FUNCTION>(function), filtersAndMethods, handlerName);
else
app().registerHandler(path + "/" + pattern, std::forward<FUNCTION>(function), filtersAndMethods, handlerName);
}
else
{
std::string path = pattern;
if (path.empty() || path[0] != '/')
{
path = "/" + path;
}
app().registerHandler(path, std::forward<FUNCTION>(function), filtersAndMethods, handlerName);
}
}
private:
@ -105,7 +93,7 @@ class HttpController : public DrObject<T>, public HttpControllerBase
T::initPathRouting();
}
};
//use static value to register controller method in framework before main();
// use static value to register controller method in framework before main();
static methodRegister _register;
virtual void *touch()
{
@ -114,4 +102,4 @@ class HttpController : public DrObject<T>, public HttpControllerBase
};
template <typename T, bool AutoCreation>
typename HttpController<T, AutoCreation>::methodRegister HttpController<T, AutoCreation>::_register;
} // namespace drogon
} // namespace drogon

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

@ -2,7 +2,7 @@
*
* HttpFilter.h
* An Tao
*
*
* Copyright 2018, An Tao. All rights reserved.
* https://github.com/an-tao/drogon
* Use of this source code is governed by a MIT license
@ -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)
@ -27,26 +27,31 @@ typedef std::function<void(const HttpResponsePtr &)> FilterCallback;
typedef std::function<void()> FilterChainCallback;
class HttpFilterBase : public virtual DrObjectBase
{
public:
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 fccb is called, the next filter's doFilter method or the handler
* 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:
public:
static const bool isAutoCreation = AutoCreation;
virtual ~HttpFilter() {}
virtual ~HttpFilter()
{
}
};
} // namespace drogon
} // namespace drogon

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

@ -17,23 +17,22 @@
#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;
/// Abstract class for webapp developer to get or set the Http request;
class HttpRequest
{
public:
public:
enum Version
{
kUnknown = 0,
@ -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,42 +118,66 @@ public:
* kHttp11 means Http verison is 1.1
*/
virtual Version version() const = 0;
Version getVersion() const { return version(); }
Version getVersion() const
{
return version();
}
/// Get the session to which the request belongs.
virtual SessionPtr session() const = 0;
SessionPtr getSession() const { return session(); }
SessionPtr getSession() const
{
return session();
}
/// Get parameters of the request.
virtual const std::unordered_map<std::string, std::string> &parameters() const = 0;
const std::unordered_map<std::string, std::string> &getParameters() const { return parameters(); }
const std::unordered_map<std::string, std::string> &getParameters() const
{
return parameters();
}
/// Get a parameter identified by the @param key
virtual const std::string &getParameter(const std::string &key, const std::string &defaultVal = std::string()) const = 0;
/// Return the remote IP address and port
virtual const trantor::InetAddress &peerAddr() const = 0;
const trantor::InetAddress &getPeerAddr() const { return peerAddr(); }
const trantor::InetAddress &getPeerAddr() const
{
return peerAddr();
}
/// Return the local IP address and port
virtual const trantor::InetAddress &localAddr() const = 0;
const trantor::InetAddress &getLocalAddr() const { return localAddr(); }
const trantor::InetAddress &getLocalAddr() const
{
return localAddr();
}
/// Return the creation timestamp set by the framework.
virtual const trantor::Date &creationDate() const = 0;
const trantor::Date &getCreationDate() const { return creationDate(); }
const trantor::Date &getCreationDate() const
{
return creationDate();
}
/// Get the Json object of the request
/**
* The content type of the request must be 'application/json', otherwise
* The content type of the request must be 'application/json', otherwise
* 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
} // namespace drogon

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

@ -1,7 +1,7 @@
/**
* HttpResponse.h
* An Tao
*
*
* Copyright 2018, An Tao. All rights reserved.
* https://github.com/an-tao/drogon
* Use of this source code is governed by a MIT license
@ -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
{
@ -27,42 +27,55 @@ class HttpResponse;
typedef std::shared_ptr<HttpResponse> HttpResponsePtr;
class HttpResponse
{
public:
public:
HttpResponse()
{
}
/// 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
} // namespace drogon

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

@ -2,7 +2,7 @@
*
* HttpSimpleController.h
* An Tao
*
*
* Copyright 2018, An Tao. All rights reserved.
* https://github.com/an-tao/drogon
* Use of this source code is governed by a MIT license
@ -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:
@ -75,4 +79,4 @@ class HttpSimpleController : public DrObject<T>, public HttpSimpleControllerBase
template <typename T, bool AutoCreation>
typename HttpSimpleController<T, AutoCreation>::pathRegister HttpSimpleController<T, AutoCreation>::_register;
} // namespace drogon
} // namespace drogon

View File

@ -1,7 +1,7 @@
/**
* HttpTypes.h
* An Tao
*
*
* Copyright 2018, An Tao. All rights reserved.
* https://github.com/an-tao/drogon
* Use of this source code is governed by a MIT license
@ -12,16 +12,15 @@
*/
#pragma once
#include <drogon/config.h>
#include <atomic>
#include <drogon/config.h>
#include <thread>
namespace drogon
{
enum HttpStatusCode
{
//rfc2616-6.1.1
// rfc2616-6.1.1
kUnknown = 0,
k100Continue = 100,
k101SwitchingProtocols = 101,
@ -119,4 +118,4 @@ enum class ReqResult
Timeout
};
} // namespace drogon
} // namespace drogon

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

@ -2,7 +2,7 @@
*
* HttpViewBase.h
* An Tao
*
*
* Copyright 2018, An Tao. All rights reserved.
* https://github.com/an-tao/drogon
* Use of this source code is governed by a MIT license
@ -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:
@ -35,4 +34,4 @@ class HttpViewBase : virtual public DrObjectBase
virtual HttpResponsePtr genHttpResponse(const HttpViewData &) = 0;
};
} // namespace drogon
} // namespace drogon

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

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

View File

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

View File

@ -2,7 +2,7 @@
*
* LocalHostFilter.h
* An Tao
*
*
* Copyright 2018, An Tao. All rights reserved.
* https://github.com/an-tao/drogon
* Use of this source code is governed by a MIT license
@ -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
} // namespace drogon

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

@ -16,51 +16,69 @@
#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.
/**
* The folder saving the file is app().getUploadPath().
* The full path is app().getUploadPath()+"/"+this->getFileName()
* The folder saving the file is app().getUploadPath().
* The full path is app().getUploadPath()+"/"+this->getFileName()
*/
int save() const;
/// 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,13 +99,14 @@ 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.
int parse(const HttpRequestPtr &req);
/// Parse the http response stream to get files and parameters.
/// Parse the http response stream to get files and parameters.
/// int parse(const HttpResponsePtr &req);
protected:
@ -96,6 +116,6 @@ class MultiPartParser
int parseEntity(const char *begin, const char *end);
};
typedef MultiPartParser FileUpload; /// In order to be compatible with old interfaces
typedef MultiPartParser FileUpload; /// In order to be compatible with old interfaces
} // namespace drogon
} // namespace drogon

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

@ -1,10 +1,10 @@
//this file is generated by program automatically,don't modify it!
// this file is generated by program automatically,don't modify it!
/**
*
* NotFound.h
* An Tao
*
*
* Copyright 2018, An Tao. All rights reserved.
* https://github.com/an-tao/drogon
* Use of this source code is governed by a MIT license
@ -19,7 +19,7 @@
class NotFound : public drogon::DrTemplate<NotFound>
{
public:
NotFound(){};
virtual ~NotFound(){};
virtual std::string genText(const drogon::HttpViewData &) override;
NotFound(){};
virtual ~NotFound(){};
virtual std::string genText(const drogon::HttpViewData &) override;
};

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

@ -2,7 +2,7 @@
*
* Session.h
* An Tao
*
*
* Copyright 2018, An Tao. All rights reserved.
* https://github.com/an-tao/drogon
* Use of this source code is governed by a MIT license
@ -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:
@ -80,4 +79,4 @@ class Session
typedef std::shared_ptr<Session> SessionPtr;
} // namespace drogon
} // namespace drogon

View File

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

View File

@ -17,14 +17,13 @@
#include <drogon/HttpRequest.h>
#include <drogon/HttpResponse.h>
#include <drogon/WebSocketConnection.h>
#include <trantor/net/EventLoop.h>
#include <string>
#include <functional>
#include <memory>
#include <string>
#include <trantor/net/EventLoop.h>
namespace drogon
{
class WebSocketClient;
typedef std::shared_ptr<WebSocketClient> WebSocketClientPtr;
typedef std::function<void(ReqResult, const HttpResponsePtr &, const WebSocketClientPtr &)> WebSocketRequestCallback;
@ -36,10 +35,14 @@ class WebSocketClient
/// Get the WebSocket connection that is typically used to send messages.
virtual WebSocketConnectionPtr getConnection() = 0;
/// Set messages handler. When a message is recieved from the server, the @param callback is called.
virtual void setMessageHandler(const std::function<void(std::string &&message, const WebSocketClientPtr &, const WebSocketMessageType &)> &callback) = 0;
/// Set messages handler. When a message is recieved from the server, the
/// @param callback is called.
virtual void setMessageHandler(
const std::function<void(std::string &&message, const WebSocketClientPtr &, const WebSocketMessageType &)>
&callback) = 0;
/// Set the connection handler. When the connection is established or closed, the @param callback is called with a bool
/// Set the connection handler. When the connection is established or closed,
/// the @param callback is called with a bool
/// parameter.
virtual void setConnectionClosedHandler(const std::function<void(const WebSocketClientPtr &)> &callback) = 0;
@ -50,14 +53,14 @@ class WebSocketClient
virtual trantor::EventLoop *getLoop() = 0;
/// Use ip and port to connect to server
/**
* If useSSL is set to true, the client
/**
* If useSSL is set to true, the client
* connects to the server using SSL.
*
* If the loop parameter is set to nullptr, the client
*
* If the loop parameter is set to nullptr, the client
* uses the HttpAppFramework's event loop, otherwise it
* runs in the loop identified by the parameter.
*
*
* Note: The @param ip support for both ipv4 and ipv6 address
*/
static WebSocketClientPtr newWebSocketClient(const std::string &ip,
@ -66,30 +69,31 @@ class WebSocketClient
trantor::EventLoop *loop = nullptr);
/// Use hostString to connect to server
/**
/**
* Examples for hostString:
* wss://www.google.com
* ws://www.google.com
* wss://127.0.0.1:8080/
* ws://127.0.0.1
*
* The @param hostString must be prefixed by 'ws://' or 'wss://'
*
* The @param hostString must be prefixed by 'ws://' or 'wss://'
* and doesn't support for ipv6 address if the host is in ip format
*
* If the @param loop is set to nullptr, the client
*
* If the @param loop is set to nullptr, the client
* uses the HttpAppFramework's main event loop, otherwise it
* runs in the loop identified by the parameter.
*
*
* NOTE:
* Don't add path and parameters in hostString, the request path
* and parameters should be set in HttpRequestPtr when calling
* Don't add path and parameters in hostString, the request path
* and parameters should be set in HttpRequestPtr when calling
* 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
} // namespace drogon

View File

@ -2,7 +2,7 @@
*
* WebSocketConnection.h
* An Tao
*
*
* Copyright 2018, An Tao. All rights reserved.
* https://github.com/an-tao/drogon
* Use of this source code is governed by a MIT license
@ -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,
@ -46,8 +45,8 @@ class WebSocketConnection
virtual bool connected() const = 0;
virtual bool disconnected() const = 0;
virtual void shutdown() = 0; //close write
virtual void forceClose() = 0; //close
virtual void shutdown() = 0; // close write
virtual void forceClose() = 0; // close
virtual void setContext(const any &context) = 0;
virtual const any &getContext() const = 0;
@ -56,9 +55,10 @@ 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;
};
typedef std::shared_ptr<WebSocketConnection> WebSocketConnectionPtr;
} // namespace drogon
} // namespace drogon

View File

@ -2,7 +2,7 @@
*
* WebSocketController.h
* An Tao
*
*
* Copyright 2018, An Tao. All rights reserved.
* https://github.com/an-tao/drogon
* Use of this source code is governed by a MIT license
@ -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;
// This function is called when a new message is received
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;
// This function is called after a new connection of WebSocket is established.
virtual void handleNewConnection(const HttpRequestPtr &, const WebSocketConnectionPtr &) = 0;
//This function is called after a WebSocket connection is closed
// 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
@ -101,4 +102,4 @@ class WebSocketController : public DrObject<T>, public WebSocketControllerBase
template <typename T, bool AutoCreation>
typename WebSocketController<T, AutoCreation>::pathRegister WebSocketController<T, AutoCreation>::_register;
} // namespace drogon
} // namespace drogon

View File

@ -2,7 +2,7 @@
*
* drogon.h
* An Tao
*
*
* Copyright 2018, An Tao. All rights reserved.
* https://github.com/an-tao/drogon
* Use of this source code is governed by a MIT license
@ -16,14 +16,14 @@
#include <drogon/config.h>
#include <trantor/utils/Logger.h>
#include <trantor/net/EventLoop.h>
#include <trantor/utils/Date.h>
#include <trantor/net/InetAddress.h>
#include <trantor/utils/Date.h>
#include <trantor/utils/Logger.h>
#include <drogon/CacheMap.h>
#include <drogon/HttpAppFramework.h>
#include <drogon/HttpClient.h>
#include <drogon/HttpController.h>
#include <drogon/HttpSimpleController.h>
#include <drogon/CacheMap.h>
#include <drogon/HttpClient.h>
#include <drogon/utils/Utilities.h>

View File

@ -1,7 +1,7 @@
/**
* Plugin.h
* An Tao
*
*
* Copyright 2018, An Tao. All rights reserved.
* https://github.com/an-tao/drogon
* Use of this source code is governed by a MIT license
@ -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()
@ -53,7 +55,7 @@ class PluginBase : public virtual DrObjectBase, public trantor::NonCopyable
}
else if (_stat == PluginState::Initialized)
{
//Do nothing;
// Do nothing;
}
else
{
@ -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
} // namespace drogon

View File

@ -18,17 +18,22 @@ 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));
};
} // namespace internal
} // namespace drogon
} // namespace internal
} // namespace drogon

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

@ -16,10 +16,10 @@
#include <drogon/DrObject.h>
#include <drogon/utils/ClassTraits.h>
#include <functional>
#include <memory>
#include <tuple>
#include <type_traits>
#include <memory>
#include <functional>
namespace drogon
{
@ -30,14 +30,12 @@ typedef std::shared_ptr<HttpResponse> HttpResponsePtr;
namespace internal
{
template <typename>
struct FunctionTraits;
//functor,lambda,std::function...
// 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;
@ -48,63 +46,61 @@ struct FunctionTraits : public FunctionTraits<
}
};
//class instance method of const object
template <typename ClassType,
typename ReturnType,
typename... Arguments>
// class instance method of const object
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>
// class instance method of non-const object
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>
// normal function for HTTP handling
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...)>
// normal function
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
} // namespace drogon
} // namespace internal
} // namespace drogon

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

@ -15,16 +15,15 @@
#pragma once
#include <drogon/config.h>
#include <trantor/utils/Date.h>
#include <string>
#include <vector>
#include <memory>
#include <string>
#include <trantor/utils/Date.h>
#include <vector>
namespace drogon
{
namespace utils
{
/// Determine if the string is an integer
bool isInteger(const std::string &str);
@ -92,5 +91,5 @@ std::string formattedString(const char *format, ...);
*/
int createPath(const std::string &path);
} // namespace utils
} // namespace drogon
} // namespace utils
} // namespace drogon

View File

@ -3,21 +3,19 @@
namespace drogon
{
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::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)
{
if (index < advices.size())
{
auto &advice = advices[index];
advice(req,
[callbackPtr](const HttpResponsePtr &resp) { (*callbackPtr)(resp); },
[index, req, callbackPtr, &advices, missCallback = std::move(missCallback)]() mutable {
[ index, req, callbackPtr, &advices, missCallback = std::move(missCallback) ]() mutable {
doAdvicesChain(advices, index + 1, req, callbackPtr, std::move(missCallback));
});
}
@ -27,20 +25,19 @@ void doAdvicesChain(const std::vector<std::function<void(const HttpRequestPtr &,
}
}
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,
std::function<void()> &&missCallback)
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,
std::function<void()> &&missCallback)
{
if (index < advices.size())
{
auto &advice = advices[index];
advice(req,
[callbackPtr](const HttpResponsePtr &resp) { (*callbackPtr)(resp); },
[index, req, callbackPtr, &advices, missCallback = std::move(missCallback)]() mutable {
[ index, req, callbackPtr, &advices, missCallback = std::move(missCallback) ]() mutable {
doAdvicesChain(advices, index + 1, req, callbackPtr, std::move(missCallback));
});
}
@ -50,4 +47,4 @@ void doAdvicesChain(const std::deque<std::function<void(const HttpRequestPtr &,
}
}
} // namespace drogon
} // namespace drogon

View File

@ -2,7 +2,7 @@
*
* AOPAdvice.h
* An Tao
*
*
* Copyright 2018, An Tao. All rights reserved.
* https://github.com/an-tao/drogon
* Use of this source code is governed by a MIT license
@ -18,18 +18,16 @@
namespace drogon
{
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,
size_t index,
const HttpRequestImplPtr &req,
const std::shared_ptr<const std::function<void(const HttpResponsePtr &)>> &callbackPtr,
std::function<void()> &&missCallback);
} // namespace drogon
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,
size_t index,
const HttpRequestImplPtr &req,
const std::shared_ptr<const std::function<void(const HttpResponsePtr &)>> &callbackPtr,
std::function<void()> &&missCallback);
} // namespace drogon

View File

@ -2,7 +2,7 @@
*
* ConfigLoader.cc
* An Tao
*
*
* Copyright 2018, An Tao. All rights reserved.
* https://github.com/an-tao/drogon
* Use of this source code is governed by a MIT license
@ -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)
@ -35,43 +35,43 @@ static bool bytesSize(std::string &sizeStr, size_t &size)
size = 1;
switch (sizeStr[sizeStr.length() - 1])
{
case 'k':
case 'K':
size = 1024;
sizeStr.resize(sizeStr.length() - 1);
break;
case 'M':
case 'm':
size = (1024 * 1024);
sizeStr.resize(sizeStr.length() - 1);
break;
case 'g':
case 'G':
size = (1024 * 1024 * 1024);
sizeStr.resize(sizeStr.length() - 1);
break;
case 'k':
case 'K':
size = 1024;
sizeStr.resize(sizeStr.length() - 1);
break;
case 'M':
case 'm':
size = (1024 * 1024);
sizeStr.resize(sizeStr.length() - 1);
break;
case 'g':
case 'G':
size = (1024 * 1024 * 1024);
sizeStr.resize(sizeStr.length() - 1);
break;
#if ((ULONG_MAX) != (UINT_MAX))
//64bit system
case 't':
case 'T':
size = (1024L * 1024L * 1024L * 1024L);
sizeStr.resize(sizeStr.length() - 1);
break;
// 64bit system
case 't':
case 'T':
size = (1024L * 1024L * 1024L * 1024L);
sizeStr.resize(sizeStr.length() - 1);
break;
#endif
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '7':
case '8':
case '9':
break;
default:
std::cerr << "Invalid value of client_max_body_size: " << sizeStr << std::endl;
return false;
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '7':
case '8':
case '9':
break;
default:
std::cerr << "Invalid value of client_max_body_size: " << sizeStr << std::endl;
return false;
break;
}
std::istringstream iss(sizeStr);
size_t tmpSize;
@ -175,7 +175,7 @@ static void loadControllers(const Json::Value &controllers)
{
constraints.push_back(Post);
}
else if (strMethod == "head") //The branch nerver work
else if (strMethod == "head") // The branch nerver work
{
constraints.push_back(Head);
}
@ -203,34 +203,34 @@ static void loadApp(const Json::Value &app)
{
if (!app)
return;
//threads number
// threads number
auto threadsNum = app.get("threads_num", 1).asUInt64();
if (threadsNum == 0)
{
//set the number to the number of processors.
// set the number to the number of processors.
threadsNum = std::thread::hardware_concurrency();
LOG_DEBUG << "The number of processors is " << threadsNum;
}
if (threadsNum < 1)
threadsNum = 1;
drogon::app().setThreadNum(threadsNum);
//session
// session
auto enableSession = app.get("enable_session", false).asBool();
auto timeout = app.get("session_timeout", 0).asUInt64();
if (enableSession)
drogon::app().enableSession(timeout);
else
drogon::app().disableSession();
//document root
// document root
auto documentRoot = app.get("document_root", "").asString();
if (documentRoot != "")
{
drogon::app().setDocumentRoot(documentRoot);
}
//upload path
// upload path
auto uploadPath = app.get("upload_path", "uploads").asString();
drogon::app().setUploadPath(uploadPath);
//file types
// file types
auto fileTypes = app["file_types"];
if (fileTypes.isArray() && !fileTypes.empty())
{
@ -242,20 +242,20 @@ static void loadApp(const Json::Value &app)
}
drogon::app().setFileTypes(types);
}
//max connections
// max connections
auto maxConns = app.get("max_connections", 0).asUInt64();
if (maxConns > 0)
{
drogon::app().setMaxConnectionNum(maxConns);
}
//max connections per IP
// max connections per IP
auto maxConnsPerIP = app.get("max_connections_per_ip", 0).asUInt64();
if (maxConnsPerIP > 0)
{
drogon::app().setMaxConnectionNumPerIP(maxConnsPerIP);
}
//dynamic views
// dynamic views
auto enableDynamicViews = app.get("load_dynamic_views", false).asBool();
if (enableDynamicViews)
{
@ -271,15 +271,15 @@ static void loadApp(const Json::Value &app)
drogon::app().enableDynamicViewsLoading(paths);
}
}
//log
// log
loadLogSetting(app["log"]);
//run as daemon
// run as daemon
auto runAsDaemon = app.get("run_as_daemon", false).asBool();
if (runAsDaemon)
{
drogon::app().enableRunAsDaemon();
}
//relaunch
// relaunch
auto relaunch = app.get("relaunch_on_error", false).asBool();
if (relaunch)
{
@ -292,7 +292,7 @@ static void loadApp(const Json::Value &app)
auto staticFilesCacheTime = app.get("static_files_cache_time", 5).asInt();
drogon::app().setStaticFilesCacheTime(staticFilesCacheTime);
loadControllers(app["simple_controllers_map"]);
//Kick off idle connections
// Kick off idle connections
auto kickOffTimeout = app.get("idle_connection_timeout", 60).asUInt64();
drogon::app().setIdleConnectionTimeout(kickOffTimeout);
auto server = app.get("server_header_field", "").asString();
@ -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
}
@ -380,7 +382,7 @@ static void loadSSL(const Json::Value &sslFiles)
}
void ConfigLoader::load()
{
//std::cout<<_configJsonRoot<<std::endl;
// std::cout<<_configJsonRoot<<std::endl;
loadApp(_configJsonRoot["app"]);
loadSSL(_configJsonRoot["ssl"]);
loadListeners(_configJsonRoot["listeners"]);

View File

@ -2,7 +2,7 @@
*
* ConfigLoader.h
* An Tao
*
*
* Copyright 2018, An Tao. All rights reserved.
* https://github.com/an-tao/drogon
* Use of this source code is governed by a MIT license
@ -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,11 +25,14 @@ 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:
std::string _configFile;
Json::Value _configJsonRoot;
};
} // namespace drogon
} // namespace drogon

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

@ -2,7 +2,7 @@
*
* Cookie.cc
* An Tao
*
*
* Copyright 2018, An Tao. All rights reserved.
* https://github.com/an-tao/drogon
* Use of this source code is governed by a MIT license
@ -39,7 +39,7 @@ std::string Cookie::cookieString() const
{
ret.append("HttpOnly; ");
}
ret.resize(ret.length() - 2); //delete last semicolon
ret.resize(ret.length() - 2); // delete last semicolon
ret.append("\r\n");
return ret;
}

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

@ -2,7 +2,7 @@
*
* DrClassMap.cc
* An Tao
*
*
* Copyright 2018, An Tao. All rights reserved.
* https://github.com/an-tao/drogon
* Use of this source code is governed by a MIT license
@ -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;
@ -35,8 +34,8 @@ static std::mutex &getMapMutex()
return mtx;
}
} // namespace internal
} // namespace drogon
} // namespace internal
} // namespace drogon
void DrClassMap::registerClass(const std::string &className, const DrAllocFunc &func)
{

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

@ -2,7 +2,7 @@
*
* DrTemplateBase.cc
* An Tao
*
*
* Copyright 2018, An Tao. All rights reserved.
* https://github.com/an-tao/drogon
* Use of this source code is governed by a MIT license
@ -12,10 +12,10 @@
*
*/
#include <drogon/DrTemplateBase.h>
#include <drogon/DrClassMap.h>
#include <trantor/utils/Logger.h>
#include <drogon/DrTemplateBase.h>
#include <memory>
#include <trantor/utils/Logger.h>
using namespace drogon;

View File

@ -2,7 +2,7 @@
*
* FiltersFunction.cc
* An Tao
*
*
* Copyright 2018, An Tao. All rights reserved.
* https://github.com/an-tao/drogon
* Use of this source code is governed by a MIT license
@ -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,15 +33,16 @@ static void doFilterChains(const std::vector<std::shared_ptr<HttpFilterBase>> &f
if (index < filters.size())
{
auto &filter = filters[index];
filter->doFilter(req,
[needSetJsessionid, callbackPtr, sessionIdPtr](const HttpResponsePtr &res) {
if (needSetJsessionid && res->statusCode() != k404NotFound)
res->addCookie("JSESSIONID", *sessionIdPtr);
(*callbackPtr)(res);
},
[=, &filters, missCallback = std::move(missCallback)]() mutable {
doFilterChains(filters, index + 1, req, callbackPtr, needSetJsessionid, sessionIdPtr, std::move(missCallback));
});
filter->doFilter(
req,
[needSetJsessionid, callbackPtr, sessionIdPtr](const HttpResponsePtr &res) {
if (needSetJsessionid && res->statusCode() != k404NotFound)
res->addCookie("JSESSIONID", *sessionIdPtr);
(*callbackPtr)(res);
},
[ =, &filters, missCallback = std::move(missCallback) ]() mutable {
doFilterChains(filters, index + 1, req, callbackPtr, needSetJsessionid, sessionIdPtr, std::move(missCallback));
});
}
else
{
@ -74,9 +74,8 @@ 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));
}
} // namespace FiltersFunction
} // namespace drogon
} // namespace FiltersFunction
} // namespace drogon

View File

@ -2,7 +2,7 @@
*
* FiltersFunction.h
* An Tao
*
*
* Copyright 2018, An Tao. All rights reserved.
* https://github.com/an-tao/drogon
* Use of this source code is governed by a MIT license
@ -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,
@ -33,5 +32,5 @@ void doFilters(const std::vector<std::shared_ptr<HttpFilterBase>> &filters,
const std::shared_ptr<std::string> &sessionIdPtr,
std::function<void()> &&missCallback);
} // namespace FiltersFunction
} // namespace drogon
} // namespace FiltersFunction
} // namespace drogon

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

@ -2,7 +2,7 @@
*
* HttpAppFrameworkImpl.cc
* An Tao
*
*
* Copyright 2018, An Tao. All rights reserved.
* https://github.com/an-tao/drogon
* Use of this source code is governed by a MIT license
@ -13,51 +13,49 @@
*/
#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.
/// 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:
public:
DrogonFileLocker()
{
_fd = open("/tmp/drogon.lock", O_TRUNC | O_CREAT, 0755);
@ -68,11 +66,11 @@ public:
close(_fd);
}
private:
private:
int _fd = 0;
};
} // namespace drogon
} // namespace drogon
static void godaemon(void)
{
printf("Initializing daemon mode\n");
@ -82,7 +80,7 @@ static void godaemon(void)
pid_t pid;
pid = fork();
if (pid > 0)
exit(0); // parent
exit(0); // parent
if (pid < 0)
{
perror("fork");
@ -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;
@ -238,14 +232,14 @@ void HttpAppFrameworkImpl::run()
if (_runAsDaemon)
{
//go daemon!
// go daemon!
godaemon();
#ifdef __linux__
getLoop()->resetTimerQueue();
#endif
getLoop()->resetAfterFork();
}
//set relaunching
// set relaunching
if (_relaunchOnError)
{
while (true)
@ -259,7 +253,7 @@ void HttpAppFrameworkImpl::run()
}
else if (child_pid == 0)
{
//child
// child
break;
}
waitpid(child_pid, &child_status, 0);
@ -269,7 +263,7 @@ void HttpAppFrameworkImpl::run()
getLoop()->resetAfterFork();
}
//set logger
// set logger
if (!_logPath.empty())
{
if (access(_logPath.c_str(), R_OK | W_OK) >= 0)
@ -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
@ -294,7 +289,7 @@ void HttpAppFrameworkImpl::run()
{
LOG_INFO << "Start child process";
}
//now start runing!!
// now start runing!!
_running = true;
@ -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,23 +426,25 @@ 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
// Initialize plugins
const auto &pluginConfig = _jsonConfig["plugins"];
if (!pluginConfig.isNull())
{
_pluginsManager.initializeAllPlugins(pluginConfig,
[](PluginBase *plugin) {
//TODO: new plugin
});
_pluginsManager.initializeAllPlugins(pluginConfig, [](PluginBase *plugin) {
// TODO: new plugin
});
}
// Let listener event loops run when everything is ready.
@ -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();
@ -656,17 +650,17 @@ void HttpAppFrameworkImpl::onAsyncRequest(const HttpRequestImplPtr &req, std::fu
transform(filetype.begin(), filetype.end(), filetype.begin(), tolower);
if (_fileTypeSet.find(filetype) != _fileTypeSet.end())
{
//LOG_INFO << "file query!" << path;
// LOG_INFO << "file query!" << path;
std::string filePath = _rootPath + path;
if (filePath.find("/../") != std::string::npos)
{
//Downloading files from the parent folder is forbidden.
// Downloading files from the parent folder is forbidden.
auto resp = HttpResponse::newHttpResponse();
resp->setStatusCode(k403Forbidden);
callback(resp);
return;
}
//find cached response
// find cached response
HttpResponsePtr cachedResp;
{
std::lock_guard<std::mutex> guard(_staticFilesCacheMutex);
@ -680,15 +674,16 @@ void HttpAppFrameworkImpl::onAsyncRequest(const HttpRequestImplPtr &req, std::fu
}
}
//check last modified time,rfc2616-14.25
//If-Modified-Since: Mon, 15 Oct 2018 06:26:33 GMT
// check last modified time,rfc2616-14.25
// If-Modified-Since: Mon, 15 Oct 2018 06:26:33 GMT
std::string timeStr;
if (_enableLastModify)
{
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);
@ -733,8 +728,9 @@ 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));
// make a copy
auto newCachedResp =
std::make_shared<HttpResponseImpl>(*std::dynamic_pointer_cast<HttpResponseImpl>(cachedResp));
newCachedResp->addCookie("JSESSIONID", sessionId);
newCachedResp->setExpiredTime(-1);
callback(newCachedResp);
@ -746,7 +742,7 @@ void HttpAppFrameworkImpl::onAsyncRequest(const HttpRequestImplPtr &req, std::fu
HttpResponsePtr resp;
if (_gzipStaticFlag && req->getHeaderBy("accept-encoding").find("gzip") != std::string::npos)
{
//Find compressed file first.
// Find compressed file first.
auto gzipFileName = filePath + ".gz";
std::ifstream infile(gzipFileName, std::ifstream::binary);
if (infile)
@ -764,7 +760,7 @@ void HttpAppFrameworkImpl::onAsyncRequest(const HttpRequestImplPtr &req, std::fu
resp->addHeader("Last-Modified", timeStr);
resp->addHeader("Expires", "Thu, 01 Jan 1970 00:00:00 GMT");
}
//cache the response for 5 seconds by default
// cache the response for 5 seconds by default
if (_staticFilesCacheTime >= 0)
{
resp->setExpiredTime(_staticFilesCacheTime);
@ -783,7 +779,7 @@ void HttpAppFrameworkImpl::onAsyncRequest(const HttpRequestImplPtr &req, std::fu
auto newCachedResp = resp;
if (resp->expiredTime() >= 0)
{
//make a copy
// make a copy
newCachedResp = std::make_shared<HttpResponseImpl>(*std::dynamic_pointer_cast<HttpResponseImpl>(resp));
newCachedResp->setExpiredTime(-1);
}
@ -797,7 +793,7 @@ void HttpAppFrameworkImpl::onAsyncRequest(const HttpRequestImplPtr &req, std::fu
}
}
//Route to controller
// Route to controller
if (!_preRoutingObservers.empty())
{
for (auto &observer : _preRoutingObservers)
@ -816,17 +812,19 @@ 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) {
if (!needSetJsessionid || resp->statusCode() == k404NotFound)
(*callbackPtr)(resp);
else
{
resp->addCookie("JSESSIONID", *sessionIdPtr);
(*callbackPtr)(resp);
}
}),
std::make_shared<std::function<void(const HttpResponsePtr &)>>(
[callbackPtr, needSetJsessionid, sessionIdPtr](const HttpResponsePtr &resp) {
if (!needSetJsessionid || resp->statusCode() == k404NotFound)
(*callbackPtr)(resp);
else
{
resp->addCookie("JSESSIONID", *sessionIdPtr);
(*callbackPtr)(resp);
}
}),
[this, callbackPtr, req, needSetJsessionid, sessionIdPtr]() {
_httpSimpleCtrlsRouter.route(req, std::move(*callbackPtr), needSetJsessionid, std::move(*sessionIdPtr));
_httpSimpleCtrlsRouter.route(
req, std::move(*callbackPtr), needSetJsessionid, std::move(*sessionIdPtr));
});
}
}
@ -854,8 +852,7 @@ orm::DbClientPtr HttpAppFrameworkImpl::getDbClient(const std::string &name)
}
orm::DbClientPtr HttpAppFrameworkImpl::getFastDbClient(const std::string &name)
{
assert(_dbFastClientsMap[name].find(trantor::EventLoop::getEventLoopOfCurrentThread()) !=
_dbFastClientsMap[name].end());
assert(_dbFastClientsMap[name].find(trantor::EventLoop::getEventLoopOfCurrentThread()) != _dbFastClientsMap[name].end());
return _dbFastClientsMap[name][trantor::EventLoop::getEventLoopOfCurrentThread()];
}
void HttpAppFrameworkImpl::createDbClient(const std::string &dbType,
@ -870,7 +867,8 @@ void HttpAppFrameworkImpl::createDbClient(const std::string &dbType,
const bool isFast)
{
assert(!_running);
auto connStr = utils::formattedString("host=%s port=%u dbname=%s user=%s", host.c_str(), port, databaseName.c_str(), userName.c_str());
auto connStr =
utils::formattedString("host=%s port=%u dbname=%s user=%s", host.c_str(), port, databaseName.c_str(), userName.c_str());
if (!password.empty())
{
connStr += " password=";
@ -890,7 +888,9 @@ void HttpAppFrameworkImpl::createDbClient(const std::string &dbType,
info._dbType = orm::ClientType::PostgreSQL;
_dbInfos.push_back(info);
#else
std::cout << "The PostgreSQL is not supported by drogon, please install the development library first." << std::endl;
std::cout << "The PostgreSQL is not supported by drogon, please install "
"the development library first."
<< std::endl;
exit(1);
#endif
}
@ -900,7 +900,9 @@ void HttpAppFrameworkImpl::createDbClient(const std::string &dbType,
info._dbType = orm::ClientType::Mysql;
_dbInfos.push_back(info);
#else
std::cout << "The Mysql is not supported by drogon, please install the development library first." << std::endl;
std::cout << "The Mysql is not supported by drogon, please install the "
"development library first."
<< std::endl;
exit(1);
#endif
}
@ -912,14 +914,18 @@ void HttpAppFrameworkImpl::createDbClient(const std::string &dbType,
info._dbType = orm::ClientType::Sqlite3;
_dbInfos.push_back(info);
#else
std::cout << "The Sqlite3 is not supported by drogon, please install the development library first." << std::endl;
std::cout << "The Sqlite3 is not supported by drogon, please install the "
"development library first."
<< std::endl;
exit(1);
#endif
}
}
#endif
void HttpAppFrameworkImpl::forward(const HttpRequestImplPtr &req, std::function<void(const HttpResponsePtr &)> &&callback, const std::string &hostString)
void HttpAppFrameworkImpl::forward(const HttpRequestImplPtr &req,
std::function<void(const HttpResponsePtr &)> &&callback,
const std::string &hostString)
{
if (hostString.empty())
{
@ -940,7 +946,9 @@ void HttpAppFrameworkImpl::forward(const HttpRequestImplPtr &req, std::function<
}
else
{
clientPtr = std::make_shared<HttpClientImpl>(trantor::EventLoop::getEventLoopOfCurrentThread() ? trantor::EventLoop::getEventLoopOfCurrentThread() : getLoop(),
clientPtr = std::make_shared<HttpClientImpl>(trantor::EventLoop::getEventLoopOfCurrentThread()
? trantor::EventLoop::getEventLoopOfCurrentThread()
: getLoop(),
hostString);
clientsMap[hostString] = clientPtr;
}

View File

@ -2,7 +2,7 @@
*
* HttpAppFrameworkImpl.h
* An Tao
*
*
* Copyright 2018, An Tao. All rights reserved.
* https://github.com/an-tao/drogon
* Use of this source code is governed by a MIT license
@ -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
{
@ -47,10 +47,19 @@ struct InitBeforeMainFunction
};
class HttpAppFrameworkImpl : public HttpAppFramework
{
public:
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,46 +166,118 @@ 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
{
//Destroy the following objects before _loop destruction
// Destroy the following objects before _loop destruction
_sharedLibManagerPtr.reset();
_sessionMapPtr.reset();
}
@ -243,9 +327,12 @@ public:
static HttpAppFrameworkImpl _instance;
return _instance;
}
bool useSendfile() { return _useSendfile; }
bool useSendfile()
{
return _useSendfile;
}
private:
private:
virtual void registerHttpController(const std::string &pathPattern,
const internal::HttpBinderBasePtr &binder,
const std::vector<HttpMethod> &validMethods = std::vector<HttpMethod>(),
@ -261,8 +348,9 @@ private:
const std::vector<HttpMethod> &validMethods,
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;
// We use a uuid string as session id;
// 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;
@ -316,7 +420,7 @@ private:
int _staticFilesCacheTime = 5;
std::unordered_map<std::string, std::weak_ptr<HttpResponse>> _staticFilesCache;
std::mutex _staticFilesCacheMutex;
//Json::Value _customConfig;
// Json::Value _customConfig;
Json::Value _jsonConfig;
PluginsManager _pluginsManager;
HttpResponsePtr _custom404;
@ -336,25 +440,14 @@ 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;
std::vector<std::function<void(const HttpRequestPtr &)>> _preHandlingObservers;
};
} // namespace drogon
} // namespace drogon

View File

@ -2,7 +2,7 @@
*
* HttpClientImpl.cc
* An Tao
*
*
* Copyright 2018, An Tao. All rights reserved.
* https://github.com/an-tao/drogon
* Use of this source code is governed by a MIT license
@ -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);
@ -54,7 +48,7 @@ HttpClientImpl::HttpClientImpl(trantor::EventLoop *loop,
auto pos = lowerHost.find("]");
if (lowerHost[0] == '[' && pos != std::string::npos)
{
//ipv6
// ipv6
_domain = lowerHost.substr(1, pos - 1);
if (lowerHost[pos + 1] == ':')
{
@ -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
// 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)
@ -209,7 +194,7 @@ void HttpClientImpl::sendRequestInLoop(const drogon::HttpRequestPtr &req,
if (connPtr->connected())
{
connPtr->setContext(HttpResponseParser(connPtr));
//send request;
// send request;
LOG_TRACE << "Connection established!";
while (thisPtr->_pipeliningCallbacks.size() <= thisPtr->_pipeliningDepth &&
!thisPtr->_requestsBuffer.empty())
@ -229,7 +214,7 @@ void HttpClientImpl::sendRequestInLoop(const drogon::HttpRequestPtr &req,
auto thisPtr = weakPtr.lock();
if (!thisPtr)
return;
//can't connect to server
// can't connect to server
thisPtr->onError(ReqResult::BadServerAddress);
});
_tcpClient->setMessageCallback([weakPtr](const trantor::TcpConnectionPtr &connPtr, trantor::MsgBuffer *msg) {
@ -243,14 +228,13 @@ void HttpClientImpl::sendRequestInLoop(const drogon::HttpRequestPtr &req,
}
else
{
callback(ReqResult::BadServerAddress,
HttpResponse::newHttpResponse());
callback(ReqResult::BadServerAddress, HttpResponse::newHttpResponse());
return;
}
}
else
{
//send request;
// send request;
auto connPtr = _tcpClient->connection();
auto thisPtr = shared_from_this();
if (connPtr && connPtr->connected())
@ -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);
@ -293,7 +274,7 @@ void HttpClientImpl::onRecvMessage(const trantor::TcpConnectionPtr &connPtr, tra
{
HttpResponseParser *responseParser = any_cast<HttpResponseParser>(connPtr->getMutableContext());
//LOG_TRACE << "###:" << msg->readableBytes();
// LOG_TRACE << "###:" << msg->readableBytes();
while (msg->readableBytes() > 0)
{
if (!responseParser->parseResponse(msg))
@ -348,7 +329,8 @@ void HttpClientImpl::onRecvMessage(const trantor::TcpConnectionPtr &connPtr, tra
HttpClientPtr HttpClient::newHttpClient(const std::string &ip, uint16_t port, bool useSSL, trantor::EventLoop *loop)
{
bool isIpv6 = ip.find(":") == std::string::npos ? false : true;
return std::make_shared<HttpClientImpl>(loop == nullptr ? app().getLoop() : loop, trantor::InetAddress(ip, port, isIpv6), useSSL);
return std::make_shared<HttpClientImpl>(
loop == nullptr ? app().getLoop() : loop, trantor::InetAddress(ip, port, isIpv6), useSSL);
}
HttpClientPtr HttpClient::newHttpClient(const std::string &hostString, trantor::EventLoop *loop)

View File

@ -2,7 +2,7 @@
*
* HttpClientImpl.h
* An Tao
*
*
* Copyright 2018, An Tao. All rights reserved.
* https://github.com/an-tao/drogon
* Use of this source code is governed by a MIT license
@ -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;
@ -51,4 +54,4 @@ class HttpClientImpl : public HttpClient, public std::enable_shared_from_this<Ht
size_t _pipeliningDepth = 0;
};
typedef std::shared_ptr<HttpClientImpl> HttpClientImplPtr;
} // namespace drogon
} // namespace drogon

View File

@ -2,7 +2,7 @@
*
* HttpControllersRouter.cc
* An Tao
*
*
* Copyright 2018, An Tao. All rights reserved.
* https://github.com/an-tao/drogon
* Use of this source code is governed by a MIT license
@ -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());
@ -39,7 +38,7 @@ static void doWhenNoHandlerFound(const HttpRequestImplPtr &req,
callback(resp);
}
} // namespace drogon
} // namespace drogon
void HttpControllersRouter::init(const std::vector<trantor::EventLoop *> &ioLoops)
{
std::string regString;
@ -62,7 +61,7 @@ void HttpControllersRouter::init(const std::vector<trantor::EventLoop *> &ioLoop
}
}
if (regString.length() > 0)
regString.resize(regString.length() - 1); //remove the last '|'
regString.resize(regString.length() - 1); // remove the last '|'
LOG_TRACE << "regex string:" << regString;
_ctrlRegex = std::regex(regString, std::regex_constants::icase);
}
@ -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));
}
}
@ -92,7 +92,7 @@ void HttpControllersRouter::addHttpPath(const std::string &path,
const std::vector<std::string> &filters,
const std::string &handlerName)
{
//Path is like /api/v1/service/method/{1}/{2}/xxx...
// Path is like /api/v1/service/method/{1}/{2}/xxx...
std::vector<size_t> places;
std::string tmpPath = path;
std::string paras = "";
@ -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;
@ -201,7 +200,7 @@ void HttpControllersRouter::route(const HttpRequestImplPtr &req,
bool needSetJsessionid,
std::string &&sessionId)
{
//Find http controller
// Find http controller
if (_ctrlRegex.mark_count() > 0)
{
std::smatch result;
@ -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())
@ -221,7 +221,7 @@ void HttpControllersRouter::route(const HttpRequestImplPtr &req,
auto &binder = routerItem._binders[req->method()];
if (!binder)
{
//Invalid Http Method
// Invalid Http Method
auto res = drogon::HttpResponse::newHttpResponse();
if (req->method() != Options)
{
@ -247,50 +247,69 @@ 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,
callbackPtr,
[&binder, sessionId = std::move(sessionId), callbackPtr, 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));
});
}
else
{
doPreHandlingAdvices(binder, routerItem, req, std::move(*callbackPtr), needSetJsessionid, std::move(sessionId));
}
});
doAdvicesChain(_postRoutingAdvices, 0, req, callbackPtr, [
&binder,
sessionId = std::move(sessionId),
callbackPtr,
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));
});
}
else
{
doPreHandlingAdvices(
binder, routerItem, req, std::move(*callbackPtr), needSetJsessionid, std::move(sessionId));
}
});
}
}
}
}
else
{
//No handler found
// No handler found
doWhenNoHandlerFound(req, std::move(callback));
}
}
else
{
//No handler found
// No handler found
doWhenNoHandlerFound(req, std::move(callback));
}
}
@ -303,18 +322,19 @@ 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!
// use cached response!
LOG_TRACE << "Use cached response";
if (!needSetJsessionid || responsePtr->statusCode() == k404NotFound)
invokeCallback(callback, req, responsePtr);
else
{
//make a copy response;
// make a copy response;
auto newResp = std::make_shared<HttpResponseImpl>(*std::dynamic_pointer_cast<HttpResponseImpl>(responsePtr));
newResp->setExpiredTime(-1); //make it temporary
newResp->setExpiredTime(-1); // make it temporary
newResp->addCookie("JSESSIONID", sessionId);
invokeCallback(callback, req, newResp);
}
@ -339,8 +359,7 @@ void HttpControllersRouter::doControllerHandler(const CtrlBinderPtr &ctrlBinderP
auto qureyPara = req->getParameters();
for (auto const &parameter : qureyPara)
{
if (ctrlBinderPtr->_queryParametersPlaces.find(parameter.first) !=
ctrlBinderPtr->_queryParametersPlaces.end())
if (ctrlBinderPtr->_queryParametersPlaces.find(parameter.first) != ctrlBinderPtr->_queryParametersPlaces.end())
{
auto place = ctrlBinderPtr->_queryParametersPlaces.find(parameter.first)->second;
if (place > params.size())
@ -350,42 +369,41 @@ void HttpControllersRouter::doControllerHandler(const CtrlBinderPtr &ctrlBinderP
}
}
std::list<std::string> paraList;
for (auto &p : params) ///Use reference
for (auto &p : params) /// Use reference
{
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) {
LOG_TRACE << "http resp:needSetJsessionid=" << needSetJsessionid << ";JSESSIONID=" << sessionId;
auto newResp = resp;
if (resp->expiredTime() >= 0)
{
//cache the response;
std::dynamic_pointer_cast<HttpResponseImpl>(resp)->makeHeaderString();
auto loop = req->getLoop();
if (loop->isInLoopThread())
{
ctrlBinderPtr->_responsePtrMap[loop] = resp;
}
else
{
req->getLoop()->queueInLoop([loop, resp, ctrlBinderPtr]() {
ctrlBinderPtr->_responsePtrMap[loop] = resp;
});
}
}
if (needSetJsessionid && resp->statusCode() != k404NotFound)
{
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)
{
//make a copy
newResp = std::make_shared<HttpResponseImpl>(*std::dynamic_pointer_cast<HttpResponseImpl>(resp));
newResp->setExpiredTime(-1); //make it temporary
// cache the response;
std::dynamic_pointer_cast<HttpResponseImpl>(resp)->makeHeaderString();
auto loop = req->getLoop();
if (loop->isInLoopThread())
{
ctrlBinderPtr->_responsePtrMap[loop] = resp;
}
else
{
req->getLoop()->queueInLoop([loop, resp, ctrlBinderPtr]() { ctrlBinderPtr->_responsePtrMap[loop] = resp; });
}
}
newResp->addCookie("JSESSIONID", sessionId);
}
invokeCallback(callback, req, newResp);
});
if (needSetJsessionid && resp->statusCode() != k404NotFound)
{
if (resp->expiredTime() >= 0)
{
// make a copy
newResp = std::make_shared<HttpResponseImpl>(*std::dynamic_pointer_cast<HttpResponseImpl>(resp));
newResp->setExpiredTime(-1); // make it temporary
}
newResp->addCookie("JSESSIONID", sessionId);
}
invokeCallback(callback, req, newResp);
});
return;
}
@ -437,20 +455,23 @@ 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,
0,
req,
std::make_shared<std::function<void(const HttpResponsePtr &)>>([callbackPtr, needSetJsessionid, sessionIdPtr](const HttpResponsePtr &resp) {
if (!needSetJsessionid || resp->statusCode() == k404NotFound)
(*callbackPtr)(resp);
else
{
resp->addCookie("JSESSIONID", *sessionIdPtr);
(*callbackPtr)(resp);
}
}),
[this, ctrlBinderPtr, &routerItem, req, callbackPtr, needSetJsessionid, sessionIdPtr]() {
doControllerHandler(ctrlBinderPtr, routerItem, req, std::move(*callbackPtr), needSetJsessionid, std::move(*sessionIdPtr));
});
doAdvicesChain(
_preHandlingAdvices,
0,
req,
std::make_shared<std::function<void(const HttpResponsePtr &)>>(
[callbackPtr, needSetJsessionid, sessionIdPtr](const HttpResponsePtr &resp) {
if (!needSetJsessionid || resp->statusCode() == k404NotFound)
(*callbackPtr)(resp);
else
{
resp->addCookie("JSESSIONID", *sessionIdPtr);
(*callbackPtr)(resp);
}
}),
[this, ctrlBinderPtr, &routerItem, req, callbackPtr, needSetJsessionid, sessionIdPtr]() {
doControllerHandler(
ctrlBinderPtr, routerItem, req, std::move(*callbackPtr), needSetJsessionid, std::move(*sessionIdPtr));
});
}
}

View File

@ -2,7 +2,7 @@
*
* HttpControllersRouter.h
* An Tao
*
*
* Copyright 2018, An Tao. All rights reserved.
* https://github.com/an-tao/drogon
* Use of this source code is governed by a MIT license
@ -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 &&)>>
&postRoutingAdvices,
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)
public:
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 &&)>>
&preHandlingAdvices,
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),
@ -65,7 +58,7 @@ public:
std::string &&sessionId);
std::vector<std::tuple<std::string, HttpMethod, std::string>> getHandlersInfo() const;
private:
private:
struct CtrlBinder
{
internal::HttpBinderBasePtr _binderPtr;
@ -83,25 +76,19 @@ private:
std::string _pathParameterPattern;
std::string _pathPattern;
std::regex _regex;
CtrlBinderPtr _binders[Invalid] = {nullptr}; //The enum value of Invalid is the http methods number
CtrlBinderPtr _binders[Invalid] = {nullptr}; // The enum value of Invalid is the http methods number
};
std::vector<HttpControllerRouterItem> _ctrlVector;
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,
@ -127,4 +114,4 @@ private:
callback(resp);
}
};
} // namespace drogon
} // namespace drogon

View File

@ -2,7 +2,7 @@
*
* HttpFileUploadRequest.cc
* An Tao
*
*
* Copyright 2018, An Tao. All rights reserved.
* https://github.com/an-tao/drogon
* Use of this source code is governed by a MIT license
@ -18,9 +18,7 @@
using namespace drogon;
HttpFileUploadRequest::HttpFileUploadRequest(const std::vector<UploadFile> &files)
: HttpRequestImpl(nullptr),
_boundary(utils::genRandomString(32)),
_files(files)
: HttpRequestImpl(nullptr), _boundary(utils::genRandomString(32)), _files(files)
{
setMethod(drogon::Post);
setVersion(drogon::HttpRequest::kHttp11);

View File

@ -2,7 +2,7 @@
*
* HttpFileUploadRequest.h
* An Tao
*
*
* Copyright 2018, An Tao. All rights reserved.
* https://github.com/an-tao/drogon
* Use of this source code is governed by a MIT license
@ -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:
@ -32,4 +37,4 @@ class HttpFileUploadRequest : public HttpRequestImpl
std::vector<UploadFile> _files;
};
} // namespace drogon
} // namespace drogon

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

@ -2,7 +2,7 @@
*
* HttpRequestImpl.cc
* An Tao
*
*
* Copyright 2018, An Tao. All rights reserved.
* https://github.com/an-tao/drogon
* Use of this source code is governed by a MIT license
@ -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())
{
@ -75,7 +75,7 @@ void HttpRequestImpl::parseParameters() const
}
if (type.find("application/json") != std::string::npos)
{
//parse json data in request
// parse json data in request
_jsonPtr = std::make_shared<Json::Value>();
Json::CharReaderBuilder builder;
builder["collectComments"] = false;
@ -98,26 +98,26 @@ void HttpRequestImpl::appendToBuffer(MsgBuffer *output) const
{
switch (_method)
{
case Get:
output->append("GET ");
break;
case Post:
output->append("POST ");
break;
case Head:
output->append("HEAD ");
break;
case Put:
output->append("PUT ");
break;
case Delete:
output->append("DELETE ");
break;
case Options:
output->append("OPTIONS ");
break;
default:
return;
case Get:
output->append("GET ");
break;
case Post:
output->append("POST ");
break;
case Head:
output->append("HEAD ");
break;
case Put:
output->append("PUT ");
break;
case Delete:
output->append("DELETE ");
break;
case Options:
output->append("OPTIONS ");
break;
default:
return;
}
if (!_path.empty())
@ -153,7 +153,6 @@ void HttpRequestImpl::appendToBuffer(MsgBuffer *output) const
}
else
{
output->append("?");
}
output->append(content);
@ -161,9 +160,12 @@ 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";
/// 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";
content.clear();
}
}
@ -217,7 +219,7 @@ void HttpRequestImpl::appendToBuffer(MsgBuffer *output) const
{
std::streambuf *pbuf = infile.rdbuf();
std::streamsize filesize = pbuf->pubseekoff(0, infile.end);
pbuf->pubseekoff(0, infile.beg); // rewind
pbuf->pubseekoff(0, infile.beg); // rewind
std::string str;
str.resize(filesize);
pbuf->sgetn(&str[0], filesize);
@ -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())
{
@ -263,7 +266,7 @@ void HttpRequestImpl::appendToBuffer(MsgBuffer *output) const
output->append(it->second);
output->append(";");
}
output->unwrite(1); //delete last ';'
output->unwrite(1); // delete last ';'
output->append("\r\n");
}
@ -277,7 +280,7 @@ void HttpRequestImpl::appendToBuffer(MsgBuffer *output) const
void HttpRequestImpl::addHeader(const char *start, const char *colon, const char *end)
{
std::string field(start, colon);
//Field name is case-insensitive.so we transform it to lower;(rfc2616-4.2)
// Field name is case-insensitive.so we transform it to lower;(rfc2616-4.2)
std::transform(field.begin(), field.end(), field.begin(), ::tolower);
++colon;
while (colon < end && isspace(*colon))

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

@ -2,7 +2,7 @@
*
* HttpRequestImpl.h
* An Tao
*
*
* Copyright 2018, An Tao. All rights reserved.
* https://github.com/an-tao/drogon
* Use of this source code is governed by a MIT license
@ -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:
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,62 +64,61 @@ public:
bool setMethod(const char *start, const char *end)
{
assert(_method == Invalid);
string_view m(start, end - start);
switch (m.length())
{
case 3:
if (m == "GET")
{
_method = Get;
}
else if (m == "PUT")
{
_method = Put;
}
else
{
case 3:
if (m == "GET")
{
_method = Get;
}
else if (m == "PUT")
{
_method = Put;
}
else
{
_method = Invalid;
}
break;
case 4:
if (m == "POST")
{
_method = Post;
}
else if (m == "HEAD")
{
_method = Head;
}
else
{
_method = Invalid;
}
break;
case 6:
if (m == "DELETE")
{
_method = Delete;
}
else
{
_method = Invalid;
}
break;
case 7:
if (m == "OPTIONS")
{
_method = Options;
}
else
{
_method = Invalid;
}
break;
default:
_method = Invalid;
}
break;
case 4:
if (m == "POST")
{
_method = Post;
}
else if (m == "HEAD")
{
_method = Head;
}
else
{
_method = Invalid;
}
break;
case 6:
if (m == "DELETE")
{
_method = Delete;
}
else
{
_method = Invalid;
}
break;
case 7:
if (m == "OPTIONS")
{
_method = Options;
}
else
{
_method = Invalid;
}
break;
default:
_method = Invalid;
break;
break;
}
// if (_method != Invalid)
@ -156,26 +153,26 @@ public:
const char *result = "UNKNOWN";
switch (_method)
{
case Get:
result = "GET";
break;
case Post:
result = "POST";
break;
case Head:
result = "HEAD";
break;
case Put:
result = "PUT";
break;
case Delete:
result = "DELETE";
break;
case Options:
result = "OPTIONS";
break;
default:
break;
case Get:
result = "GET";
break;
case Post:
result = "POST";
break;
case Head:
result = "HEAD";
break;
case Put:
result = "PUT";
break;
case Delete:
result = "DELETE";
break;
case Options:
result = "OPTIONS";
break;
default:
break;
}
return result;
}
@ -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));
@ -407,7 +406,7 @@ public:
_matchedPathPattern = pathPattern;
}
protected:
protected:
friend class HttpRequest;
void setContentType(const std::string &contentType)
{
@ -418,11 +417,12 @@ protected:
_contentTypeString = std::move(contentType);
}
private:
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;
@ -444,7 +444,7 @@ private:
trantor::InetAddress _local;
trantor::Date _date;
protected:
protected:
std::string _content;
size_t _contentLen;
trantor::EventLoop *_loop;
@ -454,4 +454,4 @@ protected:
typedef std::shared_ptr<HttpRequestImpl> HttpRequestImplPtr;
} // namespace drogon
} // namespace drogon

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

@ -2,7 +2,7 @@
*
* HttpRequestParser.cc
* An Tao
*
*
* Copyright 2018, An Tao. All rights reserved.
* https://github.com/an-tao/drogon
* Use of this source code is governed by a MIT license
@ -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)
{
@ -177,7 +177,7 @@ bool HttpRequestParser::parseRequest(MsgBuffer *buf)
shutdownConnection(k400BadRequest);
return false;
}
//rfc2616-8.2.3
// rfc2616-8.2.3
auto connPtr = _conn.lock();
if (connPtr)
{
@ -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();

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

@ -2,7 +2,7 @@
*
* HttpRequestParser.h
* An Tao
*
*
* Copyright 2018, An Tao. All rights reserved.
* https://github.com/an-tao/drogon
* Use of this source code is governed by a MIT license
@ -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
@ -80,16 +80,28 @@ class HttpRequestParser
{
_websockConnPtr = conn;
}
//to support request pipelining(rfc2616-8.1.2.2)
// to support request pipelining(rfc2616-8.1.2.2)
void pushRquestToPipelining(const HttpRequestPtr &req);
HttpRequestPtr getFirstRequest() const;
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);
@ -105,4 +117,4 @@ class HttpRequestParser
bool _stopWorking = false;
};
} // namespace drogon
} // namespace drogon

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

@ -2,7 +2,7 @@
*
* HttpResponseImpl.cc
* An Tao
*
*
* Copyright 2018, An Tao. All rights reserved.
* https://github.com/an-tao/drogon
* Use of this source code is governed by a MIT license
@ -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)
@ -92,12 +93,12 @@ HttpResponsePtr HttpResponse::newFileResponse(const std::string &fullPath, const
auto resp = std::make_shared<HttpResponseImpl>();
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)
//TODO : Is 200k an appropriate value? Or set it to be configurable
pbuf->pubseekoff(0, infile.beg); // rewind
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,8 +167,7 @@ void HttpResponseImpl::makeHeaderString(const std::shared_ptr<std::string> &head
}
else
{
//output->append("Connection: Keep-Alive\r\n");
// output->append("Connection: Keep-Alive\r\n");
}
}
headerStringPtr->append(_contentTypeString.data(), _contentTypeString.length());
@ -214,17 +214,16 @@ std::shared_ptr<std::string> HttpResponseImpl::renderToString() const
httpString->append(*_fullHeaderString);
}
//output cookies
// output cookies
if (_cookies.size() > 0)
{
for (auto it = _cookies.begin(); it != _cookies.end(); ++it)
{
httpString->append(it->second.cookieString());
}
}
//output Date header
// output Date header
httpString->append("Date: ");
auto datePos = httpString->length();
httpString->append(utils::getHttpFullDate(trantor::Date::date()));
@ -253,17 +252,16 @@ std::shared_ptr<std::string> HttpResponseImpl::renderHeaderForHeadMethod() const
httpString->append(*_fullHeaderString);
}
//output cookies
// output cookies
if (_cookies.size() > 0)
{
for (auto it = _cookies.begin(); it != _cookies.end(); ++it)
{
httpString->append(it->second.cookieString());
}
}
//output Date header
// output Date header
httpString->append("Date: ");
httpString->append(utils::getHttpFullDate(trantor::Date::date()));
httpString->append("\r\n\r\n");

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

@ -2,7 +2,7 @@
*
* HttpResponseImpl.h
* An Tao
*
*
* Copyright 2018, An Tao. All rights reserved.
* https://github.com/an-tao/drogon
* Use of this source code is governed by a MIT license
@ -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
@ -33,7 +33,7 @@ class HttpResponseImpl : public HttpResponse
{
friend class HttpResponseParser;
public:
public:
HttpResponseImpl()
: _statusCode(kUnknown),
_creationDate(trantor::Date::now()),
@ -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));
@ -189,7 +191,7 @@ public:
if (field == "set-cookie")
{
//LOG_INFO<<"cookies!!!:"<<value;
// LOG_INFO<<"cookies!!!:"<<value;
auto values = utils::splitString(value, ";");
Cookie cookie;
cookie.setHttpOnly(false);
@ -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)
// {
@ -355,7 +360,7 @@ public:
}
void parseJson() const
{
//parse json data in reponse
// parse json data in reponse
_jsonPtr = std::make_shared<Json::Value>();
Json::CharReaderBuilder builder;
builder["collectComments"] = false;
@ -400,10 +405,10 @@ public:
}
}
protected:
protected:
void makeHeaderString(const std::shared_ptr<std::string> &headerStringPtr) const;
private:
private:
std::unordered_map<std::string, std::string> _headers;
std::unordered_map<std::string, Cookie> _cookies;
@ -440,4 +445,4 @@ private:
}
};
typedef std::shared_ptr<HttpResponseImpl> HttpResponseImplPtr;
} // namespace drogon
} // namespace drogon

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

@ -2,7 +2,7 @@
*
* HttpResponseParser.cc
* An Tao
*
*
* Copyright 2018, An Tao. All rights reserved.
* https://github.com/an-tao/drogon
* Use of this source code is governed by a MIT license
@ -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)
{
}
@ -102,7 +101,7 @@ bool HttpResponseParser::parseResponse(MsgBuffer *buf)
else
{
const std::string &len = _response->getHeaderBy("content-length");
//LOG_INFO << "content len=" << len;
// LOG_INFO << "content len=" << len;
if (!len.empty())
{
_response->_leftBodyLength = atoi(len.c_str());
@ -118,10 +117,11 @@ bool HttpResponseParser::parseResponse(MsgBuffer *buf)
}
else
{
if (_response->statusCode() == k204NoContent || (_response->statusCode() == k101SwitchingProtocols &&
_response->getHeaderBy("upgrade") == "websocket"))
if (_response->statusCode() == k204NoContent ||
(_response->statusCode() == k101SwitchingProtocols &&
_response->getHeaderBy("upgrade") == "websocket"))
{
//The Websocket response may not have a content-length header.
// The Websocket response may not have a content-length header.
_state = HttpResponseParseState::kGotAll;
hasMore = false;
}
@ -142,8 +142,8 @@ bool HttpResponseParser::parseResponse(MsgBuffer *buf)
}
else if (_state == HttpResponseParseState::kExpectBody)
{
//LOG_INFO << "expectBody:len=" << request_->contentLen;
//LOG_INFO << "expectBody:buf=" << buf;
// LOG_INFO << "expectBody:len=" << request_->contentLen;
// LOG_INFO << "expectBody:buf=" << buf;
if (buf->readableBytes() == 0)
{
if (_response->_leftBodyLength == 0)
@ -168,7 +168,7 @@ bool HttpResponseParser::parseResponse(MsgBuffer *buf)
{
_state = HttpResponseParseState::kGotAll;
LOG_TRACE << "post got all:len=" << _response->_leftBodyLength;
//LOG_INFO<<"content:"<<request_->content_;
// LOG_INFO<<"content:"<<request_->content_;
LOG_TRACE << "content(END)";
hasMore = false;
}
@ -184,11 +184,11 @@ bool HttpResponseParser::parseResponse(MsgBuffer *buf)
const char *crlf = buf->findCRLF();
if (crlf)
{
//chunk length line
// chunk length line
std::string len(buf->peek(), crlf - buf->peek());
char *end;
_response->_currentChunkLength = strtol(len.c_str(), &end, 16);
//LOG_TRACE << "chun length : " << _response->_currentChunkLength;
// LOG_TRACE << "chun length : " << _response->_currentChunkLength;
if (_response->_currentChunkLength != 0)
{
_state = HttpResponseParseState::kExpectChunkBody;
@ -206,7 +206,7 @@ bool HttpResponseParser::parseResponse(MsgBuffer *buf)
}
else if (_state == HttpResponseParseState::kExpectChunkBody)
{
//LOG_TRACE<<"expect chunk len="<<_response->_currentChunkLength;
// LOG_TRACE<<"expect chunk len="<<_response->_currentChunkLength;
if (buf->readableBytes() >= (_response->_currentChunkLength + 2))
{
if (*(buf->peek() + _response->_currentChunkLength) == '\r' &&
@ -219,7 +219,7 @@ bool HttpResponseParser::parseResponse(MsgBuffer *buf)
}
else
{
//error!
// error!
buf->retrieveAll();
return false;
}
@ -231,7 +231,7 @@ bool HttpResponseParser::parseResponse(MsgBuffer *buf)
}
else if (_state == HttpResponseParseState::kExpectLastEmptyChunk)
{
//last empty chunk
// last empty chunk
const char *crlf = buf->findCRLF();
if (crlf)
{

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

@ -2,7 +2,7 @@
*
* HttpResponseParser.h
* An Tao
*
*
* Copyright 2018, An Tao. All rights reserved.
* https://github.com/an-tao/drogon
* Use of this source code is governed by a MIT license
@ -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
@ -69,4 +69,4 @@ class HttpResponseParser
HttpResponseImplPtr _response;
};
} // namespace drogon
} // namespace drogon

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

@ -2,7 +2,7 @@
*
* HttpServer.cc
* An Tao
*
*
* Copyright 2018, An Tao. All rights reserved.
* https://github.com/an-tao/drogon
* Use of this source code is governed by a MIT license
@ -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();
}
@ -111,7 +105,7 @@ void HttpServer::onConnection(const TcpConnectionPtr &conn)
requestParser->webSocketConn()->onClose();
}
#if (CXX_STD > 14)
conn->getMutableContext()->reset(); //reset(): since c++17
conn->getMutableContext()->reset(); // reset(): since c++17
#else
conn->getMutableContext()->clear();
#endif
@ -119,25 +113,24 @@ 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())
{
//Websocket payload
// Websocket payload
requestParser->webSocketConn()->onNewMessage(conn, buf);
}
else
{
while (buf->readableBytes() > 0)
{
if (requestParser->isStop())
{
//The number of requests has reached the limit.
// The number of requests has reached the limit.
buf->retrieveAll();
return;
}
@ -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
// 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)
@ -229,7 +219,7 @@ void HttpServer::onRequest(const TcpConnectionPtr &conn, const HttpRequestImplPt
LOG_TRACE << "length after compressing:" << zlen;
if (response->expiredTime() >= 0)
{
//cached response,we need to make a clone
// cached response,we need to make a clone
newResp = std::make_shared<HttpResponseImpl>(*std::dynamic_pointer_cast<HttpResponseImpl>(response));
newResp->setExpiredTime(-1);
}
@ -275,7 +265,7 @@ void HttpServer::onRequest(const TcpConnectionPtr &conn, const HttpRequestImplPt
}
else
{
//some earlier requests are waiting for responses;
// some earlier requests are waiting for responses;
requestParser->pushResponseToPipelining(req, newResp);
}
}
@ -307,7 +297,7 @@ void HttpServer::onRequest(const TcpConnectionPtr &conn, const HttpRequestImplPt
}
else
{
//some earlier requests are waiting for responses;
// some earlier requests are waiting for responses;
requestParser->pushResponseToPipelining(req, newResp);
}
}
@ -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);

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

@ -2,7 +2,7 @@
*
* HttpServer.h
* An Tao
*
*
* Copyright 2018, An Tao. All rights reserved.
* https://github.com/an-tao/drogon
* Use of this source code is governed by a MIT license
@ -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;
@ -96,4 +95,4 @@ class HttpServer : trantor::NonCopyable
trantor::ConnectionCallback _connectionCallback;
};
} // namespace drogon
} // namespace drogon

View File

@ -2,7 +2,7 @@
*
* HttpSimpleControllersRouter.cc
* An Tao
*
*
* Copyright 2018, An Tao. All rights reserved.
* https://github.com/an-tao/drogon
* Use of this source code is governed by a MIT license
@ -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;
@ -72,7 +72,7 @@ void HttpSimpleControllersRouter::registerHttpSimpleController(const std::string
}
else
{
//All HTTP methods are valid
// All HTTP methods are valid
for (size_t i = 0; i < Invalid; i++)
{
item._binders[i] = binder;
@ -96,7 +96,7 @@ void HttpSimpleControllersRouter::route(const HttpRequestImplPtr &req,
auto &binder = ctrlInfo._binders[req->method()];
if (!binder)
{
//Invalid Http Method
// Invalid Http Method
auto res = drogon::HttpResponse::newHttpResponse();
if (req->method() != Options)
{
@ -109,7 +109,7 @@ void HttpSimpleControllersRouter::route(const HttpRequestImplPtr &req,
callback(res);
return;
}
//Do post routing advices.
// Do post routing advices.
if (!_postRoutingObservers.empty())
{
for (auto &observer : _postRoutingObservers)
@ -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,25 +137,32 @@ void HttpSimpleControllersRouter::route(const HttpRequestImplPtr &req,
}
else
{
auto callbackPtr = std::make_shared<std::function<void(const HttpResponsePtr &)>>(std::move(callback));
doAdvicesChain(_postRoutingAdvices,
0,
req,
callbackPtr,
[callbackPtr, &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));
});
}
else
{
doPreHandlingAdvices(binder, ctrlInfo, req, std::move(*callbackPtr), needSetJsessionid, std::move(sessionId));
}
});
doAdvicesChain(_postRoutingAdvices, 0, req, callbackPtr, [
callbackPtr,
&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));
});
}
else
{
doPreHandlingAdvices(
binder, ctrlInfo, req, std::move(*callbackPtr), needSetJsessionid, std::move(sessionId));
}
});
}
return;
}
@ -172,17 +180,18 @@ 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!
// use cached response!
LOG_TRACE << "Use cached response";
if (!needSetJsessionid || responsePtr->statusCode() == k404NotFound)
invokeCallback(callback, req, responsePtr);
else
{
//make a copy response;
// make a copy response;
auto newResp = std::make_shared<HttpResponseImpl>(*std::dynamic_pointer_cast<HttpResponseImpl>(responsePtr));
newResp->setExpiredTime(-1); //make it temporary
newResp->setExpiredTime(-1); // make it temporary
newResp->addCookie("JSESSIONID", sessionId);
invokeCallback(callback, req, newResp);
}
@ -190,36 +199,37 @@ void HttpSimpleControllersRouter::doControllerHandler(const CtrlBinderPtr &ctrlB
}
else
{
controller->asyncHandleHttpRequest(req, [=, callback = std::move(callback), &ctrlBinderPtr, sessionId = std::move(sessionId)](const HttpResponsePtr &resp) {
auto newResp = resp;
if (resp->expiredTime() >= 0)
{
//cache the response;
std::dynamic_pointer_cast<HttpResponseImpl>(resp)->makeHeaderString();
auto loop = req->getLoop();
if (loop->isInLoopThread())
{
ctrlBinderPtr->_responsePtrMap[loop] = resp;
}
else
{
loop->queueInLoop([loop, resp, &ctrlBinderPtr]() {
ctrlBinderPtr->_responsePtrMap[loop] = resp;
});
}
}
if (needSetJsessionid && resp->statusCode() != k404NotFound)
{
controller->asyncHandleHttpRequest(
req,
[ =, callback = std::move(callback), &ctrlBinderPtr, sessionId = std::move(sessionId) ](
const HttpResponsePtr &resp) {
auto newResp = resp;
if (resp->expiredTime() >= 0)
{
//make a copy
newResp = std::make_shared<HttpResponseImpl>(*std::dynamic_pointer_cast<HttpResponseImpl>(resp));
newResp->setExpiredTime(-1); //make it temporary
// cache the response;
std::dynamic_pointer_cast<HttpResponseImpl>(resp)->makeHeaderString();
auto loop = req->getLoop();
if (loop->isInLoopThread())
{
ctrlBinderPtr->_responsePtrMap[loop] = resp;
}
else
{
loop->queueInLoop([loop, resp, &ctrlBinderPtr]() { ctrlBinderPtr->_responsePtrMap[loop] = resp; });
}
}
newResp->addCookie("JSESSIONID", sessionId);
}
invokeCallback(callback, req, newResp);
});
if (needSetJsessionid && resp->statusCode() != k404NotFound)
{
if (resp->expiredTime() >= 0)
{
// make a copy
newResp = std::make_shared<HttpResponseImpl>(*std::dynamic_pointer_cast<HttpResponseImpl>(resp));
newResp->setExpiredTime(-1); // make it temporary
}
newResp->addCookie("JSESSIONID", sessionId);
}
invokeCallback(callback, req, newResp);
});
}
return;
@ -242,9 +252,10 @@ 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,
(HttpMethod)i,
std::string("HttpSimpleController: ") + item.second._binders[i]->_controllerName);
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,20 +331,23 @@ 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,
0,
req,
std::make_shared<std::function<void(const HttpResponsePtr &)>>([callbackPtr, needSetJsessionid, sessionIdPtr](const HttpResponsePtr &resp) {
if (!needSetJsessionid || resp->statusCode() == k404NotFound)
(*callbackPtr)(resp);
else
{
resp->addCookie("JSESSIONID", *sessionIdPtr);
(*callbackPtr)(resp);
}
}),
[this, ctrlBinderPtr, &routerItem, req, callbackPtr, needSetJsessionid, sessionIdPtr]() {
doControllerHandler(ctrlBinderPtr, routerItem, req, std::move(*callbackPtr), needSetJsessionid, std::move(*sessionIdPtr));
});
doAdvicesChain(
_preHandlingAdvices,
0,
req,
std::make_shared<std::function<void(const HttpResponsePtr &)>>(
[callbackPtr, needSetJsessionid, sessionIdPtr](const HttpResponsePtr &resp) {
if (!needSetJsessionid || resp->statusCode() == k404NotFound)
(*callbackPtr)(resp);
else
{
resp->addCookie("JSESSIONID", *sessionIdPtr);
(*callbackPtr)(resp);
}
}),
[this, ctrlBinderPtr, &routerItem, req, callbackPtr, needSetJsessionid, sessionIdPtr]() {
doControllerHandler(
ctrlBinderPtr, routerItem, req, std::move(*callbackPtr), needSetJsessionid, std::move(*sessionIdPtr));
});
}
}

View File

@ -2,7 +2,7 @@
*
* HttpSimpleControllersRouter.h
* An Tao
*
*
* Copyright 2018, An Tao. All rights reserved.
* https://github.com/an-tao/drogon
* Use of this source code is governed by a MIT license
@ -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 &&)>>
&postRoutingAdvices,
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)
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 &&)>>
&preHandlingAdvices,
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),
@ -70,24 +62,16 @@ class HttpSimpleControllersRouter : public trantor::NonCopyable
std::vector<std::tuple<std::string, HttpMethod, std::string>> getHandlersInfo() const;
private:
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;
@ -124,9 +108,9 @@ private:
{
for (auto &advice : _postHandlingAdvices)
{
advice(req,resp);
advice(req, resp);
}
callback(resp);
}
};
} // namespace drogon
} // namespace drogon

View File

@ -2,7 +2,7 @@
*
* HttpUtils.h
* An Tao
*
*
* Copyright 2018, An Tao. All rights reserved.
* https://github.com/an-tao/drogon
* Use of this source code is governed by a MIT license
@ -18,122 +18,121 @@
namespace drogon
{
const string_view &webContentTypeToString(ContentType contenttype)
{
switch (contenttype)
{
case CT_TEXT_HTML:
{
static string_view sv = "Content-Type: text/html; charset=utf-8\r\n";
return sv;
}
case CT_APPLICATION_X_FORM:
{
static string_view sv = "Content-Type: application/x-www-form-urlencoded\r\n";
return sv;
}
case CT_APPLICATION_XML:
{
static string_view sv = "Content-Type: application/xml; charset=utf-8\r\n";
return sv;
}
case CT_APPLICATION_JSON:
{
static string_view sv = "Content-Type: application/json; charset=utf-8\r\n";
return sv;
}
case CT_APPLICATION_X_JAVASCRIPT:
{
static string_view sv = "Content-Type: application/x-javascript; charset=utf-8\r\n";
return sv;
}
case CT_TEXT_CSS:
{
static string_view sv = "Content-Type: text/css; charset=utf-8\r\n";
return sv;
}
case CT_TEXT_XML:
{
static string_view sv = "Content-Type: text/xml; charset=utf-8\r\n";
return sv;
}
case CT_TEXT_XSL:
{
static string_view sv = "Content-Type: text/xsl; charset=utf-8\r\n";
return sv;
}
case CT_APPLICATION_OCTET_STREAM:
{
static string_view sv = "Content-Type: application/octet-stream\r\n";
return sv;
}
case CT_IMAGE_SVG_XML:
{
static string_view sv = "Content-Type: image/svg+xml\r\n";
return sv;
}
case CT_APPLICATION_X_FONT_TRUETYPE:
{
static string_view sv = "Content-Type: application/x-font-truetype\r\n";
return sv;
}
case CT_APPLICATION_X_FONT_OPENTYPE:
{
static string_view sv = "Content-Type: application/x-font-opentype\r\n";
return sv;
}
case CT_APPLICATION_FONT_WOFF:
{
static string_view sv = "Content-Type: application/font-woff\r\n";
return sv;
}
case CT_APPLICATION_FONT_WOFF2:
{
static string_view sv = "Content-Type: application/font-woff2\r\n";
return sv;
}
case CT_APPLICATION_VND_MS_FONTOBJ:
{
static string_view sv = "Content-Type: application/vnd.ms-fontobject\r\n";
return sv;
}
case CT_IMAGE_PNG:
{
static string_view sv = "Content-Type: image/png\r\n";
return sv;
}
case CT_IMAGE_JPG:
{
static string_view sv = "Content-Type: image/jpeg\r\n";
return sv;
}
case CT_IMAGE_GIF:
{
static string_view sv = "Content-Type: image/gif\r\n";
return sv;
}
case CT_IMAGE_XICON:
{
static string_view sv = "Content-Type: image/x-icon\r\n";
return sv;
}
case CT_IMAGE_BMP:
{
static string_view sv = "Content-Type: image/bmp\r\n";
return sv;
}
case CT_IMAGE_ICNS:
{
static string_view sv = "Content-Type: image/icns\r\n";
return sv;
}
default:
case CT_TEXT_PLAIN:
{
static string_view sv = "Content-Type: text/plain; charset=utf-8\r\n";
return sv;
}
case CT_TEXT_HTML:
{
static string_view sv = "Content-Type: text/html; charset=utf-8\r\n";
return sv;
}
case CT_APPLICATION_X_FORM:
{
static string_view sv = "Content-Type: application/x-www-form-urlencoded\r\n";
return sv;
}
case CT_APPLICATION_XML:
{
static string_view sv = "Content-Type: application/xml; charset=utf-8\r\n";
return sv;
}
case CT_APPLICATION_JSON:
{
static string_view sv = "Content-Type: application/json; charset=utf-8\r\n";
return sv;
}
case CT_APPLICATION_X_JAVASCRIPT:
{
static string_view sv = "Content-Type: application/x-javascript; charset=utf-8\r\n";
return sv;
}
case CT_TEXT_CSS:
{
static string_view sv = "Content-Type: text/css; charset=utf-8\r\n";
return sv;
}
case CT_TEXT_XML:
{
static string_view sv = "Content-Type: text/xml; charset=utf-8\r\n";
return sv;
}
case CT_TEXT_XSL:
{
static string_view sv = "Content-Type: text/xsl; charset=utf-8\r\n";
return sv;
}
case CT_APPLICATION_OCTET_STREAM:
{
static string_view sv = "Content-Type: application/octet-stream\r\n";
return sv;
}
case CT_IMAGE_SVG_XML:
{
static string_view sv = "Content-Type: image/svg+xml\r\n";
return sv;
}
case CT_APPLICATION_X_FONT_TRUETYPE:
{
static string_view sv = "Content-Type: application/x-font-truetype\r\n";
return sv;
}
case CT_APPLICATION_X_FONT_OPENTYPE:
{
static string_view sv = "Content-Type: application/x-font-opentype\r\n";
return sv;
}
case CT_APPLICATION_FONT_WOFF:
{
static string_view sv = "Content-Type: application/font-woff\r\n";
return sv;
}
case CT_APPLICATION_FONT_WOFF2:
{
static string_view sv = "Content-Type: application/font-woff2\r\n";
return sv;
}
case CT_APPLICATION_VND_MS_FONTOBJ:
{
static string_view sv = "Content-Type: application/vnd.ms-fontobject\r\n";
return sv;
}
case CT_IMAGE_PNG:
{
static string_view sv = "Content-Type: image/png\r\n";
return sv;
}
case CT_IMAGE_JPG:
{
static string_view sv = "Content-Type: image/jpeg\r\n";
return sv;
}
case CT_IMAGE_GIF:
{
static string_view sv = "Content-Type: image/gif\r\n";
return sv;
}
case CT_IMAGE_XICON:
{
static string_view sv = "Content-Type: image/x-icon\r\n";
return sv;
}
case CT_IMAGE_BMP:
{
static string_view sv = "Content-Type: image/bmp\r\n";
return sv;
}
case CT_IMAGE_ICNS:
{
static string_view sv = "Content-Type: image/icns\r\n";
return sv;
}
default:
case CT_TEXT_PLAIN:
{
static string_view sv = "Content-Type: text/plain; charset=utf-8\r\n";
return sv;
}
}
}
@ -141,237 +140,237 @@ const string_view &statusCodeToString(int code)
{
switch (code)
{
case 100:
{
static string_view sv = "Continue";
return sv;
}
case 101:
{
static string_view sv = "Switching Protocols";
return sv;
}
case 200:
{
static string_view sv = "OK";
return sv;
}
case 201:
{
static string_view sv = "Created";
return sv;
}
case 202:
{
static string_view sv = "Accepted";
return sv;
}
case 203:
{
static string_view sv = "Non-Authoritative Information";
return sv;
}
case 204:
{
static string_view sv = "No Content";
return sv;
}
case 205:
{
static string_view sv = "Reset Content";
return sv;
}
case 206:
{
static string_view sv = "Partial Content";
return sv;
}
case 300:
{
static string_view sv = "Multiple Choices";
return sv;
}
case 301:
{
static string_view sv = "Moved Permanently";
return sv;
}
case 302:
{
static string_view sv = "Found";
return sv;
}
case 303:
{
static string_view sv = "See Other";
return sv;
}
case 304:
{
static string_view sv = "Not Modified";
return sv;
}
case 305:
{
static string_view sv = "Use Proxy";
return sv;
}
case 307:
{
static string_view sv = "Temporary Redirect";
return sv;
}
case 400:
{
static string_view sv = "Bad Request";
return sv;
}
case 401:
{
static string_view sv = "Unauthorized";
return sv;
}
case 402:
{
static string_view sv = "Payment Required";
return sv;
}
case 403:
{
static string_view sv = "Forbidden";
return sv;
}
case 404:
{
static string_view sv = "Not Found";
return sv;
}
case 405:
{
static string_view sv = "Method Not Allowed";
return sv;
}
case 406:
{
static string_view sv = "Not Acceptable";
return sv;
}
case 407:
{
static string_view sv = "Proxy Authentication Required";
return sv;
}
case 408:
{
static string_view sv = "Request Time-out";
return sv;
}
case 409:
{
static string_view sv = "Conflict";
return sv;
}
case 410:
{
static string_view sv = "Gone";
return sv;
}
case 411:
{
static string_view sv = "Length Required";
return sv;
}
case 412:
{
static string_view sv = "Precondition Failed";
return sv;
}
case 413:
{
static string_view sv = "Request Entity Too Large";
return sv;
}
case 414:
{
static string_view sv = "Request-URI Too Large";
return sv;
}
case 415:
{
static string_view sv = "Unsupported Media Type";
return sv;
}
case 416:
{
static string_view sv = "Requested range not satisfiable";
return sv;
}
case 417:
{
static string_view sv = "Expectation Failed";
return sv;
}
case 500:
{
static string_view sv = "Internal Server Error";
return sv;
}
case 501:
{
static string_view sv = "Not Implemented";
return sv;
}
case 502:
{
static string_view sv = "Bad Gateway";
return sv;
}
case 503:
{
static string_view sv = "Service Unavailable";
return sv;
}
case 504:
{
static string_view sv = "Gateway Time-out";
return sv;
}
case 505:
{
static string_view sv = "HTTP Version not supported";
return sv;
}
default:
if (code >= 100 && code < 200)
case 100:
{
static string_view sv = "Informational";
static string_view sv = "Continue";
return sv;
}
else if (code >= 200 && code < 300)
case 101:
{
static string_view sv = "Successful";
static string_view sv = "Switching Protocols";
return sv;
}
else if (code >= 300 && code < 400)
case 200:
{
static string_view sv = "Redirection";
static string_view sv = "OK";
return sv;
}
else if (code >= 400 && code < 500)
case 201:
{
static string_view sv = "Created";
return sv;
}
case 202:
{
static string_view sv = "Accepted";
return sv;
}
case 203:
{
static string_view sv = "Non-Authoritative Information";
return sv;
}
case 204:
{
static string_view sv = "No Content";
return sv;
}
case 205:
{
static string_view sv = "Reset Content";
return sv;
}
case 206:
{
static string_view sv = "Partial Content";
return sv;
}
case 300:
{
static string_view sv = "Multiple Choices";
return sv;
}
case 301:
{
static string_view sv = "Moved Permanently";
return sv;
}
case 302:
{
static string_view sv = "Found";
return sv;
}
case 303:
{
static string_view sv = "See Other";
return sv;
}
case 304:
{
static string_view sv = "Not Modified";
return sv;
}
case 305:
{
static string_view sv = "Use Proxy";
return sv;
}
case 307:
{
static string_view sv = "Temporary Redirect";
return sv;
}
case 400:
{
static string_view sv = "Bad Request";
return sv;
}
else if (code >= 500 && code < 600)
case 401:
{
static string_view sv = "Server Error";
static string_view sv = "Unauthorized";
return sv;
}
else
case 402:
{
static string_view sv = "Undefined Error";
static string_view sv = "Payment Required";
return sv;
}
case 403:
{
static string_view sv = "Forbidden";
return sv;
}
case 404:
{
static string_view sv = "Not Found";
return sv;
}
case 405:
{
static string_view sv = "Method Not Allowed";
return sv;
}
case 406:
{
static string_view sv = "Not Acceptable";
return sv;
}
case 407:
{
static string_view sv = "Proxy Authentication Required";
return sv;
}
case 408:
{
static string_view sv = "Request Time-out";
return sv;
}
case 409:
{
static string_view sv = "Conflict";
return sv;
}
case 410:
{
static string_view sv = "Gone";
return sv;
}
case 411:
{
static string_view sv = "Length Required";
return sv;
}
case 412:
{
static string_view sv = "Precondition Failed";
return sv;
}
case 413:
{
static string_view sv = "Request Entity Too Large";
return sv;
}
case 414:
{
static string_view sv = "Request-URI Too Large";
return sv;
}
case 415:
{
static string_view sv = "Unsupported Media Type";
return sv;
}
case 416:
{
static string_view sv = "Requested range not satisfiable";
return sv;
}
case 417:
{
static string_view sv = "Expectation Failed";
return sv;
}
case 500:
{
static string_view sv = "Internal Server Error";
return sv;
}
case 501:
{
static string_view sv = "Not Implemented";
return sv;
}
case 502:
{
static string_view sv = "Bad Gateway";
return sv;
}
case 503:
{
static string_view sv = "Service Unavailable";
return sv;
}
case 504:
{
static string_view sv = "Gateway Time-out";
return sv;
}
case 505:
{
static string_view sv = "HTTP Version not supported";
return sv;
}
default:
if (code >= 100 && code < 200)
{
static string_view sv = "Informational";
return sv;
}
else if (code >= 200 && code < 300)
{
static string_view sv = "Successful";
return sv;
}
else if (code >= 300 && code < 400)
{
static string_view sv = "Redirection";
return sv;
}
else if (code >= 400 && code < 500)
{
static string_view sv = "Bad Request";
return sv;
}
else if (code >= 500 && code < 600)
{
static string_view sv = "Server Error";
return sv;
}
else
{
static string_view sv = "Undefined Error";
return sv;
}
}
}
@ -386,92 +385,92 @@ ContentType getContentType(const std::string &filename)
}
switch (extName.length())
{
case 0:
return CT_APPLICATION_OCTET_STREAM;
case 2:
{
if (extName == "js")
return CT_APPLICATION_X_JAVASCRIPT;
return CT_APPLICATION_OCTET_STREAM;
}
case 3:
{
switch (extName[0])
case 0:
return CT_APPLICATION_OCTET_STREAM;
case 2:
{
case 'b':
if (extName == "bmp")
return CT_IMAGE_BMP;
break;
case 'c':
if (extName == "css")
return CT_TEXT_CSS;
break;
case 'e':
if (extName == "eot")
return CT_APPLICATION_VND_MS_FONTOBJ;
break;
case 'g':
if (extName == "gif")
return CT_IMAGE_GIF;
break;
case 'i':
if (extName == "ico")
return CT_IMAGE_XICON;
break;
case 'j':
if (extName == "jpg")
return CT_IMAGE_JPG;
break;
case 'o':
if (extName == "otf")
return CT_APPLICATION_X_FONT_OPENTYPE;
break;
case 'p':
if (extName == "png")
return CT_IMAGE_PNG;
break;
case 's':
if (extName == "svg")
return CT_IMAGE_SVG_XML;
break;
case 't':
if (extName == "txt")
return CT_TEXT_PLAIN;
else if (extName == "ttf")
return CT_APPLICATION_X_FONT_TRUETYPE;
break;
case 'x':
if (extName == "xml")
return CT_TEXT_XML;
else if (extName == "xsl")
return CT_TEXT_XSL;
break;
default:
break;
if (extName == "js")
return CT_APPLICATION_X_JAVASCRIPT;
return CT_APPLICATION_OCTET_STREAM;
}
return CT_APPLICATION_OCTET_STREAM;
}
case 4:
{
if (extName == "html")
return CT_TEXT_HTML;
else if (extName == "jpeg")
return CT_IMAGE_JPG;
else if (extName == "icns")
return CT_IMAGE_ICNS;
else if (extName == "woff")
return CT_APPLICATION_FONT_WOFF;
return CT_APPLICATION_OCTET_STREAM;
}
case 5:
{
if (extName == "woff2")
return CT_APPLICATION_FONT_WOFF2;
return CT_APPLICATION_OCTET_STREAM;
}
default:
return CT_APPLICATION_OCTET_STREAM;
case 3:
{
switch (extName[0])
{
case 'b':
if (extName == "bmp")
return CT_IMAGE_BMP;
break;
case 'c':
if (extName == "css")
return CT_TEXT_CSS;
break;
case 'e':
if (extName == "eot")
return CT_APPLICATION_VND_MS_FONTOBJ;
break;
case 'g':
if (extName == "gif")
return CT_IMAGE_GIF;
break;
case 'i':
if (extName == "ico")
return CT_IMAGE_XICON;
break;
case 'j':
if (extName == "jpg")
return CT_IMAGE_JPG;
break;
case 'o':
if (extName == "otf")
return CT_APPLICATION_X_FONT_OPENTYPE;
break;
case 'p':
if (extName == "png")
return CT_IMAGE_PNG;
break;
case 's':
if (extName == "svg")
return CT_IMAGE_SVG_XML;
break;
case 't':
if (extName == "txt")
return CT_TEXT_PLAIN;
else if (extName == "ttf")
return CT_APPLICATION_X_FONT_TRUETYPE;
break;
case 'x':
if (extName == "xml")
return CT_TEXT_XML;
else if (extName == "xsl")
return CT_TEXT_XSL;
break;
default:
break;
}
return CT_APPLICATION_OCTET_STREAM;
}
case 4:
{
if (extName == "html")
return CT_TEXT_HTML;
else if (extName == "jpeg")
return CT_IMAGE_JPG;
else if (extName == "icns")
return CT_IMAGE_ICNS;
else if (extName == "woff")
return CT_APPLICATION_FONT_WOFF;
return CT_APPLICATION_OCTET_STREAM;
}
case 5:
{
if (extName == "woff2")
return CT_APPLICATION_FONT_WOFF2;
return CT_APPLICATION_OCTET_STREAM;
}
default:
return CT_APPLICATION_OCTET_STREAM;
}
}
} // namespace drogon
} // namespace drogon

View File

@ -2,7 +2,7 @@
*
* HttpUtils.h
* An Tao
*
*
* Copyright 2018, An Tao. All rights reserved.
* https://github.com/an-tao/drogon
* Use of this source code is governed by a MIT license
@ -13,17 +13,16 @@
*/
#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);
} // namespace drogon
} // namespace drogon

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

@ -2,7 +2,7 @@
*
* HttpViewBase.cc
* An Tao
*
*
* Copyright 2018, An Tao. All rights reserved.
* https://github.com/an-tao/drogon
* Use of this source code is governed by a MIT license
@ -12,12 +12,12 @@
*
*/
#include <drogon/HttpViewBase.h>
#include <drogon/DrClassMap.h>
#include <drogon/HttpViewBase.h>
#include <drogon/DrTemplateBase.h>
#include <trantor/utils/Logger.h>
#include <memory>
#include <trantor/utils/Logger.h>
using namespace drogon;
HttpResponsePtr HttpViewBase::genHttpResponse(std::string viewName, const HttpViewData &data)
{

View File

@ -24,21 +24,21 @@ std::string HttpViewData::htmlTranslate(const std::string &str)
{
switch (ch)
{
case '"':
ret.append("&quot;");
break;
case '<':
ret.append("&lt;");
break;
case '>':
ret.append("&gt;");
break;
case '&':
ret.append("&amp;");
break;
default:
ret.push_back(ch);
break;
case '"':
ret.append("&quot;");
break;
case '<':
ret.append("&lt;");
break;
case '>':
ret.append("&gt;");
break;
case '&':
ret.append("&amp;");
break;
default:
ret.push_back(ch);
break;
}
}
return ret;

View File

@ -2,7 +2,7 @@
*
* IntranetIpFilter.cc
* An Tao
*
*
* Copyright 2018, An Tao. All rights reserved.
* https://github.com/an-tao/drogon
* Use of this source code is governed by a MIT license
@ -12,12 +12,10 @@
*
*/
#include <drogon/IntranetIpFilter.h>
#include "HttpResponseImpl.h"
#include <drogon/IntranetIpFilter.h>
using namespace drogon;
void IntranetIpFilter::doFilter(const HttpRequestPtr &req,
FilterCallback &&fcb,
FilterChainCallback &&fccb)
void IntranetIpFilter::doFilter(const HttpRequestPtr &req, FilterCallback &&fcb, FilterChainCallback &&fccb)
{
if (req->peerAddr().isIntranetIp())
{

View File

@ -2,7 +2,7 @@
*
* LocalHostFilter.cc
* An Tao
*
*
* Copyright 2018, An Tao. All rights reserved.
* https://github.com/an-tao/drogon
* Use of this source code is governed by a MIT license
@ -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();

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

@ -2,7 +2,7 @@
*
* MultiPart.cc
* An Tao
*
*
* Copyright 2018, An Tao. All rights reserved.
* https://github.com/an-tao/drogon
* Use of this source code is governed by a MIT license
@ -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;
@ -62,7 +62,7 @@ int MultiPartParser::parse(const HttpRequestPtr &req)
if (pos == std::string::npos)
return -1;
std::string boundary = contentType.substr(pos + 9);
//std::cout << "boundary[" << boundary << "]" << std::endl;
// std::cout << "boundary[" << boundary << "]" << std::endl;
auto &content = req->query();
return parse(content, boundary);
}
@ -135,7 +135,7 @@ int MultiPartParser::parse(const std::string &content, const std::string &bounda
pos2 -= 4;
if (parseEntity(content.c_str() + pos1, content.c_str() + pos2) != 0)
return -1;
//pos2+=boundary.length();
// pos2+=boundary.length();
}
return 0;
}
@ -147,12 +147,10 @@ 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
// Absolute or relative path
}
else
{
@ -183,11 +181,10 @@ 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
// Absolute or relative path
}
else
{

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

@ -1,10 +1,10 @@
//this file is generated by program automatically,don't modify it!
// this file is generated by program automatically,don't modify it!
/**
*
* NotFound.cc
* An Tao
*
*
* Copyright 2018, An Tao. All rights reserved.
* https://github.com/an-tao/drogon
* Use of this source code is governed by a MIT license
@ -15,32 +15,32 @@
*/
#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;
std::string NotFound::genText(const HttpViewData &NotFound_view_data)
{
std::stringstream NotFound_tmp_stream;
NotFound_tmp_stream << "<html>\n";
NotFound_tmp_stream << "<head><title>404 Not Found</title></head>\n";
NotFound_tmp_stream << "<body bgcolor=\"white\">\n";
NotFound_tmp_stream << "<center><h1>404 Not Found</h1></center>\n";
NotFound_tmp_stream << "<hr><center>drogon/";
NotFound_tmp_stream << NotFound_view_data.get<std::string>("version");
NotFound_tmp_stream << "</center>\n";
NotFound_tmp_stream << "</body>\n";
NotFound_tmp_stream << "</html>\n";
NotFound_tmp_stream << "<!-- a padding to disable MSIE and Chrome friendly error page -->\n";
NotFound_tmp_stream << "<!-- a padding to disable MSIE and Chrome friendly error page -->\n";
NotFound_tmp_stream << "<!-- a padding to disable MSIE and Chrome friendly error page -->\n";
NotFound_tmp_stream << "<!-- a padding to disable MSIE and Chrome friendly error page -->\n";
NotFound_tmp_stream << "<!-- a padding to disable MSIE and Chrome friendly error page -->\n";
NotFound_tmp_stream << "<!-- a padding to disable MSIE and Chrome friendly error page -->\n";
return NotFound_tmp_stream.str();
std::stringstream NotFound_tmp_stream;
NotFound_tmp_stream << "<html>\n";
NotFound_tmp_stream << "<head><title>404 Not Found</title></head>\n";
NotFound_tmp_stream << "<body bgcolor=\"white\">\n";
NotFound_tmp_stream << "<center><h1>404 Not Found</h1></center>\n";
NotFound_tmp_stream << "<hr><center>drogon/";
NotFound_tmp_stream << NotFound_view_data.get<std::string>("version");
NotFound_tmp_stream << "</center>\n";
NotFound_tmp_stream << "</body>\n";
NotFound_tmp_stream << "</html>\n";
NotFound_tmp_stream << "<!-- a padding to disable MSIE and Chrome friendly error page -->\n";
NotFound_tmp_stream << "<!-- a padding to disable MSIE and Chrome friendly error page -->\n";
NotFound_tmp_stream << "<!-- a padding to disable MSIE and Chrome friendly error page -->\n";
NotFound_tmp_stream << "<!-- a padding to disable MSIE and Chrome friendly error page -->\n";
NotFound_tmp_stream << "<!-- a padding to disable MSIE and Chrome friendly error page -->\n";
NotFound_tmp_stream << "<!-- a padding to disable MSIE and Chrome friendly error page -->\n";
return NotFound_tmp_stream.str();
}

View File

@ -2,7 +2,7 @@
*
* PluginsManager.cc
* An Tao
*
*
* Copyright 2018, An Tao. All rights reserved.
* https://github.com/an-tao/drogon
* Use of this source code is governed by a MIT license
@ -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;
@ -47,7 +46,7 @@ void PluginsManager::initializeAllPlugins(const Json::Value &configs,
assert(dependencies.isArray() || dependencies.isNull());
if (dependencies.isArray())
{
//Is not null and is an array
// Is not null and is an array
for (auto &depName : dependencies)
{
auto *dp = getPlugin(depName.asString());
@ -68,7 +67,7 @@ void PluginsManager::initializeAllPlugins(const Json::Value &configs,
});
plugins.push_back(pluginPtr);
}
//Initialize them, Depth first
// Initialize them, Depth first
for (auto plugin : plugins)
{
plugin->initialize();

View File

@ -2,7 +2,7 @@
*
* PluginsManager.h
* An Tao
*
*
* Copyright 2018, An Tao. All rights reserved.
* https://github.com/an-tao/drogon
* Use of this source code is governed by a MIT license
@ -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();
@ -35,4 +33,4 @@ class PluginsManager : trantor::NonCopyable
std::vector<PluginBase *> _initializedPlugins;
};
} // namespace drogon
} // namespace drogon

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

@ -2,7 +2,7 @@
*
* SharedLibManager.cc
* An Tao
*
*
* Copyright 2018, An Tao. All rights reserved.
* https://github.com/an-tao/drogon
* Use of this source code is governed by a MIT license
@ -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;
@ -30,7 +30,7 @@ static void forEachFileIn(const std::string &path, const std::function<void(cons
/* open dirent directory */
if ((dp = opendir(path.c_str())) == NULL)
{
//perror("opendir:");
// perror("opendir:");
LOG_ERROR << "can't open dir,path:" << path;
return;
}
@ -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()
{
@ -86,7 +84,7 @@ void SharedLibManager::managerLibs()
auto exName = filename.substr(pos + 1);
if (exName == "csp")
{
//compile
// compile
auto lockFile = filename + ".lock";
std::ifstream fin(lockFile);
if (fin)
@ -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;
@ -117,7 +116,7 @@ void SharedLibManager::managerLibs()
cmd.append(filename).append(" -o ").append(libPath);
LOG_TRACE << cmd;
auto r = system(cmd.c_str());
//TODO: handle r
// TODO: handle r
(void)(r);
auto srcFile = filename.substr(0, pos);
srcFile.append(".cc");
@ -126,7 +125,7 @@ void SharedLibManager::managerLibs()
#ifdef __linux__
dlStat.mTime = st.st_mtim;
#else
dlStat.mTime=st.st_mtimespec;
dlStat.mTime = st.st_mtimespec;
#endif
if (dlStat.handle)
{
@ -182,7 +181,7 @@ void *SharedLibManager::loadLibs(const std::string &sourceFile, void *oldHld)
}
}
//loading so file;
// loading so file;
Handle = dlopen(soFile.c_str(), RTLD_LAZY);
if (!Handle)
{

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

@ -2,7 +2,7 @@
*
* SharedLibManager.h
* An Tao
*
*
* Copyright 2018, An Tao. All rights reserved.
* https://github.com/an-tao/drogon
* Use of this source code is governed by a MIT license
@ -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
@ -39,4 +39,4 @@ class SharedLibManager : public trantor::NonCopyable
void *loadLibs(const std::string &sourceFile, void *oldHld);
trantor::TimerId _timeId;
};
} // namespace drogon
} // namespace drogon

View File

@ -1,7 +1,7 @@
/**
* SpinLock.h
* An Tao
*
*
* Copyright 2018, An Tao. All rights reserved.
* https://github.com/an-tao/drogon
* Use of this source code is governed by a MIT license
@ -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))
{
@ -83,4 +80,4 @@ class SimpleSpinLock
std::atomic_flag &_flag;
};
} // namespace drogon
} // namespace drogon

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

@ -2,7 +2,7 @@
*
* Utilities.cc
* An Tao
*
*
* Copyright 2018, An Tao. All rights reserved.
* https://github.com/an-tao/drogon
* Use of this source code is governed by a MIT license
@ -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;
@ -352,94 +349,94 @@ std::string urlEncode(const std::string &src)
{
switch (*iter)
{
case ' ':
result.append(1, '+');
break;
case ' ':
result.append(1, '+');
break;
// alnum
case 'A':
case 'B':
case 'C':
case 'D':
case 'E':
case 'F':
case 'G':
case 'H':
case 'I':
case 'J':
case 'K':
case 'L':
case 'M':
case 'N':
case 'O':
case 'P':
case 'Q':
case 'R':
case 'S':
case 'T':
case 'U':
case 'V':
case 'W':
case 'X':
case 'Y':
case 'Z':
case 'a':
case 'b':
case 'c':
case 'd':
case 'e':
case 'f':
case 'g':
case 'h':
case 'i':
case 'j':
case 'k':
case 'l':
case 'm':
case 'n':
case 'o':
case 'p':
case 'q':
case 'r':
case 's':
case 't':
case 'u':
case 'v':
case 'w':
case 'x':
case 'y':
case 'z':
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
case 'A':
case 'B':
case 'C':
case 'D':
case 'E':
case 'F':
case 'G':
case 'H':
case 'I':
case 'J':
case 'K':
case 'L':
case 'M':
case 'N':
case 'O':
case 'P':
case 'Q':
case 'R':
case 'S':
case 'T':
case 'U':
case 'V':
case 'W':
case 'X':
case 'Y':
case 'Z':
case 'a':
case 'b':
case 'c':
case 'd':
case 'e':
case 'f':
case 'g':
case 'h':
case 'i':
case 'j':
case 'k':
case 'l':
case 'm':
case 'n':
case 'o':
case 'p':
case 'q':
case 'r':
case 's':
case 't':
case 'u':
case 'v':
case 'w':
case 'x':
case 'y':
case 'z':
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
// mark
case '-':
case '_':
case '.':
case '!':
case '~':
case '*':
case '\'':
case '(':
case ')':
case '&':
case '=':
case '/':
case '\\':
case '?':
result.append(1, *iter);
break;
case '-':
case '_':
case '.':
case '!':
case '~':
case '*':
case '\'':
case '(':
case ')':
case '&':
case '=':
case '/':
case '\\':
case '?':
result.append(1, *iter);
break;
// escape
default:
result.append(1, '%');
result.append(charToHex(*iter));
break;
default:
result.append(1, '%');
result.append(charToHex(*iter));
break;
}
}
@ -461,61 +458,65 @@ std::string urlDecode(const char *begin, const char *end)
{
switch (begin[i])
{
case '+':
result += ' ';
break;
case '%':
if ((i + 2) < len && isxdigit(begin[i + 1]) && isxdigit(begin[i + 2]))
{
uint x1 = begin[i + 1];
if (x1 >= '0' && x1 <= '9')
case '+':
result += ' ';
break;
case '%':
if ((i + 2) < len && isxdigit(begin[i + 1]) && isxdigit(begin[i + 2]))
{
x1 -= '0';
}
else if (x1 >= 'a' && x1 <= 'f')
{
x1 = x1 - 'a' + 10;
}
else if (x1 >= 'A' && x1 <= 'F')
{
x1 = x1 - 'A' + 10;
}
uint x2 = begin[i + 2];
if (x2 >= '0' && x2 <= '9')
{
x2 -= '0';
}
else if (x2 >= 'a' && x2 <= 'f')
{
x2 = x2 - 'a' + 10;
}
else if (x2 >= 'A' && x2 <= 'F')
{
x2 = x2 - 'A' + 10;
}
hex = x1 * 16 + x2;
//字母和数字[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))
{
result += char(hex);
i += 2;
uint x1 = begin[i + 1];
if (x1 >= '0' && x1 <= '9')
{
x1 -= '0';
}
else if (x1 >= 'a' && x1 <= 'f')
{
x1 = x1 - 'a' + 10;
}
else if (x1 >= 'A' && x1 <= 'F')
{
x1 = x1 - 'A' + 10;
}
uint x2 = begin[i + 2];
if (x2 >= '0' && x2 <= '9')
{
x2 -= '0';
}
else if (x2 >= 'a' && x2 <= 'f')
{
x2 = x2 - 'a' + 10;
}
else if (x2 >= 'A' && x2 <= 'F')
{
x2 = x2 - 'A' + 10;
}
hex = x1 * 16 + x2;
//字母和数字[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))
{
result += char(hex);
i += 2;
}
else
result += '%';
}
else
{
result += '%';
}
else
{
result += '%';
}
break;
default:
result += begin[i];
break;
}
break;
default:
result += begin[i];
break;
}
}
return result;
@ -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;
@ -713,5 +712,5 @@ int createPath(const std::string &path)
return 0;
}
} // namespace utils
} // namespace drogon
} // namespace utils
} // namespace drogon

View File

@ -14,11 +14,11 @@
#include "WebSocketClientImpl.h"
#include "HttpRequestImpl.h"
#include "HttpUtils.h"
#include "HttpResponseParser.h"
#include "HttpUtils.h"
#include <drogon/HttpAppFramework.h>
#include <trantor/net/InetAddress.h>
#include <drogon/utils/Utilities.h>
#include <trantor/net/InetAddress.h>
#ifdef USE_OPENSSL
#include <openssl/sha.h>
#else
@ -65,12 +65,10 @@ 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
// dns
// TODO: timeout should be set by user
if (InetAddress::resolve(_domain, &_server) == false)
{
_requestCallback(ReqResult::BadServerAddress, nullptr, shared_from_this());
@ -100,7 +98,7 @@ void WebSocketClientImpl::connectToServerInLoop()
if (connPtr->connected())
{
connPtr->setContext(HttpResponseParser(connPtr));
//send request;
// send request;
LOG_TRACE << "Connection established!";
thisPtr->sendReq(connPtr);
}
@ -109,20 +107,16 @@ 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]() {
auto thisPtr = weakPtr.lock();
if (!thisPtr)
return;
//can't connect to server
// 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();
@ -155,7 +149,7 @@ void WebSocketClientImpl::onRecvMessage(const trantor::TcpConnectionPtr &connPtr
}
HttpResponseParser *responseParser = any_cast<HttpResponseParser>(connPtr->getMutableContext());
//LOG_TRACE << "###:" << msg->readableBytes();
// LOG_TRACE << "###:" << msg->readableBytes();
if (!responseParser->parseResponse(msgBuffer))
{
@ -195,11 +189,10 @@ 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) {
thisPtr->_messageCallback(std::move(message), thisPtr, 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());
if (msgBuffer->readableBytes() > 0)
{
@ -221,14 +214,11 @@ void WebSocketClientImpl::reconnect()
}
WebSocketClientImpl::WebSocketClientImpl(trantor::EventLoop *loop, const trantor::InetAddress &addr, bool useSSL)
: _loop(loop),
_server(addr),
_useSSL(useSSL)
: _loop(loop), _server(addr), _useSSL(useSSL)
{
}
WebSocketClientImpl::WebSocketClientImpl(trantor::EventLoop *loop, const std::string &hostString)
: _loop(loop)
WebSocketClientImpl::WebSocketClientImpl(trantor::EventLoop *loop, const std::string &hostString) : _loop(loop)
{
auto lowerHost = hostString;
std::transform(lowerHost.begin(), lowerHost.end(), lowerHost.begin(), tolower);
@ -298,11 +288,11 @@ WebSocketClientPtr WebSocketClient::newWebSocketClient(const std::string &ip,
trantor::EventLoop *loop)
{
bool isIpv6 = ip.find(":") == std::string::npos ? false : true;
return std::make_shared<WebSocketClientImpl>(loop == nullptr ? app().getLoop() : loop, trantor::InetAddress(ip, port, isIpv6), useSSL);
return std::make_shared<WebSocketClientImpl>(
loop == nullptr ? app().getLoop() : loop, trantor::InetAddress(ip, port, isIpv6), useSSL);
}
WebSocketClientPtr WebSocketClient::newWebSocketClient(const std::string &hostString,
trantor::EventLoop *loop)
WebSocketClientPtr WebSocketClient::newWebSocketClient(const std::string &hostString, trantor::EventLoop *loop)
{
return std::make_shared<WebSocketClientImpl>(loop == nullptr ? app().getLoop() : loop, hostString);
}

View File

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

View File

@ -2,7 +2,7 @@
*
* WebSocketConnectionImpl.cc
* An Tao
*
*
* Copyright 2018, An Tao. All rights reserved.
* https://github.com/an-tao/drogon
* Use of this source code is governed by a MIT license
@ -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,10 +56,9 @@ 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
// Format the frame
std::string bytesFormatted;
bytesFormatted.resize(len + 10);
bytesFormatted[0] = char(0x80 | (opcode & 0x0f));
@ -99,11 +95,9 @@ void WebSocketConnectionImpl::sendWsData(const char *msg, size_t len, unsigned c
}
if (!_isServer)
{
//Add masking key;
// 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);
@ -178,7 +172,7 @@ void WebSocketConnectionImpl::setPingMessage(const std::string &message, const s
bool WebSocketMessageParser::parse(trantor::MsgBuffer *buffer)
{
//According to the rfc6455
// According to the rfc6455
_gotAll = false;
if (buffer->readableBytes() >= 2)
{
@ -186,37 +180,37 @@ bool WebSocketMessageParser::parse(trantor::MsgBuffer *buffer)
bool isControlFrame = false;
switch (opcode)
{
case 0:
//continuation frame
break;
case 1:
_type = WebSocketMessageType::Text;
break;
case 2:
_type = WebSocketMessageType::Binary;
break;
case 8:
_type = WebSocketMessageType::Close;
isControlFrame = true;
break;
case 9:
_type = WebSocketMessageType::Ping;
isControlFrame = true;
break;
case 10:
_type = WebSocketMessageType::Pong;
isControlFrame = true;
break;
default:
LOG_ERROR << "Unknown frame type";
return false;
break;
case 0:
// continuation frame
break;
case 1:
_type = WebSocketMessageType::Text;
break;
case 2:
_type = WebSocketMessageType::Binary;
break;
case 8:
_type = WebSocketMessageType::Close;
isControlFrame = true;
break;
case 9:
_type = WebSocketMessageType::Ping;
isControlFrame = true;
break;
case 10:
_type = WebSocketMessageType::Pong;
isControlFrame = true;
break;
default:
LOG_ERROR << "Unknown frame type";
return false;
break;
}
bool isFin = (((*buffer)[0] & 0x80) == 0x80);
if (!isFin && isControlFrame)
{
//rfc6455-5.5
// rfc6455-5.5
LOG_ERROR << "Bad frame: all control frames MUST NOT be fragmented";
return false;
}
@ -243,8 +237,9 @@ 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";
// rfc6455-5.5
LOG_ERROR << "Bad frame: all control frames MUST have a payload length "
"of 125 bytes or less";
return false;
}
if (indexFirstMask == 4)
@ -271,7 +266,7 @@ bool WebSocketMessageParser::parse(trantor::MsgBuffer *buffer)
}
if (isMasked != 0)
{
//The message is sent by the client, check the length
// The message is sent by the client, check the length
if (length > HttpAppFrameworkImpl::instance().getClientMaxWebSocketMessageSize())
{
LOG_ERROR << "The size of the WebSocket message is too large!";

View File

@ -2,7 +2,7 @@
*
* WebSocketConnectionImpl.h
* An Tao
*
*
* Copyright 2018, An Tao. All rights reserved.
* https://github.com/an-tao/drogon
* Use of this source code is governed by a MIT license
@ -20,13 +20,12 @@
namespace drogon
{
class WebSocketConnectionImpl;
typedef std::shared_ptr<WebSocketConnectionImpl> WebSocketConnectionImplPtr;
class WebSocketMessageParser
{
public:
public:
bool parse(trantor::MsgBuffer *buffer);
bool gotAll(std::string &message, WebSocketMessageType &type)
{
@ -38,7 +37,7 @@ public:
return true;
}
private:
private:
std::string _message;
WebSocketMessageType _type;
bool _gotAll = false;
@ -48,7 +47,7 @@ class WebSocketConnectionImpl : public WebSocketConnection,
public std::enable_shared_from_this<WebSocketConnectionImpl>,
public trantor::NonCopyable
{
public:
public:
explicit WebSocketConnectionImpl(const trantor::TcpConnectionPtr &conn, bool isServer = true);
virtual void send(const char *msg, uint64_t len, const WebSocketMessageType &type = WebSocketMessageType::Text) override;
@ -60,8 +59,8 @@ public:
virtual bool connected() const override;
virtual bool disconnected() const override;
virtual void shutdown() override; //close write
virtual void forceClose() override; //close
virtual void shutdown() override; // close write
virtual void forceClose() override; // close
virtual void setContext(const any &context) override;
virtual const any &getContext() const override;
@ -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)
{
@ -95,12 +92,12 @@ public:
{
if (type == WebSocketMessageType::Ping)
{
//ping
// ping
send(message, WebSocketMessageType::Pong);
}
else if (type == WebSocketMessageType::Close)
{
//close
// close
connPtr->shutdown();
}
else if (type == WebSocketMessageType::Unknown)
@ -116,7 +113,7 @@ public:
}
else
{
//Websock error!
// Websock error!
connPtr->shutdown();
return;
}
@ -131,7 +128,7 @@ public:
_closeCallback(shared_from_this());
}
private:
private:
trantor::TcpConnectionPtr _tcpConn;
trantor::InetAddress _localAddr;
trantor::InetAddress _peerAddr;
@ -140,14 +137,10 @@ 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);
};
} // namespace drogon
} // namespace drogon

View File

@ -2,7 +2,7 @@
*
* WebsocketControllersRouter.cc
* An Tao
*
*
* Copyright 2018, An Tao. All rights reserved.
* https://github.com/an-tao/drogon
* Use of this source code is governed by a MIT license
@ -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) {
ctrlPtr->handleNewMessage(connPtr, std::move(message), type);
});
wsConnPtr->setCloseCallback([ctrlPtr](const WebSocketConnectionImplPtr &connPtr) {
ctrlPtr->handleConnectionClosed(connPtr);
});
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); });
ctrlPtr->handleNewConnection(req, wsConnPtr);
return;
}

View File

@ -2,7 +2,7 @@
*
* WebsocketControllersRouter.h
* An Tao
*
*
* Copyright 2018, An Tao. All rights reserved.
* https://github.com/an-tao/drogon
* Use of this source code is governed by a MIT license
@ -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);
@ -58,4 +60,4 @@ class WebsocketControllersRouter : public trantor::NonCopyable
std::function<void(const HttpResponsePtr &)> &&callback,
const WebSocketConnectionImplPtr &wsConnPtr);
};
} // namespace drogon
} // namespace drogon

View File

@ -2,7 +2,7 @@
*
* Md5.cc
* An Tao
*
*
* Copyright 2018, An Tao. All rights reserved.
* https://github.com/an-tao/drogon
* Use of this source code is governed by a MIT license
@ -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,7 @@ UInt32 Md5Encode::FillData(const char *in_data_ptr, int data_byte_len, char **ou
}
else
{
bit_need_fill = (BIT_OF_GROUP - SRC_DATA_LEN) - mod_bit_num;
bit_need_fill = (BIT_OF_GROUP - SRC_DATA_LEN) - mod_bit_num;
}
int all_bit = bit_num + bit_need_fill;
if (0 < bit_need_fill)
@ -245,7 +245,7 @@ std::string Md5Encode::encode(const std::string &src_info)
std::string result;
char *out_data_ptr = NULL;
int total_byte = FillData(src_info.c_str(), src_info.length(), &out_data_ptr);
//char * data_BIT_OF_GROUP = out_data_ptr;
// char * data_BIT_OF_GROUP = out_data_ptr;
for (int i = 0; i < total_byte / (BIT_OF_GROUP / BIT_OF_BYTE); ++i)
{
char *data_BIT_OF_GROUP = out_data_ptr;

View File

@ -9,7 +9,7 @@
*
* Md5.h
* An Tao
*
*
* Copyright 2018, An Tao. All rights reserved.
* https://github.com/an-tao/drogon
* Use of this source code is governed by a MIT license
@ -60,7 +60,6 @@ class Md5Encode
};
public:
static std::string encode(const std::string &src_info);
protected:

View File

@ -2,7 +2,7 @@
*
* Sha1.cc
* An Tao
*
*
* Copyright 2018, An Tao. All rights reserved.
* https://github.com/an-tao/drogon
* Use of this source code is governed by a MIT license
@ -17,137 +17,136 @@
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)
{
memset(p, 0, 8);
memcpy(p, &v, 4);
int i = 0;
for (i = 0; i < 4; i++)
{
unsigned char t = p[i];
p[i] = p[7 - i];
p[7 - i] = t;
}
memset(p, 0, 8);
memcpy(p, &v, 4);
int i = 0;
for (i = 0; i < 4; i++)
{
unsigned char t = p[i];
p[i] = p[7 - i];
p[7 - i] = t;
}
}
static unsigned int LeftRol(unsigned int v, int n)
{
return (v << n) | (v >> (32 - n));
return (v << n) | (v >> (32 - n));
}
unsigned char *SHA1(const unsigned char *data, size_t dataLen, unsigned char *md)
{
unsigned char *pbytes = (unsigned char *)data;
unsigned int nbyte = dataLen;
unsigned char *pbytes = (unsigned char *)data;
unsigned int nbyte = dataLen;
static unsigned int words[80];
unsigned int H[5] = {0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0};
unsigned int a, b, c, d, e, f, k, temp, bitlen[2], word;
unsigned int i, j, index, p1, p2, maxlen;
unsigned char spec[4] = {0};
i = nbyte % 4;
static unsigned int words[80];
unsigned int H[5] = {0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0};
unsigned int a, b, c, d, e, f, k, temp, bitlen[2], word;
unsigned int i, j, index, p1, p2, maxlen;
unsigned char spec[4] = {0};
i = nbyte % 4;
p1 = nbyte - i;
spec[i] = 1 << 7;
while (i--)
{
spec[i] = pbytes[p1 + i];
}
p1 = nbyte - i;
spec[i] = 1 << 7;
while (i--)
{
spec[i] = pbytes[p1 + i];
}
maxlen = (nbyte + 1) % 64;
if (maxlen <= 56)
{
maxlen = (nbyte + 1) - maxlen + 64;
}
else
{
maxlen = (nbyte + 1) - maxlen + 128;
}
p2 = maxlen - 8;
WriteBigEndian64((unsigned char *)bitlen, nbyte * 8);
maxlen = (nbyte + 1) % 64;
if (maxlen <= 56)
{
maxlen = (nbyte + 1) - maxlen + 64;
}
else
{
maxlen = (nbyte + 1) - maxlen + 128;
}
p2 = maxlen - 8;
WriteBigEndian64((unsigned char *)bitlen, nbyte * 8);
for (j = 0; j < maxlen; j += 64)
{
a = H[0];
b = H[1];
c = H[2];
d = H[3];
e = H[4];
for (i = 0; i < 80; i++)
{
if (i < 16)
{
index = j + (i << 2);
if (index < p1)
{
word = *((unsigned int *)(pbytes + index));
}
else if (index == p1)
{
word = *(unsigned int *)spec;
}
else if (index < p2)
{
word = 0;
}
else
{
word = (index < maxlen - 4) ? bitlen[0] : bitlen[1];
}
words[i] = FromBigEndian(word);
}
else
{
words[i] = LeftRol(words[i - 3] ^ words[i - 8] ^ words[i - 14] ^ words[i - 16], 1);
}
if (i < 20)
{
f = (b & c) | ((~b) & d);
k = 0x5A827999;
}
else if (i < 40)
{
f = b ^ c ^ d;
k = 0x6ED9EBA1;
}
else if (i < 60)
{
f = (b & c) | (b & d) | (c & d);
k = 0x8F1BBCDC;
}
else
{
f = b ^ c ^ d;
k = 0xCA62C1D6;
}
temp = LeftRol(a, 5) + f + e + k + words[i];
e = d;
d = c;
c = LeftRol(b, 30);
b = a;
a = temp;
}
H[0] += a;
H[1] += b;
H[2] += c;
H[3] += d;
H[4] += e;
}
int ct = 0;
for (i = 0; i < 5; i++)
{
unsigned char buf[4] = {0};
memcpy(buf, &(H[i]), 4);
for (int r = 3; r >= 0; r--)
{
md[ct] = buf[r];
ct++;
}
}
for (j = 0; j < maxlen; j += 64)
{
a = H[0];
b = H[1];
c = H[2];
d = H[3];
e = H[4];
for (i = 0; i < 80; i++)
{
if (i < 16)
{
index = j + (i << 2);
if (index < p1)
{
word = *((unsigned int *)(pbytes + index));
}
else if (index == p1)
{
word = *(unsigned int *)spec;
}
else if (index < p2)
{
word = 0;
}
else
{
word = (index < maxlen - 4) ? bitlen[0] : bitlen[1];
}
words[i] = FromBigEndian(word);
}
else
{
words[i] = LeftRol(words[i - 3] ^ words[i - 8] ^ words[i - 14] ^ words[i - 16], 1);
}
if (i < 20)
{
f = (b & c) | ((~b) & d);
k = 0x5A827999;
}
else if (i < 40)
{
f = b ^ c ^ d;
k = 0x6ED9EBA1;
}
else if (i < 60)
{
f = (b & c) | (b & d) | (c & d);
k = 0x8F1BBCDC;
}
else
{
f = b ^ c ^ d;
k = 0xCA62C1D6;
}
temp = LeftRol(a, 5) + f + e + k + words[i];
e = d;
d = c;
c = LeftRol(b, 30);
b = a;
a = temp;
}
H[0] += a;
H[1] += b;
H[2] += c;
H[3] += d;
H[4] += e;
}
int ct = 0;
for (i = 0; i < 5; i++)
{
unsigned char buf[4] = {0};
memcpy(buf, &(H[i]), 4);
for (int r = 3; r >= 0; r--)
{
md[ct] = buf[r];
ct++;
}
}
return md;
return md;
}

View File

@ -2,7 +2,7 @@
*
* Sha1.h
* An Tao
*
*
* Copyright 2018, An Tao. All rights reserved.
* https://github.com/an-tao/drogon
* Use of this source code is governed by a MIT license

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

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

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

@ -1,16 +1,15 @@
#include <drogon/CacheMap.h>
#include <trantor/utils/Logger.h>
#include <trantor/net/EventLoopThread.h>
#include <drogon/utils/Utilities.h>
#include <unistd.h>
#include <string>
#include <thread>
#include <iostream>
#include <memory>
#include <string>
#include <thread>
#include <trantor/net/EventLoopThread.h>
#include <trantor/utils/Logger.h>
#include <unistd.h>
int main()
{
trantor::Logger::setLogLevel(trantor::Logger::TRACE);
trantor::EventLoopThread loopThread;
loopThread.run();
@ -19,19 +18,16 @@ 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), [&]() {
(*main_cachePtr)["new"]="new";
(*main_cachePtr)["new"] = "new";
if (main_cachePtr->find("1"))
{
LOG_DEBUG << "find item 1:" << (*main_cachePtr)["1"];
@ -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();
}

View File

@ -16,8 +16,8 @@ class handler : public drogon::DrObject<T>
class hh : public handler<hh>
{
};
} // namespace v1
} // namespace api
} // namespace v1
} // namespace api
int main()
{
api::v1::hh h;

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

View File

@ -5,310 +5,323 @@ using namespace drogon;
int main()
{
const std::string inStr = "Applications\n"
"Developer\n"
"Library\n"
"Network\n"
"System\n"
"Users\n"
"Volumes\n"
"bin\n"
"cores\n"
"dev\n"
"etc\n"
"home\n"
"installer.failurerequests\n"
"net\n"
"opt\n"
"private\n"
"sbin\n"
"tmp\n"
"usb\n"
"usr\n"
"var\n"
"vm\n"
"用户信息\n"
"\n"
"/Applications:\n"
"Adobe\n"
"Adobe Creative Cloud\n"
"Adobe Photoshop CC\n"
"AirPlayer Pro.app\n"
"Android Studio.app\n"
"App Store.app\n"
"Autodesk\n"
"Automator.app\n"
"Axure RP Pro 7.0.app\n"
"BaiduNetdisk_mac.app\n"
"CLion.app\n"
"Calculator.app\n"
"Calendar.app\n"
"Chess.app\n"
"CleanApp.app\n"
"Contacts.app\n"
"DVD Player.app\n"
"Dashboard.app\n"
"Dictionary.app\n"
"Docs for Xcode.app\n"
"FaceTime.app\n"
"FinalShell\n"
"Firefox.app\n"
"Folx.app\n"
"Font Book.app\n"
"GitHub.app\n"
"Google Chrome.app\n"
"Grammarly.app\n"
"Image Capture.app\n"
"Lantern.app\n"
"Launchpad.app\n"
"License.rtf\n"
"MacPorts\n"
"Mail.app\n"
"Maps.app\n"
"Messages.app\n"
"Microsoft Excel.app\n"
"Microsoft Office 2011\n"
"Microsoft OneNote.app\n"
"Microsoft Outlook.app\n"
"Microsoft PowerPoint.app\n"
"Microsoft Word.app\n"
"Mindjet MindManager.app\n"
"Mission Control.app\n"
"Mockplus.app\n"
"MyEclipse 2015\n"
"Notes.app\n"
"OmniGraffle.app\n"
"PP助手.app\n"
"Pages.app\n"
"Photo Booth.app\n"
"Photos.app\n"
"Preview.app\n"
"QJVPN.app\n"
"QQ.app\n"
"QuickTime Player.app\n"
"RAR Extractor Lite.app\n"
"Reminders.app\n"
"Remote Desktop Connection.app\n"
"Renee Undeleter.app\n"
"Sabaki.app\n"
"Safari.app\n"
"ShadowsocksX.app\n"
"Siri.app\n"
"SogouInputPad.app\n"
"Stickies.app\n"
"System Preferences.app\n"
"TeX\n"
"Telegram.app\n"
"Termius.app\n"
"Tesumego - How to Make a Professional Go Player.app\n"
"TextEdit.app\n"
"Thunder.app\n"
"Time Machine.app\n"
"Tunnelblick.app\n"
"Utilities\n"
"VPN Shield.appdownload\n"
"VirtualBox.app\n"
"WeChat.app\n"
"WinOnX2.app\n"
"Wireshark.app\n"
"Xcode.app\n"
"Yose.app\n"
"YoudaoNote.localized\n"
"finalshelldata\n"
"iBooks.app\n"
"iPhoto.app\n"
"iTools.app\n"
"iTunes.app\n"
"pgAdmin 4.app\n"
"wechatwebdevtools.app\n"
"搜狐影音.appdownload\n"
"网易有道词典.app\n"
"万能数据恢复大师.app\n"
"\n"
"/Applications/Adobe:\n"
"Flash Player\n"
"\n"
"/Applications/Adobe/Flash Player:\n"
"AddIns\n"
"\n"
"/Applications/Adobe/Flash Player/AddIns:\n"
"airappinstaller\n"
"\n"
"/Applications/Adobe/Flash Player/AddIns/airappinstaller:\n"
"airappinstaller\n"
"digest.s\n"
"\n"
"/Applications/Adobe Creative Cloud:\n"
"Adobe Creative Cloud\n"
"Icon\n"
"Uninstall Adobe Creative Cloud\n"
"\n"
"/Applications/Adobe Photoshop CC:\n"
"Adobe Photoshop CC.app\n"
"Configuration\n"
"Icon\n"
"Legal\n"
"LegalNotices.pdf\n"
"Locales\n"
"Plug-ins\n"
"Presets\n"
"卸载 Adobe Photoshop CC\n"
"\n"
"/Applications/Adobe Photoshop CC/Adobe Photoshop CC.app:\n"
"Contents\n"
"Linguistics\n"
"\n"
"/Applications/Adobe Photoshop CC/Adobe Photoshop CC.app/Contents:\n"
"Application Data\n"
"Frameworks\n"
"Info.plist\n"
"MacOS\n"
"PkgInfo\n"
"Required\n"
"Resources\n"
"_CodeSignature\n"
"\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"
"4.0\n"
"\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"
"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"
"FileInfo_ar_AE.dat\n"
"FileInfo_bg_BG.dat\n"
"FileInfo_cs_CZ.dat\n"
"FileInfo_da_DK.dat\n"
"FileInfo_de_DE.dat\n"
"FileInfo_el_GR.dat\n"
"FileInfo_en_US.dat\n"
"FileInfo_es_ES.dat\n"
"FileInfo_et_EE.dat\n"
"FileInfo_fi_FI.dat\n"
"FileInfo_fr_FR.dat\n"
"FileInfo_he_IL.dat\n"
"FileInfo_hr_HR.dat\n"
"FileInfo_hu_HU.dat\n"
"FileInfo_it_IT.dat\n"
"FileInfo_ja_JP.dat\n"
"FileInfo_ko_KR.dat\n"
"FileInfo_lt_LT.dat\n"
"FileInfo_lv_LV.dat\n"
"FileInfo_nb_NO.dat\n"
"FileInfo_nl_NL.dat\n"
"FileInfo_pl_PL.dat\n"
"FileInfo_pt_BR.dat\n"
"FileInfo_ro_RO.dat\n"
"FileInfo_ru_RU.dat\n"
"FileInfo_sk_SK.dat\n"
"FileInfo_sl_SI.dat\n"
"FileInfo_sv_SE.dat\n"
"FileInfo_tr_TR.dat\n"
"FileInfo_uk_UA.dat\n"
"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"
"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"
"DICOM_ar_AE.dat\n"
"DICOM_bg_BG.dat\n"
"DICOM_cs_CZ.dat\n"
"DICOM_da_DK.dat\n"
"DICOM_de_DE.dat\n"
"DICOM_el_GR.dat\n"
"DICOM_en_US.dat\n"
"DICOM_es_ES.dat\n"
"DICOM_et_EE.dat\n"
"DICOM_fi_FI.dat\n"
"DICOM_fr_FR.dat\n"
"DICOM_he_IL.dat\n"
"DICOM_hr_HR.dat\n"
"DICOM_hu_HU.dat\n"
"DICOM_it_IT.dat\n"
"DICOM_ja_JP.dat\n"
"DICOM_ko_KR.dat\n"
"DICOM_lt_LT.dat\n"
"DICOM_lv_LV.dat\n"
"DICOM_nb_NO.dat\n"
"DICOM_nl_NL.dat\n"
"DICOM_pl_PL.dat\n"
"DICOM_pt_BR.dat\n"
"DICOM_ro_RO.dat\n"
"DICOM_ru_RU.dat\n"
"DICOM_sk_SK.dat\n"
"DICOM_sl_SI.dat\n"
"DICOM_sv_SE.dat\n"
"DICOM_tr_TR.dat\n"
"DICOM_uk_UA.dat\n"
"DICOM_zh_CN.dat\n"
"DICOM_zh_TW.dat\n"
"Mobile_ar_AE.dat\n"
"Mobile_bg_BG.dat\n"
"Mobile_cs_CZ.dat\n"
"Mobile_da_DK.dat\n"
"Mobile_de_DE.dat\n"
"Mobile_el_GR.dat\n"
"Mobile_en_US.dat\n"
"Mobile_es_ES.dat\n"
"Mobile_et_EE.dat\n"
"Mobile_fi_FI.dat\n"
"Mobile_fr_FR.dat\n"
"Mobile_he_IL.dat\n"
"Mobile_hr_HR.dat\n"
"Mobile_hu_HU.dat\n"
"Mobile_it_IT.dat\n"
"Mobile_ja_JP.dat\n"
"Mobile_ko_KR.dat\n"
"Mobile_lt_LT.dat\n"
"Mobile_lv_LV.dat\n"
"Mobile_nb_NO.dat\n"
"Mobile_nl_NL.dat\n"
"Mobile_pl_PL.dat\n"
"Mobile_pt_BR.dat\n"
"Mobile_ro_RO.dat\n"
"Mobile_ru_RU.dat\n"
"Mobile_sk_SK.dat\n"
"Mobile_sl_SI.dat\n"
"Mobile_sv_SE.dat\n"
"Mobile_tr_TR.dat\n"
"Mobile_uk_UA.dat\n"
"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"
"IPTC\n"
"IPTCExt\n"
"advanced\n"
"audioData\n"
"camera\n"
"categories\n"
"description\n"
"dicom\n"
"gpsData\n"
"history\n"
"mobile\n"
"origin\n"
"rawpacket";
auto ret=utils::gzipCompress(inStr.c_str(), inStr.length());
if(ret)
const std::string inStr =
"Applications\n"
"Developer\n"
"Library\n"
"Network\n"
"System\n"
"Users\n"
"Volumes\n"
"bin\n"
"cores\n"
"dev\n"
"etc\n"
"home\n"
"installer.failurerequests\n"
"net\n"
"opt\n"
"private\n"
"sbin\n"
"tmp\n"
"usb\n"
"usr\n"
"var\n"
"vm\n"
"用户信息\n"
"\n"
"/Applications:\n"
"Adobe\n"
"Adobe Creative Cloud\n"
"Adobe Photoshop CC\n"
"AirPlayer Pro.app\n"
"Android Studio.app\n"
"App Store.app\n"
"Autodesk\n"
"Automator.app\n"
"Axure RP Pro 7.0.app\n"
"BaiduNetdisk_mac.app\n"
"CLion.app\n"
"Calculator.app\n"
"Calendar.app\n"
"Chess.app\n"
"CleanApp.app\n"
"Contacts.app\n"
"DVD Player.app\n"
"Dashboard.app\n"
"Dictionary.app\n"
"Docs for Xcode.app\n"
"FaceTime.app\n"
"FinalShell\n"
"Firefox.app\n"
"Folx.app\n"
"Font Book.app\n"
"GitHub.app\n"
"Google Chrome.app\n"
"Grammarly.app\n"
"Image Capture.app\n"
"Lantern.app\n"
"Launchpad.app\n"
"License.rtf\n"
"MacPorts\n"
"Mail.app\n"
"Maps.app\n"
"Messages.app\n"
"Microsoft Excel.app\n"
"Microsoft Office 2011\n"
"Microsoft OneNote.app\n"
"Microsoft Outlook.app\n"
"Microsoft PowerPoint.app\n"
"Microsoft Word.app\n"
"Mindjet MindManager.app\n"
"Mission Control.app\n"
"Mockplus.app\n"
"MyEclipse 2015\n"
"Notes.app\n"
"OmniGraffle.app\n"
"PP助手.app\n"
"Pages.app\n"
"Photo Booth.app\n"
"Photos.app\n"
"Preview.app\n"
"QJVPN.app\n"
"QQ.app\n"
"QuickTime Player.app\n"
"RAR Extractor Lite.app\n"
"Reminders.app\n"
"Remote Desktop Connection.app\n"
"Renee Undeleter.app\n"
"Sabaki.app\n"
"Safari.app\n"
"ShadowsocksX.app\n"
"Siri.app\n"
"SogouInputPad.app\n"
"Stickies.app\n"
"System Preferences.app\n"
"TeX\n"
"Telegram.app\n"
"Termius.app\n"
"Tesumego - How to Make a Professional Go Player.app\n"
"TextEdit.app\n"
"Thunder.app\n"
"Time Machine.app\n"
"Tunnelblick.app\n"
"Utilities\n"
"VPN Shield.appdownload\n"
"VirtualBox.app\n"
"WeChat.app\n"
"WinOnX2.app\n"
"Wireshark.app\n"
"Xcode.app\n"
"Yose.app\n"
"YoudaoNote.localized\n"
"finalshelldata\n"
"iBooks.app\n"
"iPhoto.app\n"
"iTools.app\n"
"iTunes.app\n"
"pgAdmin 4.app\n"
"wechatwebdevtools.app\n"
"搜狐影音.appdownload\n"
"网易有道词典.app\n"
"万能数据恢复大师.app\n"
"\n"
"/Applications/Adobe:\n"
"Flash Player\n"
"\n"
"/Applications/Adobe/Flash Player:\n"
"AddIns\n"
"\n"
"/Applications/Adobe/Flash Player/AddIns:\n"
"airappinstaller\n"
"\n"
"/Applications/Adobe/Flash Player/AddIns/airappinstaller:\n"
"airappinstaller\n"
"digest.s\n"
"\n"
"/Applications/Adobe Creative Cloud:\n"
"Adobe Creative Cloud\n"
"Icon\n"
"Uninstall Adobe Creative Cloud\n"
"\n"
"/Applications/Adobe Photoshop CC:\n"
"Adobe Photoshop CC.app\n"
"Configuration\n"
"Icon\n"
"Legal\n"
"LegalNotices.pdf\n"
"Locales\n"
"Plug-ins\n"
"Presets\n"
"卸载 Adobe Photoshop CC\n"
"\n"
"/Applications/Adobe Photoshop CC/Adobe Photoshop CC.app:\n"
"Contents\n"
"Linguistics\n"
"\n"
"/Applications/Adobe Photoshop CC/Adobe Photoshop CC.app/Contents:\n"
"Application Data\n"
"Frameworks\n"
"Info.plist\n"
"MacOS\n"
"PkgInfo\n"
"Required\n"
"Resources\n"
"_CodeSignature\n"
"\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"
"4.0\n"
"\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"
"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"
"FileInfo_ar_AE.dat\n"
"FileInfo_bg_BG.dat\n"
"FileInfo_cs_CZ.dat\n"
"FileInfo_da_DK.dat\n"
"FileInfo_de_DE.dat\n"
"FileInfo_el_GR.dat\n"
"FileInfo_en_US.dat\n"
"FileInfo_es_ES.dat\n"
"FileInfo_et_EE.dat\n"
"FileInfo_fi_FI.dat\n"
"FileInfo_fr_FR.dat\n"
"FileInfo_he_IL.dat\n"
"FileInfo_hr_HR.dat\n"
"FileInfo_hu_HU.dat\n"
"FileInfo_it_IT.dat\n"
"FileInfo_ja_JP.dat\n"
"FileInfo_ko_KR.dat\n"
"FileInfo_lt_LT.dat\n"
"FileInfo_lv_LV.dat\n"
"FileInfo_nb_NO.dat\n"
"FileInfo_nl_NL.dat\n"
"FileInfo_pl_PL.dat\n"
"FileInfo_pt_BR.dat\n"
"FileInfo_ro_RO.dat\n"
"FileInfo_ru_RU.dat\n"
"FileInfo_sk_SK.dat\n"
"FileInfo_sl_SI.dat\n"
"FileInfo_sv_SE.dat\n"
"FileInfo_tr_TR.dat\n"
"FileInfo_uk_UA.dat\n"
"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"
"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"
"DICOM_ar_AE.dat\n"
"DICOM_bg_BG.dat\n"
"DICOM_cs_CZ.dat\n"
"DICOM_da_DK.dat\n"
"DICOM_de_DE.dat\n"
"DICOM_el_GR.dat\n"
"DICOM_en_US.dat\n"
"DICOM_es_ES.dat\n"
"DICOM_et_EE.dat\n"
"DICOM_fi_FI.dat\n"
"DICOM_fr_FR.dat\n"
"DICOM_he_IL.dat\n"
"DICOM_hr_HR.dat\n"
"DICOM_hu_HU.dat\n"
"DICOM_it_IT.dat\n"
"DICOM_ja_JP.dat\n"
"DICOM_ko_KR.dat\n"
"DICOM_lt_LT.dat\n"
"DICOM_lv_LV.dat\n"
"DICOM_nb_NO.dat\n"
"DICOM_nl_NL.dat\n"
"DICOM_pl_PL.dat\n"
"DICOM_pt_BR.dat\n"
"DICOM_ro_RO.dat\n"
"DICOM_ru_RU.dat\n"
"DICOM_sk_SK.dat\n"
"DICOM_sl_SI.dat\n"
"DICOM_sv_SE.dat\n"
"DICOM_tr_TR.dat\n"
"DICOM_uk_UA.dat\n"
"DICOM_zh_CN.dat\n"
"DICOM_zh_TW.dat\n"
"Mobile_ar_AE.dat\n"
"Mobile_bg_BG.dat\n"
"Mobile_cs_CZ.dat\n"
"Mobile_da_DK.dat\n"
"Mobile_de_DE.dat\n"
"Mobile_el_GR.dat\n"
"Mobile_en_US.dat\n"
"Mobile_es_ES.dat\n"
"Mobile_et_EE.dat\n"
"Mobile_fi_FI.dat\n"
"Mobile_fr_FR.dat\n"
"Mobile_he_IL.dat\n"
"Mobile_hr_HR.dat\n"
"Mobile_hu_HU.dat\n"
"Mobile_it_IT.dat\n"
"Mobile_ja_JP.dat\n"
"Mobile_ko_KR.dat\n"
"Mobile_lt_LT.dat\n"
"Mobile_lv_LV.dat\n"
"Mobile_nb_NO.dat\n"
"Mobile_nl_NL.dat\n"
"Mobile_pl_PL.dat\n"
"Mobile_pt_BR.dat\n"
"Mobile_ro_RO.dat\n"
"Mobile_ru_RU.dat\n"
"Mobile_sk_SK.dat\n"
"Mobile_sl_SI.dat\n"
"Mobile_sv_SE.dat\n"
"Mobile_tr_TR.dat\n"
"Mobile_uk_UA.dat\n"
"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"
"IPTC\n"
"IPTCExt\n"
"advanced\n"
"audioData\n"
"camera\n"
"categories\n"
"description\n"
"dicom\n"
"gpsData\n"
"history\n"
"mobile\n"
"origin\n"
"rawpacket";
auto ret = utils::gzipCompress(inStr.c_str(), inStr.length());
if (ret)
{
std::cout << "origin length=" << inStr.length() << " compressing length=" << ret->length() << std::endl;
auto decompressStr = utils::gzipDecompress(ret);
if (decompressStr)
{

View File

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

View File

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

View File

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

View File

@ -9,11 +9,13 @@
int main()
{
unsigned char in[] = "1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890";
unsigned char out[SHA_DIGEST_LENGTH] = {0};
SHA1(in, strlen((const char *)in), out);
/// fecfd28bbc9345891a66d7c1b8ff46e60192d284
for (int i = 0; i < SHA_DIGEST_LENGTH; i++)
printf("%02x", out[i]);
putchar('\n');
unsigned char in[] =
"1234567890123456789012345678901234567890123456789012345"
"678901234567890123456789012345678901234567890";
unsigned char out[SHA_DIGEST_LENGTH] = {0};
SHA1(in, strlen((const char *)in), out);
/// fecfd28bbc9345891a66d7c1b8ff46e60192d284
for (int i = 0; i < SHA_DIGEST_LENGTH; i++)
printf("%02x", out[i]);
putchar('\n');
}

View File

@ -8,7 +8,7 @@
* COPYING with this source code, please notify the distributor of this mistake,
* or contact the author.
*/
//Taken from libpqxx and modified
// Taken from libpqxx and modified
#pragma once
@ -68,5 +68,5 @@ class ArrayParser
const char *m_pos;
};
} // namespace orm
} // namespace drogon
} // namespace orm
} // namespace drogon

View File

@ -9,7 +9,7 @@
* that can be found in the License file.
*
* Drogon
*
*
*/
#pragma once
@ -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,71 +42,74 @@ 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)
{
case CompareOperator::EQ:
_condString += " = $?";
break;
case CompareOperator::NE:
_condString += " != $?";
break;
case CompareOperator::GT:
_condString += " > $?";
break;
case CompareOperator::GE:
_condString += " >= $?";
break;
case CompareOperator::LT:
_condString += " < $?";
break;
case CompareOperator::LE:
_condString += " <= $?";
break;
case CompareOperator::LIKE:
_condString += " like $?";
break;
case CompareOperator::IsNull:
case CompareOperator::IsNotNull:
default:
break;
case CompareOperator::EQ:
_condString += " = $?";
break;
case CompareOperator::NE:
_condString += " != $?";
break;
case CompareOperator::GT:
_condString += " > $?";
break;
case CompareOperator::GE:
_condString += " >= $?";
break;
case CompareOperator::LT:
_condString += " < $?";
break;
case CompareOperator::LE:
_condString += " <= $?";
break;
case CompareOperator::LIKE:
_condString += " like $?";
break;
case CompareOperator::IsNull:
case CompareOperator::IsNotNull:
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)
{
case CompareOperator::IsNull:
_condString += " is null";
break;
case CompareOperator::IsNotNull:
_condString += " is not null";
break;
default:
break;
case CompareOperator::IsNull:
_condString += " is null";
break;
case CompareOperator::IsNotNull:
_condString += " is not null";
break;
default:
break;
}
}
Criteria() {}
Criteria()
{
}
void outputArgs(internal::SqlBinder &binder) const
{
if (_outputArgumentsFunc)
@ -119,10 +121,10 @@ class Criteria
friend const Criteria operator||(Criteria cond1, Criteria cond2);
std::string _condString;
std::function<void(internal::SqlBinder &)> _outputArgumentsFunc;
}; // namespace orm
}; // namespace orm
const Criteria operator&&(Criteria cond1, Criteria cond2);
const Criteria operator||(Criteria cond1, Criteria cond2);
} // namespace orm
} // namespace drogon
} // namespace orm
} // namespace drogon

View File

@ -15,24 +15,23 @@
#pragma once
#include <drogon/config.h>
#include <drogon/orm/Exception.h>
#include <drogon/orm/Field.h>
#include <drogon/orm/Result.h>
#include <drogon/orm/ResultIterator.h>
#include <drogon/orm/Row.h>
#include <drogon/orm/RowIterator.h>
#include <drogon/orm/SqlBinder.h>
#include <exception>
#include <functional>
#include <future>
#include <string>
#include <trantor/utils/Logger.h>
#include <trantor/utils/NonCopyable.h>
#include <drogon/orm/SqlBinder.h>
#include <drogon/orm/Result.h>
#include <drogon/orm/Row.h>
#include <drogon/orm/Field.h>
#include <drogon/orm/ResultIterator.h>
#include <drogon/orm/RowIterator.h>
#include <string>
#include <functional>
#include <exception>
#include <future>
namespace drogon
{
namespace orm
{
typedef std::function<void(const Result &)> ResultCallback;
typedef std::function<void(const DrogonDbException &)> ExceptionCallback;
@ -43,28 +42,33 @@ class DbClient : public trantor::NonCopyable
{
public:
virtual ~DbClient(){};
/// 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,
* i.e., \' and \\.
* Example:
* host=localhost port=5432 dbname=mydb connect_timeout=10 password=''
* The currently recognized parameter key words are:
* - host: can be either a host name or an IP address.
* - port: Port number to connect to at the server host.
* - 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.
*
* 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'.
*
* @param connNum: The number of connections to database server;
*/
/// 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,
* i.e., \' and \\.
* Example:
* host=localhost port=5432 dbname=mydb connect_timeout=10 password=''
* The currently recognized parameter key words are:
* - host: can be either a host name or an IP address.
* - port: Port number to connect to at the server host.
* - 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.
*
* 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'.
*
* @param connNum: The number of connections to database server;
*/
#if USE_POSTGRESQL
static std::shared_ptr<DbClient> newPgClient(const std::string &connInfo, const size_t connNum);
#endif
@ -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.
* NOTE:
*
* @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.
*
* Strictly speaking, try not to splice SQL statements dynamically, Instead, use the constant sql string
* 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.
*
* 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,64 +116,67 @@ 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
// 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);
{
auto binder = *this << sql;
(void)std::initializer_list<int>{(binder << std::forward<Arguments>(args), 0)...};
//Use blocking mode
// Use blocking mode
binder << Mode::Blocking;
binder >> [&r](const Result &result) {
r = result;
};
binder.exec(); //exec may be throw exception;
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,
* The Boolean type parameter in the callback function indicates whether the
* @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;
@ -190,9 +198,9 @@ class Transaction : public DbClient
{
public:
virtual void rollback() = 0;
//virtual void commit() = 0;
// virtual void commit() = 0;
virtual void setCommitCallback(const std::function<void(bool)> &commitCallback) = 0;
};
} // namespace orm
} // namespace drogon
} // namespace orm
} // namespace drogon

View File

@ -7,7 +7,7 @@
* or contact the author.
*/
//taken from libpqxx and modified
// taken from libpqxx and modified
/**
*
@ -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
@ -79,10 +80,11 @@ class DrogonDbException
{
static std::exception except;
return except;
} //[t00]
} //[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
@ -488,5 +490,5 @@ class TooManyConnections : public BrokenConnection
// const char sqlstate[] = nullptr) : plpgsql_error(err, Q, sqlstate) {}
// };
typedef std::function<void(const DrogonDbException &)> DrogonDbExceptionCallback;
} // namespace orm
} // namespace drogon
} // namespace orm
} // namespace drogon

View File

@ -12,24 +12,23 @@
*
*/
//Taken from libpqxx and modified.
//The license for libpqxx can be found in the COPYING file.
// Taken from libpqxx and modified.
// The license for libpqxx can be found in the COPYING file.
#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,9 +77,8 @@ 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
* in the result set, and can be converted to various types.
*/
@ -99,7 +94,7 @@ class Field
bool isNull() const;
/// Read as plain C string
/**
/**
* Since the field's data is stored internally in the form of a
* zero-terminated C string, this is the fastest way to read it. Use the
* to() or as() functions to convert the string to other types such as
@ -112,7 +107,7 @@ class Field
T as() const
{
auto _data = _result.getValue(_row, _column);
//auto _dataLength = _result.getLength(_row, _column);
// auto _dataLength = _result.getLength(_row, _column);
// For binary format!
// if (_dataLength == 1)
// {
@ -139,7 +134,7 @@ class Field
}
/// Parse the field as an SQL array.
/**
/**
* Call the parser to retrieve values (and structure) from the array.
*
* Make sure the @c result object stays alive until parsing is finished. If
@ -205,5 +200,5 @@ string_view Field::as<string_view>() const;
// std::vector<int32_t> Field::as<std::vector<int32_t>>() const;
// template <>
// std::vector<int64_t> Field::as<std::vector<int64_t>>() const;
} // namespace orm
} // namespace drogon
} // namespace orm
} // namespace drogon

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