Implement connection establishment via web sockets

This commit is contained in:
Martin 2020-07-05 21:18:34 +02:00
parent bde001411b
commit 4fb806e7b0
28 changed files with 1173 additions and 17 deletions

View File

@ -299,6 +299,11 @@ bool CAcceptThread::init_socket_v4(unsigned short port)
addr.sin_port = htons(port);
addr.sin_addr.s_addr = htonl(INADDR_ANY);
if (Server->getServerParameter("fastcgi_localhost_only") == "1")
{
addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
}
int rc = bind(s, (sockaddr*)&addr, sizeof(addr));
if (rc == SOCKET_ERROR)
{
@ -341,6 +346,11 @@ bool CAcceptThread::init_socket_v6(unsigned short port)
addr.sin6_port = htons(port);
addr.sin6_addr = in6addr_any;
if (Server->getServerParameter("fastcgi_localhost_only") == "1")
{
addr.sin6_addr = in6addr_loopback;
}
int rc = bind(s_v6, (sockaddr*)&addr, sizeof(addr));
if (rc == SOCKET_ERROR)
{

View File

@ -343,6 +343,7 @@
<ClInclude Include="Interface\DatabaseInt.h" />
<ClInclude Include="Interface\PipeThrottler.h" />
<ClInclude Include="Interface\SharedMutex.h" />
<ClInclude Include="Interface\WebSocket.h" />
<ClInclude Include="libs.h" />
<ClInclude Include="LoadbalancerClient.h" />
<ClInclude Include="LookupService.h" />

View File

@ -380,5 +380,8 @@
<ClInclude Include="SChannelPipe.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Interface\WebSocket.h">
<Filter>Interface</Filter>
</ClInclude>
</ItemGroup>
</Project>

View File

@ -31,6 +31,7 @@ class IScopedLock;
class IDatabaseFactory;
class IPipeThrottler;
class IPipeThrottlerUpdater;
class IWebSocket;
struct SPostfile
{
@ -80,6 +81,9 @@ public:
virtual void setActionContext(std::string context)=0;
virtual void resetActionContext(void)=0;
virtual void addWebSocket(IWebSocket* websocket) = 0;
virtual THREAD_ID ExecuteWebSocket(const std::string& name, str_map& GET, str_map& PARAMS, IPipe* pipe, const std::string& endpoint_name) = 0;
virtual int64 getTimeSeconds(void)=0;
virtual int64 getTimeMS(void)=0;

12
Interface/WebSocket.h Normal file
View File

@ -0,0 +1,12 @@
#pragma once
#include "Types.h"
#include "Object.h"
#include "Pipe.h"
class IWebSocket : public IObject
{
public:
virtual void Execute(str_map& GET, THREAD_ID tid, str_map& PARAMS, IPipe* pipe, const std::string& endpoint_name) = 0;
virtual std::string getName() = 0;
};

View File

@ -11,7 +11,7 @@ if WITH_EMBEDDED_SQLITE3
urbackupclientbackend_SOURCES += sqlite/sqlite3.c
endif
urbackupclientbackend_SOURCES += urbackupcommon/os_functions_lin.cpp urbackupcommon/sha2/sha2.cpp urbackupcommon/fileclient/FileClient.cpp urbackupcommon/fileclient/tcpstack.cpp urbackupcommon/escape.cpp urbackupcommon/bufmgr.cpp urbackupcommon/json.cpp urbackupcommon/CompressedPipe.cpp urbackupcommon/InternetServicePipe2.cpp urbackupcommon/settingslist.cpp urbackupcommon/fileclient/FileClientChunked.cpp urbackupcommon/InternetServicePipe.cpp urbackupcommon/filelist_utils.cpp urbackupcommon/file_metadata.cpp urbackupcommon/glob.cpp urbackupcommon/chunk_hasher.cpp urbackupcommon/CompressedPipe2.cpp urbackupcommon/SparseFile.cpp urbackupcommon/ExtentIterator.cpp urbackupcommon/TreeHash.cpp urbackupcommon/WalCheckpointThread.cpp
urbackupclientbackend_SOURCES += urbackupcommon/os_functions_lin.cpp urbackupcommon/sha2/sha2.cpp urbackupcommon/fileclient/FileClient.cpp urbackupcommon/fileclient/tcpstack.cpp urbackupcommon/escape.cpp urbackupcommon/bufmgr.cpp urbackupcommon/json.cpp urbackupcommon/CompressedPipe.cpp urbackupcommon/InternetServicePipe2.cpp urbackupcommon/settingslist.cpp urbackupcommon/fileclient/FileClientChunked.cpp urbackupcommon/InternetServicePipe.cpp urbackupcommon/filelist_utils.cpp urbackupcommon/file_metadata.cpp urbackupcommon/glob.cpp urbackupcommon/chunk_hasher.cpp urbackupcommon/CompressedPipe2.cpp urbackupcommon/SparseFile.cpp urbackupcommon/ExtentIterator.cpp urbackupcommon/TreeHash.cpp urbackupcommon/WalCheckpointThread.cpp urbackupcommon/WebSocketPipe.cpp
if WITH_ZSTD
urbackupclientbackend_SOURCES += urbackupcommon/CompressedPipeZstd.cpp
@ -277,7 +277,7 @@ else
client_headers =
endif
urbackupclient_headers = urbackupclient/DirectoryWatcherThread.h urbackupcommon/os_functions.h urbackupclient/ChangeJournalWatcher.h urbackupcommon/sha2/sha2.h urbackupclient/database.h urbackupcommon/escape.h urbackupclient/ClientSend.h urbackupclient/clientdao.h urbackupclient/client.h urbackupclient/ClientService.h fileservplugin/IFileServFactory.h fileservplugin/IFileServ.h common/data.h urbackupcommon/fileclient/tcpstack.h urbackupcommon/capa_bits.h urbackupclient/ServerIdentityMgr.h urbackupcommon/bufmgr.h urbackupcommon/CompressedPipe.h urbackupclient/ImageThread.h urbackupclient/InternetClient.h urbackupcommon/InternetServicePipe2.h urbackupcommon/settingslist.h cryptoplugin/IZlibCompression.h cryptoplugin/IZlibDecompression.h cryptoplugin/ICryptoFactory.h cryptoplugin/IAESDecryption.h cryptoplugin/IAESEncryption.h urbackupcommon/internet_pipe_capabilities.h urbackupcommon/settings.h urbackupcommon/fileclient/socket_header.h urbackupcommon/mbrdata.h urbackupcommon/InternetServiceIDs.h urbackupcommon/json.h urbackupclient/file_permissions.h urbackupclient/lin_ver.h urbackupcommon/glob.h urbackupclient/tokens.h urbackupclient/FileMetadataDownloadThread.h urbackupclient/RestoreFiles.h urbackupcommon/chunk_hasher.h common/adler32.h urbackupcommon/fileclient/FileClient.h urbackupcommon/fileclient/FileClientChunked.h urbackupcommon/file_metadata.h urbackupcommon/filelist_utils.h urbackupclient/RestoreDownloadThread.h urbackupclient/TokenCallback.h urbackupcommon/CompressedPipe2.h urbackupcommon/server_compat.h urbackupcommon/fileclient/packet_ids.h urbackupcommon/InternetServicePipe.h urbackupclient/backup_client_db.h urbackupcommon/SparseFile.h urbackupcommon/ExtentIterator.h urbackupcommon/TreeHash.h urbackupcommon/WalCheckpointThread.h common/miniz.h urbackupclient/ParallelHash.h urbackupclient/ClientHash.h urbackupcommon/CompressedPipeZstd.h urbackupclient/lin_sysvol.h
urbackupclient_headers = urbackupclient/DirectoryWatcherThread.h urbackupcommon/os_functions.h urbackupclient/ChangeJournalWatcher.h urbackupcommon/sha2/sha2.h urbackupclient/database.h urbackupcommon/escape.h urbackupclient/ClientSend.h urbackupclient/clientdao.h urbackupclient/client.h urbackupclient/ClientService.h fileservplugin/IFileServFactory.h fileservplugin/IFileServ.h common/data.h urbackupcommon/fileclient/tcpstack.h urbackupcommon/capa_bits.h urbackupclient/ServerIdentityMgr.h urbackupcommon/bufmgr.h urbackupcommon/CompressedPipe.h urbackupclient/ImageThread.h urbackupclient/InternetClient.h urbackupcommon/InternetServicePipe2.h urbackupcommon/settingslist.h cryptoplugin/IZlibCompression.h cryptoplugin/IZlibDecompression.h cryptoplugin/ICryptoFactory.h cryptoplugin/IAESDecryption.h cryptoplugin/IAESEncryption.h urbackupcommon/internet_pipe_capabilities.h urbackupcommon/settings.h urbackupcommon/fileclient/socket_header.h urbackupcommon/mbrdata.h urbackupcommon/InternetServiceIDs.h urbackupcommon/json.h urbackupclient/file_permissions.h urbackupclient/lin_ver.h urbackupcommon/glob.h urbackupclient/tokens.h urbackupclient/FileMetadataDownloadThread.h urbackupclient/RestoreFiles.h urbackupcommon/chunk_hasher.h common/adler32.h urbackupcommon/fileclient/FileClient.h urbackupcommon/fileclient/FileClientChunked.h urbackupcommon/file_metadata.h urbackupcommon/filelist_utils.h urbackupclient/RestoreDownloadThread.h urbackupclient/TokenCallback.h urbackupcommon/CompressedPipe2.h urbackupcommon/server_compat.h urbackupcommon/fileclient/packet_ids.h urbackupcommon/InternetServicePipe.h urbackupclient/backup_client_db.h urbackupcommon/SparseFile.h urbackupcommon/ExtentIterator.h urbackupcommon/TreeHash.h urbackupcommon/WalCheckpointThread.h common/miniz.h urbackupclient/ParallelHash.h urbackupclient/ClientHash.h urbackupcommon/CompressedPipeZstd.h urbackupclient/lin_sysvol.h urbackupcommon/WebSocketPipe.h
tclap_headers = \
@ -340,7 +340,7 @@ zstd_headers = \
external/zstd/dictBuilder/zdict.h \
external/zstd/zstd.h
noinst_HEADERS=SessionMgr.h WorkerThread.h Helper_win32.h Database.h defaults.h ServiceAcceptor.h Query.h SettingsReader.h file.h file_memory.h MemorySettingsReader.h Condition_lin.h LookupService.h Template.h types.h DBSettingsReader.h stringtools.h ThreadPool.h libs.h vld_.h ServiceWorker.h StreamPipe.h LoadbalancerClient.h socket_header.h FileSettingsReader.h SelectThread.h md5.h vld.h Table.h Client.h MemoryPipe.h Mutex_lin.h AcceptThread.h OutputStream.h Server.h Interface/SessionMgr.h Interface/Service.h Interface/PluginMgr.h Interface/Database.h Interface/Pipe.h Interface/CustomClient.h Interface/User.h Interface/Query.h Interface/SettingsReader.h Interface/Types.h Interface/Template.h Interface/ThreadPool.h Interface/Mutex.h Interface/File.h Interface/Condition.h Interface/Table.h Interface/Plugin.h Interface/Thread.h Interface/Action.h Interface/Object.h Interface/OutputStream.h Interface/Server.h libfastcgi/fastcgi.hpp sqlite/sqlite3.h sqlite/sqlite3ext.h utf8/utf8.h utf8/utf8/checked.h utf8/utf8/core.h utf8/utf8/unchecked.h cryptoplugin/ICryptoFactory.h cryptoplugin/IAESEncryption.h cryptoplugin/IAESDecryption.h Interface/DatabaseFactory.h Interface/DatabaseInt.h sqlite/shell.h SQLiteFactory.h PipeThrottler.h Interface/PipeThrottler.h mt19937ar.h DatabaseCursor.h Interface/DatabaseCursor.h client_version.h Interface/SharedMutex.h SharedMutex_lin.h StaticPluginRegistration.h common/bitmap.h OpenSSLPipe.h $(cryptoplugin_headers) $(fileservplugin_headers) $(fsimageplugin_headers) $(urbackupclientctl_headers) $(client_headers) $(tclap_headers) $(urbackupclient_headers) $(cryptopp_headers) $(blockalign_headers) $(zstd_headers)
noinst_HEADERS=SessionMgr.h WorkerThread.h Helper_win32.h Database.h defaults.h ServiceAcceptor.h Query.h SettingsReader.h file.h file_memory.h MemorySettingsReader.h Condition_lin.h LookupService.h Template.h types.h DBSettingsReader.h stringtools.h ThreadPool.h libs.h vld_.h ServiceWorker.h StreamPipe.h LoadbalancerClient.h socket_header.h FileSettingsReader.h SelectThread.h md5.h vld.h Table.h Client.h MemoryPipe.h Mutex_lin.h AcceptThread.h OutputStream.h Server.h Interface/SessionMgr.h Interface/Service.h Interface/PluginMgr.h Interface/Database.h Interface/Pipe.h Interface/CustomClient.h Interface/User.h Interface/Query.h Interface/SettingsReader.h Interface/Types.h Interface/Template.h Interface/ThreadPool.h Interface/Mutex.h Interface/File.h Interface/Condition.h Interface/Table.h Interface/Plugin.h Interface/Thread.h Interface/Action.h Interface/Object.h Interface/OutputStream.h Interface/Server.h libfastcgi/fastcgi.hpp sqlite/sqlite3.h sqlite/sqlite3ext.h utf8/utf8.h utf8/utf8/checked.h utf8/utf8/core.h utf8/utf8/unchecked.h cryptoplugin/ICryptoFactory.h cryptoplugin/IAESEncryption.h cryptoplugin/IAESDecryption.h Interface/DatabaseFactory.h Interface/DatabaseInt.h sqlite/shell.h SQLiteFactory.h PipeThrottler.h Interface/PipeThrottler.h mt19937ar.h DatabaseCursor.h Interface/DatabaseCursor.h Interface/WebSocket.h client_version.h Interface/SharedMutex.h SharedMutex_lin.h StaticPluginRegistration.h common/bitmap.h OpenSSLPipe.h $(cryptoplugin_headers) $(fileservplugin_headers) $(fsimageplugin_headers) $(urbackupclientctl_headers) $(client_headers) $(tclap_headers) $(urbackupclient_headers) $(cryptopp_headers) $(blockalign_headers) $(zstd_headers)
EXTRA_DIST_GUI = client/info.txt client/data/backup-bad.xpm client/data/backup-ok.xpm client/data/backup-progress.xpm client/data/backup-progress-pause.xpm client/data/backup-no-server.xpm client/data/backup-no-recent.xpm client/data/backup-indexing.xpm client/data/logo1.png client/data/lang/it/urbackup.mo client/data/lang/pl/urbackup.mo client/data/lang/pt_BR/urbackup.mo client/data/lang/sk/urbackup.mo client/data/lang/zh_TW/urbackup.mo client/data/lang/zh_CN/urbackup.mo client/data/lang/de/urbackup.mo client/data/lang/es/urbackup.mo client/data/lang/fr/urbackup.mo client/data/lang/ru/urbackup.mo client/data/lang/uk/urbackup.mo client/data/lang/da/urbackup.mo client/data/lang/nl/urbackup.mo client/data/lang/fa/urbackup.mo client/data/lang/cs/urbackup.mo client/gui/GUISetupWizard.h client/SetupWizard.h

File diff suppressed because one or more lines are too long

View File

@ -35,6 +35,7 @@
#include "Interface/PluginMgr.h"
#include "Interface/Thread.h"
#include "Interface/DatabaseFactory.h"
#include "Interface/WebSocket.h"
#include "Server.h"
#include "Template.h"
@ -175,6 +176,7 @@ CServer::CServer()
log_mutex=createMutex();
action_mutex=createMutex();
web_socket_mutex = createMutex();
requests_mutex=createMutex();
outputs_mutex=createMutex();
db_mutex=createMutex();
@ -353,6 +355,7 @@ CServer::~CServer()
destroy(log_mutex);
destroy(action_mutex);
destroy(web_socket_mutex);
destroy(requests_mutex);
destroy(outputs_mutex);
destroy(db_mutex);
@ -2267,3 +2270,29 @@ int CServer::getRecvWindowSize()
return recv_window_size;
}
#endif
void CServer::addWebSocket(IWebSocket* websocket)
{
IScopedLock lock(web_socket_mutex);
web_sockets[websocket->getName()] = websocket;
}
THREAD_ID CServer::ExecuteWebSocket(const std::string& name, str_map& GET, str_map& PARAMS, IPipe* pipe, const std::string& endpoint_name)
{
IWebSocket* ws;
{
IScopedLock lock(web_socket_mutex);
std::map<std::string, IWebSocket*>::iterator it = web_sockets.find(name);
if (it == web_sockets.end())
return ILLEGAL_THREAD_ID;
ws = it->second;
}
THREAD_ID tid = getThreadID();
ws->Execute(GET, tid, PARAMS, pipe, endpoint_name);
return tid;
}

View File

@ -87,6 +87,9 @@ public:
virtual void setActionContext(std::string context);
virtual void resetActionContext(void);
virtual void addWebSocket(IWebSocket* websocket);
virtual THREAD_ID ExecuteWebSocket(const std::string& name, str_map& GET, str_map& PARAMS, IPipe* pipe, const std::string& endpoint_name);
virtual int64 getTimeSeconds(void);
virtual int64 getTimeMS(void);
@ -233,6 +236,7 @@ private:
IMutex* log_mutex;
IMutex* action_mutex;
IMutex* web_socket_mutex;
IMutex* requests_mutex;
IMutex* outputs_mutex;
IMutex* db_mutex;
@ -249,6 +253,8 @@ private:
std::map< std::string, std::map<std::string, IAction*> > actions;
std::map<std::string, IWebSocket*> web_sockets;
std::map<std::string, UNLOADACTIONS> unload_functs;
std::vector<HMODULE> unload_handles;

View File

@ -1,7 +1,7 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.25420.1
# Visual Studio Version 16
VisualStudioVersion = 16.0.30114.105
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fileservplugin", "fileservplugin\fileservplugin.vcxproj", "{B1F1AF2E-E544-45F7-864A-883461A4B574}"
EndProject
@ -177,4 +177,7 @@ Global
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {790C4817-D528-41A0-94B8-198C09841390}
EndGlobalSection
EndGlobal

View File

@ -397,3 +397,10 @@ IECDHKeyExchange* CryptoFactory::createECDHKeyExchange()
{
return new ECDHKeyExchange();
}
std::string CryptoFactory::sha1Binary(const std::string& data)
{
byte sha1_digest[CryptoPP::SHA1::DIGESTSIZE];
CryptoPP::SHA1().CalculateDigest(sha1_digest, reinterpret_cast<const byte*>(data.data()), data.size());
return std::string(reinterpret_cast<char*>(sha1_digest), sizeof(sha1_digest));
}

View File

@ -27,5 +27,6 @@ public:
virtual std::string encryptAuthenticatedAES(const std::string& data, const std::string &password, size_t iterations=20000);
virtual std::string decryptAuthenticatedAES(const std::string& data, const std::string &password, size_t iterations=20000);
virtual IECDHKeyExchange* createECDHKeyExchange();
virtual std::string sha1Binary(const std::string& data);
};

View File

@ -39,4 +39,6 @@ public:
virtual std::string encryptAuthenticatedAES(const std::string& data, const std::string &password, size_t iterations=20000)=0;
virtual std::string decryptAuthenticatedAES(const std::string& data, const std::string &password, size_t iterations=20000)=0;
virtual IECDHKeyExchange* createECDHKeyExchange()=0;
virtual std::string sha1Binary(const std::string& data) = 0;
};

View File

@ -29,6 +29,7 @@
#include "HTTPFile.h"
#include "HTTPAction.h"
#include "HTTPProxy.h"
#include "HTTPSocket.h"
extern CHTTPService* http_service;
@ -118,7 +119,7 @@ bool CHTTPClient::Run(IRunOtherCallback* run_other)
{
if( http_g_state==HTTP_STATE_WAIT_FOR_THREAD )
{
if( Server->getThreadPool()->isRunning(request_ticket)==false )
if( !Server->getThreadPool()->isRunning(request_ticket) )
{
//Server->Log("Connection: "+http_params["CONNECTION"], LL_DEBUG);
/*if( strlower(http_params["CONNECTION"])=="close" )
@ -507,7 +508,18 @@ bool CHTTPClient::processRequest(void)
std::string name;
std::string context;
size_t pstart;
if( pl->size()>1 && (*pl)[0]=='x' && (*pl)[1]=='?' )
str_map::iterator upgrade_param = http_params.find("UPGRADE");
if (upgrade_param != http_params.end()
&& upgrade_param->second == "websocket")
{
std::string name = getuntil("?", *pl);
std::string gparams = getafter("?", *pl);
CHTTPSocket* socket_handler = new CHTTPSocket(name, gparams, http_params, pipe, endpoint);
request_ticket = Server->getThreadPool()->execute(socket_handler, "http websocket");
request_handler = socket_handler;
return true;
}
else if( pl->size()>1 && (*pl)[0]=='x' && (*pl)[1]=='?' )
{
parseAction(*pl, name, context);
}
@ -538,7 +550,7 @@ bool CHTTPClient::processRequest(void)
rp = greplace("\\", "_", rp);
#endif
CHTTPFile *file_handler=new CHTTPFile(http_service->getRoot()+rp, pipe);
request_ticket=Server->getThreadPool()->execute(file_handler);
request_ticket=Server->getThreadPool()->execute(file_handler, "http file request");
request_handler=file_handler;
return true;
}
@ -573,9 +585,7 @@ void CHTTPClient::WaitForRemove(void)
{
if(request_ticket!=ILLEGAL_THREADPOOL_TICKET)
{
std::vector<THREADPOOL_TICKET> tmp;
tmp.push_back(request_ticket);
Server->getThreadPool()->waitFor(tmp);
Server->getThreadPool()->waitFor(request_ticket);
}
}

32
httpserver/HTTPSocket.cpp Normal file
View File

@ -0,0 +1,32 @@
#include "HTTPSocket.h"
#include "../stringtools.h"
#include "../Interface/Server.h"
#include "../Interface/Pipe.h"
CHTTPSocket::CHTTPSocket(const std::string& name, const std::string& gparams, const str_map& pRawPARAMS, IPipe* pOutput, const std::string& endpoint_name)
: RawPARAMS(pRawPARAMS), output(pOutput), name(name), gparams(gparams), endpoint_name(endpoint_name)
{
}
void CHTTPSocket::operator()()
{
std::map<std::string, std::string> GET;
ParseParamStrHttp(gparams, &GET, true);
THREAD_ID tid = 0;
try
{
tid = Server->ExecuteWebSocket(name, GET, RawPARAMS, output, endpoint_name);
}
catch (...)
{
return;
}
if (tid == ILLEGAL_THREAD_ID)
{
std::string error = "Error: Unknown web socket [" + EscapeHTML(name) + "]";
Server->Log(error, LL_WARNING);
output->Write("Content-type: text/html; charset=UTF-8\r\n\r\n" + error);
}
}

23
httpserver/HTTPSocket.h Normal file
View File

@ -0,0 +1,23 @@
#pragma once
#include "../Interface/Types.h"
#include "../Interface/Thread.h"
#include "../Interface/Object.h"
class IPipe;
class CHTTPSocket : public IThread, public IObject
{
public:
CHTTPSocket(const std::string& name, const std::string& gparams, const str_map& pRawPARAMS, IPipe* pOutput, const std::string& endpoint_name);
void operator()();
private:
std::string name;
std::string gparams;
str_map RawPARAMS;
std::string endpoint_name;
IPipe* output;
};

View File

@ -105,7 +105,14 @@ DLLEXPORT void LoadActions(IServer* pServer)
Server->Log("Starting HTTP-Server on port "+convert(port), LL_INFO);
Server->StartCustomStreamService( http_service, "HTTP", (unsigned short)port, 1);
IServer::BindTarget bind_target = IServer::BindTarget_All;
if (Server->getServerParameter("http_localhost_only") == "1")
{
bind_target = IServer::BindTarget_Localhost;
}
Server->StartCustomStreamService( http_service, "HTTP", (unsigned short)port, 1, bind_target);
}
DLLEXPORT void UnloadActions(void)

View File

@ -170,6 +170,7 @@
<ClCompile Include="HTTPFile.cpp" />
<ClCompile Include="HTTPProxy.cpp" />
<ClCompile Include="HTTPService.cpp" />
<ClCompile Include="HTTPSocket.cpp" />
<ClCompile Include="IndexFiles.cpp" />
<ClCompile Include="MIMEType.cpp" />
<ClCompile Include="..\stringtools.cpp" />
@ -180,6 +181,7 @@
<ClInclude Include="HTTPFile.h" />
<ClInclude Include="HTTPProxy.h" />
<ClInclude Include="HTTPService.h" />
<ClInclude Include="HTTPSocket.h" />
<ClInclude Include="IndexFiles.h" />
<ClInclude Include="MIMEType.h" />
<ClInclude Include="..\stringtools.h" />

View File

@ -42,6 +42,9 @@
<ClCompile Include="..\stringtools.cpp">
<Filter>Quelldateien</Filter>
</ClCompile>
<ClCompile Include="HTTPSocket.cpp">
<Filter>Quelldateien</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="HTTPAction.h">
@ -68,5 +71,8 @@
<ClInclude Include="..\stringtools.h">
<Filter>Headerdateien</Filter>
</ClInclude>
<ClInclude Include="HTTPSocket.h">
<Filter>Headerdateien</Filter>
</ClInclude>
</ItemGroup>
</Project>

View File

@ -34,6 +34,7 @@
#include "../urbackupcommon/internet_pipe_capabilities.h"
#include "../urbackupcommon/CompressedPipe2.h"
#include "../urbackupcommon/CompressedPipeZstd.h"
#include "../urbackupcommon/WebSocketPipe.h"
#include "../stringtools.h"
@ -1006,7 +1007,7 @@ IPipe * InternetClient::connect(const SServerConnectionSettings & selected_serve
std::string password = getafter(":", udata);
std::string adata = username + ":" + password;
authorization = "Proxy-Authorization: Basic " + base64_encode(reinterpret_cast<const unsigned char*>(adata.c_str()), adata.size())+"\r\n";
authorization = "Proxy-Authorization: Basic " + base64_encode(reinterpret_cast<const unsigned char*>(adata.c_str()), static_cast<unsigned int>(adata.size()))+"\r\n";
}
unsigned short port = ssl ? 443 : 80;
@ -1145,6 +1146,204 @@ IPipe * InternetClient::connect(const SServerConnectionSettings & selected_serve
Server->destroy(cs);
return NULL;
}
else if(next(selected_server_settings.hostname, 0, "ws://") ||
next(selected_server_settings.hostname, 0, "wss://") )
{
std::string hostname;
bool ssl;
if (next(selected_server_settings.hostname, 0, "ws://"))
{
ssl = false;
hostname = selected_server_settings.hostname.substr(5);
}
else
{
ssl = true;
hostname = selected_server_settings.hostname.substr(6);
}
std::string authorization;
if (hostname.find("@") != std::string::npos)
{
std::string udata = getuntil("@", hostname);
hostname = getafter("@", hostname);
std::string username = getuntil(":", udata);
std::string password = getafter(":", udata);
std::string adata = username + ":" + password;
authorization = "Authorization: Basic " + base64_encode(reinterpret_cast<const unsigned char*>(adata.c_str()), static_cast<unsigned int>(adata.size())) + "\r\n";
}
unsigned short port = ssl ? 443 : 80;
std::string loc;
if (hostname.find(":") != std::string::npos)
{
std::string port_str = getafter(":", hostname);
if(port_str.find("/")!=std::string::npos)
{
port = static_cast<unsigned short>(watoi(getuntil("/", port_str)));
loc = getafter("/", port_str);
}
else
{
port = static_cast<unsigned short>(watoi(port_str));
}
hostname = getuntil(":", hostname);
}
if (loc.empty() ||
loc[0] != '/')
loc = "/" + loc;
IPipe* cs;
if (ssl)
cs = Server->ConnectSslStream(hostname, port, 10000);
else
cs = Server->ConnectStream(hostname, port, 10000);
if (cs == NULL)
return cs;
unsigned char websocket_key[16];
Server->secureRandomFill(reinterpret_cast<char*>(websocket_key), sizeof(websocket_key));
std::string websocket_key_str = base64_encode(websocket_key, sizeof(websocket_key));
cs->Write(std::string("GET ")+loc+" HTTP/1.1\r\n"
"Host: "+hostname+"\r\n"
"Upgrade: websocket\r\n"
"Connection: upgrade\r\n"
"Sec-WebSocket-Key: "+ websocket_key_str+"\r\n"
"Sec-WebSocket-Protocol: urbackup\r\n"
"Sec-WebSocket-Version: 13\r\n\r\n");
char buf[512];
int64 resp_timeout = 30000;
int64 starttime = Server->getTimeMS();
int state = 0;
std::string header;
std::string pipe_add;
bool has_header = false;
do
{
size_t read = cs->Read(buf, sizeof(buf), 10000);
if (read > 0)
{
for (size_t i = 0; i < read; ++i)
{
char ch = buf[i];
if (state == 0)
{
if (ch == '\r')
state = 1;
else if (ch == '\n')
state = 2;
else
state = 0;
}
else if (state == 1)
{
if (ch == '\n')
state = 2;
else
state = 0;
}
else if (state == 2)
{
if (ch == '\r')
state = 3;
else if (ch == '\n')
state = 4;
else
state = 0;
}
else if (state == 3)
{
if (ch == '\n')
state = 4;
else
state = 0;
}
else if (state == 4)
{
pipe_add.assign(buf + i, read - i);
has_header = true;
break;
}
header += ch;
}
}
} while (!has_header &&
Server->getTimeMS() - starttime < resp_timeout);
if (!has_header)
{
Server->Log("Timeout connecting via web socket");
Server->destroy(cs);
return NULL;
}
if (!next(header, 0, "HTTP/1.1 101"))
{
Server->Log("Error connecting via web socket. Response: " + header, LL_ERROR);
Server->destroy(cs);
return NULL;
}
std::vector<std::string> headers;
Tokenize(getafter("\n", header), headers, "\n");
str_map header_map;
for (size_t i = 0; i < headers.size(); ++i)
{
std::string key = strlower(getuntil(":", headers[i]));
header_map[key] = trim(getafter(":", headers[i]));
}
if (header_map["sec-websocket-protocol"] != "urbackup")
{
Server->Log("Unknown web socket protocol \"" + header_map["sec-websocket-protocol"] + "\"", LL_ERROR);
Server->destroy(cs);
return NULL;
}
if (header_map["upgrade"] != "websocket")
{
Server->Log("Unknown web socket upgrade value \"" + header_map["upgrade"] + "\"", LL_ERROR);
Server->destroy(cs);
return NULL;
}
if (header_map["connection"] != "upgrade")
{
Server->Log("Unknown web socket connection value \"" + header_map["connection"] + "\"", LL_ERROR);
Server->destroy(cs);
return NULL;
}
std::string accept_key = header_map["sec-websocket-accept"];
std::string expected_accept_key = websocket_key_str + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
std::string sha_bin = crypto_fak->sha1Binary(expected_accept_key);
expected_accept_key = base64_encode(reinterpret_cast<const unsigned char*>(sha_bin.data()), static_cast<unsigned int>(sha_bin.size()));
if (accept_key != expected_accept_key)
{
Server->Log("Web socket accept key wrong. Expected " + expected_accept_key + " got "+accept_key, LL_ERROR);
Server->destroy(cs);
return NULL;
}
return new WebSocketPipe(cs, true, false, pipe_add, true);
}
#endif
return Server->ConnectStream(selected_server_settings.hostname,

View File

@ -0,0 +1,438 @@
#include "WebSocketPipe.h"
#include "WebSocketPipe.h"
#include "../Interface/Server.h"
#include <algorithm>
#include <assert.h>
inline WebSocketPipe::WebSocketPipe(IPipe* pipe, bool mask_writes, bool expect_read_mask, std::string pipe_add, bool destroy_pipe)
: pipe(pipe), mask_writes(mask_writes), expect_read_mask(expect_read_mask), has_error(false),
pipe_add(pipe_add), read_state(EReadState_Header1), masking_key(0), destroy_pipe(destroy_pipe),
read_mutex(Server->createMutex()), write_mutex(Server->createMutex())
{
if (mask_writes)
{
/*
* Just use a fixed non-random masking key. We are not a browser, so the security implications
* are a bit different
*/
while (masking_key == 0)
{
masking_key = Server->getRandomNumber();
}
}
}
WebSocketPipe::~WebSocketPipe()
{
if (destroy_pipe)
delete pipe;
}
size_t WebSocketPipe::Read(char* buffer, size_t bsize, int timeoutms)
{
IScopedLock lock(read_mutex.get());
if (!pipe_add.empty())
{
size_t consumed_out = 0;
size_t data_size = consume(&pipe_add[0], (std::min)(bsize, pipe_add.size()), timeoutms, &consumed_out);
if (data_size > 0)
{
memcpy(buffer, pipe_add.data(), data_size);
}
if (consumed_out > 0)
{
pipe_add.erase(0, consumed_out);
}
if (data_size > 0)
{
return data_size;
}
}
int64 starttime = 0;
if (timeoutms > 0)
{
starttime = Server->getTimeMS();
}
do
{
int curr_timeoutms = static_cast<int>(timeoutms > 0 ? (timeoutms - (Server->getTimeMS() - starttime)) : timeoutms);
size_t read = pipe->Read(buffer, bsize, curr_timeoutms);
if (read > 0)
{
size_t data_size = consume(buffer, read, curr_timeoutms, NULL);
if (data_size > 0)
{
return data_size;
}
}
else
{
return 0;
}
} while (timeoutms == -1 || (timeoutms > 0 && Server->getTimeMS() - starttime < timeoutms));
return 0;
}
bool WebSocketPipe::Write(const char* buffer, size_t bsize, int timeoutms, bool flush)
{
IScopedLock lock(write_mutex.get());
size_t payload_len_size = 1;
if (bsize > 65535)
{
payload_len_size = 8;
}
else if (bsize > 125)
{
payload_len_size = 2;
}
char header[2 + 8 + 4];
unsigned char bits = 0;
bits |= 1 << 7; //FIN bit
unsigned char opcode = 2; //binary frame;
bits |= opcode;
header[0] = static_cast<char>(bits);
size_t header_pos = 1;
if (bsize > 65535)
{
header[header_pos] = 127;
++header_pos;
uint64 payload_size = bsize;
memcpy(&header[header_pos], &payload_size, sizeof(payload_size));
header_pos += sizeof(payload_size);
}
else if (bsize > 125)
{
header[header_pos] = 126;
++header_pos;
unsigned short payload_size = static_cast<unsigned short>(bsize);
memcpy(&header[header_pos], &payload_size, sizeof(payload_size));
header_pos += sizeof(payload_size);
}
else
{
header[header_pos] = static_cast<char>(bsize);
++header_pos;
}
if (mask_writes)
{
header[1] |= 1 << 7;
memcpy(&header[header_pos], &masking_key, sizeof(masking_key));
header_pos += sizeof(masking_key);
std::vector<char> new_buf;
new_buf.resize(header_pos + bsize);
memcpy(new_buf.data(), header, header_pos);
char* mask_ptr = reinterpret_cast<char*>(&masking_key);
for (size_t i = 0; i < bsize; ++i)
{
size_t j = i % 4;
new_buf[header_pos + i] = buffer[i] ^ mask_ptr[j];
}
return pipe->Write(new_buf.data(), header_pos + bsize, timeoutms, flush);
}
else
{
if (!pipe->Write(header, header_pos, timeoutms, false))
{
return false;
}
return pipe->Write(buffer, bsize, timeoutms, flush);
}
}
size_t WebSocketPipe::Read(std::string* ret, int timeoutms)
{
IScopedLock lock(read_mutex.get());
if (!pipe_add.empty())
{
size_t consumed_out = 0;
size_t data_size = consume(&pipe_add[0], pipe_add.size(), timeoutms, &consumed_out);
if (data_size > 0)
{
ret->assign(pipe_add.data(), data_size);
}
if (consumed_out > 0)
{
pipe_add.erase(0, consumed_out);
}
if (data_size > 0)
{
return data_size;
}
}
int64 starttime = 0;
if (timeoutms > 0)
{
starttime = Server->getTimeMS();
}
do
{
int curr_timeoutms = static_cast<int>(timeoutms > 0 ? (timeoutms - (Server->getTimeMS() - starttime)) : timeoutms);
size_t read = pipe->Read(ret, curr_timeoutms);
if (read > 0)
{
size_t data_size = consume(&(*ret)[0], ret->size(), curr_timeoutms, NULL);
if (data_size > 0)
{
ret->resize(data_size);
return ret->size();
}
}
else
{
return 0;
}
} while (timeoutms < 0
|| (timeoutms > 0 && Server->getTimeMS() - starttime < timeoutms));
return 0;
}
size_t WebSocketPipe::consume(char* buffer, size_t bsize, int write_timeoutms, size_t* consumed_out)
{
size_t consumed = 0;
size_t out_off = 0;
while (bsize > consumed)
{
switch (read_state)
{
case EReadState_Header1:
{
header_bits1 = buffer[consumed];
++consumed;
read_state = EReadState_HeaderSize1;
unsigned char opcode = get_opcode();
if (opcode != 0
&& opcode != 1
&& opcode != 2
&& opcode != 8
&& opcode != 9
&& opcode != 10)
{
has_error = true;
}
if (!(header_bits1 & 1)
&& opcode != 0
&& opcode != 1
&& opcode != 2)
{
has_error = true;
}
}break;
case EReadState_HeaderSize1:
{
header_bits2 = buffer[consumed];
if (expect_read_mask
&& !has_read_mask())
{
has_error = true;
}
unsigned char tmp_payload_size = header_bits2 & 0x7F;
++consumed;
if (tmp_payload_size < 126)
{
payload_size = tmp_payload_size;
if (has_read_mask())
{
read_state = EReadState_HeaderMask;
remaining_size_bytes = 4;
consumed_size_bytes = 0;
}
else
{
read_mask = 0;
read_state = EReadState_Body;
}
}
else if (tmp_payload_size == 126)
{
remaining_size_bytes = 2;
consumed_size_bytes = 0;
read_state = EReadState_HeaderSize2;
}
else if (tmp_payload_size == 127)
{
remaining_size_bytes = 8;
consumed_size_bytes = 0;
read_state = EReadState_HeaderSize2;
}
else
{
has_error = true;
}
}break;
case EReadState_HeaderSize2:
{
//PERF: In EReadState_HeaderSize2 and EReadState_HeaderMask read multiple via memcpy if available
unsigned char size_byte = buffer[consumed];
++consumed;
--remaining_size_bytes;
payload_size |= size_byte << (consumed_size_bytes * 8);
++consumed_size_bytes;
if (remaining_size_bytes == 0)
{
if (has_read_mask())
{
read_state = EReadState_HeaderMask;
remaining_size_bytes = 4;
consumed_size_bytes = 0;
}
else
{
read_mask = 0;
read_state = EReadState_Body;
}
}
}break;
case EReadState_HeaderMask:
{
unsigned char mask_byte = buffer[consumed];
++consumed;
--remaining_size_bytes;
read_mask |= mask_byte << (consumed_size_bytes * 8);
++consumed_size_bytes;
if (remaining_size_bytes == 0)
{
read_state = EReadState_Body;
read_mask_idx = 0;
}
} break;
case EReadState_Body:
{
size_t toread = static_cast<size_t>((std::min)(static_cast<uint64>(bsize - consumed), payload_size));
payload_size -= toread;
unsigned char opcode = get_opcode();
if (opcode != 0 && opcode!=1 && opcode != 2)
{
//Ignore payload
consumed += toread;
}
else if (out_off == consumed)
{
if (read_mask != 0)
{
for (size_t i = 0; i < toread; ++i)
{
buffer[out_off] = buffer[out_off] ^ reinterpret_cast<char*>(&read_mask)[read_mask_idx % 4];
++read_mask_idx;
++out_off;
}
consumed = out_off;
}
else
{
consumed += toread;
out_off += toread;
}
}
else
{
assert(out_off < consumed);
if (read_mask != 0)
{
for (size_t i = 0; i < toread; ++i)
{
buffer[out_off] = buffer[consumed] ^ reinterpret_cast<char*>(&read_mask)[read_mask_idx % 4];
++read_mask_idx;
++out_off;
}
}
else
{
memmove(&buffer[out_off], &buffer[consumed], toread);
consumed += toread;
out_off += toread;
}
}
if (payload_size == 0)
{
read_state = EReadState_Header1;
unsigned char opcode = get_opcode();
if (opcode == 8)
{
//Close
char msg[2];
msg[0] = header_bits1;
msg[1] = header_bits2 | (1<<7);
pipe->Write(msg, 2, write_timeoutms, true);
has_error = true;
}
else if (opcode == 9)
{
//Close
char msg[2];
unsigned char opcode = 10; //pong
msg[0] = opcode | (1 << 7);
msg[1] = (1<<7);
if (!pipe->Write(msg, 2, write_timeoutms, true))
{
has_error = true;
}
}
}
}break;
}
}
if (consumed_out != NULL)
*consumed_out = consumed;
return out_off;
}

View File

@ -0,0 +1,111 @@
#pragma once
#include "../Interface/Pipe.h"
#include "../Interface/Mutex.h"
#include <memory>
class WebSocketPipe : public IPipe
{
enum EReadState
{
EReadState_Header1,
EReadState_HeaderSize1,
EReadState_HeaderSize2,
EReadState_HeaderMask,
EReadState_Body
};
public:
WebSocketPipe(IPipe* pipe, bool mask_writes, bool expect_read_mask, std::string pipe_add, bool destroy_pipe);
~WebSocketPipe();
virtual size_t Read(char* buffer, size_t bsize, int timeoutms = -1);
virtual bool Write(const char* buffer, size_t bsize, int timeoutms = -1, bool flush = true);
virtual size_t Read(std::string* ret, int timeoutms = -1);
virtual bool Write(const std::string& str, int timeoutms = -1, bool flush = true)
{
return Write(str.data(), str.size(), timeoutms, flush);
}
virtual bool Flush(int timeoutms = -1)
{
return pipe->Flush(timeoutms);
}
virtual bool isWritable(int timeoutms = 0)
{
return pipe->isWritable();
}
virtual bool isReadable(int timeoutms = 0)
{
return pipe->isReadable();
}
virtual bool hasError(void)
{
return has_error || pipe->hasError();
}
virtual void shutdown(void)
{
pipe->shutdown();
}
virtual size_t getNumElements(void)
{
return pipe->getNumElements();
}
virtual void addThrottler(IPipeThrottler* throttler)
{
pipe->addThrottler(throttler);
}
virtual void addOutgoingThrottler(IPipeThrottler* throttler)
{
pipe->addOutgoingThrottler(throttler);
}
virtual void addIncomingThrottler(IPipeThrottler* throttler)
{
pipe->addIncomingThrottler(throttler);
}
virtual _i64 getTransferedBytes(void)
{
return pipe->getTransferedBytes();
}
virtual void resetTransferedBytes(void)
{
pipe->resetTransferedBytes();
}
private:
bool has_read_mask()
{
return header_bits2 & (1 << 7);
}
unsigned char get_opcode()
{
return (header_bits1 & (1 << 3 | 1 << 2 | 1 << 1 | 1 << 0));
}
size_t consume(char* buffer, size_t bsize, int write_timeoutms, size_t* consumed_out);
bool mask_writes;
bool expect_read_mask;
IPipe* pipe;
EReadState read_state;
std::vector<char> read_buffer;
unsigned char header_bits1;
unsigned char header_bits2;
uint64 payload_size;
size_t remaining_size_bytes;
size_t consumed_size_bytes;
unsigned int read_mask;
unsigned int read_mask_idx;
bool has_error;
std::string pipe_add;
unsigned int masking_key;
bool destroy_pipe;
std::auto_ptr<IMutex> read_mutex;
std::auto_ptr<IMutex> write_mutex;
};

View File

@ -0,0 +1,90 @@
#include "WebSocketConnector.h"
#include "../stringtools.h"
#include "../Interface/Server.h"
#include "../cryptoplugin/ICryptoFactory.h"
#include "../urbackupcommon/WebSocketPipe.h"
#include <assert.h>
extern ICryptoFactory* crypto_fak;
void WebSocketConnector::Execute(str_map& GET, THREAD_ID tid, str_map& PARAMS, IPipe* pipe, const std::string& endpoint_name)
{
if (PARAMS["CONNECTION"] != "Upgrade")
{
pipe->Write("HTTP/1.1 500 Expecting Connection: Upgrade\r\nConnection: Close\r\n\r\n");
return;
}
std::string protocol_list = PARAMS["SEC-WEBSOCKET-PROTOCOL"];
std::vector<std::string> protocols;
Tokenize(protocol_list, protocols, ",");
for (size_t i = 0; i < protocols.size(); ++i)
protocols[i] = trim(protocols[i]);
if (std::find(protocols.begin(), protocols.end(), "urbackup") == protocols.end())
{
pipe->Write("HTTP/1.1 500 urbackup protocol not supported\r\nConnection: Close\r\n\r\n");
return;
}
if (PARAMS["SEC-WEBSOCKET-VERSION"] != "13")
{
pipe->Write("HTTP/1.1 500 websocket protocol version not supported\r\nConnection: Close\r\n\r\n");
return;
}
std::string websocket_key = trim(PARAMS["SEC-WEBSOCKET-KEY"]);
websocket_key += "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
std::string key_response = crypto_fak->sha1Binary(websocket_key);
pipe->Write(std::string("HTTP/1.1 101 Switching Protocols\r\n"
"Upgrade: websocket\r\n"
"Connection: Upgrade\r\n"
"Sec-WebSocket-Accept: ") + base64_encode(reinterpret_cast<const unsigned char*>(key_response.data()),
static_cast<unsigned int>(key_response.size())) + "\r\n"
"Sec-WebSocket-Protocol: urbackup\r\n\r\n");
ICustomClient* client = wrapped_service->createClient();
str_map::iterator it_forwarded_for = PARAMS.find("X-FORWARDED-FOR");
WebSocketPipe ws_pipe(pipe, false, true, std::string(), false);
client->Init(tid, &ws_pipe, it_forwarded_for != PARAMS.end() ? it_forwarded_for->second : endpoint_name);
while (true)
{
bool b = client->Run(NULL);
if (!b)
{
break;
}
if (client->wantReceive())
{
if (ws_pipe.isReadable(10))
{
client->ReceivePackets(NULL);
}
else if (ws_pipe.hasError())
{
client->ReceivePackets(NULL);
Server->wait(20);
}
}
else
{
Server->wait(20);
}
}
wrapped_service->destroyClient(client);
}
std::string WebSocketConnector::getName()
{
return name;
}

View File

@ -0,0 +1,19 @@
#pragma once
#include "../Interface/WebSocket.h"
#include "../Interface/Service.h"
class WebSocketConnector : public IWebSocket
{
public:
WebSocketConnector(IService* wrapped_service, const std::string& name)
: wrapped_service(wrapped_service),
name(name) {}
virtual void Execute(str_map& GET, THREAD_ID tid, str_map& PARAMS, IPipe* pipe, const std::string& endpoint_name);
virtual std::string getName();
private:
IService* wrapped_service;
std::string name;
};

View File

@ -230,6 +230,32 @@ void read_config_file(std::string fn, std::vector<std::string>& real_args)
real_args.push_back(strlower(val));
}
}
if (settings->getValue("HTTP_LOCALHOST_ONLY", &val))
{
val = unquote_value(val);
if (!val.empty()
&& ( val=="1" ||
strlower(val)=="true" ||
strlower(val)=="yes") )
{
real_args.push_back("--http_localhost_only");
real_args.push_back("1");
}
}
if (settings->getValue("FASTCGI_LOCALHOST_ONLY", &val))
{
val = unquote_value(val);
if (!val.empty()
&& (val == "1" ||
strlower(val) == "true" ||
strlower(val) == "yes"))
{
real_args.push_back("--fastcgi_localhost_only");
real_args.push_back("1");
}
}
if (settings->getValue("LOG_ROTATE_FILESIZE", &val))
{
val = trim(unquote_value(val));

View File

@ -99,6 +99,7 @@ SStartupStatus startup_status;
#include "FileMetadataDownloadThread.h"
#include "../urbackupcommon/chunk_hasher.h"
#include "LogReport.h"
#include "WebSocketConnector.h"
#define MINIZ_NO_ZLIB_COMPATIBLE_NAMES
#include "../common/miniz.h"
@ -382,6 +383,8 @@ void detach_other_dbs(IDatabase* db)
db->Write("DETACH DATABASE links_db");
}
#include "../urbackupcommon/WebSocketPipe.h"
DLLEXPORT void LoadActions(IServer* pServer)
{
Server=pServer;
@ -414,6 +417,98 @@ DLLEXPORT void LoadActions(IServer* pServer)
exit(0);
}
IPipe* pipe = Server->ConnectStream("192.168.239.142", 8080, 10000);
pipe->Write("GET / HTTP/1.1\r\n"
"Host: localhost\r\n"
"Upgrade: websocket\r\n"
"Connection: upgrade\r\n"
"Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
"Origin: http://localhost\r\n"
"Sec-WebSocket-Protocol: urbackup\r\n"
"Sec-WebSocket-Version: 13\r\n\r\n");
char buf[512];
int64 resp_timeout = 30000;
int64 starttime = Server->getTimeMS();
int state = 0;
std::string header;
std::string pipe_add;
bool has_header = false;
do
{
_u32 read = pipe->Read(buf, sizeof(buf), 10000);
if (read > 0)
{
for (_u32 i = 0; i < read; ++i)
{
char ch = buf[i];
if (state == 0)
{
if (ch == '\r')
state = 1;
else if (ch == '\n')
state = 2;
else
state = 0;
}
else if (state == 1)
{
if (ch == '\n')
state = 2;
else
state = 0;
}
else if (state == 2)
{
if (ch == '\r')
state = 3;
else if (ch == '\n')
state = 4;
else
state = 0;
}
else if (state == 3)
{
if (ch == '\n')
state = 4;
else
state = 0;
}
else if (state == 4)
{
pipe_add.assign(buf + i, read - i);
has_header = true;
break;
}
header += ch;
}
}
} while (!has_header &&
Server->getTimeMS() - starttime < resp_timeout);
WebSocketPipe ws_pipe(pipe, true, false, pipe_add);
while (true)
{
std::string ret;
ws_pipe.Read(&ret);
Server->Log("Read " + ret);
if (ret == "something")
{
ws_pipe.Write("other");
}
}
exit(0);
std::string download_file=Server->getServerParameter("download_file");
if(!download_file.empty())
{
@ -871,7 +966,11 @@ DLLEXPORT void LoadActions(IServer* pServer)
{
port=settings.getSettings()->internet_server_port;
}
Server->StartCustomStreamService(new InternetService(backup_server), "InternetService", port);
InternetService* internet_service = new InternetService(backup_server);
Server->StartCustomStreamService(internet_service, "InternetService", port);
Server->addWebSocket(new WebSocketConnector(internet_service, "socket"));
Server->addWebSocket(new WebSocketConnector(internet_service, ""));
}
}

View File

@ -213,6 +213,7 @@
<ClCompile Include="..\urbackupcommon\SparseFile.cpp" />
<ClCompile Include="..\urbackupcommon\TreeHash.cpp" />
<ClCompile Include="..\urbackupcommon\WalCheckpointThread.cpp" />
<ClCompile Include="..\urbackupcommon\WebSocketPipe.cpp" />
<ClCompile Include="Alerts.cpp" />
<ClCompile Include="apps\blockalign.cpp" />
<ClCompile Include="apps\check_files_index.cpp" />
@ -300,6 +301,7 @@
<ClCompile Include="treediff\TreeNode.cpp" />
<ClCompile Include="treediff\TreeReader.cpp" />
<ClCompile Include="verify_hashes.cpp" />
<ClCompile Include="WebSocketConnector.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\common\adler32.h" />
@ -333,6 +335,7 @@
<ClInclude Include="..\urbackupcommon\SparseFile.h" />
<ClInclude Include="..\urbackupcommon\TreeHash.h" />
<ClInclude Include="..\urbackupcommon\WalCheckpointThread.h" />
<ClInclude Include="..\urbackupcommon\WebSocketPipe.h" />
<ClInclude Include="action_header.h" />
<ClInclude Include="actions.h" />
<ClInclude Include="Alerts.h" />
@ -402,6 +405,7 @@
<ClInclude Include="treediff\TreeNode.h" />
<ClInclude Include="treediff\TreeReader.h" />
<ClInclude Include="server_status.h" />
<ClInclude Include="WebSocketConnector.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">

View File

@ -390,6 +390,12 @@
<ClCompile Include="serverinterface\restore_image.cpp">
<Filter>serverinterface</Filter>
</ClCompile>
<ClCompile Include="WebSocketConnector.cpp">
<Filter>Quelldateien</Filter>
</ClCompile>
<ClCompile Include="..\urbackupcommon\WebSocketPipe.cpp">
<Filter>Quelldateien</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="action_header.h">
@ -692,5 +698,11 @@
<ClInclude Include="..\urbackupcommon\sha2\sha2.h">
<Filter>sha2</Filter>
</ClInclude>
<ClInclude Include="WebSocketConnector.h">
<Filter>Headerdateien</Filter>
</ClInclude>
<ClInclude Include="..\urbackupcommon\WebSocketPipe.h">
<Filter>Headerdateien</Filter>
</ClInclude>
</ItemGroup>
</Project>