bool http_servlet::doApp(acl::HttpServletRequest& req, acl::HttpServletResponse& res) { acl::http_request* conn = (acl::http_request *) conns_->peek(); if (conn == NULL) { logger_error("no connection available, addr: %s", var_cfg_manager_addr); return doReply(req, res, 500, "%s", "no connection"); } acl::http_header& hdr = conn->request_header(); hdr.set_url(var_cfg_access_url) .set_keep_alive(true) .set_method(acl::HTTP_METHOD_GET) .accept_gzip(true); if (conn->request(NULL, 0) == false) { logger_error("send request to %s error", var_cfg_manager_addr); conns_->put(conn, false); return doReply(req, res, 505, "%s", "send request error"); } acl::xml1 xml; char buf[8192]; while (true) { int ret = conn->read_body(buf, sizeof(buf) - 1); if (ret == 0) break; else if (ret < 0) { conns_->put(conn, false); logger_error("read_body error from %s", var_cfg_manager_addr); return doReply(req, res, 505, "%s", "read_body error"); } buf[ret] = 0; xml.update(buf); } conns_->put(conn, true); acl::json json; if (xmlToJson(xml, json) == false) return doReply(req, res, 505, "%s", "invalid xml data"); return doReply(req, res, 200, json); }
/** * Network manager creates DHCPNAK */ int NetworkManager::nak(const Client& client, uint32_t u32Xid) { Lease l = client.lease(); if (l == Lease::NullLease) return VERR_INTERNAL_ERROR; prepareReplyPacket4Client(client, u32Xid); /* this field filed in prepareReplyPacket4Session, and * RFC 2131 require to have it zero fo NAK. */ m->BootPReplyMsg.BootPHeader.bp_yiaddr.u = 0; /* options: * - message type (if DHCPREQUEST) * - server identifier */ RawOption opt; std::vector<RawOption> extra; opt.u8OptId = RTNET_DHCP_OPT_MSG_TYPE; opt.au8RawOpt[0] = RTNET_DHCP_MT_NAC; opt.cbRawOpt = 1; extra.push_back(opt); return doReply(client, extra); }
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); }
/** * Network manager creates DHCPACK */ int NetworkManager::ack(const Client& client, uint32_t u32Xid, uint8_t *pu8ReqList, int cReqList) { RTNETADDRIPV4 address; prepareReplyPacket4Client(client, u32Xid); Lease l = client.lease(); address = l.getAddress(); m->BootPReplyMsg.BootPHeader.bp_ciaddr = address; /* rfc2131 4.3.1 is about DHCPDISCOVER and this value is equal to ciaddr from * DHCPREQUEST or 0 ... * XXX: Using addressHint is not correct way to initialize [cy]iaddress... */ m->BootPReplyMsg.BootPHeader.bp_ciaddr = address; m->BootPReplyMsg.BootPHeader.bp_yiaddr = address; Assert(m->BootPReplyMsg.BootPHeader.bp_yiaddr.u); /* options: * - IP address lease time (if DHCPREQUEST) * - message type * - server identifier */ RawOption opt; RT_ZERO(opt); std::vector<RawOption> extra; opt.u8OptId = RTNET_DHCP_OPT_MSG_TYPE; opt.au8RawOpt[0] = RTNET_DHCP_MT_ACK; opt.cbRawOpt = 1; extra.push_back(opt); /* * XXX: lease time should be conditional. If on dhcprequest then tim should be provided, * else on dhcpinform it mustn't. */ opt.u8OptId = RTNET_DHCP_OPT_LEASE_TIME; *(uint32_t *)opt.au8RawOpt = RT_H2N_U32(l.getExpiration()); opt.cbRawOpt = sizeof(RTNETADDRIPV4); extra.push_back(opt); processParameterReqList(client, pu8ReqList, cReqList, extra); return doReply(client, extra); }
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; }
/** * Network manager creates DHCPOFFER datagramm */ int NetworkManager::offer4Client(const Client& client, uint32_t u32Xid, uint8_t *pu8ReqList, int cReqList) { Lease l(client); /* XXX: oh, it looks badly, but now we have lease */ prepareReplyPacket4Client(client, u32Xid); RTNETADDRIPV4 address = l.getAddress(); m->BootPReplyMsg.BootPHeader.bp_yiaddr = address; /* Ubuntu ???*/ m->BootPReplyMsg.BootPHeader.bp_ciaddr = address; /* options: * - IP lease time * - message type * - server identifier */ RawOption opt; RT_ZERO(opt); std::vector<RawOption> extra; opt.u8OptId = RTNET_DHCP_OPT_MSG_TYPE; opt.au8RawOpt[0] = RTNET_DHCP_MT_OFFER; opt.cbRawOpt = 1; extra.push_back(opt); opt.u8OptId = RTNET_DHCP_OPT_LEASE_TIME; const NetworkConfigEntity *pCfg = l.getConfig(); AssertPtr(pCfg); *(uint32_t *)opt.au8RawOpt = RT_H2N_U32(pCfg->expirationPeriod()); opt.cbRawOpt = sizeof(RTNETADDRIPV4); extra.push_back(opt); processParameterReqList(client, pu8ReqList, cReqList, extra); return doReply(client, extra); }
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); }
void HttpRequestAndResponsePacketTF::testDecodeAndEncode() { HttpRequestPacket *request = new HttpRequestPacket; HttpResponsePacket *response; DataBuffer output; DataBuffer input; PacketHeader header; // http_load -r 1 -f 2 url char s1[] = "GET / HTTP/1.0\r\n" "Host: localhost\r\n" "User-Agent: http_load 12mar2006\r\n\r\n"; header._dataLen = sizeof(s1)-1; input.writeBytes(s1, sizeof(s1) - 1); CPPUNIT_ASSERT(request->decode(&input, &header)); CPPUNIT_ASSERT_EQUAL(1, request->_method); CPPUNIT_ASSERT_EQUAL(1, request->_version); CPPUNIT_ASSERT_EQUAL(false, request->isKeepAlive()); CPPUNIT_ASSERT(strcmp("localhost", request->findHeader("Host")) == 0); CPPUNIT_ASSERT(request->findHeader("User-Agent")); CPPUNIT_ASSERT(strcmp("http_load 12mar2006", request->findHeader("User-Agent")) == 0); response = doReply(request); response->encode(&output); char r1[] = "HTTP/1.1 200 OK\r\n" "Connection: close\r\n" "Content-Type: text/html\r\n" "Content-Length: 1\r\n\r\n/"; CPPUNIT_ASSERT(strncmp(r1, output.getData(), sizeof(r1) - 1) == 0); output.clear(); delete response; request->free(); request = new HttpRequestPacket; //fbench -q url -c 0 -n 15 -k -s 10 localhost 12345 request->_isKeepAlive = true; char s2[] = "GET http://localhost:12345?name=huang&jj=yy HTTP/1.1\r\n" "Host: localhost\r\n" "User-Agent: fbench/0.9\r\n\r\n"; header._dataLen = sizeof(s2)-1; input.writeBytes(s2, sizeof(s2) - 1); CPPUNIT_ASSERT(request->decode(&input, &header)); CPPUNIT_ASSERT_EQUAL(1, request->_method); CPPUNIT_ASSERT_EQUAL(2, request->_version); CPPUNIT_ASSERT_EQUAL(true, request->isKeepAlive()); CPPUNIT_ASSERT(strcmp("localhost", request->findHeader("Host")) == 0); CPPUNIT_ASSERT(strcmp("fbench/0.9", request->findHeader("User-Agent")) == 0); CPPUNIT_ASSERT(strcmp(request->getQuery(), "http://localhost:12345?name=huang&jj=yy") == 0); response = doReply(request); response->encode(&output); char r2[] = "HTTP/1.1 200 OK\r\n" "Connection: Keep-Alive\r\n" "Keep-Alive: timeout=10, max=10\r\n" "Content-Type: text/html\r\n" "Content-Length: 39\r\n\r\n" "http://localhost:12345?name=huang&jj=yy"; CPPUNIT_ASSERT(strncmp(r2, output.getData(), sizeof(r2) - 1) == 0); output.clear(); delete response; request->free(); request = new HttpRequestPacket; //fbench -q url -c 0 -n 15 -s 10 localhost 12345 char s3[] = "GET http://localhost:12345?name=huang&jj=yy HTTP/1.1\r\n" "Host: localhost\r\n" "Connection: close\r\n" "User-Agent: fbench/0.9\r\n\r\n"; header._dataLen = sizeof(s3)-1; input.writeBytes(s3, sizeof(s3) - 1); CPPUNIT_ASSERT(request->decode(&input, &header)); CPPUNIT_ASSERT_EQUAL(1, request->_method); CPPUNIT_ASSERT_EQUAL(2, request->_version); CPPUNIT_ASSERT_EQUAL(false, request->isKeepAlive()); CPPUNIT_ASSERT(strcmp("localhost", request->findHeader("Host")) == 0); CPPUNIT_ASSERT(strcmp("fbench/0.9", request->findHeader("User-Agent")) == 0); CPPUNIT_ASSERT(strcmp(request->getQuery(), "http://localhost:12345?name=huang&jj=yy") == 0); response = doReply(request); response->encode(&output); char r3[] = "HTTP/1.1 200 OK\r\n" "Connection: close\r\n" "Content-Type: text/html\r\n" "Content-Length: 39\r\n\r\n" "http://localhost:12345?name=huang&jj=yytp://localhost:12345?name=huang&jj=yy"; CPPUNIT_ASSERT(strncmp(r3, output.getData(), sizeof(r3) - 1) == 0); output.clear(); delete response; request->free(); request = new HttpRequestPacket; //firefox request->_isKeepAlive = true; char s4[] ="GET /?name=huang&jj=yy HTTP/1.0\r\n" "Host: localhost:12345\r\n" "User-Agent: Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9b5) Gecko/2008042803 Red Hat/3.0b5-0.beta5.6.el5 Firefox/3.0b5\r\n" "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n" "Accept-Language: en-us,en;q=0.5\r\n" "Accept-Encoding: gzip,deflate\r\n" "Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7\r\n" "Keep-Alive: 300\r\n" "Connection: keep-alive\r\n\r\n"; header._dataLen = sizeof(s4)-1; input.writeBytes(s4, sizeof(s4) - 1); CPPUNIT_ASSERT(request->decode(&input, &header)); CPPUNIT_ASSERT_EQUAL(1, request->_method); CPPUNIT_ASSERT_EQUAL(1, request->_version); CPPUNIT_ASSERT_EQUAL(true, request->isKeepAlive()); CPPUNIT_ASSERT(strcmp("localhost:12345", request->findHeader("Host")) == 0); CPPUNIT_ASSERT(strcmp("Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9b5) Gecko/2008042803 Red Hat/3.0b5-0.beta5.6.el5 Firefox/3.0b5", request->findHeader("User-Agent")) == 0); CPPUNIT_ASSERT(strcmp(request->getQuery(), "/?name=huang&jj=yy") == 0); response = doReply(request); response->encode(&output); char r4[] = "HTTP/1.1 200 OK\r\n" "Connection: Keep-Alive\r\n" "Keep-Alive: timeout=10, max=10\r\n" "Content-Type: text/html\r\n" "Content-Length: 18\r\n\r\n" "/?name=huang&jj=yy2345?name=huang&jj=yy"; CPPUNIT_ASSERT(strncmp(r4, output.getData(), sizeof(r4) - 1) == 0); output.clear(); delete response; request->free(); request = new HttpRequestPacket; // http_load -r 1 -f 2 url keep-alive:true request->_isKeepAlive = true; char s5[] = "GET / HTTP/1.0\r\n" "Host: localhost\r\n" "Connection: keep-alive\r\n" "User-Agent: http_load 12mar2006\r\n\r\n"; header._dataLen = sizeof(s5)-1; input.writeBytes(s5, sizeof(s5) - 1); CPPUNIT_ASSERT(request->decode(&input, &header)); CPPUNIT_ASSERT_EQUAL(1, request->_method); CPPUNIT_ASSERT_EQUAL(1, request->_version); CPPUNIT_ASSERT_EQUAL(true, request->isKeepAlive()); CPPUNIT_ASSERT(strcmp("localhost", request->findHeader("Host")) == 0); CPPUNIT_ASSERT(request->findHeader("User-Agent")); CPPUNIT_ASSERT(strcmp("http_load 12mar2006", request->findHeader("User-Agent")) == 0); response = doReply(request); response->encode(&output); cout<<output.getData(); char r5[] = "HTTP/1.1 200 OK\r\n" "Connection: Keep-Alive\r\n" "Keep-Alive: timeout=10, max=10\r\n" "Content-Type: text/html\r\n" "Content-Length: 1\r\n\r\n" "//?name=huang&jj=yy2345?name=huang&jj=yy"; CPPUNIT_ASSERT(strncmp(r5, output.getData(), sizeof(r5) - 1) == 0); output.clear(); delete response; request->free(); request = new HttpRequestPacket; //wrong query request->_isKeepAlive = true; char s6[] = "GET HTTP/1.0\r\n" "Host: localhost\r\n" "Connection: keep-alive\r\n"; header._dataLen = sizeof(s6)-1; input.writeBytes(s6, sizeof(s6) - 1); CPPUNIT_ASSERT(!request->decode(&input, &header)); request->free(); }
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::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"); }
void Socket::onInput(StreamBuffer& sb) { log_debug("onInput"); sb.endRead(); if (sb.in_avail() == 0 || sb.device()->eof()) { close(); return; } _timer.start(_server.readTimeout()); if ( _responder == 0 ) { _parser.advance(sb); if (_parser.fail()) { _responder = _server.getDefaultResponder(_request); _responder->replyError(_reply.body(), _request, _reply, std::runtime_error("invalid http header")); _responder->release(); _responder = 0; sendReply(); onOutput(sb); return; } if (_parser.end()) { log_info("request " << _request.method() << ' ' << _request.header().query() << " from client " << getPeerAddr()); _responder = _server.getResponder(_request); try { _responder->beginRequest(_stream, _request); } catch (const std::exception& e) { _reply.setHeader("Connection", "close"); _responder->replyError(_reply.body(), _request, _reply, e); _responder->release(); _responder = 0; sendReply(); onOutput(sb); return; } _contentLength = _request.header().contentLength(); log_debug("content length of request is " << _contentLength); if (_contentLength == 0) { _timer.stop(); doReply(); return; } } else { sb.beginRead(); } } if (_responder) { if (sb.in_avail() > 0) { try { std::size_t s = _responder->readBody(_stream); assert(s > 0); _contentLength -= s; } catch (const std::exception& e) { _reply.setHeader("Connection", "close"); _responder->replyError(_reply.body(), _request, _reply, e); _responder->release(); _responder = 0; sendReply(); onOutput(sb); return; } } if (_contentLength <= 0) { _timer.stop(); doReply(); } else { sb.beginRead(); } } }