Add unix socket support

This commit is contained in:
2025-05-27 10:51:21 -05:00
parent 9da9a5d8c0
commit 62111cd42e
8 changed files with 211 additions and 18 deletions

View File

@ -8,11 +8,20 @@ int main(int argc, char** argv)
if(argc < 3)
{
printf("USAGE: %s <url> <path>\n",argv[0]);
printf("USAGE: %s <unixSocket> <url> <path>\n",argv[0]);
return 1;
}
if(argc >= 4)
{
std::string unixSocket = argv[1];
std::string url = argv[2];
std::string path = argv[3];
Tesses::Framework::Http::DownloadUnixSocketToFileSimple(unixSocket,url,path);
}
else {
std::string path = argv[2];
Tesses::Framework::Http::DownloadToFileSimple(argv[1],path);
}
return 0;
}

View File

@ -45,10 +45,12 @@ namespace Tesses::Framework::Http
std::string method;
std::string url;
std::string unixSocket;
HttpDictionary requestHeaders;
HttpRequestBody* body;
static Tesses::Framework::Streams::Stream* EstablishConnection(Uri uri,bool ignoreSSLErrors,std::string trusted_root_cert_bundle);
static Tesses::Framework::Streams::Stream* EstablishUnixPathConnection(std::string unixPath, Uri uri, bool ignoreSSLErrors, std::string trusted_root_cert_bundle);
void SendRequest(Tesses::Framework::Streams::Stream* strm);
};
@ -77,8 +79,22 @@ namespace Tesses::Framework::Http
void DownloadToFileSimple(std::string url, Tesses::Framework::Filesystem::VFS& vfs, Tesses::Framework::Filesystem::VFSPath path);
void DownloadToFileSimple(std::string url, Tesses::Framework::Filesystem::VFSPath path);
std::string DownloadToStringSimple(std::string url);
bool WebSocketClientSuccessDefault(HttpDictionary& dict,bool v);
void WebSocketClient(std::string url, HttpDictionary& requestHeaders, WebSocketConnection& wsc, std::function<bool(HttpDictionary&,bool)> cb=WebSocketClientSuccessDefault);
void WebSocketClient(std::string url, HttpDictionary& requestHeaders, WebSocketConnection* wsc, std::function<bool(HttpDictionary&,bool)> cb=WebSocketClientSuccessDefault);
void DownloadUnixSocketToStreamSimple(std::string unixSocket,std::string url, Tesses::Framework::Streams::Stream* strm);
void DownloadUnixSocketToStreamSimple(std::string unixSocket,std::string url, Tesses::Framework::Streams::Stream& strm);
void DownloadUnixSocketToFileSimple(std::string unixSocket,std::string url, Tesses::Framework::Filesystem::VFS* vfs, Tesses::Framework::Filesystem::VFSPath path);
void DownloadUnixSocketToFileSimple(std::string unixSocket,std::string url, Tesses::Framework::Filesystem::VFS& vfs, Tesses::Framework::Filesystem::VFSPath path);
void DownloadUnixSocketToFileSimple(std::string unixSocket,std::string url, Tesses::Framework::Filesystem::VFSPath path);
std::string DownloadUnixSocketToStringSimple(std::string unixSocket,std::string url);
void WebSocketUnixSocketClient(std::string unixSocket,std::string url, HttpDictionary& requestHeaders, WebSocketConnection& wsc, std::function<bool(HttpDictionary&,bool)> cb=WebSocketClientSuccessDefault);
void WebSocketUnixSocketClient(std::string unixSocket,std::string url,HttpDictionary& requestHeaders, WebSocketConnection* wsc, std::function<bool(HttpDictionary&,bool)> cb=WebSocketClientSuccessDefault);
}

View File

@ -88,6 +88,7 @@ namespace Tesses::Framework::Http
bool ownsTCP;
bool ownsHttp;
bool showIPs;
bool showARTL;
public:
HttpServer(Tesses::Framework::Streams::TcpServer& tcpServer, IHttpServer& http, bool showIPs=true);
@ -96,6 +97,8 @@ namespace Tesses::Framework::Http
HttpServer(Tesses::Framework::Streams::TcpServer* tcpServer, bool ownsTCP, IHttpServer* http, bool ownsHttpServer, bool showIPs=true);
HttpServer(uint16_t port, IHttpServer& http, bool showIPs=true);
HttpServer(uint16_t port, IHttpServer* http, bool owns, bool showIPs=true);
HttpServer(std::string unixPath, IHttpServer& http);
HttpServer(std::string unixPath, IHttpServer* http, bool owns);
uint16_t GetPort();
void StartAccepting();
static void Process(Tesses::Framework::Streams::Stream& strm, IHttpServer& server, std::string ip, uint16_t port, bool encrypted);

View File

@ -14,6 +14,7 @@ namespace Tesses::Framework::Streams
TcpServer(int32_t sock,bool owns);
TcpServer(uint16_t port, int32_t backlog);
TcpServer(std::string ip, uint16_t port, int32_t backlog);
TcpServer(std::string unixPath,int32_t backlog);
NetworkStream* GetStream(std::string& ip, uint16_t& port);
uint16_t GetPort();
~TcpServer();
@ -30,6 +31,7 @@ namespace Tesses::Framework::Streams
bool CanRead();
bool CanWrite();
NetworkStream(bool ipV6,bool datagram);
NetworkStream(std::string unixPath,bool isServer);
NetworkStream(std::string ipOrFqdn, uint16_t port, bool datagram,bool broadcast,bool supportIPv6);
NetworkStream(int32_t sock, bool owns);
uint16_t GetPort();

View File

@ -117,7 +117,6 @@ namespace Tesses::Framework::Http
body->Write(strm);
}
}
Stream* HttpRequest::EstablishConnection(Uri uri, bool ignoreSSLErrors, std::string trusted_root_cert_bundle)
{
if(uri.scheme == "http:" || uri.scheme == "ws:")
@ -127,7 +126,22 @@ namespace Tesses::Framework::Http
else if(uri.scheme == "https:" || uri.scheme == "wss:")
{
auto netStrm = new NetworkStream(uri.host,uri.GetPort(),false,false,false);
if(netStrm == nullptr) return netStrm;
if(netStrm == nullptr) return nullptr;
return new ClientTLSStream(netStrm, true, ignoreSSLErrors,uri.host, trusted_root_cert_bundle);
}
return nullptr;
}
Stream* HttpRequest::EstablishUnixPathConnection(std::string unixPath,Uri uri, bool ignoreSSLErrors, std::string trusted_root_cert_bundle)
{
if(uri.scheme == "http:" || uri.scheme == "ws:")
{
return new NetworkStream(unixPath,false);
}
else if(uri.scheme == "https:" || uri.scheme == "wss:")
{
auto netStrm = new NetworkStream(unixPath,false);
if(netStrm == nullptr) return nullptr;
return new ClientTLSStream(netStrm, true, ignoreSSLErrors,uri.host, trusted_root_cert_bundle);
}
@ -182,7 +196,7 @@ namespace Tesses::Framework::Http
Uri uri;
while(Uri::TryParse(url, uri))
{
auto strm = HttpRequest::EstablishConnection(uri, req.ignoreSSLErrors,req.trusted_root_cert_bundle);
auto strm = req.unixSocket.empty() ? HttpRequest::EstablishConnection(uri, req.ignoreSSLErrors,req.trusted_root_cert_bundle) : HttpRequest::EstablishUnixPathConnection(req.unixSocket,uri, req.ignoreSSLErrors,req.trusted_root_cert_bundle);
if(strm == nullptr) return;
auto reqHeaders = req.requestHeaders;
@ -284,40 +298,73 @@ namespace Tesses::Framework::Http
return new HttpStream(this->handleStrm,false,length,true,version=="HTTP/1.1");
}
void DownloadToStreamSimple(std::string url, Tesses::Framework::Streams::Stream* strm)
void DownloadUnixSocketToStreamSimple(std::string unixSocket,std::string url, Tesses::Framework::Streams::Stream* strm)
{
if(strm == nullptr) throw TextException("strm is null");
HttpRequest request;
request.url = url;
request.unixSocket = unixSocket;
request.followRedirects=true;
request.method = "GET";
HttpResponse response(request);
if(response.statusCode < 200 || response.statusCode > 299) throw TextException("Status code does not indicate success: " + std::to_string(response.statusCode) + " " + HttpUtils::StatusCodeString(response.statusCode));
response.CopyToStream(strm);
}
void DownloadToStreamSimple(std::string url, Tesses::Framework::Streams::Stream& strm)
void DownloadUnixSocketToStreamSimple(std::string unixSocket,std::string url, Tesses::Framework::Streams::Stream& strm)
{
DownloadToStreamSimple(url,&strm);
DownloadUnixSocketToStreamSimple(unixSocket,url,&strm);
}
void DownloadToFileSimple(std::string url, Tesses::Framework::Filesystem::VFS* vfs, Tesses::Framework::Filesystem::VFSPath path)
void DownloadUnixSocketToFileSimple(std::string unixSocket,std::string url, Tesses::Framework::Filesystem::VFS* vfs, Tesses::Framework::Filesystem::VFSPath path)
{
if(vfs == nullptr) throw TextException("vfs is null");
auto strm = vfs->OpenFile(path,"wb");
if(strm == nullptr) throw TextException("strm is null");
DownloadToStreamSimple(url,strm);
DownloadUnixSocketToStreamSimple(unixSocket,url,strm);
delete strm;
}
void DownloadToFileSimple(std::string url, Tesses::Framework::Filesystem::VFS& vfs, Tesses::Framework::Filesystem::VFSPath path)
void DownloadUnixSocketToFileSimple(std::string unixSocket,std::string url, Tesses::Framework::Filesystem::VFS& vfs, Tesses::Framework::Filesystem::VFSPath path)
{
auto strm = vfs.OpenFile(path,"wb");
if(strm == nullptr) throw TextException("strm is null");
DownloadToStreamSimple(url,strm);
DownloadUnixSocketToStreamSimple(unixSocket,url,strm);
delete strm;
}
void DownloadUnixSocketToFileSimple(std::string unixSocket,std::string url, Tesses::Framework::Filesystem::VFSPath path)
{
DownloadUnixSocketToFileSimple(unixSocket,url,Tesses::Framework::Filesystem::LocalFS,path);
}
std::string DownloadUnixSocketToStringSimple(std::string unixSocket,std::string url)
{
HttpRequest request;
request.url = url;
request.unixSocket = unixSocket;
request.followRedirects=true;
request.method = "GET";
HttpResponse response(request);
if(response.statusCode < 200 || response.statusCode > 299) throw TextException("Status code does not indicate success: " + std::to_string(response.statusCode) + " " + HttpUtils::StatusCodeString(response.statusCode));
return response.ReadAsString();
}
void DownloadToStreamSimple(std::string url, Tesses::Framework::Streams::Stream* strm)
{
DownloadUnixSocketToStreamSimple("",url,strm);
}
void DownloadToStreamSimple(std::string url, Tesses::Framework::Streams::Stream& strm)
{
DownloadUnixSocketToStreamSimple("",url,strm);
}
void DownloadToFileSimple(std::string url, Tesses::Framework::Filesystem::VFS* vfs, Tesses::Framework::Filesystem::VFSPath path)
{
DownloadUnixSocketToFileSimple("",url,vfs,path);
}
void DownloadToFileSimple(std::string url, Tesses::Framework::Filesystem::VFS& vfs, Tesses::Framework::Filesystem::VFSPath path)
{
DownloadUnixSocketToFileSimple("",url,vfs,path);
}
void DownloadToFileSimple(std::string url, Tesses::Framework::Filesystem::VFSPath path)
{
DownloadToFileSimple(url,Tesses::Framework::Filesystem::LocalFS,path);
DownloadUnixSocketToFileSimple("",url,path);
}
std::string DownloadToStringSimple(std::string url)
{
@ -328,6 +375,7 @@ namespace Tesses::Framework::Http
HttpResponse response(request);
if(response.statusCode < 200 || response.statusCode > 299) throw TextException("Status code does not indicate success: " + std::to_string(response.statusCode) + " " + HttpUtils::StatusCodeString(response.statusCode));
return response.ReadAsString();
}
bool WebSocketClientSuccessDefault(HttpDictionary& dict,bool v)
{
@ -335,7 +383,11 @@ namespace Tesses::Framework::Http
}
void WebSocketClient(std::string url, HttpDictionary& requestHeaders, WebSocketConnection& wsc, std::function<bool(HttpDictionary&,bool)> cb)
{
WebSocketClient(url,requestHeaders, &wsc,cb);
WebSocketUnixSocketClient("",url,requestHeaders,wsc,cb);
}
void WebSocketUnixSocketClient(std::string unixSocket,std::string url, HttpDictionary& requestHeaders, WebSocketConnection& wsc, std::function<bool(HttpDictionary&,bool)> cb)
{
WebSocketUnixSocketClient(unixSocket,url,requestHeaders, &wsc,cb);
}
class WSClient {
@ -574,13 +626,18 @@ namespace Tesses::Framework::Http
};
void WebSocketClient(std::string url, HttpDictionary& requestHeaders, WebSocketConnection* wsc, std::function<bool(HttpDictionary&,bool)> cb)
{
WebSocketUnixSocketClient("",url,requestHeaders,wsc,cb);
}
void WebSocketUnixSocketClient(std::string unixSocket,std::string url, HttpDictionary& requestHeaders, WebSocketConnection* wsc, std::function<bool(HttpDictionary&,bool)> cb)
{
HttpRequest req;
req.url = url;
req.requestHeaders = requestHeaders;
req.followRedirects=true;
req.unixSocket = unixSocket;
std::string hash = "";

View File

@ -550,6 +550,7 @@ namespace Tesses::Framework::Http
this->ownsHttp = ownsHttpServer;
this->showIPs = showIPs;
this->thrd=nullptr;
this->showARTL = showIPs;
}
@ -561,6 +562,15 @@ namespace Tesses::Framework::Http
{
}
HttpServer::HttpServer(std::string unixPath, IHttpServer* http, bool owns) : HttpServer(new TcpServer(unixPath,10),true,http,owns,false)
{
this->showARTL=true;
}
HttpServer::HttpServer(std::string unixPath, IHttpServer& http) : HttpServer(unixPath,&http,false)
{
}
uint16_t HttpServer::GetPort()
{
if(server != nullptr)
@ -633,6 +643,11 @@ namespace Tesses::Framework::Http
std::cout << "\x1B[35mhttp://";
std::cout << _ip.second << ":" << std::to_string(this->GetPort()) << "/\n";
}
}
if(this->showARTL)
{
if(!svr->IsValid()) std::cout << "\x1B[31mError, we failed to bind or something\x1B[39m\n" << std::endl;
std::cout << "\x1B[31mAlmost Ready to Listen\x1B[39m\n";
}

View File

@ -93,6 +93,7 @@ namespace Tesses::Framework::Http {
uri.port=0;
auto firstPart = HttpUtils::SplitString(url,"//",2);
if(firstPart.size() == 2)
uri.scheme=firstPart[0];
else if(firstPart.empty())
return false;

View File

@ -34,6 +34,9 @@ extern "C" {
#include <netdb.h>
#include <fcntl.h>
#include <unistd.h>
#if defined(AF_UNIX)
#include <sys/un.h>
#endif
}
#endif
#if defined(GEKKO)
@ -264,6 +267,81 @@ namespace Tesses::Framework::Streams {
uint32_t addr;
uint8_t addr_parts[4];
} my_addr_t;
NetworkStream::NetworkStream(std::string unixPath,bool isServer)
{
this->endOfStream=false;
this->owns = true;
this->success=false;
#if defined(AF_UNIX)
this->sock = NETWORK_SOCKET(AF_UNIX,SOCK_STREAM,0);
if(this->sock < 0)
{
this->success=false;
return;
}
struct sockaddr_un unx;
memset(&unx, 0, sizeof(unx));
unx.sun_family = AF_UNIX;
strncpy(unx.sun_path, unixPath.c_str(),sizeof(unx.sun_path)-1);
if(isServer)
{
unlink(unixPath.c_str());
if(NETWORK_BIND(this->sock, (const sockaddr*)&unx, (socklen_t)sizeof(unx)) != 0)
{
std::cout << "FAILED TO BIND: " << strerror(errno) << std::endl;
this->success = false;
return;
}
}
else
{
if(NETWORK_CONNECT(this->sock,(const sockaddr*)&unx, (socklen_t)sizeof(unx)) != 0)
{
this->success=false;
return;
}
}
#endif
}
TcpServer::TcpServer(std::string unixPath,int32_t backlog)
{
this->owns=true;
this->valid=false;
#if defined(AF_UNIX)
this->sock = NETWORK_SOCKET(AF_UNIX,SOCK_STREAM,0);
if(this->sock < 0)
{
this->valid=false;
return;
}
struct sockaddr_un unx;
memset(&unx, 0, sizeof(unx));
unx.sun_family = AF_UNIX;
unlink(unixPath.c_str());
strncpy(unx.sun_path, unixPath.c_str(),sizeof(unx.sun_path)-1);
if(NETWORK_BIND(this->sock, (const sockaddr*)&unx, (socklen_t)sizeof(unx)) != 0)
{
std::cout << "FAILED TO BIND: " << strerror(errno) << std::endl;
this->valid = false;
return;
}
if(NETWORK_LISTEN(this->sock, backlog) != 0)
{
std::cout << "FAILED TO LISTEN FOR SOME REASON" << std::endl;
this->valid = false;
return;
}
this->valid = true;
#endif
}
TcpServer::TcpServer(uint16_t port, int32_t backlog)
{
@ -302,7 +380,7 @@ namespace Tesses::Framework::Streams {
}
if(NETWORK_BIND(this->sock, (const sockaddr*)&addr, (socklen_t)sizeof(addr)) != 0)
{
std::cout << "FAILED TO BIND FOR SOME REASON" << std::endl;
std::cout << "FAILED TO BIND: " << strerror(errno) << std::endl;
this->valid = false;
return;
}
@ -387,6 +465,8 @@ namespace Tesses::Framework::Streams {
if(NETWORK_BIND(this->sock, (const sockaddr*)&addr, (socklen_t)sizeof(addr)) != 0)
{
std::cout << "FAILED TO BIND: " << strerror(errno) << std::endl;
this->valid = false;
return;
}
@ -557,6 +637,8 @@ namespace Tesses::Framework::Streams {
int r = NETWORK_BIND(this->sock, (struct sockaddr*)&addr, sizeof(addr));
if(r != 0)
{
std::cout << "FAILED TO BIND: " << strerror(errno) << std::endl;
this->success=false;
if(this->owns)
NETWORK_CLOSE(this->sock);
@ -683,6 +765,10 @@ TcpServer::TcpServer(uint16_t port, int32_t backlog)
TcpServer::TcpServer(std::string ip, uint16_t port, int32_t backlog)
{
}
TcpServer::TcpServer(std::string unixPath,int32_t backlog)
{
}
NetworkStream* TcpServer::GetStream(std::string& ip, uint16_t& port)
{
@ -717,6 +803,10 @@ NetworkStream::NetworkStream(bool ipV6,bool datagram)
NetworkStream::NetworkStream(std::string ipOrFqdn, uint16_t port, bool datagram,bool broadcast,bool supportIPv6)
{
}
NetworkStream::NetworkStream(std::string unixPath, bool isServer)
{
}
NetworkStream::NetworkStream(int32_t sock, bool owns)
{