109 #pragma pack(push, 1) 125 memset(
this, 0,
sizeof(*
this) );
143 memset(
this, 0,
sizeof(*
this) );
146 template <
typename _Ty >
149 return reinterpret_cast<_Ty*
>(
this + 1 );
154 #pragma pack(push, 2) 163 memset(
this, 0,
sizeof(*
this) );
166 template <
typename _Ty >
169 return reinterpret_cast<_Ty*
>(
this + 1 );
180 memset(
this, 0,
sizeof(*
this) );
183 template <
typename _Ty >
186 return reinterpret_cast<_Ty*
>(
this + 1 );
198 memset(
this, 0,
sizeof(*
this) );
201 template <
typename _Ty >
204 return reinterpret_cast<_Ty*
>(
this + 1 );
215 memset(
this, 0,
sizeof(*
this) );
218 template <
typename _Ty >
221 return reinterpret_cast<_Ty*
>(
this + 1 );
233 memset(
this, 0,
sizeof(*
this) );
236 template <
typename _Ty >
239 return reinterpret_cast<_Ty*
>(
this + 1 );
247 template <
typename _Ty >
250 return reinterpret_cast<_Ty*
>(
this + 1 );
283 errCode =
htont(errCode);
284 data.
append( &errCode,
sizeof(errCode) );
307 :
ClientCtx( clientId, clientEpStr, clientSockPtr ), url(
http::Url::urlSimple), config(nullptr), isWebSocketWrapper(false), websocket(this)
312 if ( !this->config || this->config->outputVerbose )
327 template <
class _ClientCtx = WsHttpClientCtx >
334 using MessageHandlerFunction = std::function< void( ClientCtxSharedPointer clientCtxPtr, winux::AnsiString const & data, int messageType ) >;
335 using CloseHandlerFunction = std::function< void( ClientCtxSharedPointer clientCtxPtr, winux::uint16 errCode, winux::AnsiString const & errStr ) >;
336 using ErrorHandlerFunction = std::function< void( ClientCtxSharedPointer clientCtxPtr, WebSocketErrorCode ec ) >;
338 using ResponseHandlerFunction = std::function< void ( ClientCtxSharedPointer & clientCtxPtr, http::Header const & reqHdr, http::Url const & url, http::Header & rspHdr, std::ostream & rspOut ) >;
343 Server<_ClientCtx>( ip::
EndPoint( confObj.serverIp, confObj.serverPort ), confObj.threadCount, confObj.listenBacklog ),
345 _cache(confObj.cacheLifeTime)
350 Server<_ClientCtx>( ip::
EndPoint( serverIp, port ), threadCount, listenBacklog ),
351 config( serverIp, port, threadCount, listenBacklog, durationSec ),
352 _cache(config.cacheLifeTime)
371 clientCtxPtr->config = &this->config;
380 int rc = clientCtxPtr->clientSockPtr->recvWaitUntilTarget(
382 &clientCtxPtr->forClient.data,
383 &clientCtxPtr->forClient.extraData,
384 &clientCtxPtr->forClient.hadBytes,
385 &clientCtxPtr->forClient.startpos,
386 &clientCtxPtr->forClient.pos,
387 this->config.durationSec,
389 [&clientCtxPtr] (
int had,
void* ) {
390 clientCtxPtr->forClient.retryCount = 0;
394 if ( clientCtxPtr->forClient.pos != -1 )
397 clientCtxPtr->requestHeaderStr = clientCtxPtr->forClient.data.toAnsi();
398 clientCtxPtr->requestHeader.clear();
399 clientCtxPtr->requestHeader.parse(clientCtxPtr->requestHeaderStr);
401 clientCtxPtr->forClient.resetStatus();
402 clientCtxPtr->forClient.data = std::move(clientCtxPtr->forClient.extraData);
404 int contentLength =
static_cast<http::Header&
>(clientCtxPtr->requestHeader).getHeader<int>(
"Content-Length");
405 clientCtxPtr->forClient.targetBytes = contentLength - clientCtxPtr->forClient.data.getSize();
406 if ( clientCtxPtr->forClient.targetBytes > 0 )
414 clientCtxPtr->requestBody = std::move(clientCtxPtr->forClient.data);
420 else if ( rcWait == 0 )
422 clientCtxPtr->forClient.retryCount++;
423 if ( (
int)clientCtxPtr->forClient.retryCount < this->config.retryCount )
432 this->removeClient(clientCtxPtr->clientId);
439 this->removeClient(clientCtxPtr->clientId);
447 int rc = clientCtxPtr->clientSockPtr->recvWaitUntilSize(
448 clientCtxPtr->forClient.targetBytes,
449 &clientCtxPtr->forClient.data,
450 &clientCtxPtr->forClient.hadBytes,
451 this->config.durationSec,
453 [&clientCtxPtr] (
int had,
void* ) {
454 clientCtxPtr->forClient.retryCount = 0;
458 if ( clientCtxPtr->forClient.hadBytes == clientCtxPtr->forClient.targetBytes )
461 clientCtxPtr->requestBody = std::move(clientCtxPtr->forClient.data);
462 clientCtxPtr->forClient.resetStatus();
467 else if ( rcWait == 0 )
469 clientCtxPtr->forClient.retryCount++;
470 if ( (
int)clientCtxPtr->forClient.retryCount < this->config.retryCount )
479 this->removeClient(clientCtxPtr->clientId);
486 this->removeClient(clientCtxPtr->clientId);
494 if ( this->config.
outputVerbose ) std::cout << clientCtxPtr->requestHeaderStr;
498 std::stringbuf rspBuf;
499 std::ostream rspOut(&rspBuf);
502 rspHdr[
"Content-Type"] =
"text/html";
504 clientCtxPtr->url.
clear();
505 clientCtxPtr->url.parse( clientCtxPtr->requestHeader.getUrl() );
508 this->_httpProcess( clientCtxPtr, clientCtxPtr->requestHeader, clientCtxPtr->url, rspHdr, rspOut );
512 rspHdr(
"Content-Length") << rspStr.size();
516 if ( clientCtxPtr->clientSockPtr->sendUntil( rspHdrStr + rspStr ) )
521 if (
winux::StrLower( clientCtxPtr->requestHeader[
"Connection"] ) ==
"keep-alive" )
526 else if ( clientCtxPtr->isWebSocketWrapper )
531 this->onOpen(clientCtxPtr);
540 this->removeClient(clientCtxPtr->clientId);
545 if ( clientCtxPtr->isWebSocketWrapper )
552 this->removeClient(clientCtxPtr->clientId);
568 rspHdr[
"Upgrade"] =
"websocket";
569 rspHdr[
"Connection"] =
"Upgrade";
571 rspHdr[
"Sec-WebSocket-Accept"] = secWebsocketAccept;
580 clientCtxPtr->isWebSocketWrapper =
true;
584 this->_webProcess( clientCtxPtr, reqHdr, url, rspHdr, rspOut );
595 _handlers[urlPath].operator()( clientCtxPtr, clientCtxPtr->requestHeader, url, rspHdr, rspOut );
603 if ( urlPath.empty() )
626 if ( _cache.hasCache(filePath) )
629 rspHdr[
"Content-Type"] = cacheItem.
mime;
639 rspHdr[
"Content-Type"] = cacheItem.
mime;
648 rspOut <<
"<h1>HTTP 404</h1><strong>URLpath: `" << filePath <<
"` is not found!</strong>";
666 if ( !clientCtxPtr->clientSockPtr->recvUntilSize(
sizeof(
ws::FrameBase), &frameBuf ) )
671 goto RecvFrameFailure;
691 goto RecvFrameFailure;
704 goto RecvFrameFailure;
715 if ( !clientCtxPtr->clientSockPtr->recvUntilSize( 4, &frameBuf ) )
720 goto RecvFrameFailure;
725 if ( !clientCtxPtr->clientSockPtr->recvUntilSize( (
int)wantBytes, &frameBuf ) )
730 goto RecvFrameFailure;
740 char * data = frame->
data<
char>();
741 size_t len = frame->payloadLen;
751 char * data = frame->
data<
char>();
752 int len = frame->payloadLen;
755 for (
int i = 0; i < len; ++i )
756 data[i] ^= frame->maskingKey[ i % 4 ];
766 char * data = frame->
data<
char>();
767 int len =
ntoht(frame->extendedPayloadLen);
777 char * data = frame->
data<
char>();
778 int len =
ntoht(frame->extendedPayloadLen);
781 for (
int i = 0; i < len; ++i )
782 data[i] ^= frame->maskingKey[ i % 4 ];
792 char * data = frame->
data<
char>();
803 char * data = frame->
data<
char>();
808 data[i] ^= frame->maskingKey[ i % 4 ];
820 this->removeClient(clientCtxPtr->clientId);
826 if ( this->config.
outputVerbose )
ColorOutputLine(
winux::fgGreen,
"Client[", clientCtxPtr->clientId,
"]客户`", clientCtxPtr->clientEpStr,
"`收到一个帧{fin:", (
winux::uint)fin,
",opcode:", opcode,
",datasize:", payloadData.
getSize(),
"}" );
834 clientCtxPtr->websocket.messageBuf.append( payloadData.
getBuf<
char>(), payloadData.
getSize() );
835 this->onMessage( clientCtxPtr, clientCtxPtr->websocket.messageBuf, clientCtxPtr->websocket.messageType );
836 clientCtxPtr->websocket.messageBuf.clear();
837 clientCtxPtr->websocket.messageType = 0;
841 clientCtxPtr->websocket.messageBuf.append( payloadData.
getBuf<
char>(), payloadData.
getSize() );
858 clientCtxPtr->websocket.messageBuf.append( payloadData.
getBuf<
char>(), payloadData.
getSize() );
859 clientCtxPtr->websocket.messageType =
opcode;
860 this->onMessage( clientCtxPtr, clientCtxPtr->websocket.messageBuf, clientCtxPtr->websocket.messageType );
861 clientCtxPtr->websocket.messageBuf.clear();
862 clientCtxPtr->websocket.messageType = 0;
866 clientCtxPtr->websocket.messageBuf.append( payloadData.
getBuf<
char>(), payloadData.
getSize() );
867 clientCtxPtr->websocket.messageType =
opcode;
880 if ( payloadData.
getSize() > 0 )
883 errCode =
ntoht(closeData->code);
885 if ( this->config.
outputVerbose )
ColorOutputLine(
winux::fgMaroon,
"Client[", clientCtxPtr->clientId,
"]客户`", clientCtxPtr->clientEpStr,
"`收到一个Close帧{errcode:", errCode,
",errstr:", errStr,
"}" );
895 clientCtxPtr->clientSockPtr->close();
898 this->onClose( clientCtxPtr, errCode, errStr );
902 this->removeClient(clientCtxPtr->clientId);
908 if ( clientCtxPtr->websocket.close( errCode, errStr ) )
911 clientCtxPtr->clientSockPtr->close();
915 this->onClose( clientCtxPtr, errCode, errStr );
918 this->removeClient(clientCtxPtr->clientId);
941 if ( this->config.
outputVerbose )
ColorOutputLine(
winux::fgRed,
"Client[", clientCtxPtr->clientId,
"]客户`", clientCtxPtr->clientEpStr,
"`收到一个意外帧{fin:",(
winux::uint)fin,
",opcode:",opcode,
",datasize:",payloadData.
getSize(),
"}" );
943 this->removeClient(clientCtxPtr->clientId);
950 if ( _openHandler ) _openHandler(clientCtxPtr);
955 if ( _messageHandler ) _messageHandler( clientCtxPtr, data, messageType );
960 if ( _closeHandler ) _closeHandler( clientCtxPtr, errCode, errStr );
965 if ( _errorHandler ) _errorHandler( clientCtxPtr, ec );
973 std::map< winux::String, ResponseHandlerFunction >
_handlers;
XString< char > AnsiString
#define EIENNET_FUNC_DECL(ret)
void append(void const *data, size_t size)
添加数据:C语言缓冲区
void * getBuf() const
暴露缓冲区指针
typename Server< _ClientCtx >::ClientCtxSharedPointer ClientCtxSharedPointer
virtual ~WsHttpClientCtx()
void _doRecvWebSocketFrameTask(ClientCtxSharedPointer clientCtxPtr)
winux::SharedPointer< ip::tcp::Socket > clientSockPtr
virtual void onClose(ClientCtxSharedPointer clientCtxPtr, winux::uint16 errCode, winux::AnsiString const &errStr)
winux::String getMime(winux::String const &extName) const
void _doRecvRequestHeaderTask(ClientCtxSharedPointer clientCtxPtr)
winux::AnsiString messageBuf
virtual void onOpen(ClientCtxSharedPointer clientCtxPtr)
http::Header requestHeader
static void ColorOutputLine(winux::ConsoleAttr const &ca, _ArgType &&...arg)
void _doProcessWebSocketFrameTask(ClientCtxSharedPointer clientCtxPtr, bool fin, winux::uint opcode, winux::Buffer &payloadData)
CloseHandlerFunction _closeHandler
std::function< void(ClientCtxSharedPointer clientCtxPtr, winux::uint16 errCode, winux::AnsiString const &errStr) > CloseHandlerFunction
bool send(winux::AnsiString const &data, ws::OpCode opcode=ws::dataText)
Buffer Sha1(void const *buf, size_t size)
将数据进行sha1编码,返回二进制数据
OpenHandlerFunction _openHandler
std::function< void(ClientCtxSharedPointer clientCtxPtr, winux::AnsiString const &data, int messageType) > MessageHandlerFunction
StaticFileMemoryCache _cache
size_t getSize() const
获取数据大小
HttpServerConfig * config
bool SendWebSocketBuffer(eiennet::Socket *sock, OpCode opcode, bool mask, winux::Buffer payloadData=winux::Buffer(), size_t perFrameMaxPayloadSize=-1)
void setHandler(winux::String const &urlPath, ResponseHandlerFunction handler)
设置动态页面处理
WsHttpClientCtx(winux::uint64 clientId, winux::String clientEpStr, winux::SharedPointer< ip::tcp::Socket > clientSockPtr)
winux::GrowBuffer requestBody
WsHttpServer(HttpServerConfig const &confObj)
void onOpenHandler(OpenHandlerFunction handler)
设置WebSocket打开事件处理
void _webProcess(ClientCtxSharedPointer &clientCtxPtr, http::Header const &reqHdr, http::Url const &url, http::Header &rspHdr, std::ostream &rspOut)
缓冲区,表示内存中一块二进制数据(利用malloc/realloc进行内存分配)
winux::uint16 extendedPayloadLen
winux::uint16 extendedPayloadLen
bool SendWebSocketAnsi(eiennet::Socket *sock, OpCode opcode, bool mask, winux::AnsiString payloadData=winux::AnsiString(), size_t perFrameMaxPayloadSize=-1)
String CombinePath(String const &dirPath, String const &fileName)
把一个目录路径和一个文件名组合成一个新路径
WebSocketWrapper websocket
String Base64Encode(void const *buf, size_t size)
Base64编码
bool DetectPath(String const &path, bool *isDir=NULL)
探测一个路径是存在还是不存在,是目录还是文件
void _doRecvRequestBodyTask(ClientCtxSharedPointer clientCtxPtr)
bool isset(_MAP const &m, _KEY const &k)
检测map中是否有该键的值
winux::String documentRoot
void onCloseHandler(CloseHandlerFunction handler)
设置WebSocket关闭事件处理
String FileTitle(String const &fileName, String *extName=NULL)
获取文件标题
WebSocketErrorCode
WebSocket错误码
virtual void onError(ClientCtxSharedPointer clientCtxPtr, WebSocketErrorCode ec)
std::function< void(ClientCtxSharedPointer clientCtxPtr, WebSocketErrorCode ec) > ErrorHandlerFunction
void onErrorHandler(ErrorHandlerFunction handler)
设置WebSocket出错事件处理
std::function< void(ClientCtxSharedPointer &clientCtxPtr, http::Header const &reqHdr, http::Url const &url, http::Header &rspHdr, std::ostream &rspOut) > ResponseHandlerFunction
std::map< winux::String, ResponseHandlerFunction > _handlers
winux::String documentIndex
WebSocketWrapper(ClientCtx *clientCtx)
virtual void onStartup(ClientCtxSharedPointer clientCtxPtr) override
AnsiString StrLower(AnsiString str)
使字符串小写
virtual void onMessage(ClientCtxSharedPointer clientCtxPtr, winux::AnsiString const &data, int messageType)
bool close(winux::uint16 errCode=-1, winux::AnsiString const &errStr="")
MessageHandlerFunction _messageHandler
bool SendWebSocketFrame(eiennet::Socket *sock, OpCode opcode, bool fin, bool mask, winux::byte *payloadData=nullptr, size_t payloadDataSize=0)
DataRecvSendCtx forClient
winux::uint64 extendedPayloadLen
winux::String toString() const
根据flags和存储的信息,组装成整个URL串.
winux::String getPath() const
获取路径。不以'/'开头
WsHttpServer(winux::String const &serverIp, winux::ushort port, int threadCount=10, int listenBacklog=10, double durationSec=0.1)
winux::AnsiString requestHeaderStr
void onMessageHandler(MessageHandlerFunction handler)
设置WebSocket消息到达事件处理
void _doRequestTask(ClientCtxSharedPointer clientCtxPtr)
winux::uint64 extendedPayloadLen
void _httpProcess(ClientCtxSharedPointer &clientCtxPtr, http::Header const &reqHdr, http::Url const &url, http::Header &rspHdr, std::ostream &rspOut)
ErrorHandlerFunction _errorHandler
std::function< void(ClientCtxSharedPointer clientCtxPtr) > OpenHandlerFunction
Buffer FileGetContentsEx(String const &filename, bool textMode)
载入文件内容为一个Buffer,textMode表示是否为文本模式