acl  3.5.3.0
http_header.hpp
浏览该文件的文档.
1 #pragma once
2 #include "../acl_cpp_define.hpp"
3 #include <list>
4 #include "../stdlib/dbuf_pool.hpp"
5 #include "../http/http_type.hpp"
6 
7 struct HTTP_HDR_RES;
8 struct HTTP_HDR_REQ;
9 struct HTTP_HDR_ENTRY;
10 
11 namespace acl {
12 
13 class string;
14 class HttpCookie;
15 
16 /**
17  * HTTP 头类,可以构建请求头或响应头
18 */
20 {
21 public:
22  /**
23  * 构造函数
24  * @param dbuf {dbuf_guard*} 非空时将做为内存分配池
25  */
26  http_header(dbuf_guard* dbuf = NULL);
27 
28  /**
29  * HTTP 请求头构造函数
30  * @param url {const char*} 请求的 URL,url 格式示例如下:
31  * http://www.test.com/
32  * /cgi-bin/test.cgi
33  * http://www.test.com/cgi-bin/test.cgi
34  * http://www.test.com/cgi-bin/test.cgi?name=value
35  * /cgi-bin/test.cgi?name=value
36  * 如果该 url 中有主机字段,则内部自动添加主机;
37  * 如果该 url 中有参数字段,则内部自动进行处理并调用 add_param 方法;
38  * 调用该函数后用户仍可以调用 add_param 等函数添加其它参数;
39  * 当参数字段只有参数名没有参数值时,该参数将会被忽略,所以如果想
40  * 单独添加参数名,应该调用 add_param 方法来添加
41  * @param dbuf {dbuf_guard*} 非空时将做为内存分配池
42  * @param encoding {bool} 是否对存在于 url 中的参数进行 url 编码,如果为
43  * true 则会重新解析 url 并重新对 url 中的参数进行编码,否则则 url 保持原样
44  */
45  http_header(const char* url, dbuf_guard* dbuf = NULL,
46  bool encoding = true);
47 
48  /**
49  * HTTP 响应头构造函数
50  * @param status {int} 状态字如:1xx, 2xx, 3xx, 4xx, 5xx
51  * @param dbuf {dbuf_guard*} 非空时将做为内存分配池
52  */
53  http_header(int status, dbuf_guard* dbuf = NULL);
54 
55  /**
56  * 根据 C语言 的 HTTP 响应头进行构造
57  * @param hdr_res {const HTTP_HDR_RES&}
58  * @param dbuf {dbuf_guard*} 非空时将做为内存分配池
59  */
60  http_header(const HTTP_HDR_RES& hdr_res, dbuf_guard* dbuf = NULL);
61 
62  /**
63  * 根据 C语言 的 HTTP 请求头进行构造
64  * @param hdr_req {const HTTP_HDR_REQ&}
65  * @param dbuf {dbuf_guard*} 非空时将做为内存分配池
66  */
67  http_header(const HTTP_HDR_REQ& hdr_req, dbuf_guard* dbuf = NULL);
68 
69  virtual ~http_header(void);
70 
71  /**
72  * 重置 HTTP 头信息同时将上次的临时资源释放
73  */
74  void reset(void);
75 
76  //////////////////////////////////////////////////////////////////////
77  // HTTP 请求与 HTTP 响应通用的方法函数
78  //////////////////////////////////////////////////////////////////////
79 
80  /**
81  * 设置 HTTP 协议版本号
82  * @param version {const char*} HTTP 协议版本号,格式:1.0, 1.1
83  * @return {http_header&}
84  */
85  http_header& set_proto_version(const char* version);
86 
87  /**
88  * 设置 HTTP 头是客户端的请求头还是服务器的响应头
89  * @param onoff {bool} true 表示是请求头,否则表示响应头
90  * @return {http_header&} 返回本对象的引用,便于用户连续操作
91  */
92  http_header& set_request_mode(bool onoff);
93 
94  /**
95  * 向 HTTP 头中添加字段
96  * @param name {const char*} 字段名,非空指针
97  * @param value {const char*} 字段值,非空指针
98  * @param replace {bool} 如果存在重复项时是否自动覆盖旧数据
99  * @return {http_header&} 返回本对象的引用,便于用户连续操作
100  */
101  http_header& add_entry(const char* name, const char* value,
102  bool replace = true);
103 
104  /**
105  * 从 HTTP 头中获得指定的头部字段
106  * @param name {const char*} 字段名,非空指针
107  * @return {const char*} 返回值 NULL 表示不存在
108  */
109  const char* get_entry(const char* name) const;
110 
111  /**
112  * 设置 HTTP 头中的 Content-Length 字段
113  * @param n {int64} 设置值
114  * @return {http_header&} 返回本对象的引用,便于用户连续操作
115  */
116 #if defined(_WIN32) || defined(_WIN64)
117  http_header& set_content_length(__int64 n);
118 
119  /**
120  * 获得通过 set_content_length 设置的 HTTP 头中的 Content-Length 值
121  * @return {int64}
122  */
123  __int64 get_content_length() const
124  {
125  return content_length_;
126  }
127 #else
128  http_header& set_content_length(long long int n);
129  long long int get_content_length() const
130  {
131  return content_length_;
132  }
133 #endif
134 
135  /**
136  * 设置 HTTP 请求头(响应头)中的 Range 字段,用于分段请求(响应)数据,
137  * 多用于支持断点续传的 WEB 服务器中
138  * @param from {http_off_t} 起始偏移位置,下标从 0 开始,该
139  * 值当 >= 0 时才有效
140  * @param to {http_off_t} 请求结束偏移位置,下标从 0 开始,
141  * 在请求头中当该值输入 < 0 时,则认为是请求从起始位置开始至最终长度位置
142  * @return {http_header&} 返回本对象的引用,便于用户连续操作
143  */
144 #if defined(_WIN32) || defined(_WIN64)
145  http_header& set_range(__int64 from, __int64 to);
146 #else
147  http_header& set_range(long long from, long long to);
148 #endif
149 
150  /**
151  * 对于响应头在分段传输前需要调用此函数设置数据体总长度
152  * @param total {http_off_t} 仅对于响应头,该参数需要设为数据总长度
153  * @return {http_header&}
154  */
155 #if defined(_WIN32) || defined(_WIN64)
156  http_header& set_range_total(__int64 total);
157 #else
158  http_header& set_range_total(long long total);
159 #endif
160 
161  /**
162  * 获得由 set_range 设置的分段请求位置值
163  * @param from {http_off_t*} 非空时存储起始位置偏移
164  * @param to {http_off_t*} 非空时存储结束位置偏移
165  */
166 #if defined(_WIN32) || defined(_WIN64)
167  void get_range(__int64* from, __int64* to);
168 #else
169  void get_range(long long int* from, long long int* to);
170 #endif
171 
172  /**
173  * 设置 HTTP 头中的 Content-Type 字段
174  * @param value {const char*} 设置值
175  * @return {http_header&} 返回本对象的引用,便于用户连续操作
176  */
177  http_header& set_content_type(const char* value);
178 
179  /**
180  * 设置 HTTP 头中的 Connection 字段,是否保持长连接
181  * 不过,目前并未真正支持长连接,即使设置了该标志位,
182  * 则得到响应数据后也会主动关闭连接
183  * @param on {bool} 是否保持长连接
184  * @return {http_header&} 返回本对象的引用,便于用户连续操作
185  */
186  http_header& set_keep_alive(bool on);
187 
188  /**
189  * 检查当前头是否设置了保持长连接选项
190  */
191  bool get_keep_alive() const
192  {
193  return keep_alive_;
194  }
195 
196  http_header& set_upgrade(const char* value = "websocket");
197  const char* get_upgrade(void) const
198  {
199  return upgrade_;
200  }
201 
202  /**
203  * 向 HTTP 头中添加 cookie
204  * @param name {const char*} cookie 名
205  * @param value {const char*} cookie 值
206  * @param domain {const char*} 所属域
207  * @param path {const char*} 存储路径
208  * @param expires {time_t} 过期时间,当该值为 0 时表示不过期,
209  * > 0 时,则从现在起再增加 expires 即为过期时间,单位为秒
210  * @return {http_header&} 返回本对象的引用,便于用户连续操作
211  */
212  http_header& add_cookie(const char* name, const char* value,
213  const char* domain = NULL, const char* path = NULL,
214  time_t expires = 0);
215 
216  /**
217  * 向 HTTP 头中添加 cookie
218  * @param cookie {const http_cookie*} cookie 对象
219  * @return {http_header&} 返回本对象的引用,便于用户连续操作
220  */
221  http_header& add_cookie(const HttpCookie* cookie);
222 
223  /**
224  * 从 HTTP 头中获得对应名称的 cookie 对象
225  * @param name {const char*} cookie 名
226  * @return {const HttpCookie*}
227  */
228  const HttpCookie* get_cookie(const char* name) const;
229 
230  /**
231  * 将整型的日期转换为 rfc1123 字符串格式的日期
232  */
233  static void date_format(char* out, size_t size, time_t t);
234 
235  /**
236  * 判断是否是 HTTP 请求头
237  * @return {bool} 返回 false 表明是 HTTP 响应头
238  */
239  bool is_request(void) const;
240 
241  /**
242  * 设置标志位,针对 HTTP 请求的 URI 中的 ? 问号被转义(即被转成 %3F)的请求是否
243  * 做兼容性处理,内部缺省为做兼容性处理
244  * @param on {bool} 为 true 表示做兼容性处理
245  */
246  static void uri_unsafe_correct(bool on);
247 
248  //////////////////////////////////////////////////////////////////////
249  // HTTP 请求方法函数
250  //////////////////////////////////////////////////////////////////////
251 
252  /**
253  * 创建 HTTP 请求头数据
254  * @param buf {string&} 存储结果数据
255  * @return {bool} 创建请求头中否成功
256  */
257  bool build_request(string& buf) const;
258 
259  /**
260  * 设置请求的 URL,url 格式示例如下:
261  * 1、http://www.test.com/
262  * 2、/cgi-bin/test.cgi
263  * 3、http://www.test.com/cgi-bin/test.cgi
264  * 3、http://www.test.com/cgi-bin/test.cgi?name=value
265  * 4、/cgi-bin/test.cgi?name=value
266  * 5、http://www.test.com
267  * 如果该 url 中有主机字段,则内部自动添加主机;
268  * 如果该 url 中有参数字段,则内部自动进行处理并调用 add_param 方法;
269  * 调用该函数后用户仍可以调用 add_param 等函数添加其它参数;
270  * 当参数字段只有参数名没有参数值时,该参数将会被忽略,所以如果想
271  * 单独添加参数名,应该调用 add_param 方法来添加
272  * @param url {const char*} 请求的 url,非空指针
273  * @param encoding {bool} 是否对存在于 url 中的参数进行 url 编码,如果为
274  * true 则会重新解析 url 并重新对 url 中的参数进行编码,否则则 url 保持原样
275  * @return {http_header&} 返回本对象的引用,便于用户连续操作
276  */
277  http_header& set_url(const char* url, bool encoding = true);
278 
279  /**
280  * 设置 HTTP 请求头的 HOST 字段
281  * @param value {const char*} 请求头的 HOST 字段值
282  * @return {http_header&} 返回本对象的引用,便于用户连续操作
283  */
284  http_header& set_host(const char* value);
285 
286  /**
287  * 获得设置的 HTTP 请求头中的 HOST 字段
288  * @return {const char*} 返回空指针表示没有设置 HOST 字段
289  */
290  const char* get_host() const
291  {
292  return host_[0] == 0 ? NULL : host_;
293  }
294 
295  /**
296  * 设置 HTTP 协议的请求方法,如果不调用此函数,则默认用 GET 方法
297  * @param method {http_method_t} HTTP 请求方法
298  * @return {http_header&} 返回本对象的引用,便于用户连续操作
299  */
300  http_header& set_method(http_method_t method);
301 
302  /**
303  * 设置 HTTP 协议的请求方法,本函数允许用户扩展 HTTP 请求方法,
304  * 通过该函数设置的请求方法仅影响 HTTP 请求过程
305  * @param method {const char*} 请求方法
306  * @return {http_header&} 返回本对象的引用,便于用户连续操作
307  */
308  http_header& set_method(const char* method);
309 
310  /**
311  * 当作为请求头时,本函数取得当前邮件头的请求方法
312  * @param buf {string*} 存储用字符串表示的请求方法
313  * @return {http_method_t}
314  */
315  http_method_t get_method(string* buf = NULL) const;
316 
317  /**
318  * 设置 HTTP 请求头中是否允许接收压缩数据,对应的 HTTP 头字段为:
319  * Accept-Encoding: gzip, deflate,但目前仅支持 gzip 格式
320  * @param on {bool} 如果为 true 则自动添加 HTTP 压缩头请求
321  * @return {http_header&} 返回本对象的引用,便于用户连续操作
322  */
323  http_header& accept_gzip(bool on);
324 
325  /**
326  * 在调用下面的 add_param/add_int/add_format 时,是否允许覆盖同名参数,
327  * 内部缺省值为否,既不覆盖同名参数
328  * @param yes {bool}
329  * @return {http_header&}
330  */
331  http_header& set_param_override(bool yes);
332 
333  /**
334  * 向请求的 URL 中添加参数对,当只有参数名没有参数值时则:
335  * 1、参数名非空串,但参数值为空指针,则 URL 参数中只有:{name}
336  * 2、参数名非空串,但参数值为空串,则 URL参数中为:{name}=
337  * @param name {const char*} 参数名,不能为空指针
338  * @param value {const char*} 参数值,当为空指针时,仅添加参数名,
339  * @return {http_header&} 返回本对象的引用,便于用户连续操作
340  */
341  http_header& add_param(const char* name, const char* value);
342  http_header& add_int(const char* name, short value);
343  http_header& add_int(const char* name, int value);
344  http_header& add_int(const char* name, long value);
345  http_header& add_int(const char* name, unsigned short value);
346  http_header& add_int(const char* name, unsigned int value);
347  http_header& add_int(const char* name, unsigned long value);
348  http_header& add_format(const char* name, const char* fmt, ...)
349  ACL_CPP_PRINTF(3, 4);
350 #if defined(_WIN32) || defined(_WIN64)
351  http_header& add_int(const char* name, __int64 vlaue);
352  http_header& add_int(const char* name, unsigned __int64 vlaue);
353 #else
354  http_header& add_int(const char* name, long long int value);
355  http_header& add_int(const char* name, unsigned long long int value);
356 #endif
357 
358  http_header& set_ws_origin(const char* url);
359  http_header& set_ws_key(const void* key, size_t len);
360  http_header& set_ws_key(const char* key);
361  http_header& set_ws_protocol(const char* proto);
362  http_header& set_ws_version(int ver);
363 
364  const char* get_ws_origin(void) const
365  {
366  return ws_origin_;
367  }
368 
369  const char* get_ws_key(void) const
370  {
371  return ws_sec_key_;
372  }
373 
374  const char* get_ws_protocol(void) const
375  {
376  return ws_sec_proto_;
377  }
378 
379  int get_ws_version(void) const
380  {
381  return ws_sec_ver_;
382  }
383 
384  http_header& set_ws_accept(const char* key);
385  const char* get_ws_accept(void) const
386  {
387  return ws_sec_accept_;
388  }
389 
390  /**
391  * url 重定向
392  * @param url {const char*} 重定向的 URL,格式为:
393  * http://xxx.xxx.xxx/xxx 或 /xxx
394  * 如果是前者,则自动从中取出 HOST 字段,如果是后者,则
395  * 延用之前的 HOST
396  */
397  bool redirect(const char* url);
398 
399  /**
400  * 设置重定向次数,如果该值 == 0 则不主动进行重定向,否则
401  * 进行重定向且重定向的次数由该值决定
402  * @param n {int} 允许重定向的次数
403  * @return {http_header&} 返回本对象的引用,便于用户连续操作
404  */
405  http_header& set_redirect(unsigned int n = 5);
406 
407  /**
408  * 获取通过 set_redirect 设置的允许的最大重定向次数
409  * @return {unsigned int}
410  */
411  unsigned int get_redirect(void) const;
412 
413  /**
414  * 当需要重定向时,会主动调用此函数允许子类做一些重置工作
415  */
416  virtual void redicrect_reset(void) {}
417 
418  //////////////////////////////////////////////////////////////////////
419  // HTTP 响应方法函数
420  //////////////////////////////////////////////////////////////////////
421 
422  /**
423  * 创建 HTTP 响应头数据
424  * @param buf {string&} 存储结果数据
425  * @return {bool} 创建响应头中否成功
426  */
427  bool build_response(string& buf) const;
428 
429  /**
430  * 设置 HTTP 响应头中的响应状态字
431  * @param status {int} 状态字如:1xx, 2xx, 3xx, 4xx, 5xx
432  * @return {http_header&} 返回本对象的引用,便于用户连续操作
433  */
434  http_header& set_status(int status);
435 
436  /**
437  * 获得响应头中的 HTTP 状态字
438  * @return {int} HTTP 响应状态码:1xx, 2xx, 3xx, 4xx, 5xx
439  */
440  int get_status(void) const
441  {
442  return status_;
443  }
444 
445  /**
446  * 设置 HTTP 响应头中的 chunked 传输标志
447  * @param on {bool}
448  * @return {http_header&}
449  */
450  http_header& set_chunked(bool on);
451 
452  /**
453  * 判断当前 HTTP 传输是否采用 chunked 传输方式
454  * @return {bool}
455  */
456  bool chunked_transfer(void) const
457  {
458  return chunked_transfer_;
459  }
460 
461  /**
462  * 设置是否用来生成 CGI 格式的响应头
463  * @param on {bool} 是否 CGI 格式响应头
464  * @return {http_header&} 返回本对象的引用,便于用户连续操作
465  */
466  http_header& set_cgi_mode(bool on);
467 
468  /**
469  * 是否设置了 CGI 模式
470  * @return {bool}
471  */
472  bool is_cgi_mode() const
473  {
474  return cgi_mode_;
475  }
476 
477  /**
478  * 设置传输的数据是否采用 gzip 方式进行压缩
479  * @param on {bool}
480  * @return {http_header&}
481  */
482  http_header& set_transfer_gzip(bool on);
483 
484  /**
485  * 获得当前的数据传输是否设置了采用 gzip 压缩方式
486  * @return {bool}
487  */
488  bool is_transfer_gzip() const
489  {
490  return transfer_gzip_;
491  }
492 
493 private:
494  dbuf_guard* dbuf_internal_;
495  dbuf_guard* dbuf_;
496  bool fixed_; // HTTP 是否已经完整了
497  //char* domain_; // HTTP 服务器域名
498  //unsigned short port_; // HTTP 服务器端口
499  char* url_; // HTTP 请求的 URL
500  std::list<HTTP_PARAM*> params_; // 请求参数集合
501  bool param_override_; // 在添加参数时是否覆盖同步参数
502  std::list<HttpCookie*> cookies_; // cookies 集合
503  std::list<HTTP_HDR_ENTRY*> entries_; // HTTP 请求头中各字段集合
504  http_method_t method_; // HTTP 请求的方法
505  char version_[8]; // HTTP 协议版本号
506  char method_s_[64]; // HTTP 请求方法以字符串表示
507  char host_[256]; // HTTP 请求头中的 HOST 字段
508  bool keep_alive_; // 是否保持长连接
509  unsigned int nredirect_; // 最大重定向的次数限制
510  bool accept_compress_; // 是否接收压缩数据
511  int status_; // 响应头的状态字
512  bool is_request_; // 是请求头还是响应头
513  bool cgi_mode_; // 是否 CGI 响应头
514 #if defined(_WIN32) || defined(_WIN64)
515  __int64 range_from_; // 请求头中,range 起始位置
516  __int64 range_to_; // 请求头中,range 结束位置
517  __int64 range_total_; // range 传输模式下记录数据总长度
518  __int64 content_length_; // HTTP 数据体长度
519 #else
520  long long int range_from_; // 请求头中,range 起始位置
521  long long int range_to_; // 请求头中,range 结束位置
522  long long int range_total_; // range 传输模式下记录数据总长度
523  long long int content_length_; // HTTP 数据体长度
524 #endif
525  bool chunked_transfer_; // 是否为 chunked 传输模式
526  bool transfer_gzip_; // 数据是否采用 gzip 压缩
527 
528  char* upgrade_;
529  // just for websocket
530  char* ws_origin_;
531  char* ws_sec_key_;
532  char* ws_sec_proto_;
533  int ws_sec_ver_;
534  char* ws_sec_accept_;
535 
536  void init(void); // 初始化
537  void clear(void);
538  void build_common(string& buf) const; // 构建通用头
539 
540  void add_res_cookie(const HTTP_HDR_ENTRY& entry);
541  void append_accept_key(const char* sec_key, string& out) const;
542  unsigned char* create_ws_key(const void* key, size_t len) const;
543 };
544 
545 } // namespace acl end
const char * get_ws_protocol(void) const
virtual void redicrect_reset(void)
const char * get_ws_key(void) const
HTTP_API void const char * name
Definition: lib_http.h:620
#define ACL_CPP_PRINTF(format_idx, arg_idx)
Definition: atomic.hpp:75
const char * get_upgrade(void) const
bool chunked_transfer(void) const
int get_status(void) const
bool get_keep_alive() const
const char * get_ws_origin(void) const
http_method_t
Definition: http_type.hpp:29
bool is_transfer_gzip() const
ACL_API void const char * fmt
Definition: acl_aio.h:771
const char * get_host() const
#define ACL_CPP_API
int get_ws_version(void) const
long long int get_content_length() const
const char * get_ws_accept(void) const
bool is_cgi_mode() const