23 std::map< winux::String, winux::String >
mime;
39 : ClientCtx( clientId, clientEpStr, clientSockPtr ), url(
http::
urlSimple), config(nullptr)
44 if ( !this->config || this->config->outputVerbose )
61 #define RESPONSE_HANDLER_PARAMS http::old_v1::HttpServer::ClientCtxSharedPointer & clientCtxPtr, http::Header const & reqHdr, http::Url const & url, http::Header & rspHdr, std::ostream & rspOut 88 std::map< winux::String, ResponseHandlerFunction > _handlers;
206 #pragma pack(push, 1) 222 memset(
this, 0,
sizeof(*
this) );
231 memset(
this, 0,
sizeof(*
this) );
234 template <
typename _Ty >
237 return reinterpret_cast<_Ty*
>(
this + 1 );
242 #pragma pack(push, 2) 251 memset(
this, 0,
sizeof(*
this) );
254 template <
typename _Ty >
257 return reinterpret_cast<_Ty*
>(
this + 1 );
268 memset(
this, 0,
sizeof(*
this) );
271 template <
typename _Ty >
274 return reinterpret_cast<_Ty*
>(
this + 1 );
286 memset(
this, 0,
sizeof(*
this) );
289 template <
typename _Ty >
292 return reinterpret_cast<_Ty*
>(
this + 1 );
303 memset(
this, 0,
sizeof(*
this) );
306 template <
typename _Ty >
309 return reinterpret_cast<_Ty*
>(
this + 1 );
321 memset(
this, 0,
sizeof(*
this) );
324 template <
typename _Ty >
327 return reinterpret_cast<_Ty*
>(
this + 1 );
335 template <
typename _Ty >
338 return reinterpret_cast<_Ty*
>(
this + 1 );
372 data.
append( &errCode,
sizeof(errCode) );
395 : ClientCtx( clientId, clientEpStr, clientSockPtr ), url(
http::
urlSimple), config(nullptr), isWebSocketWrapper(false), websocket(this)
400 if ( !this->config || this->config->outputVerbose )
415 template <
class _ClientCtx = WsHttpClientCtx >
422 using MessageHandlerFunction = std::function< void( ClientCtxSharedPointer clientCtxPtr, winux::AnsiString const & data, int messageType ) >;
423 using CloseHandlerFunction = std::function< void( ClientCtxSharedPointer clientCtxPtr, winux::uint16 errCode, winux::AnsiString const & errStr ) >;
424 using ErrorHandlerFunction = std::function< void( ClientCtxSharedPointer clientCtxPtr, WebSocketErrorCode ec ) >;
426 using ResponseHandlerFunction = std::function< void ( ClientCtxSharedPointer & clientCtxPtr, http::Header const & reqHdr, http::Url const & url, http::Header & rspHdr, std::ostream & rspOut ) >;
431 eiennet::old_v1::Server<_ClientCtx>(
eiennet::ip::EndPoint( confObj.serverIp, confObj.serverPort ), confObj.threadCount, confObj.listenBacklog ),
433 _cache(confObj.cacheLifeTime)
438 eiennet::old_v1::Server<_ClientCtx>(
eiennet::ip::EndPoint( serverIp, port ), threadCount, listenBacklog ),
439 config( serverIp, port, threadCount, listenBacklog, durationSec ),
440 _cache(config.cacheLifeTime)
459 clientCtxPtr->config = &this->config;
461 this->_pool.task( &WsHttpServer::_doRecvRequestHeaderTask,
this, clientCtxPtr ).post();
468 int rc = clientCtxPtr->clientSockPtr->recvWaitUntilTarget(
470 &clientCtxPtr->forClient.data,
471 &clientCtxPtr->forClient.extraData,
472 &clientCtxPtr->forClient.hadBytes,
473 &clientCtxPtr->forClient.startpos,
474 &clientCtxPtr->forClient.pos,
475 this->config.durationSec,
477 [&clientCtxPtr] (
int had,
void* ) {
478 clientCtxPtr->forClient.retryCount = 0;
482 if ( clientCtxPtr->forClient.pos != -1 )
485 clientCtxPtr->requestHeaderStr = clientCtxPtr->forClient.data.toAnsi();
486 clientCtxPtr->requestHeader.clear();
487 clientCtxPtr->requestHeader.parse(clientCtxPtr->requestHeaderStr);
489 clientCtxPtr->forClient.resetStatus();
490 clientCtxPtr->forClient.data = std::move(clientCtxPtr->forClient.extraData);
492 int contentLength =
static_cast<http::Header&
>(clientCtxPtr->requestHeader).getHeader<int>(
"Content-Length");
493 clientCtxPtr->forClient.targetBytes = contentLength - clientCtxPtr->forClient.data.getSize();
494 if ( clientCtxPtr->forClient.targetBytes > 0 )
497 this->_pool.task( &WsHttpServer::_doRecvRequestBodyTask,
this, clientCtxPtr ).post();
502 clientCtxPtr->requestBody = std::move(clientCtxPtr->forClient.data);
505 this->_pool.task( &WsHttpServer::_doRequestTask,
this, clientCtxPtr ).post();
508 else if ( rcWait == 0 )
510 clientCtxPtr->forClient.retryCount++;
511 if ( clientCtxPtr->forClient.retryCount < this->config.retryCount )
514 this->_pool.task( &WsHttpServer::_doRecvRequestHeaderTask,
this, clientCtxPtr ).post();
520 this->removeClient(clientCtxPtr->clientId);
527 this->removeClient(clientCtxPtr->clientId);
535 int rc = clientCtxPtr->clientSockPtr->recvWaitUntilSize(
536 clientCtxPtr->forClient.targetBytes,
537 &clientCtxPtr->forClient.data,
538 &clientCtxPtr->forClient.hadBytes,
539 this->config.durationSec,
541 [&clientCtxPtr] (
int had,
void* ) {
542 clientCtxPtr->forClient.retryCount = 0;
546 if ( clientCtxPtr->forClient.hadBytes == clientCtxPtr->forClient.targetBytes )
549 clientCtxPtr->requestBody = std::move(clientCtxPtr->forClient.data);
550 clientCtxPtr->forClient.resetStatus();
553 this->_pool.task( &WsHttpServer::_doRequestTask,
this, clientCtxPtr ).post();
555 else if ( rcWait == 0 )
557 clientCtxPtr->forClient.retryCount++;
558 if ( clientCtxPtr->forClient.retryCount < this->config.retryCount )
561 this->_pool.task( &WsHttpServer::_doRecvRequestBodyTask,
this, clientCtxPtr ).post();
567 this->removeClient(clientCtxPtr->clientId);
574 this->removeClient(clientCtxPtr->clientId);
582 if ( this->config.
outputVerbose ) std::cout << clientCtxPtr->requestHeaderStr;
586 std::stringbuf rspBuf;
587 std::ostream rspOut(&rspBuf);
590 rspHdr[
"Content-Type"] =
"text/html";
592 clientCtxPtr->url.
clear();
593 clientCtxPtr->url.parse( clientCtxPtr->requestHeader.getUrl() );
596 this->_httpProcess( clientCtxPtr, clientCtxPtr->requestHeader, clientCtxPtr->url, rspHdr, rspOut );
600 rspHdr(
"Content-Length") << rspStr.size();
604 if ( clientCtxPtr->clientSockPtr->sendUntil( rspHdrStr + rspStr ) )
609 if (
winux::StrLower( clientCtxPtr->requestHeader[
"Connection"] ) ==
"keep-alive" )
612 this->_pool.task( &WsHttpServer::_doRecvRequestHeaderTask,
this, clientCtxPtr ).post();
614 else if ( clientCtxPtr->isWebSocketWrapper )
619 this->onOpen(clientCtxPtr);
622 this->_pool.task( &WsHttpServer::_doRecvWebSocketFrameTask,
this, clientCtxPtr ).post();
628 this->removeClient(clientCtxPtr->clientId);
633 if ( clientCtxPtr->isWebSocketWrapper )
640 this->removeClient(clientCtxPtr->clientId);
656 rspHdr[
"Upgrade"] =
"websocket";
657 rspHdr[
"Connection"] =
"Upgrade";
659 rspHdr[
"Sec-WebSocket-Accept"] = secWebsocketAccept;
668 clientCtxPtr->isWebSocketWrapper =
true;
672 this->_webProcess( clientCtxPtr, reqHdr, url, rspHdr, rspOut );
683 _handlers[urlPath].operator()( clientCtxPtr, clientCtxPtr->requestHeader, url, rspHdr, rspOut );
691 if ( urlPath.empty() )
714 if ( _cache.hasCache(filePath) )
717 rspHdr[
"Content-Type"] = cacheItem.
mime;
727 rspHdr[
"Content-Type"] = cacheItem.
mime;
736 rspOut <<
"<h1>HTTP 404</h1><strong>URLpath: `" << filePath <<
"` is not found!</strong>";
754 if ( !clientCtxPtr->clientSockPtr->recvUntilSize(
sizeof(
ws::FrameBase), &frameBuf ) )
759 goto RecvFrameFailure;
779 goto RecvFrameFailure;
792 goto RecvFrameFailure;
803 if ( !clientCtxPtr->clientSockPtr->recvUntilSize( 4, &frameBuf ) )
808 goto RecvFrameFailure;
813 if ( !clientCtxPtr->clientSockPtr->recvUntilSize( (
int)wantBytes, &frameBuf ) )
818 goto RecvFrameFailure;
828 char * data = frame->
data<
char>();
829 size_t len = frame->payloadLen;
832 this->_pool.task( &WsHttpServer::_doProcessWebSocketFrameTask,
this, clientCtxPtr, (
bool)frame->fin, (
winux::uint)frame->opcode,
winux::Buffer( data, len ) ).post();
839 char * data = frame->
data<
char>();
840 int len = frame->payloadLen;
843 for (
int i = 0; i < len; ++i )
844 data[i] ^= frame->maskingKey[ i % 4 ];
847 this->_pool.task( &WsHttpServer::_doProcessWebSocketFrameTask,
this, clientCtxPtr, (
bool)frame->fin, (
winux::uint)frame->opcode,
winux::Buffer( data, len ) ).post();
854 char * data = frame->
data<
char>();
858 this->_pool.task( &WsHttpServer::_doProcessWebSocketFrameTask,
this, clientCtxPtr, (
bool)frame->fin, (
winux::uint)frame->opcode,
winux::Buffer( data, len ) ).post();
865 char * data = frame->
data<
char>();
869 for (
int i = 0; i < len; ++i )
870 data[i] ^= frame->maskingKey[ i % 4 ];
873 this->_pool.task( &WsHttpServer::_doProcessWebSocketFrameTask,
this, clientCtxPtr, (
bool)frame->fin, (
winux::uint)frame->opcode,
winux::Buffer( data, (
winux::uint)len ) ).post();
880 char * data = frame->
data<
char>();
884 this->_pool.task( &WsHttpServer::_doProcessWebSocketFrameTask,
this, clientCtxPtr, (
bool)frame->fin, (
winux::uint)frame->opcode,
winux::Buffer( data, (
winux::uint)len ) ).post();
891 char * data = frame->
data<
char>();
896 data[i] ^= frame->maskingKey[ i % 4 ];
899 this->_pool.task( &WsHttpServer::_doProcessWebSocketFrameTask,
this, clientCtxPtr, (
bool)frame->fin, (
winux::uint)frame->opcode,
winux::Buffer( data, (
winux::uint)len ) ).post();
908 this->removeClient(clientCtxPtr->clientId);
914 if ( this->config.
outputVerbose )
ColorOutputLine(
winux::fgGreen,
"Client[", clientCtxPtr->clientId,
"]客户`", clientCtxPtr->clientEpStr,
"`收到一个帧{fin:", (
winux::uint)fin,
",opcode:", opcode,
",datasize:", payloadData.
getSize(),
"}" );
922 clientCtxPtr->websocket.messageBuf.append( payloadData.
getBuf<
char>(), payloadData.
getSize() );
923 this->onMessage( clientCtxPtr, clientCtxPtr->websocket.messageBuf, clientCtxPtr->websocket.messageType );
924 clientCtxPtr->websocket.messageBuf.clear();
925 clientCtxPtr->websocket.messageType = 0;
929 clientCtxPtr->websocket.messageBuf.append( payloadData.
getBuf<
char>(), payloadData.
getSize() );
933 this->_pool.task( &WsHttpServer::_doRecvWebSocketFrameTask,
this, clientCtxPtr ).post();
946 clientCtxPtr->websocket.messageBuf.append( payloadData.
getBuf<
char>(), payloadData.
getSize() );
947 clientCtxPtr->websocket.messageType = opcode;
948 this->onMessage( clientCtxPtr, clientCtxPtr->websocket.messageBuf, clientCtxPtr->websocket.messageType );
949 clientCtxPtr->websocket.messageBuf.clear();
950 clientCtxPtr->websocket.messageType = 0;
954 clientCtxPtr->websocket.messageBuf.append( payloadData.
getBuf<
char>(), payloadData.
getSize() );
955 clientCtxPtr->websocket.messageType = opcode;
959 this->_pool.task( &WsHttpServer::_doRecvWebSocketFrameTask,
this, clientCtxPtr ).post();
968 if ( payloadData.
getSize() > 0 )
973 if ( this->config.
outputVerbose )
ColorOutputLine(
winux::fgMaroon,
"Client[", clientCtxPtr->clientId,
"]客户`", clientCtxPtr->clientEpStr,
"`收到一个Close帧{errcode:", errCode,
",errstr:", errStr,
"}" );
983 clientCtxPtr->clientSockPtr->close();
986 this->onClose( clientCtxPtr, errCode, errStr );
990 this->removeClient(clientCtxPtr->clientId);
996 if ( clientCtxPtr->websocket.close( errCode, errStr ) )
999 clientCtxPtr->clientSockPtr->close();
1003 this->onClose( clientCtxPtr, errCode, errStr );
1006 this->removeClient(clientCtxPtr->clientId);
1016 this->_pool.task( &WsHttpServer::_doRecvWebSocketFrameTask,
this, clientCtxPtr ).post();
1024 this->_pool.task( &WsHttpServer::_doRecvWebSocketFrameTask,
this, clientCtxPtr ).post();
1029 if ( this->config.
outputVerbose )
ColorOutputLine(
winux::fgRed,
"Client[", clientCtxPtr->clientId,
"]客户`", clientCtxPtr->clientEpStr,
"`收到一个意外帧{fin:",(
winux::uint)fin,
",opcode:",opcode,
",datasize:",payloadData.
getSize(),
"}" );
1031 this->removeClient(clientCtxPtr->clientId);
1038 if ( _openHandler ) _openHandler(clientCtxPtr);
1043 if ( _messageHandler ) _messageHandler( clientCtxPtr, data, messageType );
1048 if ( _closeHandler ) _closeHandler( clientCtxPtr, errCode, errStr );
1053 if ( _errorHandler ) _errorHandler( clientCtxPtr, ec );
1061 std::map< winux::String, ResponseHandlerFunction >
_handlers;
XString< char > AnsiString
#define HTTPWRAPPER_FUNC_DECL(ret)
HttpServerConfig * config
eiennet::old_v1::ClientCtx * clientCtx
http::StaticFileMemoryCache _cache
void append(void const *data, size_t size)
添加数据:C语言缓冲区
void _doRequestTask(ClientCtxSharedPointer clientCtxPtr)
winux::GrowBuffer requestBody
void * getBuf() const
暴露缓冲区指针
ErrorHandlerFunction _errorHandler
eiennet::DataRecvSendCtx forClient
void _doRecvWebSocketFrameTask(ClientCtxSharedPointer clientCtxPtr)
void onErrorHandler(ErrorHandlerFunction handler)
设置WebSocket出错事件处理
winux::SharedPointer< ip::tcp::Socket > clientSockPtr
std::function< void(http::old_v1::HttpServer::ClientCtxSharedPointer &clientCtxPtr, http::Header const &reqHdr, http::Url const &url, http::Header &rspHdr, std::ostream &rspOut) > ResponseHandlerFunction
winux::String documentRoot
virtual void onStartup(ClientCtxSharedPointer clientCtxPtr) override
void onOpenHandler(OpenHandlerFunction handler)
设置WebSocket打开事件处理
CloseHandlerFunction _closeHandler
void _doProcessWebSocketFrameTask(ClientCtxSharedPointer clientCtxPtr, bool fin, winux::uint opcode, winux::Buffer &payloadData)
winux::AnsiString messageBuf
WsHttpServer(HttpServerConfig const &confObj)
void setHandler(winux::String const &urlPath, ResponseHandlerFunction handler)
设置动态页面处理
static void ColorOutputLine(winux::ConsoleAttr const &ca, _ArgType &&...arg)
static void ColorOutput(winux::ConsoleAttr const &ca, _ArgType &&...arg)
HttpServerConfig config
配置参数
bool SendWebSocketBuffer(eiennet::Socket *sock, OpCode opcode, bool mask, winux::Buffer payloadData=winux::Buffer(), size_t perFrameMaxPayloadSize=-1)
std::function< void(ClientCtxSharedPointer clientCtxPtr, winux::uint16 errCode, winux::AnsiString const &errStr) > CloseHandlerFunction
bool send(winux::AnsiString const &data, ws::OpCode opcode=ws::dataText)
XString< _ChTy > StrLower(XString< _ChTy > str)
void _webProcess(ClientCtxSharedPointer &clientCtxPtr, http::Header const &reqHdr, http::Url const &url, http::Header &rspHdr, std::ostream &rspOut)
Buffer Sha1(void const *buf, size_t size)
将数据进行sha1编码,返回二进制数据
bool SendWebSocketFrame(eiennet::Socket *sock, OpCode opcode, bool fin, bool mask, winux::byte *payloadData=nullptr, size_t payloadDataSize=0)
size_t getSize() const
获取数据大小
eiennet::DataRecvSendCtx forClient
winux::GrowBuffer requestBody
winux::uint64 extendedPayloadLen
virtual ~WsHttpClientCtx()
winux::uint16 extendedPayloadLen
OpenHandlerFunction _openHandler
HttpServerConfig * config
std::function< void(ClientCtxSharedPointer &clientCtxPtr, http::Header const &reqHdr, http::Url const &url, http::Header &rspHdr, std::ostream &rspOut) > ResponseHandlerFunction
WsHttpServer(winux::String const &serverIp, winux::ushort port, int threadCount=10, int listenBacklog=10, double durationSec=0.1)
HttpClientCtx(winux::uint64 clientId, winux::String clientEpStr, winux::SharedPointer< eiennet::ip::tcp::Socket > clientSockPtr)
WebSocketWrapper websocket
winux::uint16 extendedPayloadLen
缓冲区,表示内存中一块二进制数据(利用malloc/realloc进行内存分配)
WsHttpClientCtx(winux::uint64 clientId, winux::String clientEpStr, winux::SharedPointer< eiennet::ip::tcp::Socket > clientSockPtr)
String CombinePath(String const &dirPath, String const &fileName)
把一个目录路径和一个文件名组合成一个新路径
virtual void onOpen(ClientCtxSharedPointer clientCtxPtr)
bool DetectPath(String const &path, bool *isDir=NULL)
探测一个路径是存在还是不存在,是目录还是文件
void _doRecvRequestBodyTask(ClientCtxSharedPointer clientCtxPtr)
std::map< winux::String, winux::String > mime
void onCloseHandler(CloseHandlerFunction handler)
设置WebSocket关闭事件处理
virtual void onMessage(ClientCtxSharedPointer clientCtxPtr, winux::AnsiString const &data, int messageType)
bool isset(_MAP const &m, _KEY const &k)
检测map中是否有该键的值
std::map< winux::String, ResponseHandlerFunction > _handlers
void onMessageHandler(MessageHandlerFunction handler)
设置WebSocket消息到达事件处理
bool close(winux::uint16 errCode=-1, winux::AnsiString const &errStr="")
http::Header requestHeader
virtual void onError(ClientCtxSharedPointer clientCtxPtr, WebSocketErrorCode ec)
String FileTitle(String const &fileName, String *extName=NULL)
获取文件标题
typename eiennet::old_v1::Server< _ClientCtx >::ClientCtxSharedPointer ClientCtxSharedPointer
virtual void onClose(ClientCtxSharedPointer clientCtxPtr, winux::uint16 errCode, winux::AnsiString const &errStr)
http::Header requestHeader
XString< _ChTy > Base64EncodeBuffer(Buffer const &buf)
Base64编码
void setHandler(winux::String const &urlPath, ResponseHandlerFunction handler)
设置动态页面处理
WebSocketWrapper(eiennet::old_v1::ClientCtx *clientCtx)
std::function< void(ClientCtxSharedPointer clientCtxPtr) > OpenHandlerFunction
winux::String getMime(winux::String const &extName) const
bool SendWebSocketAnsi(eiennet::Socket *sock, OpCode opcode, bool mask, winux::AnsiString payloadData=winux::AnsiString(), size_t perFrameMaxPayloadSize=-1)
winux::Configure const * constConfObj
winux::AnsiString requestHeaderStr
void _doRecvRequestHeaderTask(ClientCtxSharedPointer clientCtxPtr)
winux::String toString() const
根据flags和存储的信息组装成整个URL串
winux::String getPath() const
获取路径。不以'/'开头
std::function< void(ClientCtxSharedPointer clientCtxPtr, winux::AnsiString const &data, int messageType) > MessageHandlerFunction
WebSocketErrorCode
WebSocket错误码
void _httpProcess(ClientCtxSharedPointer &clientCtxPtr, http::Header const &reqHdr, http::Url const &url, http::Header &rspHdr, std::ostream &rspOut)
MessageHandlerFunction _messageHandler
winux::String documentIndex
winux::uint64 extendedPayloadLen
winux::AnsiString requestHeaderStr
void appendString(XString< _ChTy > const &data)
添加数据:XString对象
Buffer FileGetContentsEx(String const &filename, bool textMode)
载入文件内容为一个Buffer,textMode表示是否为文本模式
std::function< void(ClientCtxSharedPointer clientCtxPtr, WebSocketErrorCode ec) > ErrorHandlerFunction