4G_module/include/cmiot/cm_http.h

438 lines
16 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.

/**
* @file cm_http_client.h
* @brief HTTP协议客户端接口
* @copyright Copyright © 2021 China Mobile IOT. All rights reserved.
* @author By chenxy
* @date 2021/05/21
*
* @defgroup http http
* @ingroup NP
* @{
*/
#ifndef __CM_HTTP_H__
#define __CM_HTTP_H__
#include <stdint.h>
#ifdef __cplusplus
extern "C"
{
#endif
/** @defgroup httpclient_define Define
* @{
*/
#ifndef true
#define true (1)
#endif
#ifndef false
#define false (0)
#endif
#ifndef bool
#define bool int
#endif
#ifndef NULL
#define NULL ((void *)0)
#endif
/**HTTP默认端口*/
#define HTTP_DEFAULT_PORT 80
/**HTTPS默认端口*/
#define HTTPS_DEFAULT_PORT 443
/**HTTP可创建实例个数*/
#define HTTPCLIENT_CTX_MAX_NUM 4
/**HTTP连接超时最大时间*/
#define HTTPCLIENT_CONNECT_TIMEOUT_MAXTIME 180
/**HTTP请求响应超时最大时间*/
#define HTTPCLIENT_WAITRSP_TIMEOUT_MAXTIME 60
/**HTTP连接超时默认时间*/
#define HTTPCLIENT_CONNECT_TIMEOUT_DEFAULT 60
/**HTTP请求响应超时默认时间*/
#define HTTPCLIENT_WAITRSP_TIMEOUT_DEFAULT 0
/**
* @}
*/
/** @defgroup httpclient_enum Enum
* @{
*/
/**HTTP请求类型*/
typedef enum {
HTTPCLIENT_REQUEST_NONE = 0,
HTTPCLIENT_REQUEST_GET,
HTTPCLIENT_REQUEST_POST,
HTTPCLIENT_REQUEST_PUT,
HTTPCLIENT_REQUEST_DELETE,
HTTPCLIENT_REQUEST_HEAD,
HTTPCLIENT_REQUEST_MAX
} cm_httpclient_request_type_e;
/**HTTP回调事件*/
typedef enum{
CM_HTTP_CALLBACK_EVENT_REQ_START_SUCC_IND=1, /*!< 请求启动成功事件 */
CM_HTTP_CALLBACK_EVENT_RSP_HEADER_IND, /*!< 接收到报头事件 */
CM_HTTP_CALLBACK_EVENT_RSP_CONTENT_IND, /*!< 接收到消息体事件 */
CM_HTTP_CALLBACK_EVENT_RSP_END_IND, /*!< 请求响应结束事件 */
CM_HTTP_CALLBACK_EVENT_ERROR_IND, /*!< 请求失败事件 */
}cm_httpclient_callback_event_e;
/**HTTP异常状态码*/
typedef enum{
CM_HTTP_EVENT_CODE_DNS_FAIL=1, /*!< DNS解析失败 */
CM_HTTP_EVENT_CODE_CONNECT_FAIL, /*!< 连接服务器失败 */
CM_HTTP_EVENT_CODE_CONNECT_TIMEOUT, /*!< 连接超时 */
CM_HTTP_EVENT_CODE_SSL_CONNECT_FAIL, /*!< SSL握手失败 */
CM_HTTP_EVENT_CODE_CONNECT_BREAK, /*!< 连接异常断开 */
CM_HTTP_EVENT_CODE_WAITRSP_TIMEOUT, /*!< 等待响应超时 */
CM_HTTP_EVENT_CODE_DATA_PARSE_FAIL, /*!< 数据解析失败 */
CM_HTTP_EVENT_CODE_CACHR_NOT_ENOUGH, /*!< 缓存空间不足 */
CM_HTTP_EVENT_CODE_DATA_DROP, /*!< 数据丢包 */
CM_HTTP_EVENT_CODE_WRITE_FILE_FAIL, /*!< 写文件失败 */
CM_HTTP_EVENT_CODE_UNKNOWN=255, /*!< 未知错误 */
}cm_httpclient_error_event_e;
/**HTTP结果码*/
typedef enum{
CM_HTTP_RET_CODE_OK = 0, /*!< 成功 */
CM_HTTP_RET_CODE_OPERATION_NOT_ALLOWED = 3, /*!< 操作不被允许 3 */
CM_HTTP_RET_CODE_MALLOC_FAIL = 23, /*!< 内存分配失败 23 */
CM_HTTP_RET_CODE_PARAM_ERROR = 50, /*!< 参数错误 50 */
CM_HTTP_RET_CODE_UNKNOWN_ERROR = 650, /*!< 未知错误 650 */
CM_HTTP_RET_CODE_NO_MORE_FREE_CLIENT = 651, /*!< 没有空闲客户端 651 */
CM_HTTP_RET_CODE_CLIENT_NOT_CREATE = 652, /*!< 客户端未创建 652 */
CM_HTTP_RET_CODE_CLIENT_IS_BUSY = 653, /*!< 客户端忙 653 */
CM_HTTP_RET_CODE_URL_PARSE_FAIL = 654, /*!< URL解析失败 654 */
CM_HTTP_RET_CODE_SSL_NOT_ENABLE = 655, /*!< SSL未使能 655 */
CM_HTTP_RET_CODE_CONNECT_FAIL = 656, /*!< 连接失败 656 */
CM_HTTP_RET_CODE_SEND_DATA_FAIL = 657, /*!< 数据发送失败 657 */
CM_HTTP_RET_CODE_OPEN_FILE_FAIL = 658, /*!< 打开文件失败 658 */
} cm_httpclient_ret_code_e;
/**
* @}
*/
/** @defgroup httpclient_struct Struct
* @{
*/
/**HTTP实例句柄*/
typedef void *cm_httpclient_handle_t;
/**HTTP回调*/
/*
* @param [in] client_handle 客户端句柄
* @param [in] event 回调消息事件
* @param [in] param 事件相关对应响应数据
*
* CM_HTTP_CALLBACK_EVENT_REQ_START_SUCC_IND NULL
* CM_HTTP_CALLBACK_EVENT_RSP_HEADER_IND cm_httpclient_callback_rsp_header_param_t
* CM_HTTP_CALLBACK_EVENT_RSP_CONTENT_IND cm_httpclient_callback_rsp_content_param_t
* CM_HTTP_CALLBACK_EVENT_RSP_END_IND NULL
* CM_HTTP_CALLBACK_EVENT_ERROR_IND cm_httpclient_error_event_e
*/
typedef void (*cm_httpclient_event_callback_func)(cm_httpclient_handle_t client_handle, cm_httpclient_callback_event_e event, void *param);
/**HTTP相关回调函数*/
typedef struct {
uint16_t response_code;
uint16_t response_header_len;
const uint8_t *response_header;
}cm_httpclient_callback_rsp_header_param_t;
/**HTTP相关回调函数*/
typedef struct {
uint32_t total_len; /*!< 数据总长度chunked模式时为0 */
uint32_t sum_len; /*!< 已接收长度 */
uint32_t current_len; /*!< 当前包长度 */
const uint8_t *response_content; /*!< 数据 */
}cm_httpclient_callback_rsp_content_param_t;
/**HTTP可配参数*/
typedef struct {
uint8_t ssl_enable; /*!< 是否使用HTTPS */
int32_t ssl_id; /*!< ssl 索引号 */
uint8_t cid; /*!< PDP索引 */
uint8_t conn_timeout; /*!< 连接超时时间 */
uint8_t rsp_timeout; /*!< 响应超时时间 */
uint8_t dns_priority; /*!< dns解析优先级 0使用全局优先级。1v4优先。2v6优先 */
}cm_httpclient_cfg_t;
/**HTTP 同步接口输入参数*/
typedef struct {
cm_httpclient_request_type_e method; /*!< 请求类型 */
const uint8_t *path; /*!< 请求路径 */
uint32_t content_length; /*!< 数据长度 */
uint8_t *content; /*!< 数据 */
}cm_httpclient_sync_param_t;
/**HTTP 同步接口响应数据*/
typedef struct {
uint32_t response_code; /*!< 请求成功时的响应结果码 */
uint32_t response_header_len; /*!< 响应报头长度 */
uint32_t response_content_len; /*!< 响应消息体长度 */
uint8_t *response_header; /*!< 响应报头内部分配空间使用完后可调用cm_httpclient_sync_free_data释放 */
uint8_t *response_content; /*!< 响应消息体内部分配空间使用完后可调用cm_httpclient_sync_free_data释放 */
}cm_httpclient_sync_response_t;
/**
* @}
*/
/**
* @brief uri编码(不对字母数字以及-_.!~*'();/?:@&=+$,#进行编码)
*
* @param [in] src 原始数据
* @param [in] len 原始数据长度
*
* @return 编码数据/NULL 失败
*
* @details uri编码不对字母数字以及-_.!~*'();/?:@&=+$,#进行编码,返回值为内部分配空间使用完后,需自行释放。不支持中文域名解析。
*/
uint8_t *cm_httpclient_uri_encode(const uint8_t *src, const uint32_t len);
/**
* @brief uri编码(不对字母数字以及-_.!~*'()进行编码)
*
* @param [in] src 原始数据
* @param [in] len 原始数据长度
*
* @return 编码数据/NULL 失败
*
* @details uri编码不对字母数字以及-_.!~*'()进行编码,返回值为内部分配空间使用完后,需自行释放。不支持中文域名解析。
*/
uint8_t *cm_httpclient_uri_encode_component(const uint8_t *src, const uint32_t len);
/**
* @brief 创建客户端实例
*
* @param [in] url 服务器地址服务器地址url需要填写完整例如服务器url仅为格式示例"https://39.106.55.200:80"
* @param [in] callback 客户端相关回调函数使用cm_httpclient_sync_request()同步接口可忽略该参数传NULL即可
* @param [out] handle 实例句柄
*
* @return 0 成功/其他 失败见cm_httpclient_ret_code_e
*
* @details 创建客户端实例
*/
cm_httpclient_ret_code_e cm_httpclient_create(const uint8_t *url, cm_httpclient_event_callback_func callback, cm_httpclient_handle_t *handle);
/**
* @brief 删除客户端实例
*
* @param [in] handle 客户端实例句柄
*
* @return 0 成功/其他 失败见cm_httpclient_ret_code_e
*
* @details 本接口会将close socketHTTP操作发送至eloop模块中让其执行close socket操作。本接口返回成功代表操作已发送至eloop中不代表已完成实例删除操作。用户连续两次调用本接口时建议中间保证100ms的延时。
*/
cm_httpclient_ret_code_e cm_httpclient_delete(cm_httpclient_handle_t handle);
/**
* @brief 检测是否在执行请求
*
* @param [in] client 客户端实例句柄
*
* @return false 未执行请求/ true 正在执行请求
*
* @details 检测是否在执行请求
*/
bool cm_httpclient_is_busy(cm_httpclient_handle_t handle);
/**
* @brief 客户端参数设置
*
* @param [in] handle 客户端实例句柄
* @param [in] cfg 客户端配置
*
* @return 0 成功/其他 失败见cm_httpclient_ret_code_e
*
* @details 客户端参数设置,创建实例后设置,请求过程中不可设置服务器应答重定向信息的情况下采用cm_httpclient_set_cfg()配置的参数连接重定向的服务器
*/
cm_httpclient_ret_code_e cm_httpclient_set_cfg(cm_httpclient_handle_t handle, cm_httpclient_cfg_t cfg);
/**
* @brief 终止http连接
*
* @param [in] handle 客户端实例句柄
*
* @return
*
* @details 终止http连接
*/
void cm_httpclient_terminate(cm_httpclient_handle_t handle);
/**
* @brief 设置通用报头
*
* @param [in] handle 客户端实例句柄
* @param [in] header 报头内容
* @param [in] header_len 长度
*
* @return 0 成功/其他 失败见cm_httpclient_ret_code_e
*
* @details 设置通用报头,实例期间有效,不设置时,发送请求时将自动添加默认报头。
* 直接引用header指针不做拷贝需保证请求过程中不做修改和释放如外部释放
* 需调用cm_httpclient_custom_header_free接口释放内部设置。
*/
cm_httpclient_ret_code_e cm_httpclient_custom_header_set(cm_httpclient_handle_t handle, uint8_t *header, uint16_t header_len);
/**
* @brief 释放通用报头
*
* @param [in] handle 客户端实例句柄
*
* @return 0 成功/其他 失败见cm_httpclient_ret_code_e
*
* @details 重置客户端内部指针为NULL、长度为0。
*/
cm_httpclient_ret_code_e cm_httpclient_custom_header_free(cm_httpclient_handle_t handle);
/**
* @brief 设置特定报头
*
* @param [in] handle 客户端实例句柄
* @param [in] header 报头内容
* @param [in] header_len 长度
*
* @return 0 成功/其他 失败见cm_httpclient_ret_code_e
*
* @details 设置特定报头,用于设置报头中,在不同请求时存在变化的字段,
* 如果通用报头中同样存在该字段,将在发送请求时自动替换为当前设置值。
* 直接引用header指针不做拷贝需保证请求过程中不做修改和释放如外部释放
* 需调用cm_httpclient_specific_header_free接口释放内部设置。
*/
cm_httpclient_ret_code_e cm_httpclient_specific_header_set(cm_httpclient_handle_t handle, uint8_t *header, uint16_t header_len);
/**
* @brief 释放特定报头
*
* @param [in] handle 客户端实例句柄
*
* @return 0 成功/其他 失败见cm_httpclient_ret_code_e
*
* @details 重置客户端内部指针为NULL、长度为0。
*/
cm_httpclient_ret_code_e cm_httpclient_specific_header_free(cm_httpclient_handle_t handle);
/**
* @brief 开始发送请求
*
* @param [in] handle 客户端实例句柄
* @param [in] method 请求类型
* @param [in] path 请求路径
* @param [in] chunked 是否为chunked模式
* @param [in] content_length content数据总长度chunked模式时无效
*
* @return 0 成功/其他 失败见cm_httpclient_ret_code_e
*
* @details 开始发送请求主要为建立连接并发送报头将在request_start_func回调中指示开始完成
* 后续可发送content数据。
*/
cm_httpclient_ret_code_e cm_httpclient_request_start(cm_httpclient_handle_t handle, cm_httpclient_request_type_e method, const uint8_t *path,
bool chunked, uint32_t content_length);
/**
* @brief 发送消息体
*
* @param [in] handle 客户端实例句柄
* @param [in] content 消息体内容
* @param [in] content_len 消息体长度
*
* @return 0 成功/其他 失败见cm_httpclient_ret_code_e
*
* @details 发送消息体执行request_start_func回调后可使用。 \n
* socket发送缓存空间64240单次发送超过64240长度数据时可能会造成缓存区溢出从而导致发送失败。
*/
cm_httpclient_ret_code_e cm_httpclient_request_send(cm_httpclient_handle_t handle, const uint8_t *content, uint32_t content_len);
/**
* @brief 请求发送结束
*
* @param [in] handle 客户端实例句柄
*
* @return 0 成功/其他 失败见cm_httpclient_ret_code_e
*
* @details 请求发送结束chunked模式下将发送结束包普通模式下无实际效果可不执行。
*/
cm_httpclient_ret_code_e cm_httpclient_request_end(cm_httpclient_handle_t handle);
/**
* @brief 获取响应结果码
*
* @param [in] handle 客户端实例句柄
*
* @return -1 失败/其他 结果码
*
* @details 获取响应结果码。
*/
int32_t cm_httpclient_get_response_code(cm_httpclient_handle_t handle);
/**
* @brief 解析报头
*
* @param [in] header 需解析的报头
* @param [in] key 需要找到的字段key
* @param [out] value 需要找到的字段数据
*
* @return 解析到的数据长度
*
* @details 解析报头用于解析接收到的报头按键值对进行解析输入相应key返回对应value
* value输出的为header中的指针位置未单独分配空间。
*/
uint32_t cm_httpclient_parse_header(const uint8_t *header, const uint8_t *key, uint8_t **value);
/**
* @brief 发送请求(同步接口)
*
* @param [in] handle 客户端实例句柄
* @param [in] param 输入参数见cm_httpclient_sync_param_t
* @param [out] response 响应结果见cm_httpclient_sync_response_t
*
* @return 见cm_httpclient_ret_code_e
*
* @details 发送http请求同步接口只可用于非chunk模式发送需先创建实例并完成相关参数设置
* 响应结果中的数据未内部动态分配空间使用完后可通过cm_httpclient_sync_free_data接口释放
* 下次请求时也会自动释放。 \n
* socket发送缓存空间64240单次发送超过64240长度数据时可能会造成缓存区溢出从而导致发送失败。
*/
cm_httpclient_ret_code_e cm_httpclient_sync_request(cm_httpclient_handle_t handle, cm_httpclient_sync_param_t param,
cm_httpclient_sync_response_t *response);
/**
* @brief 释放响应数据(同步接口)
*
* @param [in] handle 客户端实例句柄
*
* @return
*
* @details 释放响应数据。
*/
void cm_httpclient_sync_free_data(cm_httpclient_handle_t handle);
/**
* @}
*/
#ifdef __cplusplus
}
#endif
#endif /* __CM_HTTP_H__ */