http module can response json&xml data

This commit is contained in:
shuxin   zheng 2020-06-26 15:21:13 +08:00
parent ccce38b52d
commit dee4ebeaea
11 changed files with 251 additions and 40 deletions

View File

@ -37,7 +37,7 @@ public:
* @param memcache_addr {const char*}
*/
HttpServlet(socket_stream* stream,
const char* memcache_addr = "127.0.0.1:11211");
const char* memcache_addr = "127.0.0.1|11211");
HttpServlet(void);
virtual ~HttpServlet(void) = 0;

View File

@ -8,6 +8,8 @@ namespace acl {
class dbuf_guard;
class string;
class xml;
class json;
class ostream;
class socket_stream;
class http_header;
@ -191,6 +193,22 @@ public:
*/
bool write(const string& buf);
/**
* HTTP Xml
* @param buf {const xml&}
* @param charset {const char*}
* @return {bool} false
*/
bool write(const xml& body, const char* charset = "utf-8");
/**
* HTTP Json
* @param buf {const json&}
* @param charset {const char*}
* @return {bool} false
*/
bool write(const json& body, const char* charset = "utf-8");
/**
* HTTP
* HttpServletResponse::write(const void*, size_t) 使

View File

@ -434,7 +434,7 @@ public:
* HTTP chunked
* @return {bool}
*/
bool chunked_transfer() const
bool chunked_transfer(void) const
{
return chunked_transfer_;
}

View File

@ -38,7 +38,7 @@ typedef enum
HTTP_METHOD_HEAD, // HEAD 方法
HTTP_METHOD_OPTION, // OPTION 方法
HTTP_METHOD_PROPFIND, // PROPFIND 方法
HTTP_METHOD_PATCH, // PATCH 方法
HTTP_METHOD_PATCH, // PATCH 方法
HTTP_METHOD_OTHER, // 其它的方法
} http_method_t;

View File

@ -24,7 +24,7 @@ HttpServlet::HttpServlet(socket_stream* stream, session* session)
init();
if (session == NULL) {
session_ = NEW memcache_session("127.0.0.1");
session_ = NEW memcache_session("127.0.0.1|11211");
session_ptr_ = session_;
} else {
session_ = session;

View File

@ -3,6 +3,8 @@
#include "acl_cpp/stdlib/dbuf_pool.hpp"
#include "acl_cpp/stdlib/snprintf.hpp"
#include "acl_cpp/stdlib/string.hpp"
#include "acl_cpp/stdlib/xml.hpp"
#include "acl_cpp/stdlib/json.hpp"
#include "acl_cpp/stream/ostream.hpp"
#include "acl_cpp/stream/socket_stream.hpp"
#include "acl_cpp/http/http_header.hpp"
@ -223,6 +225,39 @@ int HttpServletResponse::format(const char* fmt, ...)
return ret;
}
bool HttpServletResponse::write(const xml& body, const char* charset /* utf-8 */)
{
if (charset && *charset) {
setCharacterEncoding(charset);
}
setContentType("application/xml");
const string& buf = body.to_string();
if (!header_->chunked_transfer()) {
setContentLength(buf.size());
return write(buf.c_str(), buf.size());
}
return write(buf.c_str(), buf.size()) && write(NULL, 0);
}
bool HttpServletResponse::write(const json& body, const char* charset /* utf-8 */)
{
if (charset && *charset) {
setCharacterEncoding(charset);
}
setContentType("application/json");
const string& buf = body.to_string();
if (!header_->chunked_transfer()) {
setContentLength(buf.size());
return write(buf.c_str(), buf.size());
}
return write(buf.c_str(), buf.size()) && write(NULL, 0);
}
void HttpServletResponse::encodeUrl(string& out, const char* url)
{
out.clear();

View File

@ -15,47 +15,62 @@ typedef std::function<bool(acl::socket_stream&)> thread_accept_t;
class http_server_impl : public master_fiber {
public:
http_server_impl(void) {}
http_server_impl(const char* addr, bool use_redis) {
if (use_redis) {
redis_ = new redis_client_cluster;
redis_->init(NULL, addr, 0, 10, 10);
redis_->bind_thread(true);
}
}
virtual ~http_server_impl(void) {}
public:
http_server_impl& service(const std::string& path, handler_t fn) {
return service(path.c_str(), fn);
}
void onService(int type, const char* path, http_handler_t fn) {
if (type >= http_handler_get && type < http_handler_max
&& path && *path) {
// The path should lookup like as "/xxx/" with
// lower charactors.
http_server_impl& service(const char* path, handler_t fn) {
if (path && *path) {
acl::string buf(path);
if (buf[buf.size() - 1] != '/') {
buf += '/';
}
buf.lower();
handlers_[buf] = std::move(fn);
handlers_[type][buf] = std::move(fn);
}
return *this;
}
protected:
std::map<acl::string, handler_t> handlers_;
redis_client_cluster* redis_ = nullptr;
proc_jail_t proc_jail_ = nullptr;
proc_init_t proc_init_ = nullptr;
proc_exit_t proc_exit_ = nullptr;
proc_sighup_t proc_sighup_ = nullptr;
thread_init_t thread_init_ = nullptr;
thread_accept_t thread_accept_ = nullptr;
http_handlers_t handlers_[http_handler_max];
// @override
void on_accept(socket_stream& conn) {
if (thread_accept_) {
if (!thread_accept_(conn)) {
return;
}
if (thread_accept_ && !thread_accept_(conn)) {
return;
}
memcache_session session("127.0.0.1:11211");
http_servlet servlet(handlers_, &conn, &session);
servlet.setLocalCharset("gb2312");
acl::session* session;
if (redis_) {
session = new redis_session(*redis_, 0);
} else {
session = new memcache_session("127.0.0.1|11211");
}
http_servlet servlet(handlers_, &conn, session);
servlet.setLocalCharset("utf-8");
while (servlet.doRun()) {}
delete session;
}
// @override

View File

@ -10,14 +10,32 @@ namespace acl {
class HttpServletRequest;
class HttpServletResponse;
typedef HttpServletRequest request_t;
typedef HttpServletResponse response_t;
typedef HttpServletRequest HttpRequest;
typedef HttpServletResponse HttpResponse;
typedef std::function<bool(request_t&, response_t&)> handler_t;
typedef std::function<bool(HttpRequest&, HttpResponse&)> http_handler_t;
typedef std::map<acl::string, http_handler_t> http_handlers_t;
enum {
http_handler_get = 0,
http_handler_post,
http_handler_head,
http_handler_put,
http_handler_patch,
http_handler_connect,
http_handler_purge,
http_handler_delete,
http_handler_options,
http_handler_profind,
http_handler_websocket,
http_handler_error,
http_handler_unknown,
http_handler_max,
};
class http_servlet_impl : public HttpServlet {
public:
http_servlet_impl(std::map<acl::string, handler_t>& handlers,
http_servlet_impl(http_handlers_t* handlers,
socket_stream* stream, session* session)
: HttpServlet(stream, session), handlers_(handlers) {}
@ -25,12 +43,76 @@ public:
protected:
// override
bool doGet(request_t& req, response_t& res) {
return doPost(req, res);
bool doGet(HttpRequest& req, HttpResponse& res) {
return doService(http_handler_get, req, res);
}
// override
bool doPost(request_t& req, response_t& res) {
bool doPost(HttpRequest& req, HttpResponse& res) {
return doService(http_handler_post, req, res);
}
// override
bool doHead(HttpRequest& req, HttpResponse& res) {
return doService(http_handler_head, req, res);
}
// override
bool doPut(HttpRequest& req, HttpResponse& res) {
return doService(http_handler_put, req, res);
}
// override
bool doPatch(HttpRequest& req, HttpResponse& res) {
return doService(http_handler_patch, req, res);
}
// override
bool doConnect(HttpRequest& req, HttpResponse& res) {
return doService(http_handler_connect, req, res);
}
// override
bool doPurge(HttpRequest& req, HttpResponse& res) {
return doService(http_handler_purge, req, res);
}
// override
bool doDelete(HttpRequest& req, HttpResponse& res) {
return doService(http_handler_delete, req, res);
}
// override
bool doOptions(HttpRequest& req, HttpResponse& res) {
return doService(http_handler_options, req, res);
}
// override
bool doProfind(HttpRequest& req, HttpResponse& res) {
return doService(http_handler_profind, req, res);
}
// override
bool doWebsocket(HttpRequest& req, HttpResponse& res) {
return doService(http_handler_websocket, req, res);
}
// override
bool doUnknown(HttpRequest& req, HttpResponse& res) {
return doService(http_handler_unknown, req, res);
}
// override
bool doError(HttpRequest& req, HttpResponse& res) {
return doService(http_handler_error, req, res);
}
private:
bool doService(int type, HttpRequest& req, HttpResponse& res) {
if (type < http_handler_get || type >= http_handler_max) {
return false;
}
res.setKeepAlive(req.isKeepAlive());
bool keep = req.isKeepAlive();
@ -49,10 +131,10 @@ protected:
}
buf.lower();
std::map<acl::string, handler_t>::iterator it
= handlers_.find(buf);
std::map<acl::string, http_handler_t>::iterator it
= handlers_[type].find(buf);
if (it != handlers_.end()) {
if (it != handlers_[type].end()) {
return it->second(req, res) && keep;
}
@ -65,7 +147,7 @@ protected:
}
private:
std::map<acl::string, handler_t> handlers_;
http_handlers_t* handlers_;
};
} // namespace acl

View File

@ -7,17 +7,67 @@ namespace acl {
class http_server : public http_server_impl {
public:
http_server(void) {}
http_server(const char* addr = "127.0.0.1|6379", bool use_redis = true) : http_server_impl(addr, use_redis) {}
~http_server(void) {}
public:
http_server& get(const std::string path, handler_t fn) {
this->service(path, fn);
http_server& onGet(const char* path, http_handler_t fn) {
this->onService(http_handler_get, path, fn);
return *this;
}
http_server& post(const std::string& path, handler_t fn) {
this->service(path, fn);
http_server& onPost(const char* path, http_handler_t fn) {
this->onService(http_handler_post, path, fn);
return *this;
}
http_server& onHead(const char* path, http_handler_t fn) {
this->onService(http_handler_head, path, fn);
return *this;
}
http_server& onPut(const char* path, http_handler_t fn) {
this->onService(http_handler_put, path, fn);
return *this;
}
http_server& onPatch(const char* path, http_handler_t fn) {
this->onService(http_handler_patch, path, fn);
return *this;
}
http_server& onConnect(const char* path, http_handler_t fn) {
this->onService(http_handler_connect, path, fn);
return *this;
}
http_server& onPurge(const char* path, http_handler_t fn) {
this->onService(http_handler_purge, path, fn);
return *this;
}
http_server& onDelete(const char* path, http_handler_t fn) {
this->onService(http_handler_delete, path, fn);
return *this;
}
http_server& onOptions(const char* path, http_handler_t fn) {
this->onService(http_handler_options, path, fn);
return *this;
}
http_server& onPropfind(const char* path, http_handler_t fn) {
this->onService(http_handler_profind, path, fn);
return *this;
}
http_server& onError(const char* path, http_handler_t fn) {
this->onService(http_handler_error, path, fn);
return *this;
}
http_server& onWebsocket(const char* path, http_handler_t fn) {
this->onService(http_handler_websocket, path, fn);
return *this;
}

View File

@ -8,7 +8,7 @@ namespace acl {
class http_servlet : public http_servlet_impl {
public:
http_servlet(std::map<acl::string, handler_t>& handlers,
http_servlet(http_handlers_t* handlers,
socket_stream* stream, session* session)
: http_servlet_impl(handlers, stream, session) {}

View File

@ -67,19 +67,30 @@ int main(int argc, char *argv[]) {
// set http route
server.get("/", [](acl::request_t&, acl::response_t& res) {
server.onGet("/", [](acl::HttpRequest&, acl::HttpResponse& res) {
acl::string buf("hello world1!\r\n");
res.setContentLength(buf.size());
return res.write(buf.c_str(), buf.size());
}).get("/hello", [](acl::request_t&, acl::response_t& res) {
}).onGet("/hello", [](acl::HttpRequest&, acl::HttpResponse& res) {
acl::string buf("hello world2!\r\n");
res.setContentLength(buf.size());
return res.write(buf.c_str(), buf.size());
}).post("/ok", [](acl::request_t& req, acl::response_t& res) {
}).onPost("/ok", [](acl::HttpRequest& req, acl::HttpResponse& res) {
acl::string buf;
req.getBody(buf);
res.setContentLength(buf.size());
return res.write(buf.c_str(), buf.size());
}).onGet("/json", [](acl::HttpRequest&, acl::HttpResponse& res) {
acl::json json;
acl::json_node& root = json.get_root();
root.add_number("code", 200)
.add_text("status", "+ok")
.add_child("data",
json.create_node()
.add_text("name", "value")
.add_bool("success", true)
.add_number("number", 100));
return res.write(json);
});
// start the server in alone or daemon mode