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  */
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
HTTP_API void const char * name
Definition: lib_http.h:620
#define ACL_CPP_API