Exemplo n.º 1
0
	int read_respond_body(char* buf, int dlen)
	{
		acl_assert(vstream_);
		acl_assert(res_);

		char* ptr = buf;
		int   dlen_saved = dlen;
		int   ret;

		// 因为 buf 是动态分配的,所以应尽量让 buf 填满,
		// 这样可以节省内存分配的消耗

		while (true)
		{
			ret = (int) http_res_body_get_sync(res_, vstream_,
					ptr, dlen);
			if (ret <= 0)
			{
				respond_over_ = true;
				break;
			}
			dlen -= ret;
			if (dlen <= 0)
				break;
			ptr += ret;
		}

		return (dlen_saved - dlen);
	}
Exemplo n.º 2
0
int http_client::read_response_body(char* buf, size_t size)
{
	if (hdr_res_ == NULL)
	{
		logger_error("response header not get yet");
		disconnected_ = true;
		return -1;
	}

	if (stream_ == NULL)
	{
		logger_error("not connected yet");
		disconnected_ = true;
		return -1;
	}
	ACL_VSTREAM* vstream = stream_->get_vstream();
	if (vstream == NULL)
	{
		logger_error("connect stream null");
		disconnected_ = true;
		return -1;
	}

	if (res_ == NULL)
		res_ = http_res_new(hdr_res_);

	// 缓冲区太大了没有任何意义
	if (size >= 1024000)
		size = 1024000;
	http_off_t ret = http_res_body_get_sync(res_, vstream, buf, size);

	if (ret <= 0)
	{
		// 如果在读响应头时调用了 unzip_begin,则必须保证读完数据
		// 后再调用 unzip_finish,否则会因为 zlib 本身的设计而导致
		// 内存泄露
		if (zstream_ != NULL)
		{
			string dummy(64);
			zstream_->unzip_finish(&dummy);
		}
		body_finish_ = true;
		if (ret < 0)
			disconnected_ = true;
	}

	return (int) ret;
}
Exemplo n.º 3
0
int http_util_get_res_body(HTTP_UTIL *http_util, char *buf, size_t size)
{
	const char *myname = "http_util_get_res_body";
	int   ret;

	if (buf == NULL || size == 0) {
		acl_msg_error("%s(%d): buf(%s), size(%d) invalid",
			myname, __LINE__, buf ? "not null" : "null", (int) size);
		return (-1);
	}

	if ((http_util->flag & (HTTP_UTIL_FLAG_HAS_RES_BODY
		| HTTP_UTIL_FLAG_NO_RES_BODY)) == 0)
	{
		if (!http_util_has_res_body(http_util))
			return (http_util->res_body_dlen);
	}

	ret = (int) http_res_body_get_sync(http_util->http_res,
			http_util->stream, buf, (int) size);
	if (ret <= 0)
		return (ret);
	http_util->res_body_dlen += ret;
	if (http_util->dump_stream == NULL)
		return (ret);

	if (acl_vstream_writen(http_util->dump_stream, buf, ret) == ACL_VSTREAM_EOF)
	{
		/* 如果有一次不能转储数据至文件或流则关闭该功能不再进行转储 */

		acl_msg_error("%s(%d): dump to stream(%s) error(%s)",
			myname, __LINE__, ACL_VSTREAM_PATH(http_util->dump_stream),
			acl_last_serror());
		if ((http_util->flag & HTTP_UTIL_FLAG_SET_DUMP_FILE)) {
			if (http_util->dump_stream)
				acl_vstream_close(http_util->dump_stream);
			http_util->flag &= ~HTTP_UTIL_FLAG_SET_DUMP_FILE;
		} else
			http_util->flag &= ~HTTP_UTIL_FLAG_SET_DUMP_STREAM;

		http_util->dump_stream = NULL;
	}

	return (ret);
}
Exemplo n.º 4
0
int http_client::read_response_body(string& out, bool clean,
	int* real_size)
{
	if (real_size)
		*real_size = 0;
	if (body_finish_)
		return (last_ret_);

	if (stream_ == NULL)
	{
		logger_error("connect null");
		disconnected_ = true;
		return -1;
	}
	ACL_VSTREAM* vstream = stream_->get_vstream();
	if (vstream == NULL)
	{
		logger_error("connect stream null");
		disconnected_ = true;
		return -1;
	}

	if (hdr_res_ == NULL)
	{
		logger_error("response header not get yet");
		disconnected_ = true;
		return -1;
	}
	if (res_ == NULL)
		res_ = http_res_new(hdr_res_);

	if (clean)
		out.clear();

	int   saved_count = (int) out.length();
	char  buf[8192];

SKIP_GZIP_HEAD_AGAIN:  // 对于有 GZIP 头数据,可能需要重复读

	int ret = (int) http_res_body_get_sync(res_, vstream, buf, sizeof(buf));

	if (zstream_ == NULL)
	{
		if (ret > 0)
		{
			out.append(buf, ret);
			if (real_size)
				*real_size = ret;
		}
		else
		{
			body_finish_ = true; // 表示数据已经读完
			if (ret < 0)
				disconnected_ = true;
			last_ret_ = ret;
		}
		return ret;
	}

	if (ret <= 0)
	{
		if (zstream_->unzip_finish(&out) == false)
		{
			logger_error("unzip_finish error");
			return -1;
		}

		last_ret_ = ret; // 记录返回值
		body_finish_ = true; // 表示数据已经读完且解压缩完毕
		if (ret < 0)
			disconnected_ = true;
		return (int) out.length() - saved_count;
	}

	if (real_size)
		(*real_size) += ret;

	// 需要先跳过 gzip 头

	if (gzip_header_left_ >= ret)
	{
		gzip_header_left_ -= ret;
		goto SKIP_GZIP_HEAD_AGAIN;
	}

	int  n;
	if (gzip_header_left_ > 0)
	{
		n = gzip_header_left_;
		gzip_header_left_ = 0;
	}
	else
		n = 0;
	if (zstream_->unzip_update(buf + n, ret - n, &out) == false)
	{
		logger_error("unzip_update error");
		return -1;
	}
	return (int) out.length() - saved_count;
}
Exemplo n.º 5
0
static void get_url(const char *method, const char *url,
	const char *proxy, const char *dump)
{
	/* 创建 HTTP 请求头 */
	HTTP_HDR_REQ *hdr_req = http_hdr_req_create(url, method, "HTTP/1.1");
	ACL_VSTREAM *stream;
	ACL_VSTRING *buf = acl_vstring_alloc(256);
	HTTP_HDR_RES *hdr_res;
	HTTP_RES *res;
	ACL_FILE *fp = NULL;
	const char *ptr;
	int   ret;

	/* 输出 HTTP 请求头内容 */

	http_hdr_print(&hdr_req->hdr, "---request hdr---");

	/* 如果设定代理服务器,则连接代理服务器地址,
	 * 否则使用 HTTP 请求头里指定的地址
	 */

	if (*proxy)
		acl_vstring_strcpy(buf, proxy);
	else
		acl_vstring_strcpy(buf, http_hdr_req_host(hdr_req));

	/* 获得远程 HTTP 服务器的连接地址 */

	ptr = acl_vstring_memchr(buf, ':');
	if (ptr == NULL)
		acl_vstring_strcat(buf, ":80");
	else {
		int   port;
		ptr++;
		port = atoi(ptr);
		if (port <= 0 || port >= 65535) {
			printf("http server's addr(%s) invalid\n", acl_vstring_str(buf));
			acl_vstring_free(buf);
			http_hdr_req_free(hdr_req);
			return;
		}
	}

	/* 连接远程 http 服务器 */

	stream = acl_vstream_connect(acl_vstring_str(buf) /* 服务器地址 */,
			ACL_BLOCKING /* 采用阻塞方式 */,
			10 /* 连接超时时间为 10 秒 */,
			10 /* 网络 IO 操作超时时间为 10 秒 */,
			4096 /* stream 流缓冲区大小为 4096 字节 */);
	if (stream == NULL) {
		printf("connect addr(%s) error(%s)\n",
			acl_vstring_str(buf), acl_last_serror());
		acl_vstring_free(buf);
		http_hdr_req_free(hdr_req);
		return;
	}

	/* 构建 HTTP 请求头数据 */

	http_hdr_build_request(hdr_req, buf);

	/* 向 HTTP 服务器发送请求 */

	ret = acl_vstream_writen(stream, acl_vstring_str(buf), ACL_VSTRING_LEN(buf));
	if (ret == ACL_VSTREAM_EOF) {
		printf("write to server error(%s)\n", acl_last_serror());
		acl_vstream_close(stream);
		acl_vstring_free(buf);
		http_hdr_req_free(hdr_req);
		return;
	}

	/* 创建一个 HTTP 响应头对象 */

	hdr_res = http_hdr_res_new();

	/* 读取 HTTP 服务器响应头*/

	ret = http_hdr_res_get_sync(hdr_res, stream, 10 /* IO 超时时间为 10 秒 */);
	if (ret < 0) {
		printf("get http reply header error(%s)\n", acl_last_serror());
		http_hdr_res_free(hdr_res);
		acl_vstream_close(stream);
		acl_vstring_free(buf);
		http_hdr_req_free(hdr_req);
		return;
	}

	if (http_hdr_res_parse(hdr_res) < 0) {
		printf("parse http reply header error\n");
		http_hdr_print(&hdr_res->hdr, "--- reply http header ---");
		http_hdr_res_free(hdr_res);
		acl_vstream_close(stream);
		acl_vstring_free(buf);
		http_hdr_req_free(hdr_req);
		return;
	}

	/* 如果需要转储至磁盘则需要先打开文件 */

	if (dump != NULL) {
		fp = acl_fopen(dump, "w+");
		if (fp == NULL)
			printf("open file(%s) error(%s)\n",
				dump, acl_last_serror());
	}

	/* 如果 HTTP 响应没有数据体则仅输出 HTTP 响应头即可 */

	if (hdr_res->hdr.content_length == 0
		|| (hdr_res->hdr.content_length == -1
			&& !hdr_res->hdr.chunked
			&& hdr_res->reply_status > 300
			&& hdr_res->reply_status < 400))
	{
		if (fp)
			http_hdr_fprint(ACL_FSTREAM(fp), &hdr_res->hdr,
				"--- reply http header ---");
		else
			http_hdr_fprint(ACL_VSTREAM_OUT, &hdr_res->hdr,
				"--- reply http header ---");
		http_hdr_res_free(hdr_res);
		acl_vstream_close(stream);
		acl_vstring_free(buf);
		http_hdr_req_free(hdr_req);
		return;
	}

	/* 输出 HTTP 响应头 */

	http_hdr_print(&hdr_res->hdr, "--- reply http header ---");

	/* 创建 HTTP 响应体对象 */

	res = http_res_new(hdr_res);

	/* 如果有数据体则开始读取 HTTP 响应数据体部分 */
	while (1) {
		http_off_t  n;
		char  buf2[4096];
		
		n = http_res_body_get_sync(res, stream, buf2, sizeof(buf2) - 1);
		if (n <= 0)
			break;

		if (fp) {
			if (acl_fwrite(buf2, (size_t) n, 1, fp) == (size_t) EOF) {
				printf("write to dump file(%s) error(%s)\n",
					dump, acl_last_serror());
				break;
			}
		} else {
			buf2[n] = 0;
			printf("%s", buf2);
		}
	}

	if (fp)
		acl_fclose(fp);
	http_res_free(res);  /* 释放 HTTP 响应对象, hdr_res 会在此函数内部自动被释放 */
	acl_vstream_close(stream);  /* 关闭网络流 */
	acl_vstring_free(buf);  /* 释放内存区 */
	http_hdr_req_free(hdr_req);  /* 释放 HTTP 请求头对象 */
}