bool logger_servlet::doPost(acl::HttpServletRequest& req, acl::HttpServletResponse&) { const char* uri = req.getRequestUri(); if (uri == NULL || *uri == 0) { logger_debug(DEBUG_HTTP, 1, "getRequestUri null"); return false; } const char* host = req.getRemoteHost(); if (host == NULL || *host == 0) { logger_debug(DEBUG_HTTP, 1, "no Host"); return false; } acl::string url; url.format("http://%s/%s", host, uri); logger("%s", url.c_str()); int n; char buf[8192]; acl::http_client* conn = req.getClient(); while (true) { n = conn->read_body(buf, sizeof(buf)); if (n < 0) return false; else if (n == 0) break; } return true; }
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; }
void http_servlet::logger_request(acl::HttpServletRequest& req) { acl::string req_hdr; acl::http_client* client = req.getClient(); client->sprint_header(req_hdr, NULL); out_.format("\r\n>>>request header<<<\r\n"); out_.write(req_hdr); out_.format("\r\n"); }
bool http_servlet::doPost(acl::HttpServletRequest& req, acl::HttpServletResponse& res) { handled_ = true; acl::http_client* conn = req.getClient(); conn->header_disable("Accept-Encoding"); logger_request(req); // 生成完整的 url,以备下面使用 const char* host = req.getRemoteHost(); const char* uri = req.getRequestUri(); if (host == NULL || *host == 0) host = req.getLocalAddr(); url_.format("http://%s%s", host, uri ? uri : "/"); out_.format(">>> request url: %s\r\n", url_.c_str()); https_client client(out_, client_ssl_conf_); return client.http_request(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 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::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::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::doWebsocket(acl::HttpServletRequest& req, acl::HttpServletResponse&) { acl::socket_stream& ss = req.getSocketStream(); acl::websocket in(ss), out(ss); while (true) { if (in.read_frame_head() == false) { printf("read_frame_head error\r\n"); return false; } bool ret; unsigned char opcode = in.get_frame_opcode(); printf("opcode: 0x%x\r\n", opcode); switch (opcode) { case acl::FRAME_PING: ret = doPing(in, out); break; case acl::FRAME_PONG: ret = doPong(in, out); break; case acl::FRAME_CLOSE: ret = doClose(in, out); break; case acl::FRAME_TEXT: case acl::FRAME_BINARY: ret = doMsg(in, out); break; case acl::FRAME_CONTINUATION: ret = false; break; default: ret = false; break; } if (ret == false) return false; } // XXX: NOT REACHED return false; }
bool http_servlet::doUpload(acl::HttpServletRequest& req, acl::HttpServletResponse& res) { // 获得输入流 acl::istream& in = req.getInputStream(); acl::string buf; bool finish = false; //logger(">>>>>>>>>>read: %lld, total: %lld<<<<<", // read_length_, content_length_); // 读取 HTTP 客户端请求数据 while (content_length_ > read_length_) { if (in.read_peek(buf, true) == false) break; //if (buf.empty()) // break; // printf(">>>size: %ld, space: %ld\r\n", // (long) buf.size(), (long) buf.capacity()); if (fp_.write(buf) == -1) { logger_error("write error %s", acl::last_serror()); (void) doReply(req, res, "write error"); return false; } read_length_ += buf.size(); // 将读得到的数据输入至解析器进行解析 if (!finish && mime_->update(buf, buf.size()) == true) finish = true; } if (in.eof()) { logger_error("read error"); return false; } return true; }
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 http_servlet::doParse(acl::HttpServletRequest& req, acl::HttpServletResponse& res) { const char* ptr = req.getParameter("name1"); if (ptr) param1_ = ptr; ptr = req.getParameter("name2"); if (ptr) param2_ = ptr; ptr = req.getParameter("name3"); if (ptr) param3_ = ptr; acl::string path; // 遍历所有的 MIME 结点,找出其中为文件结点的部分进行转储 const std::list<acl::http_mime_node*>& nodes = mime_->get_nodes(); std::list<acl::http_mime_node*>::const_iterator cit = nodes.begin(); for (; cit != nodes.end(); ++cit) { const char* name = (*cit)->get_name(); if (name == NULL) continue; acl::http_mime_t mime_type = (*cit)->get_mime_type(); if (mime_type == acl::HTTP_MIME_FILE) { const char* filename = (*cit)->get_filename(); if (filename == NULL) { logger("filename null"); continue; } // 有的浏览器(如IE)上传文件时会带着文件路径,所以 // 需要先将路径去掉 filename = acl_safe_basename(filename); #if defined(_WIN32) || defined(_WIN64) path.format("%s\\%s", var_cfg_var_path, filename); #else path.format("%s/%s", var_cfg_var_path, filename); #endif (void) (*cit)->save(path.c_str()); if (strcmp(name, "file1") == 0) { file1_ = filename; fsize1_ = get_fsize(var_cfg_var_path, filename); } else if (strcmp(name, "file2") == 0) { file2_ = filename; fsize2_ = get_fsize(var_cfg_var_path, filename); } else if (strcmp(name, "file3") == 0) { file3_ = filename; fsize3_ = get_fsize(var_cfg_var_path, filename); } } } // 查找上载的某个文件并转储 const acl::http_mime_node* node = mime_->get_node("file1"); if (node && node->get_mime_type() == acl::HTTP_MIME_FILE) { ptr = node->get_filename(); if (ptr) { // 有的浏览器(如IE)上传文件时会带着文件路径,所以 // 需要先将路径去掉 ptr = acl_safe_basename(ptr); #if defined(_WIN32) || defined(_WIN64) path.format("%s\\1_%s", var_cfg_var_path, ptr); #else path.format("%s/1_%s", var_cfg_var_path, ptr); #endif (void) node->save(path.c_str()); } } return doReply(req, res, "OK"); }
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::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) { 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; }