acl/lib_acl_cpp/include/acl_cpp/http/HttpServletResponse.hpp
2024-07-22 17:07:57 +08:00

285 lines
8.4 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#pragma once
#include "../acl_cpp_define.hpp"
#include "../stdlib/noncopyable.hpp"
#ifndef ACL_CLIENT_ONLY
namespace acl {
class dbuf_guard;
class string;
class xml;
class json;
class ostream;
class socket_stream;
class http_header;
class http_client;
class HttpCookie;
class HttpServletRequest;
/**
* 与 HTTP 客户端响应相关的类,该类不应被继承,用户也不需要
* 定义或创建该类对象
*/
class ACL_CPP_API HttpServletResponse : public noncopyable {
public:
/**
* 构造函数
* @param stream {socket_stream&} 数据流,内部不会自动关闭流
*/
explicit HttpServletResponse(socket_stream& stream);
~HttpServletResponse();
/**
* 设置 HTTP 响应数据体的长度
* @param n {acl_int64} 数据体长度
*/
#if defined(_WIN32) || defined(_WIN64)
HttpServletResponse& setContentLength(__int64 n);
#else
HttpServletResponse& setContentLength(long long int n);
#endif
/**
* 设置 HTTP chunked 传输模式
* @param on {bool} 如果为 true即使设置了 setContentLength
* 则内部也会采用 chunked 传输方式,根据 HTTP RFC 规范要求,
* chunked 传输的优先级高级 conteng-length 方式
* @return {HttpServletResponse&}
*/
HttpServletResponse& setChunkedTransferEncoding(bool on);
/**
* 设置与 HTTP 客户端保持联系长连接
* @param on {bool}
* @return {HttpServletResponse&}
*/
HttpServletResponse& setKeepAlive(bool on);
/**
* 设置 HTTP 响应数据体的 Content-Type 字段值,可字段值可以为:
* text/html 或 text/html; charset=utf8 格式
* @param value {const char*} 字段值
* @return {HttpServletResponse&}
*/
HttpServletResponse& setContentType(const char* value);
/**
* 设置 HTTP 响应数据体采用 gzip 压缩格式
* @param gzip {bool} 是否采用 gzip 压缩格式
* @return {HttpServletResponse&}
*/
HttpServletResponse& setContentEncoding(bool gzip);
/**
* 设置 HTTP 响应数据体中字符集,当已经在 setContentType 设置
* 了字符集,则就不必再调用本函数设置字符集
* @param charset {const char*} 响应体数据的字符集
* @return {HttpServletResponse&}
*/
HttpServletResponse& setCharacterEncoding(const char* charset);
/**
* 设置 HTTP 响应头中的日期格式的字段
* @param name {const char*} HTTP 响应头中的字段名
* @param value {time_t} 时间值
*/
HttpServletResponse& setDateHeader(const char* name, time_t value);
/**
* 设置 HTTP 响应头中的字符串格式字段
* @param name {const char*} HTTP 响应头中的字段名
* @param value {const char*} 字段值
*/
HttpServletResponse& setHeader(const char* name, const char* value);
/**
* 设置 HTTP 响应头中的整数格式字段
* @param name {const char*} HTTP 响应头中的字段名
* @param value {int} 字段值
*/
HttpServletResponse& setHeader(const char* name, int value);
/**
* 对于分区下载,调用本函数设置数据下载的偏移位置(下标从 0 开始)
* @param from {http_off_t} 数据区间起始偏移位置(下标从 0 开始计算)
* @param to {http_off_t} 数据区间结束位置(该值需小于总数据长度)
* @param total {http_off_t} 总数据长度,当数据源为一个静态文件时该值
* 应等于该文件的总长度大小
* @return {HttpServletResponse&}
*/
#if defined(_WIN32) || defined(_WIN64)
HttpServletResponse& setRange(__int64 from,
__int64 to, __int64 total);
#else
HttpServletResponse& setRange(long long from,
long long to, long long total);
#endif
/**
* 设置 HTTP 响应头中的状态码1xx, 2xx, 3xx, 4xx, 5xx
* @param status {int} HTTP 响应状态码, 如200
*/
HttpServletResponse& setStatus(int status);
/**
* 设置为 CGI 模式,用户一般不需手工设置,因为 HttpServlet 类
* 会自动设置是否是 CGI 模式
* @param on {bool} 是否是 CGI 模式
*/
HttpServletResponse& setCgiMode(bool on);
/**
* 设置 HTTP 响应头中的重定向 location 字段
* @param location {const char*} URL非空
* @param status {int} HTTP 响应状态码,一般为 3xx 类
*/
HttpServletResponse& setRedirect(const char* location, int status = 302);
/**
* 添加 cookie 对象,该对象必须是动态分配的,且用户自己不能
* 再显示释放该对象,因为内部会自动释放
* @param cookie {HttpCookie*}
*/
HttpServletResponse& addCookie(HttpCookie* cookie);
/**
* 添加 cookie
* @param name {const char*} cookie 名
* @param value {const char*} cookie 值
* @param domain {const char*} cookie 存储域
* @param path {const char*} cookie 存储路径
* @param expires {time_t} cookie 过期时间间隔,当当前时间加
* 该值为 cookie 的过期时间截(秒)
*/
HttpServletResponse& addCookie(const char* name, const char* value,
const char* domain = NULL, const char* path = NULL,
time_t expires = 0);
/**
* 将 url 进行 url 编码
* @param out {string&} 存储编码后的结果
* @param url {const char*} 未编码前原始的 url
*/
void encodeUrl(string& out, const char* url);
/**
* 获得 HTTP 响应头
* @return {http_header&}
*/
http_header& getHttpHeader() const;
/**
* 向客户端发送 HTTP 数据体响应数据,可以循环调用此函数,
* 当通过 setChunkedTransferEncoding 设置了 chunked 传输方式后,
* 内部自动采用 chunked 传输方式;调用此函数不必显式调用
* sendHeader 函数来发送 HTTP 响应头,因为内部会自动在第一次
* 写时发送 HTTP 响应头;另外,在使用 chunked 方式传输数据时,
* 应该应该最后再调用一次本函数,且参数均设为 0 表示数据结束
* @param data {const void*} 数据地址
* @param len {size_t} data 数据长度
* @return {bool} 发送是否成功,如果返回 false 表示连接中断
*/
bool write(const void* data, size_t len);
/**
* 向客户端发送 HTTP 数据体响应数据,可以循环调用此函数,该函数
* 内部调用 HttpServletResponse::write(const void*, size_t) 过程,
* 另外,在使用 chunked 方式传输数据时,应该应该最后再调用一次本函数,
* 且输入空串,即 buf.empty() == true
* @param buf {const string&} 数据缓冲区
* @return {bool} 发送是否成功,如果返回 false 表示连接中断
*/
bool write(const string& buf);
/**
* 向客户端发送 HTTP Xml 响应数据体
* @param body {const xml&} 数据缓冲区
* @param charset {const char*} 数据体字符集
* @return {bool} 发送是否成功,如果返回 false 表示连接中断
*/
bool write(const xml& body, const char* charset = "utf-8");
/**
* 向客户端发送 HTTP Json 响应数据体
* @param body {const json&} 数据缓冲区
* @param charset {const char*} 数据体字符集
* @return {bool} 发送是否成功,如果返回 false 表示连接中断
*/
bool write(const json& body, const char* charset = "utf-8");
/**
* 带格式方式向 HTTP 客户端发送响应数据,内部自动调用
* HttpServletResponse::write(const void*, size_t) 过程,在使用
* chunked 方式传输数据时,应该应该最后再调用 write(NULL, 0)
* 表示数据结束
* @param fmt {const char*} 变参格式字符串
* @return {int} 成功则返回值 > 0否则返回 -1
*/
int format(const char* fmt, ...) ACL_CPP_PRINTF(2, 3);
/**
* 带格式方式向 HTTP 客户端发送响应数据,内部自动调用
* HttpServletResponse::write(const string&) 过程,在使用 chunked
* 方式传输数据时,应该应该最后再调用 write(NULL, 0) 表示数据结束
* @param fmt {const char*} 变参格式字符串
* @param ap {va_list} 变参列表
* @return {int} 成功则返回值 > 0否则返回 -1
*/
int vformat(const char* fmt, va_list ap);
///////////////////////////////////////////////////////////////////
/**
* 发送 HTTP 响应头,用户应该发送数据体前调用此函数将 HTTP
* 响应头发送给客户端
* @return {bool} 发送是否成功,若返回 false 则表示连接中断,
* 当调用以上几个写的函数时,本函数不必显式被调用,如果是
* 通过从 getOutputStream 获得的 socket 流写数据时,则本函数
* 必须显式被调用
*/
bool sendHeader();
/**
* 获得 HTTP 响应对象的输出流对象,用户在调用 sendHeader 发送
* 完 HTTP 响应头后,通过该输出流来发送 HTTP 数据体
* @return {ostream&}
*/
ostream& getOutputStream() const;
/**
* 获得 HTTP 双向流对象,由构造函数的参数输入
* @return {socket_stream&}
*/
socket_stream& getSocketStream() const;
/**
* 获得底层的 http_client 通信对象
* @return {http_client*} 非 NULL
*/
http_client* getClient() const {
return client_;
}
/**
* 设置 http 请求对象,该函数目前只应被 HttpServlet 类内部调用
* @param request {HttpServletRequest*}
*/
void setHttpServletRequest(HttpServletRequest* request);
private:
dbuf_guard* dbuf_internal_;
dbuf_guard* dbuf_;
socket_stream& stream_; // 客户端连接流
HttpServletRequest* request_; // http 请求对象
http_client* client_; // http 响应流对象
http_header* header_; // http 响应头
char charset_[32]; // 字符集
char content_type_[32]; // content-type 类型
bool head_sent_; // 是否已经发送了 HTTP 响应头
};
} // namespace acl
#endif // ACL_CLIENT_ONLY