Compare commits
	
		
			27 Commits
		
	
	
		
			v5.0.7
			...
			user/bserg
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					cbf0b826d0 | ||
| 
						 | 
					747b4495b0 | ||
| 
						 | 
					f0b955efd2 | ||
| 
						 | 
					0c689bc382 | ||
| 
						 | 
					6bcbaea293 | ||
| 
						 | 
					0ef9e81435 | ||
| 
						 | 
					6f9e7ad245 | ||
| 
						 | 
					c1ef3f4e1d | ||
| 
						 | 
					720f57da27 | ||
| 
						 | 
					e29c0ce654 | ||
| 
						 | 
					e50974dc4b | ||
| 
						 | 
					0d83ffdf6e | ||
| 
						 | 
					c0a80264d1 | ||
| 
						 | 
					72b3ebf69e | ||
| 
						 | 
					e17309f030 | ||
| 
						 | 
					e9f4e9647e | ||
| 
						 | 
					0187735998 | ||
| 
						 | 
					d2fa1da30b | ||
| 
						 | 
					00dc631f2b | ||
| 
						 | 
					40069b50a2 | ||
| 
						 | 
					33f50e809a | ||
| 
						 | 
					9d61084e7b | ||
| 
						 | 
					1f6b497015 | ||
| 
						 | 
					afb1626ceb | ||
| 
						 | 
					c07ca74186 | ||
| 
						 | 
					4e6a57dc07 | ||
| 
						 | 
					d93f723e68 | 
@@ -1 +1 @@
 | 
			
		||||
docker/Dockerfile.fedora
 | 
			
		||||
docker/Dockerfile.ubuntu_xenial
 | 
			
		||||
@@ -221,13 +221,15 @@ namespace ix
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool WebSocket::isConnectedOrClosing() const
 | 
			
		||||
 | 
			
		||||
    {
 | 
			
		||||
        return isConnected() || isClosing();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void WebSocket::close()
 | 
			
		||||
    void WebSocket::close(uint16_t code,
 | 
			
		||||
                          const std::string& reason)
 | 
			
		||||
    {
 | 
			
		||||
        _ws.close();
 | 
			
		||||
        _ws.close(code, reason);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void WebSocket::reconnectPerpetuallyIfDisconnected()
 | 
			
		||||
 
 | 
			
		||||
@@ -111,7 +111,11 @@ namespace ix
 | 
			
		||||
        WebSocketSendInfo sendText(const std::string& text,
 | 
			
		||||
                                   const OnProgressCallback& onProgressCallback = nullptr);
 | 
			
		||||
        WebSocketSendInfo ping(const std::string& text);
 | 
			
		||||
        void close();
 | 
			
		||||
 | 
			
		||||
        // A close frame can provide a code and a reason
 | 
			
		||||
        // FIXME: use constants
 | 
			
		||||
        void close(uint16_t code = 1000,
 | 
			
		||||
                   const std::string& reason = "Normal closure");
 | 
			
		||||
 | 
			
		||||
        void setOnMessageCallback(const OnMessageCallback& callback);
 | 
			
		||||
        static void setTrafficTrackerCallback(const OnTrafficTrackerCallback& callback);
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										407
									
								
								test/IXWebSocketCloseTest.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										407
									
								
								test/IXWebSocketCloseTest.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,407 @@
 | 
			
		||||
/*
 | 
			
		||||
 *  IXWebSocketCloseTest.cpp
 | 
			
		||||
 *  Author: Alexandre Konieczny
 | 
			
		||||
 *  Copyright (c) 2019 Machine Zone. All rights reserved.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <iostream>
 | 
			
		||||
#include <sstream>
 | 
			
		||||
#include <queue>
 | 
			
		||||
#include <ixwebsocket/IXWebSocket.h>
 | 
			
		||||
#include <ixwebsocket/IXWebSocketServer.h>
 | 
			
		||||
 | 
			
		||||
#include "IXTest.h"
 | 
			
		||||
 | 
			
		||||
#include "catch.hpp"
 | 
			
		||||
 | 
			
		||||
using namespace ix;
 | 
			
		||||
 | 
			
		||||
namespace
 | 
			
		||||
{
 | 
			
		||||
    class WebSocketClient
 | 
			
		||||
    {
 | 
			
		||||
        public:
 | 
			
		||||
            WebSocketClient(int port);
 | 
			
		||||
 | 
			
		||||
            void subscribe(const std::string& channel);
 | 
			
		||||
            void start();
 | 
			
		||||
            void stop();
 | 
			
		||||
            void stop(uint16_t code, const std::string& reason);
 | 
			
		||||
            bool isReady() const;
 | 
			
		||||
            void sendMessage(const std::string& text);
 | 
			
		||||
 | 
			
		||||
            uint16_t getCloseCode();
 | 
			
		||||
            const std::string& getCloseReason();
 | 
			
		||||
            bool getCloseRemote();
 | 
			
		||||
 | 
			
		||||
        private:
 | 
			
		||||
            ix::WebSocket _webSocket;
 | 
			
		||||
            int _port;
 | 
			
		||||
 | 
			
		||||
            mutable std::mutex _mutexCloseData;
 | 
			
		||||
            uint16_t _closeCode;
 | 
			
		||||
            std::string _closeReason;
 | 
			
		||||
            bool _closeRemote;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    WebSocketClient::WebSocketClient(int port)
 | 
			
		||||
        : _port(port)
 | 
			
		||||
        , _closeCode(0)
 | 
			
		||||
        , _closeReason(std::string(""))
 | 
			
		||||
        , _closeRemote(false)
 | 
			
		||||
    {
 | 
			
		||||
        ;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool WebSocketClient::isReady() const
 | 
			
		||||
    {
 | 
			
		||||
        return _webSocket.getReadyState() == ix::WebSocket_ReadyState_Open;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    uint16_t WebSocketClient::getCloseCode()
 | 
			
		||||
    {
 | 
			
		||||
        std::lock_guard<std::mutex> lck(_mutexCloseData);
 | 
			
		||||
        
 | 
			
		||||
        return _closeCode;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const std::string& WebSocketClient::getCloseReason()
 | 
			
		||||
    {
 | 
			
		||||
        std::lock_guard<std::mutex> lck(_mutexCloseData);
 | 
			
		||||
 | 
			
		||||
        return _closeReason;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool WebSocketClient::getCloseRemote()
 | 
			
		||||
    {
 | 
			
		||||
        std::lock_guard<std::mutex> lck(_mutexCloseData);
 | 
			
		||||
        
 | 
			
		||||
        return _closeRemote;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void WebSocketClient::stop()
 | 
			
		||||
    {
 | 
			
		||||
        _webSocket.stop();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void WebSocketClient::stop(uint16_t code, const std::string& reason)
 | 
			
		||||
    {
 | 
			
		||||
        _webSocket.close(code, reason);
 | 
			
		||||
        _webSocket.stop();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void WebSocketClient::start()
 | 
			
		||||
    {
 | 
			
		||||
        std::string url;
 | 
			
		||||
        {
 | 
			
		||||
            std::stringstream ss;
 | 
			
		||||
            ss << "ws://localhost:"
 | 
			
		||||
               << _port
 | 
			
		||||
               << "/";
 | 
			
		||||
 | 
			
		||||
            url = ss.str();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        _webSocket.setUrl(url);
 | 
			
		||||
 | 
			
		||||
        std::stringstream ss;
 | 
			
		||||
        log(std::string("Connecting to url: ") + url);
 | 
			
		||||
 | 
			
		||||
        _webSocket.setOnMessageCallback(
 | 
			
		||||
            [this](ix::WebSocketMessageType messageType,
 | 
			
		||||
               const std::string& str,
 | 
			
		||||
               size_t wireSize,
 | 
			
		||||
               const ix::WebSocketErrorInfo& error,
 | 
			
		||||
               const ix::WebSocketOpenInfo& openInfo,
 | 
			
		||||
                   const ix::WebSocketCloseInfo& closeInfo)
 | 
			
		||||
            {
 | 
			
		||||
                std::stringstream ss;
 | 
			
		||||
                if (messageType == ix::WebSocket_MessageType_Open)
 | 
			
		||||
                {
 | 
			
		||||
                    log("client connected");
 | 
			
		||||
 | 
			
		||||
                    _webSocket.disableAutomaticReconnection();
 | 
			
		||||
                }
 | 
			
		||||
                else if (messageType == ix::WebSocket_MessageType_Close)
 | 
			
		||||
                {
 | 
			
		||||
                    log("client disconnected");
 | 
			
		||||
 | 
			
		||||
                    std::lock_guard<std::mutex> lck(_mutexCloseData);
 | 
			
		||||
                    
 | 
			
		||||
                    _closeCode = closeInfo.code;
 | 
			
		||||
                    _closeReason = std::string(closeInfo.reason);
 | 
			
		||||
                    _closeRemote = closeInfo.remote;
 | 
			
		||||
                    
 | 
			
		||||
                    _webSocket.disableAutomaticReconnection();
 | 
			
		||||
                }
 | 
			
		||||
                else if (messageType == ix::WebSocket_MessageType_Error)
 | 
			
		||||
                {
 | 
			
		||||
                    ss << "Error ! " << error.reason;
 | 
			
		||||
                    log(ss.str());
 | 
			
		||||
 | 
			
		||||
                    _webSocket.disableAutomaticReconnection();
 | 
			
		||||
                }
 | 
			
		||||
                else if (messageType == ix::WebSocket_MessageType_Pong)
 | 
			
		||||
                {
 | 
			
		||||
                    ss << "Received pong message " << str;
 | 
			
		||||
                    log(ss.str());
 | 
			
		||||
                }
 | 
			
		||||
                else if (messageType == ix::WebSocket_MessageType_Ping)
 | 
			
		||||
                {
 | 
			
		||||
                    ss << "Received ping message " << str;
 | 
			
		||||
                    log(ss.str());
 | 
			
		||||
                }
 | 
			
		||||
                else if (messageType == ix::WebSocket_MessageType_Message)
 | 
			
		||||
                {
 | 
			
		||||
                    ss << "Received message " << str;
 | 
			
		||||
                    log(ss.str());
 | 
			
		||||
                }
 | 
			
		||||
                else
 | 
			
		||||
                {
 | 
			
		||||
                    ss << "Invalid ix::WebSocketMessageType";
 | 
			
		||||
                    log(ss.str());
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
        _webSocket.start();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void WebSocketClient::sendMessage(const std::string& text)
 | 
			
		||||
    {
 | 
			
		||||
        _webSocket.send(text);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool startServer(ix::WebSocketServer& server,
 | 
			
		||||
                     uint16_t& receivedCloseCode,
 | 
			
		||||
                     std::string& receivedCloseReason,
 | 
			
		||||
                     bool& receivedCloseRemote,
 | 
			
		||||
                     std::mutex& mutexWrite)
 | 
			
		||||
    {
 | 
			
		||||
        // A dev/null server
 | 
			
		||||
        server.setOnConnectionCallback(
 | 
			
		||||
            [&server, &receivedCloseCode, &receivedCloseReason, &receivedCloseRemote, &mutexWrite](std::shared_ptr<ix::WebSocket> webSocket,
 | 
			
		||||
                                             std::shared_ptr<ConnectionState> connectionState)
 | 
			
		||||
            {
 | 
			
		||||
                webSocket->setOnMessageCallback(
 | 
			
		||||
                    [webSocket, connectionState, &server, &receivedCloseCode, &receivedCloseReason, &receivedCloseRemote, &mutexWrite](ix::WebSocketMessageType messageType,
 | 
			
		||||
                       const std::string& str,
 | 
			
		||||
                       size_t wireSize,
 | 
			
		||||
                       const ix::WebSocketErrorInfo& error,
 | 
			
		||||
                       const ix::WebSocketOpenInfo& openInfo,
 | 
			
		||||
                       const ix::WebSocketCloseInfo& closeInfo)
 | 
			
		||||
                    {
 | 
			
		||||
                        if (messageType == ix::WebSocket_MessageType_Open)
 | 
			
		||||
                        {
 | 
			
		||||
                            Logger() << "New server connection";
 | 
			
		||||
                            Logger() << "id: " << connectionState->getId();
 | 
			
		||||
                            Logger() << "Uri: " << openInfo.uri;
 | 
			
		||||
                            Logger() << "Headers:";
 | 
			
		||||
                            for (auto it : openInfo.headers)
 | 
			
		||||
                            {
 | 
			
		||||
                                Logger() << it.first << ": " << it.second;
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                        else if (messageType == ix::WebSocket_MessageType_Close)
 | 
			
		||||
                        {
 | 
			
		||||
                            log("Server closed connection");
 | 
			
		||||
 | 
			
		||||
                            //Logger() << closeInfo.code;
 | 
			
		||||
                            //Logger() << closeInfo.reason;
 | 
			
		||||
                            //Logger() << closeInfo.remote;
 | 
			
		||||
 | 
			
		||||
                            std::lock_guard<std::mutex> lck(mutexWrite);
 | 
			
		||||
                            
 | 
			
		||||
                            receivedCloseCode = closeInfo.code;
 | 
			
		||||
                            receivedCloseReason = std::string(closeInfo.reason);
 | 
			
		||||
                            receivedCloseRemote = closeInfo.remote;
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                );
 | 
			
		||||
            }
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        auto res = server.listen();
 | 
			
		||||
        if (!res.first)
 | 
			
		||||
        {
 | 
			
		||||
            log(res.second);
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        server.start();
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE("Websocket_client_close_default", "[close]")
 | 
			
		||||
{
 | 
			
		||||
    SECTION("Make sure that close code and reason was used and sent to server.")
 | 
			
		||||
    {
 | 
			
		||||
        ix::setupWebSocketTrafficTrackerCallback();
 | 
			
		||||
 | 
			
		||||
        int port = getFreePort();
 | 
			
		||||
        ix::WebSocketServer server(port);
 | 
			
		||||
        
 | 
			
		||||
        uint16_t serverReceivedCloseCode(0);
 | 
			
		||||
        bool serverReceivedCloseRemote(false);
 | 
			
		||||
        std::string serverReceivedCloseReason("");
 | 
			
		||||
        std::mutex mutexWrite;
 | 
			
		||||
 | 
			
		||||
        REQUIRE(startServer(server, serverReceivedCloseCode, serverReceivedCloseReason, serverReceivedCloseRemote, mutexWrite));
 | 
			
		||||
 | 
			
		||||
        std::string session = ix::generateSessionId();
 | 
			
		||||
        WebSocketClient webSocketClient(port);
 | 
			
		||||
 | 
			
		||||
        webSocketClient.start();
 | 
			
		||||
 | 
			
		||||
        // Wait for all chat instance to be ready
 | 
			
		||||
        while (true)
 | 
			
		||||
        {
 | 
			
		||||
            if (webSocketClient.isReady()) break;
 | 
			
		||||
            ix::msleep(10);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        REQUIRE(server.getClients().size() == 1);
 | 
			
		||||
 | 
			
		||||
        ix::msleep(100);
 | 
			
		||||
 | 
			
		||||
        webSocketClient.stop();
 | 
			
		||||
 | 
			
		||||
        ix::msleep(200);
 | 
			
		||||
 | 
			
		||||
        // ensure client close is the same as values given
 | 
			
		||||
        REQUIRE(webSocketClient.getCloseCode() == 1000);
 | 
			
		||||
        REQUIRE(webSocketClient.getCloseReason() == "Normal closure");
 | 
			
		||||
        REQUIRE(webSocketClient.getCloseRemote() == false);
 | 
			
		||||
 | 
			
		||||
        {
 | 
			
		||||
            std::lock_guard<std::mutex> lck(mutexWrite);
 | 
			
		||||
            
 | 
			
		||||
            // Here we read the code/reason received by the server, and ensure that remote is true
 | 
			
		||||
            REQUIRE(serverReceivedCloseCode == 1000);
 | 
			
		||||
            REQUIRE(serverReceivedCloseReason == "Normal closure");
 | 
			
		||||
            REQUIRE(serverReceivedCloseRemote == true);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Give us 1000ms for the server to notice that clients went away
 | 
			
		||||
        ix::msleep(1000);
 | 
			
		||||
        REQUIRE(server.getClients().size() == 0);
 | 
			
		||||
 | 
			
		||||
        ix::reportWebSocketTraffic();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE("Websocket_client_close_params_given", "[close]")
 | 
			
		||||
{
 | 
			
		||||
    SECTION("Make sure that close code and reason was used and sent to server.")
 | 
			
		||||
    {
 | 
			
		||||
        ix::setupWebSocketTrafficTrackerCallback();
 | 
			
		||||
 | 
			
		||||
        int port = getFreePort();
 | 
			
		||||
        ix::WebSocketServer server(port);
 | 
			
		||||
        
 | 
			
		||||
        uint16_t serverReceivedCloseCode(0);
 | 
			
		||||
        bool serverReceivedCloseRemote(false);
 | 
			
		||||
        std::string serverReceivedCloseReason("");
 | 
			
		||||
        std::mutex mutexWrite;
 | 
			
		||||
 | 
			
		||||
        REQUIRE(startServer(server, serverReceivedCloseCode, serverReceivedCloseReason, serverReceivedCloseRemote, mutexWrite));
 | 
			
		||||
 | 
			
		||||
        std::string session = ix::generateSessionId();
 | 
			
		||||
        WebSocketClient webSocketClient(port);
 | 
			
		||||
 | 
			
		||||
        webSocketClient.start();
 | 
			
		||||
 | 
			
		||||
        // Wait for all chat instance to be ready
 | 
			
		||||
        while (true)
 | 
			
		||||
        {
 | 
			
		||||
            if (webSocketClient.isReady()) break;
 | 
			
		||||
            ix::msleep(10);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        REQUIRE(server.getClients().size() == 1);
 | 
			
		||||
 | 
			
		||||
        ix::msleep(100);
 | 
			
		||||
 | 
			
		||||
        webSocketClient.stop(4000, "My reason");
 | 
			
		||||
 | 
			
		||||
        ix::msleep(500);
 | 
			
		||||
 | 
			
		||||
        // ensure client close is the same as values given
 | 
			
		||||
        REQUIRE(webSocketClient.getCloseCode() == 4000);
 | 
			
		||||
        REQUIRE(webSocketClient.getCloseReason() == "My reason");
 | 
			
		||||
        REQUIRE(webSocketClient.getCloseRemote() == false);
 | 
			
		||||
 | 
			
		||||
        {
 | 
			
		||||
            std::lock_guard<std::mutex> lck(mutexWrite);
 | 
			
		||||
            
 | 
			
		||||
            // Here we read the code/reason received by the server, and ensure that remote is true
 | 
			
		||||
            REQUIRE(serverReceivedCloseCode == 4000);
 | 
			
		||||
            REQUIRE(serverReceivedCloseReason == "My reason");
 | 
			
		||||
            REQUIRE(serverReceivedCloseRemote == true);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Give us 1000ms for the server to notice that clients went away
 | 
			
		||||
        ix::msleep(1000);
 | 
			
		||||
        REQUIRE(server.getClients().size() == 0);
 | 
			
		||||
 | 
			
		||||
        ix::reportWebSocketTraffic();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE("Websocket_server_close", "[close]")
 | 
			
		||||
{
 | 
			
		||||
    SECTION("Make sure that close code and reason was read from server.")
 | 
			
		||||
    {
 | 
			
		||||
        ix::setupWebSocketTrafficTrackerCallback();
 | 
			
		||||
 | 
			
		||||
        int port = getFreePort();
 | 
			
		||||
        ix::WebSocketServer server(port);
 | 
			
		||||
        
 | 
			
		||||
        uint16_t serverReceivedCloseCode(0);
 | 
			
		||||
        bool serverReceivedCloseRemote(false);
 | 
			
		||||
        std::string serverReceivedCloseReason("");
 | 
			
		||||
        std::mutex mutexWrite;
 | 
			
		||||
 | 
			
		||||
        REQUIRE(startServer(server, serverReceivedCloseCode, serverReceivedCloseReason, serverReceivedCloseRemote, mutexWrite));
 | 
			
		||||
 | 
			
		||||
        std::string session = ix::generateSessionId();
 | 
			
		||||
        WebSocketClient webSocketClient(port);
 | 
			
		||||
 | 
			
		||||
        webSocketClient.start();
 | 
			
		||||
 | 
			
		||||
        // Wait for all chat instance to be ready
 | 
			
		||||
        while (true)
 | 
			
		||||
        {
 | 
			
		||||
            if (webSocketClient.isReady()) break;
 | 
			
		||||
            ix::msleep(10);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        REQUIRE(server.getClients().size() == 1);
 | 
			
		||||
 | 
			
		||||
        ix::msleep(200);
 | 
			
		||||
 | 
			
		||||
        server.stop();
 | 
			
		||||
 | 
			
		||||
        ix::msleep(500);
 | 
			
		||||
 | 
			
		||||
        // ensure client close is the same as values given
 | 
			
		||||
        REQUIRE(webSocketClient.getCloseCode() == 1000);
 | 
			
		||||
        REQUIRE(webSocketClient.getCloseReason() == "Normal closure");
 | 
			
		||||
        REQUIRE(webSocketClient.getCloseRemote() == true);
 | 
			
		||||
 | 
			
		||||
        {
 | 
			
		||||
            std::lock_guard<std::mutex> lck(mutexWrite);
 | 
			
		||||
            
 | 
			
		||||
            // Here we read the code/reason received by the server, and ensure that remote is true
 | 
			
		||||
            REQUIRE(serverReceivedCloseCode == 1000);
 | 
			
		||||
            REQUIRE(serverReceivedCloseReason == "Normal closure");
 | 
			
		||||
            REQUIRE(serverReceivedCloseRemote == false);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Give us 1000ms for the server to notice that clients went away
 | 
			
		||||
        ix::msleep(1000);
 | 
			
		||||
        REQUIRE(server.getClients().size() == 0);
 | 
			
		||||
 | 
			
		||||
        ix::reportWebSocketTraffic();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user