#include <time.h>
#include
#include "uni_time.h"
#include "uni_time.h"
#include "tuya_hal_network.h"
#include "tuya_hal_network.h"
#define _HTTPC_H_
#define STANDARD_HDR_FLAGS \
(HDR_ADD_DEFAULT_USER_AGENT)
#define HTTP_RESP_INFORMATIONAL(x) (x >=100 && < 200)
/* Status codes */
#define HTTP_RESP_SUCCESS(x) (x >= 200 && x < 300)
#define HTTP_RESP_REDIR(x) (x >= 300 && x < 400)
#define HTTP_RESP_CLIENT_ERR(x) (x >= 400 && x < 500)
#define HTTP_RESP_SERVER_ERR(x) (x >= 500 && x < 600)
#define HTTP_OK 200
/* * These macros are not of any use to the HTTP client itself. They are used * by the users of the HTTP client. This list may be extended if required */
#define HTTP_CREATED 201
#define HTTP_ACCEPTED 202
#define HTTP_FOUND 302
#define HTTP_NOT_MODIFIED 304
#define HTTP_BAD_REQUEST 400
#define HTTP_NOT_AUTH 401
#define HTTP_FORBIDDEN 403
#define HTTP_NOT_FOUND 404
#define REDIRECT_CNT_MAX 5
/* max redirect count */
#define REDIRECT_CNT_DEFAULT 3
/* default redirect count */
#define REDIRECT_CNT_DISABLED 0
/* zero means disable http redirect */
void http_reset_session_state(http_session_t handle);
int http_open_session(http_session_t *handle,const char *hostname, \
int flags,int retry_cnt);
/** * Start an HTTP session. * * @par * This API starts a new HTTP session. It will create a socket and * then connect to the server given as a parameter. * * @param[in,out] handle Pointer to a handle for the session. Will be * assigned by the callee. * @param[in] hostname Host name or IP address. The hostname should be in * the format [http://]hostname[:portno][/path/to/resource]. The fields * between the square brackets above are optional. The part specifying * the path to resource will be ignored as it is of no use during session * setup. * @param[in] flags Pass OR of the flags mentioned in enum * \ref http_open_flags_t. * @param[in] cfg This is a pointer of the type \a * tls_init_config_t. Please refer to file wm-tls.h for the structure * internals. This pointer will be passed verbatim to the tls API * tls_session_init(). \b If TLS (secure connection) is not needed please * pass NULL value. * @param[in] retry_cnt There are limited sockets available due to memory * constraints. A socket creation can fail if all sockets are currently * used up. If the socket creation fails, http_open_session() will wait * for some time and try to create the socket again for retry_cnt number * of times. 0 is default value which lets the SDK decide the count. * * @return WM_SUCCESS on success * @return -WM_E_INVAL if any of the arguments were invalid * @return -WM_FAIL if the API was unable to initiate an HTTP session with * the server. */
int http_prepare_req(http_session_t handle, const http_req_t *req,
http_hdr_field_sel_t field_flags);
/** * Prepare the HTTP header for sending to the server. * * This API will prepare an HTTP request for sending it out through * http_send_request(). Calling this API is mandatory before calling * http_send_request(). * * @pre http_open_session() * * @param[in] handle Handle returned from the call to http_open_session() * @param[in] req Allocated and initialized \ref http_req_t structure. * @param[in] field_flags Bitwise OR of flags of enum \ref * http_hdr_field_sel_t as required by the caller. * * @note The request structure \ref http_req_t needs to be filled before * invoking this API. * @note The field_flags parameter is a way to request the http client to * use default field values for standard fields. If the corresponding bits * are not set then the respective fields are not added. The user can add * any custom fields including the standard ones using the API * http_add_header() * * @return Standard wmsdk return codes. */
int http_add_header(http_session_t handle, const http_req_t *req,
const char *name, const char *value);
/** * Add custom http headers to the partially generated header. * * This API allows the caller to add custom headers to the partial * http header generated by earlier call to http_prepare_req() * * @note Calling this API is optional and needs to be called only if custom * headers (or standard headers with non-default values) are to be added. * * @pre http_prepare_req() * * @param[in] handle Handle returned from the call to http_open_session() * @param[in] req Structure of the type \ref http_req_t passed earlier to * http_prepare_req() * @param[in] name The name of the field. e.g User-Agent or * If-Modified-Since * @param[in] value Value associated with the name given above. * * @return Standard wmsdk value. */
int http_send_request(http_session_t handle, const http_req_t * req, int send_content);
/** * Perform an HTTP request. * * This API sends the prepared request header and content if * applicable. * * @note If this API fails and the caller decides to abandon this * session altogether it needs to call the API http_close_session() * explicitly. Failure to do this will cause undefined behaviour. * * @pre http_prepare_req() is mandatory. http_add_header() is optional. * * @param[in] handle Handle returned from the call to http_open_session() * @param[in] req The \ref http_req_t structure filled up with appropriate * parameters. * * @return WM_SUCCESS on success * @return -WM_E_IO if failed to send data to network * @return -WM_E_INVAL for an invalid arguments. */
int http_get_response_hdr(http_session_t handle, http_resp_t ** resp);
/** * Get the HTTP response header * * This API received the response header from the server and parses * it. It then populates the \ref http_resp_t structure and returns the * pointer to this structure. The structure \ref http_resp_t is allocated by * the callee. * * @par * The caller is expected to analyse this information to find out the * result of the earlier request sent through API http_send_request(). If * the earlier request was HTTP_GET then the caller will need to call the * API http_read_content() to read the data sent by the server. * * @note Calling this API is \a optional. If the caller does not want * to read/analyse the header and knows beforehand what to expect, it can * directly call http_read_content(). The API http_read_content() * will internally read the HTTP response header. However, the API * http_read_content() will return an error if the HTTP status code * returned is not 200. If you need to read content in cases where the * return status code is other than 200 you need to call * http_get_response_hdr() first. * * @note After invoking this API, it is mandatory to read the entire * content using the http_read_content() API, especially in the case * of repeat http transaction on the same session handle (interleaved mode). * @note If this API fails and the caller decides to abandon this * session altogether it needs to call http_close_session() * explicitly. Failure to do this will cause undefined behaviour. * * @pre http_send_request() is called before. * * @param[in] handle Handle returned from the call to http_new_session() * @param[in,out] resp Pointer to a pointer of type \ref http_resp_t .The * structure will be allocated by the callee. Note that the caller does * \b not need to free the structure allocated and returned from this * API. The allocation and free is done by the callee automatically. * * @return WM_SUCCESS on success * @return -WM_FAIL on error */
int http_get_response_hdr_value(http_session_t handle,
const char *header_name, char **value);
int http_get_response_hdr_all(http_session_t handle, http_header_pair_t *arr,
int *count);
int http_read_content(http_session_t handle, void *buf, unsigned int max_len);
int http_parse_URL(const char *URL, char *tmp_buf, int tmp_buf_len,
parsed_url_t *parsed_url);
/** * Parse the given string into URL subcomponents. * * The hostname string syntax is: * [scheme://]hostname[:port][/path_to_resource?query_string#fragment_id] * The fields between the square brackets above are optional. * * @note Buffer management: To free the caller of the task of * allocating multiple buffers of arbitrary size to store each of the * subcomponents we use the following strategy. This API takes a temporary * buffer, allocated (static or dynamic) by the caller to store the * subcomponents. The caller needs to allocate this buffer with size equal * to (strlen(URL) + 10). When this API returns, the pointers in the * parsed_url structure will point to appropriate address in this * buffer. The caller may free this buffer after usage of the * sub-components is complete. Freeing before that will cause undefined * behavior. * * @param[in] URL Pointer to the string containing the URL. This API * will not modify this argument. * @param[in] tmp_buf A buffer where the strings will be stored after * parsing. Needs to be allocated by the caller and should be of size * atleast 10 greater than size of the URL string passed as first * argument. * @param[in] tmp_buf_len Size of the caller allocated, temporary buffer * sent as second argument. * @param[in, out] parsed_url Pointer to an allocated structure. The member * pointers will point to the appropriate address in the temporary buffer * holding the NULL terminated string corresponding to the subcomponent. * * @return Standard WMSDK return codes. */
int http_lowlevel_read(http_session_t handle, void *buf, unsigned maxlen);
int http_lowlevel_write(http_session_t handle, const void *buf, unsigned len);
int http_write_standard(http_session_t handle, const void *buf, unsigned len);
int httpc_write_chunked(http_session_t handle, const char *data, int len);
/** * HTTP write chunked * * This API is used for chunked transfer encoding * * @note To end the chunked data transfer, this API should be called with * len=0, buf may be NULL * * @param[in] handle Handle retrieved from the call to http_open_session() * @param[in] data Pointer to the buffer to be written. * @param[in] len The number of bytes to be written. * * @return WM_SUCCESS is returned on success. * @return -WM_E_INVAL is returned in case of invalid parameters. * @return -WM_FAIL is returned if session is invalid. * @return Standard libc error codes are returned when there are other * problems. */
void http_close_session(http_session_t *handle);
/** * Close the session. * * This API will close the session represented by the given * handle. The socket associated with this session will be closed and thus * the TCP connection with the server will be terminated. No requests on * this same session will succeed after this API is called. * * @note The response structure \ref http_resp_t returned earlier from * http_get_response_hdr() will be invalid after this call. * * @param[in] handle Handle returned from the previous call to * http_new_session(). The handle will be set to NULL by the callee thus * effectively blocking futher requests on the same session handle. * */
OPERATE_RET http_redirect_limit_set(IN UINT8_T cnt);
/** * @brief This API is used to SET HTTP Redirect Limit Count * * @param[in] cnt The count of redirect, the max value should <= REDIRECT_CNT_MAX * Set as zero, means disable http redirect function. * * @return OPRT_OK on success. Others on error, please refer to tuya_error_code.h */
UINT8_T http_redirect_limit_get(void);
/** * @brief This API is used to GET HTTP Redirect Limit Count * * @param[in] * * @return count of http redirect */
typedef void * http_session_t;
typedef enum {
HTTP_OPTIONS, /* request to server for communication options */
HTTP_GET, /* retrieve information */
HTTP_HEAD, /* get meta-info */
HTTP_POST, /* request to accept new sub-ordinate of resource */
HTTP_PUT, /* modify or create new resource referred to by URI */
HTTP_DELETE, /* delete the resource */
HTTP_TRACE, /* echo */
HTTP_CONNECT, /* do we need this ? */
} http_method_t;
/* Request methods */
typedef enum {
HTTP_VER_1_0,
HTTP_VER_1_1,
} http_ver_t;
typedef enum {
HDR_ADD_DEFAULT_USER_AGENT = 1,
/* Note: This flag is not necessary to set up persistent
* connections in HTTP 1.1. However, if you want the server to
* respond with persistent connection timeout values you may need
* to add this flag. These timeout values are used to find out how
* long a persistent connection will be kept alive by the
* server. */
HDR_ADD_CONN_KEEP_ALIVE = 2,
HDR_ADD_CONN_CLOSE = 4,
HDR_ADD_TYPE_CHUNKED = 8,
// add content type
HDR_ADD_CONTENT_TYPE_JSON = 16,
HDR_ADD_CONTENT_TYPE_FORM_URLENCODE = 32, // add by nzy 20150608
HRD_ADD_DOWNLOAD_RANGE = 64, /* add downlaod offset */
HRD_ADD_HTTP_RAW = 128, /* add downlaod offset */
} http_hdr_field_sel_t;
/** * The OR of zero or more flags below is passed to the API * http_prepare_req(). If the a flag is passed the corresponding HTTP * header field is added to the HTTP header. The values added will be * default ones. */
typedef void (*HTTP_HEAD_ADD_CB)(http_session_t session, VOID* data);
// user http head add callback
typedef unsigned int (*HTTP_CUSTOM_GET_CONTENT_LEN_CB)(VOID *pri_data);
typedef int (*HTTP_CUSTOM_BEFORE_READ_CONTENT_CB)(VOID *pri_data, unsigned int *p_malloc_buffer_size);
typedef int (*HTTP_CUSTOM_READ_CONTENT_CB)(unsigned char *p_buffer, int buf_size, VOID *pri_data);
typedef int (*HTTP_CUSTOM_AFTER_READ_CONTENT_CB)(VOID *pri_data);
typedef struct {
HTTP_CUSTOM_GET_CONTENT_LEN_CB get_content_len_cb;
HTTP_CUSTOM_BEFORE_READ_CONTENT_CB before_read_cb;
HTTP_CUSTOM_READ_CONTENT_CB read_content_cb;
HTTP_CUSTOM_AFTER_READ_CONTENT_CB after_read_cb;
VOID *pri_data;
}http_custom_content_ctx_s;
typedef struct {
/** The Type of HTTP Request */
http_method_t type;
/** The target resource for the HTTP Request. A complete URL is also
* accepted.
*/
const char *resource;
/** initialzied redirect count, default is zero */
unsigned char redirect_cnt;
/** The HTTP Protocol Version */
http_ver_t version;
/** Pointer to data buffer. NULL if GET request */
const char *content;
/** The length of the data pointed to by \a content above. This is
* don't-care if the content is set to NULL
*/
int content_len;
HTTP_HEAD_ADD_CB add_head_cb;
VOID *add_head_data;
unsigned int download_offset;
unsigned int download_size;
http_custom_content_ctx_s *p_custom_content_ctx;
} http_req_t;
/** The HTTP Client's Request structure * * \par * The application should fill up this structure and pass it to the * http_prepare_req() API while making an HTTP request. * For HTTP POST, the fields content and content_len of this structure * have to be set as well. * More name-value fields can be added to HTTP header using http_add_header(). */
typedef struct {
/** The value of the protocol field in the first line of the HTTP
header response. e.g. "HTTP". */
const char *protocol;
/** HTTP version */
http_ver_t version;
/** The status code returned as a part of the first line of the
HTTP response e.g. 200 if success
*/
int status_code;
/** The ASCII string present in the first line of HTTP response. It
is the verbose representation of status code. e.g. "OK" if
status_code is 200
*/
const char *reason_phrase;
/** HTTP "Location" header field value */
const char *location;
/** HTTP "Server" header field value */
const char *server;
/** Accept-Ranges */
const char *p_accept_ranges;
/** Last-Modified header field value in POSIX time format */
time_t modify_time;
/** The value of "Content-Type" header field. e.g. "text/html" */
const char *content_type;
/** The value of "Content-Encoding" header field e.g. "gzip" */
const char *content_encoding;
/** If "Keep-Alive" field is present or if the value of
"Connection" field is "Keep-Alive" then this member is set to
'true'. It is set to 'false' in other cases
*/
bool_t keep_alive_ack;
/** If "Keep-Alive" field is present in the response, this member
contains the value of the "timeout" sub-field of this
field. This is the time the server will allow an idle
connection to remain open before it is closed.
*/
int keep_alive_timeout;
/** If "Keep-Alive" field is present in the response, this member
contains the value of the "max" sub-field of this field. The
max parameter indicates the maximum number of requests that a
client will make, or that a server will allow to be made on the
persistent connection.
*/
int keep_alive_max;
/** This will be 'true' if "Transfer-Encoding" field is set to
"chunked". Note that this is only for information and the API
http_read_content() transparently handles chunked reads.
*/
bool_t chunked;
/** Value of the "Content-Length" field. If "Transfer-Encoding" is
set to chunked then this value will be zero.
*/
unsigned int content_length;
} http_resp_t;
/** * Structure used to give back http header response fields to the caller. */
typedef struct {
char *name;
char *value;
} http_header_pair_t;
typedef struct {
const char *scheme;
const char *hostname;
unsigned portno;
const char *resource;
} parsed_url_t;
typedef enum {
/** Pass this flag when you want the connection to be SSL based */
TLS_ENABLE = 1,
} http_open_flags_t;
/** * If the given URL has a scheme field, and it is https then the http * client will auto-switch to SSL mode, irrespective of the TLS_ENABLE * flag below. */