acl/app/wizard_demo/fiber_chat/http_servlet.cpp

509 lines
11 KiB
C++
Raw Normal View History

#include "stdafx.h"
2016-09-23 22:04:07 +08:00
#include "configure.h"
2016-09-20 19:55:38 +08:00
#include "http_servlet.h"
2016-09-23 22:45:53 +08:00
static std::vector<chat_client*> __clients;
2016-09-20 19:55:38 +08:00
http_servlet::http_servlet(acl::socket_stream* stream, acl::session* session)
: acl::HttpServlet(stream, session)
2016-09-23 22:04:07 +08:00
, logined_(false)
2016-09-20 19:55:38 +08:00
{
}
http_servlet::~http_servlet(void)
{
2016-09-23 22:04:07 +08:00
if (!username_.empty())
oneLogout(username_);
2016-09-20 19:55:38 +08:00
}
bool http_servlet::doError(acl::HttpServletRequest&,
acl::HttpServletResponse& res)
{
res.setStatus(400);
res.setContentType("text/html; charset=");
// <20><><EFBFBD><EFBFBD> http <20><>Ӧͷ
2016-09-20 19:55:38 +08:00
if (res.sendHeader() == false)
return false;
// <20><><EFBFBD><EFBFBD> http <20><>Ӧ<EFBFBD><D3A6>
2016-09-20 19:55:38 +08:00
acl::string buf;
buf.format("<root error='some error happened!' />\r\n");
(void) res.getOutputStream().write(buf);
return false;
}
bool http_servlet::doOther(acl::HttpServletRequest&,
acl::HttpServletResponse& res, const char* method)
{
res.setStatus(400);
res.setContentType("text/html; charset=");
// <20><><EFBFBD><EFBFBD> http <20><>Ӧͷ
2016-09-20 19:55:38 +08:00
if (res.sendHeader() == false)
return false;
// <20><><EFBFBD><EFBFBD> http <20><>Ӧ<EFBFBD><D3A6>
2016-09-20 19:55:38 +08:00
acl::string buf;
buf.format("<root error='unkown request method %s' />\r\n", method);
(void) res.getOutputStream().write(buf);
return false;
}
bool http_servlet::doGet(acl::HttpServletRequest& req,
acl::HttpServletResponse& res)
{
return doPost(req, res);
}
bool http_servlet::doPost(acl::HttpServletRequest& req,
acl::HttpServletResponse& res)
{
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ҫ http session <20><><EFBFBD>ƣ<EFBFBD><C6A3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ע<EFBFBD>ͣ<EFBFBD><CDA3><EFBFBD><EFBFBD><EFBFBD>Ҫ<EFBFBD><D2AA>֤
// <20><> master_service.cpp <20>ĺ<EFBFBD><C4BA><EFBFBD> thread_on_read <20><><EFBFBD><EFBFBD><EFBFBD>õ<EFBFBD>
// memcached <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
2016-09-20 19:55:38 +08:00
/*
const char* sid = req.getSession().getAttribute("sid");
if (*sid == 0)
req.getSession().setAttribute("sid", "xxxxxx");
sid = req.getSession().getAttribute("sid");
*/
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ҫȡ<D2AA><C8A1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> cookie <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ע<EFBFBD><D7A2>
2016-09-20 19:55:38 +08:00
/*
*/
res.setContentType("text/html; charset=utf-8") // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ӧ<EFBFBD>ַ<EFBFBD><D6B7><EFBFBD>
.setKeepAlive(req.isKeepAlive()) // <20><><EFBFBD><EFBFBD><EFBFBD>Ƿ񱣳ֳ<F1B1A3B3><D6B3><EFBFBD><EFBFBD><EFBFBD>
.setContentEncoding(true) // <20>Զ<EFBFBD>֧<EFBFBD><D6A7>ѹ<EFBFBD><D1B9><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
.setChunkedTransferEncoding(true); // <20><><EFBFBD><EFBFBD> chunk <20><><EFBFBD>ʽ
2016-09-20 19:55:38 +08:00
2016-09-23 22:04:07 +08:00
acl::string path;
path << var_cfg_html_path << "/" << "user.html";
2016-09-20 19:55:38 +08:00
acl::string buf;
2016-09-23 22:04:07 +08:00
if (acl::ifstream::load(path, &buf) == false)
{
logger_error("load %s error %s", path.c_str(), acl::last_serror());
return doError(req, res);
}
2016-09-20 19:55:38 +08:00
// <20><><EFBFBD><EFBFBD> http <20><>Ӧ<EFBFBD><EFBFBD><E5A3AC>Ϊ<EFBFBD><CEAA><EFBFBD><EFBFBD><EFBFBD><EFBFBD> chunk <20><><EFBFBD><EFBFBD>ģʽ<C4A3><CABD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ҫ<EFBFBD><D2AA><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><D2BB>
// res.write <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊ 0 <20>Ա<EFBFBD>ʾ chunk <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ݽ<EFBFBD><DDBD><EFBFBD>
2016-09-23 22:45:53 +08:00
bool ret = res.write(buf) && res.write(NULL, 0);
if (ret == false)
remove(req.getSocketStream());
return ret;
2016-09-20 19:55:38 +08:00
}
2022-02-10 09:50:00 +08:00
bool http_servlet::doWebSocket(acl::HttpServletRequest& req,
2016-09-20 19:55:38 +08:00
acl::HttpServletResponse&)
{
acl::socket_stream& ss = req.getSocketStream();
acl::websocket in(ss), out(ss);
while (true)
{
if (in.read_frame_head() == false)
{
2016-09-23 22:45:53 +08:00
remove(ss);
2016-09-20 19:55:38 +08:00
printf("read_frame_head error\r\n");
return false;
}
bool ret;
unsigned char opcode = in.get_frame_opcode();
switch (opcode)
{
case acl::FRAME_PING:
ret = doPing(in, out);
break;
case acl::FRAME_PONG:
ret = doPong(in, out);
break;
case acl::FRAME_CLOSE:
ret = doClose(in, out);
break;
case acl::FRAME_TEXT:
case acl::FRAME_BINARY:
ret = doMsg(in, out);
break;
case acl::FRAME_CONTINUATION:
ret = false;
2016-09-23 22:45:53 +08:00
printf("1-invalid opcode: 0x%x\r\n", opcode);
2016-09-20 19:55:38 +08:00
break;
default:
2016-09-23 22:45:53 +08:00
printf("2-invalid opcode: 0x%x\r\n", opcode);
2016-09-20 19:55:38 +08:00
ret = false;
break;
}
if (ret == false)
2016-09-23 22:45:53 +08:00
{
printf("remove one, opcode: 0x%x\r\n", opcode);
remove(ss);
2016-09-20 19:55:38 +08:00
return false;
2016-09-23 22:45:53 +08:00
}
2016-09-20 19:55:38 +08:00
}
// XXX: NOT REACHED
return false;
}
bool http_servlet::doPing(acl::websocket& in, acl::websocket& out)
{
unsigned long long len = in.get_frame_payload_len();
if (len == 0)
{
2016-09-23 22:04:07 +08:00
if (out.send_frame_pong((const void*) NULL, 0) == false)
2016-09-20 19:55:38 +08:00
return false;
else
return true;
}
out.reset().set_frame_fin(true)
.set_frame_opcode(acl::FRAME_PONG)
.set_frame_payload_len(len);
char buf[8192];
while (true)
{
int ret = in.read_frame_data(buf, sizeof(buf) - 1);
if (ret == 0)
break;
if (ret < 0)
{
printf("read_frame_data error\r\n");
return false;
}
buf[ret] = 0;
printf("read: [%s]\r\n", buf);
if (out.send_frame_data(buf, ret) == false)
{
printf("send_frame_data error\r\n");
return false;
}
}
return true;
}
2016-09-23 22:45:53 +08:00
bool http_servlet::doPong(acl::websocket& in, acl::websocket&)
2016-09-20 19:55:38 +08:00
{
unsigned long long len = in.get_frame_payload_len();
if (len == 0)
return true;
char buf[8192];
while (true)
{
int ret = in.read_frame_data(buf, sizeof(buf) - 1);
if (ret == 0)
break;
if (ret < 0)
{
printf("read_frame_data error\r\n");
return false;
}
buf[ret] = 0;
printf("read: [%s]\r\n", buf);
}
return true;
}
2016-09-23 22:45:53 +08:00
bool http_servlet::doClose(acl::websocket&, acl::websocket&)
2016-09-20 19:55:38 +08:00
{
return false;
}
bool http_servlet::doMsg(acl::websocket& in, acl::websocket& out)
{
acl::string tbuf((size_t) in.get_frame_payload_len() + 1);
acl::socket_stream& conn = out.get_stream();
char buf[8192];
while (true)
{
int ret = in.read_frame_data(buf, sizeof(buf) - 1);
if (ret == 0)
break;
if (ret < 0)
{
printf("read_frame_data error\r\n");
return false;
}
tbuf.append(buf, ret);
}
std::vector<acl::string>& tokens = tbuf.split2("|");
const acl::string& cmd = tokens[0];
2016-09-23 22:04:07 +08:00
while (!logined_)
2016-09-20 19:55:38 +08:00
{
2016-09-23 22:04:07 +08:00
if (cmd.equal("login", false))
2016-09-20 19:55:38 +08:00
{
2016-09-23 22:04:07 +08:00
if (doLogin(conn, tokens) == false)
return false;
else
return true;
2016-09-20 19:55:38 +08:00
}
2016-09-23 23:27:34 +08:00
else
{
printf("invalid cmd: %s, tbuf: %s\r\n",
cmd.c_str(), tbuf.c_str());
return doStatus(conn, "please login first!");
}
2016-09-20 19:55:38 +08:00
}
2016-09-23 22:04:07 +08:00
if (cmd.equal("login", false))
return doStatus(conn, "already logined");
if (cmd.equal("chat", false))
2016-09-20 19:55:38 +08:00
{
if (doChat(conn, tokens) == false)
return false;
else
return true;
}
else
{
2016-09-23 22:04:07 +08:00
printf("unknown cmd: %s, msg: %s\r\n",
cmd.c_str(), tbuf.c_str());
acl::string info;
info.format("unknown cmd: %s", cmd.c_str());
return doStatus(conn, info);
2016-09-20 19:55:38 +08:00
}
return true;
}
2016-09-23 22:04:07 +08:00
bool http_servlet::doStatus(acl::socket_stream& conn, const char* info)
{
acl::string buf;
buf.format("status|%s", info);
acl::websocket out(conn);
out.set_frame_fin(true)
.set_frame_opcode(acl::FRAME_TEXT)
.set_frame_payload_len(buf.size());
return out.send_frame_data(buf.c_str(), buf.size());
}
2016-09-20 19:55:38 +08:00
bool http_servlet::doLogin(acl::socket_stream& conn,
const std::vector<acl::string>& tokens)
{
// format: login|user
if (tokens.size() != 2)
{
printf("format: login|user\r\n");
return false;
}
const acl::string& user = tokens[1];
2016-09-23 22:04:07 +08:00
chat_client* client = find(user);
if (client != NULL)
{
if (&client->get_conn() == &conn)
{
printf("user: %s has beean already logined\r\n",
user.c_str());
return doStatus(conn, "already logined");
}
else
{
printf("ERROR, user: %s has beean already logined\r\n",
user.c_str());
const char* status = "login|error";
acl::websocket out(conn);
out.set_frame_fin(true)
.set_frame_opcode(acl::FRAME_TEXT)
.set_frame_payload_len(strlen(status));
out.send_frame_data(status);
return false;
}
}
2016-09-20 19:55:38 +08:00
2016-09-23 22:04:07 +08:00
client = new chat_client(user, conn);
2016-09-23 22:45:53 +08:00
__clients.push_back(client);
2016-09-23 22:04:07 +08:00
username_ = user;
2016-09-20 19:55:38 +08:00
printf("status: ok, cmd: login, user: %s\r\n", user.c_str());
2016-09-23 22:04:07 +08:00
logined_ = true;
acl::string buf("users");
2016-09-23 22:45:53 +08:00
for (std::vector<chat_client*>::iterator it = __clients.begin();
it != __clients.end(); ++it)
2016-09-23 22:04:07 +08:00
{
client = *it;
buf << "|" << (*it)->get_name();
oneLogin(**it, user);
}
acl::websocket out(conn);
out.set_frame_fin(true)
.set_frame_opcode(acl::FRAME_TEXT)
.set_frame_payload_len(buf.size());
return out.send_frame_data(buf.c_str(), buf.size());
}
void http_servlet::oneLogin(const acl::string& user)
{
2016-09-23 22:45:53 +08:00
for (std::vector<chat_client*>::iterator it = __clients.begin();
it != __clients.end(); ++it)
2016-09-23 22:04:07 +08:00
{
if (user.equal((*it)->get_name()))
continue;
oneLogin(**it, user);
}
2016-09-20 19:55:38 +08:00
}
2016-09-23 22:04:07 +08:00
void http_servlet::oneLogin(chat_client& client, const acl::string& user)
{
acl::string buf;
buf << "login|" << user;
acl::websocket out(client.get_conn());
out.set_frame_fin(true)
.set_frame_opcode(acl::FRAME_TEXT)
.set_frame_payload_len(buf.size());
out.send_frame_data(buf.c_str(), buf.size());
}
void http_servlet::oneLogout(const acl::string& user)
{
2016-09-23 22:45:53 +08:00
for (std::vector<chat_client*>::iterator it = __clients.begin();
it != __clients.end(); ++it)
2016-09-23 22:04:07 +08:00
{
if (user.equal((*it)->get_name()))
continue;
oneLogout(**it, user);
}
}
void http_servlet::oneLogout(chat_client& client, const acl::string& user)
{
acl::string buf;
buf << "logout|" << user;
acl::websocket out(client.get_conn());
out.set_frame_fin(true)
.set_frame_opcode(acl::FRAME_TEXT)
.set_frame_payload_len(buf.size());
out.send_frame_data(buf.c_str(), buf.size());
}
bool http_servlet::doChat(acl::socket_stream& from_conn,
2016-09-20 19:55:38 +08:00
const std::vector<acl::string>& tokens)
{
// format: chat|msg|to_user
if (tokens.size() != 3)
{
printf("format: chat|msg|to_user\r\n");
return false;
}
2016-09-23 22:04:07 +08:00
chat_client* from = find(from_conn);
if (from == NULL)
{
printf("not found from: %p\r\n", &from_conn);
(void) doStatus(from_conn, "not logined!");
return false;
}
2016-09-20 19:55:38 +08:00
const acl::string& msg = tokens[1];
const acl::string& to_user = tokens[2];
2016-09-23 22:04:07 +08:00
if (to_user.equal("all", false))
{
2016-09-23 22:45:53 +08:00
for (std::vector<chat_client*>::iterator it = __clients.begin();
it != __clients.end(); ++it)
2016-09-23 22:04:07 +08:00
{
doChat(from->get_name(), **it, msg);
}
return true;
}
2016-09-20 19:55:38 +08:00
chat_client* to_client = find(to_user);
if (to_client == NULL)
{
printf("no exist to_user: %s\r\n", to_user.c_str());
return true;
}
2016-09-23 22:04:07 +08:00
doChat(from->get_name(), *to_client, msg);
return true;
}
bool http_servlet::doChat(const acl::string& from_user,
chat_client& to_client, const acl::string& msg)
{
acl::string buf;
buf.format("chat|%s|%s", from_user.c_str(), msg.c_str());
acl::websocket out(to_client.get_conn());
2016-09-20 19:55:38 +08:00
out.set_frame_fin(true)
.set_frame_opcode(acl::FRAME_TEXT)
2016-09-23 22:04:07 +08:00
.set_frame_payload_len(buf.size());
2016-09-20 19:55:38 +08:00
2016-09-28 16:05:55 +08:00
if (out.send_frame_data(buf.c_str(), buf.size()) == false)
{
printf("----close socket: %d----\r\n",
to_client.get_conn().sock_handle());
shutdown(to_client.get_conn().sock_handle(), SHUT_RDWR);
//close(to_client.get_conn().sock_handle());
}
2016-09-20 19:55:38 +08:00
printf("status: ok, cmd: chat, msg: %s, to_user: %s\r\n",
2016-09-23 22:04:07 +08:00
msg.c_str(), to_client.get_name().c_str());
2016-09-20 19:55:38 +08:00
return true;
}
chat_client* http_servlet::find(const char* user)
{
2016-09-23 22:45:53 +08:00
for (std::vector<chat_client*>::iterator it = __clients.begin();
it != __clients.end(); ++it)
2016-09-20 19:55:38 +08:00
{
printf("user: %s, %s\r\n", user, (*it)->get_name().c_str());
if (*(*it) == user)
return *it;
}
return NULL;
}
2016-09-23 22:04:07 +08:00
chat_client* http_servlet::find(acl::socket_stream& conn)
{
2016-09-23 22:45:53 +08:00
for (std::vector<chat_client*>::iterator it = __clients.begin();
it != __clients.end(); ++it)
2016-09-23 22:04:07 +08:00
{
acl::socket_stream* ss = &(*it)->get_conn();
if (ss == &conn)
return *it;
}
printf("not found connection: %p\r\n", &conn);
return NULL;
}
2016-09-20 19:55:38 +08:00
void http_servlet::remove(acl::socket_stream& conn)
{
2016-09-23 22:45:53 +08:00
for (std::vector<chat_client*>::iterator it = __clients.begin();
it != __clients.end(); ++it)
2016-09-20 19:55:38 +08:00
{
acl::socket_stream* ss = &(*it)->get_conn();
if (ss == &conn)
{
2016-09-23 22:04:07 +08:00
printf("removed: %s\r\n", (*it)->get_name().c_str());
2016-09-23 22:45:53 +08:00
__clients.erase(it);
2016-09-20 19:55:38 +08:00
return;
}
}
printf("not found connection: %p\r\n", &conn);
}