acl/lib_acl_cpp/samples/http/webSocketServlet/WebsocketServlet_impl.cpp

205 lines
4.7 KiB
C++

#include "stdafx.h"
#include "WebsocketServlet_impl.h"
WebsocketServlet_impl::WebsocketServlet_impl(acl::redis_client_cluster& cluster,
size_t max_conns)
{
// 创建 session 存储对象
session_ = new acl::redis_session(cluster, max_conns);
step_ = 0;
}
WebsocketServlet_impl::~WebsocketServlet_impl(void)
{
delete session_;
}
bool WebsocketServlet_impl::doUnknown(acl::HttpServletRequest&,
acl::HttpServletResponse& res)
{
res.setStatus(400);
res.setContentType("text/html; charset=");
// 发送 http 响应头
if (res.sendHeader() == false)
return false;
// 发送 http 响应体
acl::string buf("<root error='unkown request method' />\r\n");
(void) res.getOutputStream().write(buf);
return false;
}
bool WebsocketServlet_impl::doGet(acl::HttpServletRequest& req,
acl::HttpServletResponse& res)
{
return doPost(req, res);
}
bool WebsocketServlet_impl::doPost(acl::HttpServletRequest& req,
acl::HttpServletResponse& res)
{
res.setContentType("text/html; charset=utf-8") // 设置响应字符集
.setContentEncoding(false) // 设置是否压缩数据
.setChunkedTransferEncoding(true); // 采用 chunk 传输方式
const char* ip = req.getLocalAddr();
if (ip == NULL || *ip == 0) {
logger_error("getLocalAddr error");
return false;
}
unsigned short port = req.getLocalPort();
if (port == 0) {
logger_error("getLocalPort error");
return false;
}
acl::string local_addr;
local_addr << ip << ":" << port;
printf("getLocalAddr: %s\r\n", local_addr.c_str());
acl::string html_file;
html_file << "www/upload.html";
acl::string buf;
if (acl::ifstream::load(html_file, &buf) == false) {
logger_error("load %s error %s",
html_file.c_str(), acl::last_serror());
return doError(req, res);
}
buf << "<script>g_url='ws://" << local_addr << "/'</script>";
// 发送 http 响应体,因为设置了 chunk 传输模式,所以需要多调用一次
// res.write 且两个参数均为 0 以表示 chunk 传输数据结束
return res.write(buf) && res.write(NULL, 0);
}
bool WebsocketServlet_impl::onPing(unsigned long long, bool)
{
return sendPong();
}
bool WebsocketServlet_impl::onPong(unsigned long long, bool)
{
return sendPing();
}
bool WebsocketServlet_impl::onMessage(unsigned long long payload_len,
bool text, bool finish)
{
(void) text;
(void) finish;
switch (step_) {
case 0:
step_++;
return getFilename(payload_len);
case 1:
step_++;
if (getFilesize(payload_len) == false) {
fp_.close();
return false;
}
return true;
case 2:
if (saveFile(payload_len) == false) {
fp_.close();
return false;
}
return true;
default:
return true;
}
}
bool WebsocketServlet_impl::getFilename(unsigned long long payload_len)
{
if (readData(payload_len, filename_) == false) {
printf("read filename error\r\n");
return false;
}
printf("get filename=%s\r\n", filename_.c_str());
if (fp_.open_trunc(filename_) == false) {
printf("open %s error %s\r\n", filename_.c_str(),
acl::last_serror());
return false;
}
return true;
}
bool WebsocketServlet_impl::getFilesize(unsigned long long payload_len)
{
acl::string buf;
if (readData(payload_len, buf) == false) {
printf("read filesize error\r\n");
fp_.close();
return false;
}
filesize_ = atoll(buf.c_str());
nread_ = 0;
printf("get filesize=%lld\r\n", filesize_);
if (filesize_ <= 0) {
fp_.close();
}
return filesize_ > 0;
}
bool WebsocketServlet_impl::readData(unsigned long long len, acl::string& path)
{
char buf[8192];
while (len > 0) {
size_t n = len > sizeof(buf) ? sizeof(buf) : len;
int ret = readPayload(buf, n);
if (ret == -1) {
printf("readPayload error\r\n");
return false;
}
path.append(buf, ret);
len -= ret;
}
return true;
}
bool WebsocketServlet_impl::saveFile(unsigned long long len)
{
char buf[8192];
while (nread_ < filesize_) {
size_t left = (size_t) (filesize_ - nread_);
size_t n = left > sizeof(buf) ? sizeof(buf) : left;
int ret = readPayload(buf, n);
if (ret == -1) {
printf("readPayload error\r\n");
return false;
}
if (ret == 0) {
break;
}
nread_ += ret;
if (fp_.write(buf, ret) == -1) {
printf("write data to %s error %s\r\n",
filename_.c_str(), acl::last_serror());
return false;
}
}
printf("file=%s, payload_len=%llu, filesize_=%lld, nread_=%lld\r\n",
filename_.c_str(), len, filesize_, nread_);
if (nread_ == filesize_) {
printf("READ OVER FOR FILE %s\r\n", filename_.c_str());
step_ = 0;
filesize_ = 0;
nread_ = 0;
filename_.clear();
fp_.close();
return sendText("+ok");
} else {
return true;
}
}