1
0
mirror of https://github.com/VCMP-SqMod/SqMod.git synced 2024-11-08 00:37:15 +01:00

Initial implementation of WebSocket client.

This commit is contained in:
Sandu Liviu Catalin 2021-09-07 20:55:05 +03:00
parent 1bd1b5545b
commit 5dcc57a130
21 changed files with 29950 additions and 1 deletions

View File

@ -76,6 +76,7 @@ add_library(SqModule MODULE SqBase.hpp Main.cpp
Library/IO/Stream.cpp Library/IO/Stream.hpp Library/IO/Stream.cpp Library/IO/Stream.hpp
Library/JSON.cpp Library/JSON.hpp Library/JSON.cpp Library/JSON.hpp
Library/MMDB.cpp Library/MMDB.hpp Library/MMDB.cpp Library/MMDB.hpp
Library/Net.cpp Library/Net.hpp
Library/Numeric.cpp Library/Numeric.hpp Library/Numeric.cpp Library/Numeric.hpp
Library/Numeric/Long.cpp Library/Numeric/Long.hpp Library/Numeric/Long.cpp Library/Numeric/Long.hpp
Library/Numeric/Math.cpp Library/Numeric/Math.hpp Library/Numeric/Math.cpp Library/Numeric/Math.hpp
@ -133,7 +134,7 @@ if(WIN32 OR MINGW)
target_link_libraries(SqModule wsock32 ws2_32 shlwapi) target_link_libraries(SqModule wsock32 ws2_32 shlwapi)
endif() endif()
# Link to base libraries # Link to base libraries
target_link_libraries(SqModule Squirrel fmt::fmt SimpleINI TinyDir xxHash ConcurrentQueue SAJSON CPR PUGIXML maxminddb libzmq-static) target_link_libraries(SqModule Squirrel fmt::fmt SimpleINI TinyDir xxHash ConcurrentQueue SAJSON CPR PUGIXML CivetWeb maxminddb libzmq-static)
# Link to POCO libraries # Link to POCO libraries
target_link_libraries(SqModule Poco::Foundation Poco::Crypto Poco::Data Poco::Net Poco::JSON Poco::XML) target_link_libraries(SqModule Poco::Foundation Poco::Crypto Poco::Data Poco::Net Poco::JSON Poco::XML)
# Does POCO have SQLite support? # Does POCO have SQLite support?

View File

@ -48,6 +48,7 @@ extern void TerminatePrivileges();
extern void TerminateRoutines(); extern void TerminateRoutines();
extern void TerminateCommands(); extern void TerminateCommands();
extern void TerminateSignals(); extern void TerminateSignals();
extern void TerminateNet();
extern void TerminatePocoNet(); extern void TerminatePocoNet();
extern void TerminatePocoData(); extern void TerminatePocoData();
@ -548,6 +549,9 @@ void Core::Terminate(bool shutdown)
// Release announcers // Release announcers
AnnounceTerminate(); AnnounceTerminate();
cLogDbg(m_Verbosity >= 1, "Announcer terminated"); cLogDbg(m_Verbosity >= 1, "Announcer terminated");
// Release network
TerminateNet();
cLogDbg(m_Verbosity >= 1, "Network terminated");
// Release Poco statement results // Release Poco statement results
TerminatePocoNet(); TerminatePocoNet();
TerminatePocoData(); TerminatePocoData();

203
module/Library/Net.cpp Normal file
View File

@ -0,0 +1,203 @@
// ------------------------------------------------------------------------------------------------
#include "Library/Net.hpp"
// ------------------------------------------------------------------------------------------------
#include <sqratConst.h>
// ------------------------------------------------------------------------------------------------
namespace SqMod {
// ------------------------------------------------------------------------------------------------
SQMOD_DECL_TYPENAME(SqWebSocketClient, _SC("SqWebSocketClient"))
// ------------------------------------------------------------------------------------------------
static std::thread::id sMainThreadID{}; // Main thread ID
// ------------------------------------------------------------------------------------------------
void InitializeNet()
{
int f = MG_FEATURES_DEFAULT;
#ifndef NO_FILES
f |= MG_FEATURES_FILES;
#endif
#ifndef NO_SSL
f |= MG_FEATURES_SSL;
#endif
#ifndef NO_CGI
f |= MG_FEATURES_CGI;
#endif
#ifndef NO_CACHING
f |= MG_FEATURES_CACHE;
#endif
#ifdef USE_IPV6
f |= MG_FEATURES_CGI;
#endif
#ifdef USE_WEBSOCKET
f |= MG_FEATURES_WEBSOCKET;
#endif
#ifdef USE_SERVER_STATS
f |= MG_FEATURES_STATS;
#endif
#ifdef USE_ZLIB
f |= MG_FEATURES_COMPRESSION;
#endif
#ifdef USE_HTTP2
f |= MG_FEATURES_HTTP2;
#endif
#ifdef USE_X_DOM_SOCKET
f |= MG_FEATURES_X_DOMAIN_SOCKET;
#endif
mg_init_library(f);
}
// ------------------------------------------------------------------------------------------------
void TerminateNet()
{
// Go over all connections and try to terminate them
for (WebSocketClient * inst = WebSocketClient::sHead; inst && inst->mNext != WebSocketClient::sHead; inst = inst->mNext)
{
inst->Terminate(); // Terminate() the connection
}
}
// ------------------------------------------------------------------------------------------------
void ProcessNet()
{
// Go over all connections and allow them to process data
for (WebSocketClient * inst = WebSocketClient::sHead; inst && inst->mNext != WebSocketClient::sHead; inst = inst->mNext)
{
inst->Process();
}
}
// ------------------------------------------------------------------------------------------------
WebSocketClient & WebSocketClient::Connect()
{
// Make sure another connection does not exist
Invalid();
// Error buffer
char err_buf[128] = {0};
// Connect to the given WS or WSS (WS secure) server
mHandle = mg_connect_websocket_client(mHost.c_str(), mPort, mSecure?1:0,
err_buf, sizeof(err_buf), mPath.c_str(),
mOrigin.empty() ? nullptr : mOrigin.c_str(),
&WebSocketClient::DataHandler_,
&WebSocketClient::CloseHandler_,
this);
// Check if connection was possible
if (!mHandle)
{
STHROWF("Connection failed: {}", err_buf);
}
// Allow chaining
return *this;
}
// ------------------------------------------------------------------------------------------------
WebSocketClient & WebSocketClient::ConnectExt()
{
// Make sure another connection does not exist
Invalid();
// Error buffer
char err_buf[128] = {0};
// Connect to the given WS or WSS (WS secure) server
mHandle = mg_connect_websocket_client_extensions(mHost.c_str(), mPort, mSecure?1:0,
err_buf, sizeof(err_buf), mPath.c_str(),
mOrigin.empty() ? nullptr : mOrigin.c_str(),
mExtensions.empty() ? nullptr : mExtensions.c_str(),
&WebSocketClient::DataHandler_,
&WebSocketClient::CloseHandler_,
this);
// Check if connection was possible
if (!mHandle)
{
STHROWF("Connection failed: {}", err_buf);
}
// Allow chaining
return *this;
}
// ------------------------------------------------------------------------------------------------
int WebSocketClient::DataHandler(int flags, char * data, size_t data_len) noexcept
{
// Create a frame instance to store information and queue it
try
{
mQueue.enqueue(std::make_unique< Frame >(data, data_len, flags));
}
catch(...)
{
LogFtl("Failed to queue web-socket data");
}
// Return 1 to keep the connection open
return 1;
}
// ------------------------------------------------------------------------------------------------
void WebSocketClient::CloseHandler() noexcept
{
mClosing.store(true);
}
// ================================================================================================
void Register_Net(HSQUIRRELVM vm)
{
Table ns(vm);
// --------------------------------------------------------------------------------------------
ns.Bind(_SC("WebSocketClient"),
Class< WebSocketClient, NoCopy< WebSocketClient > >(ns.GetVM(), SqWebSocketClient::Str)
// Constructors
.Ctor()
.Ctor< StackStrF &, uint16_t, StackStrF & >()
.Ctor< StackStrF &, uint16_t, StackStrF &, bool >()
.Ctor< StackStrF &, uint16_t, StackStrF &, bool, StackStrF & >()
.Ctor< StackStrF &, uint16_t, StackStrF &, bool, StackStrF &, StackStrF & >()
// Meta-methods
.SquirrelFunc(_SC("_typename"), &SqWebSocketClient::Fn)
// Properties
.Prop(_SC("Tag"), &WebSocketClient::GetTag, &WebSocketClient::SetTag)
.Prop(_SC("Data"), &WebSocketClient::GetData, &WebSocketClient::SetData)
.Prop(_SC("Host"), &WebSocketClient::GetHost, &WebSocketClient::SetHost)
.Prop(_SC("Port"), &WebSocketClient::GetPort, &WebSocketClient::SetPort)
.Prop(_SC("Path"), &WebSocketClient::GetPath, &WebSocketClient::SetPath)
.Prop(_SC("Secure"), &WebSocketClient::GetSecure, &WebSocketClient::SetSecure)
.Prop(_SC("Origin"), &WebSocketClient::GetOrigin, &WebSocketClient::SetOrigin)
.Prop(_SC("Extensions"), &WebSocketClient::GetExtensions, &WebSocketClient::SetExtensions)
.Prop(_SC("OnData"), &WebSocketClient::GetOnData, &WebSocketClient::SetOnData)
.Prop(_SC("OnClose"), &WebSocketClient::GetOnClose, &WebSocketClient::SetOnClose)
.Prop(_SC("Valid"), &WebSocketClient::IsValid)
.Prop(_SC("Closing"), &WebSocketClient::IsClosing)
// Member Methods
.FmtFunc(_SC("SetTag"), &WebSocketClient::ApplyTag)
.FmtFunc(_SC("SetData"), &WebSocketClient::ApplyData)
.FmtFunc(_SC("SetHost"), &WebSocketClient::ApplyHost)
.Func(_SC("SetPort"), &WebSocketClient::ApplyPort)
.FmtFunc(_SC("SetPath"), &WebSocketClient::ApplyPath)
.Func(_SC("SetSecure"), &WebSocketClient::ApplySecure)
.FmtFunc(_SC("SetOrigin"), &WebSocketClient::ApplyOrigin)
.FmtFunc(_SC("SetExtensions"), &WebSocketClient::ApplyExtensions)
.CbFunc(_SC("BindOnData"), &WebSocketClient::BindOnData)
.CbFunc(_SC("BindOnClose"), &WebSocketClient::BindOnClose)
.Func(_SC("Connect"), &WebSocketClient::Connect)
.Func(_SC("ConnectExt"), &WebSocketClient::ConnectExt)
.Func(_SC("SendOpCode"), &WebSocketClient::SendOpCode)
.Func(_SC("SendBuffer"), &WebSocketClient::SendBuffer)
.FmtFunc(_SC("SendString"), &WebSocketClient::SendString)
.Func(_SC("Close"), &WebSocketClient::Close)
);
// --------------------------------------------------------------------------------------------
RootTable(vm).Bind(_SC("SqNet"), ns);
// --------------------------------------------------------------------------------------------
ConstTable(vm).Enum(_SC("SqWsOpCode"), Enumeration(vm)
.Const(_SC("Continuation"), static_cast< SQInteger >(MG_WEBSOCKET_OPCODE_CONTINUATION))
.Const(_SC("Text"), static_cast< SQInteger >(MG_WEBSOCKET_OPCODE_TEXT))
.Const(_SC("Binary"), static_cast< SQInteger >(MG_WEBSOCKET_OPCODE_BINARY))
.Const(_SC("ConnectionClose"), static_cast< SQInteger >(MG_WEBSOCKET_OPCODE_CONNECTION_CLOSE))
.Const(_SC("Ping"), static_cast< SQInteger >(MG_WEBSOCKET_OPCODE_PING))
.Const(_SC("Pong"), static_cast< SQInteger >(MG_WEBSOCKET_OPCODE_PONG))
);
// Main thread ID
sMainThreadID = std::this_thread::get_id();
}
} // Namespace:: SqMod

760
module/Library/Net.hpp Normal file
View File

@ -0,0 +1,760 @@
#pragma once
// ------------------------------------------------------------------------------------------------
#include "Library/IO/Buffer.hpp"
// ------------------------------------------------------------------------------------------------
#include <atomic>
// ------------------------------------------------------------------------------------------------
#include <sqratFunction.h>
#include <concurrentqueue.h>
#include <civetweb.h>
// ------------------------------------------------------------------------------------------------
namespace SqMod {
/* ------------------------------------------------------------------------------------------------
* WebSocket client implementation.
*/
struct WebSocketClient : public SqChainedInstances< WebSocketClient >
{
using Base = SqChainedInstances< WebSocketClient >;
/* --------------------------------------------------------------------------------------------
* WebSocket frame.
*/
struct Frame
{
/* ----------------------------------------------------------------------------------------
* Frame data.
*/
char * mData{nullptr};
/* ----------------------------------------------------------------------------------------
* Frame data capacity.
*/
uint32_t mSize{0};
/* ----------------------------------------------------------------------------------------
* Frame flags.
*/
int mFlags{0};
/* ----------------------------------------------------------------------------------------
* Default constructor.
*/
Frame() = default;
/* ----------------------------------------------------------------------------------------
* Explicit constructor.
*/
Frame(char * data, size_t size, int flags)
: mData(nullptr), mSize(static_cast< uint32_t >(size)), mFlags(flags)
{
// Do we need to allocate a buffer?
if (mSize != 0)
{
// Allocate the memory buffer.
mData = new char[mSize];
// Copy the data into the buffer we own
std::memcpy(mData, data, mSize);
}
}
/* ----------------------------------------------------------------------------------------
* Copy constructor (disabled).
*/
Frame(const Frame & o) = delete;
/* ----------------------------------------------------------------------------------------
* Move constructor (disabled).
*/
Frame(Frame && o) noexcept = delete;
/* ----------------------------------------------------------------------------------------
* Destructor.
*/
~Frame()
{
delete[] mData;
}
/* ----------------------------------------------------------------------------------------
* Copy assignment operator (disabled).
*/
Frame & operator = (const Frame & o) = delete;
/* ----------------------------------------------------------------------------------------
* Move assignment operator (disabled).
*/
Frame & operator = (Frame && o) noexcept = delete;
/* ----------------------------------------------------------------------------------------
* Forget about the associated memory buffer.
*/
void ForgetBuffer() noexcept
{
mData = nullptr;
mSize = 0;
}
};
/* --------------------------------------------------------------------------------------------
* Smart frame pointer.
*/
using FramePtr = std::unique_ptr< Frame >;
/* --------------------------------------------------------------------------------------------
* Queue of frames written from other threads.
*/
using FrameQueue = moodycamel::ConcurrentQueue< FramePtr >;
/* --------------------------------------------------------------------------------------------
* Connection handle.
*/
struct mg_connection * mHandle{nullptr};
/* --------------------------------------------------------------------------------------------
* Queue of frames that must be processed.
*/
FrameQueue mQueue{1024};
/* --------------------------------------------------------------------------------------------
* Callback to invoke when receiving data.
*/
Function mOnData{};
/* --------------------------------------------------------------------------------------------
* Callback to invoke when the socket is shutting down.
*/
Function mOnClose{};
/* --------------------------------------------------------------------------------------------
* User tag associated with this instance.
*/
String mTag{};
/* --------------------------------------------------------------------------------------------
* User data associated with this instance.
*/
LightObj mData{};
/* --------------------------------------------------------------------------------------------
* Server port.
*/
int mPort{0};
/* --------------------------------------------------------------------------------------------
* Make a secure connection to server.
*/
bool mSecure{false};
/* --------------------------------------------------------------------------------------------
* Whether the connection is currently closing.
*/
std::atomic< bool > mClosing{false};
/* --------------------------------------------------------------------------------------------
* Server host to connect to, i.e. "echo.websocket.org" or "192.168.1.1" or "localhost".
*/
String mHost{};
/* --------------------------------------------------------------------------------------------
* Server path you are trying to connect to, i.e. if connection to localhost/app, path should be "/app".
*/
String mPath{};
/* --------------------------------------------------------------------------------------------
* Value of the Origin HTTP header.
*/
String mOrigin{};
/* --------------------------------------------------------------------------------------------
* Extensions to include in the connection.
*/
String mExtensions{};
/* --------------------------------------------------------------------------------------------
* Default constructor.
*/
WebSocketClient()
: Base(), mHandle(nullptr), mQueue(1024), mOnData(), mOnClose(), mTag(), mData()
, mPort(0), mSecure(false), mClosing(false), mHost(), mPath(), mOrigin(), mExtensions()
{
ChainInstance(); // Remember this instance
}
/* --------------------------------------------------------------------------------------------
* Explicit constructor.
*/
WebSocketClient(StackStrF & host, uint16_t port, StackStrF & path)
: Base(), mHandle(nullptr), mQueue(1024), mOnData(), mOnClose(), mTag(), mData()
, mPort(port), mSecure(false), mClosing(false)
, mHost(host.mPtr, host.GetSize())
, mPath(path.mPtr, path.GetSize())
, mOrigin(), mExtensions()
{
ChainInstance(); // Remember this instance
}
/* --------------------------------------------------------------------------------------------
* Explicit constructor.
*/
WebSocketClient(StackStrF & host, uint16_t port, StackStrF & path, bool secure)
: Base(), mHandle(nullptr), mQueue(1024), mOnData(), mOnClose(), mTag(), mData()
, mPort(port), mSecure(secure), mClosing(false)
, mHost(host.mPtr, host.GetSize())
, mPath(path.mPtr, path.GetSize())
, mOrigin(), mExtensions()
{
ChainInstance(); // Remember this instance
}
/* --------------------------------------------------------------------------------------------
* Explicit constructor.
*/
WebSocketClient(StackStrF & host, uint16_t port, StackStrF & path, bool secure, StackStrF & origin)
: Base(), mHandle(nullptr), mQueue(1024), mOnData(), mOnClose(), mTag(), mData()
, mPort(port), mSecure(secure), mClosing(false)
, mHost(host.mPtr, host.GetSize())
, mPath(path.mPtr, path.GetSize())
, mOrigin(origin.mPtr, origin.GetSize())
, mExtensions()
{
ChainInstance(); // Remember this instance
}
/* --------------------------------------------------------------------------------------------
* Explicit constructor.
*/
WebSocketClient(StackStrF & host, uint16_t port, StackStrF & path, bool secure, StackStrF & origin, StackStrF & ext)
: Base(), mHandle(nullptr), mQueue(1024), mOnData(), mOnClose(), mTag(), mData()
, mPort(port), mSecure(secure), mClosing(false)
, mHost(host.mPtr, host.GetSize())
, mPath(path.mPtr, path.GetSize())
, mOrigin(origin.mPtr, origin.GetSize())
, mExtensions(ext.mPtr, ext.GetSize())
{
ChainInstance(); // Remember this instance
}
/* --------------------------------------------------------------------------------------------
* Copy constructor.
*/
WebSocketClient(const WebSocketClient &) = delete;
/* --------------------------------------------------------------------------------------------
* Move constructor.
*/
WebSocketClient(WebSocketClient &&) = delete;
/* --------------------------------------------------------------------------------------------
* Destructor. Closes the connection.
*/
~WebSocketClient()
{
// Is there a connection left to close?
if (mHandle != nullptr)
{
Close();
}
// Forget about this instance
UnchainInstance();
}
/* --------------------------------------------------------------------------------------------
* Copy assignment operator.
*/
WebSocketClient & operator = (const WebSocketClient &) = delete;
/* --------------------------------------------------------------------------------------------
* Move assignment operator.
*/
WebSocketClient & operator = (WebSocketClient &&) = delete;
/* --------------------------------------------------------------------------------------------
* Retrieve the associated user tag.
*/
SQMOD_NODISCARD const String & GetTag() const
{
return mTag;
}
/* --------------------------------------------------------------------------------------------
* Return whether the associated connection handle is valid.
*/
SQMOD_NODISCARD bool IsValid() const
{
return mHandle != nullptr;
}
/* --------------------------------------------------------------------------------------------
* Return whether the associated connection is closing.
* This is only valid inside the OnClose callback.
*/
SQMOD_NODISCARD bool IsClosing() const
{
return mClosing.load();
}
/* --------------------------------------------------------------------------------------------
* Modify the associated user tag.
*/
void SetTag(StackStrF & tag)
{
if (tag.mLen > 0)
{
mTag.assign(tag.mPtr, static_cast< size_t >(tag.mLen));
}
else
{
mTag.clear();
}
}
/* --------------------------------------------------------------------------------------------
* Modify the associated user tag.
*/
WebSocketClient & ApplyTag(StackStrF & tag)
{
SetTag(tag);
return *this;
}
/* --------------------------------------------------------------------------------------------
* Retrieve the associated user data.
*/
SQMOD_NODISCARD LightObj & GetData()
{
return mData;
}
/* --------------------------------------------------------------------------------------------
* Modify the associated user data.
*/
void SetData(LightObj & data)
{
mData = data;
}
/* --------------------------------------------------------------------------------------------
* Modify the associated user data.
*/
WebSocketClient & ApplyData(LightObj & data)
{
mData = data;
return *this;
}
/* --------------------------------------------------------------------------------------------
* Make sure a connection exists.
*/
void Validate() const
{
if (mHandle == nullptr)
{
STHROWF("No connection was made to server ({}:{}{})", mHost, mPort, mPath);
}
}
/* --------------------------------------------------------------------------------------------
* Return a valid connection.
*/
SQMOD_NODISCARD struct mg_connection * Valid() const
{
Validate();
return mHandle;
}
/* --------------------------------------------------------------------------------------------
* Make sure a connection does not exist.
*/
void Invalid() const
{
if (mHandle != nullptr)
{
STHROWF("Connection already made to server ({}:{}{})", mHost, mPort, mPath);
}
}
/* --------------------------------------------------------------------------------------------
* Retrieve the associated server host.
*/
SQMOD_NODISCARD const String & GetHost() const
{
return mHost;
}
/* --------------------------------------------------------------------------------------------
* Modify the associated server host.
*/
void SetHost(StackStrF & host)
{
Invalid();
// Is there a valid host?
if (host.mLen > 0)
{
mHost.assign(host.mPtr, static_cast< size_t >(host.mLen));
}
else
{
mHost.clear();
}
}
/* --------------------------------------------------------------------------------------------
* Modify the associated server host.
*/
WebSocketClient & ApplyHost(StackStrF & host)
{
SetHost(host);
return *this;
}
/* --------------------------------------------------------------------------------------------
* Retrieve the associated server path.
*/
SQMOD_NODISCARD const String & GetPath() const
{
return mPath;
}
/* --------------------------------------------------------------------------------------------
* Modify the associated server path.
*/
void SetPath(StackStrF & path)
{
Invalid();
// Is there a valid path?
if (path.mLen > 0)
{
mPath.assign(path.mPtr, static_cast< size_t >(path.mLen));
}
else
{
mPath.clear();
}
}
/* --------------------------------------------------------------------------------------------
* Modify the associated server path.
*/
WebSocketClient & ApplyPath(StackStrF & path)
{
SetPath(path);
return *this;
}
/* --------------------------------------------------------------------------------------------
* Retrieve the associated origin value.
*/
SQMOD_NODISCARD const String & GetOrigin() const
{
return mOrigin;
}
/* --------------------------------------------------------------------------------------------
* Modify the associated origin value.
*/
void SetOrigin(StackStrF & origin)
{
Invalid();
// Is there a valid origin?
if (origin.mLen > 0)
{
mOrigin.assign(origin.mPtr, static_cast< size_t >(origin.mLen));
}
else
{
mOrigin.clear();
}
}
/* --------------------------------------------------------------------------------------------
* Modify the associated origin value.
*/
WebSocketClient & ApplyOrigin(StackStrF & origin)
{
SetOrigin(origin);
return *this;
}
/* --------------------------------------------------------------------------------------------
* Retrieve the associated connection extensions.
*/
SQMOD_NODISCARD const String & GetExtensions() const
{
return mExtensions;
}
/* --------------------------------------------------------------------------------------------
* Modify the associated connection extensions.
*/
void SetExtensions(StackStrF & ext)
{
Invalid();
// Is there a valid extension?
if (ext.mLen > 0)
{
mExtensions.assign(ext.mPtr, static_cast< size_t >(ext.mLen));
}
else
{
mExtensions.clear();
}
}
/* --------------------------------------------------------------------------------------------
* Modify the associated connection extensions.
*/
WebSocketClient & ApplyExtensions(StackStrF & ext)
{
SetExtensions(ext);
return *this;
}
/* --------------------------------------------------------------------------------------------
* Retrieve the associated server port number.
*/
SQMOD_NODISCARD int GetPort() const
{
return mPort;
}
/* --------------------------------------------------------------------------------------------
* Modify the associated server port number.
*/
void SetPort(int port)
{
Invalid();
// Is there a valid port?
if (port < 0 || port > 65535)
{
STHROWF("Invalid port number: {0} < 0 || {0} > 65535", port);
}
else
{
mPort = port;
}
}
/* --------------------------------------------------------------------------------------------
* Modify the associated server port number.
*/
WebSocketClient & ApplyPort(int port)
{
SetPort(port);
return *this;
}
/* --------------------------------------------------------------------------------------------
* Retrieve the associated SSL status.
*/
SQMOD_NODISCARD bool GetSecure() const
{
return mSecure;
}
/* --------------------------------------------------------------------------------------------
* Modify the associated SSL status.
*/
void SetSecure(bool secure)
{
Invalid();
mSecure = secure;
}
/* --------------------------------------------------------------------------------------------
* Modify the associated SSL status.
*/
WebSocketClient & ApplySecure(bool secure)
{
SetSecure(secure);
return *this;
}
/* --------------------------------------------------------------------------------------------
* Retrieve the associated data callback.
*/
SQMOD_NODISCARD Function & GetOnData()
{
return mOnData;
}
/* --------------------------------------------------------------------------------------------
* Modify the associated data callback.
*/
void SetOnData(Function & cb)
{
mOnData = cb;
}
/* --------------------------------------------------------------------------------------------
* Modify the associated data callback.
*/
WebSocketClient & BindOnData(Function & cb)
{
mOnData = cb;
return *this;
}
/* --------------------------------------------------------------------------------------------
* Retrieve the associated close callback.
*/
SQMOD_NODISCARD Function & GetOnClose()
{
return mOnClose;
}
/* --------------------------------------------------------------------------------------------
* Modify the associated close callback.
*/
void SetOnClose(Function & cb)
{
mOnClose = cb;
}
/* --------------------------------------------------------------------------------------------
* Modify the associated close callback.
*/
WebSocketClient & BindOnClose(Function & cb)
{
mOnClose = cb;
return *this;
}
/* --------------------------------------------------------------------------------------------
* Connect to a web-socket as a client.
*/
WebSocketClient & Connect();
/* --------------------------------------------------------------------------------------------
* Connect to a web-socket as a client with specific extensions.
*/
WebSocketClient & ConnectExt();
/* --------------------------------------------------------------------------------------------
* Close client connection.
*/
void Close()
{
mg_close_connection(Valid());
// Prevent further use
mHandle = nullptr;
// Process pending events
Process(true);
}
/* --------------------------------------------------------------------------------------------
* Sends the contents of the given buffer through the socket as a single frame.
*/
SQMOD_NODISCARD SQInteger SendOpCode(SqBuffer & buf, SQInteger opcode)
{
return mg_websocket_client_write(Valid(), static_cast< int >(opcode), nullptr, 0);
}
/* --------------------------------------------------------------------------------------------
* Sends the contents of the given buffer through the socket as a single frame.
*/
SQMOD_NODISCARD SQInteger SendBuffer(SqBuffer & buf, SQInteger opcode)
{
return mg_websocket_client_write(Valid(), static_cast< int >(opcode), buf.Valid().Data(), buf.Valid().Position());
}
/* --------------------------------------------------------------------------------------------
* Sends the contents of the given string through the socket as a single frame.
*/
SQMOD_NODISCARD SQInteger SendString(SQInteger opcode, StackStrF & str)
{
return mg_websocket_client_write(Valid(), static_cast< int >(opcode), str.mPtr, static_cast< size_t >(str.mLen));
}
/* --------------------------------------------------------------------------------------------
* Process received data.
*/
void Process(bool force = false)
{
// Is there a valid connection?
if (mHandle == nullptr && !force)
{
return; // No point in going forward
}
FramePtr frame;
// See if connection is closing
const bool closing = mClosing.load();
// Is the connection closing?
if (closing)
{
mHandle = nullptr; // Prevent further use
}
// Retrieve each frame individually and process it
for (size_t count = mQueue.size_approx(), n = 0; n <= count; ++n)
{
// Try to get a frame from the queue
if (mQueue.try_dequeue(frame) && !mOnData.IsNull())
{
// Obtain a buffer from the frame
Buffer b(frame->mData, frame->mSize, frame->mSize, Buffer::OwnIt{});
// Backup the frame size before forgetting about it
const SQInteger size = static_cast< SQInteger >(frame->mSize);
// Take ownership of the memory
frame->ForgetBuffer();
// Transform the buffer into a script object
LightObj obj(SqTypeIdentity< SqBuffer >{}, SqVM(), std::move(b));
// Forward the event to the callback
mOnData.Execute(obj, size, frame->mFlags);
}
}
// Is the server closing the connection?
if (closing && !mOnClose.IsNull())
{
mOnClose.Execute(); // Let the user know
}
}
/* --------------------------------------------------------------------------------------------
* Used internally to release script resources, if any. The VM is about to be closed.
* If you don't close the connection yourself don't care about what is received after this.
*/
void Terminate()
{
// Process pending data
Process(true);
// Release callbacks
mOnData.Release();
mOnClose.Release();
// Release user data
mData.Release();
}
protected:
/* --------------------------------------------------------------------------------------------
* Callback for handling data received from the server
*/
int DataHandler(int flags, char * data, size_t data_len) noexcept;
/* --------------------------------------------------------------------------------------------
* Callback for handling a close message received from the server.
*/
void CloseHandler() noexcept;
/* --------------------------------------------------------------------------------------------
* Proxy for DataHandler()
*/
static int DataHandler_(struct mg_connection * SQ_UNUSED_ARG(c), int f, char * d, size_t n, void * u) noexcept
{
return reinterpret_cast< WebSocketClient * >(u)->DataHandler(f, d, n);
}
/* --------------------------------------------------------------------------------------------
* Proxy for CloseHandler();
*/
static void CloseHandler_(const struct mg_connection * SQ_UNUSED_ARG(c), void * u) noexcept
{
reinterpret_cast< WebSocketClient * >(u)->CloseHandler();
}
};
} // Namespace:: SqMod

View File

@ -18,10 +18,12 @@ static bool g_Reload = false;
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
//extern void InitExports(); //extern void InitExports();
extern void InitializeNet();
extern void InitializePocoDataConnectors(); extern void InitializePocoDataConnectors();
extern void ProcessRoutines(); extern void ProcessRoutines();
extern void ProcessTasks(); extern void ProcessTasks();
extern void ProcessThreads(); extern void ProcessThreads();
extern void ProcessNet();
/* ------------------------------------------------------------------------------------------------ /* ------------------------------------------------------------------------------------------------
* Will the scripts be reloaded at the end of the current event? * Will the scripts be reloaded at the end of the current event?
@ -168,6 +170,8 @@ static void OnServerFrame(float elapsed_time)
ProcessTasks(); ProcessTasks();
// Process threads // Process threads
ProcessThreads(); ProcessThreads();
// Process network
ProcessNet();
// Process log messages from other threads // Process log messages from other threads
Logger::Get().ProcessQueue(); Logger::Get().ProcessQueue();
// See if a reload was requested // See if a reload was requested
@ -991,6 +995,7 @@ SQMOD_API_EXPORT unsigned int VcmpPluginInit(PluginFuncs * funcs, PluginCallback
try try
{ {
// External plugs that need to happen (once) before initialization // External plugs that need to happen (once) before initialization
InitializeNet();
InitializePocoDataConnectors(); InitializePocoDataConnectors();
// Proceed with plug-in initialization // Proceed with plug-in initialization
if (!Core::Get().Initialize()) if (!Core::Get().Initialize())

View File

@ -37,6 +37,7 @@ extern void Register_Format(HSQUIRRELVM vm);
extern void Register_IO(HSQUIRRELVM vm); extern void Register_IO(HSQUIRRELVM vm);
extern void Register_JSON(HSQUIRRELVM vm); extern void Register_JSON(HSQUIRRELVM vm);
extern void Register_MMDB(HSQUIRRELVM vm); extern void Register_MMDB(HSQUIRRELVM vm);
extern void Register_Net(HSQUIRRELVM vm);
extern void Register_Numeric(HSQUIRRELVM vm); extern void Register_Numeric(HSQUIRRELVM vm);
extern void Register_String(HSQUIRRELVM vm); extern void Register_String(HSQUIRRELVM vm);
extern void Register_System(HSQUIRRELVM vm); extern void Register_System(HSQUIRRELVM vm);
@ -102,6 +103,7 @@ bool RegisterAPI(HSQUIRRELVM vm)
Register_IO(vm); Register_IO(vm);
Register_JSON(vm); Register_JSON(vm);
Register_MMDB(vm); Register_MMDB(vm);
Register_Net(vm);
Register_Numeric(vm); Register_Numeric(vm);
Register_String(vm); Register_String(vm);
Register_System(vm); Register_System(vm);

View File

@ -7,6 +7,7 @@ add_subdirectory(TinyDir)
add_subdirectory(SAJSON) add_subdirectory(SAJSON)
add_subdirectory(CPR) add_subdirectory(CPR)
add_subdirectory(PUGIXML) add_subdirectory(PUGIXML)
add_subdirectory(CivetWeb)
set(BUILD_TESTING OFF CACHE INTERNAL "" FORCE) set(BUILD_TESTING OFF CACHE INTERNAL "" FORCE)
set(BUILD_SHARED_LIBS OFF CACHE INTERNAL "" FORCE) set(BUILD_SHARED_LIBS OFF CACHE INTERNAL "" FORCE)
add_subdirectory(MaxmindDB) add_subdirectory(MaxmindDB)

47
vendor/CivetWeb/CMakeLists.txt vendored Normal file
View File

@ -0,0 +1,47 @@
# Create the CivetWeb library
add_library(CivetWeb STATIC
include/civetweb.h civetweb.c
mod_mbedtls.inl
mod_zlib.inl
openssl_dl.inl
response.inl
sha1.inl
timer.inl
wolfssl_extras.inl
handle_form.inl
md5.inl
mod_http2.inl
)
# Configure include folders
target_include_directories(CivetWeb PRIVATE ${CMAKE_CURRENT_LIST_DIR})
target_include_directories(CivetWeb PUBLIC ${CMAKE_CURRENT_LIST_DIR}/include)
# Configure macro options
if(WIN32 OR MINGW)
target_compile_definitions(CivetWeb PRIVATE _WIN32_WINNT=0x0601)
endif()
# Generic macro options
target_compile_definitions(CivetWeb PUBLIC USE_TIMERS=1 USE_WEBSOCKET=1 USE_IPV6=1 USE_HTTP2=1)
# Look for SSL
find_package(OpenSSL)
# Check SSL status
if (OPENSSL_FOUND)
message(STATUS "CivetWeb: OpenSSL was found")
target_link_libraries(CivetWeb PUBLIC OpenSSL::Crypto OpenSSL::SSL)
string(REPLACE "." ";" OPENSSL_VERSION_LIST ${OPENSSL_VERSION})
list(GET OPENSSL_VERSION_LIST 0 OPENSSL_VERSION_MAJOR)
list(GET OPENSSL_VERSION_LIST 1 OPENSSL_VERSION_MINOR)
list(GET OPENSSL_VERSION_LIST 2 OPENSSL_VERSION_PATCH)
# Tell the library what SSL version to expect
target_compile_definitions(CivetWeb PUBLIC "OPENSSL_API_${OPENSSL_VERSION_MAJOR}_${OPENSSL_VERSION_MINOR}")
message(STATUS "CivetWeb: OPENSSL_API_${OPENSSL_VERSION_MAJOR}_${OPENSSL_VERSION_MINOR}")
else()
target_compile_definitions(CivetWeb PUBLIC NO_SSL=1)
endif()
# Look for ZLib
find_package(ZLIB)
# Check ZLib status
if (ZLIB_FOUND)
message(STATUS "CivetWeb: ZLib was found")
target_link_libraries(CivetWeb PUBLIC ZLIB::ZLIB)
target_compile_definitions(CivetWeb PUBLIC USE_ZLIB=1)
endif()

248
vendor/CivetWeb/LICENSE.md vendored Normal file
View File

@ -0,0 +1,248 @@
ALL LICENSES
=====
This document includes several copyright licenses for different
aspects of the software. Not all licenses may apply depending
on the features chosen.
Civetweb License
-----
### Included with all features.
> Copyright (c) 2013-2021 The CivetWeb developers ([CREDITS.md](https://github.com/civetweb/civetweb/blob/master/CREDITS.md))
>
> Copyright (c) 2004-2013 Sergey Lyubka
>
> Copyright (c) 2013 No Face Press, LLC (Thomas Davis)
>
> Copyright (c) 2013 F-Secure Corporation
>
> Permission is hereby granted, free of charge, to any person obtaining a copy
> of this software and associated documentation files (the "Software"), to deal
> in the Software without restriction, including without limitation the rights
> to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
> copies of the Software, and to permit persons to whom the Software is
> furnished to do so, subject to the following conditions:
>
> The above copyright notice and this permission notice shall be included in
> all copies or substantial portions of the Software.
>
> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
> AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
> OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
> THE SOFTWARE.
Lua License
------
### Included only if built with Lua support.
http://www.lua.org/license.html
> Copyright (C) 1994-2020 Lua.org, PUC-Rio.
>
> Permission is hereby granted, free of charge, to any person obtaining a copy
> of this software and associated documentation files (the "Software"), to deal
> in the Software without restriction, including without limitation the rights
> to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
> copies of the Software, and to permit persons to whom the Software is
> furnished to do so, subject to the following conditions:
>
> The above copyright notice and this permission notice shall be included in
> all copies or substantial portions of the Software.
>
> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
> AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
> OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
> THE SOFTWARE.
SQLite3 License
------
### Included only if built with Lua and SQLite support.
http://www.sqlite.org/copyright.html
> 2001-09-15
>
> The author disclaims copyright to this source code. In place of
> a legal notice, here is a blessing:
>
> May you do good and not evil.
> May you find forgiveness for yourself and forgive others.
> May you share freely, never taking more than you give.
lsqlite3 License
------
### Included only if built with Lua and SQLite support.
> Copyright (C) 2002-2016 Tiago Dionizio, Doug Currie
> All rights reserved.
> Author : Tiago Dionizio <tiago.dionizio@ist.utl.pt>
> Author : Doug Currie <doug.currie@alum.mit.edu>
> Library : lsqlite3 - an SQLite 3 database binding for Lua 5
>
> Permission is hereby granted, free of charge, to any person obtaining a copy
> of this software and associated documentation files (the "Software"), to deal
> in the Software without restriction, including without limitation the rights
> to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
> copies of the Software, and to permit persons to whom the Software is
> furnished to do so, subject to the following conditions:
>
> The above copyright notice and this permission notice shall be included in
> all copies or substantial portions of the Software.
>
> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
> AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
> OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
> THE SOFTWARE.
Lua File System License
------
### Included only if built with Lua support.
https://github.com/keplerproject/luafilesystem/blob/master/LICENSE
> Copyright © 2003-2020 Kepler Project.
>
> Permission is hereby granted, free of charge, to any person
> obtaining a copy of this software and associated documentation
> files (the "Software"), to deal in the Software without
> restriction, including without limitation the rights to use, copy,
> modify, merge, publish, distribute, sublicense, and/or sell copies
> of the Software, and to permit persons to whom the Software is
> furnished to do so, subject to the following conditions:
>
> The above copyright notice and this permission notice shall be
> included in all copies or substantial portions of the Software.
>
> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
> EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
> MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
> NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
> BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
> ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
> CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
> SOFTWARE.
LuaXML License
------
### Included only if built with Lua and LuaXML support.
Version 1.8.0 (Lua 5.2), 2013-06-10 by Gerald Franz, eludi.net
Modified and extended 2015 by Bernhard Nortmann, https://github.com/n1tehawk/LuaXML version 2.0.x, compatible with Lua 5.1 to 5.3 and LuaJIT.
> LuaXML License
>
> LuaXml is licensed under the terms of the MIT license reproduced below,
> the same as Lua itself. This means that LuaXml is free software and can be
> used for both academic and commercial purposes at absolutely no cost.
>
> Copyright (C) 2007-2013 Gerald Franz, eludi.net
>
> Permission is hereby granted, free of charge, to any person obtaining a copy
> of this software and associated documentation files (the "Software"), to deal
> in the Software without restriction, including without limitation the rights
> to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
> copies of the Software, and to permit persons to whom the Software is
> furnished to do so, subject to the following conditions:
>
> The above copyright notice and this permission notice shall be included in
> all copies or substantial portions of the Software.
>
> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
> AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
> OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
> THE SOFTWARE.
Duktape License
------
### Included only if built with Duktape support.
https://github.com/svaarala/duktape/blob/master/LICENSE.txt
> ===============
> Duktape license
> ===============
>
> (http://opensource.org/licenses/MIT)
>
> Copyright (c) 2013-2017 by Duktape authors (see AUTHORS.rst)
>
> Permission is hereby granted, free of charge, to any person obtaining a copy
> of this software and associated documentation files (the "Software"), to deal
> in the Software without restriction, including without limitation the rights
> to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
> copies of the Software, and to permit persons to whom the Software is
> furnished to do so, subject to the following conditions:
>
> The above copyright notice and this permission notice shall be included in
> all copies or substantial portions of the Software.
>
> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
> AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
> OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
> THE SOFTWARE.
zlib License
------
### Included only if built with zlib support.
https://www.zlib.net/zlib_license.html
> zlib.h -- interface of the 'zlib' general purpose compression library
> version 1.2.11, January 15th, 2017
>
> Copyright (C) 1995-2017 Jean-loup Gailly and Mark Adler
>
> This software is provided 'as-is', without any express or implied
> warranty. In no event will the authors be held liable for any damages
> arising from the use of this software.
>
> Permission is granted to anyone to use this software for any purpose,
> including commercial applications, and to alter it and redistribute it
> freely, subject to the following restrictions:
>
> 1. The origin of this software must not be misrepresented; you must not
> claim that you wrote the original software. If you use this software
> in a product, an acknowledgment in the product documentation would be
> appreciated but is not required.
> 2. Altered source versions must be plainly marked as such, and must not be
> misrepresented as being the original software.
> 3. This notice may not be removed or altered from any source distribution.
>
> Jean-loup Gailly Mark Adler
> jloup@gzip.org madler@alumni.caltech.edu

21475
vendor/CivetWeb/civetweb.c vendored Normal file

File diff suppressed because it is too large Load Diff

1082
vendor/CivetWeb/handle_form.inl vendored Normal file

File diff suppressed because it is too large Load Diff

1712
vendor/CivetWeb/include/civetweb.h vendored Normal file

File diff suppressed because it is too large Load Diff

471
vendor/CivetWeb/md5.inl vendored Normal file
View File

@ -0,0 +1,471 @@
/*
* This an amalgamation of md5.c and md5.h into a single file
* with all static declaration to reduce linker conflicts
* in Civetweb.
*
* The MD5_STATIC declaration was added to facilitate static
* inclusion.
* No Face Press, LLC
*/
/* $Id: md5.h,v 1.4 2002/04/13 19:20:28 lpd Exp $ */
/*
Independent implementation of MD5 (RFC 1321).
This code implements the MD5 Algorithm defined in RFC 1321, whose
text is available at
http://www.ietf.org/rfc/rfc1321.txt
The code is derived from the text of the RFC, including the test suite
(section A.5) but excluding the rest of Appendix A. It does not include
any code or documentation that is identified in the RFC as being
copyrighted.
The original and principal author of md5.h is L. Peter Deutsch
<ghost@aladdin.com>. Other authors are noted in the change history
that follows (in reverse chronological order):
2002-04-13 lpd Removed support for non-ANSI compilers; removed
references to Ghostscript; clarified derivation from RFC 1321;
now handles byte order either statically or dynamically.
1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5);
added conditionalization for C++ compilation from Martin
Purschke <purschke@bnl.gov>.
1999-05-03 lpd Original version.
*/
#if !defined(md5_INCLUDED)
#define md5_INCLUDED
/*
* This package supports both compile-time and run-time determination of CPU
* byte order. If ARCH_IS_BIG_ENDIAN is defined as 0, the code will be
* compiled to run only on little-endian CPUs; if ARCH_IS_BIG_ENDIAN is
* defined as non-zero, the code will be compiled to run only on big-endian
* CPUs; if ARCH_IS_BIG_ENDIAN is not defined, the code will be compiled to
* run on either big- or little-endian CPUs, but will run slightly less
* efficiently on either one than if ARCH_IS_BIG_ENDIAN is defined.
*/
typedef unsigned char md5_byte_t; /* 8-bit byte */
typedef unsigned int md5_word_t; /* 32-bit word */
/* Define the state of the MD5 Algorithm. */
typedef struct md5_state_s {
md5_word_t count[2]; /* message length in bits, lsw first */
md5_word_t abcd[4]; /* digest buffer */
md5_byte_t buf[64]; /* accumulate block */
} md5_state_t;
#if defined(__cplusplus)
extern "C" {
#endif
/* Initialize the algorithm. */
MD5_STATIC void md5_init(md5_state_t *pms);
/* Append a string to the message. */
MD5_STATIC void
md5_append(md5_state_t *pms, const md5_byte_t *data, size_t nbytes);
/* Finish the message and return the digest. */
MD5_STATIC void md5_finish(md5_state_t *pms, md5_byte_t digest[16]);
#if defined(__cplusplus)
} /* end extern "C" */
#endif
#endif /* md5_INCLUDED */
/*
Copyright (C) 1999, 2000, 2002 Aladdin Enterprises. All rights reserved.
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
L. Peter Deutsch
ghost@aladdin.com
*/
/* $Id: md5.c,v 1.6 2002/04/13 19:20:28 lpd Exp $ */
/*
Independent implementation of MD5 (RFC 1321).
This code implements the MD5 Algorithm defined in RFC 1321, whose
text is available at
http://www.ietf.org/rfc/rfc1321.txt
The code is derived from the text of the RFC, including the test suite
(section A.5) but excluding the rest of Appendix A. It does not include
any code or documentation that is identified in the RFC as being
copyrighted.
The original and principal author of md5.c is L. Peter Deutsch
<ghost@aladdin.com>. Other authors are noted in the change history
that follows (in reverse chronological order):
2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order
either statically or dynamically; added missing #include <string.h>
in library.
2002-03-11 lpd Corrected argument list for main(), and added int return
type, in test program and T value program.
2002-02-21 lpd Added missing #include <stdio.h> in test program.
2000-07-03 lpd Patched to eliminate warnings about "constant is
unsigned in ANSI C, signed in traditional"; made test program
self-checking.
1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5).
1999-05-03 lpd Original version.
*/
#if !defined(MD5_STATIC)
#include <string.h>
#endif
#undef BYTE_ORDER /* 1 = big-endian, -1 = little-endian, 0 = unknown */
#if defined(ARCH_IS_BIG_ENDIAN)
#define BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1)
#else
#define BYTE_ORDER (0)
#endif
#define T_MASK ((md5_word_t)~0)
#define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87)
#define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9)
#define T3 (0x242070db)
#define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111)
#define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050)
#define T6 (0x4787c62a)
#define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec)
#define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe)
#define T9 (0x698098d8)
#define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850)
#define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e)
#define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841)
#define T13 (0x6b901122)
#define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c)
#define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71)
#define T16 (0x49b40821)
#define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d)
#define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf)
#define T19 (0x265e5a51)
#define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855)
#define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2)
#define T22 (0x02441453)
#define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e)
#define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437)
#define T25 (0x21e1cde6)
#define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829)
#define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278)
#define T28 (0x455a14ed)
#define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa)
#define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07)
#define T31 (0x676f02d9)
#define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375)
#define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd)
#define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e)
#define T35 (0x6d9d6122)
#define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3)
#define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb)
#define T38 (0x4bdecfa9)
#define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f)
#define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f)
#define T41 (0x289b7ec6)
#define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805)
#define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a)
#define T44 (0x04881d05)
#define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6)
#define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a)
#define T47 (0x1fa27cf8)
#define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a)
#define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb)
#define T50 (0x432aff97)
#define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58)
#define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6)
#define T53 (0x655b59c3)
#define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d)
#define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82)
#define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e)
#define T57 (0x6fa87e4f)
#define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f)
#define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb)
#define T60 (0x4e0811a1)
#define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d)
#define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca)
#define T63 (0x2ad7d2bb)
#define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e)
static void
md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/)
{
md5_word_t a = pms->abcd[0], b = pms->abcd[1], c = pms->abcd[2],
d = pms->abcd[3];
md5_word_t t;
#if BYTE_ORDER > 0
/* Define storage only for big-endian CPUs. */
md5_word_t X[16];
#else
/* Define storage for little-endian or both types of CPUs. */
md5_word_t xbuf[16];
const md5_word_t *X;
#endif
{
#if BYTE_ORDER == 0
/*
* Determine dynamically whether this is a big-endian or
* little-endian machine, since we can use a more efficient
* algorithm on the latter.
*/
static const int w = 1;
if (*((const md5_byte_t *)&w)) /* dynamic little-endian */
#endif
#if BYTE_ORDER <= 0 /* little-endian */
{
/*
* On little-endian machines, we can process properly aligned
* data without copying it.
*/
if (!((data - (const md5_byte_t *)0) & 3)) {
/* data are properly aligned, a direct assignment is possible */
/* cast through a (void *) should avoid a compiler warning,
see
https://github.com/bel2125/civetweb/issues/94#issuecomment-98112861
*/
X = (const md5_word_t *)(const void *)data;
} else {
/* not aligned */
memcpy(xbuf, data, 64);
X = xbuf;
}
}
#endif
#if BYTE_ORDER == 0
else /* dynamic big-endian */
#endif
#if BYTE_ORDER >= 0 /* big-endian */
{
/*
* On big-endian machines, we must arrange the bytes in the
* right order.
*/
const md5_byte_t *xp = data;
int i;
#if BYTE_ORDER == 0
X = xbuf; /* (dynamic only) */
#else
#define xbuf X /* (static only) */
#endif
for (i = 0; i < 16; ++i, xp += 4)
xbuf[i] = (md5_word_t)(xp[0]) + (md5_word_t)(xp[1] << 8)
+ (md5_word_t)(xp[2] << 16)
+ (md5_word_t)(xp[3] << 24);
}
#endif
}
#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
/* Round 1. */
/* Let [abcd k s i] denote the operation
a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */
#define F(x, y, z) (((x) & (y)) | (~(x) & (z)))
#define SET(a, b, c, d, k, s, Ti) \
t = (a) + F(b, c, d) + X[k] + (Ti); \
(a) = ROTATE_LEFT(t, s) + (b)
/* Do the following 16 operations. */
SET(a, b, c, d, 0, 7, T1);
SET(d, a, b, c, 1, 12, T2);
SET(c, d, a, b, 2, 17, T3);
SET(b, c, d, a, 3, 22, T4);
SET(a, b, c, d, 4, 7, T5);
SET(d, a, b, c, 5, 12, T6);
SET(c, d, a, b, 6, 17, T7);
SET(b, c, d, a, 7, 22, T8);
SET(a, b, c, d, 8, 7, T9);
SET(d, a, b, c, 9, 12, T10);
SET(c, d, a, b, 10, 17, T11);
SET(b, c, d, a, 11, 22, T12);
SET(a, b, c, d, 12, 7, T13);
SET(d, a, b, c, 13, 12, T14);
SET(c, d, a, b, 14, 17, T15);
SET(b, c, d, a, 15, 22, T16);
#undef SET
/* Round 2. */
/* Let [abcd k s i] denote the operation
a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */
#define G(x, y, z) (((x) & (z)) | ((y) & ~(z)))
#define SET(a, b, c, d, k, s, Ti) \
t = (a) + G(b, c, d) + X[k] + (Ti); \
(a) = ROTATE_LEFT(t, s) + (b)
/* Do the following 16 operations. */
SET(a, b, c, d, 1, 5, T17);
SET(d, a, b, c, 6, 9, T18);
SET(c, d, a, b, 11, 14, T19);
SET(b, c, d, a, 0, 20, T20);
SET(a, b, c, d, 5, 5, T21);
SET(d, a, b, c, 10, 9, T22);
SET(c, d, a, b, 15, 14, T23);
SET(b, c, d, a, 4, 20, T24);
SET(a, b, c, d, 9, 5, T25);
SET(d, a, b, c, 14, 9, T26);
SET(c, d, a, b, 3, 14, T27);
SET(b, c, d, a, 8, 20, T28);
SET(a, b, c, d, 13, 5, T29);
SET(d, a, b, c, 2, 9, T30);
SET(c, d, a, b, 7, 14, T31);
SET(b, c, d, a, 12, 20, T32);
#undef SET
/* Round 3. */
/* Let [abcd k s t] denote the operation
a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */
#define H(x, y, z) ((x) ^ (y) ^ (z))
#define SET(a, b, c, d, k, s, Ti) \
t = (a) + H(b, c, d) + X[k] + (Ti); \
(a) = ROTATE_LEFT(t, s) + b
/* Do the following 16 operations. */
SET(a, b, c, d, 5, 4, T33);
SET(d, a, b, c, 8, 11, T34);
SET(c, d, a, b, 11, 16, T35);
SET(b, c, d, a, 14, 23, T36);
SET(a, b, c, d, 1, 4, T37);
SET(d, a, b, c, 4, 11, T38);
SET(c, d, a, b, 7, 16, T39);
SET(b, c, d, a, 10, 23, T40);
SET(a, b, c, d, 13, 4, T41);
SET(d, a, b, c, 0, 11, T42);
SET(c, d, a, b, 3, 16, T43);
SET(b, c, d, a, 6, 23, T44);
SET(a, b, c, d, 9, 4, T45);
SET(d, a, b, c, 12, 11, T46);
SET(c, d, a, b, 15, 16, T47);
SET(b, c, d, a, 2, 23, T48);
#undef SET
/* Round 4. */
/* Let [abcd k s t] denote the operation
a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */
#define I(x, y, z) ((y) ^ ((x) | ~(z)))
#define SET(a, b, c, d, k, s, Ti) \
t = (a) + I(b, c, d) + X[k] + (Ti); \
(a) = ROTATE_LEFT(t, s) + (b)
/* Do the following 16 operations. */
SET(a, b, c, d, 0, 6, T49);
SET(d, a, b, c, 7, 10, T50);
SET(c, d, a, b, 14, 15, T51);
SET(b, c, d, a, 5, 21, T52);
SET(a, b, c, d, 12, 6, T53);
SET(d, a, b, c, 3, 10, T54);
SET(c, d, a, b, 10, 15, T55);
SET(b, c, d, a, 1, 21, T56);
SET(a, b, c, d, 8, 6, T57);
SET(d, a, b, c, 15, 10, T58);
SET(c, d, a, b, 6, 15, T59);
SET(b, c, d, a, 13, 21, T60);
SET(a, b, c, d, 4, 6, T61);
SET(d, a, b, c, 11, 10, T62);
SET(c, d, a, b, 2, 15, T63);
SET(b, c, d, a, 9, 21, T64);
#undef SET
/* Then perform the following additions. (That is increment each
of the four registers by the value it had before this block
was started.) */
pms->abcd[0] += a;
pms->abcd[1] += b;
pms->abcd[2] += c;
pms->abcd[3] += d;
}
MD5_STATIC void
md5_init(md5_state_t *pms)
{
pms->count[0] = pms->count[1] = 0;
pms->abcd[0] = 0x67452301;
pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476;
pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301;
pms->abcd[3] = 0x10325476;
}
MD5_STATIC void
md5_append(md5_state_t *pms, const md5_byte_t *data, size_t nbytes)
{
const md5_byte_t *p = data;
size_t left = nbytes;
size_t offset = (pms->count[0] >> 3) & 63;
md5_word_t nbits = (md5_word_t)(nbytes << 3);
if (nbytes <= 0)
return;
/* Update the message length. */
pms->count[1] += (md5_word_t)(nbytes >> 29);
pms->count[0] += nbits;
if (pms->count[0] < nbits)
pms->count[1]++;
/* Process an initial partial block. */
if (offset) {
size_t copy = (offset + nbytes > 64 ? 64 - offset : nbytes);
memcpy(pms->buf + offset, p, copy);
if (offset + copy < 64)
return;
p += copy;
left -= copy;
md5_process(pms, pms->buf);
}
/* Process full blocks. */
for (; left >= 64; p += 64, left -= 64)
md5_process(pms, p);
/* Process a final partial block. */
if (left)
memcpy(pms->buf, p, left);
}
MD5_STATIC void
md5_finish(md5_state_t *pms, md5_byte_t digest[16])
{
static const md5_byte_t pad[64] = {0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
md5_byte_t data[8];
int i;
/* Save the length before padding. */
for (i = 0; i < 8; ++i)
data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3));
/* Pad to 56 bytes mod 64. */
md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1);
/* Append the length. */
md5_append(pms, data, 8);
for (i = 0; i < 16; ++i)
digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3));
}
/* End of md5.inl */

1853
vendor/CivetWeb/mod_http2.inl vendored Normal file

File diff suppressed because it is too large Load Diff

239
vendor/CivetWeb/mod_mbedtls.inl vendored Normal file
View File

@ -0,0 +1,239 @@
#if defined(USE_MBEDTLS) // USE_MBEDTLS used with NO_SSL
#include "mbedtls/certs.h"
#include "mbedtls/ctr_drbg.h"
#include "mbedtls/debug.h"
#include "mbedtls/entropy.h"
#include "mbedtls/error.h"
#include "mbedtls/net.h"
#include "mbedtls/pk.h"
#include "mbedtls/platform.h"
#include "mbedtls/ssl.h"
#include "mbedtls/x509.h"
#include "mbedtls/x509_crt.h"
#include <string.h>
typedef mbedtls_ssl_context SSL;
typedef struct {
mbedtls_ssl_config conf; /* SSL configuration */
mbedtls_x509_crt cert; /* Certificate */
mbedtls_ctr_drbg_context ctr; /* Counter random generator state */
mbedtls_entropy_context entropy; /* Entropy context */
mbedtls_pk_context pkey; /* Private key */
} SSL_CTX;
/* public api */
int mbed_sslctx_init(SSL_CTX *ctx, const char *crt);
void mbed_sslctx_uninit(SSL_CTX *ctx);
void mbed_ssl_close(mbedtls_ssl_context *ssl);
int mbed_ssl_accept(mbedtls_ssl_context **ssl,
SSL_CTX *ssl_ctx,
int *sock,
struct mg_context *phys_ctx);
int mbed_ssl_read(mbedtls_ssl_context *ssl, unsigned char *buf, int len);
int mbed_ssl_write(mbedtls_ssl_context *ssl, const unsigned char *buf, int len);
static void mbed_debug(void *context,
int level,
const char *file,
int line,
const char *str);
static int mbed_ssl_handshake(mbedtls_ssl_context *ssl);
int
mbed_sslctx_init(SSL_CTX *ctx, const char *crt)
{
mbedtls_ssl_config *conf;
int rc;
if (ctx == NULL || crt == NULL) {
return -1;
}
DEBUG_TRACE("%s", "Initializing MbedTLS SSL");
mbedtls_entropy_init(&ctx->entropy);
conf = &ctx->conf;
mbedtls_ssl_config_init(conf);
/* Set mbedTLS debug level by defining MG_CONFIG_MBEDTLS_DEBUG:
* 0 No debug = mbedTLS DEFAULT
* 1 Error (default if "DEBUG" is set for CivetWeb)
* 2 State change
* 3 Informational
* 4 Verbose
*/
#if defined(DEBUG) || defined(MG_CONFIG_MBEDTLS_DEBUG)
#if defined(MG_CONFIG_MBEDTLS_DEBUG)
mbedtls_debug_set_threshold(MG_CONFIG_MBEDTLS_DEBUG);
#else
mbedtls_debug_set_threshold(1);
#endif
mbedtls_ssl_conf_dbg(conf, mbed_debug, (void *)ctx);
#endif
/* Initialize TLS key and cert */
mbedtls_pk_init(&ctx->pkey);
mbedtls_ctr_drbg_init(&ctx->ctr);
mbedtls_x509_crt_init(&ctx->cert);
rc = mbedtls_ctr_drbg_seed(&ctx->ctr,
mbedtls_entropy_func,
&ctx->entropy,
(unsigned char *)"CivetWeb",
strlen("CivetWeb"));
if (rc != 0) {
DEBUG_TRACE("TLS random seed failed (%i)", rc);
return -1;
}
rc = mbedtls_pk_parse_keyfile(&ctx->pkey, crt, NULL);
if (rc != 0) {
DEBUG_TRACE("TLS parse key file failed (%i)", rc);
return -1;
}
rc = mbedtls_x509_crt_parse_file(&ctx->cert, crt);
if (rc != 0) {
DEBUG_TRACE("TLS parse crt file failed (%i)", rc);
return -1;
}
rc = mbedtls_ssl_config_defaults(conf,
MBEDTLS_SSL_IS_SERVER,
MBEDTLS_SSL_TRANSPORT_STREAM,
MBEDTLS_SSL_PRESET_DEFAULT);
if (rc != 0) {
DEBUG_TRACE("TLS set defaults failed (%i)", rc);
return -1;
}
mbedtls_ssl_conf_rng(conf, mbedtls_ctr_drbg_random, &ctx->ctr);
/* Set auth mode if peer cert should be verified */
mbedtls_ssl_conf_authmode(conf, MBEDTLS_SSL_VERIFY_NONE);
mbedtls_ssl_conf_ca_chain(conf, NULL, NULL);
/* Configure server cert and key */
rc = mbedtls_ssl_conf_own_cert(conf, &ctx->cert, &ctx->pkey);
if (rc != 0) {
DEBUG_TRACE("TLS cannot set certificate and private key (%i)", rc);
return -1;
}
return 0;
}
void
mbed_sslctx_uninit(SSL_CTX *ctx)
{
mbedtls_ctr_drbg_free(&ctx->ctr);
mbedtls_pk_free(&ctx->pkey);
mbedtls_x509_crt_free(&ctx->cert);
mbedtls_entropy_free(&ctx->entropy);
mbedtls_ssl_config_free(&ctx->conf);
}
int
mbed_ssl_accept(mbedtls_ssl_context **ssl,
SSL_CTX *ssl_ctx,
int *sock,
struct mg_context *phys_ctx)
{
int rc;
(void)phys_ctx; /* unused, if server statistics is not turned on */
DEBUG_TRACE("TLS accept processing %p", ssl);
*ssl = (mbedtls_ssl_context *)mg_calloc_ctx(1,
sizeof(mbedtls_ssl_context),
phys_ctx);
if (*ssl == NULL) {
DEBUG_TRACE("TLS accept: malloc ssl failed (%i)",
(int)sizeof(mbedtls_ssl_context));
return -1;
}
mbedtls_ssl_init(*ssl);
mbedtls_ssl_setup(*ssl, &ssl_ctx->conf);
mbedtls_ssl_set_bio(*ssl, sock, mbedtls_net_send, mbedtls_net_recv, NULL);
rc = mbed_ssl_handshake(*ssl);
if (rc != 0) {
DEBUG_TRACE("TLS handshake failed (%i)", rc);
mbedtls_ssl_free(*ssl);
mg_free(*ssl);
*ssl = NULL;
return -1;
}
DEBUG_TRACE("TLS connection %p accepted, state: %d", ssl, (*ssl)->state);
return 0;
}
void
mbed_ssl_close(mbedtls_ssl_context *ssl)
{
DEBUG_TRACE("TLS connection %p closed", ssl);
mbedtls_ssl_close_notify(ssl);
mbedtls_ssl_free(ssl);
mg_free(ssl); /* mg_free for mg_calloc in mbed_ssl_accept */
}
static int
mbed_ssl_handshake(mbedtls_ssl_context *ssl)
{
int rc;
while ((rc = mbedtls_ssl_handshake(ssl)) != 0) {
if (rc != MBEDTLS_ERR_SSL_WANT_READ && rc != MBEDTLS_ERR_SSL_WANT_WRITE
&& rc != MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS) {
break;
}
}
DEBUG_TRACE("TLS handshake rc: %d, state: %d", rc, ssl->state);
return rc;
}
int
mbed_ssl_read(mbedtls_ssl_context *ssl, unsigned char *buf, int len)
{
int rc = mbedtls_ssl_read(ssl, buf, len);
/* DEBUG_TRACE("mbedtls_ssl_read: %d", rc); */
return rc;
}
int
mbed_ssl_write(mbedtls_ssl_context *ssl, const unsigned char *buf, int len)
{
int rc = mbedtls_ssl_write(ssl, buf, len);
/* DEBUG_TRACE("mbedtls_ssl_write: %d", rc); */
return rc;
}
static void
mbed_debug(void *user_param,
int level,
const char *file,
int line,
const char *str)
{
(void)level; /* Ignored. Limit is set using mbedtls_debug_set_threshold */
(void)user_param; /* Ignored. User parameter (context) is set using
mbedtls_ssl_conf_dbg */
DEBUG_TRACE("mbedTLS DEBUG: file: [%s] line: [%d] str: [%s]",
file,
line,
str);
}
#endif /* USE_MBEDTLS */

281
vendor/CivetWeb/mod_zlib.inl vendored Normal file
View File

@ -0,0 +1,281 @@
/* Experimental implementation for on-the-fly compression */
#if !defined(USE_ZLIB)
#error "This file must only be included, if USE_ZLIB is set"
#endif
#if !defined(MEM_LEVEL)
#define MEM_LEVEL (8)
#endif
static void *
zalloc(void *opaque, uInt items, uInt size)
{
struct mg_connection *conn = (struct mg_connection *)opaque;
void *ret = mg_calloc_ctx(items, size, conn->phys_ctx);
(void)conn; /* mg_calloc_ctx makro might not need it */
return ret;
}
static void
zfree(void *opaque, void *address)
{
struct mg_connection *conn = (struct mg_connection *)opaque;
(void)conn; /* not required */
mg_free(address);
}
static void
send_compressed_data(struct mg_connection *conn, struct mg_file *filep)
{
int zret;
z_stream zstream;
int do_flush;
unsigned bytes_avail;
unsigned char in_buf[MG_BUF_LEN];
unsigned char out_buf[MG_BUF_LEN];
FILE *in_file = filep->access.fp;
/* Prepare state buffer. User server context memory allocation. */
memset(&zstream, 0, sizeof(zstream));
zstream.zalloc = zalloc;
zstream.zfree = zfree;
zstream.opaque = (void *)conn;
/* Initialize for GZIP compression (MAX_WBITS | 16) */
zret = deflateInit2(&zstream,
Z_BEST_COMPRESSION,
Z_DEFLATED,
MAX_WBITS | 16,
MEM_LEVEL,
Z_DEFAULT_STRATEGY);
if (zret != Z_OK) {
mg_cry_internal(conn,
"GZIP init failed (%i): %s",
zret,
(zstream.msg ? zstream.msg : "<no error message>"));
deflateEnd(&zstream);
return;
}
/* Read until end of file */
do {
zstream.avail_in = fread(in_buf, 1, MG_BUF_LEN, in_file);
if (ferror(in_file)) {
mg_cry_internal(conn, "fread failed: %s", strerror(ERRNO));
(void)deflateEnd(&zstream);
return;
}
do_flush = (feof(in_file) ? Z_FINISH : Z_NO_FLUSH);
zstream.next_in = in_buf;
/* run deflate() on input until output buffer not full, finish
* compression if all of source has been read in */
do {
zstream.avail_out = MG_BUF_LEN;
zstream.next_out = out_buf;
zret = deflate(&zstream, do_flush);
if (zret == Z_STREAM_ERROR) {
/* deflate error */
zret = -97;
break;
}
bytes_avail = MG_BUF_LEN - zstream.avail_out;
if (bytes_avail) {
if (mg_send_chunk(conn, (char *)out_buf, bytes_avail) < 0) {
zret = -98;
break;
}
}
} while (zstream.avail_out == 0);
if (zret < -90) {
/* Forward write error */
break;
}
if (zstream.avail_in != 0) {
/* all input will be used, otherwise GZIP is incomplete */
zret = -99;
break;
}
/* done when last data in file processed */
} while (do_flush != Z_FINISH);
if (zret != Z_STREAM_END) {
/* Error: We did not compress everything. */
mg_cry_internal(conn,
"GZIP incomplete (%i): %s",
zret,
(zstream.msg ? zstream.msg : "<no error message>"));
}
deflateEnd(&zstream);
/* Send "end of chunked data" marker */
mg_write(conn, "0\r\n\r\n", 5);
}
#if defined(USE_WEBSOCKET) && defined(MG_EXPERIMENTAL_INTERFACES)
static int
websocket_deflate_initialize(struct mg_connection *conn, int server)
{
int zret =
deflateInit2(&conn->websocket_deflate_state,
Z_BEST_COMPRESSION,
Z_DEFLATED,
server
? -1 * conn->websocket_deflate_server_max_windows_bits
: -1 * conn->websocket_deflate_client_max_windows_bits,
MEM_LEVEL,
Z_DEFAULT_STRATEGY);
if (zret != Z_OK) {
mg_cry_internal(conn,
"Websocket deflate init failed (%i): %s",
zret,
(conn->websocket_deflate_state.msg
? conn->websocket_deflate_state.msg
: "<no error message>"));
deflateEnd(&conn->websocket_deflate_state);
return zret;
}
zret = inflateInit2(
&conn->websocket_inflate_state,
server ? -1 * conn->websocket_deflate_client_max_windows_bits
: -1 * conn->websocket_deflate_server_max_windows_bits);
if (zret != Z_OK) {
mg_cry_internal(conn,
"Websocket inflate init failed (%i): %s",
zret,
(conn->websocket_inflate_state.msg
? conn->websocket_inflate_state.msg
: "<no error message>"));
inflateEnd(&conn->websocket_inflate_state);
return zret;
}
if ((conn->websocket_deflate_server_no_context_takeover && server)
|| (conn->websocket_deflate_client_no_context_takeover && !server))
conn->websocket_deflate_flush = Z_FULL_FLUSH;
else
conn->websocket_deflate_flush = Z_SYNC_FLUSH;
conn->websocket_deflate_initialized = 1;
return Z_OK;
}
static void
websocket_deflate_negotiate(struct mg_connection *conn)
{
const char *extensions = mg_get_header(conn, "Sec-WebSocket-Extensions");
int val;
if (extensions && !strncmp(extensions, "permessage-deflate", 18)) {
conn->accept_gzip = 1;
conn->websocket_deflate_client_max_windows_bits = 15;
conn->websocket_deflate_server_max_windows_bits = 15;
conn->websocket_deflate_server_no_context_takeover = 0;
conn->websocket_deflate_client_no_context_takeover = 0;
extensions += 18;
while (*extensions != '\0') {
if (*extensions == ';' || *extensions == ' ')
++extensions;
else if (!strncmp(extensions, "server_no_context_takeover", 26)) {
extensions += 26;
conn->websocket_deflate_server_no_context_takeover = 1;
} else if (!strncmp(extensions, "client_no_context_takeover", 26)) {
extensions += 26;
conn->websocket_deflate_client_no_context_takeover = 1;
} else if (!strncmp(extensions, "server_max_window_bits", 22)) {
extensions += 22;
if (*extensions == '=') {
++extensions;
if (*extensions == '"')
++extensions;
val = 0;
while (*extensions >= '0' && *extensions <= '9') {
val = val * 10 + (*extensions - '0');
++extensions;
}
if (val < 9 || val > 15) {
// The permessage-deflate spec specifies that a
// value of 8 is also allowed, but zlib doesn't accept
// that.
mg_cry_internal(conn,
"server-max-window-bits must be "
"between 9 and 15. Got %i",
val);
} else
conn->websocket_deflate_server_max_windows_bits = val;
if (*extensions == '"')
++extensions;
}
} else if (!strncmp(extensions, "client_max_window_bits", 22)) {
extensions += 22;
if (*extensions == '=') {
++extensions;
if (*extensions == '"')
++extensions;
val = 0;
while (*extensions >= '0' && *extensions <= '9') {
val = val * 10 + (*extensions - '0');
++extensions;
}
if (val < 9 || val > 15)
// The permessage-deflate spec specifies that a
// value of 8 is also allowed, but zlib doesn't
// accept that.
mg_cry_internal(conn,
"client-max-window-bits must be "
"between 9 and 15. Got %i",
val);
else
conn->websocket_deflate_client_max_windows_bits = val;
if (*extensions == '"')
++extensions;
}
} else {
mg_cry_internal(conn,
"Unknown parameter %s for permessage-deflate",
extensions);
break;
}
}
} else {
conn->accept_gzip = 0;
}
conn->websocket_deflate_initialized = 0;
}
static void
websocket_deflate_response(struct mg_connection *conn)
{
if (conn->accept_gzip) {
mg_printf(conn,
"Sec-WebSocket-Extensions: permessage-deflate; "
"server_max_window_bits=%i; "
"client_max_window_bits=%i"
"%s%s\r\n",
conn->websocket_deflate_server_max_windows_bits,
conn->websocket_deflate_client_max_windows_bits,
conn->websocket_deflate_client_no_context_takeover
? "; client_no_context_takeover"
: "",
conn->websocket_deflate_server_no_context_takeover
? "; server_no_context_takeover"
: "");
};
}
#endif

545
vendor/CivetWeb/openssl_dl.inl vendored Normal file
View File

@ -0,0 +1,545 @@
/* Copyright (c) 2013-2021 the Civetweb developers
* Copyright (c) 2004-2013 Sergey Lyubka
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
typedef struct ssl_st SSL;
typedef struct ssl_method_st SSL_METHOD;
typedef struct ssl_ctx_st SSL_CTX;
typedef struct x509_store_ctx_st X509_STORE_CTX;
typedef struct x509_name X509_NAME;
typedef struct asn1_integer ASN1_INTEGER;
typedef struct bignum BIGNUM;
typedef struct ossl_init_settings_st OPENSSL_INIT_SETTINGS;
typedef struct evp_md EVP_MD;
typedef struct x509 X509;
#define SSL_CTRL_OPTIONS (32)
#define SSL_CTRL_CLEAR_OPTIONS (77)
#define SSL_CTRL_SET_ECDH_AUTO (94)
#define OPENSSL_INIT_NO_LOAD_SSL_STRINGS 0x00100000L
#define OPENSSL_INIT_LOAD_SSL_STRINGS 0x00200000L
#define OPENSSL_INIT_LOAD_CRYPTO_STRINGS 0x00000002L
#define SSL_VERIFY_NONE (0)
#define SSL_VERIFY_PEER (1)
#define SSL_VERIFY_FAIL_IF_NO_PEER_CERT (2)
#define SSL_VERIFY_CLIENT_ONCE (4)
#define SSL_OP_ALL (0x80000BFFul)
#define SSL_OP_NO_SSLv2 (0x01000000ul)
#define SSL_OP_NO_SSLv3 (0x02000000ul)
#define SSL_OP_NO_TLSv1 (0x04000000ul)
#define SSL_OP_NO_TLSv1_2 (0x08000000ul)
#define SSL_OP_NO_TLSv1_1 (0x10000000ul)
#define SSL_OP_NO_TLSv1_3 (0x20000000ul)
#define SSL_OP_SINGLE_DH_USE (0x00100000ul)
#define SSL_OP_CIPHER_SERVER_PREFERENCE (0x00400000ul)
#define SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION (0x00010000ul)
#define SSL_OP_NO_COMPRESSION (0x00020000ul)
#define SSL_OP_NO_RENEGOTIATION (0x40000000ul)
#define SSL_CB_HANDSHAKE_START (0x10)
#define SSL_CB_HANDSHAKE_DONE (0x20)
#define SSL_ERROR_NONE (0)
#define SSL_ERROR_SSL (1)
#define SSL_ERROR_WANT_READ (2)
#define SSL_ERROR_WANT_WRITE (3)
#define SSL_ERROR_WANT_X509_LOOKUP (4)
#define SSL_ERROR_SYSCALL (5) /* see errno */
#define SSL_ERROR_ZERO_RETURN (6)
#define SSL_ERROR_WANT_CONNECT (7)
#define SSL_ERROR_WANT_ACCEPT (8)
#define TLSEXT_TYPE_server_name (0)
#define TLSEXT_NAMETYPE_host_name (0)
#define SSL_TLSEXT_ERR_OK (0)
#define SSL_TLSEXT_ERR_ALERT_WARNING (1)
#define SSL_TLSEXT_ERR_ALERT_FATAL (2)
#define SSL_TLSEXT_ERR_NOACK (3)
#define SSL_SESS_CACHE_BOTH (3)
enum ssl_func_category {
TLS_Mandatory, /* required for HTTPS */
TLS_ALPN, /* required for Application Layer Protocol Negotiation */
TLS_END_OF_LIST
};
/* Check if all TLS functions/features are available */
static int tls_feature_missing[TLS_END_OF_LIST] = {0};
struct ssl_func {
const char *name; /* SSL function name */
enum ssl_func_category required; /* Mandatory or optional */
void (*ptr)(void); /* Function pointer */
};
#if (defined(OPENSSL_API_1_1) || defined(OPENSSL_API_3_0)) \
&& !defined(NO_SSL_DL)
#define SSL_free (*(void (*)(SSL *))ssl_sw[0].ptr)
#define SSL_accept (*(int (*)(SSL *))ssl_sw[1].ptr)
#define SSL_connect (*(int (*)(SSL *))ssl_sw[2].ptr)
#define SSL_read (*(int (*)(SSL *, void *, int))ssl_sw[3].ptr)
#define SSL_write (*(int (*)(SSL *, const void *, int))ssl_sw[4].ptr)
#define SSL_get_error (*(int (*)(SSL *, int))ssl_sw[5].ptr)
#define SSL_set_fd (*(int (*)(SSL *, SOCKET))ssl_sw[6].ptr)
#define SSL_new (*(SSL * (*)(SSL_CTX *)) ssl_sw[7].ptr)
#define SSL_CTX_new (*(SSL_CTX * (*)(SSL_METHOD *)) ssl_sw[8].ptr)
#define TLS_server_method (*(SSL_METHOD * (*)(void)) ssl_sw[9].ptr)
#define OPENSSL_init_ssl \
(*(int (*)(uint64_t opts, \
const OPENSSL_INIT_SETTINGS *settings))ssl_sw[10] \
.ptr)
#define SSL_CTX_use_PrivateKey_file \
(*(int (*)(SSL_CTX *, const char *, int))ssl_sw[11].ptr)
#define SSL_CTX_use_certificate_file \
(*(int (*)(SSL_CTX *, const char *, int))ssl_sw[12].ptr)
#define SSL_CTX_set_default_passwd_cb \
(*(void (*)(SSL_CTX *, mg_callback_t))ssl_sw[13].ptr)
#define SSL_CTX_free (*(void (*)(SSL_CTX *))ssl_sw[14].ptr)
#define SSL_CTX_use_certificate_chain_file \
(*(int (*)(SSL_CTX *, const char *))ssl_sw[15].ptr)
#define TLS_client_method (*(SSL_METHOD * (*)(void)) ssl_sw[16].ptr)
#define SSL_pending (*(int (*)(SSL *))ssl_sw[17].ptr)
#define SSL_CTX_set_verify \
(*(void (*)(SSL_CTX *, \
int, \
int (*verify_callback)(int, X509_STORE_CTX *)))ssl_sw[18] \
.ptr)
#define SSL_shutdown (*(int (*)(SSL *))ssl_sw[19].ptr)
#define SSL_CTX_load_verify_locations \
(*(int (*)(SSL_CTX *, const char *, const char *))ssl_sw[20].ptr)
#define SSL_CTX_set_default_verify_paths (*(int (*)(SSL_CTX *))ssl_sw[21].ptr)
#define SSL_CTX_set_verify_depth (*(void (*)(SSL_CTX *, int))ssl_sw[22].ptr)
#define SSL_get_peer_certificate (*(X509 * (*)(SSL *)) ssl_sw[23].ptr)
#define SSL_get_version (*(const char *(*)(SSL *))ssl_sw[24].ptr)
#define SSL_get_current_cipher (*(SSL_CIPHER * (*)(SSL *)) ssl_sw[25].ptr)
#define SSL_CIPHER_get_name \
(*(const char *(*)(const SSL_CIPHER *))ssl_sw[26].ptr)
#define SSL_CTX_check_private_key (*(int (*)(SSL_CTX *))ssl_sw[27].ptr)
#define SSL_CTX_set_session_id_context \
(*(int (*)(SSL_CTX *, const unsigned char *, unsigned int))ssl_sw[28].ptr)
#define SSL_CTX_ctrl (*(long (*)(SSL_CTX *, int, long, void *))ssl_sw[29].ptr)
#define SSL_CTX_set_cipher_list \
(*(int (*)(SSL_CTX *, const char *))ssl_sw[30].ptr)
#define SSL_CTX_set_options \
(*(unsigned long (*)(SSL_CTX *, unsigned long))ssl_sw[31].ptr)
#define SSL_CTX_set_info_callback \
(*(void (*)(SSL_CTX * ctx, void (*callback)(const SSL *, int, int))) \
ssl_sw[32] \
.ptr)
#define SSL_get_ex_data (*(char *(*)(const SSL *, int))ssl_sw[33].ptr)
#define SSL_set_ex_data (*(void (*)(SSL *, int, char *))ssl_sw[34].ptr)
#define SSL_CTX_callback_ctrl \
(*(long (*)(SSL_CTX *, int, void (*)(void)))ssl_sw[35].ptr)
#define SSL_get_servername \
(*(const char *(*)(const SSL *, int type))ssl_sw[36].ptr)
#define SSL_set_SSL_CTX (*(SSL_CTX * (*)(SSL *, SSL_CTX *)) ssl_sw[37].ptr)
#define SSL_ctrl (*(long (*)(SSL *, int, long, void *))ssl_sw[38].ptr)
#define SSL_CTX_set_alpn_protos \
(*(int (*)(SSL_CTX *, const unsigned char *, unsigned))ssl_sw[39].ptr)
typedef int (*tSSL_alpn_select_cb)(SSL *ssl,
const unsigned char **out,
unsigned char *outlen,
const unsigned char *in,
unsigned int inlen,
void *arg);
#define SSL_CTX_set_alpn_select_cb \
(*(void (*)(SSL_CTX *, tSSL_alpn_select_cb, void *))ssl_sw[40].ptr)
typedef int (*tSSL_next_protos_advertised_cb)(SSL *ssl,
const unsigned char **out,
unsigned int *outlen,
void *arg);
#define SSL_CTX_set_next_protos_advertised_cb \
(*(void (*)(SSL_CTX *, tSSL_next_protos_advertised_cb, void *))ssl_sw[41] \
.ptr)
#define SSL_CTX_set_timeout (*(long (*)(SSL_CTX *, long))ssl_sw[42].ptr)
#define SSL_CTX_clear_options(ctx, op) \
SSL_CTX_ctrl((ctx), SSL_CTRL_CLEAR_OPTIONS, (op), NULL)
#define SSL_CTX_set_ecdh_auto(ctx, onoff) \
SSL_CTX_ctrl(ctx, SSL_CTRL_SET_ECDH_AUTO, onoff, NULL)
#define SSL_CTRL_SET_TLSEXT_SERVERNAME_CB 53
#define SSL_CTRL_SET_TLSEXT_SERVERNAME_ARG 54
#define SSL_CTRL_SET_TLSEXT_HOSTNAME 55
#define SSL_CTX_set_tlsext_servername_callback(ctx, cb) \
SSL_CTX_callback_ctrl(ctx, \
SSL_CTRL_SET_TLSEXT_SERVERNAME_CB, \
(void (*)(void))cb)
#define SSL_set_tlsext_host_name(ctx, arg) \
SSL_ctrl(ctx, SSL_CTRL_SET_TLSEXT_HOSTNAME, 0, (void *)arg)
#define X509_get_notBefore(x) ((x)->cert_info->validity->notBefore)
#define X509_get_notAfter(x) ((x)->cert_info->validity->notAfter)
#define SSL_set_app_data(s, arg) (SSL_set_ex_data(s, 0, (char *)arg))
#define SSL_get_app_data(s) (SSL_get_ex_data(s, 0))
#define SSL_CTX_sess_set_cache_size(ctx, size) SSL_CTX_ctrl(ctx, 42, size, NULL)
#define SSL_CTX_set_session_cache_mode(ctx, mode) \
SSL_CTX_ctrl(ctx, 44, mode, NULL)
#define ERR_get_error (*(unsigned long (*)(void))crypto_sw[0].ptr)
#define ERR_error_string (*(char *(*)(unsigned long, char *))crypto_sw[1].ptr)
#define CONF_modules_unload (*(void (*)(int))crypto_sw[2].ptr)
#define X509_free (*(void (*)(X509 *))crypto_sw[3].ptr)
#define X509_get_subject_name (*(X509_NAME * (*)(X509 *)) crypto_sw[4].ptr)
#define X509_get_issuer_name (*(X509_NAME * (*)(X509 *)) crypto_sw[5].ptr)
#define X509_NAME_oneline \
(*(char *(*)(X509_NAME *, char *, int))crypto_sw[6].ptr)
#define X509_get_serialNumber (*(ASN1_INTEGER * (*)(X509 *)) crypto_sw[7].ptr)
#define EVP_get_digestbyname \
(*(const EVP_MD *(*)(const char *))crypto_sw[8].ptr)
#define EVP_Digest \
(*(int (*)( \
const void *, size_t, void *, unsigned int *, const EVP_MD *, void *)) \
crypto_sw[9] \
.ptr)
#define i2d_X509 (*(int (*)(X509 *, unsigned char **))crypto_sw[10].ptr)
#define BN_bn2hex (*(char *(*)(const BIGNUM *a))crypto_sw[11].ptr)
#define ASN1_INTEGER_to_BN \
(*(BIGNUM * (*)(const ASN1_INTEGER *ai, BIGNUM *bn)) crypto_sw[12].ptr)
#define BN_free (*(void (*)(const BIGNUM *a))crypto_sw[13].ptr)
#define CRYPTO_free (*(void (*)(void *addr))crypto_sw[14].ptr)
#define ERR_clear_error (*(void (*)(void))crypto_sw[15].ptr)
#define OPENSSL_free(a) CRYPTO_free(a)
#define OPENSSL_REMOVE_THREAD_STATE()
/* init_ssl_ctx() function updates this array.
* It loads SSL library dynamically and changes NULLs to the actual addresses
* of respective functions. The macros above (like SSL_connect()) are really
* just calling these functions indirectly via the pointer. */
static struct ssl_func ssl_sw[] = {
{"SSL_free", TLS_Mandatory, NULL},
{"SSL_accept", TLS_Mandatory, NULL},
{"SSL_connect", TLS_Mandatory, NULL},
{"SSL_read", TLS_Mandatory, NULL},
{"SSL_write", TLS_Mandatory, NULL},
{"SSL_get_error", TLS_Mandatory, NULL},
{"SSL_set_fd", TLS_Mandatory, NULL},
{"SSL_new", TLS_Mandatory, NULL},
{"SSL_CTX_new", TLS_Mandatory, NULL},
{"TLS_server_method", TLS_Mandatory, NULL},
{"OPENSSL_init_ssl", TLS_Mandatory, NULL},
{"SSL_CTX_use_PrivateKey_file", TLS_Mandatory, NULL},
{"SSL_CTX_use_certificate_file", TLS_Mandatory, NULL},
{"SSL_CTX_set_default_passwd_cb", TLS_Mandatory, NULL},
{"SSL_CTX_free", TLS_Mandatory, NULL},
{"SSL_CTX_use_certificate_chain_file", TLS_Mandatory, NULL},
{"TLS_client_method", TLS_Mandatory, NULL},
{"SSL_pending", TLS_Mandatory, NULL},
{"SSL_CTX_set_verify", TLS_Mandatory, NULL},
{"SSL_shutdown", TLS_Mandatory, NULL},
{"SSL_CTX_load_verify_locations", TLS_Mandatory, NULL},
{"SSL_CTX_set_default_verify_paths", TLS_Mandatory, NULL},
{"SSL_CTX_set_verify_depth", TLS_Mandatory, NULL},
#if defined(OPENSSL_API_3_0)
{"SSL_get1_peer_certificate", TLS_Mandatory, NULL},
#else
{"SSL_get_peer_certificate", TLS_Mandatory, NULL},
#endif
{"SSL_get_version", TLS_Mandatory, NULL},
{"SSL_get_current_cipher", TLS_Mandatory, NULL},
{"SSL_CIPHER_get_name", TLS_Mandatory, NULL},
{"SSL_CTX_check_private_key", TLS_Mandatory, NULL},
{"SSL_CTX_set_session_id_context", TLS_Mandatory, NULL},
{"SSL_CTX_ctrl", TLS_Mandatory, NULL},
{"SSL_CTX_set_cipher_list", TLS_Mandatory, NULL},
{"SSL_CTX_set_options", TLS_Mandatory, NULL},
{"SSL_CTX_set_info_callback", TLS_Mandatory, NULL},
{"SSL_get_ex_data", TLS_Mandatory, NULL},
{"SSL_set_ex_data", TLS_Mandatory, NULL},
{"SSL_CTX_callback_ctrl", TLS_Mandatory, NULL},
{"SSL_get_servername", TLS_Mandatory, NULL},
{"SSL_set_SSL_CTX", TLS_Mandatory, NULL},
{"SSL_ctrl", TLS_Mandatory, NULL},
{"SSL_CTX_set_alpn_protos", TLS_ALPN, NULL},
{"SSL_CTX_set_alpn_select_cb", TLS_ALPN, NULL},
{"SSL_CTX_set_next_protos_advertised_cb", TLS_ALPN, NULL},
{"SSL_CTX_set_timeout", TLS_Mandatory, NULL},
{NULL, TLS_END_OF_LIST, NULL}};
/* Similar array as ssl_sw. These functions could be located in different
* lib. */
static struct ssl_func crypto_sw[] = {
{"ERR_get_error", TLS_Mandatory, NULL},
{"ERR_error_string", TLS_Mandatory, NULL},
{"CONF_modules_unload", TLS_Mandatory, NULL},
{"X509_free", TLS_Mandatory, NULL},
{"X509_get_subject_name", TLS_Mandatory, NULL},
{"X509_get_issuer_name", TLS_Mandatory, NULL},
{"X509_NAME_oneline", TLS_Mandatory, NULL},
{"X509_get_serialNumber", TLS_Mandatory, NULL},
{"EVP_get_digestbyname", TLS_Mandatory, NULL},
{"EVP_Digest", TLS_Mandatory, NULL},
{"i2d_X509", TLS_Mandatory, NULL},
{"BN_bn2hex", TLS_Mandatory, NULL},
{"ASN1_INTEGER_to_BN", TLS_Mandatory, NULL},
{"BN_free", TLS_Mandatory, NULL},
{"CRYPTO_free", TLS_Mandatory, NULL},
{"ERR_clear_error", TLS_Mandatory, NULL},
{NULL, TLS_END_OF_LIST, NULL}};
#endif
#if defined(OPENSSL_API_1_0)
#define SSL_free (*(void (*)(SSL *))ssl_sw[0].ptr)
#define SSL_accept (*(int (*)(SSL *))ssl_sw[1].ptr)
#define SSL_connect (*(int (*)(SSL *))ssl_sw[2].ptr)
#define SSL_read (*(int (*)(SSL *, void *, int))ssl_sw[3].ptr)
#define SSL_write (*(int (*)(SSL *, const void *, int))ssl_sw[4].ptr)
#define SSL_get_error (*(int (*)(SSL *, int))ssl_sw[5].ptr)
#define SSL_set_fd (*(int (*)(SSL *, SOCKET))ssl_sw[6].ptr)
#define SSL_new (*(SSL * (*)(SSL_CTX *)) ssl_sw[7].ptr)
#define SSL_CTX_new (*(SSL_CTX * (*)(SSL_METHOD *)) ssl_sw[8].ptr)
#define SSLv23_server_method (*(SSL_METHOD * (*)(void)) ssl_sw[9].ptr)
#define SSL_library_init (*(int (*)(void))ssl_sw[10].ptr)
#define SSL_CTX_use_PrivateKey_file \
(*(int (*)(SSL_CTX *, const char *, int))ssl_sw[11].ptr)
#define SSL_CTX_use_certificate_file \
(*(int (*)(SSL_CTX *, const char *, int))ssl_sw[12].ptr)
#define SSL_CTX_set_default_passwd_cb \
(*(void (*)(SSL_CTX *, mg_callback_t))ssl_sw[13].ptr)
#define SSL_CTX_free (*(void (*)(SSL_CTX *))ssl_sw[14].ptr)
#define SSL_load_error_strings (*(void (*)(void))ssl_sw[15].ptr)
#define SSL_CTX_use_certificate_chain_file \
(*(int (*)(SSL_CTX *, const char *))ssl_sw[16].ptr)
#define SSLv23_client_method (*(SSL_METHOD * (*)(void)) ssl_sw[17].ptr)
#define SSL_pending (*(int (*)(SSL *))ssl_sw[18].ptr)
#define SSL_CTX_set_verify \
(*(void (*)(SSL_CTX *, \
int, \
int (*verify_callback)(int, X509_STORE_CTX *)))ssl_sw[19] \
.ptr)
#define SSL_shutdown (*(int (*)(SSL *))ssl_sw[20].ptr)
#define SSL_CTX_load_verify_locations \
(*(int (*)(SSL_CTX *, const char *, const char *))ssl_sw[21].ptr)
#define SSL_CTX_set_default_verify_paths (*(int (*)(SSL_CTX *))ssl_sw[22].ptr)
#define SSL_CTX_set_verify_depth (*(void (*)(SSL_CTX *, int))ssl_sw[23].ptr)
#define SSL_get_peer_certificate (*(X509 * (*)(SSL *)) ssl_sw[24].ptr)
#define SSL_get_version (*(const char *(*)(SSL *))ssl_sw[25].ptr)
#define SSL_get_current_cipher (*(SSL_CIPHER * (*)(SSL *)) ssl_sw[26].ptr)
#define SSL_CIPHER_get_name \
(*(const char *(*)(const SSL_CIPHER *))ssl_sw[27].ptr)
#define SSL_CTX_check_private_key (*(int (*)(SSL_CTX *))ssl_sw[28].ptr)
#define SSL_CTX_set_session_id_context \
(*(int (*)(SSL_CTX *, const unsigned char *, unsigned int))ssl_sw[29].ptr)
#define SSL_CTX_ctrl (*(long (*)(SSL_CTX *, int, long, void *))ssl_sw[30].ptr)
#define SSL_CTX_set_cipher_list \
(*(int (*)(SSL_CTX *, const char *))ssl_sw[31].ptr)
#define SSL_CTX_set_info_callback \
(*(void (*)(SSL_CTX *, void (*callback)(const SSL *, int, int)))ssl_sw[32] \
.ptr)
#define SSL_get_ex_data (*(char *(*)(const SSL *, int))ssl_sw[33].ptr)
#define SSL_set_ex_data (*(void (*)(SSL *, int, char *))ssl_sw[34].ptr)
#define SSL_CTX_callback_ctrl \
(*(long (*)(SSL_CTX *, int, void (*)(void)))ssl_sw[35].ptr)
#define SSL_get_servername \
(*(const char *(*)(const SSL *, int type))ssl_sw[36].ptr)
#define SSL_set_SSL_CTX (*(SSL_CTX * (*)(SSL *, SSL_CTX *)) ssl_sw[37].ptr)
#define SSL_ctrl (*(long (*)(SSL *, int, long, void *))ssl_sw[38].ptr)
#define SSL_CTX_set_alpn_protos \
(*(int (*)(SSL_CTX *, const unsigned char *, unsigned))ssl_sw[39].ptr)
typedef int (*tSSL_alpn_select_cb)(SSL *ssl,
const unsigned char **out,
unsigned char *outlen,
const unsigned char *in,
unsigned int inlen,
void *arg);
#define SSL_CTX_set_alpn_select_cb \
(*(void (*)(SSL_CTX *, tSSL_alpn_select_cb, void *))ssl_sw[40].ptr)
typedef int (*tSSL_next_protos_advertised_cb)(SSL *ssl,
const unsigned char **out,
unsigned int *outlen,
void *arg);
#define SSL_CTX_set_next_protos_advertised_cb \
(*(void (*)(SSL_CTX *, tSSL_next_protos_advertised_cb, void *))ssl_sw[41] \
.ptr)
#define SSL_CTX_set_timeout (*(long (*)(SSL_CTX *, long))ssl_sw[42].ptr)
#define SSL_CTX_set_options(ctx, op) \
SSL_CTX_ctrl((ctx), SSL_CTRL_OPTIONS, (op), NULL)
#define SSL_CTX_clear_options(ctx, op) \
SSL_CTX_ctrl((ctx), SSL_CTRL_CLEAR_OPTIONS, (op), NULL)
#define SSL_CTX_set_ecdh_auto(ctx, onoff) \
SSL_CTX_ctrl(ctx, SSL_CTRL_SET_ECDH_AUTO, onoff, NULL)
#define SSL_CTRL_SET_TLSEXT_SERVERNAME_CB 53
#define SSL_CTRL_SET_TLSEXT_SERVERNAME_ARG 54
#define SSL_CTRL_SET_TLSEXT_HOSTNAME 55
#define SSL_CTX_set_tlsext_servername_callback(ctx, cb) \
SSL_CTX_callback_ctrl(ctx, \
SSL_CTRL_SET_TLSEXT_SERVERNAME_CB, \
(void (*)(void))cb)
#define SSL_set_tlsext_host_name(ctx, arg) \
SSL_ctrl(ctx, SSL_CTRL_SET_TLSEXT_HOSTNAME, 0, (void *)arg)
#define X509_get_notBefore(x) ((x)->cert_info->validity->notBefore)
#define X509_get_notAfter(x) ((x)->cert_info->validity->notAfter)
#define SSL_set_app_data(s, arg) (SSL_set_ex_data(s, 0, (char *)arg))
#define SSL_get_app_data(s) (SSL_get_ex_data(s, 0))
#define SSL_CTX_sess_set_cache_size(ctx, size) SSL_CTX_ctrl(ctx, 42, size, NULL)
#define SSL_CTX_set_session_cache_mode(ctx, mode) \
SSL_CTX_ctrl(ctx, 44, mode, NULL)
#define CRYPTO_num_locks (*(int (*)(void))crypto_sw[0].ptr)
#define CRYPTO_set_locking_callback \
(*(void (*)(void (*)(int, int, const char *, int)))crypto_sw[1].ptr)
#define CRYPTO_set_id_callback \
(*(void (*)(unsigned long (*)(void)))crypto_sw[2].ptr)
#define ERR_get_error (*(unsigned long (*)(void))crypto_sw[3].ptr)
#define ERR_error_string (*(char *(*)(unsigned long, char *))crypto_sw[4].ptr)
#define ERR_remove_state (*(void (*)(unsigned long))crypto_sw[5].ptr)
#define ERR_free_strings (*(void (*)(void))crypto_sw[6].ptr)
#define ENGINE_cleanup (*(void (*)(void))crypto_sw[7].ptr)
#define CONF_modules_unload (*(void (*)(int))crypto_sw[8].ptr)
#define CRYPTO_cleanup_all_ex_data (*(void (*)(void))crypto_sw[9].ptr)
#define EVP_cleanup (*(void (*)(void))crypto_sw[10].ptr)
#define X509_free (*(void (*)(X509 *))crypto_sw[11].ptr)
#define X509_get_subject_name (*(X509_NAME * (*)(X509 *)) crypto_sw[12].ptr)
#define X509_get_issuer_name (*(X509_NAME * (*)(X509 *)) crypto_sw[13].ptr)
#define X509_NAME_oneline \
(*(char *(*)(X509_NAME *, char *, int))crypto_sw[14].ptr)
#define X509_get_serialNumber (*(ASN1_INTEGER * (*)(X509 *)) crypto_sw[15].ptr)
#define i2c_ASN1_INTEGER \
(*(int (*)(ASN1_INTEGER *, unsigned char **))crypto_sw[16].ptr)
#define EVP_get_digestbyname \
(*(const EVP_MD *(*)(const char *))crypto_sw[17].ptr)
#define EVP_Digest \
(*(int (*)( \
const void *, size_t, void *, unsigned int *, const EVP_MD *, void *)) \
crypto_sw[18] \
.ptr)
#define i2d_X509 (*(int (*)(X509 *, unsigned char **))crypto_sw[19].ptr)
#define BN_bn2hex (*(char *(*)(const BIGNUM *a))crypto_sw[20].ptr)
#define ASN1_INTEGER_to_BN \
(*(BIGNUM * (*)(const ASN1_INTEGER *ai, BIGNUM *bn)) crypto_sw[21].ptr)
#define BN_free (*(void (*)(const BIGNUM *a))crypto_sw[22].ptr)
#define CRYPTO_free (*(void (*)(void *addr))crypto_sw[23].ptr)
#define ERR_clear_error (*(void (*)(void))crypto_sw[24].ptr)
#define OPENSSL_free(a) CRYPTO_free(a)
/* use here ERR_remove_state,
* while on some platforms function is not included into library due to
* deprication */
#define OPENSSL_REMOVE_THREAD_STATE() ERR_remove_state(0)
/* init_ssl_ctx() function updates this array.
* It loads SSL library dynamically and changes NULLs to the actual addresses
* of respective functions. The macros above (like SSL_connect()) are really
* just calling these functions indirectly via the pointer. */
static struct ssl_func ssl_sw[] = {
{"SSL_free", TLS_Mandatory, NULL},
{"SSL_accept", TLS_Mandatory, NULL},
{"SSL_connect", TLS_Mandatory, NULL},
{"SSL_read", TLS_Mandatory, NULL},
{"SSL_write", TLS_Mandatory, NULL},
{"SSL_get_error", TLS_Mandatory, NULL},
{"SSL_set_fd", TLS_Mandatory, NULL},
{"SSL_new", TLS_Mandatory, NULL},
{"SSL_CTX_new", TLS_Mandatory, NULL},
{"SSLv23_server_method", TLS_Mandatory, NULL},
{"SSL_library_init", TLS_Mandatory, NULL},
{"SSL_CTX_use_PrivateKey_file", TLS_Mandatory, NULL},
{"SSL_CTX_use_certificate_file", TLS_Mandatory, NULL},
{"SSL_CTX_set_default_passwd_cb", TLS_Mandatory, NULL},
{"SSL_CTX_free", TLS_Mandatory, NULL},
{"SSL_load_error_strings", TLS_Mandatory, NULL},
{"SSL_CTX_use_certificate_chain_file", TLS_Mandatory, NULL},
{"SSLv23_client_method", TLS_Mandatory, NULL},
{"SSL_pending", TLS_Mandatory, NULL},
{"SSL_CTX_set_verify", TLS_Mandatory, NULL},
{"SSL_shutdown", TLS_Mandatory, NULL},
{"SSL_CTX_load_verify_locations", TLS_Mandatory, NULL},
{"SSL_CTX_set_default_verify_paths", TLS_Mandatory, NULL},
{"SSL_CTX_set_verify_depth", TLS_Mandatory, NULL},
{"SSL_get_peer_certificate", TLS_Mandatory, NULL},
{"SSL_get_version", TLS_Mandatory, NULL},
{"SSL_get_current_cipher", TLS_Mandatory, NULL},
{"SSL_CIPHER_get_name", TLS_Mandatory, NULL},
{"SSL_CTX_check_private_key", TLS_Mandatory, NULL},
{"SSL_CTX_set_session_id_context", TLS_Mandatory, NULL},
{"SSL_CTX_ctrl", TLS_Mandatory, NULL},
{"SSL_CTX_set_cipher_list", TLS_Mandatory, NULL},
{"SSL_CTX_set_info_callback", TLS_Mandatory, NULL},
{"SSL_get_ex_data", TLS_Mandatory, NULL},
{"SSL_set_ex_data", TLS_Mandatory, NULL},
{"SSL_CTX_callback_ctrl", TLS_Mandatory, NULL},
{"SSL_get_servername", TLS_Mandatory, NULL},
{"SSL_set_SSL_CTX", TLS_Mandatory, NULL},
{"SSL_ctrl", TLS_Mandatory, NULL},
{"SSL_CTX_set_alpn_protos", TLS_ALPN, NULL},
{"SSL_CTX_set_alpn_select_cb", TLS_ALPN, NULL},
{"SSL_CTX_set_next_protos_advertised_cb", TLS_ALPN, NULL},
{"SSL_CTX_set_timeout", TLS_Mandatory, NULL},
{NULL, TLS_END_OF_LIST, NULL}};
/* Similar array as ssl_sw. These functions could be located in different
* lib. */
static struct ssl_func crypto_sw[] = {
{"CRYPTO_num_locks", TLS_Mandatory, NULL},
{"CRYPTO_set_locking_callback", TLS_Mandatory, NULL},
{"CRYPTO_set_id_callback", TLS_Mandatory, NULL},
{"ERR_get_error", TLS_Mandatory, NULL},
{"ERR_error_string", TLS_Mandatory, NULL},
{"ERR_remove_state", TLS_Mandatory, NULL},
{"ERR_free_strings", TLS_Mandatory, NULL},
{"ENGINE_cleanup", TLS_Mandatory, NULL},
{"CONF_modules_unload", TLS_Mandatory, NULL},
{"CRYPTO_cleanup_all_ex_data", TLS_Mandatory, NULL},
{"EVP_cleanup", TLS_Mandatory, NULL},
{"X509_free", TLS_Mandatory, NULL},
{"X509_get_subject_name", TLS_Mandatory, NULL},
{"X509_get_issuer_name", TLS_Mandatory, NULL},
{"X509_NAME_oneline", TLS_Mandatory, NULL},
{"X509_get_serialNumber", TLS_Mandatory, NULL},
{"i2c_ASN1_INTEGER", TLS_Mandatory, NULL},
{"EVP_get_digestbyname", TLS_Mandatory, NULL},
{"EVP_Digest", TLS_Mandatory, NULL},
{"i2d_X509", TLS_Mandatory, NULL},
{"BN_bn2hex", TLS_Mandatory, NULL},
{"ASN1_INTEGER_to_BN", TLS_Mandatory, NULL},
{"BN_free", TLS_Mandatory, NULL},
{"CRYPTO_free", TLS_Mandatory, NULL},
{"ERR_clear_error", TLS_Mandatory, NULL},
{NULL, TLS_END_OF_LIST, NULL}};
#endif /* OPENSSL_API_1_0 */

326
vendor/CivetWeb/response.inl vendored Normal file
View File

@ -0,0 +1,326 @@
/* response.inl
*
* Bufferring for HTTP headers for HTTP response.
* This function are only intended to be used at the server side.
* Optional for HTTP/1.0 and HTTP/1.1, mandatory for HTTP/2.
*
* This file is part of the CivetWeb project.
*/
#if defined(NO_RESPONSE_BUFFERING) && defined(USE_HTTP2)
#error "HTTP2 works only if NO_RESPONSE_BUFFERING is not set"
#endif
/* Internal function to free header list */
static void
free_buffered_response_header_list(struct mg_connection *conn)
{
#if !defined(NO_RESPONSE_BUFFERING)
while (conn->response_info.num_headers > 0) {
conn->response_info.num_headers--;
mg_free((void *)conn->response_info
.http_headers[conn->response_info.num_headers]
.name);
conn->response_info.http_headers[conn->response_info.num_headers].name =
0;
mg_free((void *)conn->response_info
.http_headers[conn->response_info.num_headers]
.value);
conn->response_info.http_headers[conn->response_info.num_headers]
.value = 0;
}
#else
(void)conn; /* Nothing to do */
#endif
}
/* Send first line of HTTP/1.x response */
static void
send_http1_response_status_line(struct mg_connection *conn)
{
const char *status_txt;
const char *http_version = conn->request_info.http_version;
int status_code = conn->status_code;
if ((status_code < 100) || (status_code > 999)) {
/* Set invalid status code to "500 Internal Server Error" */
status_code = 500;
}
if (!http_version) {
http_version = "1.0";
}
/* mg_get_response_code_text will never return NULL */
status_txt = mg_get_response_code_text(conn, conn->status_code);
mg_printf(conn, "HTTP/%s %i %s\r\n", http_version, status_code, status_txt);
}
/* Initialize a new HTTP response
* Parameters:
* conn: Current connection handle.
* status: HTTP status code (e.g., 200 for "OK").
* Return:
* 0: ok
* -1: parameter error
* -2: invalid connection type
* -3: invalid connection status
*/
int
mg_response_header_start(struct mg_connection *conn, int status)
{
if ((conn == NULL) || (status < 100) || (status > 999)) {
/* Parameter error */
return -1;
}
if ((conn->connection_type != CONNECTION_TYPE_REQUEST)
|| (conn->protocol_type == PROTOCOL_TYPE_WEBSOCKET)) {
/* Only allowed in server context */
return -2;
}
if (conn->request_state != 0) {
/* only allowed if nothing was sent up to now */
return -3;
}
conn->status_code = status;
conn->request_state = 1;
/* Buffered response is stored, unbuffered response will be sent directly,
* but we can only send HTTP/1.x response here */
#if !defined(NO_RESPONSE_BUFFERING)
free_buffered_response_header_list(conn);
#else
send_http1_response_status_line(conn);
conn->request_state = 1; /* Reset from 10 to 1 */
#endif
return 0;
}
/* Add a new HTTP response header line
* Parameters:
* conn: Current connection handle.
* header: Header name.
* value: Header value.
* value_len: Length of header value, excluding the terminating zero.
* Use -1 for "strlen(value)".
* Return:
* 0: ok
* -1: parameter error
* -2: invalid connection type
* -3: invalid connection status
* -4: too many headers
* -5: out of memory
*/
int
mg_response_header_add(struct mg_connection *conn,
const char *header,
const char *value,
int value_len)
{
#if !defined(NO_RESPONSE_BUFFERING)
int hidx;
#endif
if ((conn == NULL) || (header == NULL) || (value == NULL)) {
/* Parameter error */
return -1;
}
if ((conn->connection_type != CONNECTION_TYPE_REQUEST)
|| (conn->protocol_type == PROTOCOL_TYPE_WEBSOCKET)) {
/* Only allowed in server context */
return -2;
}
if (conn->request_state != 1) {
/* only allowed if mg_response_header_start has been called before */
return -3;
}
#if !defined(NO_RESPONSE_BUFFERING)
hidx = conn->response_info.num_headers;
if (hidx >= MG_MAX_HEADERS) {
/* Too many headers */
return -4;
}
/* Alloc new element */
conn->response_info.http_headers[hidx].name =
mg_strdup_ctx(header, conn->phys_ctx);
if (value_len >= 0) {
char *hbuf =
(char *)mg_malloc_ctx((unsigned)value_len + 1, conn->phys_ctx);
if (hbuf) {
memcpy(hbuf, value, (unsigned)value_len);
hbuf[value_len] = 0;
}
conn->response_info.http_headers[hidx].value = hbuf;
} else {
conn->response_info.http_headers[hidx].value =
mg_strdup_ctx(value, conn->phys_ctx);
}
if ((conn->response_info.http_headers[hidx].name == 0)
|| (conn->response_info.http_headers[hidx].value == 0)) {
/* Out of memory */
mg_free((void *)conn->response_info.http_headers[hidx].name);
conn->response_info.http_headers[hidx].name = 0;
mg_free((void *)conn->response_info.http_headers[hidx].value);
conn->response_info.http_headers[hidx].value = 0;
return -5;
}
/* OK, header stored */
conn->response_info.num_headers++;
#else
if (value_len >= 0) {
mg_printf(conn, "%s: %.*s\r\n", header, (int)value_len, value);
} else {
mg_printf(conn, "%s: %s\r\n", header, value);
}
conn->request_state = 1; /* Reset from 10 to 1 */
#endif
return 0;
}
/* forward */
static int parse_http_headers(char **buf, struct mg_header hdr[MG_MAX_HEADERS]);
/* Add a complete header string (key + value).
* Parameters:
* conn: Current connection handle.
* http1_headers: Header line(s) in the form "name: value".
* Return:
* >=0: no error, number of header lines added
* -1: parameter error
* -2: invalid connection type
* -3: invalid connection status
* -4: too many headers
* -5: out of memory
*/
int
mg_response_header_add_lines(struct mg_connection *conn,
const char *http1_headers)
{
struct mg_header add_hdr[MG_MAX_HEADERS];
int num_hdr, i, ret;
char *workbuffer, *parse;
/* We need to work on a copy of the work buffer, sice parse_http_headers
* will modify */
workbuffer = mg_strdup_ctx(http1_headers, conn->phys_ctx);
if (!workbuffer) {
/* Out of memory */
return -5;
}
/* Call existing method to split header buffer */
parse = workbuffer;
num_hdr = parse_http_headers(&parse, add_hdr);
ret = num_hdr;
for (i = 0; i < num_hdr; i++) {
int lret =
mg_response_header_add(conn, add_hdr[i].name, add_hdr[i].value, -1);
if ((ret > 0) && (lret < 0)) {
/* Store error return value */
ret = lret;
}
}
/* mg_response_header_add created a copy, so we can free the original */
mg_free(workbuffer);
return ret;
}
#if defined(USE_HTTP2)
static int http2_send_response_headers(struct mg_connection *conn);
#endif
/* Send http response
* Parameters:
* conn: Current connection handle.
* Return:
* 0: ok
* -1: parameter error
* -2: invalid connection type
* -3: invalid connection status
*/
int
mg_response_header_send(struct mg_connection *conn)
{
#if !defined(NO_RESPONSE_BUFFERING)
int i;
int has_date = 0;
int has_connection = 0;
#endif
if (conn == NULL) {
/* Parameter error */
return -1;
}
if ((conn->connection_type != CONNECTION_TYPE_REQUEST)
|| (conn->protocol_type == PROTOCOL_TYPE_WEBSOCKET)) {
/* Only allowed in server context */
return -2;
}
if (conn->request_state != 1) {
/* only allowed if mg_response_header_start has been called before */
return -3;
}
/* State: 2 */
conn->request_state = 2;
#if !defined(NO_RESPONSE_BUFFERING)
#if defined(USE_HTTP2)
if (conn->protocol_type == PROTOCOL_TYPE_HTTP2) {
int ret = http2_send_response_headers(conn);
return ret ? 0 : 0; /* todo */
}
#endif
/* Send */
send_http1_response_status_line(conn);
for (i = 0; i < conn->response_info.num_headers; i++) {
mg_printf(conn,
"%s: %s\r\n",
conn->response_info.http_headers[i].name,
conn->response_info.http_headers[i].value);
/* Check for some special headers */
if (!mg_strcasecmp("Date", conn->response_info.http_headers[i].name)) {
has_date = 1;
}
if (!mg_strcasecmp("Connection",
conn->response_info.http_headers[i].name)) {
has_connection = 1;
}
}
if (!has_date) {
time_t curtime = time(NULL);
char date[64];
gmt_time_string(date, sizeof(date), &curtime);
mg_printf(conn, "Date: %s\r\n", date);
}
if (!has_connection) {
mg_printf(conn, "Connection: %s\r\n", suggest_connection_header(conn));
}
#endif
mg_write(conn, "\r\n", 2);
conn->request_state = 3;
/* ok */
return 0;
}

323
vendor/CivetWeb/sha1.inl vendored Normal file
View File

@ -0,0 +1,323 @@
/*
SHA-1 in C
By Steve Reid <sreid@sea-to-sky.net>
100% Public Domain
-----------------
Modified 7/98
By James H. Brown <jbrown@burgoyne.com>
Still 100% Public Domain
Corrected a problem which generated improper hash values on 16 bit machines
Routine SHA1Update changed from
void SHA1Update(SHA_CTX* context, unsigned char* data, unsigned int
len)
to
void SHA1Update(SHA_CTX* context, unsigned char* data, unsigned
long len)
The 'len' parameter was declared an int which works fine on 32 bit machines.
However, on 16 bit machines an int is too small for the shifts being done
against
it. This caused the hash function to generate incorrect values if len was
greater than 8191 (8K - 1) due to the 'len << 3' on line 3 of SHA1Update().
Since the file IO in main() reads 16K at a time, any file 8K or larger would
be guaranteed to generate the wrong hash (e.g. Test Vector #3, a million
"a"s).
I also changed the declaration of variables i & j in SHA1Update to
unsigned long from unsigned int for the same reason.
These changes should make no difference to any 32 bit implementations since
an
int and a long are the same size in those environments.
--
I also corrected a few compiler warnings generated by Borland C.
1. Added #include <process.h> for exit() prototype
2. Removed unused variable 'j' in SHA1Final
3. Changed exit(0) to return(0) at end of main.
ALL changes I made can be located by searching for comments containing 'JHB'
-----------------
Modified 8/98
By Steve Reid <sreid@sea-to-sky.net>
Still 100% public domain
1- Removed #include <process.h> and used return() instead of exit()
2- Fixed overwriting of finalcount in SHA1Final() (discovered by Chris Hall)
3- Changed email address from steve@edmweb.com to sreid@sea-to-sky.net
-----------------
Modified 4/01
By Saul Kravitz <Saul.Kravitz@celera.com>
Still 100% PD
Modified to run on Compaq Alpha hardware.
-----------------
Modified 07/2002
By Ralph Giles <giles@ghostscript.com>
Still 100% public domain
modified for use with stdint types, autoconf
code cleanup, removed attribution comments
switched SHA1Final() argument order for consistency
use SHA1_ prefix for public api
move public api to sha1.h
*/
/*
11/2016 adapted for CivetWeb:
include sha1.h in sha1.c,
rename to sha1.inl
remove unused #ifdef sections
make endian independent
align buffer to 4 bytes
remove unused variable assignments
*/
/*
Test Vectors (from FIPS PUB 180-1)
"abc"
A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D
"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1
A million repetitions of "a"
34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F
*/
#include <stdint.h>
#include <string.h>
typedef struct {
uint32_t state[5];
uint32_t count[2];
uint8_t buffer[64];
} SHA_CTX;
#define SHA1_DIGEST_SIZE 20
#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
/* blk0() and blk() perform the initial expand. */
/* I got the idea of expanding during the round function from SSLeay */
typedef union {
uint8_t c[64];
uint32_t l[16];
} CHAR64LONG16;
static uint32_t
blk0(CHAR64LONG16 *block, int i)
{
static const uint32_t n = 1u;
if ((*((uint8_t *)(&n))) == 1) {
/* little endian / intel byte order */
block->l[i] = (rol(block->l[i], 24) & 0xFF00FF00)
| (rol(block->l[i], 8) & 0x00FF00FF);
}
return block->l[i];
}
#define blk(block, i) \
((block)->l[(i)&15] = \
rol((block)->l[((i) + 13) & 15] ^ (block)->l[((i) + 8) & 15] \
^ (block)->l[((i) + 2) & 15] ^ (block)->l[(i)&15], \
1))
/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */
#define R0(v, w, x, y, z, i) \
z += ((w & (x ^ y)) ^ y) + blk0(block, i) + 0x5A827999 + rol(v, 5); \
w = rol(w, 30);
#define R1(v, w, x, y, z, i) \
z += ((w & (x ^ y)) ^ y) + blk(block, i) + 0x5A827999 + rol(v, 5); \
w = rol(w, 30);
#define R2(v, w, x, y, z, i) \
z += (w ^ x ^ y) + blk(block, i) + 0x6ED9EBA1 + rol(v, 5); \
w = rol(w, 30);
#define R3(v, w, x, y, z, i) \
z += (((w | x) & y) | (w & x)) + blk(block, i) + 0x8F1BBCDC + rol(v, 5); \
w = rol(w, 30);
#define R4(v, w, x, y, z, i) \
z += (w ^ x ^ y) + blk(block, i) + 0xCA62C1D6 + rol(v, 5); \
w = rol(w, 30);
/* Hash a single 512-bit block. This is the core of the algorithm. */
static void
SHA1_Transform(uint32_t state[5], const uint8_t buffer[64])
{
uint32_t a, b, c, d, e;
/* Must use an aligned, read/write buffer */
CHAR64LONG16 block[1];
memcpy(block, buffer, sizeof(block));
/* Copy context->state[] to working vars */
a = state[0];
b = state[1];
c = state[2];
d = state[3];
e = state[4];
/* 4 rounds of 20 operations each. Loop unrolled. */
R0(a, b, c, d, e, 0);
R0(e, a, b, c, d, 1);
R0(d, e, a, b, c, 2);
R0(c, d, e, a, b, 3);
R0(b, c, d, e, a, 4);
R0(a, b, c, d, e, 5);
R0(e, a, b, c, d, 6);
R0(d, e, a, b, c, 7);
R0(c, d, e, a, b, 8);
R0(b, c, d, e, a, 9);
R0(a, b, c, d, e, 10);
R0(e, a, b, c, d, 11);
R0(d, e, a, b, c, 12);
R0(c, d, e, a, b, 13);
R0(b, c, d, e, a, 14);
R0(a, b, c, d, e, 15);
R1(e, a, b, c, d, 16);
R1(d, e, a, b, c, 17);
R1(c, d, e, a, b, 18);
R1(b, c, d, e, a, 19);
R2(a, b, c, d, e, 20);
R2(e, a, b, c, d, 21);
R2(d, e, a, b, c, 22);
R2(c, d, e, a, b, 23);
R2(b, c, d, e, a, 24);
R2(a, b, c, d, e, 25);
R2(e, a, b, c, d, 26);
R2(d, e, a, b, c, 27);
R2(c, d, e, a, b, 28);
R2(b, c, d, e, a, 29);
R2(a, b, c, d, e, 30);
R2(e, a, b, c, d, 31);
R2(d, e, a, b, c, 32);
R2(c, d, e, a, b, 33);
R2(b, c, d, e, a, 34);
R2(a, b, c, d, e, 35);
R2(e, a, b, c, d, 36);
R2(d, e, a, b, c, 37);
R2(c, d, e, a, b, 38);
R2(b, c, d, e, a, 39);
R3(a, b, c, d, e, 40);
R3(e, a, b, c, d, 41);
R3(d, e, a, b, c, 42);
R3(c, d, e, a, b, 43);
R3(b, c, d, e, a, 44);
R3(a, b, c, d, e, 45);
R3(e, a, b, c, d, 46);
R3(d, e, a, b, c, 47);
R3(c, d, e, a, b, 48);
R3(b, c, d, e, a, 49);
R3(a, b, c, d, e, 50);
R3(e, a, b, c, d, 51);
R3(d, e, a, b, c, 52);
R3(c, d, e, a, b, 53);
R3(b, c, d, e, a, 54);
R3(a, b, c, d, e, 55);
R3(e, a, b, c, d, 56);
R3(d, e, a, b, c, 57);
R3(c, d, e, a, b, 58);
R3(b, c, d, e, a, 59);
R4(a, b, c, d, e, 60);
R4(e, a, b, c, d, 61);
R4(d, e, a, b, c, 62);
R4(c, d, e, a, b, 63);
R4(b, c, d, e, a, 64);
R4(a, b, c, d, e, 65);
R4(e, a, b, c, d, 66);
R4(d, e, a, b, c, 67);
R4(c, d, e, a, b, 68);
R4(b, c, d, e, a, 69);
R4(a, b, c, d, e, 70);
R4(e, a, b, c, d, 71);
R4(d, e, a, b, c, 72);
R4(c, d, e, a, b, 73);
R4(b, c, d, e, a, 74);
R4(a, b, c, d, e, 75);
R4(e, a, b, c, d, 76);
R4(d, e, a, b, c, 77);
R4(c, d, e, a, b, 78);
R4(b, c, d, e, a, 79);
/* Add the working vars back into context.state[] */
state[0] += a;
state[1] += b;
state[2] += c;
state[3] += d;
state[4] += e;
}
/* SHA1Init - Initialize new context */
SHA_API void
SHA1_Init(SHA_CTX *context)
{
/* SHA1 initialization constants */
context->state[0] = 0x67452301;
context->state[1] = 0xEFCDAB89;
context->state[2] = 0x98BADCFE;
context->state[3] = 0x10325476;
context->state[4] = 0xC3D2E1F0;
context->count[0] = context->count[1] = 0;
}
SHA_API void
SHA1_Update(SHA_CTX *context, const uint8_t *data, const uint32_t len)
{
uint32_t i, j;
j = context->count[0];
if ((context->count[0] += (len << 3)) < j) {
context->count[1]++;
}
context->count[1] += (len >> 29);
j = (j >> 3) & 63;
if ((j + len) > 63) {
i = 64 - j;
memcpy(&context->buffer[j], data, i);
SHA1_Transform(context->state, context->buffer);
for (; i + 63 < len; i += 64) {
SHA1_Transform(context->state, &data[i]);
}
j = 0;
} else {
i = 0;
}
memcpy(&context->buffer[j], &data[i], len - i);
}
/* Add padding and return the message digest. */
SHA_API void
SHA1_Final(unsigned char *digest, SHA_CTX *context)
{
uint32_t i;
uint8_t finalcount[8];
for (i = 0; i < 8; i++) {
finalcount[i] =
(uint8_t)((context->count[(i >= 4 ? 0 : 1)] >> ((3 - (i & 3)) * 8))
& 255); /* Endian independent */
}
SHA1_Update(context, (uint8_t *)"\x80", 1);
while ((context->count[0] & 504) != 448) {
SHA1_Update(context, (uint8_t *)"\x00", 1);
}
SHA1_Update(context, finalcount, 8); /* Should cause a SHA1_Transform() */
for (i = 0; i < SHA1_DIGEST_SIZE; i++) {
digest[i] =
(uint8_t)((context->state[i >> 2] >> ((3 - (i & 3)) * 8)) & 255);
}
/* Wipe variables */
memset(context, '\0', sizeof(*context));
}
/* End of sha1.inl */

294
vendor/CivetWeb/timer.inl vendored Normal file
View File

@ -0,0 +1,294 @@
/* This file is part of the CivetWeb web server.
* See https://github.com/civetweb/civetweb/
* (C) 2014-2021 by the CivetWeb authors, MIT license.
*/
#if !defined(MAX_TIMERS)
#define MAX_TIMERS MAX_WORKER_THREADS
#endif
#if !defined(TIMER_RESOLUTION)
/* Timer resolution in ms */
#define TIMER_RESOLUTION (10)
#endif
typedef int (*taction)(void *arg);
typedef void (*tcancelaction)(void *arg);
struct ttimer {
double time;
double period;
taction action;
void *arg;
tcancelaction cancel;
};
struct ttimers {
pthread_t threadid; /* Timer thread ID */
pthread_mutex_t mutex; /* Protects timer lists */
struct ttimer *timers; /* List of timers */
unsigned timer_count; /* Current size of timer list */
unsigned timer_capacity; /* Capacity of timer list */
#if defined(_WIN32)
DWORD last_tick;
uint64_t now_tick64;
#endif
};
TIMER_API double
timer_getcurrenttime(struct mg_context *ctx)
{
#if defined(_WIN32)
/* GetTickCount returns milliseconds since system start as
* unsigned 32 bit value. It will wrap around every 49.7 days.
* We need to use a 64 bit counter (will wrap in 500 mio. years),
* by adding the 32 bit difference since the last call to a
* 64 bit counter. This algorithm will only work, if this
* function is called at least once every 7 weeks. */
uint64_t now_tick64 = 0;
DWORD now_tick = GetTickCount();
if (ctx->timers) {
pthread_mutex_lock(&ctx->timers->mutex);
ctx->timers->now_tick64 += now_tick - ctx->timers->last_tick;
now_tick64 = ctx->timers->now_tick64;
ctx->timers->last_tick = now_tick;
pthread_mutex_unlock(&ctx->timers->mutex);
}
return (double)now_tick64 * 1.0E-3;
#else
struct timespec now_ts;
(void)ctx;
clock_gettime(CLOCK_MONOTONIC, &now_ts);
return (double)now_ts.tv_sec + (double)now_ts.tv_nsec * 1.0E-9;
#endif
}
TIMER_API int
timer_add(struct mg_context *ctx,
double next_time,
double period,
int is_relative,
taction action,
void *arg,
tcancelaction cancel)
{
int error = 0;
double now;
if (!ctx->timers) {
return 1;
}
now = timer_getcurrenttime(ctx);
/* HCP24: if is_relative = 0 and next_time < now
* action will be called so fast as possible
* if additional period > 0
* action will be called so fast as possible
* n times until (next_time + (n * period)) > now
* then the period is working
* Solution:
* if next_time < now then we set next_time = now.
* The first callback will be so fast as possible (now)
* but the next callback on period
*/
if (is_relative) {
next_time += now;
}
/* You can not set timers into the past */
if (next_time < now) {
next_time = now;
}
pthread_mutex_lock(&ctx->timers->mutex);
if (ctx->timers->timer_count == MAX_TIMERS) {
error = 1;
} else if (ctx->timers->timer_count == ctx->timers->timer_capacity) {
unsigned capacity = (ctx->timers->timer_capacity * 2) + 1;
struct ttimer *timers =
(struct ttimer *)mg_realloc_ctx(ctx->timers->timers,
capacity * sizeof(struct ttimer),
ctx);
if (timers) {
ctx->timers->timers = timers;
ctx->timers->timer_capacity = capacity;
} else {
error = 1;
}
}
if (!error) {
/* Insert new timer into a sorted list. */
/* The linear list is still most efficient for short lists (small
* number of timers) - if there are many timers, different
* algorithms will work better. */
unsigned u = ctx->timers->timer_count;
for (; (u > 0) && (ctx->timers->timers[u - 1].time > next_time); u--) {
ctx->timers->timers[u] = ctx->timers->timers[u - 1];
}
ctx->timers->timers[u].time = next_time;
ctx->timers->timers[u].period = period;
ctx->timers->timers[u].action = action;
ctx->timers->timers[u].arg = arg;
ctx->timers->timers[u].cancel = cancel;
ctx->timers->timer_count++;
}
pthread_mutex_unlock(&ctx->timers->mutex);
return error;
}
static void
timer_thread_run(void *thread_func_param)
{
struct mg_context *ctx = (struct mg_context *)thread_func_param;
double d;
unsigned u;
int action_res;
struct ttimer t;
mg_set_thread_name("timer");
if (ctx->callbacks.init_thread) {
/* Timer thread */
ctx->callbacks.init_thread(ctx, 2);
}
/* Timer main loop */
d = timer_getcurrenttime(ctx);
while (STOP_FLAG_IS_ZERO(&ctx->stop_flag)) {
pthread_mutex_lock(&ctx->timers->mutex);
if ((ctx->timers->timer_count > 0)
&& (d >= ctx->timers->timers[0].time)) {
/* Timer list is sorted. First action should run now. */
/* Store active timer in "t" */
t = ctx->timers->timers[0];
/* Shift all other timers */
for (u = 1; u < ctx->timers->timer_count; u++) {
ctx->timers->timers[u - 1] = ctx->timers->timers[u];
}
ctx->timers->timer_count--;
pthread_mutex_unlock(&ctx->timers->mutex);
/* Call timer action */
action_res = t.action(t.arg);
/* action_res == 1: reschedule */
/* action_res == 0: do not reschedule, free(arg) */
if ((action_res > 0) && (t.period > 0)) {
/* Should schedule timer again */
timer_add(ctx,
t.time + t.period,
t.period,
0,
t.action,
t.arg,
t.cancel);
} else {
/* Allow user to free timer argument */
if (t.cancel != NULL) {
t.cancel(t.arg);
}
}
continue;
} else {
pthread_mutex_unlock(&ctx->timers->mutex);
}
/* TIMER_RESOLUTION = 10 ms seems reasonable.
* A faster loop (smaller sleep value) increases CPU load,
* a slower loop (higher sleep value) decreases timer accuracy.
*/
mg_sleep(TIMER_RESOLUTION);
d = timer_getcurrenttime(ctx);
}
/* Remove remaining timers */
for (u = 0; u < ctx->timers->timer_count; u++) {
t = ctx->timers->timers[u];
if (t.cancel != NULL) {
t.cancel(t.arg);
}
}
}
#if defined(_WIN32)
static unsigned __stdcall timer_thread(void *thread_func_param)
{
timer_thread_run(thread_func_param);
return 0;
}
#else
static void *
timer_thread(void *thread_func_param)
{
struct sigaction sa;
/* Ignore SIGPIPE */
memset(&sa, 0, sizeof(sa));
sa.sa_handler = SIG_IGN;
sigaction(SIGPIPE, &sa, NULL);
timer_thread_run(thread_func_param);
return NULL;
}
#endif /* _WIN32 */
TIMER_API int
timers_init(struct mg_context *ctx)
{
/* Initialize timers data structure */
ctx->timers =
(struct ttimers *)mg_calloc_ctx(sizeof(struct ttimers), 1, ctx);
if (!ctx->timers) {
return -1;
}
ctx->timers->timers = NULL;
/* Initialize mutex */
if (0 != pthread_mutex_init(&ctx->timers->mutex, NULL)) {
mg_free(ctx->timers);
ctx->timers = NULL;
return -1;
}
/* For some systems timer_getcurrenttime does some initialization
* during the first call. Call it once now, ignore the result. */
(void)timer_getcurrenttime(ctx);
/* Start timer thread */
if (mg_start_thread_with_id(timer_thread, ctx, &ctx->timers->threadid)
!= 0) {
(void)pthread_mutex_destroy(&ctx->timers->mutex);
mg_free(ctx->timers);
ctx->timers = NULL;
return -1;
}
return 0;
}
TIMER_API void
timers_exit(struct mg_context *ctx)
{
if (ctx->timers) {
mg_join_thread(ctx->timers->threadid);
(void)pthread_mutex_destroy(&ctx->timers->mutex);
mg_free(ctx->timers->timers);
mg_free(ctx->timers);
ctx->timers = NULL;
}
}
/* End of timer.inl */

77
vendor/CivetWeb/wolfssl_extras.inl vendored Normal file
View File

@ -0,0 +1,77 @@
/* Additional defines for WolfSSL, see
* https://github.com/civetweb/civetweb/issues/583 */
/* Required for WOLFSSL_X509 */
#include <openssl/../internal.h>
#define i2d_X509 cw_i2d_X509
#define EVP_Digest cw_EVP_Digest
/* i2d_X509 has no valid implementation in wolfssl
*
* The letters i and d in for example i2d_X509 stand for "internal" (that is an
*internal C structure)
* and " DER ". So that i2d_X509 converts from internal to DER.
*
* For OpenSSL 0.9.7 and later if *out is NULL memory will be allocated for a
*buffer and the encoded
* data written to it. In this case *out is not incremented and it points to the
*start of the data
* just written.
*/
int
cw_i2d_X509(struct WOLFSSL_X509 *x, unsigned char **out)
{
if (!x || !x->derCert) {
return -1;
}
const int ret = (int)x->derCert->length;
if (out && (ret > 0)) {
if (*out == NULL) {
*out = mg_malloc(ret);
}
if (*out != NULL) {
memcpy(*out, x->derCert->buffer, ret);
}
}
return ret;
}
/* EVP_Digest not in wolfssl */
int
cw_EVP_Digest(const void *data,
size_t count,
unsigned char *md,
unsigned int *size,
const EVP_MD *type,
ENGINE *impl)
{
EVP_MD_CTX *ctx = EVP_MD_CTX_new();
int ret;
if (ctx == NULL)
return 0;
/* EVP_MD_CTX_set_flags(ctx, EVP_MD_CTX_FLAG_ONESHOT); */
ret = EVP_DigestInit_ex(ctx, type, impl)
&& EVP_DigestUpdate(ctx, data, count)
&& EVP_DigestFinal_ex(ctx, md, size);
EVP_MD_CTX_free(ctx);
return ret;
}
/*
* the variable SSL_OP_NO_TLSv1_1 is not defined within the context of
* wolfssl but since the methods using the value are all stubs, we can
* define it arbitrarily and it will not have any consequences
*/
#define SSL_OP_NO_TLSv1_1 (0x10000000L)