mirror of
https://github.com/falk-werner/webfuse-provider
synced 2024-10-27 20:44:10 +00:00
remove unused tests
This commit is contained in:
parent
797ee2bd15
commit
fdd93149fe
@ -117,9 +117,7 @@ alltests = executable('alltests',
|
|||||||
'test/webfuse_provider/utils/file_utils.cc',
|
'test/webfuse_provider/utils/file_utils.cc',
|
||||||
'test/webfuse_provider/utils/timeout_watcher.cc',
|
'test/webfuse_provider/utils/timeout_watcher.cc',
|
||||||
'test/webfuse_provider/utils/path.c',
|
'test/webfuse_provider/utils/path.c',
|
||||||
'test/webfuse_provider/utils/static_filesystem.c',
|
|
||||||
'test/webfuse_provider/utils/ws_server.cc',
|
'test/webfuse_provider/utils/ws_server.cc',
|
||||||
'test/webfuse_provider/utils/ws_server2.cc',
|
|
||||||
'test/webfuse_provider/utils/jansson_test_environment.cc',
|
'test/webfuse_provider/utils/jansson_test_environment.cc',
|
||||||
'test/webfuse_provider/mocks/fake_invokation_context.cc',
|
'test/webfuse_provider/mocks/fake_invokation_context.cc',
|
||||||
'test/webfuse_provider/mocks/mock_request.cc',
|
'test/webfuse_provider/mocks/mock_request.cc',
|
||||||
|
@ -1,85 +0,0 @@
|
|||||||
#include "webfuse_provider/tests/integration/file.hpp"
|
|
||||||
#include <cstdio>
|
|
||||||
#include <sstream>
|
|
||||||
|
|
||||||
namespace
|
|
||||||
{
|
|
||||||
|
|
||||||
bool invoke(std::string const & command)
|
|
||||||
{
|
|
||||||
int exit_code = -1;
|
|
||||||
|
|
||||||
FILE * file = ::popen(command.c_str(), "r");
|
|
||||||
if (nullptr != file)
|
|
||||||
{
|
|
||||||
exit_code = ::pclose(file);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (0 == exit_code);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace webfuse_test
|
|
||||||
{
|
|
||||||
|
|
||||||
File::File(std::string const& path)
|
|
||||||
: path_(path)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
File::~File()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
bool File::isFile()
|
|
||||||
{
|
|
||||||
std::stringstream command;
|
|
||||||
command << "./fs_check -c is_file -f " << path_;
|
|
||||||
|
|
||||||
return invoke(command.str());
|
|
||||||
}
|
|
||||||
|
|
||||||
bool File::isDirectory()
|
|
||||||
{
|
|
||||||
std::stringstream command;
|
|
||||||
command << "./fs_check -c is_dir -f " << path_;
|
|
||||||
|
|
||||||
return invoke(command.str());
|
|
||||||
}
|
|
||||||
|
|
||||||
bool File::hasAccessRights(int accessRights)
|
|
||||||
{
|
|
||||||
std::stringstream command;
|
|
||||||
command << "./fs_check -c has_mode -f " << path_ << " -a " << accessRights;
|
|
||||||
|
|
||||||
return invoke(command.str());
|
|
||||||
}
|
|
||||||
|
|
||||||
bool File::hasSize(size_t size)
|
|
||||||
{
|
|
||||||
std::stringstream command;
|
|
||||||
command << "./fs_check -c has_size -f " << path_ << " -a " << size;
|
|
||||||
|
|
||||||
return invoke(command.str());
|
|
||||||
}
|
|
||||||
|
|
||||||
bool File::hasSubdirectory(std::string const & subdir)
|
|
||||||
{
|
|
||||||
std::stringstream command;
|
|
||||||
command << "./fs_check -c has_subdir -f " << path_ << " -a " << subdir;
|
|
||||||
|
|
||||||
return invoke(command.str());
|
|
||||||
}
|
|
||||||
|
|
||||||
bool File::hasContents(std::string const & contents)
|
|
||||||
{
|
|
||||||
std::stringstream command;
|
|
||||||
command << "./fs_check -c has_contents -f " << path_ << " -a " << contents;
|
|
||||||
|
|
||||||
return invoke(command.str());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,26 +0,0 @@
|
|||||||
#ifndef WFP_TEST_INTEGRATION_FILE_HPP
|
|
||||||
#define WFP_TEST_INTEGRATION_FILE_HPP
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
namespace webfuse_test
|
|
||||||
{
|
|
||||||
|
|
||||||
class File final
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
explicit File(std::string const& path);
|
|
||||||
~File();
|
|
||||||
bool isFile();
|
|
||||||
bool isDirectory();
|
|
||||||
bool hasAccessRights(int accessRights);
|
|
||||||
bool hasSize(size_t size);
|
|
||||||
bool hasSubdirectory(std::string const & subdir);
|
|
||||||
bool hasContents(std::string const & contents);
|
|
||||||
private:
|
|
||||||
std::string path_;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,148 +0,0 @@
|
|||||||
#include "webfuse_provider/tests/integration/provider.hpp"
|
|
||||||
#include "webfuse_provider.h"
|
|
||||||
#include "webfuse_provider/impl/client.h"
|
|
||||||
#include <thread>
|
|
||||||
#include <mutex>
|
|
||||||
#include <chrono>
|
|
||||||
#include <string>
|
|
||||||
#include "webfuse/utils/static_filesystem.h"
|
|
||||||
|
|
||||||
using namespace std::chrono_literals;
|
|
||||||
|
|
||||||
namespace
|
|
||||||
{
|
|
||||||
enum class ConnectionState
|
|
||||||
{
|
|
||||||
disconnected,
|
|
||||||
connected,
|
|
||||||
connecting
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C"
|
|
||||||
{
|
|
||||||
|
|
||||||
void
|
|
||||||
webfuse_test_provider_onconnected(
|
|
||||||
void * user_data)
|
|
||||||
{
|
|
||||||
auto * fs = reinterpret_cast<wfp_static_filesystem*>(user_data);
|
|
||||||
auto * connection_state = reinterpret_cast<ConnectionState*>(wfp_static_filesystem_get_user_data(fs));
|
|
||||||
*connection_state = ConnectionState::connected;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
webfuse_test_provider_ondisconnected(
|
|
||||||
void * user_data)
|
|
||||||
{
|
|
||||||
auto * fs = reinterpret_cast<wfp_static_filesystem*>(user_data);
|
|
||||||
auto * connection_state = reinterpret_cast<ConnectionState*>(wfp_static_filesystem_get_user_data(fs));
|
|
||||||
*connection_state = ConnectionState::disconnected;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace webfuse_test
|
|
||||||
{
|
|
||||||
|
|
||||||
class Provider::Private
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
explicit Private(char const * url)
|
|
||||||
: is_shutdown_requested(false)
|
|
||||||
, connection_state(ConnectionState::connecting)
|
|
||||||
{
|
|
||||||
config = wfp_client_config_create();
|
|
||||||
wfp_client_config_set_certpath(config, "client-cert.pem");
|
|
||||||
wfp_client_config_set_keypath(config, "client-key.pem");
|
|
||||||
wfp_client_config_set_ca_filepath(config, "server-cert.pem");
|
|
||||||
wfp_client_config_set_onconnected(config, &webfuse_test_provider_onconnected);
|
|
||||||
wfp_client_config_set_ondisconnected(config, &webfuse_test_provider_ondisconnected);
|
|
||||||
|
|
||||||
fs = wfp_static_filesystem_create(config);
|
|
||||||
wfp_static_filesystem_set_user_data(fs, reinterpret_cast<void*>(&connection_state));
|
|
||||||
wfp_static_filesystem_add_text(fs, "hello.txt", 0444, "Hello, World");
|
|
||||||
|
|
||||||
client = wfp_client_create(config);
|
|
||||||
wfp_client_connect(client, url);
|
|
||||||
while (ConnectionState::connecting == connection_state)
|
|
||||||
{
|
|
||||||
wfp_client_service(client);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ConnectionState::connected == connection_state)
|
|
||||||
{
|
|
||||||
thread = std::thread(Run, this);
|
|
||||||
std::this_thread::sleep_for(200ms);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
wfp_client_dispose(client);
|
|
||||||
|
|
||||||
wfp_static_filesystem_dispose(fs);
|
|
||||||
wfp_client_config_dispose(config);
|
|
||||||
|
|
||||||
throw std::runtime_error("unable to connect");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
~Private()
|
|
||||||
{
|
|
||||||
RequestShutdown();
|
|
||||||
thread.join();
|
|
||||||
|
|
||||||
wfp_client_disconnect(client);
|
|
||||||
while (ConnectionState::disconnected != connection_state)
|
|
||||||
{
|
|
||||||
wfp_client_service(client);
|
|
||||||
}
|
|
||||||
|
|
||||||
wfp_client_dispose(client);
|
|
||||||
|
|
||||||
wfp_static_filesystem_dispose(fs);
|
|
||||||
wfp_client_config_dispose(config);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IsShutdownRequested()
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> lock(shutdown_lock);
|
|
||||||
return is_shutdown_requested;
|
|
||||||
}
|
|
||||||
private:
|
|
||||||
void RequestShutdown()
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> lock(shutdown_lock);
|
|
||||||
is_shutdown_requested = true;
|
|
||||||
wfp_client_interrupt(client);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void Run(Provider::Private * context)
|
|
||||||
{
|
|
||||||
while (!context->IsShutdownRequested())
|
|
||||||
{
|
|
||||||
wfp_client_service(context->client);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::mutex shutdown_lock;
|
|
||||||
std::thread thread;
|
|
||||||
bool is_shutdown_requested;
|
|
||||||
ConnectionState connection_state;
|
|
||||||
|
|
||||||
wfp_client_config * config;
|
|
||||||
wfp_static_filesystem * fs;
|
|
||||||
public:
|
|
||||||
wfp_client * client;
|
|
||||||
};
|
|
||||||
|
|
||||||
Provider::Provider(char const * url)
|
|
||||||
: d(new Provider::Private(url))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
Provider::~Provider()
|
|
||||||
{
|
|
||||||
delete d;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,19 +0,0 @@
|
|||||||
#ifndef WFP_TEST_INTEGRATION_PROVIDER
|
|
||||||
#define WFP_TEST_INTEGRATION_PROVIDER
|
|
||||||
|
|
||||||
namespace webfuse_test
|
|
||||||
{
|
|
||||||
|
|
||||||
class Provider
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
explicit Provider(char const * url);
|
|
||||||
~Provider();
|
|
||||||
private:
|
|
||||||
class Private;
|
|
||||||
Private * d;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,154 +0,0 @@
|
|||||||
#include "webfuse_provider/tests/integration/server.hpp"
|
|
||||||
#include <thread>
|
|
||||||
#include <mutex>
|
|
||||||
#include <sstream>
|
|
||||||
#include <cstdlib>
|
|
||||||
#include <cstring>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include "webfuse_adapter.h"
|
|
||||||
#include "webfuse/adapter/impl/server.h"
|
|
||||||
|
|
||||||
#define WFP_PATH_MAX (100)
|
|
||||||
|
|
||||||
extern "C"
|
|
||||||
{
|
|
||||||
|
|
||||||
static void webfuse_test_server_cleanup_mountpoint(
|
|
||||||
void * user_data)
|
|
||||||
{
|
|
||||||
char * path = reinterpret_cast<char*>(user_data);
|
|
||||||
rmdir(path);
|
|
||||||
free(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct wfp_mountpoint *
|
|
||||||
webfuse_test_server_create_mountpoint(
|
|
||||||
char const * filesystem,
|
|
||||||
void * user_data)
|
|
||||||
{
|
|
||||||
char const * base_dir = reinterpret_cast<char const*>(user_data);
|
|
||||||
char path[WFP_PATH_MAX];
|
|
||||||
snprintf(path, WFP_PATH_MAX, "%s/%s", base_dir, filesystem);
|
|
||||||
mkdir(path, 0755);
|
|
||||||
struct wfp_mountpoint * mountpoint = wfp_mountpoint_create(path);
|
|
||||||
wfp_mountpoint_set_userdata(
|
|
||||||
mountpoint,
|
|
||||||
reinterpret_cast<void*>(strdup(path)),
|
|
||||||
&webfuse_test_server_cleanup_mountpoint);
|
|
||||||
|
|
||||||
return mountpoint;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace webfuse_test
|
|
||||||
{
|
|
||||||
|
|
||||||
class Server::Private
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
Private()
|
|
||||||
: is_shutdown_requested(false)
|
|
||||||
{
|
|
||||||
snprintf(base_dir, WFP_PATH_MAX, "%s", "/tmp/webfuse_test_integration_XXXXXX");
|
|
||||||
char const * result = mkdtemp(base_dir);
|
|
||||||
if (NULL == result)
|
|
||||||
{
|
|
||||||
throw std::runtime_error("unable to create temp dir");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
config = wfp_server_config_create();
|
|
||||||
wfp_server_config_set_port(config, 0);
|
|
||||||
wfp_server_config_set_mountpoint_factory(config,
|
|
||||||
&webfuse_test_server_create_mountpoint,
|
|
||||||
reinterpret_cast<void*>(base_dir));
|
|
||||||
wfp_server_config_set_keypath(config, "server-key.pem");
|
|
||||||
wfp_server_config_set_certpath(config, "server-cert.pem");
|
|
||||||
|
|
||||||
server = wfp_server_create(config);
|
|
||||||
|
|
||||||
while (!wfp_impl_server_is_operational(server))
|
|
||||||
{
|
|
||||||
wfp_server_service(server);
|
|
||||||
}
|
|
||||||
|
|
||||||
thread = std::thread(Run, this);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
~Private()
|
|
||||||
{
|
|
||||||
RequestShutdown();
|
|
||||||
thread.join();
|
|
||||||
rmdir(base_dir);
|
|
||||||
wfp_server_dispose(server);
|
|
||||||
wfp_server_config_dispose(config);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IsShutdownRequested()
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> lock(shutdown_lock);
|
|
||||||
return is_shutdown_requested;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string GetUrl(void) const
|
|
||||||
{
|
|
||||||
int const port = wfp_server_get_port(server);
|
|
||||||
std::ostringstream stream;
|
|
||||||
stream << "wss://localhost:" << port << "/";
|
|
||||||
return stream.str();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
void RequestShutdown()
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> lock(shutdown_lock);
|
|
||||||
is_shutdown_requested = true;
|
|
||||||
wfp_server_interrupt(server);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void Run(Server::Private * context)
|
|
||||||
{
|
|
||||||
while (!context->IsShutdownRequested())
|
|
||||||
{
|
|
||||||
wfp_server_service(context->server);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
std::mutex shutdown_lock;
|
|
||||||
std::thread thread;
|
|
||||||
bool is_shutdown_requested;
|
|
||||||
|
|
||||||
|
|
||||||
public:
|
|
||||||
char base_dir[WFP_PATH_MAX];
|
|
||||||
wfp_server_config * config;
|
|
||||||
wfp_server * server;
|
|
||||||
};
|
|
||||||
|
|
||||||
Server::Server()
|
|
||||||
: d(new Server::Private())
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
Server::~Server()
|
|
||||||
{
|
|
||||||
delete d;
|
|
||||||
}
|
|
||||||
|
|
||||||
char const * Server::GetBaseDir(void) const
|
|
||||||
{
|
|
||||||
return d->base_dir;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string Server::GetUrl(void) const
|
|
||||||
{
|
|
||||||
return d->GetUrl();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
@ -1,25 +0,0 @@
|
|||||||
#ifndef WFP_TEST_INTEGRATION_SERVER_HPP
|
|
||||||
#define WFP_TEST_INTEGRATION_SERVER_HPP
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
namespace webfuse_test
|
|
||||||
{
|
|
||||||
|
|
||||||
class Server
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
Server();
|
|
||||||
~Server();
|
|
||||||
void Start(void);
|
|
||||||
void Stop(void);
|
|
||||||
char const * GetBaseDir(void) const;
|
|
||||||
std::string GetUrl(void) const;
|
|
||||||
private:
|
|
||||||
class Private;
|
|
||||||
Private * d;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,97 +0,0 @@
|
|||||||
#include <gtest/gtest.h>
|
|
||||||
#include "webfuse_provider/tests/integration/server.hpp"
|
|
||||||
#include "webfuse_provider/tests/integration/provider.hpp"
|
|
||||||
#include "webfuse_provider/tests/integration/file.hpp"
|
|
||||||
|
|
||||||
#include <cstdio>
|
|
||||||
#include <csignal>
|
|
||||||
#include <cstring>
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <dirent.h>
|
|
||||||
|
|
||||||
#include <jansson.h>
|
|
||||||
#include "webfuse_provider/impl/lws_log.h"
|
|
||||||
|
|
||||||
using webfuse_test::Server;
|
|
||||||
using webfuse_test::Provider;
|
|
||||||
using webfuse_test::File;
|
|
||||||
|
|
||||||
namespace
|
|
||||||
{
|
|
||||||
class IntegrationTest: public ::testing::Test
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
IntegrationTest()
|
|
||||||
: server(nullptr)
|
|
||||||
, provider(nullptr)
|
|
||||||
{
|
|
||||||
json_object_seed(0);
|
|
||||||
wfp_impl_lwslog_disable();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void SetUp()
|
|
||||||
{
|
|
||||||
server = new Server();
|
|
||||||
provider = new Provider(server->GetUrl().c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
void TearDown()
|
|
||||||
{
|
|
||||||
delete provider;
|
|
||||||
delete server;
|
|
||||||
}
|
|
||||||
|
|
||||||
char const * GetBaseDir() const
|
|
||||||
{
|
|
||||||
return server->GetBaseDir();
|
|
||||||
}
|
|
||||||
private:
|
|
||||||
Server * server;
|
|
||||||
Provider * provider;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(IntegrationTest, HasMountpoint)
|
|
||||||
{
|
|
||||||
struct stat buffer;
|
|
||||||
int rc = stat(GetBaseDir(), &buffer);
|
|
||||||
|
|
||||||
ASSERT_EQ(0, rc);
|
|
||||||
ASSERT_TRUE(S_ISDIR(buffer.st_mode));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(IntegrationTest, ProvidesTextFile)
|
|
||||||
{
|
|
||||||
std::string file_name = std::string(GetBaseDir()) + "/cprovider/hello.txt";
|
|
||||||
|
|
||||||
File file(file_name);
|
|
||||||
ASSERT_TRUE(file.isFile());
|
|
||||||
ASSERT_TRUE(file.hasAccessRights(0444));
|
|
||||||
ASSERT_TRUE(file.hasSize(12));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(IntegrationTest, ReadTextFile)
|
|
||||||
{
|
|
||||||
std::string file_name = std::string(GetBaseDir()) + "/cprovider/hello.txt";
|
|
||||||
|
|
||||||
File file(file_name);
|
|
||||||
ASSERT_TRUE(file.hasContents("Hello, World"));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(IntegrationTest, ReadDir)
|
|
||||||
{
|
|
||||||
std::string dir_name = std::string(GetBaseDir()) + "/cprovider";
|
|
||||||
|
|
||||||
File dir(dir_name);
|
|
||||||
ASSERT_TRUE(dir.isDirectory());
|
|
||||||
ASSERT_TRUE(dir.hasSubdirectory("."));
|
|
||||||
ASSERT_TRUE(dir.hasSubdirectory(".."));
|
|
||||||
ASSERT_TRUE(dir.hasSubdirectory("hello.txt"));
|
|
||||||
ASSERT_FALSE(dir.hasSubdirectory("other"));
|
|
||||||
}
|
|
@ -1,112 +0,0 @@
|
|||||||
#include "webfuse_adapter.h"
|
|
||||||
#include "webfuse_provider.h"
|
|
||||||
#include <libwebsockets.h>
|
|
||||||
|
|
||||||
#include "webfuse/utils/tempdir.hpp"
|
|
||||||
|
|
||||||
#include <gtest/gtest.h>
|
|
||||||
|
|
||||||
using ::webfuse_test::TempDir;
|
|
||||||
|
|
||||||
extern "C"
|
|
||||||
{
|
|
||||||
|
|
||||||
wfp_mountpoint *
|
|
||||||
wfp_test_integration_lowlevel_create_mountpoint(
|
|
||||||
char const *, void * user_data)
|
|
||||||
{
|
|
||||||
auto * tempDir = reinterpret_cast<TempDir*>(user_data);
|
|
||||||
return wfp_mountpoint_create(tempDir->path());
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
wfp_test_integration_lowlevel_on_connected(
|
|
||||||
void * user_data)
|
|
||||||
{
|
|
||||||
int * state = reinterpret_cast<int*>(user_data);
|
|
||||||
*state = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
wfp_test_integration_lowlevel_on_disconnected(
|
|
||||||
void * user_data)
|
|
||||||
{
|
|
||||||
int * state = reinterpret_cast<int*>(user_data);
|
|
||||||
*state = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
wfp_test_integration_lowlevel_authenticate(
|
|
||||||
struct wfp_credentials const * credentials,
|
|
||||||
void * )
|
|
||||||
{
|
|
||||||
char const * username = wfp_credentials_get(credentials, "username");
|
|
||||||
char const * password = wfp_credentials_get(credentials, "password");
|
|
||||||
|
|
||||||
return ((0 == strcmp(username, "bob")) && (0 == strcmp(password, "secret")));
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
wfp_test_integration_lowlevel_get_credentials(
|
|
||||||
struct wfp_credentials * credentials,
|
|
||||||
void * )
|
|
||||||
{
|
|
||||||
wfp_credentials_set_type(credentials, "username");
|
|
||||||
wfp_credentials_add(credentials, "username", "bob");
|
|
||||||
wfp_credentials_add(credentials, "password", "secret");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(integration, lowlevel)
|
|
||||||
{
|
|
||||||
TempDir dir("wfp_test");
|
|
||||||
|
|
||||||
wfp_server_protocol * server_protocol = wfp_server_protocol_create(
|
|
||||||
&wfp_test_integration_lowlevel_create_mountpoint,
|
|
||||||
reinterpret_cast<void*>(&dir));
|
|
||||||
ASSERT_NE(nullptr, server_protocol);
|
|
||||||
wfp_server_protocol_add_authenticator(server_protocol, "username",
|
|
||||||
&wfp_test_integration_lowlevel_authenticate, nullptr);
|
|
||||||
|
|
||||||
int state = 0;
|
|
||||||
wfp_client_config * client_config = wfp_client_config_create();
|
|
||||||
ASSERT_NE(nullptr, client_config);
|
|
||||||
wfp_client_config_set_userdata(client_config, reinterpret_cast<void*>(&state));
|
|
||||||
wfp_client_config_set_onconnected(client_config, &wfp_test_integration_lowlevel_on_connected);
|
|
||||||
wfp_client_config_set_ondisconnected(client_config, &wfp_test_integration_lowlevel_on_disconnected);
|
|
||||||
wfp_client_config_enable_authentication(client_config, &wfp_test_integration_lowlevel_get_credentials);
|
|
||||||
|
|
||||||
wfp_client_protocol * client_protocol = wfp_client_protocol_create(client_config);
|
|
||||||
ASSERT_NE(nullptr, client_protocol);
|
|
||||||
|
|
||||||
lws_protocols protocols[3];
|
|
||||||
memset(protocols, 0, 3 * sizeof(lws_protocols));
|
|
||||||
wfp_server_protocol_init_lws(server_protocol, &protocols[0]);
|
|
||||||
wfp_client_protocol_init_lws(client_protocol, &protocols[1]);
|
|
||||||
|
|
||||||
lws_context_creation_info info;
|
|
||||||
memset(&info, 0, sizeof(info));
|
|
||||||
info.port = 8080;
|
|
||||||
info.protocols = protocols;
|
|
||||||
info.vhost_name = "localhost";
|
|
||||||
info.ws_ping_pong_interval = 10;
|
|
||||||
info.options = LWS_SERVER_OPTION_HTTP_HEADERS_SECURITY_BEST_PRACTICES_ENFORCE;
|
|
||||||
|
|
||||||
struct lws_context * context = lws_create_context(&info);
|
|
||||||
ASSERT_NE(nullptr, context);
|
|
||||||
|
|
||||||
wfp_client_protocol_connect(client_protocol, context, "ws://localhost:8080/");
|
|
||||||
while (0 == state)
|
|
||||||
{
|
|
||||||
lws_service(context, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
EXPECT_EQ(1, state);
|
|
||||||
|
|
||||||
lws_context_destroy(context);
|
|
||||||
|
|
||||||
wfp_client_protocol_dispose(client_protocol);
|
|
||||||
wfp_client_config_dispose(client_config);
|
|
||||||
wfp_server_protocol_dispose(server_protocol);
|
|
||||||
}
|
|
@ -1,149 +0,0 @@
|
|||||||
#include "webfuse/utils/adapter_client.hpp"
|
|
||||||
#include "webfuse/utils/tempdir.hpp"
|
|
||||||
#include <thread>
|
|
||||||
#include <mutex>
|
|
||||||
|
|
||||||
namespace
|
|
||||||
{
|
|
||||||
|
|
||||||
enum class Command
|
|
||||||
{
|
|
||||||
run,
|
|
||||||
shutdown,
|
|
||||||
connect,
|
|
||||||
disconnect,
|
|
||||||
authenticate,
|
|
||||||
add_filesystem
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace webfuse_test
|
|
||||||
{
|
|
||||||
|
|
||||||
class AdapterClient::Private
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
Private(
|
|
||||||
wfp_client_callback_fn * callback,
|
|
||||||
void * user_data,
|
|
||||||
std::string const & url)
|
|
||||||
: client(wfp_client_create(callback, user_data))
|
|
||||||
, url_(url)
|
|
||||||
, command(Command::run)
|
|
||||||
, tempdir("webfuse_adpter_client")
|
|
||||||
{
|
|
||||||
thread = std::thread(&Run, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
~Private()
|
|
||||||
{
|
|
||||||
ApplyCommand(Command::shutdown);
|
|
||||||
thread.join();
|
|
||||||
wfp_client_dispose(client);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ApplyCommand(Command actual_command)
|
|
||||||
{
|
|
||||||
{
|
|
||||||
std::unique_lock<std::mutex> lock(mutex);
|
|
||||||
command = actual_command;
|
|
||||||
}
|
|
||||||
|
|
||||||
wfp_client_interrupt(client);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string GetDir()
|
|
||||||
{
|
|
||||||
return tempdir.path();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
static void Run(Private * self)
|
|
||||||
{
|
|
||||||
bool is_running = true;
|
|
||||||
while (is_running)
|
|
||||||
{
|
|
||||||
Command actual_command;
|
|
||||||
{
|
|
||||||
std::unique_lock<std::mutex> lock(self->mutex);
|
|
||||||
actual_command = self->command;
|
|
||||||
self->command = Command::run;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (actual_command)
|
|
||||||
{
|
|
||||||
case Command::run:
|
|
||||||
wfp_client_service(self->client);
|
|
||||||
break;
|
|
||||||
case Command::connect:
|
|
||||||
wfp_client_connect(self->client, self->url_.c_str());
|
|
||||||
break;
|
|
||||||
case Command::disconnect:
|
|
||||||
wfp_client_disconnect(self->client);
|
|
||||||
break;
|
|
||||||
case Command::authenticate:
|
|
||||||
wfp_client_authenticate(self->client);
|
|
||||||
break;
|
|
||||||
case Command::add_filesystem:
|
|
||||||
wfp_client_add_filesystem(self->client, self->tempdir.path(), "test");
|
|
||||||
break;
|
|
||||||
case Command::shutdown:
|
|
||||||
// fall-through
|
|
||||||
default:
|
|
||||||
is_running = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
wfp_client * client;
|
|
||||||
std::string url_;
|
|
||||||
Command command;
|
|
||||||
TempDir tempdir;
|
|
||||||
std::thread thread;
|
|
||||||
std::mutex mutex;
|
|
||||||
};
|
|
||||||
|
|
||||||
AdapterClient::AdapterClient(
|
|
||||||
wfp_client_callback_fn * callback,
|
|
||||||
void * user_data,
|
|
||||||
std::string const & url)
|
|
||||||
: d(new Private(callback, user_data, url))
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
AdapterClient::~AdapterClient()
|
|
||||||
{
|
|
||||||
delete d;
|
|
||||||
}
|
|
||||||
|
|
||||||
void AdapterClient::Connect()
|
|
||||||
{
|
|
||||||
d->ApplyCommand(Command::connect);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AdapterClient::Disconnect()
|
|
||||||
{
|
|
||||||
d->ApplyCommand(Command::disconnect);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AdapterClient::Authenticate()
|
|
||||||
{
|
|
||||||
d->ApplyCommand(Command::authenticate);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AdapterClient::AddFileSystem()
|
|
||||||
{
|
|
||||||
d->ApplyCommand(Command::add_filesystem);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string AdapterClient::GetDir() const
|
|
||||||
{
|
|
||||||
return d->GetDir();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
@ -1,32 +0,0 @@
|
|||||||
#ifndef WFP_UTILS_ADAPTER_CLIENT_HPP
|
|
||||||
#define WFP_UTILS_APAPTER_CLIENT_HPP
|
|
||||||
|
|
||||||
#include "webfuse/adapter/client.h"
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
namespace webfuse_test
|
|
||||||
{
|
|
||||||
|
|
||||||
class AdapterClient
|
|
||||||
{
|
|
||||||
AdapterClient(AdapterClient const &) = delete;
|
|
||||||
AdapterClient& operator=(AdapterClient const &) = delete;
|
|
||||||
public:
|
|
||||||
AdapterClient(
|
|
||||||
wfp_client_callback_fn * callback,
|
|
||||||
void * user_data,
|
|
||||||
std::string const & url);
|
|
||||||
~AdapterClient();
|
|
||||||
void Connect();
|
|
||||||
void Disconnect();
|
|
||||||
void Authenticate();
|
|
||||||
void AddFileSystem();
|
|
||||||
std::string GetDir() const;
|
|
||||||
private:
|
|
||||||
class Private;
|
|
||||||
Private * d;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,421 +0,0 @@
|
|||||||
#include "webfuse_provider/utils/static_filesystem.h"
|
|
||||||
#include "webfuse_provider/client_config.h"
|
|
||||||
#include "webfuse_provider/dirbuffer.h"
|
|
||||||
#include "webfuse_provider/operation/error.h"
|
|
||||||
|
|
||||||
#include "webfuse_provider/utils/path.h"
|
|
||||||
#include "webfuse_provider/impl/util.h"
|
|
||||||
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdbool.h>
|
|
||||||
|
|
||||||
#define WFP_STATIC_FILESYSTEM_DEFAULT_CAPACITY (16)
|
|
||||||
#define WFP_STATIC_FILSYSTEM_INODE_ROOT (1)
|
|
||||||
#define WFP_STATIC_FILESYSTEM_MAX_READ_SIZE (4 * 1024)
|
|
||||||
|
|
||||||
struct wfp_static_filesystem_entry
|
|
||||||
{
|
|
||||||
size_t inode;
|
|
||||||
size_t parent;
|
|
||||||
char * name;
|
|
||||||
bool is_file;
|
|
||||||
int mode;
|
|
||||||
size_t size;
|
|
||||||
char * content;
|
|
||||||
wfp_static_filesystem_read_fn * read;
|
|
||||||
wfp_static_filesystem_get_info_fn * get_info;
|
|
||||||
void * user_data;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct wfp_static_filesystem
|
|
||||||
{
|
|
||||||
struct wfp_static_filesystem_entry * entries;
|
|
||||||
size_t size;
|
|
||||||
size_t capacity;
|
|
||||||
void * user_data;
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct wfp_static_filesystem_entry *
|
|
||||||
wfp_static_filesystem_get_entry(
|
|
||||||
struct wfp_static_filesystem * filesystem,
|
|
||||||
size_t inode)
|
|
||||||
{
|
|
||||||
struct wfp_static_filesystem_entry * entry = NULL;
|
|
||||||
|
|
||||||
if ((0 < inode) && (inode <= filesystem->size))
|
|
||||||
{
|
|
||||||
entry = &filesystem->entries[inode - 1];
|
|
||||||
}
|
|
||||||
|
|
||||||
return entry;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct wfp_static_filesystem_entry *
|
|
||||||
wfp_static_filesystem_get_entry_by_name(
|
|
||||||
struct wfp_static_filesystem * filesystem,
|
|
||||||
size_t parent,
|
|
||||||
char const * name)
|
|
||||||
{
|
|
||||||
struct wfp_static_filesystem_entry * entry = NULL;
|
|
||||||
for(size_t i = 0; i < filesystem->size; i++)
|
|
||||||
{
|
|
||||||
struct wfp_static_filesystem_entry * current = &filesystem->entries[i];
|
|
||||||
if ((parent == current->parent) && (0 == strcmp(name, current->name)))
|
|
||||||
{
|
|
||||||
entry = current;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return entry;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct wfp_static_filesystem_entry *
|
|
||||||
wfp_static_filesystem_add_entry(
|
|
||||||
struct wfp_static_filesystem * filesystem)
|
|
||||||
{
|
|
||||||
struct wfp_static_filesystem_entry * entry = NULL;
|
|
||||||
|
|
||||||
if (filesystem->size >= filesystem->capacity)
|
|
||||||
{
|
|
||||||
struct wfp_static_filesystem_entry * entries;
|
|
||||||
|
|
||||||
size_t new_capacity = 2 * filesystem->capacity;
|
|
||||||
size_t new_size = new_capacity * sizeof(struct wfp_static_filesystem_entry);
|
|
||||||
entries = realloc(filesystem->entries, new_size);
|
|
||||||
|
|
||||||
if (NULL != entries)
|
|
||||||
{
|
|
||||||
filesystem->entries = entries;
|
|
||||||
filesystem->capacity = new_capacity;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (filesystem->size < filesystem->capacity)
|
|
||||||
{
|
|
||||||
entry = &filesystem->entries[filesystem->size];
|
|
||||||
entry->inode = filesystem->size + 1;
|
|
||||||
filesystem->size++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return entry;
|
|
||||||
}
|
|
||||||
|
|
||||||
static size_t
|
|
||||||
wfp_static_filesystem_entry_read(
|
|
||||||
size_t offset,
|
|
||||||
char * buffer,
|
|
||||||
size_t buffer_size,
|
|
||||||
void * user_data)
|
|
||||||
{
|
|
||||||
size_t result = 0;
|
|
||||||
struct wfp_static_filesystem_entry * entry = user_data;
|
|
||||||
if (offset < entry->size)
|
|
||||||
{
|
|
||||||
size_t remaining = (entry->size - offset);
|
|
||||||
result = (buffer_size < remaining) ? buffer_size : remaining;
|
|
||||||
memcpy(buffer, entry->content, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
wfp_static_filesystem_entry_get_info(
|
|
||||||
void * user_data,
|
|
||||||
int * result_mode,
|
|
||||||
size_t * result_size)
|
|
||||||
{
|
|
||||||
struct wfp_static_filesystem_entry * entry = user_data;
|
|
||||||
*result_mode = entry->mode;
|
|
||||||
*result_size = entry->size;
|
|
||||||
}
|
|
||||||
|
|
||||||
static size_t
|
|
||||||
wfp_static_filesystem_add_dir(
|
|
||||||
struct wfp_static_filesystem * filesystem,
|
|
||||||
size_t parent,
|
|
||||||
char const * name
|
|
||||||
)
|
|
||||||
{
|
|
||||||
struct wfp_static_filesystem_entry * entry = wfp_static_filesystem_get_entry_by_name(filesystem, parent, name);
|
|
||||||
if (NULL == entry)
|
|
||||||
{
|
|
||||||
entry = wfp_static_filesystem_add_entry(filesystem);
|
|
||||||
entry->parent = parent;
|
|
||||||
entry->is_file = false;
|
|
||||||
entry->mode = 0555;
|
|
||||||
entry->name = strdup(name);
|
|
||||||
entry->user_data = entry;
|
|
||||||
entry->read = &wfp_static_filesystem_entry_read;
|
|
||||||
entry->get_info = &wfp_static_filesystem_entry_get_info;
|
|
||||||
entry->size = 0;
|
|
||||||
entry->content = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return entry->inode;
|
|
||||||
}
|
|
||||||
|
|
||||||
static size_t
|
|
||||||
wfp_static_filesystem_make_parent(
|
|
||||||
struct wfp_static_filesystem * filesystem,
|
|
||||||
struct wfp_path * path)
|
|
||||||
{
|
|
||||||
size_t result = WFP_STATIC_FILSYSTEM_INODE_ROOT;
|
|
||||||
|
|
||||||
size_t count = wfp_path_element_count(path);
|
|
||||||
if (0 < count)
|
|
||||||
{
|
|
||||||
for(size_t i = 0; i < (count - 1); i++)
|
|
||||||
{
|
|
||||||
char const * name = wfp_path_get_element(path, i);
|
|
||||||
result = wfp_static_filesystem_add_dir(filesystem, result, name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
wfp_static_filesystem_stat(
|
|
||||||
struct wfp_static_filesystem_entry * entry,
|
|
||||||
struct stat * stat
|
|
||||||
)
|
|
||||||
{
|
|
||||||
memset(stat, 0, sizeof(struct stat));
|
|
||||||
|
|
||||||
int mode;
|
|
||||||
size_t size;
|
|
||||||
entry->get_info(entry->user_data, &mode, &size);
|
|
||||||
|
|
||||||
stat->st_ino = entry->inode;
|
|
||||||
stat->st_size = entry->size;
|
|
||||||
stat->st_mode = entry->mode & 0777;
|
|
||||||
stat->st_mode |= (entry->is_file) ? S_IFREG: S_IFDIR;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void wfp_static_filesystem_lookup(
|
|
||||||
struct wfp_request * request,
|
|
||||||
ino_t parent,
|
|
||||||
char const * name,
|
|
||||||
void * user_data)
|
|
||||||
{
|
|
||||||
struct wfp_static_filesystem * filesystem = user_data;
|
|
||||||
struct wfp_static_filesystem_entry * entry = wfp_static_filesystem_get_entry_by_name(filesystem, parent, name);
|
|
||||||
|
|
||||||
if (NULL != entry)
|
|
||||||
{
|
|
||||||
struct stat stat;
|
|
||||||
wfp_static_filesystem_stat(entry, &stat);
|
|
||||||
wfp_respond_lookup(request, &stat);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
wfp_respond_error(request, WFP_BAD_NOENTRY);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void wfp_static_filesystem_getattr(
|
|
||||||
struct wfp_request * request,
|
|
||||||
ino_t inode,
|
|
||||||
void * user_data)
|
|
||||||
{
|
|
||||||
struct wfp_static_filesystem * filesystem = user_data;
|
|
||||||
struct wfp_static_filesystem_entry * entry = wfp_static_filesystem_get_entry(filesystem, inode);
|
|
||||||
|
|
||||||
if (NULL != entry)
|
|
||||||
{
|
|
||||||
struct stat stat;
|
|
||||||
wfp_static_filesystem_stat(entry, &stat);
|
|
||||||
wfp_respond_getattr(request, &stat);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
wfp_respond_error(request, WFP_BAD_NOENTRY);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void wfp_static_filesystem_readdir(
|
|
||||||
struct wfp_request * request,
|
|
||||||
ino_t directory,
|
|
||||||
void * user_data)
|
|
||||||
{
|
|
||||||
struct wfp_static_filesystem * filesystem = user_data;
|
|
||||||
struct wfp_static_filesystem_entry * dir = wfp_static_filesystem_get_entry(filesystem, directory);
|
|
||||||
|
|
||||||
if ((NULL != dir) && (!dir->is_file))
|
|
||||||
{
|
|
||||||
struct wfp_dirbuffer * buffer = wfp_dirbuffer_create();
|
|
||||||
wfp_dirbuffer_add(buffer, ".", dir->inode);
|
|
||||||
wfp_dirbuffer_add(buffer, "..", dir->inode);
|
|
||||||
|
|
||||||
for(size_t i = 0; i < filesystem->size; i++)
|
|
||||||
{
|
|
||||||
struct wfp_static_filesystem_entry const * entry = &filesystem->entries[i];
|
|
||||||
if (directory == entry->parent)
|
|
||||||
{
|
|
||||||
wfp_dirbuffer_add(buffer, entry->name, entry->inode);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
wfp_respond_readdir(request, buffer);
|
|
||||||
wfp_dirbuffer_dispose(buffer);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
wfp_respond_error(request, WFP_BAD_NOENTRY);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void wfp_static_filesystem_open(
|
|
||||||
struct wfp_request * request,
|
|
||||||
ino_t inode,
|
|
||||||
int flags,
|
|
||||||
void * user_data)
|
|
||||||
{
|
|
||||||
struct wfp_static_filesystem * filesystem = user_data;
|
|
||||||
struct wfp_static_filesystem_entry * entry = wfp_static_filesystem_get_entry(filesystem, inode);
|
|
||||||
|
|
||||||
if ((NULL != entry) && (entry->is_file))
|
|
||||||
{
|
|
||||||
if (O_RDONLY == (flags & O_ACCMODE))
|
|
||||||
{
|
|
||||||
wfp_respond_open(request, 0U);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
wfp_respond_error(request, WFP_BAD_ACCESS_DENIED);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
wfp_respond_error(request, WFP_BAD_NOENTRY);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void wfp_static_filesystem_read(
|
|
||||||
struct wfp_request * request,
|
|
||||||
ino_t inode,
|
|
||||||
uint32_t WFP_UNUSED_PARAM(handle),
|
|
||||||
size_t offset,
|
|
||||||
size_t length,
|
|
||||||
void * user_data)
|
|
||||||
{
|
|
||||||
struct wfp_static_filesystem * filesystem = user_data;
|
|
||||||
struct wfp_static_filesystem_entry * entry = wfp_static_filesystem_get_entry(filesystem, inode);
|
|
||||||
|
|
||||||
if ((NULL != entry) && (entry->is_file))
|
|
||||||
{
|
|
||||||
char buffer[WFP_STATIC_FILESYSTEM_MAX_READ_SIZE];
|
|
||||||
size_t max_size = (length < WFP_STATIC_FILESYSTEM_MAX_READ_SIZE) ? length : WFP_STATIC_FILESYSTEM_MAX_READ_SIZE;
|
|
||||||
|
|
||||||
size_t count = entry->read(offset, buffer, max_size, entry->user_data);
|
|
||||||
wfp_respond_read(request, buffer, count);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
wfp_respond_error(request, WFP_BAD_NOENTRY);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
struct wfp_static_filesystem *
|
|
||||||
wfp_static_filesystem_create(
|
|
||||||
struct wfp_client_config * config)
|
|
||||||
{
|
|
||||||
(void) config;
|
|
||||||
|
|
||||||
struct wfp_static_filesystem * filesystem = malloc(sizeof(struct wfp_static_filesystem));
|
|
||||||
filesystem->entries = malloc(sizeof(struct wfp_static_filesystem_entry) * WFP_STATIC_FILESYSTEM_DEFAULT_CAPACITY);
|
|
||||||
filesystem->size = 0;
|
|
||||||
filesystem->capacity = WFP_STATIC_FILESYSTEM_DEFAULT_CAPACITY;
|
|
||||||
filesystem->user_data = NULL;
|
|
||||||
|
|
||||||
wfp_static_filesystem_add_dir(filesystem, 0, "<root>");
|
|
||||||
|
|
||||||
wfp_client_config_set_userdata(config, filesystem);
|
|
||||||
wfp_client_config_set_onlookup(config, &wfp_static_filesystem_lookup);
|
|
||||||
wfp_client_config_set_ongetattr(config, &wfp_static_filesystem_getattr);
|
|
||||||
wfp_client_config_set_onreaddir(config, &wfp_static_filesystem_readdir);
|
|
||||||
wfp_client_config_set_onopen(config, &wfp_static_filesystem_open);
|
|
||||||
wfp_client_config_set_onread(config, &wfp_static_filesystem_read);
|
|
||||||
|
|
||||||
return filesystem;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
wfp_static_filesystem_dispose(
|
|
||||||
struct wfp_static_filesystem * filesystem)
|
|
||||||
{
|
|
||||||
for(size_t i = 0; i < filesystem->size; i++)
|
|
||||||
{
|
|
||||||
struct wfp_static_filesystem_entry * entry = &filesystem->entries[i];
|
|
||||||
free(entry->name);
|
|
||||||
free(entry->content);
|
|
||||||
}
|
|
||||||
|
|
||||||
free(filesystem->entries);
|
|
||||||
free(filesystem);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
wfp_static_filesystem_add(
|
|
||||||
struct wfp_static_filesystem * filesystem,
|
|
||||||
char const * path,
|
|
||||||
int mode,
|
|
||||||
char const * content,
|
|
||||||
size_t length)
|
|
||||||
{
|
|
||||||
struct wfp_path * path_ = wfp_path_create(path);
|
|
||||||
if (NULL != path_)
|
|
||||||
{
|
|
||||||
size_t parent = wfp_static_filesystem_make_parent(filesystem, path_);
|
|
||||||
struct wfp_static_filesystem_entry * entry = wfp_static_filesystem_add_entry(filesystem);
|
|
||||||
entry->parent = parent;
|
|
||||||
entry->is_file = true;
|
|
||||||
entry->name = strdup(wfp_path_get_filename(path_));
|
|
||||||
entry->mode = mode;
|
|
||||||
entry->size = length;
|
|
||||||
entry->get_info = &wfp_static_filesystem_entry_get_info;
|
|
||||||
entry->read = &wfp_static_filesystem_entry_read;
|
|
||||||
entry->user_data = entry;
|
|
||||||
|
|
||||||
entry->content = malloc(length);
|
|
||||||
memcpy(entry->content, content, length);
|
|
||||||
|
|
||||||
wfp_path_dispose(path_);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
wfp_static_filesystem_add_text(
|
|
||||||
struct wfp_static_filesystem * filesystem,
|
|
||||||
char const * path,
|
|
||||||
int mode,
|
|
||||||
char const * content)
|
|
||||||
{
|
|
||||||
size_t length = strlen(content);
|
|
||||||
wfp_static_filesystem_add(filesystem, path, mode, content, length);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
wfp_static_filesystem_set_user_data(
|
|
||||||
struct wfp_static_filesystem * filesystem,
|
|
||||||
void * user_data)
|
|
||||||
{
|
|
||||||
filesystem->user_data = user_data;
|
|
||||||
}
|
|
||||||
|
|
||||||
void *
|
|
||||||
wfp_static_filesystem_get_user_data(
|
|
||||||
struct wfp_static_filesystem * filesystem)
|
|
||||||
{
|
|
||||||
return filesystem->user_data;
|
|
||||||
}
|
|
@ -1,72 +0,0 @@
|
|||||||
#ifndef WFP_STATIC_FILESYSTEM_H
|
|
||||||
#define WFP_STATIC_FILESYSTEM_H
|
|
||||||
|
|
||||||
#ifndef __cplusplus
|
|
||||||
#include <stddef.h>
|
|
||||||
#else
|
|
||||||
#include <cstddef>
|
|
||||||
using ::std::size_t;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <webfuse_provider/api.h>
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C"
|
|
||||||
{
|
|
||||||
#endif
|
|
||||||
|
|
||||||
struct wfp_client_config;
|
|
||||||
|
|
||||||
struct wfp_static_filesystem;
|
|
||||||
|
|
||||||
typedef size_t
|
|
||||||
wfp_static_filesystem_read_fn(
|
|
||||||
size_t offset,
|
|
||||||
char * buffer,
|
|
||||||
size_t buffer_size,
|
|
||||||
void * user_data);
|
|
||||||
|
|
||||||
typedef void
|
|
||||||
wfp_static_filesystem_get_info_fn(
|
|
||||||
void * user_data,
|
|
||||||
int * result_mode,
|
|
||||||
size_t * result_size);
|
|
||||||
|
|
||||||
|
|
||||||
extern WFP_API struct wfp_static_filesystem *
|
|
||||||
wfp_static_filesystem_create(
|
|
||||||
struct wfp_client_config * config);
|
|
||||||
|
|
||||||
extern WFP_API void
|
|
||||||
wfp_static_filesystem_dispose(
|
|
||||||
struct wfp_static_filesystem * filesystem);
|
|
||||||
|
|
||||||
extern WFP_API void
|
|
||||||
wfp_static_filesystem_add(
|
|
||||||
struct wfp_static_filesystem * filesystem,
|
|
||||||
char const * path,
|
|
||||||
int mode,
|
|
||||||
char const * content,
|
|
||||||
size_t length);
|
|
||||||
|
|
||||||
extern WFP_API void
|
|
||||||
wfp_static_filesystem_add_text(
|
|
||||||
struct wfp_static_filesystem * filesystem,
|
|
||||||
char const * path,
|
|
||||||
int mode,
|
|
||||||
char const * content);
|
|
||||||
|
|
||||||
extern void
|
|
||||||
wfp_static_filesystem_set_user_data(
|
|
||||||
struct wfp_static_filesystem * filesystem,
|
|
||||||
void * user_data);
|
|
||||||
|
|
||||||
extern void *
|
|
||||||
wfp_static_filesystem_get_user_data(
|
|
||||||
struct wfp_static_filesystem * filesystem);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,331 +0,0 @@
|
|||||||
#include "webfuse_provider/utils/ws_server2.hpp"
|
|
||||||
#include "webfuse_provider/impl/lws_log.h"
|
|
||||||
|
|
||||||
#include <libwebsockets.h>
|
|
||||||
#include <thread>
|
|
||||||
#include <mutex>
|
|
||||||
#include <chrono>
|
|
||||||
#include <sstream>
|
|
||||||
#include <queue>
|
|
||||||
|
|
||||||
namespace
|
|
||||||
{
|
|
||||||
|
|
||||||
class IServer
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
virtual ~IServer() = default;
|
|
||||||
virtual void OnConnected(lws * wsi) = 0;
|
|
||||||
virtual void OnConnectionClosed(lws * wsi) = 0;
|
|
||||||
virtual void OnMessageReceived(struct lws * wsi, char const * data, size_t length) = 0;
|
|
||||||
virtual void OnWritable(struct lws * wsi) = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C"
|
|
||||||
{
|
|
||||||
|
|
||||||
static int wfp_test_utils_ws_server_callback(
|
|
||||||
struct lws * wsi,
|
|
||||||
enum lws_callback_reasons reason,
|
|
||||||
void * user,
|
|
||||||
void * in,
|
|
||||||
size_t len)
|
|
||||||
{
|
|
||||||
int result = 0;
|
|
||||||
struct lws_protocols const * ws_protocol = lws_get_protocol(wsi);
|
|
||||||
auto * server = reinterpret_cast<IServer*>(nullptr != ws_protocol ? ws_protocol->user : nullptr);
|
|
||||||
|
|
||||||
if (nullptr != server)
|
|
||||||
{
|
|
||||||
switch (reason)
|
|
||||||
{
|
|
||||||
case LWS_CALLBACK_ESTABLISHED:
|
|
||||||
server->OnConnected(wsi);
|
|
||||||
break;
|
|
||||||
case LWS_CALLBACK_CLOSED:
|
|
||||||
server->OnConnectionClosed(wsi);
|
|
||||||
break;
|
|
||||||
case LWS_CALLBACK_RECEIVE:
|
|
||||||
{
|
|
||||||
auto * data = reinterpret_cast<char const *>(in);
|
|
||||||
server->OnMessageReceived(wsi, data, len);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case LWS_CALLBACK_SERVER_WRITEABLE:
|
|
||||||
server->OnWritable(wsi);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
namespace webfuse_test
|
|
||||||
{
|
|
||||||
|
|
||||||
class WsServer2::Private : public IServer
|
|
||||||
{
|
|
||||||
Private(Private const &) = delete;
|
|
||||||
Private & operator=(Private const &) = delete;
|
|
||||||
public:
|
|
||||||
Private(IIvokationHandler & handler, std::string const & protocol, int port, bool enable_tls);
|
|
||||||
~Private();
|
|
||||||
bool IsConnected();
|
|
||||||
std::string const & GetUrl() const;
|
|
||||||
void OnConnected(lws * wsi) override;
|
|
||||||
void OnConnectionClosed(lws * wsi) override;
|
|
||||||
void OnMessageReceived(struct lws * wsi, char const * data, size_t length) override;
|
|
||||||
void OnWritable(struct lws * wsi) override;
|
|
||||||
|
|
||||||
void SendMessage(char const * message);
|
|
||||||
void SendMessage(json_t * message);
|
|
||||||
private:
|
|
||||||
static void Run(Private * self);
|
|
||||||
|
|
||||||
IIvokationHandler & handler_;
|
|
||||||
std::string protocol_;
|
|
||||||
bool is_connected;
|
|
||||||
bool is_shutdown_requested;
|
|
||||||
lws * wsi_;
|
|
||||||
lws_context * ws_context;
|
|
||||||
lws_protocols ws_protocols[2];
|
|
||||||
lws_context_creation_info info;
|
|
||||||
std::string url;
|
|
||||||
std::thread context;
|
|
||||||
std::mutex mutex;
|
|
||||||
std::queue<std::string> writeQueue;
|
|
||||||
};
|
|
||||||
|
|
||||||
WsServer2::WsServer2(
|
|
||||||
IIvokationHandler& handler,
|
|
||||||
std::string const & protocol,
|
|
||||||
int port,
|
|
||||||
bool enable_tls)
|
|
||||||
: d(new WsServer2::Private(handler, protocol, port, enable_tls))
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
WsServer2::~WsServer2()
|
|
||||||
{
|
|
||||||
delete d;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool WsServer2::IsConnected()
|
|
||||||
{
|
|
||||||
return d->IsConnected();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string const & WsServer2::GetUrl() const
|
|
||||||
{
|
|
||||||
return d->GetUrl();
|
|
||||||
}
|
|
||||||
|
|
||||||
void WsServer2::SendMessage(char const * message)
|
|
||||||
{
|
|
||||||
d->SendMessage(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
void WsServer2::SendMessage(json_t * message)
|
|
||||||
{
|
|
||||||
d->SendMessage(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
WsServer2::Private::Private(
|
|
||||||
IIvokationHandler & handler,
|
|
||||||
std::string const & protocol,
|
|
||||||
int port,
|
|
||||||
bool enable_tls)
|
|
||||||
: handler_(handler)
|
|
||||||
, protocol_(protocol)
|
|
||||||
, is_connected(false)
|
|
||||||
, is_shutdown_requested(false)
|
|
||||||
, wsi_(nullptr)
|
|
||||||
{
|
|
||||||
wfp_impl_lwslog_disable();
|
|
||||||
IServer * server = this;
|
|
||||||
memset(ws_protocols, 0, sizeof(struct lws_protocols) * 2 );
|
|
||||||
|
|
||||||
ws_protocols[0].name = protocol_.c_str();
|
|
||||||
ws_protocols[0].callback = &wfp_test_utils_ws_server_callback;
|
|
||||||
ws_protocols[0].per_session_data_size = 0;
|
|
||||||
ws_protocols[0].user = reinterpret_cast<void*>(server);
|
|
||||||
|
|
||||||
memset(&info, 0, sizeof(struct lws_context_creation_info));
|
|
||||||
info.port = port;
|
|
||||||
info.mounts = NULL;
|
|
||||||
info.protocols =ws_protocols;
|
|
||||||
info.vhost_name = "localhost";
|
|
||||||
info.ws_ping_pong_interval = 10;
|
|
||||||
info.options = LWS_SERVER_OPTION_HTTP_HEADERS_SECURITY_BEST_PRACTICES_ENFORCE;
|
|
||||||
info.options |= LWS_SERVER_OPTION_EXPLICIT_VHOSTS;
|
|
||||||
|
|
||||||
if (enable_tls)
|
|
||||||
{
|
|
||||||
info.options |= LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
|
|
||||||
info.ssl_cert_filepath = "server-cert.pem";
|
|
||||||
info.ssl_private_key_filepath = "server-key.pem";
|
|
||||||
}
|
|
||||||
|
|
||||||
ws_context = lws_create_context(&info);
|
|
||||||
|
|
||||||
std::ostringstream stream;
|
|
||||||
struct lws_vhost * vhost = lws_create_vhost(ws_context, &info);
|
|
||||||
stream << (enable_tls ? "wss://" : "ws://")
|
|
||||||
<< "localhost:" << lws_get_vhost_port(vhost) << "/";
|
|
||||||
url = stream.str();
|
|
||||||
|
|
||||||
context = std::thread(&Run, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
WsServer2::Private::~Private()
|
|
||||||
{
|
|
||||||
{
|
|
||||||
std::unique_lock<std::mutex> lock(mutex);
|
|
||||||
is_shutdown_requested = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
lws_cancel_service(ws_context);
|
|
||||||
context.join();
|
|
||||||
lws_context_destroy(ws_context);
|
|
||||||
}
|
|
||||||
|
|
||||||
void WsServer2::Private::Run(Private * self)
|
|
||||||
{
|
|
||||||
bool is_running = true;
|
|
||||||
while (is_running)
|
|
||||||
{
|
|
||||||
lws_service(self->ws_context, 0);
|
|
||||||
{
|
|
||||||
std::unique_lock<std::mutex> lock(self->mutex);
|
|
||||||
is_running = !self->is_shutdown_requested;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool WsServer2::Private::IsConnected()
|
|
||||||
{
|
|
||||||
std::unique_lock<std::mutex> lock(mutex);
|
|
||||||
return is_connected;
|
|
||||||
}
|
|
||||||
|
|
||||||
void WsServer2::Private::OnConnected(lws * wsi)
|
|
||||||
{
|
|
||||||
std::unique_lock<std::mutex> lock(mutex);
|
|
||||||
is_connected = true;
|
|
||||||
wsi_ = wsi;
|
|
||||||
}
|
|
||||||
|
|
||||||
void WsServer2::Private::OnConnectionClosed(lws * wsi)
|
|
||||||
{
|
|
||||||
std::unique_lock<std::mutex> lock(mutex);
|
|
||||||
if (wsi == wsi_)
|
|
||||||
{
|
|
||||||
is_connected = false;
|
|
||||||
wsi_ = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void WsServer2::Private::OnWritable(struct lws * wsi)
|
|
||||||
{
|
|
||||||
bool notify = false;
|
|
||||||
|
|
||||||
{
|
|
||||||
std::unique_lock<std::mutex> lock(mutex);
|
|
||||||
|
|
||||||
if (!writeQueue.empty())
|
|
||||||
{
|
|
||||||
std::string const & message = writeQueue.front();
|
|
||||||
|
|
||||||
unsigned char * data = new unsigned char[LWS_PRE + message.size()];
|
|
||||||
memcpy(&data[LWS_PRE], message.c_str(), message.size());
|
|
||||||
lws_write(wsi, &data[LWS_PRE], message.size(), LWS_WRITE_TEXT);
|
|
||||||
delete[] data;
|
|
||||||
|
|
||||||
writeQueue.pop();
|
|
||||||
notify = !writeQueue.empty();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (notify)
|
|
||||||
{
|
|
||||||
lws_callback_on_writable(wsi);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void WsServer2::Private::SendMessage(char const * message)
|
|
||||||
{
|
|
||||||
lws * wsi = nullptr;
|
|
||||||
|
|
||||||
{
|
|
||||||
std::unique_lock<std::mutex> lock(mutex);
|
|
||||||
|
|
||||||
if (nullptr != wsi_)
|
|
||||||
{
|
|
||||||
writeQueue.push(message);
|
|
||||||
wsi = wsi_;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nullptr != wsi)
|
|
||||||
{
|
|
||||||
lws_callback_on_writable(wsi_);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void WsServer2::Private::SendMessage(json_t * message)
|
|
||||||
{
|
|
||||||
char* message_text = json_dumps(message, JSON_COMPACT);
|
|
||||||
SendMessage(message_text);
|
|
||||||
json_decref(message);
|
|
||||||
free(message_text);
|
|
||||||
}
|
|
||||||
|
|
||||||
void WsServer2::Private::OnMessageReceived(struct lws * wsi, char const * data, size_t length)
|
|
||||||
{
|
|
||||||
(void) wsi;
|
|
||||||
|
|
||||||
json_t * request = json_loadb(data, length, JSON_DECODE_ANY, nullptr);
|
|
||||||
json_t * method = json_object_get(request, "method");
|
|
||||||
json_t * params = json_object_get(request, "params");
|
|
||||||
json_t * id = json_object_get(request, "id");
|
|
||||||
|
|
||||||
if (json_is_string(method) && json_is_array(params) && json_is_integer(id))
|
|
||||||
{
|
|
||||||
json_t * response = json_object();
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
std::string result_text = handler_.Invoke(json_string_value(method), params);
|
|
||||||
json_t * result = json_loads(result_text.c_str(), JSON_DECODE_ANY, nullptr);
|
|
||||||
json_object_set_new(response, "result", result);
|
|
||||||
}
|
|
||||||
catch (...)
|
|
||||||
{
|
|
||||||
json_t * error = json_object();
|
|
||||||
json_object_set_new(error, "code", json_integer(1));
|
|
||||||
json_object_set_new(response, "error", error);
|
|
||||||
}
|
|
||||||
|
|
||||||
json_object_set(response, "id", id);
|
|
||||||
SendMessage(response);
|
|
||||||
}
|
|
||||||
|
|
||||||
json_decref(request);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string const & WsServer2::Private::GetUrl() const
|
|
||||||
{
|
|
||||||
return url;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
@ -1,39 +0,0 @@
|
|||||||
#ifndef WFP_TEST_UTILS_WS_SERVER2_HPP
|
|
||||||
#define WFP_TEST_UTILS_WS_SERVER2_HPP
|
|
||||||
|
|
||||||
#include <jansson.h>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
namespace webfuse_test
|
|
||||||
{
|
|
||||||
|
|
||||||
class IIvokationHandler
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
virtual ~IIvokationHandler() = default;
|
|
||||||
virtual std::string Invoke(char const * method, json_t * params) = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
class WsServer2
|
|
||||||
{
|
|
||||||
WsServer2(WsServer2 const &) = delete;
|
|
||||||
WsServer2 & operator=(WsServer2 const & ) = delete;
|
|
||||||
public:
|
|
||||||
WsServer2(
|
|
||||||
IIvokationHandler& handler,
|
|
||||||
std::string const & protocol,
|
|
||||||
int port = 0,
|
|
||||||
bool enable_tls = false);
|
|
||||||
virtual ~WsServer2();
|
|
||||||
bool IsConnected();
|
|
||||||
std::string const & GetUrl() const;
|
|
||||||
void SendMessage(char const * message);
|
|
||||||
void SendMessage(json_t * message);
|
|
||||||
private:
|
|
||||||
class Private;
|
|
||||||
Private * d;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
Loading…
Reference in New Issue
Block a user