mirror of
https://gitee.com/acl-dev/acl.git
synced 2024-12-05 13:29:03 +08:00
252 lines
5.9 KiB
C++
252 lines
5.9 KiB
C++
// http_servlet.cpp : 定义控制台应用程序的入口点。
|
||
//
|
||
#include <assert.h>
|
||
#include "acl_cpp/lib_acl.hpp"
|
||
|
||
static void (*format)(const char*, ...) = acl::log::msg1;
|
||
|
||
using namespace acl;
|
||
|
||
//////////////////////////////////////////////////////////////////////////
|
||
|
||
class master_service : public master_proc
|
||
{
|
||
public:
|
||
master_service(const char* to_charset = "gb2312")
|
||
{
|
||
local_charset_ = to_charset;
|
||
}
|
||
|
||
~master_service() {}
|
||
|
||
void set_charset(const char* to_charset)
|
||
{
|
||
local_charset_ = to_charset;
|
||
}
|
||
|
||
protected:
|
||
// 当接收到客户端连接流后回调的虚接口
|
||
virtual void on_accept(socket_stream* stream)
|
||
{
|
||
http_response res(stream);
|
||
|
||
// 读客户端的 HTTP 请求头
|
||
if (res.read_header() == false)
|
||
{
|
||
const char* ptr = "read request header error";
|
||
res.response_header().set_status(400).set_keep_alive(false);
|
||
res.response(ptr, strlen(ptr));
|
||
return;
|
||
}
|
||
|
||
// 从 HTTP 请求头中取出 Content-Type 字段值
|
||
// Content-Type: text/xml; charset=utf-8
|
||
http_client* client = res.get_client();
|
||
assert(client);
|
||
const char* p = client->header_value("Content-Type");
|
||
if (p == NULL || *p == 0)
|
||
{
|
||
const char* ptr = "no Content-Type";
|
||
res.response_header().set_status(400).set_keep_alive(false);
|
||
res.response(ptr, strlen(ptr));
|
||
return;
|
||
}
|
||
|
||
// 从 HTTP 请求头中取得数据类型中的子类型
|
||
// 如果请求头中有:Content-Type: text/xml; charset=utf-8
|
||
// 则 get_stype 取得 xml 子类型
|
||
http_ctype content_type;
|
||
content_type.parse(p);
|
||
const char* stype = content_type.get_stype();
|
||
const char* req_charset = content_type.get_charset();
|
||
|
||
bool ret;
|
||
string err;
|
||
|
||
// 根据子类型的不同调用不同的处理过程
|
||
|
||
if (stype == NULL)
|
||
ret = do_plain(res, req_charset, err);
|
||
|
||
// text/xml 格式
|
||
else if (strcasecmp(stype, "xml") == 0)
|
||
ret = do_xml(res, req_charset, err);
|
||
|
||
// text/json 格式
|
||
else if (strcasecmp(stype, "json") == 0)
|
||
ret = do_json(res, req_charset, err);
|
||
else
|
||
ret = do_plain(res, req_charset, err);
|
||
if (ret == false)
|
||
res.response(err.c_str(), err.length());
|
||
}
|
||
|
||
private:
|
||
// 处理 text/plain 数据体
|
||
bool do_plain(http_response& res, const char* req_charset, string& err)
|
||
{
|
||
string body;
|
||
if (res.get_body(body, local_charset_) == false)
|
||
{
|
||
err += "get_body error";
|
||
return false;
|
||
}
|
||
printf("body:\r\n(%s)\r\n", body.c_str());
|
||
|
||
// 设置响应头字段
|
||
http_header& header = res.response_header();
|
||
string ctype("text/plain");
|
||
if (req_charset)
|
||
{
|
||
ctype << "; charset=" << req_charset;
|
||
header.set_content_type(ctype);
|
||
}
|
||
else
|
||
header.set_content_type(ctype);
|
||
|
||
printf(">>ctype: %s\r\n", ctype.c_str());
|
||
|
||
// 发送响应体数据
|
||
return response_body(res, body, req_charset);
|
||
}
|
||
|
||
// 处理 text/xml 数据体
|
||
bool do_xml(http_response& res, const char* req_charset, string& err)
|
||
{
|
||
xml body;
|
||
if (res.get_body(body, local_charset_) == false)
|
||
{
|
||
err += "get_body error";
|
||
return false;
|
||
}
|
||
xml_node* node = body.first_node();
|
||
while (node)
|
||
{
|
||
const char* tag = node->tag_name();
|
||
const char* name = node->attr_value("name");
|
||
const char* pass = node->attr_value("pass");
|
||
printf(">>tag: %s, name: %s, pass: %s\r\n",
|
||
tag ? tag : "null",
|
||
name ? name : "null",
|
||
pass ? pass : "null");
|
||
node = body.next_node();
|
||
}
|
||
|
||
// 设置响应头字段
|
||
http_header& header = res.response_header();
|
||
string ctype("text/xml");
|
||
if (req_charset)
|
||
{
|
||
ctype << "; charset=" << req_charset;
|
||
header.set_content_type(ctype);
|
||
}
|
||
else
|
||
header.set_content_type(ctype);
|
||
|
||
printf(">>ctype: %s\r\n", ctype.c_str());
|
||
|
||
// 构建响应体数据,并发送响应体数据
|
||
string buf;
|
||
body.build_xml(buf);
|
||
|
||
// 发送响应体数据
|
||
return response_body(res, buf, req_charset);
|
||
}
|
||
|
||
// 处理 text/json 数据
|
||
bool do_json(http_response& res, const char* req_charset, string& err)
|
||
{
|
||
json body;
|
||
if (res.get_body(body, local_charset_) == false)
|
||
{
|
||
err += "get_body error";
|
||
return false;
|
||
}
|
||
|
||
json_node* node = body.first_node();
|
||
while (node)
|
||
{
|
||
if (node->tag_name())
|
||
{
|
||
printf("tag: %s", node->tag_name());
|
||
if (node->get_text())
|
||
printf(", value: %s\r\n", node->get_text());
|
||
else
|
||
printf("\r\n");
|
||
}
|
||
node = body.next_node();
|
||
}
|
||
|
||
// 设置响应头字段
|
||
http_header& header = res.response_header();
|
||
string ctype("text/json");
|
||
if (req_charset)
|
||
{
|
||
ctype << "; charset=" << req_charset;
|
||
header.set_content_type(ctype);
|
||
}
|
||
else
|
||
header.set_content_type(ctype);
|
||
|
||
printf(">>ctype: %s\r\n", ctype.c_str());
|
||
|
||
// 构建响应体数据,并发送响应体数据
|
||
string buf;
|
||
body.build_json(buf);
|
||
|
||
// 发送响应体数据
|
||
return response_body(res, buf, req_charset);
|
||
}
|
||
|
||
bool response_body(http_response& res, const string& body,
|
||
const char* req_charset)
|
||
{
|
||
// 如果本地字符集与请求字符集相同,则直接发送
|
||
if (local_charset_ == req_charset)
|
||
return res.response(body.c_str(), body.length());
|
||
|
||
// 不一致时,则需要进行转码
|
||
string buf;
|
||
charset_conv conv;
|
||
if (conv.convert(local_charset_, req_charset,
|
||
body.c_str(), body.length(), &buf) == false)
|
||
{
|
||
logger_error("charset convert from %s to %s error",
|
||
local_charset_.c_str(), req_charset);
|
||
return false;
|
||
}
|
||
|
||
printf(">>response\r\n(%s)\r\n", buf.c_str());
|
||
return res.response(buf.c_str(), buf.length());
|
||
}
|
||
|
||
private:
|
||
string local_charset_;
|
||
};
|
||
|
||
//////////////////////////////////////////////////////////////////////////
|
||
|
||
int main(int argc, char* argv[])
|
||
{
|
||
#ifdef WIN32
|
||
acl::acl_cpp_init();
|
||
#endif
|
||
master_service service; // 服务器单例对象
|
||
|
||
// 开始运行
|
||
|
||
if (argc >= 2 && strcmp(argv[1], "alone") == 0)
|
||
{
|
||
if (argc >= 3)
|
||
service.set_charset(argv[2]);
|
||
|
||
format = (void (*)(const char*, ...)) printf;
|
||
printf("listen: 0.0.0.0:8888 ...\r\n");
|
||
service.run_alone("0.0.0.0:8888", NULL, 1); // 单独运行方式
|
||
}
|
||
else
|
||
service.run_daemon(argc, argv); // acl_master 控制模式运行
|
||
|
||
return 0;
|
||
}
|