/** * Copyright (C) 2015-2018 * All rights reserved. * * AUTHOR(S) * Zheng Shuxin * E-mail: zhengshuxin@qiyi.com * * VERSION * Wed 14 Jun 2017 12:23:36 PM CST */ #include "stdafx.h" #include "action/service_list.h" #include "action/service_stat.h" #include "action/service_start.h" #include "action/service_kill.h" #include "action/service_stop.h" #include "action/service_reload.h" #include "action/service_restart.h" #include "action/service_master_config.h" #include "http_client.h" http_client::http_client(acl::aio_socket_stream *client, int rw_timeout) : conn_(client->get_astream()) , rw_timeout_(rw_timeout) , content_length_(0) { hdr_req_ = NULL; req_ = NULL; acl_aio_add_close_hook(conn_, on_close, this); acl_aio_add_timeo_hook(conn_, on_timeo, this); } http_client::~http_client(void) { if (req_) http_req_free(req_); else if (hdr_req_) http_hdr_req_free(hdr_req_); } void http_client::reset(void) { if (req_) { http_req_free(req_); req_ = NULL; } else if (hdr_req_) http_hdr_req_free(hdr_req_); hdr_req_ = http_hdr_req_new(); json_.reset(); } void http_client::wait(void) { reset(); http_hdr_req_get_async(hdr_req_, conn_, on_head, this, rw_timeout_); } int http_client::on_close(ACL_ASTREAM*, void* ctx) { http_client* hc = (http_client*) ctx; delete hc; return 0; } int http_client::on_timeo(ACL_ASTREAM*, void*) { // return -1 so the connection can be closed return -1; } int http_client::on_head(int status, void* ctx) { http_client* hc = (http_client*) ctx; acl_aio_disable_readwrite(hc->conn_); if (status != HTTP_CHAT_OK) { logger_error("invalid status=%d", status); acl_aio_iocp_close(hc->conn_); return -1; } if (http_hdr_req_parse(hc->hdr_req_) < 0) { logger_error("parse http header error"); acl_aio_iocp_close(hc->conn_); return -1; } hc->content_length_ = hc->hdr_req_->hdr.content_length; if (hc->content_length_ <= 0) return hc->handle() ? 0 : -1; hc->req_ = http_req_new(hc->hdr_req_); http_req_body_get_async(hc->req_, hc->conn_, on_body, hc, hc->rw_timeout_); return 0; } int http_client::on_body(int status, char *data, int dlen, void *ctx) { http_client* hc = (http_client*) ctx; if (status >= HTTP_CHAT_ERR_MIN) { logger_error("status=%d", status); acl_aio_iocp_close(hc->conn_); return -1; } if (dlen <= 0) { logger_error("invalid dlen=%d", dlen); acl_aio_iocp_close(hc->conn_); return -1; } hc->json_.update(data); if (status == HTTP_CHAT_OK) { acl_aio_disable_readwrite(hc->conn_); return hc->handle() ? 0 : -1; } return 0; } void http_client::do_reply(int status, const char* cmd, const acl::string& body, bool save) { HTTP_HDR_RES* hdr_res = http_hdr_res_static(status); http_hdr_set_keepalive(hdr_req_, hdr_res); http_hdr_put_str(&hdr_res->hdr, "Content-Type", "text/json"); http_hdr_put_int(&hdr_res->hdr, "Content-Length", (int) body.size()); acl::string buf(body.size() + 256); http_hdr_build(&hdr_res->hdr, buf.vstring()); http_hdr_res_free(hdr_res); buf.append(body); if (save) { // logger the important command's information acl::string reqhdr; http_hdr_sprint(reqhdr.vstring(), &hdr_req_->hdr, cmd); logger("cmd=[%s]:\r\n[%s\r\n%s]\r\n\r\n[%s]\r\n", cmd, reqhdr.c_str(), json_.to_string().c_str(), buf.c_str()); } acl_aio_writen(conn_, buf.c_str(), (int) buf.size()); } static struct { const char* cmd; bool (http_client::*handler)(void); } handlers[] = { { "list", &http_client::handle_list }, { "stat", &http_client::handle_stat }, { "start", &http_client::handle_start }, { "kill", &http_client::handle_kill }, { "stop", &http_client::handle_stop }, { "restart", &http_client::handle_restart }, { "reload", &http_client::handle_reload }, { "master_config",&http_client::handle_master_config }, { 0, 0 } }; bool http_client::handle(void) { const char* cmd = http_hdr_req_param(hdr_req_, "cmd"); if (cmd == NULL || *cmd == 0) { //logger_error("cmd null"); acl::string dummy; do_reply(400, "none", dummy, false); if (hdr_req_->hdr.keep_alive) wait(); else acl_aio_iocp_close(conn_); return true; } #define EQ !strcasecmp int i; for (i = 0; handlers[i].cmd != NULL; i++) { if (EQ(cmd, handlers[i].cmd)) break; } if (handlers[i].handler == NULL) { logger_warn("invalid cmd=%s", cmd); acl::string dummy; do_reply(400, "unknown", dummy, false); if (hdr_req_->hdr.keep_alive) wait(); else acl_aio_iocp_close(conn_); return true; } if ((this->*handlers[i].handler)()) return true; acl_aio_iocp_close(conn_); return false; } bool http_client::handle_list(void) { service_list service(*this); return service.run(json_); } bool http_client::handle_stat(void) { service_stat service(*this); return service.run(json_); } bool http_client::handle_kill(void) { service_kill service(*this); return service.run(json_); } bool http_client::handle_stop(void) { service_stop service(*this); return service.run(json_); } bool http_client::handle_start(void) { service_start* service = new service_start(*this); return service->run(json_); } bool http_client::handle_restart(void) { service_restart service(*this); return service.run(json_); } bool http_client::handle_reload(void) { service_reload* service = new service_reload(*this); return service->run(json_); } bool http_client::handle_master_config(void) { service_master_config service(*this); return service.run(json_); } void http_client::on_finish(void) { if (hdr_req_->hdr.keep_alive) wait(); else acl_aio_iocp_close(conn_); }