mirror of
https://gitee.com/an-tao/drogon.git
synced 2024-12-02 03:38:03 +08:00
Add .clang-format
This commit is contained in:
parent
3647f8c80e
commit
be08aba9d1
20
.clang-format
Normal file
20
.clang-format
Normal file
@ -0,0 +1,20 @@
|
||||
---
|
||||
BasedOnStyle: Google
|
||||
BreakBeforeBraces: Allman
|
||||
AllowAllParametersOfDeclarationOnNextLine: false
|
||||
IndentWidth: '4'
|
||||
Language: Cpp
|
||||
UseTab: Never
|
||||
ColumnLimit: 128
|
||||
SortIncludes: false
|
||||
AllowShortFunctionsOnASingleLine: None
|
||||
AllowShortBlocksOnASingleLine: false
|
||||
AllowShortIfStatementsOnASingleLine: false
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
BinPackArguments: false
|
||||
BinPackParameters: false
|
||||
ExperimentalAutoDetectBinPacking: false
|
||||
BreakConstructorInitializersBeforeComma: false
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: true
|
||||
AccessModifierOffset: -2
|
||||
...
|
3
format.sh
Executable file
3
format.sh
Executable file
@ -0,0 +1,3 @@
|
||||
#!/bin/sh
|
||||
|
||||
find lib orm_lib -name *.h -o -name *.cc|xargs clang-format -i -style=file
|
55
lib/inc/drogon/CacheMap.h
Executable file → Normal file
55
lib/inc/drogon/CacheMap.h
Executable file → Normal 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
120
lib/inc/drogon/Cookie.h
Executable file → Normal file
@ -13,51 +13,113 @@
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <trantor/utils/Date.h>
|
||||
#include <string>
|
||||
#include <trantor/utils/Date.h>
|
||||
|
||||
namespace drogon
|
||||
{
|
||||
|
||||
class Cookie
|
||||
{
|
||||
public:
|
||||
Cookie(const std::string &key, const std::string &value)
|
||||
: _key(key),
|
||||
_value(value)
|
||||
Cookie(const std::string &key, const std::string &value) : _key(key), _value(value)
|
||||
{
|
||||
}
|
||||
Cookie() = default;
|
||||
~Cookie() {}
|
||||
void setExpiresDate(const trantor::Date &date) { _expiresDate = date; }
|
||||
void setHttpOnly(bool only) { _httpOnly = only; }
|
||||
void setSecure(bool secure) { _secure = secure; }
|
||||
void setDomain(const std::string &domain) { _domain = domain; }
|
||||
void setPath(const std::string &path) { _path = path; }
|
||||
void setKey(const std::string &key) { _key = key; }
|
||||
void setValue(const std::string &value) { _value = value; }
|
||||
~Cookie()
|
||||
{
|
||||
}
|
||||
void setExpiresDate(const trantor::Date &date)
|
||||
{
|
||||
_expiresDate = date;
|
||||
}
|
||||
void setHttpOnly(bool only)
|
||||
{
|
||||
_httpOnly = only;
|
||||
}
|
||||
void setSecure(bool secure)
|
||||
{
|
||||
_secure = secure;
|
||||
}
|
||||
void setDomain(const std::string &domain)
|
||||
{
|
||||
_domain = domain;
|
||||
}
|
||||
void setPath(const std::string &path)
|
||||
{
|
||||
_path = path;
|
||||
}
|
||||
void setKey(const std::string &key)
|
||||
{
|
||||
_key = key;
|
||||
}
|
||||
void setValue(const std::string &value)
|
||||
{
|
||||
_value = value;
|
||||
}
|
||||
|
||||
std::string cookieString() const;
|
||||
std::string getCookieString() const { return cookieString(); }
|
||||
|
||||
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
29
lib/inc/drogon/DrClassMap.h
Executable file → Normal 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
18
lib/inc/drogon/DrObject.h
Executable file → Normal 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
7
lib/inc/drogon/DrTemplate.h
Executable file → Normal file
@ -18,12 +18,13 @@
|
||||
#include <drogon/DrTemplateBase.h>
|
||||
namespace drogon
|
||||
{
|
||||
|
||||
template <typename T>
|
||||
class DrTemplate : public DrObject<T>, public DrTemplateBase
|
||||
{
|
||||
protected:
|
||||
DrTemplate() {}
|
||||
DrTemplate()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace drogon
|
||||
} // namespace drogon
|
||||
|
18
lib/inc/drogon/DrTemplateBase.h
Executable file → Normal file
18
lib/inc/drogon/DrTemplateBase.h
Executable file → Normal file
@ -16,17 +16,17 @@
|
||||
|
||||
#include <drogon/DrObject.h>
|
||||
#include <drogon/HttpViewData.h>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
namespace drogon
|
||||
{
|
||||
|
||||
typedef HttpViewData DrTemplateData;
|
||||
|
||||
/// The templating engine class
|
||||
/**
|
||||
* This class can generate a text string from the template file and template data.
|
||||
* This class can generate a text string from the template file and template
|
||||
* data.
|
||||
* For more details on the template file, see the wiki site (the 'View' section)
|
||||
*/
|
||||
class DrTemplateBase : public virtual DrObjectBase
|
||||
@ -35,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
494
lib/inc/drogon/HttpAppFramework.h
Executable file → Normal 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
77
lib/inc/drogon/HttpBinder.h
Executable file → Normal 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
|
||||
|
@ -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
94
lib/inc/drogon/HttpController.h
Executable file → Normal file
@ -16,22 +16,20 @@
|
||||
|
||||
#include <drogon/DrObject.h>
|
||||
#include <drogon/HttpAppFramework.h>
|
||||
#include <trantor/utils/Logger.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <trantor/utils/Logger.h>
|
||||
#include <vector>
|
||||
|
||||
/// For more details on the class, see the wiki site (the 'HttpController' section)
|
||||
/// For more details on the class, see the wiki site (the 'HttpController'
|
||||
/// section)
|
||||
|
||||
#define METHOD_LIST_BEGIN \
|
||||
static void initPathRouting() \
|
||||
{
|
||||
#define METHOD_ADD(method, pattern, filters...) registerMethod(&method, pattern, {filters}, true, #method)
|
||||
|
||||
#define METHOD_ADD(method, pattern, filters...) \
|
||||
registerMethod(&method, pattern, {filters}, true, #method)
|
||||
|
||||
#define ADD_METHOD_TO(method, path_pattern, filters...) \
|
||||
registerMethod(&method, path_pattern, {filters}, false, #method)
|
||||
#define ADD_METHOD_TO(method, path_pattern, filters...) registerMethod(&method, path_pattern, {filters}, false, #method)
|
||||
|
||||
#define METHOD_LIST_END \
|
||||
return; \
|
||||
@ -39,7 +37,6 @@
|
||||
|
||||
namespace drogon
|
||||
{
|
||||
|
||||
class HttpControllerBase
|
||||
{
|
||||
};
|
||||
@ -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
33
lib/inc/drogon/HttpFilter.h
Executable file → Normal 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
115
lib/inc/drogon/HttpRequest.h
Executable file → Normal 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> ¶meters() const = 0;
|
||||
const std::unordered_map<std::string, std::string> &getParameters() const { return parameters(); }
|
||||
const std::unordered_map<std::string, std::string> &getParameters() const
|
||||
{
|
||||
return parameters();
|
||||
}
|
||||
|
||||
/// Get a parameter identified by the @param key
|
||||
virtual const std::string &getParameter(const std::string &key, const std::string &defaultVal = std::string()) const = 0;
|
||||
|
||||
/// Return the remote IP address and port
|
||||
virtual const trantor::InetAddress &peerAddr() const = 0;
|
||||
const trantor::InetAddress &getPeerAddr() const { return peerAddr(); }
|
||||
const trantor::InetAddress &getPeerAddr() const
|
||||
{
|
||||
return peerAddr();
|
||||
}
|
||||
|
||||
/// Return the local IP address and port
|
||||
virtual const trantor::InetAddress &localAddr() const = 0;
|
||||
const trantor::InetAddress &getLocalAddr() const { return localAddr(); }
|
||||
const trantor::InetAddress &getLocalAddr() const
|
||||
{
|
||||
return localAddr();
|
||||
}
|
||||
|
||||
/// Return the creation timestamp set by the framework.
|
||||
virtual const trantor::Date &creationDate() const = 0;
|
||||
const trantor::Date &getCreationDate() const { return creationDate(); }
|
||||
const trantor::Date &getCreationDate() const
|
||||
{
|
||||
return creationDate();
|
||||
}
|
||||
|
||||
/// Get the Json object of the request
|
||||
/**
|
||||
* 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
99
lib/inc/drogon/HttpResponse.h
Executable file → Normal 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
30
lib/inc/drogon/HttpSimpleController.h
Executable file → Normal 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
|
||||
|
@ -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
7
lib/inc/drogon/HttpViewBase.h
Executable file → Normal 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
20
lib/inc/drogon/HttpViewData.h
Executable file → Normal file
@ -14,24 +14,24 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <trantor/utils/Logger.h>
|
||||
#include <drogon/config.h>
|
||||
#include <trantor/utils/Logger.h>
|
||||
#include <trantor/utils/MsgBuffer.h>
|
||||
|
||||
#include <unordered_map>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace drogon
|
||||
{
|
||||
|
||||
/// This class represents the data set displayed in views.
|
||||
class HttpViewData
|
||||
{
|
||||
public:
|
||||
/// The function template is used to get an item in the data set by the @param key.
|
||||
/// The function template is used to get an item in the data set by the @param
|
||||
/// key.
|
||||
template <typename T>
|
||||
const T &get(const std::string &key, T &&nullVal = T()) const
|
||||
{
|
||||
@ -60,7 +60,8 @@ class HttpViewData
|
||||
_viewData[key] = obj;
|
||||
}
|
||||
|
||||
/// Insert an item identified by the @param key into the data set; The item is converted to a string.
|
||||
/// Insert an item identified by the @param key into the data set; The item is
|
||||
/// converted to a string.
|
||||
template <typename T>
|
||||
void insertAsString(const std::string &key, T &&val)
|
||||
{
|
||||
@ -70,8 +71,7 @@ class HttpViewData
|
||||
}
|
||||
|
||||
/// Insert a formated string identified by the @param key.
|
||||
void insertFormattedString(const std::string &key,
|
||||
const char *format, ...)
|
||||
void insertFormattedString(const std::string &key, const char *format, ...)
|
||||
{
|
||||
std::string strBuffer;
|
||||
strBuffer.resize(128);
|
||||
@ -133,4 +133,4 @@ class HttpViewData
|
||||
mutable ViewDataMap _viewData;
|
||||
};
|
||||
|
||||
} // namespace drogon
|
||||
} // namespace drogon
|
||||
|
@ -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
|
||||
|
@ -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
56
lib/inc/drogon/MultiPart.h
Executable file → Normal 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
10
lib/inc/drogon/NotFound.h
Executable file → Normal 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
9
lib/inc/drogon/Session.h
Executable file → Normal 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
|
||||
|
@ -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
|
@ -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
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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>
|
@ -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
|
@ -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
64
lib/inc/drogon/utils/FunctionTraits.h
Executable file → Normal file
@ -16,10 +16,10 @@
|
||||
|
||||
#include <drogon/DrObject.h>
|
||||
#include <drogon/utils/ClassTraits.h>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <memory>
|
||||
#include <functional>
|
||||
|
||||
namespace drogon
|
||||
{
|
||||
@ -30,14 +30,12 @@ typedef std::shared_ptr<HttpResponse> HttpResponsePtr;
|
||||
|
||||
namespace internal
|
||||
{
|
||||
|
||||
template <typename>
|
||||
struct FunctionTraits;
|
||||
|
||||
//functor,lambda,std::function...
|
||||
// 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
11
lib/inc/drogon/utils/Utilities.h
Executable file → Normal file
@ -15,16 +15,15 @@
|
||||
#pragma once
|
||||
|
||||
#include <drogon/config.h>
|
||||
#include <trantor/utils/Date.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <trantor/utils/Date.h>
|
||||
#include <vector>
|
||||
|
||||
namespace drogon
|
||||
{
|
||||
namespace utils
|
||||
{
|
||||
|
||||
/// Determine if the string is an integer
|
||||
bool isInteger(const std::string &str);
|
||||
|
||||
@ -92,5 +91,5 @@ std::string formattedString(const char *format, ...);
|
||||
*/
|
||||
int createPath(const std::string &path);
|
||||
|
||||
} // namespace utils
|
||||
} // namespace drogon
|
||||
} // namespace utils
|
||||
} // namespace drogon
|
||||
|
@ -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
|
@ -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
|
@ -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"]);
|
||||
|
@ -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
4
lib/src/Cookie.cc
Executable file → Normal 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
7
lib/src/DrClassMap.cc
Executable file → Normal 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
6
lib/src/DrTemplateBase.cc
Executable file → Normal 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;
|
||||
|
||||
|
@ -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
|
@ -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
214
lib/src/HttpAppFrameworkImpl.cc
Executable file → Normal 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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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 ¶meter : qureyPara)
|
||||
{
|
||||
if (ctrlBinderPtr->_queryParametersPlaces.find(parameter.first) !=
|
||||
ctrlBinderPtr->_queryParametersPlaces.end())
|
||||
if (ctrlBinderPtr->_queryParametersPlaces.find(parameter.first) != ctrlBinderPtr->_queryParametersPlaces.end())
|
||||
{
|
||||
auto place = ctrlBinderPtr->_queryParametersPlaces.find(parameter.first)->second;
|
||||
if (place > params.size())
|
||||
@ -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));
|
||||
});
|
||||
}
|
||||
}
|
@ -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
|
@ -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);
|
||||
|
@ -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
69
lib/src/HttpRequestImpl.cc
Executable file → Normal 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
186
lib/src/HttpRequestImpl.h
Executable file → Normal 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
21
lib/src/HttpRequestParser.cc
Executable file → Normal 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
30
lib/src/HttpRequestParser.h
Executable file → Normal 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
38
lib/src/HttpResponseImpl.cc
Executable file → Normal 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
37
lib/src/HttpResponseImpl.h
Executable file → Normal 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
34
lib/src/HttpResponseParser.cc
Executable file → Normal 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
6
lib/src/HttpResponseParser.h
Executable file → Normal 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
62
lib/src/HttpServer.cc
Executable file → Normal 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
29
lib/src/HttpServer.h
Executable file → Normal 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
|
||||
|
@ -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));
|
||||
});
|
||||
}
|
||||
}
|
@ -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
|
||||
|
@ -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
|
@ -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
6
lib/src/HttpViewBase.cc
Executable file → Normal 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)
|
||||
{
|
||||
|
@ -24,21 +24,21 @@ std::string HttpViewData::htmlTranslate(const std::string &str)
|
||||
{
|
||||
switch (ch)
|
||||
{
|
||||
case '"':
|
||||
ret.append(""");
|
||||
break;
|
||||
case '<':
|
||||
ret.append("<");
|
||||
break;
|
||||
case '>':
|
||||
ret.append(">");
|
||||
break;
|
||||
case '&':
|
||||
ret.append("&");
|
||||
break;
|
||||
default:
|
||||
ret.push_back(ch);
|
||||
break;
|
||||
case '"':
|
||||
ret.append(""");
|
||||
break;
|
||||
case '<':
|
||||
ret.append("<");
|
||||
break;
|
||||
case '>':
|
||||
ret.append(">");
|
||||
break;
|
||||
case '&':
|
||||
ret.append("&");
|
||||
break;
|
||||
default:
|
||||
ret.push_back(ch);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
|
@ -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())
|
||||
{
|
||||
|
@ -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
29
lib/src/MultiPart.cc
Executable file → Normal 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
44
lib/src/NotFound.cc
Executable file → Normal 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();
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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
33
lib/src/SharedLibManager.cc
Executable file → Normal 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
6
lib/src/SharedLibManager.h
Executable file → Normal 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
|
||||
|
@ -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
321
lib/src/Utilities.cc
Executable file → Normal 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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
@ -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!";
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
@ -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;
|
||||
|
@ -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:
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
12
lib/tests/CacheMapTest.cc
Executable file → Normal file
@ -1,11 +1,11 @@
|
||||
#include <drogon/CacheMap.h>
|
||||
#include <trantor/utils/Logger.h>
|
||||
#include <trantor/net/EventLoopThread.h>
|
||||
#include <drogon/utils/Utilities.h>
|
||||
#include <unistd.h>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <iostream>
|
||||
#include <trantor/net/EventLoopThread.h>
|
||||
#include <trantor/utils/Logger.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int main()
|
||||
{
|
||||
@ -21,9 +21,7 @@ int main()
|
||||
std::cout << i << " cache item erased!" << std::endl;
|
||||
});
|
||||
}
|
||||
cache.insert("1", "first", 20, [=] {
|
||||
LOG_DEBUG << "first item in cache timeout,erase!";
|
||||
});
|
||||
cache.insert("1", "first", 20, [=] { LOG_DEBUG << "first item in cache timeout,erase!"; });
|
||||
cache.insert("2", "second", 5);
|
||||
cache.insert("3", "third", 5);
|
||||
std::thread thread1([&] {
|
||||
|
28
lib/tests/CacheMapTest2.cc
Executable file → Normal file
28
lib/tests/CacheMapTest2.cc
Executable file → Normal file
@ -1,16 +1,15 @@
|
||||
#include <drogon/CacheMap.h>
|
||||
#include <trantor/utils/Logger.h>
|
||||
#include <trantor/net/EventLoopThread.h>
|
||||
#include <drogon/utils/Utilities.h>
|
||||
#include <unistd.h>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <trantor/net/EventLoopThread.h>
|
||||
#include <trantor/utils/Logger.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int main()
|
||||
{
|
||||
|
||||
trantor::Logger::setLogLevel(trantor::Logger::TRACE);
|
||||
trantor::EventLoopThread loopThread;
|
||||
loopThread.run();
|
||||
@ -19,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();
|
||||
}
|
||||
|
@ -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
0
lib/tests/CookiesTest.cc
Executable file → Normal 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)
|
||||
{
|
||||
|
@ -5,8 +5,6 @@ int main()
|
||||
drogon::HttpViewData data;
|
||||
std::cout << (data.insert("1", 1), data.get<int>("1")) << std::endl;
|
||||
std::cout << (data.insertAsString("2", 2.0), data.get<std::string>("2")) << std::endl;
|
||||
std::cout << (data.insertFormattedString("3", "third value is %d", 3),
|
||||
data.get<std::string>("3"))
|
||||
<< std::endl;
|
||||
std::cout << (data.insertFormattedString("3", "third value is %d", 3), data.get<std::string>("3")) << std::endl;
|
||||
std::cout << (data.insertAsString("4", "4"), data.get<std::string>("4")) << std::endl;
|
||||
}
|
||||
|
@ -4,11 +4,6 @@
|
||||
|
||||
int main()
|
||||
{
|
||||
std::thread([]() {
|
||||
drogon::app().getLoop()->runEvery(1, []() {
|
||||
std::cout << "!" << std::endl;
|
||||
});
|
||||
})
|
||||
.detach();
|
||||
std::thread([]() { drogon::app().getLoop()->runEvery(1, []() { std::cout << "!" << std::endl; }); }).detach();
|
||||
drogon::app().run();
|
||||
}
|
@ -2,5 +2,9 @@
|
||||
#include <iostream>
|
||||
int main()
|
||||
{
|
||||
std::cout << Md5Encode::encode("1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890") << std::endl;
|
||||
std::cout << Md5Encode::encode(
|
||||
"123456789012345678901234567890123456789012345"
|
||||
"678901234567890123456789012345678901234567890"
|
||||
"1234567890")
|
||||
<< std::endl;
|
||||
}
|
@ -9,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');
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
Loading…
Reference in New Issue
Block a user