Пример #1
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);
}
Пример #2
0
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;
}