bool http_servlet::reply_json(acl::HttpServletRequest&, acl::HttpServletResponse& res, int status, const acl::string& data) { res.setStatus(status) .setContentType("text/json; charset=utf-8") .setContentLength(data.size()); return res.write(data, data.size()) && res.write(NULL, 0); }
bool http_servlet::reply(acl::HttpServletRequest&, acl::HttpServletResponse& res, int status, const acl::string& buf) { res.setStatus(status) .setContentType("text/plain; charset=utf-8") .setContentLength(buf.size()); return res.write(buf, buf.size()) && res.write(NULL, 0); }
bool http_servlet::doOther(acl::HttpServletRequest&, acl::HttpServletResponse& res, const char* method) { res.setStatus(400); res.setContentType("text/xml; charset=utf-8"); // 发送 http 响应体 acl::string buf; buf.format("<root error='unkown request method %s' />\r\n", method); res.write(buf); res.write(NULL, 0); return false; }
bool http_servlet::doError(acl::HttpServletRequest&, acl::HttpServletResponse& res) { res.setStatus(400); res.setContentType("text/xml; charset=utf-8"); // 发送 http 响应体 acl::string buf; buf.format("<root error='some error happened!' />\r\n"); res.write(buf); res.write(NULL, 0); return false; }
bool http_servlet::doUnknown(acl::HttpServletRequest&, acl::HttpServletResponse& res) { res.setStatus(400); res.setContentType("text/html; charset=$<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 http_servlet::doUnknown(acl::HttpServletRequest& req, acl::HttpServletResponse& res) { out_.format(">>> request method: doUnknown <<<\r\n"); logger_request(req); res.setStatus(400); res.setContentType("text/html; charset="); // 发送 http 响应体 acl::string buf("<root error='unkown request method' />\r\n"); (void) res.getOutputStream().write(buf); return false; }
bool http_servlet::doReply(acl::HttpServletRequest&, acl::HttpServletResponse& res, int status, const char* fmt, ...) { acl::string buf; va_list ap; va_start(ap, fmt); buf.vformat(fmt, ap); va_end(ap); res.setStatus(status); res.setContentLength(buf.size()); return res.write(buf) && res.write(NULL, 0); }
bool http_servlet::doOther(acl::HttpServletRequest&, acl::HttpServletResponse& res, const char* method) { res.setStatus(400); res.setContentType("text/html; charset="); // 发送 http 响应头 if (res.sendHeader() == false) return false; // 发送 http 响应体 acl::string buf; buf.format("<root error='unkown request method %s' />\r\n", method); (void) res.getOutputStream().write(buf); return false; }
bool http_servlet::doError(acl::HttpServletRequest&, acl::HttpServletResponse& res) { res.setStatus(400); res.setContentType("text/html; charset="); // 发送 http 响应头 if (res.sendHeader() == false) return false; // 发送 http 响应体 acl::string buf; buf.format("<root error='some error happened!' />\r\n"); (void) res.getOutputStream().write(buf); return false; }
bool http_servlet::doPost(acl::HttpServletRequest& req, acl::HttpServletResponse& res) { // 如果需要 http session 控制,请打开下面注释,且需要保证 // 在 master_service.cpp 的函数 thread_on_read 中设置的 // memcached 服务正常工作 /* const char* sid = req.getSession().getAttribute("sid"); if (*sid == 0) req.getSession().setAttribute("sid", "xxxxxx"); sid = req.getSession().getAttribute("sid"); */ // 如果需要取得浏览器 cookie 请打开下面注释 /* const char* mycookie = req.getCookieValue("mycookie"); if (mycookie == NULL) res.addCookie("mycookie", "{xxx}"); */ bool keep_alive = req.isKeepAlive(); res.setContentType("text/xml; charset=utf-8") // 设置响应字符集 .setKeepAlive(keep_alive) // 设置是否保持长连接 .setChunkedTransferEncoding(true); // 采用 chunk 传输方式 const char* param1 = req.getParameter("name1"); const char* param2 = req.getParameter("name2"); // 创建 xml 格式的数据体 acl::xml body; body.get_root() .add_child("root", true) .add_child("params", true) .add_child("param", true) .add_attr("name1", param1 ? param1 : "null") .get_parent() .add_child("param", true) .add_attr("name2", param2 ? param2 : "null"); acl::string buf; body.build_xml(buf); // 发送 http 响应体,因为设置了 chunk 传输模式,所以需要多调用一次 // res.write 且两个参数均为 0 以表示 chunk 传输数据结束 return res.write(buf) && res.write(NULL, 0) && keep_alive; }
bool http_servlet::doReply(acl::HttpServletRequest& req, acl::HttpServletResponse& res, const char* info) { // 创建 xml 格式的数据体 acl::xml1 body; body.get_root().add_child("root", true) .add_child("content_type", true) .add_attr("type", (int) req.getRequestType()) .get_parent() .add_child("info", true) .set_text(info) .get_parent() .add_child("params", true) .add_child("param", true) .add_attr("name1", param1_) .get_parent() .add_child("param", true) .add_attr("name2", param2_) .get_parent() .add_child("param", true) .add_attr("name3", param3_) .get_parent() .add_child("files", true) .add_child("file", true) .add_attr("filename", file1_) .add_attr("fsize", fsize1_) .get_parent() .add_child("file", true) .add_attr("filename", file2_) .add_attr("fsize", fsize2_) .get_parent() .add_child("file", true) .add_attr("filename", file3_) .add_attr("fsize", fsize3_); acl::string buf; body.build_xml(buf); logger(">>%s<<", buf.c_str()); return res.write(buf) && res.write(NULL, 0); }
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 http_servlet::doPost(acl::HttpServletRequest& req, acl::HttpServletResponse& res) { res.setContentType("text/html; charset=utf-8") // 设置响应字符集 .setContentEncoding(true) // 设置是否压缩数据 .setChunkedTransferEncoding(false); // 采用 chunk 传输方式 acl::string html_file; html_file << var_cfg_html_path << "/client.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); } // 发送 http 响应体,因为设置了 chunk 传输模式,所以需要多调用一次 // res.write 且两个参数均为 0 以表示 chunk 传输数据结束 return res.write(buf) && res.write(NULL, 0); }
bool http_servlet::doGet(acl::HttpServletRequest& req, acl::HttpServletResponse& res) { res.setContentType("text/plain") .setKeepAlive(req.isKeepAlive()); acl::string body; body.format("%s version: %s; %s %s %s\r\n", MASTER_NAME, MASTER_VERSION, MASTER_CTLD_CMD, MASTER_CTLD_VERSION, MASTER_CTLD_DATE); return reply(req, res, 200, body); }
bool http_servlet::doReply(acl::HttpServletRequest& req, acl::HttpServletResponse& res, int status, acl::json& json) { res.setStatus(status); res.setContentType("text/json"); if (1) res.setKeepAlive(req.isKeepAlive()); else res.setKeepAlive(false); const acl::string& data = json.to_string(); res.setContentLength(data.size()); return res.write(data) && res.write(NULL, 0); }
bool http_servlet::doPost(acl::HttpServletRequest& req, acl::HttpServletResponse& res) { // 如果需要 http session 控制,请打开下面注释,且需要保证 // 在 master_service.cpp 的函数 thread_on_read 中设置的 // memcached 服务正常工作 /* const char* sid = req.getSession().getAttribute("sid"); if (*sid == 0) req.getSession().setAttribute("sid", "xxxxxx"); sid = req.getSession().getAttribute("sid"); */ res.setCharacterEncoding("utf-8") // 设置响应字符集 .setKeepAlive(req.isKeepAlive()) // 设置是否保持长连接 .setContentEncoding(false) // 自动支持压缩传输 .setChunkedTransferEncoding(false); // 采用 chunk 传输方式 acl::string path; path = req.getPathInfo(); if (path.empty()) { logger_error("getPathInfo NULL"); return doReply(req, res, 400, "%s", "no PathInfo"); } path.strip(".."); if (path.empty()) { logger_error("path empty"); return doReply(req, res, 400, "%s", "path empty"); } const std::vector<acl::string>& tokens = path.split2("/"); // printf(">>>path: %s, size: %ld\r\n", path.c_str(), tokens.size()); if (tokens.size() < 2 || !tokens[1].equal("website", false)) return doApp(req, res); else return doDoc(req, res, path); }
bool http_servlet::doPost(acl::HttpServletRequest& req, acl::HttpServletResponse& res) { // 如果需要 http session 控制,请打开下面注释,且需要保证 // 在 master_service.cpp 的函数 thread_on_read 中设置的 // memcached 服务正常工作 /* const char* sid = req.getSession().getAttribute("sid"); if (*sid == 0) req.getSession().setAttribute("sid", "xxxxxx"); sid = req.getSession().getAttribute("sid"); */ // 如果需要取得浏览器 cookie 请打开下面注释 /* */ res.setContentType("text/xml; charset=utf-8") // 设置响应字符集 .setKeepAlive(req.isKeepAlive()) // 设置是否保持长连接 .setContentEncoding(true) // 自动支持压缩传输 .setChunkedTransferEncoding(false); // chunk 传输方式 const char* cmd = req.getParameter("cmd"); if (cmd == NULL || *cmd == 0) { logger_error("cmd not found"); return replyf(req, res, 400, "%s", "no cmd"); } #define EQ !strcasecmp acl::string buf; commands_action action(addr_, req, res, cmd); action.set_conf(conf_); int status = action.run(buf); return reply_json(req, res, status, buf); }
bool http_servlet::doPost(acl::HttpServletRequest& req, acl::HttpServletResponse& res) { res.setContentType("text/xml; charset=gbk") // 设置响应字符集 .setKeepAlive(req.isKeepAlive()) // 设置是否保持长连接 .setContentEncoding(true) // 自动支持压缩传输 .setChunkedTransferEncoding(true); // 采用 chunk 传输方式 // 获得 HTTP 请求的数据类型,正常的参数类型,即 name&value 方式 // 还是 MIME 数据类型,还是数据流类型 acl::http_request_t request_type = req.getRequestType(); if (request_type != acl::HTTP_REQUEST_MULTIPART_FORM) { acl::string buf; buf.format("<root error='should acl::HTTP_REQUEST_MULTIPART_FORM' />\r\n"); (void) res.write(buf); (void) res.write(NULL, 0); return false; } // 先获得 Content-Type 对应的 http_ctype 对象 mime_ = req.getHttpMime(); if (mime_ == NULL) { logger_error("http_mime null"); (void) doReply(req, res, "http_mime null"); return false; } // 获得数据体的长度 content_length_ = req.getContentLength(); if (content_length_ <= 0) { logger_error("body empty"); (void) doReply(req, res, "body empty"); return false; } acl::string filepath; #if defined(_WIN32) || defined(_WIN64) filepath.format("%s\\mime_file", var_cfg_var_path); #else filepath.format("%s/mime_file", var_cfg_var_path); #endif if (fp_.open_write(filepath) == false) { logger_error("open %s error %s", filepath.c_str(), acl::last_serror()); (void) doReply(req, res, "open file error"); return false; } // 设置原始文件存入路径 mime_->set_saved_path(filepath); req_ = &req; res_ = &res; read_body_ = true; // 直接返回,从而触发异步读 HTTP 数据体过程 return true; }
bool http_servlet::doPost(acl::HttpServletRequest& req, acl::HttpServletResponse& res) { bool keep_alive = req.isKeepAlive(); res.setContentType("text/html; charset=utf-8") // 设置响应字符集 .setKeepAlive(keep_alive) // 设置是否保持长连接 .setChunkedTransferEncoding(true); // chunked 传输模式 // 发送 http 响应体 if (res.write("first line\r\nsecond line\r\nthird line\r\n\r\n") == false) { logger_error("write error!"); return false; } for (int i = 0; i < 10; i++) { if (res.write("hello") == false) { logger_error("write error!"); return false; } if (res.write(" ") == false) { logger_error("write error!"); return false; } if (res.write("world") == false) { logger_error("write error!"); return false; } if (res.write("\r\n") == false) { logger_error("write error!"); return false; } } for (int j = 0; j < 10; j++) { for (int i = 0; i < 10; i++) { if (res.write("X") == false) { logger_error("write error!"); return false; } } if (res.write("\r\n") == false) { logger_error("write error!"); return false; } } // 最后一行不写 \r\n if (res.write("Bye") == false) { logger_error("write error!"); return false; } return res.write(NULL, 0) && keep_alive; }
bool http_servlet::doPost(acl::HttpServletRequest& req, acl::HttpServletResponse& res) { #if 0 const char* session_name = req.getSession().getAttribute("session_name"); if (*session_name == 0) { req.getSession().setAttribute("session_name", "name"); req.getSession().setMaxAge(100); } session_name = req.getSession().getAttribute("session_name"); const char* session_user = req.getSession().getAttribute("session_user"); if (*session_user == 0) req.getSession().setAttribute("session_user", "user"); session_user = req.getSession().getAttribute("session_user"); #else const char* session_name = "name", *session_user = "******"; #endif // 取得浏览器 cookie const char* cookie_name = req.getCookieValue("cookie_name"); bool keep_alive = req.isKeepAlive(); const char* param1 = req.getParameter("name1"); const char* param2 = req.getParameter("name2"); // 创建 xml 格式的数据体 acl::xml body; body.get_root() .add_child("root", true) .add_child("session", true) .add_child("session_name", true) .set_text(session_name) .get_parent() .add_child("session_user", true) .set_text(session_user) .get_parent() .get_parent() .add_child("cookie", true) .add_child("cookie_name", true) .set_text(cookie_name ? cookie_name : "") .get_parent() .get_parent() .add_child("params", true) .add_child("param", true) .add_attr("name1", param1 ? param1 : "null") .get_parent() .add_child("param", true) .add_attr("name2", param2 ? param2 : "null"); acl::string buf; body.build_xml(buf); #if 0 res.setContentType("text/xml; charset=utf-8") // 设置响应字符集 .setKeepAlive(keep_alive) // 设置是否保持长连接 //.setContentLength(buf.length()); #else res.setContentType("text/xml; charset=utf-8") // 设置响应字符集 .setKeepAlive(keep_alive) // 设置是否保持长连接 .setContentEncoding(true) // 设置是否压缩数据 .setChunkedTransferEncoding(true); // 采用 chunk 传输方式 #endif //logger("access http://%s%s", req.getRemoteAddr(), req.getRequestUri()); // 发送 http 响应体,因为设置了 chunk 传输模式,所以需要多调用一次 // res.write 且两个参数均为 0 以表示 chunk 传输数据结束 return res.write(buf) && res.write(NULL, 0); }
bool https_client::http_request(acl::HttpServletRequest& req, acl::HttpServletResponse& res) { const char* host = req.getRemoteHost(); if (host == NULL || *host == 0) host = req.getLocalAddr(); acl::string server_addr; if (ssl_conf_ == NULL) server_addr.format("%s:80", host); else server_addr.format("%s:443", host); std::auto_ptr<acl::http_client> backend(new acl::http_client); // 连接服务器 if (connect_server(server_addr, *backend) == false) return false; acl::http_client* front = req.getClient(); // 取得 HTTP 请求头数据 acl::string req_hdr; front->sprint_header(req_hdr, NULL); // 转发 HTTP 请求头至服务器 if (backend->get_ostream().write(req_hdr) == -1) { out_.puts(">>>>write header error"); return false; } if (backend->get_ostream().write("\r\n") == -1) { out_.puts(">>>>write CRLF error"); return false; } // 如果还有数据体,则转发请求的数据体给服务器 long long int len = req.getContentLength(); if (len > 0) { char req_body[8192]; int ret; while (true) { ret = front->read_body(req_body, sizeof(req_body) - 1); if (ret < 0) { out_.puts(">>> read req body error"); return false; } if (ret == 0) break; req_body[ret] = 0; out_.write(req_body, ret); if (backend->get_ostream().write(req_body, ret) == -1) { out_.puts(">>> write body to server error"); return false; } } } out_.puts(""); // 开始从后端服务器读取响应头和响应体数据 out_.puts(">>>> begin read res header<<<<<"); if (backend->read_head() == false) { out_.puts(">>>>>>>>read header error<<<<<<<<<<"); return false; } acl::string res_hdr; backend->sprint_header(res_hdr, NULL); if (res.getOutputStream().write(res_hdr) == -1) { out_.puts(">>>>>write res hdr error<<<<<<"); return false; } if (res.getOutputStream().write("\r\n") == -1) { out_.puts(">>>write CRLF error"); return false; } out_.puts("------------------res hdr----------------"); out_.write(res_hdr); out_.puts("------------------res hdr end------------"); char buf[8192]; while (true) { int ret = backend->read_body(buf, sizeof(buf) - 1); if (ret < 0) { logger_error(">>> read body error"); return false; } else if (ret == 0) break; buf[ret] = 0; out_.write(buf, ret); if (res.getOutputStream().write(buf, ret) == -1) { out_.puts(">>> write res body error"); return false; } } const char* ptr = backend->header_value("Transfer-Encoding"); if (ptr == NULL || *ptr == 0 || strcasecmp(ptr, "chunked") != 0) return backend->keep_alive(); // 发送 http 响应体,因为设置了 chunk 传输模式,所以需要多调用一次 // res.write 且两个参数均为 0 以表示 chunk 传输数据结束 return res.write(NULL, 0); }
bool http_servlet::doDoc(acl::HttpServletRequest& req, acl::HttpServletResponse& res, const char* path) { acl::string filepath(var_cfg_home_path); if (*(var_cfg_home_path + strlen(var_cfg_home_path) - 1) != '/' && *path != '/') { filepath << '/'; } filepath << path; if (*(path + strlen(path) - 1) == '/') filepath << "index.html"; acl::ifstream in; if (in.open_read(filepath) == false) { logger_error("open %s error %s", filepath.c_str(), acl::last_serror()); return doReply(req, res, 404, "%s", "Not found"); } //printf("---open %s ok---\r\n", filepath.c_str()); long long len = in.fsize(); if (len <= 0) { logger_error("invalid fisze: %lld, file: %s", len, filepath.c_str()); return doReply(req, res, 500, "%s", "Can't get file size"); } res.setContentLength(len); acl::string ctype; getContentType(filepath, ctype); res.setContentType(ctype); char buf[8192]; int ret; long long n = 0; while (!in.eof()) { if ((ret = in.read(buf, sizeof(buf), false)) == -1) { //logger_error("read from %s error %s", filepath.c_str(), // acl::last_serror()); break; } if (res.write(buf, ret) == false) { logger_error("write to client error, file %s", filepath.c_str()); return false; } n += ret; } if (n != len) { logger_error("write length(%lld) != file size(%lld), file: %s", n, len, filepath.c_str()); return false; } return res.write(NULL, 0); }