acl
3.5.3.0
http_client.hpp
浏览该文件的文档.
1
#pragma once
2
#include "../acl_cpp_define.hpp"
3
#include "../stdlib/noncopyable.hpp"
4
5
struct
HTTP_HDR
;
6
struct
HTTP_HDR_RES
;
7
struct
HTTP_RES
;
8
struct
HTTP_HDR_REQ
;
9
struct
HTTP_REQ
;
10
11
namespace
acl
{
12
13
class
string;
14
class
zlib_stream;
15
class
socket_stream;
16
class
ostream;
17
class
istream;
18
class
http_header;
19
20
/**
21
* 该类的用处:1、当 HTTP 客户端向服务器请求数据时;2、当 HTTP 服务端接收
22
* 到 HTTP 客户端连接时创建一个对应的 HTTP 客户端流对象
23
* 该客户端流对象可以支持长连接
24
*/
25
class
ACL_CPP_API
http_client
:
public
noncopyable
26
{
27
public
:
28
/**
29
* 缺省的构造函数,使用此构造函数创建的 HTTP 客户端对象,需要显示地
30
* 调用 http_client::open 来打开数据流
31
*/
32
http_client
(
void
);
33
34
/**
35
* 根据已经连接成功的连接流对象创建 HTTP 客户端对象,但需要注意的是,
36
* 当该 http_client 对象销毁时,传入的 client 流对象并不会被销毁,需
37
* 要应用自己销毁,否则会造成资源泄露
38
* @param client {socket_stream*} HTTP 连接流对象,可以是请求端的流,
39
* 也可以是响应端的流;当本对象被销毁时,client 对象是否会被自动销毁,
40
* 取决于参数 stream_fixed 的值
41
* @param is_request {bool} 是请求端还是响应端的客户端流
42
* @param unzip {bool} 当用来读取服务器的响应数据时,如果服务器返回的
43
* 数据体为压缩数据时,该参数控制在调用下面的函数时是否自动解压缩:
44
* read_body(string&, bool, int*)
45
* @param stream_fixed {bool} 当该值为 true 时,则当 http_client 对象
46
* 被销毁时,传入的 client 流对象不会被销毁,需应用自行销毁;如果该
47
* 值为 false 时,则当本对象销毁时,client 流对象也将被销毁
48
*/
49
http_client
(
socket_stream
* client,
bool
is_request =
false
,
50
bool
unzip =
true
,
bool
stream_fixed =
true
);
51
52
virtual
~
http_client
(
void
);
53
54
/**
55
* 在支持长连接的多次请求中,可以手工调用此函数清除中间的数据对象,
56
* 当然这不是必须的,因为在多次调用 read_head 时,read_head 会自动
57
* 调用 reset 来清除上次请求过程中的是间对象
58
*/
59
void
reset(
void
);
60
61
/**
62
* 连接远程 HTTP 服务器
63
* @param addr {const char*} 服务器地址,格式:IP|PORT 或 DOMAIN|PORT
64
* @param conn_timeout {int} 连接超时时间(秒)
65
* @param rw_timeout {int} 读写超时时间(秒)
66
* @param unzip {bool} 当服务器返回的数据体为压缩数据时是否自动解压缩
67
* @return {bool} 连接是否成功
68
*/
69
bool
open(
const
char
* addr,
int
conn_timeout = 60,
int
rw_timeout = 60,
70
bool
unzip =
true
);
71
72
/**
73
* 写 HTTP 请求头数据至输出流中
74
* @param header {http_header&}
75
* @return {bool} 写头部数据是否成功
76
*/
77
bool
write_head(
const
http_header
& header);
78
79
/**
80
* 发送 HTTP 数据体,可以循环调用此函数,当在第一次调用 write 函数写入
81
* HTTP 头时设置了 chunked 传输方式,则内部自动采用 chunked 传输方式;
82
* 另外,在使用 chunked 方式传输数据时,应该最后再调用一次本函数,且参
83
* 数均设为 0 表示数据结束
84
* @param data {const void*} 数据地址
85
* @param len {size_t} data 数据长度
86
* @return {bool} 发送是否成功,如果返回 false 表示连接中断
87
*/
88
bool
write_body(
const
void
* data,
size_t
len);
89
90
/**
91
* 当调用 http_client(socket_stream*, bool) 构造函数创建
92
* 或用 http_client(void) 构建同时调用 open 打开数据流时
93
* 可以调用本函数获得输出数据流句柄
94
* @return {ostream&} 返回输出流的引用,如果该流并不存在,
95
* 则内部自动会产生断言,提示使用者应先将流打开
96
*/
97
ostream
& get_ostream(
void
)
const
;
98
99
/**
100
* 当调用 http_client(socket_stream*, bool) 构造函数创建
101
* 或用 http_client(void) 构建同时调用 open 打开数据流时
102
* 可以调用本函数获得输入数据流句柄
103
* @return {istream&} 返回输入流的引用,如果该流并不存在,
104
* 则内部自动会产生断言,提示使用者应先将流打开
105
*/
106
istream
& get_istream(
void
)
const
;
107
108
/**
109
* 当调用 http_client(socket_stream*, bool) 构造函数创建
110
* 或用 http_client(void) 构建同时调用 open 打开数据流时
111
* 可以调用本函数获得数据流句柄
112
* @return {socket_stream&} 返回流的引用,如果该流并不存在,
113
* 则内部自动会产生断言,提示使用者应先将流打开
114
*/
115
socket_stream
& get_stream(
void
)
const
;
116
117
/**
118
* 从 HTTP 服务器读取响应头数据或从 HTTP 客户端读取请求数据,
119
* 在长连接的多次请求中,后续的请求会自动清除上次的中间数据对象
120
* @return {bool} 是否成功
121
*/
122
bool
read_head(
void
);
123
124
/**
125
* 获得 HTTP 请求的数据体或响应的数据体长度
126
* @return {int64) 返回值若为 -1 则表明 HTTP 头不存在或没有长度字段
127
*/
128
#if defined(_WIN32) || defined(_WIN64)
129
__int64 body_length(
void
)
const
;
130
#else
131
long
long
int
body_length(
void
)
const
;
132
#endif
133
134
/**
135
* 当该对象为请求端流对象时,该函数将获得请求头中的长度起始地址及结束地址
136
* @param range_from {long long int&} 偏移起始位置
137
* @param range_to {long long int&} 偏移结束位置
138
* @return {bool} 若出错或非分段请求数据则返回 false;
139
* 若是分段请求则返回 true,同时给 range_from 和 range_to 赋值
140
* 注:range_from/range_to 下标从 0 开始
141
* 数据格式:
142
* Range: bytes={range_from}-{range_to} 或
143
* Range: bytes={range_from}-
144
*/
145
#if defined(_WIN32) || defined(_WIN64)
146
bool
request_range(__int64& range_from, __int64& range_to);
147
#else
148
bool
request_range(
long
long
int
& range_from,
long
long
int
& range_to);
149
#endif
150
151
/**
152
* 当该对象为响应端流对象时,该函数将获得响应头中的长度起始地址及结束地址
153
* @param range_from {long long int&} 偏移起始位置
154
* @param range_to {long long int&} 偏移结束位置
155
* @param total {long long int} 存放总长度
156
* @return {bool} 若出错或非分段响应数据则返回 false;
157
* 若是分段响应则返回 true,同时给 range_from 和 range_to 赋值
158
* 注:range_from/range_to 下标从 0 开始
159
* 数据格式:
160
* Content-Range: bytes {range_from}-{range_to}/{total_length}
161
* 如:Content-Range: bytes 2250000-11665200/11665201
162
*/
163
#if defined(_WIN32) || defined(_WIN64)
164
bool
response_range(__int64& range_from, __int64& range_to,
165
__int64& total);
166
#else
167
bool
response_range(
long
long
int
& range_from,
168
long
long
int
& range_to,
long
long
int
& total);
169
#endif
170
171
/**
172
* 获得 HTTP 头中的版本号
173
* @param major {unsigned&} 将存放主版本号
174
* @param minor {unsigned&} 将存放次版本号
175
* @return {bool} 是否成功获得了版本号
176
*/
177
bool
get_version(
unsigned
& major,
unsigned
& minor)
const
;
178
179
/**
180
* HTTP 数据流(请求流或响应流是否允许保持长连接)
181
* @return {bool}
182
*/
183
bool
is_keep_alive(
void
)
const
;
184
bool
keep_alive(
void
)
const
;
185
186
/**
187
* 当本对象为客户端请求对象时,本方法用来判断服务端返回的 HTTP 头中
188
* 是否允许保持长连接
189
* @return {bool}
190
*/
191
bool
is_server_keep_alive(
void
)
const
;
192
193
/**
194
* 当本对象为服务端响应对象时,本方法用来判断客户端请求的 HTTP 头中
195
* 是否允许保持长连接
196
* @return {bool}
197
*/
198
bool
is_client_keep_alive(
void
)
const
;
199
200
/**
201
* 获得 HTTP 请求头或响应头中某个字段名的字段值
202
* @param name {const char*} 字段名
203
* @return {const char*} 字段值,为空时表示不存在
204
*/
205
const
char
* header_value(
const
char
*
name
)
const
;
206
207
/**
208
* 禁止 HTTP 请求/响应头中的某些字段
209
* @param name {const char*} 字段名
210
*/
211
void
header_disable(
const
char
*
name
);
212
213
/**
214
* 将 HTTP 头中的某个字段进行替换
215
* @param name {const char*} HTTP 头的字段名,如:Content-Length,
216
* 该字段不区分大小写
217
* @param value {const char*} 该头部字段的值
218
* @param force_add {bool} 如果该头部字段不存在是否需要强制添加
219
* @return {bool} 返回 false 表示输入出错,或头部字段名不存在且参数
220
* force_add 为 false
221
*/
222
bool
header_update(
const
char
*
name
,
const
char
* value,
223
bool
force_add =
true
);
224
225
/**
226
* 将 HTTP 头中的某个字段中包含某个字符串的源字符串进行替换, 可以
227
* 支持多次匹配替换
228
* @param name {const char*} HTTP 头的字段名,如:Content-Length,
229
* 该字段不区分大小写
230
* @param match {const char*} 字段值中匹配的字符串
231
* @param to {const char*} 替换成的目标字符串值
232
* @param case_sensitive {bool} 在查找替换时是否区分大小写
233
* @return {int} 匹配替换的次数,0 表示未做任何替换,< 0 表示出错
234
*/
235
int
header_update(
const
char
*
name
,
const
char
* match,
236
const
char
* to,
bool
case_sensitive =
false
);
237
238
/**
239
* 获得 HTTP 服务器返回的 HTTP 响应状态:
240
* 1xx, 2xx, 3xx, 4xx, 5xx
241
* @return {int} 若返回值为 -1 则表示出错,或该会话过程
242
* 不是向 HTTP 服务器请求数据过程
243
*/
244
int
response_status(
void
)
const
;
245
246
/**
247
* 获得 HTTP 客户端请求的 HOST 字段值
248
* @return {const char*} 返回 NULL 表示不存在该字段
249
*/
250
const
char
* request_host(
void
)
const
;
251
252
/**
253
* 获得 HTTP 客户端请求的 PORT 端口号
254
* @return {int} 返回 -1 表示不存在
255
*/
256
int
request_port(
void
)
const
;
257
258
/**
259
* 获得 HTTP 客户端请求的 HTTP 方法:GET, POST, CONNECT
260
* @return {const char*} 返回值为空表示不存在
261
*/
262
const
char
* request_method(
void
)
const
;
263
264
/**
265
* 获得 HTTP 客户端请求的 URL 中除去 HTTP://domain 后的内容
266
* 如:对于 http://test.com.cn/cgi-bin/test?name=value,则该
267
* 函数应该返回:/cgi-bin/test?name=value
268
* @return {const char*} 返回 NULL 表示不存在
269
*/
270
const
char
* request_url(
void
)
const
;
271
272
/**
273
* 获得 HTTP 客户端请求的 URL 中的相对路径(不包含主机部分),
274
* 如:对于 http://test.com.cn/cgi-bin/test?name=value,则该
275
* 函数应该返回:/path/test.cgi
276
* @return {const char*} 返回 NULL 表示不存在
277
*/
278
const
char
* request_path(
void
)
const
;
279
280
/**
281
* 获得 HTTP 客户端请求的 URL 中的所有参数,如:
282
* http://test.com.cn/cgi-bin/test?name=value,则该函数应该返回:
283
* name=value
284
* @return {const char*} 返回 NULL 表示不存在
285
*/
286
const
char
* request_params(
void
)
const
;
287
288
/**
289
* 获得 HTTP 客户端请求的 URL 中指定的参数值,如:
290
* http://test.com.cn/cgi-bin/test?name=value,则通过该函数可以
291
* 获得 name 参数的值为 value
292
* @param name {const char*} 参数名
293
* @return {const char*} 参数值,返回 NULL 表示不存在
294
*/
295
const
char
* request_param(
const
char
*
name
)
const
;
296
297
/**
298
* 获得 HTTP 客户端请求头中的 cookie 值
299
* @param name {const char*} cookie 名
300
* @return {const char*} cookie 值,返回 NULL 则表示不存在
301
*/
302
const
char
* request_cookie(
const
char
*
name
)
const
;
303
304
/**
305
* 从 HTTP 服务器读取响应体数据或从 HTTP 客户端读取请求体数据,
306
* 此函数将对收到的数据内容进行解压操作
307
* @param out {string&} 存储数据体的缓冲区
308
* @param clean {bool} 在接收数据前是否自动清空 buf 缓冲区
309
* @param real_size {int*} 若该指针非空,则记录真正读到的数据长度,
310
* 通过该指针返回的数据值永远 >= 0
311
* @return {int} 返回值含义如下:(应用需要通过 body_finish 函数和
312
* disconnected 函数来判断数据体是否读完或连接是否关闭)
313
* > 0: 表示已经读到的数据,并且数据还未读完,需要继续读
314
* == 0: 有两种原因会返回 0,当数据读完时返回 0,可调用 body_finish
315
* 函数判断是否已经读完 HTTP 响应数据;当读到压缩数据的尾部时,
316
* 因压缩数据的8字节尾部数据是控制字段,所以不做为数据体返回,
317
* 此时也会返回 0;
318
* 还可以通过 disconnected() 函数判断连接是否已经被关闭
319
* 如果数据读完且连接半未关闭,则可以继续保持长连接
320
* < 0: 表示连接关闭
321
* 注:read_body 的两个函数不能混用;
322
* 当为解压缩数据时,则返回的值为解压缩后的数据长度
323
*/
324
int
read_body(
string
& out,
bool
clean =
true
,
int
* real_size = NULL);
325
326
/**
327
* 从 HTTP 服务器读取响应体数据或从 HTTP 客户端读取请求体数据,
328
* 该函数不能对数据进行解压
329
* @param buf {char*} 存储数据体的缓冲区,不能为空
330
* @param size {size_t} buf 缓冲区长度
331
* @return {int} 返回值含义如下:
332
* > 0: 表示已经读到的数据,并且数据还未读完,需要继续读
333
* == 0: 表示已经读完 HTTP 响应体数据,但连接并未关闭
334
* < 0: 表示连接关闭
335
*/
336
int
read_body(
char
* buf,
size_t
size);
337
338
/**
339
* 从 HTTP 服务器响应数据或客户端请求数据中读取一行数据,此函数内部将
340
* 会对原始数据进行解压操作;可以循环调用此函数直到该函数返回 false
341
* 或 body_finish() 返回 true 为止;当该函数返回 false 时表示连接已经
342
* 关闭,当返回 true 时表示读到了一行数据,此时可以通过判断
343
* body_finish() 返回值来判断是否已经读完了数据体
344
* @param out {string&} 存储数据体的缓冲区,在该函数内部不会自动清理该
345
* 缓冲区,用户可在调用该函数前自行清理该缓冲区(可调用:out.clear())
346
* @param nonl {bool} 读取一行数据时是否自动去掉尾部的 "\r\n" 或 "\n"
347
* @param size {size_t*} 当读到完整的一行数据时存放该行数据的长度,
348
* 当读到一个空行且 nonl 为 true 时,则该值为 0
349
* @return {bool} 是否读到了一行数据,当该函数返回 false 时表示读完毕
350
* 或读出错,且没有读到完整的一行数据;如果返回 true 表示读到了一行
351
* 数据,当读到一个空行时该函数也会返回 true,只是 *size = 0
352
*/
353
bool
body_gets(
string
& out,
bool
nonl =
true
,
size_t
* size = NULL);
354
355
/**
356
* 判断是否已经读完 HTTP 响应数据体
357
* @return {bool}
358
*/
359
bool
body_finish(
void
)
const
;
360
361
/**
362
* 判断网络连接是否已经关闭
363
* @return {bool}
364
*/
365
bool
disconnected(
void
)
const
;
366
367
/**
368
* 取得通过 read_head 读到的 HTTP 响应头对象,且当传入缓冲区
369
* 非空时,将 HTTP 响应头数据拷贝至缓冲区
370
* @param buf {string*} 非空时用来存储 HTTP 响应头数据
371
* @return {const HTTP_HDR_RES*} HTTP 响应头对象,如果为空,则说明
372
* 未读到响应头数据
373
*/
374
HTTP_HDR_RES
* get_respond_head(
string
* buf);
375
376
/**
377
* 取得通过 read_head 读到的 HTTP 请求头对象,且当传入缓冲区
378
* 非空时,将 HTTP 请求头数据拷贝至缓冲区
379
* @param buf {string*} 非空时用来存储 HTTP 请求头数据
380
* @return {const HTTP_HDR_REQ*} HTTP 请求头对象,如果为空,则说明
381
* 未读到请求头数据
382
*/
383
HTTP_HDR_REQ
* get_request_head(
string
* buf);
384
385
/**
386
* 输出服务器返回的 HTTP 响应头信息至标准输出
387
* @param prompt {const char*} 若非空则随同 HTTP 头信息一起输出
388
*/
389
void
print_header(
const
char
* prompt = NULL);
390
391
/**
392
* 输出服务器返回的 HTTP 响应头信息至输出流中
393
* @param out {ostream&} 输出流,可以是文件流,也可以是网络流
394
* @param prompt {const char*} 若非空则随同 HTTP 头信息一起输出
395
*/
396
void
fprint_header(
ostream
& out,
const
char
* prompt = NULL);
397
398
/**
399
* 输出服务器返回的 HTTP 响应头信息至缓冲区中
400
* @param out {string&} 存储结果的数据缓冲区
401
* @param prompt {const char*} 若非空则随同 HTTP 头信息一起输出
402
*/
403
void
sprint_header(
string
& out,
const
char
* prompt = NULL);
404
405
private
:
406
socket_stream
* stream_;
// HTTP 数据流
407
bool
stream_fixed_;
// 是否允许释放 stream_ 流对象
408
409
HTTP_HDR_RES
* hdr_res_;
// HTTP 头响应对象
410
struct
HTTP_RES
* res_;
// HTTP 响应对象
411
HTTP_HDR_REQ
* hdr_req_;
// HTTP 头请求对象
412
struct
HTTP_REQ
* req_;
// HTTP 请求对象
413
bool
unzip_;
// 是否对压缩数据进行解压缩
414
zlib_stream
* zstream_;
// 解压对象
415
bool
is_request_;
// 是否是客户请求端
416
int
gzip_header_left_;
// gzip 头剩余的长度
417
int
last_ret_;
// 数据读完后记录最后的返回值
418
bool
head_sent_;
// 头部数据是否已经发送完毕
419
bool
body_finish_;
// 是否已经读完 HTTP 响应体数据
420
bool
disconnected_;
// 网络连接是否已经关闭
421
bool
chunked_transfer_;
// 是否为 chunked 传输模式
422
unsigned
gzip_crc32_;
// gzip 压缩数据时的检验值
423
unsigned
gzip_total_in_;
// gzip 压缩前的总数据长度
424
string
* buf_;
// 内部缓冲区,用在按行读等操作中
425
426
bool
read_request_head(
void
);
427
bool
read_response_head(
void
);
428
int
read_request_body(
char
* buf,
size_t
size);
429
int
read_response_body(
char
* buf,
size_t
size);
430
int
read_request_body(
string
& out,
bool
clean,
int
* real_size);
431
int
read_response_body(
string
& out,
bool
clean,
int
* real_size);
432
433
HTTP_HDR
* get_http_hdr()
const
;
434
435
public
:
436
bool
write_chunk(
ostream
& out,
const
void
* data,
size_t
len);
437
bool
write_chunk_trailer(
ostream
& out);
438
439
bool
write_gzip(
ostream
& out,
const
void
* data,
size_t
len);
440
bool
write_gzip_trailer(
ostream
& out);
441
};
442
443
}
// namespace acl
acl::istream
Definition:
istream.hpp:15
name
HTTP_API void const char * name
Definition:
lib_http.h:620
acl::zlib_stream
Definition:
zlib_stream.hpp:77
HTTP_RES
Definition:
lib_http_struct.h:99
acl::http_header
Definition:
http_header.hpp:19
HTTP_HDR_RES
Definition:
lib_http_struct.h:180
HTTP_HDR
Definition:
lib_http_struct.h:117
acl
Definition:
acl_cpp_init.hpp:4
acl::ostream
Definition:
ostream.hpp:17
acl::noncopyable
Definition:
noncopyable.hpp:6
HTTP_REQ
Definition:
lib_http_struct.h:91
HTTP_HDR_REQ
Definition:
lib_http_struct.h:149
acl::socket_stream
Definition:
socket_stream.hpp:14
ACL_CPP_API
#define ACL_CPP_API
Definition:
acl_cpp_define.hpp:16
acl::http_client
Definition:
http_client.hpp:25
include
acl_cpp
http
http_client.hpp
生成于 2021年 九月 10日 星期五 11:14:44 , 为 acl使用
1.8.15