-
Notifications
You must be signed in to change notification settings - Fork 939
/
Copy pathhttp.cpp
192 lines (150 loc) · 4.35 KB
/
http.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
// http_aio.cpp : 定义控制台应用程序的入口点。
//
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <getopt.h>
#include "lib_acl.h"
#include "lib_protocol.h"
#include "http.h"
typedef struct {
ACL_ASTREAM *stream;
HTTP_HDR_REQ *hdr_req;
HTTP_HDR_RES *hdr_res;
HTTP_RES *http_res;
} CTX;
static char __server_addr[128];
static int __stop = 0;
static int on_close(ACL_ASTREAM *stream acl_unused, void *context)
{
CTX *ctx = (CTX *) context;
http_hdr_req_free(ctx->hdr_req);
// 当读到完整 HTTP 响应头时,HTTP 响应体对象应该也创建,当释放响应体
// 对象时,响应头对象会一起被释放;如果在读响应头时出错,则响应体对象
// 并未创建,所以只需释放响应头对象
if (ctx->http_res) {
http_res_free(ctx->http_res);
} else if (ctx->hdr_res) {
http_hdr_res_free(ctx->hdr_res);
}
acl_myfree(ctx);
printf("%s(%d)\n", __FUNCTION__, __LINE__);
__stop = 1;
return 0;
}
static int on_timeout(ACL_ASTREAM *stream acl_unused, void *context acl_unused)
{
printf("%s(%d)\n", __FUNCTION__, __LINE__);
return 0;
}
static int read_respond_body_ready(int status, char *data, int dlen,
void *arg acl_unused)
{
ACL_VSTRING *buf = acl_vstring_alloc(256);
acl_vstring_memcpy(buf, data, dlen);
ACL_VSTRING_TERMINATE(buf);
printf("status=%d >>%s", status, acl_vstring_str(buf));
acl_vstring_free(buf);
return 0;
}
static int on_http_hdr(int status, void *arg)
{
CTX *ctx = (CTX*) arg;
printf("%s: status=%d\r\n", __FUNCTION__, status);
http_hdr_print(&ctx->hdr_res->hdr, "---respond---");
// 构建 HTTP 响应体
ctx->http_res = http_res_new(ctx->hdr_res);
// 异步读取 HTTP 服务端的响应体
http_res_body_get_async(ctx->http_res, ctx->stream,
read_respond_body_ready, ctx, 0);
return 0;
}
static int on_connect(const ACL_ASTREAM_CTX *context)
{
ACL_ASTREAM *stream = acl_astream_get_conn(context);
if (stream == NULL) {
__stop = 1;
return -1;
}
// printf(">>>> connect %s ok!\r\n", addr);
CTX *ctx = (CTX*) acl_mycalloc(1, sizeof(CTX));
ctx->stream = stream;
// 构建 HTTP 请求头
ctx->hdr_req = http_hdr_req_create("/", "GET", "HTTP/1.1");
// 设置短连接模式
http_hdr_entry_replace(&ctx->hdr_req->hdr, "Connection", "Close", 1);
// 设置内容类型
http_hdr_put_str(&ctx->hdr_req->hdr, "Content-Type", "text/plain");
// 设置主机字段
http_hdr_put_str(&ctx->hdr_req->hdr, "Host", __server_addr);
// 设置读超时回调函数
acl_aio_add_timeo_hook(stream, on_timeout, ctx);
// 设置关闭回调函数
acl_aio_add_close_hook(stream, on_close, ctx);
// 创建动态内存并将 HTTP 请求头拷贝至其中
ACL_VSTRING *buf = acl_vstring_alloc(1024);
http_hdr_build_request(ctx->hdr_req, buf);
// 发送 HTTP 请求
acl_aio_writen(stream, acl_vstring_str(buf), ACL_VSTRING_LEN(buf));
// 释放动态内存
acl_vstring_free(buf);
// 创建 HTTP 响应对象
ctx->hdr_res = http_hdr_res_new();
// 异步读取服务端响应的 HTTP 头
http_hdr_res_get_async(ctx->hdr_res, stream, on_http_hdr, ctx, 0);
return 0;
}
static void usage(const char* procname)
{
printf("usage: %s -h[help]\r\n"
" -s server_addr\r\n"
" -N name_server\r\n"
" -t connect_timeout\r\n"
" -T dns_timeout\r\n",
procname);
}
int http_async(int argc, char* argv[])
{
ACL_AIO *aio = acl_aio_create(ACL_EVENT_SELECT);
char name_server[128];
int ch, connect_timeout = 5, dns_timeout = 1;
acl_aio_set_keep_read(aio, 1);
snprintf(__server_addr, sizeof(__server_addr), "www.baidu.com:80");
snprintf(name_server, sizeof(name_server), "8.8.8.8:53");
while ((ch = getopt(argc, argv, "hs:N:t:T:")) > 0) {
switch (ch) {
case 'h':
usage(argv[0]);
return 0;
case 's':
snprintf(__server_addr, sizeof(__server_addr), "%s", optarg);
break;
case 'N':
snprintf(name_server, sizeof(name_server), "%s", optarg);
break;
case 't':
connect_timeout = atoi(optarg);
break;
case 'T':
dns_timeout = atoi(optarg);
break;
default:
usage(argv[0]);
return 1;
}
}
// 设置域名解析服务器地址
acl_aio_set_dns(aio, name_server, dns_timeout);
// 异步连接指定 WEB 服务器
if (acl_aio_connect_addr(aio, __server_addr, connect_timeout,
on_connect, __server_addr) == -1) {
printf("connect %s error\r\n", __server_addr);
return 1;
}
// 异步事件循环
while (!__stop) {
acl_aio_loop(aio);
}
acl_aio_free(aio);
return 0;
}