1
0
mirror of https://github.com/stefanocasazza/ULib.git synced 2025-09-28 19:05:55 +08:00
This commit is contained in:
stefanocasazza 2018-05-11 18:36:10 +02:00
parent 7177337f9a
commit d4dfd5d9a8
43 changed files with 2740 additions and 399 deletions

View File

@ -53,7 +53,7 @@ extern U_EXPORT void runDynamicPage_ir_web(int param);
{
if (param == U_DPAGE_INIT) { usp_init_ir_web(); return; }
if (param == U_DPAGE_DESTROY) { usp_end_ir_web(); return; }
if (param >= U_DPAGE_FORK) return;
return;
}
UHTTP::mime_index = U_html;

View File

@ -19,7 +19,7 @@ extern U_EXPORT void runDynamicPage_wi_auth2(int param);
if (param == U_DPAGE_INIT) { usp_init_wi_auth2(); return; }
if (param == U_DPAGE_DESTROY) { usp_end_wi_auth2(); return; }
if (param == U_DPAGE_FORK) { usp_fork_wi_auth2(); return; }
if (param > U_DPAGE_FORK) return;
return;
}
U_http_info.endHeader = 0;

View File

@ -94,10 +94,10 @@ loop:
U_INTERNAL_ASSERT(lnetmask)
U_ASSERT(vnetmask.empty())
U_INTERNAL_DUMP("tok.current() = %C", tok.current())
U_INTERNAL_DUMP("tok.previous() = %C tok.current() = %C", tok.previous(), tok.current())
if (u__isdigit(tok.current())) name.clear();
else (void) tok.next(name, (bool*)U_NULLPTR);
if (tok.previous() != ',') name.clear();
else (void) tok.next(name, (bool*)U_NULLPTR);
vnetmask.push_back(lnetmask);
@ -613,7 +613,7 @@ static void deleteSession()
(void) rc->zrem(U_CONSTANT_TO_PARAM("SESSION:byCaptiveIdAndApId deviceId:%v;ip:%v"), mac->rep, ip->rep);
(void) rc->zrem(U_CONSTANT_TO_PARAM("SESSION:byLastUpdate %v"), key_session->rep);
U_LOGGER("*** SESSION(%V) deleted at deleteSession() ***", key_session->rep);
// U_LOGGER("*** SESSION(%V) deleted at deleteSession() ***", key_session->rep);
}
static void resetDeviceDailyCounter()
@ -1111,7 +1111,7 @@ static void POST_login()
(void) rc->hmset(U_CONSTANT_TO_PARAM("SESSION:%v captiveId %u apId %v deviceId %v ip %v created %u pId %v notify %c consume %c counter 0 lastUpdate %u"), key_session->rep,
addr, ap_label->rep, mac->rep, ip->rep, u_now->tv_sec, policySessionId->rep, buffer[1], '0'+ap_consume, u_now->tv_sec);
U_LOGGER("*** SESSION(%V) created at POST_login() ***", key_session->rep);
// U_LOGGER("*** SESSION(%V) created at POST_login() ***", key_session->rep);
(void) rc->zadd(U_CONSTANT_TO_PARAM("SESSION:byCaptiveIdAndApId %u%06u deviceId:%v;ip:%v"), addr, ap_label->strtoul(), mac->rep, ip->rep);
(void) rc->zadd(U_CONSTANT_TO_PARAM("SESSION:byLastUpdate %u %v"), u_now->tv_sec, key_session->rep);

View File

@ -19,7 +19,7 @@ extern U_EXPORT void runDynamicPage_wi_auth(int param);
if (param == U_DPAGE_INIT) { usp_init_wi_auth(); return; }
if (param == U_DPAGE_DESTROY) { usp_end_wi_auth(); return; }
if (param == U_DPAGE_SIGHUP) { usp_sighup_wi_auth(); return; }
if (param >= U_DPAGE_FORK) return;
return;
}
U_http_info.endHeader = 0;

View File

@ -416,8 +416,8 @@ http {
# ------------------------------------------------------------------------------------------------------------------------------------------------
# socket - plugin parameters
# ------------------------------------------------------------------------------------------------------------------------------------------------
# COMMAND command (alternative to USP websocket) to execute
# ENVIRONMENT environment for command (alternative to USP websocket) to execute
# COMMAND command (alternative to USP modsocket) to execute
# ENVIRONMENT environment for command (alternative to USP modsocket) to execute
#
# MAX_MESSAGE_SIZE Maximum size (in bytes) of a message to accept; default is approximately 4GB
# ------------------------------------------------------------------------------------------------------------------------------------------------

View File

@ -53,6 +53,7 @@
# include <ulib/ssl/digest.h>
# include <ulib/ssl/certificate.h>
# include <ulib/net/client/twilio.h>
# include <ulib/net/client/websocket.h>
# include <ulib/ssl/mime/mime_pkcs7.h>
# include <ulib/ssl/net/ssl_session.h>
# ifdef HAVE_SSL_TS

View File

@ -41,7 +41,9 @@ enum DynamicPageType {
U_DPAGE_RESET = -2,
U_DPAGE_DESTROY = -3,
U_DPAGE_SIGHUP = -4,
U_DPAGE_FORK = -5
U_DPAGE_FORK = -5,
U_DPAGE_OPEN = -6,
U_DPAGE_CLOSE = -7
};
/**

View File

@ -4163,7 +4163,9 @@ static bool runAuthCmd(const char* password, const char* prealm)
*output = UCommand::outputCommand(cmd, U_NULLPTR, -1, fd_stderr);
#ifdef U_LOG_DISABLE
UServer_Base::logCommandMsgError(cmd.data(), true);
#endif
if (UCommand::exit_value ||
output->empty())

View File

@ -178,9 +178,8 @@ public:
U_ASSERT(empty() == false)
if (getHeader(U_CONSTANT_TO_PARAM("Connection")).equal(U_CONSTANT_TO_PARAM("close")))
if (getHeader(U_CONSTANT_TO_PARAM("Connection")).equal(U_CONSTANT_TO_PARAM("close"))) U_RETURN(true);
U_RETURN(true);
U_RETURN(false);
}

View File

@ -16,6 +16,7 @@
#include <ulib/url.h>
#include <ulib/net/rpc/rpc.h>
#include <ulib/mime/header.h>
#include <ulib/utility/uhttp.h>
#ifdef USE_LIBSSL
@ -39,6 +40,7 @@ class USCGIPlugIn;
class UProxyPlugIn;
class UNoCatPlugIn;
class UServer_Base;
class UWebSocketClient;
class UHttpClient_Base;
class UClientImage_Base;
class UREDISClient_Base;
@ -297,6 +299,8 @@ protected:
bool sendRequestAndReadResponse() { return sendRequest(true); }
bool processHeader(UMimeHeader* responseHeader) { return responseHeader->readHeader(socket, response); }
#ifdef USE_LIBSSL
void setSSLContext();
@ -329,6 +333,7 @@ private:
friend class UProxyPlugIn;
friend class UNoCatPlugIn;
friend class UServer_Base;
friend class UWebSocketClient;
friend class UHttpClient_Base;
friend class UClientImage_Base;
friend class UREDISClient_Base;

View File

@ -33,7 +33,6 @@
*/
class UHTTP;
class UMimeHeader;
class Application;
class WiAuthNodog;
class UServer_Base;

View File

@ -0,0 +1,104 @@
// ============================================================================
//
// = LIBRARY
// ULib - c++ library
//
// = FILENAME
// websocket.h - simple websocket client
//
// = AUTHOR
// Stefano Casazza
//
// ============================================================================
#ifndef ULIB_WEBSOCKET_CLIENT_H
#define ULIB_WEBSOCKET_CLIENT_H 1
#include <ulib/net/client/client.h>
#include <ulib/ssl/net/sslsocket.h>
#include <ulib/utility/websocket.h>
/**
* @class UWebSocketClient
*/
class U_EXPORT UWebSocketClient {
public:
// Check for memory error
U_MEMORY_TEST
// Allocator e Deallocator
U_MEMORY_ALLOCATOR
U_MEMORY_DEALLOCATOR
/**
* Constructor
*/
UWebSocketClient()
{
U_TRACE_CTOR(0, UWebSocketClient, "", 0)
U_NEW(UClient<USSLSocket>, client, UClient<USSLSocket>(U_NULLPTR));
}
~UWebSocketClient()
{
U_TRACE_DTOR(0, UWebSocketClient)
U_INTERNAL_ASSERT_POINTER(client)
U_DELETE(client)
}
// SERVICES
bool readMessage()
{
U_TRACE_NO_PARAM(0, "UWebSocketClient::readMessage()")
U_INTERNAL_ASSERT_POINTER(client)
UWebSocket::rbuffer->setEmpty();
if (UWebSocket::handleDataFraming(client->UClient_Base::socket) == U_WS_STATUS_CODE_OK) U_RETURN(true);
U_RETURN(false);
}
bool sendMessage(const UString& msg, int type = U_WS_MESSAGE_TYPE_TEXT)
{
U_TRACE(0, "UWebSocketClient::sendMessage(%V,%d)", msg.rep, type)
U_INTERNAL_ASSERT_POINTER(client)
return UWebSocket::sendData(client->UClient_Base::socket, type, msg);
}
void close()
{
U_TRACE_NO_PARAM(0, "UWebSocketClient::close()")
U_INTERNAL_ASSERT_POINTER(client)
(void) UWebSocket::sendClose(client->UClient_Base::socket);
client->UClient_Base::close();
}
bool connectServer(const UString& url);
UClient<USSLSocket>* getClient() const { return client; }
#if defined(U_STDCPP_ENABLE) && defined(DEBUG)
const char* dump(bool reset) const;
#endif
protected:
UClient<USSLSocket>* client;
private:
U_DISALLOW_COPY_AND_ASSIGN(UWebSocketClient)
};
#endif

View File

@ -300,9 +300,7 @@ protected:
(void) peer->fw.executeAndWait(U_NULLPTR, -1, fd_stderr);
# ifndef U_LOG_DISABLE
UServer_Base::logCommandMsgError(peer->fw.getCommand(), false);
# endif
U_SRV_LOG_CMD_MSG_ERR(peer->fw, false);
U_peer_status = type;
}

View File

@ -266,7 +266,7 @@ protected:
{
U_TRACE(0, "UNoDogPlugIn::setRedirect(%p,%u)", buffer, bufsize)
return u__snprintf(buffer, bufsize, U_CONSTANT_TO_PARAM("http://%.*s/%.*s"), U_HTTP_HOST_TO_TRACE, U_HTTP_URI_QUERY_TO_TRACE);
return u__snprintf(buffer, bufsize, U_CONSTANT_TO_PARAM("http://%.*s%.*s"), U_HTTP_HOST_TO_TRACE, U_HTTP_URI_QUERY_TO_TRACE);
}
static uint32_t getApInfo(char* buffer, uint32_t bufsize, const UString& lbl)

View File

@ -45,8 +45,10 @@ public:
#endif
protected:
static int fd_stderr;
static vPFi on_message;
static UCommand* command;
static UString* penvironment;
static RETSIGTYPE handlerForSigTERM(int signo);

View File

@ -86,7 +86,11 @@ vClientImage = new client_type[UNotifier::max_connection]; } }
# define U_SRV_LOG( fmt,args...) {}
# define U_SRV_LOG_WITH_ADDR(fmt,args...) {}
# define U_SRV_LOG_CMD_MSG_ERR(cmd,balways) {}
#else
# define U_SRV_LOG_CMD_MSG_ERR(cmd,balways) { if (UServer_Base::isLog()) UServer_Base::logCommandMsgError((cmd).getCommand(),balways); }
# define U_RESET_MODULE_NAME { if (UServer_Base::isLog()) (void) strcpy(UServer_Base::mod_name[0], UServer_Base::mod_name[1]); }
# define U_SET_MODULE_NAME(name) { if (UServer_Base::isLog()) { (void) strcpy(UServer_Base::mod_name[1], UServer_Base::mod_name[0]); \
(void) strcpy(UServer_Base::mod_name[0], "["#name"] "); } }
@ -94,6 +98,7 @@ vClientImage = new client_type[UNotifier::max_connection]; } }
# define U_SRV_LOG( fmt,args...) { if (UServer_Base::isLog()) UServer_Base::log->log(U_CONSTANT_TO_PARAM("%s" fmt), UServer_Base::mod_name[0] , ##args); }
# define U_SRV_LOG_WITH_ADDR(fmt,args...) { if (UServer_Base::isLog()) UServer_Base::log->log(U_CONSTANT_TO_PARAM("%s" fmt " %v"), UServer_Base::mod_name[0] , ##args, \
UServer_Base::pClientImage->logbuf->rep); }
#endif
class UHTTP;
@ -617,13 +622,12 @@ public:
U_TRACE(0, "UServer_Base::logCommandMsgError(%S,%b)", cmd, balways)
# ifndef U_LOG_DISABLE
if (isLog())
{
if (UCommand::setMsgError(cmd, !balways) || balways) log->log(U_CONSTANT_TO_PARAM("%s%.*s"), mod_name[0], u_buffer_len, u_buffer);
U_INTERNAL_ASSERT_POINTER(log)
errno = 0;
u_buffer_len = 0;
}
if (UCommand::setMsgError(cmd, !balways) || balways) log->log(U_CONSTANT_TO_PARAM("%s%.*s"), mod_name[0], u_buffer_len, u_buffer);
errno = 0;
u_buffer_len = 0;
# endif
}

View File

@ -158,6 +158,17 @@ public:
--s;
}
// get previous char
char previous()
{
U_TRACE_NO_PARAM(0, "UTokenizer::previous()")
U_INTERNAL_ASSERT(s <= end)
U_RETURN(*(s-1));
}
// get current char
char current()

View File

@ -232,12 +232,34 @@ public:
U_RETURN_STRING(srv);
}
bool isLDAP() const
{
U_TRACE_NO_PARAM(0, "Url::isLDAP()")
if (u_get_unalignedp32(url.data()) == U_MULTICHAR_CONSTANT32('l','d','a','p')) U_RETURN(true);
U_RETURN(false);
}
bool isHTTP() const
{
U_TRACE_NO_PARAM(0, "Url::isHTTP()")
if (service_end == 4 &&
UString::str_http->equal(url.data(), (uint32_t)service_end))
u_get_unalignedp32(url.data()) == U_MULTICHAR_CONSTANT32('h','t','t','p'))
{
U_RETURN(true);
}
U_RETURN(false);
}
bool isWS() const
{
U_TRACE_NO_PARAM(0, "Url::isWS()")
if (service_end == 2 &&
u_get_unalignedp16(url.data()) == U_MULTICHAR_CONSTANT16('w','s'))
{
U_RETURN(true);
}
@ -251,7 +273,7 @@ public:
if (service_end == 5 &&
url.c_char(4) == 's' &&
UString::str_http->equal(url.data(), 4))
u_get_unalignedp32(url.data()) == U_MULTICHAR_CONSTANT32('h','t','t','p'))
{
U_RETURN(true);
}
@ -259,11 +281,16 @@ public:
U_RETURN(false);
}
bool isLDAP() const
bool isWSS() const
{
U_TRACE_NO_PARAM(0, "Url::isLDAP()")
U_TRACE_NO_PARAM(0, "Url::isWSS()")
if (getService().equal(U_CONSTANT_TO_PARAM("ldap"))) U_RETURN(true);
if (service_end == 3 &&
url.c_char(2) == 's' &&
u_get_unalignedp16(url.data()) == U_MULTICHAR_CONSTANT16('w','s'))
{
U_RETURN(true);
}
U_RETURN(false);
}
@ -272,7 +299,12 @@ public:
{
U_TRACE_NO_PARAM(0, "Url::isLDAPS()")
if (getService().equal(U_CONSTANT_TO_PARAM("ldaps"))) U_RETURN(true);
if (service_end == 5 &&
url.c_char(4) == 's' &&
u_get_unalignedp32(url.data()) == U_MULTICHAR_CONSTANT32('l','d','a','p'))
{
U_RETURN(true);
}
U_RETURN(false);
}

View File

@ -16,26 +16,33 @@
#include <ulib/string.h>
#define MESSAGE_TYPE_INVALID -1
#define MESSAGE_TYPE_TEXT 0
#define MESSAGE_TYPE_BINARY 128
#define MESSAGE_TYPE_CLOSE 255
#define MESSAGE_TYPE_PING 256
#define MESSAGE_TYPE_PONG 257
#define U_WS_MESSAGE_TYPE_INVALID -1
#define U_WS_MESSAGE_TYPE_TEXT 0
#define U_WS_MESSAGE_TYPE_BINARY 128
#define U_WS_MESSAGE_TYPE_CLOSE 255
#define U_WS_MESSAGE_TYPE_PING 256
#define U_WS_MESSAGE_TYPE_PONG 257
#define STATUS_CODE_OK 1000
#define STATUS_CODE_GOING_AWAY 1001
#define STATUS_CODE_PROTOCOL_ERROR 1002
#define STATUS_CODE_INVALID_TYPE 1003
#define STATUS_CODE_RESERVED1 1004 /* Protocol 8: frame too large */
#define STATUS_CODE_RESERVED2 1005
#define STATUS_CODE_RESERVED3 1006
#define STATUS_CODE_INVALID_UTF8 1007
#define STATUS_CODE_POLICY_VIOLATION 1008
#define STATUS_CODE_MESSAGE_TOO_LARGE 1009
#define STATUS_CODE_EXTENSION_ERROR 1010
#define STATUS_CODE_INTERNAL_ERROR 1011
#define STATUS_CODE_RESERVED4 1015
#define U_WS_OPCODE_CONTINUATION 0x0
#define U_WS_OPCODE_TEXT 0x1
#define U_WS_OPCODE_BINARY 0x2
#define U_WS_OPCODE_CLOSE 0x8
#define U_WS_OPCODE_PING 0x9
#define U_WS_OPCODE_PONG 0xA
#define U_WS_STATUS_CODE_OK 1000
#define U_WS_STATUS_CODE_GOING_AWAY 1001
#define U_WS_STATUS_CODE_PROTOCOL_ERROR 1002
#define U_WS_STATUS_CODE_INVALID_TYPE 1003
#define U_WS_STATUS_CODE_RESERVED1 1004 /* Protocol 8: frame too large */
#define U_WS_STATUS_CODE_RESERVED2 1005
#define U_WS_STATUS_CODE_RESERVED3 1006
#define U_WS_STATUS_CODE_INVALID_UTF8 1007
#define U_WS_STATUS_CODE_POLICY_VIOLATION 1008
#define U_WS_STATUS_CODE_MESSAGE_TOO_LARGE 1009
#define U_WS_STATUS_CODE_EXTENSION_ERROR 1010
#define U_WS_STATUS_CODE_INTERNAL_ERROR 1011
#define U_WS_STATUS_CODE_RESERVED4 1015
class USocket;
@ -44,11 +51,6 @@ public:
// SERVICES
static UString* rbuffer;
static uint32_t max_message_size;
static const char* upgrade_settings;
static int message_type, status_code;
typedef struct _WebSocketFrameData {
unsigned char* application_data;
uint32_t application_data_offset;
@ -57,17 +59,24 @@ public:
unsigned int utf8_state;
} WebSocketFrameData;
static UString* rbuffer;
static UString* message;
static uint32_t max_message_size;
static const char* upgrade_settings;
static int message_type, status_code;
static WebSocketFrameData control_frame;
static WebSocketFrameData message_frame;
static bool sendAccept();
static void checkForInitialData();
static bool sendAccept(USocket* socket);
static int handleDataFraming(USocket* socket);
static bool sendData(int type, const unsigned char* buffer, uint32_t buffer_size);
static bool sendData(USocket* socket, int type, const char* data, uint32_t len);
static bool sendClose()
static bool sendData(USocket* socket, int type, const UString& data) { return sendData(socket, type, U_STRING_TO_PARAM(data)); }
static bool sendClose(USocket* socket)
{
U_TRACE_NO_PARAM(0, "UWebSocket::sendClose()")
U_TRACE(0, "UWebSocket::sendClose(%p)", socket)
// Send server-side closing handshake
@ -76,12 +85,14 @@ public:
unsigned char status_code_buffer[2] = { (unsigned char)((status_code >> 8) & 0xFF),
(unsigned char)( status_code & 0xFF) };
if (sendData(MESSAGE_TYPE_CLOSE, status_code_buffer, sizeof(status_code_buffer))) U_RETURN(true);
if (sendControlFrame(socket, U_WS_OPCODE_CLOSE, status_code_buffer, sizeof(status_code_buffer))) U_RETURN(true);
U_RETURN(false);
}
private:
static bool sendControlFrame(USocket* socket, int opcode, const unsigned char* payload, uint32_t payload_length);
U_DISALLOW_COPY_AND_ASSIGN(UWebSocket)
};

File diff suppressed because it is too large Load Diff

View File

@ -174,7 +174,7 @@ endif
if SSL
SRC_C += base/ssl/cdes3.c base/ssl/dgst.c
SRC_CPP += ssl/certificate.cpp ssl/pkcs7.cpp ssl/crl.cpp ssl/pkcs10.cpp net/client/twilio.cpp \
SRC_CPP += ssl/certificate.cpp ssl/pkcs7.cpp ssl/crl.cpp ssl/pkcs10.cpp net/client/twilio.cpp net/client/uwebsocket.cpp \
ssl/mime/mime_pkcs7.cpp ssl/net/sslsocket.cpp ssl/net/ssl_session.cpp utility/des3.cpp
if SSL_TS
SRC_CPP += ssl/timestamp.cpp

View File

@ -115,7 +115,7 @@ target_triplet = @target@
@USE_PARSER_TRUE@am__append_33 = flex/flexer.cpp flex/bison.cpp
@PCRE_TRUE@am__append_34 = pcre/pcre.cpp
@SSL_TRUE@am__append_35 = base/ssl/cdes3.c base/ssl/dgst.c
@SSL_TRUE@am__append_36 = ssl/certificate.cpp ssl/pkcs7.cpp ssl/crl.cpp ssl/pkcs10.cpp net/client/twilio.cpp \
@SSL_TRUE@am__append_36 = ssl/certificate.cpp ssl/pkcs7.cpp ssl/crl.cpp ssl/pkcs10.cpp net/client/twilio.cpp net/client/uwebsocket.cpp \
@SSL_TRUE@ ssl/mime/mime_pkcs7.cpp ssl/net/sslsocket.cpp ssl/net/ssl_session.cpp utility/des3.cpp
@SSL_TRUE@@SSL_TS_TRUE@am__append_37 = ssl/timestamp.cpp
@ -267,10 +267,11 @@ am__lib@ULIB@_la_SOURCES_DIST = base/base.c base/base_error.c \
debug/objectDB.cpp internal/memory_pool.cpp zip/zip.cpp \
flex/flexer.cpp flex/bison.cpp pcre/pcre.cpp \
ssl/certificate.cpp ssl/pkcs7.cpp ssl/crl.cpp ssl/pkcs10.cpp \
net/client/twilio.cpp ssl/mime/mime_pkcs7.cpp \
ssl/net/sslsocket.cpp ssl/net/ssl_session.cpp utility/des3.cpp \
ssl/timestamp.cpp ssh/net/sshsocket.cpp ldap/ldap.cpp \
curl/curl.cpp xml/expat/attribute.cpp xml/expat/element.cpp \
net/client/twilio.cpp net/client/uwebsocket.cpp \
ssl/mime/mime_pkcs7.cpp ssl/net/sslsocket.cpp \
ssl/net/ssl_session.cpp utility/des3.cpp ssl/timestamp.cpp \
ssh/net/sshsocket.cpp ldap/ldap.cpp curl/curl.cpp \
xml/expat/attribute.cpp xml/expat/element.cpp \
xml/expat/xml_parser.cpp xml/expat/xml2txt.cpp \
xml/soap/soap_fault.cpp xml/soap/soap_gen_method.cpp \
xml/soap/soap_parser.cpp xml/soap/soap_encoder.cpp \
@ -347,8 +348,9 @@ am__objects_26 = base/base.lo base/base_error.lo base/hash.lo \
@PCRE_TRUE@am__objects_37 = pcre/pcre.lo
@SSL_TRUE@am__objects_38 = ssl/certificate.lo ssl/pkcs7.lo ssl/crl.lo \
@SSL_TRUE@ ssl/pkcs10.lo net/client/twilio.lo \
@SSL_TRUE@ ssl/mime/mime_pkcs7.lo ssl/net/sslsocket.lo \
@SSL_TRUE@ ssl/net/ssl_session.lo utility/des3.lo
@SSL_TRUE@ net/client/uwebsocket.lo ssl/mime/mime_pkcs7.lo \
@SSL_TRUE@ ssl/net/sslsocket.lo ssl/net/ssl_session.lo \
@SSL_TRUE@ utility/des3.lo
@SSL_TRUE@@SSL_TS_TRUE@am__objects_39 = ssl/timestamp.lo
@SSH_TRUE@am__objects_40 = ssh/net/sshsocket.lo
@LDAP_TRUE@am__objects_41 = ldap/ldap.lo
@ -1256,6 +1258,8 @@ ssl/crl.lo: ssl/$(am__dirstamp) ssl/$(DEPDIR)/$(am__dirstamp)
ssl/pkcs10.lo: ssl/$(am__dirstamp) ssl/$(DEPDIR)/$(am__dirstamp)
net/client/twilio.lo: net/client/$(am__dirstamp) \
net/client/$(DEPDIR)/$(am__dirstamp)
net/client/uwebsocket.lo: net/client/$(am__dirstamp) \
net/client/$(DEPDIR)/$(am__dirstamp)
ssl/mime/$(am__dirstamp):
@$(MKDIR_P) ssl/mime
@: > ssl/mime/$(am__dirstamp)
@ -1608,6 +1612,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@net/client/$(DEPDIR)/redis.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@net/client/$(DEPDIR)/smtp.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@net/client/$(DEPDIR)/twilio.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@net/client/$(DEPDIR)/uwebsocket.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@net/rpc/$(DEPDIR)/rpc.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@net/rpc/$(DEPDIR)/rpc_client.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@net/rpc/$(DEPDIR)/rpc_encoder.Plo@am__quote@

View File

@ -119,6 +119,7 @@
# include "ssl/crl.cpp"
# include "ssl/pkcs10.cpp"
# include "net/client/twilio.cpp"
# include "net/client/uwebsocket.cpp"
# include "ssl/mime/mime_pkcs7.cpp"
# include "ssl/net/sslsocket.cpp"
# include "ssl/net/ssl_session.cpp"

View File

@ -104,9 +104,7 @@ bool UFileConfig::processData(bool bload)
(void) cmd.execute(&data, &output, -1, fd_stderr);
# ifndef U_LOG_DISABLE
UServer_Base::logCommandMsgError(cmd.getCommand(), true);
# endif
U_SRV_LOG_CMD_MSG_ERR(cmd, true);
# ifdef HAVE_MCPP
if (data.empty())
@ -117,9 +115,7 @@ bool UFileConfig::processData(bool bload)
(void) _cmd.execute(&data, &output, -1, fd_stderr);
# ifndef U_LOG_DISABLE
UServer_Base::logCommandMsgError(_cmd.getCommand(), true);
# endif
U_SRV_LOG_CMD_MSG_ERR(_cmd, true);
}
# endif

View File

@ -378,7 +378,7 @@ bool UClient_Base::setUrl(const char* str, uint32_t len)
url.set(str, len);
if (socket->isSSL()) socket->setSSLActive(url.isHTTPS());
if (socket->isSSL()) socket->setSSLActive(url.isHTTPS() | url.isWSS());
uri = url.getPathAndQuery();

View File

@ -882,7 +882,7 @@ bool UHttpClient_Base::sendRequestEngine()
responseHeader->clear();
result = (UClient_Base::sendRequestAndReadResponse() &&
responseHeader->readHeader(UClient_Base::socket, UClient_Base::response) // read the HTTP response header
UClient_Base::processHeader(responseHeader)
? checkResponse(redirectCount, _uri)
: -1);

View File

@ -0,0 +1,77 @@
// ============================================================================
//
// = LIBRARY
// ULib - c++ library
//
// = FILENAME
// uwebsocket.cpp
//
// = AUTHOR
// Stefano Casazza
//
// ============================================================================
#include <ulib/net/client/websocket.h>
bool UWebSocketClient::connectServer(const UString& url)
{
U_TRACE(0, "UWebSocketClient::connectServer(%V)", url.rep)
U_INTERNAL_ASSERT_POINTER(client)
if (client->UClient_Base::connectServer(url))
{
UMimeHeader responseHeader;
UString buffer(U_CAPACITY);
buffer.snprintf(U_CONSTANT_TO_PARAM(
"GET %v HTTP/1.1\r\n"
"Host: %v:%u\r\n"
"Upgrade: websocket\r\n"
"Connection: Upgrade\r\n"
"Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
"Sec-WebSocket-Version: 13\r\n"
"\r\n"),
client->UClient_Base::uri.rep, client->UClient_Base::server.rep, client->UClient_Base::port);
client->UClient_Base::prepareRequest(buffer);
if (client->UClient_Base::sendRequestAndReadResponse() &&
(responseHeader.setIgnoreCase(true), client->UClient_Base::processHeader(&responseHeader)))
{
/**
* HTTP/1.1 101 Switching Protocols\r\n
* Upgrade: websocket\r\n
* Connection: Upgrade\r\n
* Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n\r\n
*/
if (U_http_info.nResponseCode != 101) U_RETURN(false); // invalid HTTP status response code
if (responseHeader.getHeader(U_CONSTANT_TO_PARAM("Upgrade")).equalnocase(U_CONSTANT_TO_PARAM("websocket")) == false) U_RETURN(false); // invalid HTTP upgrade header
if (responseHeader.getHeader(U_CONSTANT_TO_PARAM("Connection")).equalnocase(U_CONSTANT_TO_PARAM("Upgrade")) == false) U_RETURN(false); // invalid HTTP connection header
if (responseHeader.getHeader(U_CONSTANT_TO_PARAM("Sec-WebSocket-Accept")).equal(U_CONSTANT_TO_PARAM("s3pPLMBiTxaQ9kYGzzhZRbK+xOo="))) U_RETURN(true);
}
}
U_RETURN(false);
}
// DEBUG
#if defined(U_STDCPP_ENABLE) && defined(DEBUG)
const char* UWebSocketClient::dump(bool _reset) const
{
*UObjectIO::os << "client (UClient<USSLSocket> " << (void*)client << ')';
if (_reset)
{
UObjectIO::output();
return UObjectIO::buffer_output;
}
return U_NULLPTR;
}
#endif

View File

@ -923,7 +923,9 @@ void UClientImage_Base::manageReadBufferResize(uint32_t n)
if (U_http_info.user_agent_len) U_http_info.user_agent += diff;
if (U_http_accept_language_len) U_http_info.accept_language += diff;
# if defined(USE_LIBSSL) && !defined(U_SERVER_CAPTIVE_PORTAL)
if (U_http_websocket_len) UWebSocket::upgrade_settings += diff;
# endif
U_INTERNAL_DUMP("host = %.*S", U_HTTP_HOST_TO_TRACE)
U_INTERNAL_DUMP("vhost = %.*S", U_HTTP_VHOST_TO_TRACE)

View File

@ -657,9 +657,7 @@ loop:
ok = fw->execute(U_NULLPTR, &output, -1, fd_stderr);
#ifndef U_LOG_DISABLE
UServer_Base::logCommandMsgError(fw->getCommand(), false);
#endif
U_SRV_LOG_CMD_MSG_ERR(*fw, false);
if (ok == false)
{
@ -771,9 +769,7 @@ bool UNoCatPlugIn::checkFirewall()
(void) _fw.executeAndWait(U_NULLPTR, -1, fd_stderr);
# ifndef U_LOG_DISABLE
UServer_Base::logCommandMsgError(_fw.getCommand(), false);
# endif
U_SRV_LOG_CMD_MSG_ERR(_fw, false);
}
}
@ -1057,9 +1053,7 @@ UString UNoCatPlugIn::getSignedData(const char* ptr, uint32_t len)
(void) pgp.execute(&input, &output, -1, fd_stderr);
# ifndef U_LOG_DISABLE
UServer_Base::logCommandMsgError(pgp.getCommand(), false);
# endif
U_SRV_LOG_CMD_MSG_ERR(pgp, false);
}
*/
@ -2337,9 +2331,7 @@ int UNoCatPlugIn::handlerFork()
(void) fw->executeAndWait(U_NULLPTR, -1, fd_stderr);
#ifndef U_LOG_DISABLE
UServer_Base::logCommandMsgError(fw->getCommand(), false);
#endif
U_SRV_LOG_CMD_MSG_ERR(*fw, false);
fw->delArgument();
fw->setLastArgument("openlist");

View File

@ -360,9 +360,7 @@ void UNoDogPlugIn::executeCommand(const char* type, uint32_t len)
(void) cmd.executeAndWait(U_NULLPTR, -1, fd_stderr);
#ifndef U_LOG_DISABLE
UServer_Base::logCommandMsgError(cmd.getCommand(), false);
#endif
U_SRV_LOG_CMD_MSG_ERR(cmd, false);
}
U_NO_EXPORT void UNoDogPlugIn::setMAC()
@ -989,9 +987,7 @@ end:
(void) fw->executeAndWait(U_NULLPTR, -1, fd_stderr);
#ifndef U_LOG_DISABLE
UServer_Base::logCommandMsgError(fw->getCommand(), false);
#endif
U_SRV_LOG_CMD_MSG_ERR(*fw, false);
fw->delArgument();
fw->setLastArgument("openlist");
@ -1277,7 +1273,7 @@ next1: eraseTimer();
goto end;
}
if (U_HTTP_URI_STREQ("/nodog_peer_delay.sh"))
if (U_HTTP_URI_MEMEQ("/nodog_peer_delay.sh"))
{
if (U_peer_delay_disable == false)
{

View File

@ -146,6 +146,7 @@ int UProxyPlugIn::handlerRequest()
client_http->UClient_Base::close();
}
# if defined(USE_LIBSSL) && !defined(U_SERVER_CAPTIVE_PORTAL)
// --------------------------------------------------------------------------------------------------------------------
// A WebSocket is a long-lived connection, lasting hours or days. If each WebSocket proxy holds the original thread,
// won't that consume all of the workers very quickly? It looks as if my server, with 16 workers, will be unable to
@ -158,9 +159,9 @@ int UProxyPlugIn::handlerRequest()
{
UWebSocket::checkForInitialData(); // check if we have read more data than necessary...
while (UWebSocket::handleDataFraming(UServer_Base::csocket) == STATUS_CODE_OK &&
while (UWebSocket::handleDataFraming(UServer_Base::csocket) == U_WS_STATUS_CODE_OK &&
(client_http->UClient_Base::prepareRequest(*UClientImage_Base::wbuffer), client_http->UClient_Base::sendRequestAndReadResponse()) &&
UWebSocket::sendData(UWebSocket::message_type, (const unsigned char*)U_STRING_TO_PARAM(client_http->UClient_Base::response)))
UWebSocket::sendData(UServer_Base::csocket, UWebSocket::message_type, client_http->UClient_Base::response))
{
client_http->UClient_Base::clearData();
@ -169,6 +170,7 @@ int UProxyPlugIn::handlerRequest()
U_RETURN(U_PLUGIN_HANDLER_ERROR);
}
# endif
client_http->setFollowRedirects(UHTTP::service->isFollowRedirects(), true);
if (UHTTP::service->isAuthorization()) client_http->setRequestPasswordAuthentication(UHTTP::service->getUser(), UHTTP::service->getPassword());

View File

@ -21,7 +21,9 @@
U_CREAT_FUNC(server_plugin_socket, UWebSocketPlugIn)
int UWebSocketPlugIn::fd_stderr;
vPFi UWebSocketPlugIn::on_message;
UString* UWebSocketPlugIn::penvironment;
UCommand* UWebSocketPlugIn::command;
UWebSocketPlugIn::UWebSocketPlugIn()
@ -33,8 +35,17 @@ UWebSocketPlugIn::~UWebSocketPlugIn()
{
U_TRACE_DTOR(0, UWebSocketPlugIn)
if (command) U_DELETE(command)
if (UWebSocket::rbuffer) U_DELETE(UWebSocket::rbuffer)
if (command)
{
U_DELETE(command)
U_DELETE(penvironment)
}
if (UWebSocket::rbuffer)
{
U_DELETE(UWebSocket::rbuffer)
U_DELETE(UWebSocket::message)
}
}
RETSIGTYPE UWebSocketPlugIn::handlerForSigTERM(int signo)
@ -50,10 +61,11 @@ int UWebSocketPlugIn::handlerConfig(UFileConfig& cfg)
{
U_TRACE(0, "UWebSocketPlugIn::handlerConfig(%p)", &cfg)
// ----------------------------------------------------------------------------------------------
// Perform registration of web socket method
// ----------------------------------------------------------------------------------------------
// COMMAND command (alternative to USP websocket) to execute
// ENVIRONMENT environment for command (alternative to USP websocket) to execute
// COMMAND command (alternative to USP modsocket) to execute
// ENVIRONMENT environment for command (alternative to USP modsocket) to execute
//
// MAX_MESSAGE_SIZE Maximum size (in bytes) of a message to accept; default is approximately 4GB
// ----------------------------------------------------------------------------------------------
@ -62,8 +74,12 @@ int UWebSocketPlugIn::handlerConfig(UFileConfig& cfg)
{
command = UServer_Base::loadConfigCommand();
U_NEW_STRING(penvironment, UString(U_CAPACITY));
UWebSocket::max_message_size = cfg.readLong(U_CONSTANT_TO_PARAM("MAX_MESSAGE_SIZE"), U_STRING_MAX_SIZE);
fd_stderr = UServices::getDevNull("/tmp/UWebSocketPlugIn.err");
U_RETURN(U_PLUGIN_HANDLER_PROCESSED);
}
@ -75,21 +91,21 @@ int UWebSocketPlugIn::handlerRun()
U_TRACE_NO_PARAM(0, "UWebSocketPlugIn::handlerRun()")
U_INTERNAL_ASSERT_EQUALS(UWebSocket::rbuffer, U_NULLPTR)
U_INTERNAL_ASSERT_EQUALS(UWebSocket::message, U_NULLPTR)
U_NEW_STRING(UWebSocket::rbuffer, UString(U_CAPACITY));
U_NEW_STRING(UWebSocket::message, UString(U_CAPACITY));
if (UHTTP::getUSP(U_CONSTANT_TO_PARAM("modsocket")))
if (command == U_NULLPTR)
{
if (UHTTP::getUSP(U_CONSTANT_TO_PARAM("modsocket")) == false) U_RETURN(U_PLUGIN_HANDLER_ERROR);
U_INTERNAL_DUMP("modsocket->runDynamicPage = %p", UHTTP::usp->runDynamicPage)
U_INTERNAL_ASSERT_POINTER(UHTTP::usp->runDynamicPage)
on_message = UHTTP::usp->runDynamicPage;
}
else
{
if (command == U_NULLPTR) U_RETURN(U_PLUGIN_HANDLER_ERROR);
}
U_RETURN(U_PLUGIN_HANDLER_OK);
}
@ -102,45 +118,40 @@ int UWebSocketPlugIn::handlerRequest()
if (U_http_websocket_len)
{
int fdmax = 0;
int fdmax = 0; // NB: to avoid 'warning: fdmax may be used uninitialized in this function'...
fd_set fd_set_read, read_set;
bool bcommand = (command && on_message == U_NULLPTR);
if (bcommand)
{
// Set environment for the command application server
static int fd_stderr;
if (fd_stderr == 0) fd_stderr = UServices::getDevNull("/tmp/UWebSocketPlugIn.err");
UString environment(U_CAPACITY);
(void) environment.append(command->getStringEnvironment());
if (UHTTP::getCGIEnvironment(environment, U_GENERIC) == false) U_RETURN(U_PLUGIN_HANDLER_ERROR);
command->setEnvironment(&environment);
if (command->execute((UString*)-1, (UString*)-1, -1, fd_stderr))
{
# ifndef U_LOG_DISABLE
UServer_Base::logCommandMsgError(command->getCommand(), true);
# endif
UInterrupt::setHandlerForSignal(SIGTERM, (sighandler_t)UWebSocketPlugIn::handlerForSigTERM); // sync signal
}
FD_ZERO(&fd_set_read);
FD_SET(UProcess::filedes[2], &fd_set_read);
FD_SET(UServer_Base::csocket->iSockDesc, &fd_set_read);
fdmax = U_max(UServer_Base::csocket->iSockDesc, UProcess::filedes[2]) + 1;
}
UWebSocket::checkForInitialData(); // check if we have read more data than necessary...
if (bcommand == false) goto handle_data;
if (command == U_NULLPTR)
{
on_message(U_DPAGE_OPEN);
goto data;
}
// Set environment for the command application server
penvironment->setBuffer(U_CAPACITY);
(void) penvironment->append(command->getStringEnvironment());
if (UHTTP::getCGIEnvironment(*penvironment, U_GENERIC) == false) U_RETURN(U_PLUGIN_HANDLER_ERROR);
command->setEnvironment(penvironment);
if (command->execute((UString*)-1, (UString*)-1, -1, fd_stderr))
{
U_SRV_LOG_CMD_MSG_ERR(*command, true);
UInterrupt::setHandlerForSignal(SIGTERM, (sighandler_t)UWebSocketPlugIn::handlerForSigTERM); // sync signal
}
FD_ZERO(&fd_set_read);
FD_SET(UProcess::filedes[2], &fd_set_read);
FD_SET(UServer_Base::csocket->iSockDesc, &fd_set_read);
fdmax = U_max(UServer_Base::csocket->iSockDesc, UProcess::filedes[2]) + 1;
loop: read_set = fd_set_read;
@ -151,7 +162,7 @@ loop: read_set = fd_set_read;
UWebSocket::rbuffer->setEmpty();
if (UServices::read(UProcess::filedes[2], *UWebSocket::rbuffer) &&
UWebSocket::sendData(UWebSocket::message_type, (const unsigned char*)U_STRING_TO_PARAM(*UWebSocket::rbuffer)))
UWebSocket::sendData(UServer_Base::csocket, UWebSocket::message_type, *UWebSocket::rbuffer))
{
UWebSocket::rbuffer->setEmpty();
@ -160,16 +171,25 @@ loop: read_set = fd_set_read;
}
else if (FD_ISSET(UServer_Base::csocket->iSockDesc, &read_set))
{
handle_data:
if (UWebSocket::handleDataFraming(UServer_Base::csocket) == STATUS_CODE_OK &&
(bcommand == false ? (on_message(0), U_http_info.nResponseCode != HTTP_INTERNAL_ERROR)
: UNotifier::write(UProcess::filedes[1], U_STRING_TO_PARAM(*UClientImage_Base::wbuffer))))
data: if (UWebSocket::handleDataFraming(UServer_Base::csocket) == U_WS_STATUS_CODE_OK)
{
UWebSocket::rbuffer->setEmpty();
if (command == U_NULLPTR)
{
on_message(0);
if (bcommand == false) goto handle_data;
if (U_http_info.nResponseCode != HTTP_INTERNAL_ERROR)
{
UWebSocket::rbuffer->setEmpty();
goto loop;
goto data;
}
}
else if (UNotifier::write(UProcess::filedes[1], U_STRING_TO_PARAM(*UClientImage_Base::wbuffer)))
{
UWebSocket::rbuffer->setEmpty();
goto loop;
}
}
}
}
@ -177,7 +197,7 @@ handle_data:
// Send server-side closing handshake
if (UServer_Base::csocket->isOpen() &&
UWebSocket::sendClose())
UWebSocket::sendClose(UServer_Base::csocket))
{
UClientImage_Base::close();
}
@ -186,6 +206,8 @@ handle_data:
UClientImage_Base::setRequestProcessed();
}
if (command == U_NULLPTR) on_message(U_DPAGE_CLOSE);
U_RETURN(U_PLUGIN_HANDLER_PROCESSED);
}
@ -197,8 +219,10 @@ handle_data:
#if defined(U_STDCPP_ENABLE) && defined(DEBUG)
const char* UWebSocketPlugIn::dump(bool reset) const
{
*UObjectIO::os << "on_message " << (void*)on_message << '\n'
<< "command (UCommand " << (void*)command << ')';
*UObjectIO::os << "fd_stderr " << fd_stderr << '\n'
<< "on_message " << (void*)on_message << '\n'
<< "command (UCommand " << (void*)command << ")\n"
<< "penvironment (UString " << (void*)penvironment << ')';
if (reset)
{

View File

@ -111,9 +111,7 @@ int UStreamPlugIn::handlerInit()
bool result = command->execute(U_NULLPTR, (UString*)-1, -1, fd_stderr);
#ifndef U_LOG_DISABLE
UServer_Base::logCommandMsgError(command->getCommand(), true);
#endif
U_SRV_LOG_CMD_MSG_ERR(*command, false);
if (result == false)
{

View File

@ -100,9 +100,7 @@ int UTsaPlugIn::handlerRequest()
UHTTP::setResponse(*UString::str_ctype_tsa, &body);
}
# ifndef U_LOG_DISABLE
UServer_Base::logCommandMsgError(command->getCommand(), true);
# endif
U_SRV_LOG_CMD_MSG_ERR(*command, true);
U_RETURN(U_PLUGIN_HANDLER_PROCESSED);
}

View File

@ -1,3 +1,87 @@
<!--#code
if (UWebSocket::sendData(UWebSocket::message_type, (const unsigned char*)U_STRING_TO_PARAM(*UClientImage_Base::wbuffer)) == false) U_http_info.nResponseCode = HTTP_INTERNAL_ERROR;
<!--#
prototype for Victor Stewart
-->
<!--#declaration
static UWebSocketClient* wsclient;
static vPFi message_for_another_usp;
static void usp_init_modsocket()
{
U_TRACE_NO_PARAM(5, "::usp_init_modsocket()")
U_NEW(UWebSocketClient, wsclient, UWebSocketClient());
}
static void usp_end_modsocket()
{
U_TRACE_NO_PARAM(5, "::usp_end_modsocket()")
#ifdef DEBUG
U_DELETE(wsclient)
#endif
}
static void usp_open_modsocket()
{
U_TRACE_NO_PARAM(0, "::usp_open_modsocket()")
U_DEBUG("usp_open_modsocket(): called");
}
static void usp_close_modsocket()
{
U_TRACE_NO_PARAM(0, "::usp_close_modsocket()")
U_DEBUG("usp_close_modsocket(): called");
}
static bool isMessageForAnotherUSP(const UString& msg)
{
U_TRACE(5, "::isMessageForAnotherUSP(%V)", msg.rep)
// TODO
U_RETURN(false);
}
static bool isMessageForAnotherWebSocket(const UString& msg)
{
U_TRACE(5, "::isMessageForAnotherWebSocket(%V)", msg.rep)
// TODO
U_RETURN(true);
}
-->
<!--#code
U_DEBUG("modsocket(): message %V", UWebSocket::message->rep);
if (isMessageForAnotherUSP(*UWebSocket::message))
{
if (message_for_another_usp == U_NULLPTR)
{
(void) UHTTP::getUSP(U_CONSTANT_TO_PARAM("another_usp"));
U_INTERNAL_ASSERT_POINTER(UHTTP::usp->runDynamicPage)
message_for_another_usp = UHTTP::usp->runDynamicPage;
}
message_for_another_usp(0);
// ...
}
else if (isMessageForAnotherWebSocket(*UWebSocket::message))
{
if (wsclient->connectServer(U_STRING_FROM_CONSTANT("ws://localhost:8888/websocket"))) (void) wsclient->sendMessage(*UWebSocket::message);
// ...
}
else
{
// echo
if (UWebSocket::sendData(UServer_Base::csocket, UWebSocket::message_type, *UWebSocket::message) == false) U_http_info.nResponseCode = HTTP_INTERNAL_ERROR;
}
-->

View File

@ -712,37 +712,56 @@ loop: distance = t.getDistance();
U_INTERNAL_DUMP("declaration = %V", declaration.rep)
bool binit, // usp_init (Server-wide hooks)...
/**
* Server-wide hooks
*
* enum DynamicPageType {
* U_DPAGE_INIT = -1,
* U_DPAGE_RESET = -2,
* U_DPAGE_DESTROY = -3,
* U_DPAGE_SIGHUP = -4,
* U_DPAGE_FORK = -5,
* U_DPAGE_OPEN = -6,
* U_DPAGE_CLOSE = -7 };
*/
bool binit, // usp_init
breset, // usp_reset
bend, // usp_end
bsighup, // usp_sighup
bfork; // usp_fork
bfork, // usp_fork
bopen, // usp_open
bclose; // usp_close
char ptr1[100] = { '\0' };
char ptr2[100] = { '\0' };
char ptr3[100] = { '\0' };
char ptr4[100] = { '\0' };
char ptr5[100] = { '\0' };
const char* ptr6 = "";
const char* ptr7 = "";
char ptr6[100] = { '\0' };
char ptr7[100] = { '\0' };
const char* ptr8 = "";
# ifndef U_CACHE_REQUEST_DISABLE
if (usp.c_char(4) == '#' &&
u__isspace(usp.c_char(5)) &&
u_get_unalignedp32(usp.data()) == U_MULTICHAR_CONSTANT32('<','!','-','-')) // <!--# --> (comment)
{
ptr7 = "\n\tUClientImage_Base::setRequestNoCache();\n\t\n";
ptr8 = "\n\tUClientImage_Base::setRequestNoCache();\n\t\n";
}
# endif
if (declaration)
{
binit = (U_STRING_FIND(declaration, 0, "static void usp_init_") != U_NOT_FOUND);
breset = (U_STRING_FIND(declaration, 0, "static void usp_reset_") != U_NOT_FOUND);
bend = (U_STRING_FIND(declaration, 0, "static void usp_end_") != U_NOT_FOUND);
bsighup = (U_STRING_FIND(declaration, 0, "static void usp_sighup_") != U_NOT_FOUND);
bfork = (U_STRING_FIND(declaration, 0, "static void usp_fork_") != U_NOT_FOUND);
bopen = (U_STRING_FIND(declaration, 0, "static void usp_open_") != U_NOT_FOUND);
bclose = (U_STRING_FIND(declaration, 0, "static void usp_close_") != U_NOT_FOUND);
if (bfork) (void) u__snprintf(ptr5, 100, U_CONSTANT_TO_PARAM("\n\t\tif (param == U_DPAGE_FORK) { usp_fork_%.*s(); return; }\n"), basename_sz, basename_ptr);
if (bsighup) (void) u__snprintf(ptr4, 100, U_CONSTANT_TO_PARAM("\n\t\tif (param == U_DPAGE_SIGHUP) { usp_sighup_%.*s(); return; }\n"), basename_sz, basename_ptr);
if (breset) (void) u__snprintf(ptr2, 100, U_CONSTANT_TO_PARAM("\n\t\tif (param == U_DPAGE_RESET) { usp_reset_%.*s(); return; }\n"), basename_sz, basename_ptr);
if (bend)
{
@ -752,16 +771,24 @@ loop: distance = t.getDistance();
# endif
(void) u__snprintf(ptr3, 100, U_CONSTANT_TO_PARAM("\n\t\tif (param == U_DPAGE_DESTROY) { usp_end_%.*s(); return; }\n"), basename_sz, basename_ptr);
}
if (bsighup) (void) u__snprintf(ptr4, 100, U_CONSTANT_TO_PARAM("\n\t\tif (param == U_DPAGE_SIGHUP) { usp_sighup_%.*s(); return; }\n"), basename_sz, basename_ptr);
if (bfork) (void) u__snprintf(ptr5, 100, U_CONSTANT_TO_PARAM("\n\t\tif (param == U_DPAGE_FORK) { usp_fork_%.*s(); return; }\n"), basename_sz, basename_ptr);
if (bopen) (void) u__snprintf(ptr6, 100, U_CONSTANT_TO_PARAM("\n\t\tif (param == U_DPAGE_OPEN) { usp_open_%.*s(); return; }\n"), basename_sz, basename_ptr);
if (bclose) (void) u__snprintf(ptr7, 100, U_CONSTANT_TO_PARAM("\n\t\tif (param == U_DPAGE_CLOSE) { usp_close_%.*s(); return; }\n"), basename_sz, basename_ptr);
}
else
{
binit =
breset =
bend =
bsighup =
bfork = false;
bfork =
bopen =
bclose = false;
}
U_INTERNAL_DUMP("binit = %b bend = %b bsighup = %b bfork = %b", binit, bend, bsighup, bfork)
U_INTERNAL_DUMP("binit = %b breset = %b bend = %b bsighup = %b bfork = %b bopen = %b bclose = %b", binit, breset, bend, bsighup, bfork, bopen, bclose)
if (binit == false &&
(bsession || bstorage))
@ -787,15 +814,6 @@ loop: distance = t.getDistance();
if (binit) (void) u__snprintf(ptr1, 100, U_CONSTANT_TO_PARAM("\n\t\tif (param == U_DPAGE_INIT) { usp_init_%.*s(); return; }\n"), basename_sz, basename_ptr);
if (binit == false ||
bend == false ||
bsighup == false ||
bfork == false)
{
ptr6 = (bfork ? "\n\t\tif (param > U_DPAGE_FORK) return;\n"
: "\n\t\tif (param >= U_DPAGE_FORK) return;\n");
}
if (bvar)
{
(void) vars.append(U_CONSTANT_TO_PARAM("\n\tuint32_t usp_sz = 0;"
@ -837,6 +855,8 @@ loop: distance = t.getDistance();
"%s"
"%s"
"%s"
"%s"
"\t\treturn;\n"
"\t\t}\n"
"\t\n"
"%v"
@ -863,12 +883,13 @@ loop: distance = t.getDistance();
ptr4,
ptr5,
ptr6,
ptr7,
vcode.rep,
http_header.rep,
output0.rep,
output1.rep,
output2.rep,
ptr7);
ptr8);
UString name(200U);

View File

@ -3676,7 +3676,9 @@ U_NO_EXPORT void UServer_Base::manageCommand(const char* format, uint32_t fmt_si
UString output = UCommand::outputCommand(cmd, U_NULLPTR, -1, fd_stderr);
logCommandMsgError(cmd.data(), true);
#ifdef U_LOG_DISABLE
UServer_Base::logCommandMsgError(cmd.data(), true);
#endif
if (UCommand::exit_value) U_WARNING("command failed: EXIT_VALUE=%d OUTPUT=%V", UCommand::exit_value, output.rep);

View File

@ -198,9 +198,7 @@ int UServices::askToLDAP(UString* pinput, UHashMap<UString>* ptable, const char*
bool result = cmd.execute(pinput, &output, -1, _fd_stderr);
#ifndef U_LOG_DISABLE
UServer_Base::logCommandMsgError(cmd.getCommand(), false);
#endif
U_SRV_LOG_CMD_MSG_ERR(cmd, false);
if (pinput == U_NULLPTR) ptable->clear();

View File

@ -3101,6 +3101,7 @@ U_NO_EXPORT bool UHTTP::checkRequestForHeader()
}
# endif
}
# if defined(USE_LIBSSL) && !defined(U_SERVER_CAPTIVE_PORTAL)
else if (pn[17] == ':') // "If-Modified-Since|Sec-WebSocket-Key:"
{
pn += 17;
@ -3127,6 +3128,7 @@ U_NO_EXPORT bool UHTTP::checkRequestForHeader()
goto next;
}
}
# endif
# ifndef U_LOG_DISABLE
else if (pn[22] == ':') // "X-Http-X-Forwarded-For:"
{
@ -4622,12 +4624,12 @@ from_cache:
}
#endif
#ifndef U_SERVER_CAPTIVE_PORTAL
#if defined(USE_LIBSSL) && !defined(U_SERVER_CAPTIVE_PORTAL)
U_INTERNAL_DUMP("U_http_websocket_len = %u", U_http_websocket_len)
if (U_http_websocket_len)
{
if (UWebSocket::sendAccept() == false)
if (UWebSocket::sendAccept(UServer_Base::csocket) == false)
{
setBadRequest();
@ -4635,6 +4637,8 @@ from_cache:
}
UClientImage_Base::setRequestNoCache();
if (UServer_Base::startParallelization()) U_RETURN(U_PLUGIN_HANDLER_OK); // parent
}
#endif
@ -10630,9 +10634,7 @@ bool UHTTP::processCGIRequest(UCommand* cmd, UHTTP::ucgi* cgi)
if (cgi) (void) UFile::chdir(U_NULLPTR, true);
#ifndef U_LOG_DISABLE
UServer_Base::logCommandMsgError(cmd->getCommand(), false);
#endif
U_SRV_LOG_CMD_MSG_ERR(*cmd, false);
cmd->reset(UClientImage_Base::environment);

View File

@ -16,88 +16,40 @@
#include <ulib/utility/websocket.h>
#include <ulib/net/server/server.h>
#define OPCODE_CONTINUATION 0x0
#define OPCODE_TEXT 0x1
#define OPCODE_BINARY 0x2
#define OPCODE_CLOSE 0x8
#define OPCODE_PING 0x9
#define OPCODE_PONG 0xA
#define U_WS_DATA_FRAMING_MASK 0
#define U_WS_DATA_FRAMING_START 1
#define U_WS_DATA_FRAMING_PAYLOAD_LENGTH 2
#define U_WS_DATA_FRAMING_PAYLOAD_LENGTH_EXT 3
#define U_WS_DATA_FRAMING_EXTENSION_DATA 4
#define U_WS_DATA_FRAMING_APPLICATION_DATA 5
#define U_WS_DATA_FRAMING_CLOSE 6
#define DATA_FRAMING_MASK 0
#define DATA_FRAMING_START 1
#define DATA_FRAMING_PAYLOAD_LENGTH 2
#define DATA_FRAMING_PAYLOAD_LENGTH_EXT 3
#define DATA_FRAMING_EXTENSION_DATA 4
#define DATA_FRAMING_APPLICATION_DATA 5
#define DATA_FRAMING_CLOSE 6
#define U_WS_FRAME_GET_FIN(BYTE) (((BYTE) >> 7) & 0x01)
#define U_WS_FRAME_GET_RSV1(BYTE) (((BYTE) >> 6) & 0x01)
#define U_WS_FRAME_GET_RSV2(BYTE) (((BYTE) >> 5) & 0x01)
#define U_WS_FRAME_GET_RSV3(BYTE) (((BYTE) >> 4) & 0x01)
#define U_WS_FRAME_GET_OPCODE(BYTE) ( (BYTE) & 0x0F)
#define U_WS_FRAME_GET_MASK(BYTE) (((BYTE) >> 7) & 0x01)
#define U_WS_FRAME_GET_PAYLOAD_LEN(BYTE) ( (BYTE) & 0x7F)
#define FRAME_GET_FIN(BYTE) (((BYTE) >> 7) & 0x01)
#define FRAME_GET_RSV1(BYTE) (((BYTE) >> 6) & 0x01)
#define FRAME_GET_RSV2(BYTE) (((BYTE) >> 5) & 0x01)
#define FRAME_GET_RSV3(BYTE) (((BYTE) >> 4) & 0x01)
#define FRAME_GET_OPCODE(BYTE) ( (BYTE) & 0x0F)
#define FRAME_GET_MASK(BYTE) (((BYTE) >> 7) & 0x01)
#define FRAME_GET_PAYLOAD_LEN(BYTE) ( (BYTE) & 0x7F)
#define U_WS_FRAME_SET_FIN(BYTE) (((BYTE) & 0x01) << 7)
#define U_WS_FRAME_SET_OPCODE(BYTE) ((BYTE) & 0x0F)
#define U_WS_FRAME_SET_MASK(BYTE) (((BYTE) & 0x01) << 7)
#define U_WS_FRAME_SET_LENGTH(X64, IDX) (unsigned char)(((uint64_t)(X64) >> ((IDX)*8)) & 0xFF)
#define FRAME_SET_FIN(BYTE) (((BYTE) & 0x01) << 7)
#define FRAME_SET_OPCODE(BYTE) ((BYTE) & 0x0F)
#define FRAME_SET_MASK(BYTE) (((BYTE) & 0x01) << 7)
#define FRAME_SET_LENGTH(X64, IDX) (unsigned char)(((uint64_t)(X64) >> ((IDX)*8)) & 0xFF)
#define WEBSOCKET_GUID "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
#define WEBSOCKET_GUID_LEN 36
#define U_WS_GUID "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
#define U_WS_GUID_LEN 36
int UWebSocket::status_code;
int UWebSocket::message_type;
UString* UWebSocket::rbuffer;
UString* UWebSocket::message;
uint32_t UWebSocket::max_message_size;
const char* UWebSocket::upgrade_settings;
UWebSocket::WebSocketFrameData UWebSocket::control_frame = { U_NULLPTR, 0, 1, 8, 0 };
UWebSocket::WebSocketFrameData UWebSocket::message_frame = { U_NULLPTR, 0, 1, 0, 0 };
bool UWebSocket::sendAccept()
{
U_TRACE_NO_PARAM(0, "UWebSocket::sendAccept()")
U_INTERNAL_ASSERT_MAJOR(U_http_websocket_len, 0)
// In order to establish a websocket connection, a client (a web browser) sends a HTTP GET request with a number of HTTP headers. Among those
// headers there is the Sec-WebSocket-Key header, which contains a handshake key. According to the WebSocket protocol, the server should:
//
// 1) Concatenate the handshake key with the magic guid {258EAFA5-E914-47DA-95CA-C5AB0DC85B11}
// 2) Take the SHA1 hash of the concatenation result
// 3) Send the base64 equivalent of the hash in HTTP response to the client
unsigned char challenge[128];
U_MEMCPY(challenge, upgrade_settings, U_http_websocket_len);
U_MEMCPY(challenge+U_http_websocket_len, WEBSOCKET_GUID, WEBSOCKET_GUID_LEN);
// SHA1(challenge)
UString accept(U_CAPACITY);
UServices::generateDigest(U_HASH_SHA1, 0, challenge, U_http_websocket_len + WEBSOCKET_GUID_LEN, accept, true);
UClientImage_Base::wbuffer->snprintf(U_CONSTANT_TO_PARAM("HTTP/1.1 101 Switching Protocols\r\n"
"Upgrade: websocket\r\n"
"Connection: Upgrade\r\n"
"Sec-WebSocket-Accept: %v\r\n\r\n"), accept.rep);
if (USocketExt::write(UServer_Base::csocket, *UClientImage_Base::wbuffer, UServer_Base::timeoutMS))
{
status_code = STATUS_CODE_INTERNAL_ERROR;
message_type = MESSAGE_TYPE_INVALID;
if (max_message_size == 0) max_message_size = U_STRING_MAX_SIZE;
U_RETURN(true);
}
U_RETURN(false);
}
void UWebSocket::checkForInitialData()
{
U_TRACE_NO_PARAM(0, "UWebSocket::checkForInitialData()")
@ -113,22 +65,62 @@ void UWebSocket::checkForInitialData()
{
// we have read more data than necessary...
const char* ptr = UClientImage_Base::rbuffer->c_pointer(UClientImage_Base::size_request);
(void) rbuffer->append(ptr, sz - UClientImage_Base::size_request);
(void) rbuffer->append(UClientImage_Base::rbuffer->c_pointer(UClientImage_Base::size_request), sz - UClientImage_Base::size_request);
U_INTERNAL_DUMP("rbuffer(%u) = %V", rbuffer->size(), rbuffer->rep)
}
}
bool UWebSocket::sendAccept(USocket* socket)
{
U_TRACE(0, "UWebSocket::sendAccept(%p)", socket)
U_INTERNAL_ASSERT_MAJOR(U_http_websocket_len, 0)
// In order to establish a websocket connection, a client (a web browser) sends a HTTP GET request with a number of HTTP headers. Among those
// headers there is the Sec-WebSocket-Key header, which contains a handshake key. According to the WebSocket protocol, the server should:
//
// 1) Concatenate the handshake key with the magic guid {258EAFA5-E914-47DA-95CA-C5AB0DC85B11}
// 2) Take the SHA1 hash of the concatenation result
// 3) Send the base64 equivalent of the hash in HTTP response to the client
unsigned char challenge[128];
U_MEMCPY(challenge, upgrade_settings, U_http_websocket_len);
U_MEMCPY(challenge+U_http_websocket_len, U_WS_GUID, U_WS_GUID_LEN);
// SHA1(challenge)
UString accept(U_CAPACITY), buffer(U_CAPACITY);
UServices::generateDigest(U_HASH_SHA1, 0, challenge, U_http_websocket_len + U_WS_GUID_LEN, accept, true);
buffer.snprintf(U_CONSTANT_TO_PARAM("HTTP/1.1 101 Switching Protocols\r\n"
"Upgrade: websocket\r\n"
"Connection: Upgrade\r\n"
"Sec-WebSocket-Accept: %v\r\n\r\n"), accept.rep);
if (USocketExt::write(socket, buffer, UServer_Base::timeoutMS))
{
status_code = U_WS_STATUS_CODE_INTERNAL_ERROR;
message_type = U_WS_MESSAGE_TYPE_INVALID;
if (max_message_size == 0) max_message_size = U_STRING_MAX_SIZE;
U_RETURN(true);
}
U_RETURN(false);
}
/**
* So, WebSockets presents a sequence of infinitely long byte streams
* with a termination indicator (the FIN bit in the frame header) and
* not a message based interface as you might initially believe. Given
* that a general purpose protocol handler can only work in terms of
* partial frames, we effectively have a stream based protocol with
* lots of added complexity to provide the illusion of a message based
* @see: http://tools.ietf.org/html/rfc6455#section-5.2 Base Framing Protocol
*
* So, WebSockets presents a sequence of infinitely long byte streams with a termination indicator (the FIN bit in the frame header) and
* not a message based interface as you might initially believe. Given that a general purpose protocol handler can only work in terms of
* partial frames, we effectively have a stream based protocol with lots of added complexity to provide the illusion of a message based
* protocol that can actually only ever be dealt with as a stream of bytes
*
* +-+-+-+-+-------+-+-------------+-------------------------------+
* 0 1 2 3 |
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 |
@ -159,13 +151,13 @@ int UWebSocket::handleDataFraming(USocket* socket)
WebSocketFrameData* frame = &UWebSocket::control_frame;
unsigned char fin = 0, opcode = 0xFF, mask[4] = { 0, 0, 0, 0 };
int32_t extension_bytes_remaining = 0, payload_length = 0, mask_offset = 0;
int framing_state = DATA_FRAMING_START, payload_length_bytes_remaining = 0, mask_index = 0, masking = 0;
int framing_state = U_WS_DATA_FRAMING_START, payload_length_bytes_remaining = 0, mask_index = 0, masking = 0;
loop:
if (rbuffer->empty() &&
USocketExt::read(socket, *rbuffer, U_SINGLE_READ, UServer_Base::timeoutMS) == false)
{
status_code = STATUS_CODE_INTERNAL_ERROR;
status_code = U_WS_STATUS_CODE_INTERNAL_ERROR;
U_RETURN(status_code);
}
@ -179,35 +171,35 @@ loop:
switch (framing_state)
{
case DATA_FRAMING_START: // 1
case U_WS_DATA_FRAMING_START: // 1
{
// Since we don't currently support any extensions, the reserve bits must be 0
if ((FRAME_GET_RSV1(block[block_offset]) != 0) ||
(FRAME_GET_RSV2(block[block_offset]) != 0) ||
(FRAME_GET_RSV3(block[block_offset]) != 0))
if ((U_WS_FRAME_GET_RSV1(block[block_offset]) != 0) ||
(U_WS_FRAME_GET_RSV2(block[block_offset]) != 0) ||
(U_WS_FRAME_GET_RSV3(block[block_offset]) != 0))
{
// framing_state = DATA_FRAMING_CLOSE; // 6
// framing_state = U_WS_DATA_FRAMING_CLOSE; // 6
status_code = STATUS_CODE_PROTOCOL_ERROR;
status_code = U_WS_STATUS_CODE_PROTOCOL_ERROR;
U_RETURN(status_code);
}
fin = FRAME_GET_FIN( block[block_offset]);
opcode = FRAME_GET_OPCODE(block[block_offset++]);
fin = U_WS_FRAME_GET_FIN( block[block_offset]);
opcode = U_WS_FRAME_GET_OPCODE(block[block_offset++]);
U_INTERNAL_DUMP("fin = %d opcode = %X", fin, opcode)
framing_state = DATA_FRAMING_PAYLOAD_LENGTH; // 2
framing_state = U_WS_DATA_FRAMING_PAYLOAD_LENGTH; // 2
if (opcode >= 0x8) // Control frame
{
if (fin == 0)
{
// framing_state = DATA_FRAMING_CLOSE; // 6
// framing_state = U_WS_DATA_FRAMING_CLOSE; // 6
status_code = STATUS_CODE_PROTOCOL_ERROR;
status_code = U_WS_STATUS_CODE_PROTOCOL_ERROR;
U_RETURN(status_code);
}
@ -224,9 +216,9 @@ loop:
{
if (frame->fin == 0)
{
// framing_state = DATA_FRAMING_CLOSE; // 6
// framing_state = U_WS_DATA_FRAMING_CLOSE; // 6
status_code = STATUS_CODE_PROTOCOL_ERROR;
status_code = U_WS_STATUS_CODE_PROTOCOL_ERROR;
U_RETURN(status_code);
}
@ -237,9 +229,9 @@ loop:
else if (frame->fin ||
((opcode = frame->opcode) == 0))
{
// framing_state = DATA_FRAMING_CLOSE; // 6
// framing_state = U_WS_DATA_FRAMING_CLOSE; // 6
status_code = STATUS_CODE_PROTOCOL_ERROR;
status_code = U_WS_STATUS_CODE_PROTOCOL_ERROR;
U_RETURN(status_code);
}
@ -257,10 +249,10 @@ loop:
/* FALLTHRU */
case DATA_FRAMING_PAYLOAD_LENGTH: // 2
case U_WS_DATA_FRAMING_PAYLOAD_LENGTH: // 2
{
payload_length = FRAME_GET_PAYLOAD_LEN(block[block_offset]);
masking = FRAME_GET_MASK( block[block_offset++]);
payload_length = U_WS_FRAME_GET_PAYLOAD_LEN(block[block_offset]);
masking = U_WS_FRAME_GET_MASK( block[block_offset++]);
U_INTERNAL_DUMP("masking = %d payload_length = %d", masking, payload_length)
@ -283,14 +275,14 @@ loop:
((opcode >= 0x8) && // Control opcodes cannot have a payload larger than 125 bytes
(payload_length_bytes_remaining != 0)))
{
// framing_state = DATA_FRAMING_CLOSE; // 6
// framing_state = U_WS_DATA_FRAMING_CLOSE; // 6
status_code = STATUS_CODE_PROTOCOL_ERROR;
status_code = U_WS_STATUS_CODE_PROTOCOL_ERROR;
U_RETURN(status_code);
}
framing_state = DATA_FRAMING_PAYLOAD_LENGTH_EXT; // 3
framing_state = U_WS_DATA_FRAMING_PAYLOAD_LENGTH_EXT; // 3
if (block_offset >= block_size) goto next;
@ -299,7 +291,7 @@ loop:
/* FALLTHRU */
case DATA_FRAMING_PAYLOAD_LENGTH_EXT: // 3
case U_WS_DATA_FRAMING_PAYLOAD_LENGTH_EXT: // 3
{
while ((payload_length_bytes_remaining > 0) &&
(block_offset < block_size))
@ -317,21 +309,21 @@ loop:
{
U_SRV_LOG_WITH_ADDR("Got frame with payload greater than maximum frame buffer size: (%u > %u) from", payload_length, max_message_size);
// framing_state = DATA_FRAMING_CLOSE; // 6
// framing_state = U_WS_DATA_FRAMING_CLOSE; // 6
status_code = STATUS_CODE_MESSAGE_TOO_LARGE; // Invalid payload length
status_code = U_WS_STATUS_CODE_MESSAGE_TOO_LARGE; // Invalid payload length
U_RETURN(status_code);
}
if (masking == 0)
{
framing_state = DATA_FRAMING_EXTENSION_DATA; // 4
framing_state = U_WS_DATA_FRAMING_EXTENSION_DATA; // 4
break;
}
framing_state = DATA_FRAMING_MASK; // 0
framing_state = U_WS_DATA_FRAMING_MASK; // 0
}
if (block_offset >= block_size) goto next;
@ -341,7 +333,7 @@ loop:
/* FALLTHRU */
case DATA_FRAMING_MASK: // 0
case U_WS_DATA_FRAMING_MASK: // 0
{
U_INTERNAL_DUMP("mask_index = %d", mask_index)
@ -353,7 +345,7 @@ loop:
mask_index = 0;
mask_offset = 0;
framing_state = DATA_FRAMING_EXTENSION_DATA; // 4
framing_state = U_WS_DATA_FRAMING_EXTENSION_DATA; // 4
if ((mask[0] == 0) &&
(mask[1] == 0) &&
@ -368,7 +360,7 @@ loop:
/* FALLTHRU */
case DATA_FRAMING_EXTENSION_DATA: // 4
case U_WS_DATA_FRAMING_EXTENSION_DATA: // 4
{
// Deal with extension data when we support them -- FIXME
@ -378,12 +370,12 @@ loop:
{
if (payload_length > 0)
{
(void) UClientImage_Base::wbuffer->reserve(frame->application_data_offset + payload_length);
(void) message->setBuffer(frame->application_data_offset + payload_length);
frame->application_data = (unsigned char*) UClientImage_Base::wbuffer->data();
frame->application_data = (unsigned char*) message->data();
}
framing_state = DATA_FRAMING_APPLICATION_DATA; // 5
framing_state = U_WS_DATA_FRAMING_APPLICATION_DATA; // 5
}
U_INTERNAL_DUMP("framing_state = %d", framing_state)
@ -391,7 +383,7 @@ loop:
/* FALLTHRU */
case DATA_FRAMING_APPLICATION_DATA: // 5
case U_WS_DATA_FRAMING_APPLICATION_DATA: // 5
{
int32_t block_length = block_size - block_offset,
block_data_length = (payload_length > block_length ? block_length
@ -404,7 +396,7 @@ loop:
{
int32_t i;
if (opcode == OPCODE_TEXT)
if (opcode == U_WS_OPCODE_TEXT)
{
unsigned int utf8_state = frame->utf8_state;
@ -440,7 +432,7 @@ loop:
{
U_MEMCPY(&application_data[application_data_offset], &block[block_offset], block_data_length);
if (opcode == OPCODE_TEXT)
if (opcode == U_WS_OPCODE_TEXT)
{
unsigned int utf8_state = frame->utf8_state;
int32_t i, application_data_end = application_data_offset + block_data_length;
@ -468,51 +460,56 @@ loop:
if (payload_length == 0)
{
message_type = MESSAGE_TYPE_INVALID;
message_type = U_WS_MESSAGE_TYPE_INVALID;
switch (opcode)
{
case OPCODE_TEXT:
case U_WS_OPCODE_TEXT:
{
if ((fin &&
(frame->utf8_state != 0)) ||
(frame->utf8_state == 1))
{
// framing_state = DATA_FRAMING_CLOSE; // 6
// framing_state = U_WS_DATA_FRAMING_CLOSE; // 6
status_code = STATUS_CODE_INVALID_UTF8;
status_code = U_WS_STATUS_CODE_INVALID_UTF8;
U_RETURN(status_code);
}
message_type = MESSAGE_TYPE_TEXT;
message_type = U_WS_MESSAGE_TYPE_TEXT;
}
break;
case OPCODE_BINARY: message_type = MESSAGE_TYPE_BINARY; break;
case U_WS_OPCODE_BINARY: message_type = U_WS_MESSAGE_TYPE_BINARY; break;
case OPCODE_CLOSE:
case U_WS_OPCODE_CLOSE:
{
// framing_state = DATA_FRAMING_CLOSE; // 6
// framing_state = U_WS_DATA_FRAMING_CLOSE; // 6
status_code = STATUS_CODE_OK;
status_code = U_WS_STATUS_CODE_OK;
U_RETURN(status_code);
}
case OPCODE_PING:
case U_WS_OPCODE_PING:
{
(void) sendData(MESSAGE_TYPE_PONG, application_data, application_data_offset);
if (sendControlFrame(socket, U_WS_OPCODE_PONG, application_data, application_data_offset) == false)
{
status_code = U_WS_STATUS_CODE_PROTOCOL_ERROR;
U_RETURN(status_code);
}
}
break;
case OPCODE_PONG: break;
case U_WS_OPCODE_PONG: break;
default:
{
// framing_state = DATA_FRAMING_CLOSE; // 6
// framing_state = U_WS_DATA_FRAMING_CLOSE; // 6
status_code = STATUS_CODE_PROTOCOL_ERROR;
status_code = U_WS_STATUS_CODE_PROTOCOL_ERROR;
U_RETURN(status_code);
}
@ -522,17 +519,17 @@ loop:
{
U_INTERNAL_DUMP("framing_state = %d message_type = %d status_code = %d", framing_state, message_type, status_code)
if (message_type != MESSAGE_TYPE_INVALID)
if (message_type != U_WS_MESSAGE_TYPE_INVALID)
{
U_INTERNAL_ASSERT_EQUALS(framing_state, DATA_FRAMING_APPLICATION_DATA)
U_INTERNAL_ASSERT_EQUALS(framing_state, U_WS_DATA_FRAMING_APPLICATION_DATA)
UClientImage_Base::wbuffer->size_adjust_force(application_data_offset);
message->size_adjust_force(application_data_offset);
U_SRV_LOG_WITH_ADDR("received websocket data (%u+%u bytes) %V from",
ncount - UClientImage_Base::wbuffer->size(),
UClientImage_Base::wbuffer->size(), UClientImage_Base::wbuffer->rep)
ncount - message->size(),
message->size(), message->rep)
status_code = STATUS_CODE_OK;
status_code = U_WS_STATUS_CODE_OK;
U_RETURN(status_code);
}
@ -541,20 +538,20 @@ loop:
application_data_offset = 0;
}
framing_state = DATA_FRAMING_START; // 1
framing_state = U_WS_DATA_FRAMING_START; // 1
}
frame->application_data_offset = application_data_offset;
}
break;
// case DATA_FRAMING_CLOSE: block_offset = block_size; break;
// case U_WS_DATA_FRAMING_CLOSE: block_offset = block_size; break;
default:
{
// framing_state = DATA_FRAMING_CLOSE; // 6
// framing_state = U_WS_DATA_FRAMING_CLOSE; // 6
status_code = STATUS_CODE_PROTOCOL_ERROR;
status_code = U_WS_STATUS_CODE_PROTOCOL_ERROR;
U_RETURN(status_code);
}
@ -564,69 +561,110 @@ loop:
next:
U_INTERNAL_ASSERT(block_offset >= block_size)
U_INTERNAL_ASSERT_DIFFERS(framing_state, DATA_FRAMING_CLOSE) // 6
U_INTERNAL_ASSERT_DIFFERS(framing_state, U_WS_DATA_FRAMING_CLOSE) // 6
rbuffer->setEmpty();
goto loop;
}
bool UWebSocket::sendData(int type, const unsigned char* buffer, uint32_t buffer_size)
bool UWebSocket::sendData(USocket* socket, int type, const char* data, uint32_t len)
{
U_TRACE(0, "UWebSocket::sendData(%d,%p,%u)", type, buffer, buffer_size)
U_TRACE(0, "UWebSocket::sendData(%p,%d,%.*S,%u)", socket, type, len, data, len)
uint32_t pos = 0;
unsigned char opcode, header[32];
uint32_t payload_length = (buffer ? buffer_size : 0);
uint8_t opcode, masking_key[4];
uint32_t header_length = 6U + (len > 125U ? 2U : 0) + (len > 0xffff ? 8U : 0), ncount = header_length + len;
UString tmp(ncount);
unsigned char* header = (unsigned char*)tmp.data();
*((uint32_t*)masking_key) = u_get_num_random(0);
switch (type)
{
case MESSAGE_TYPE_TEXT:
case MESSAGE_TYPE_INVALID:
opcode = OPCODE_TEXT;
case U_WS_MESSAGE_TYPE_TEXT:
case U_WS_MESSAGE_TYPE_INVALID:
opcode = U_WS_OPCODE_TEXT;
break;
case MESSAGE_TYPE_PING: opcode = OPCODE_PING; break;
case MESSAGE_TYPE_PONG: opcode = OPCODE_PONG; break;
case MESSAGE_TYPE_BINARY: opcode = OPCODE_BINARY; break;
case U_WS_MESSAGE_TYPE_PING: opcode = U_WS_OPCODE_PING; break;
case U_WS_MESSAGE_TYPE_PONG: opcode = U_WS_OPCODE_PONG; break;
case U_WS_MESSAGE_TYPE_BINARY: opcode = U_WS_OPCODE_BINARY; break;
case MESSAGE_TYPE_CLOSE:
case U_WS_MESSAGE_TYPE_CLOSE:
default:
opcode = OPCODE_CLOSE;
opcode = U_WS_OPCODE_CLOSE;
break;
}
header[pos++] = FRAME_SET_FIN(1) | FRAME_SET_OPCODE(opcode);
header[0] = (opcode | 0x80);
if (payload_length < 126) header[pos++] = FRAME_SET_MASK(0) | FRAME_SET_LENGTH(payload_length, 0);
if (len <= 125)
{
header[1] = (len | 0x80);
u_put_unalignedp32(header+2, *((uint32_t*)masking_key));
}
else if (len > 125 &&
len <= 0xffff) // 125 && 65535
{
header[1] = (126 | 0x80);
u_put_unalignedp16(header+2, htons(len));
u_put_unalignedp32(header+4, *((uint32_t*)masking_key));
}
else if (len > 0xffff &&
len <= 0xffffffff)
{
header[1] = (127 | 0x80);
u_put_unalignedp64(header+2, htonl(len));
u_put_unalignedp32(header+10, *((uint32_t*)masking_key));
}
else
{
if (payload_length < 65536) header[pos++] = FRAME_SET_MASK(0) | 126;
else
{
header[pos++] = FRAME_SET_MASK(0) | 127;
header[pos++] = 0; // FRAME_SET_LENGTH(payload_length, 7);
header[pos++] = 0; // FRAME_SET_LENGTH(payload_length, 6);
header[pos++] = 0; // FRAME_SET_LENGTH(payload_length, 5);
header[pos++] = 0; // FRAME_SET_LENGTH(payload_length, 4);
header[pos++] = FRAME_SET_LENGTH(payload_length, 3);
header[pos++] = FRAME_SET_LENGTH(payload_length, 2);
}
status_code = U_WS_STATUS_CODE_MESSAGE_TOO_LARGE;
header[pos++] = FRAME_SET_LENGTH(payload_length, 1);
header[pos++] = FRAME_SET_LENGTH(payload_length, 0);
U_RETURN(false);
}
U_SRV_LOG_WITH_ADDR("send websocket data (%u+%u bytes) %.*S to", pos, buffer_size, buffer_size, buffer)
for (uint32_t i = 0; i < len; ++i)
{
header[6+i] = (data[i] ^ masking_key[i % 4]) & 0xff;
}
struct iovec iov[2] = { { (caddr_t)header, pos },
{ (caddr_t)buffer, payload_length } };
U_SRV_LOG_WITH_ADDR("send websocket data (%u+%u bytes) %.*S to", header_length, len, len, data)
int iBytesWrite = (payload_length
? (pos += payload_length, USocketExt::writev(UServer_Base::csocket, iov, 2, pos, UServer_Base::timeoutMS))
: USocketExt::write( UServer_Base::csocket, (const char*)header, pos, UServer_Base::timeoutMS));
if (iBytesWrite == (int)pos) U_RETURN(true);
if (USocketExt::write(socket, (const char*)header, ncount, UServer_Base::timeoutMS) == ncount) U_RETURN(true);
U_RETURN(false);
}
bool UWebSocket::sendControlFrame(USocket* socket, int opcode, const unsigned char* payload, uint32_t payload_length)
{
U_TRACE(0, "UWebSocket::sendControlFrame(%p,%d,%.*S,%u)", socket, opcode, payload_length, payload, payload_length)
uint8_t masking_key[4];
uint32_t ncount = 6U + payload_length;
UString tmp(ncount);
unsigned char* header = (unsigned char*)tmp.data();
*((uint32_t*)masking_key) = u_get_num_random(0);
header[0] = ( opcode | 0x80);
header[1] = (payload_length | 0x80);
u_put_unalignedp32(header+2, *((uint32_t*)masking_key));
for (uint32_t i = 0; i < payload_length; ++i)
{
header[6+i] = (payload[i] ^ masking_key[i % 4]) & 0xff;
}
U_SRV_LOG_WITH_ADDR("send control frame(%d) (6+%u bytes) %.*S to", opcode, payload_length, payload_length, payload)
if (USocketExt::write(socket, (const char*)header, ncount, UServer_Base::timeoutMS) == ncount) U_RETURN(true);
U_RETURN(false);
}

View File

@ -91,7 +91,7 @@ kill_server userver_tcp
$SLEEP
pkill userver_tcp 2>/dev/null
cat err/userver_tcp.err >> err/webserver_proxy.err
cat err/userver_tcp.err > err/webserver_proxy.err
rm err/userver_tcp.err
# Test against expected output

View File

@ -2,44 +2,49 @@
. ../.function
rm -f web_socket.log \
/tmp/UWebSocketPlugIn.err \
out/userver_tcp.out err/userver_tcp.err \
trace.*userver_tcp*.[0-9]* object.*userver_tcp*.[0-9]* stack.*userver_tcp*.[0-9]*
rm -f /tmp/web_socket.log \
/tmp/UWebSocketPlugIn.err \
out/web_socket.out err/userver_tcp.err \
/tmp/trace.*userver_tcp*.[0-9]* /tmp/object.*userver_tcp*.[0-9]* /tmp/stack.*userver_tcp*.[0-9]*
UTRACE="0 50M 0"
#UOBJDUMP="0 1M 10"
UTRACE_SIGNAL="0 50M 0"
UTRACE_FOLDER=/tmp
TMPDIR=/tmp
#UOBJDUMP="0 10M 100"
#USIMERR="error.sim"
export UTRACE UOBJDUMP USIMERR
#UMEMUSAGE=yes
export UTRACE UOBJDUMP USIMERR UTRACE_SIGNAL UMEMUSAGE UTRACE_FOLDER TMPDIR
cat <<EOF >web_socket_sh.cfg
cat <<EOF >inp/webserver.cfg
userver {
PORT 8787
MAX_KEEP_ALIVE 6
RUN_AS_USER apache
PID_FILE docroot/web_socket_sh.pid
LOG_FILE web_socket.log
PID_FILE /tmp/web_socket.pid
LOG_FILE /tmp/web_socket.log
LOG_FILE_SZ 1M
LOG_MSG_SIZE -1
PLUGIN "socket http"
DOCUMENT_ROOT docroot
DOCUMENT_ROOT websocket
PLUGIN_DIR ../../../src/ulib/net/server/plugin/.libs
ORM_DRIVER_DIR ../../../src/ulib/orm/driver/.libs
PREFORK_CHILD 1
}
socket {
COMMAND ../my_websocket.sh
}
EOF
(cd websocket; ln -sf ../../../src/ulib/net/server/plugin/usp/.libs/modsocket.so)
DIR_CMD="../../examples/userver"
check_for_netcat
#STRACE=$TRUSS
start_prg_background userver_tcp -c web_socket_sh.cfg
start_prg_background userver_tcp -c inp/webserver.cfg
#$SLEEP
#kill_prg userver_tcp TERM
wait_server_ready localhost 8787
$SLEEP
send_req $NCAT localhost 8787 inp/http/websocket.req web_socket 3 kill
$SLEEP
kill_prg userver_tcp TERM
mv err/userver_tcp.err err/web_socket.err
mv err/userver_tcp.err /tmp/web_socket.err
echo "PID = `cat docroot/web_socket_sh.pid`"
#echo "PID = `cat /tmp/web_socket.pid`"

View File

@ -2,34 +2,52 @@
. ../.function
# set -x
## web_socket.test -- Test web socket feature
start_msg web_socket
DOC_ROOT=websocket
rm -f $DOC_ROOT/web_socket.log \
/tmp/UWebSocketPlugIn.err \
out/userver_tcp.out err/userver_tcp.err \
rm -f /tmp/web_socket*.log /tmp/UWebSocketPlugIn.err out/userver_tcp.out err/userver_tcp.err \
trace.*userver_*.[0-9]* object.*userver_*.[0-9]* stack.*userver_*.[0-9]* mempool.*userver_*.[0-9]* \
/tmp/trace.*userver_*.[0-9]* /tmp/object.*userver_*.[0-9]* /tmp/stack.*userver_*.[0-9]* /tmp/mempool.*userver_*.[0-9]* \
$DOC_ROOT/trace.*userver_*.[0-9]* $DOC_ROOT/object.*userver_*.[0-9]* $DOC_ROOT/stack.*userver_*.[0-9]* $DOC_ROOT/mempool.*userver_*.[0-9]*
#UTRACE="0 50M 0"
#UOBJDUMP="0 50M 1000"
#UTRACE="0 100M 0"
UTRACE_FOLDER=/tmp
TMPDIR=/tmp
#UOBJDUMP="0 10M 100"
#USIMERR="error.sim"
export UTRACE UOBJDUMP USIMERR
#UMEMUSAGE=yes
export UTRACE UOBJDUMP USIMERR UTRACE_SIGNAL UMEMUSAGE UTRACE_FOLDER TMPDIR
cat <<EOF >inp/webserver.cfg
userver {
PORT 8787
RUN_AS_USER apache
MAX_KEEP_ALIVE 6
LOG_FILE web_socket.log
LOG_FILE /tmp/web_socket.log
LOG_FILE_SZ 1M
LOG_MSG_SIZE -1
PID_FILE /tmp/userver_tcp.pid
PLUGIN "socket http"
DOCUMENT_ROOT websocket
PLUGIN_DIR ../../../src/ulib/net/server/plugin/.libs
ORM_DRIVER_DIR ../../../src/ulib/orm/driver/.libs
PREFORK_CHILD 1
}
EOF
cat <<EOF >inp/webserver_proxy.cfg
userver {
PORT 8888
LOG_FILE /tmp/webserver_proxy.log
LOG_FILE_SZ 10M
LOG_MSG_SIZE -1
PID_FILE /tmp/userver_tcp_proxy.pid
PREFORK_CHILD 0
DOCUMENT_ROOT python
PLUGIN "socket http"
PLUGIN_DIR ../../../src/ulib/net/server/plugin/.libs
}
socket {
COMMAND ../my_websocket.sh
@ -42,14 +60,21 @@ check_for_netcat
#STRACE=$TRUSS
start_prg_background userver_tcp -c inp/webserver.cfg
wait_server_ready localhost 8787
start_prg_background userver_tcp -c inp/webserver_proxy.cfg
wait_server_ready localhost 8888
sync
#echo "PID1 = `cat /tmp/userver_tcp.pid`"
#echo "PID2 = `cat /tmp/userver_tcp_proxy.pid`"
send_req $NCAT localhost 8787 inp/http/websocket.req web_socket 3 kill
$SLEEP
kill_prg userver_tcp TERM
mv err/userver_tcp.err err/web_socket.err
kill_prg userver_tcp TERM
$SLEEP
pkill userver_tcp 2>/dev/null
mv err/userver_tcp.err err/websocket.err
# Test against expected output
test_output_wc l web_socket