/** * Copyright (2017) Baidu Inc. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * File: lightduer_http_client.h * Author: Pan Haijun, Gang Chen(chengang12@baidu.com) * Desc: HTTP Client Head File */ #ifndef BAIDU_DUER_LIGHTDUER_HTTP_CLIENT_H #define BAIDU_DUER_LIGHTDUER_HTTP_CLIENT_H #include // #include #include "lightduer_timers.h" #include "lightduer_mutex.h" #ifdef __cplusplus extern "C" { #endif #define DUER_HTTP_CONTENT_TYPE_LEN_MAX (32) // the max length of "content type" section //http client results typedef enum { DUER_HTTP_ERR_FAILED = -1, DUER_HTTP_OK, // Success DUER_HTTP_PROCESSING, // Processing DUER_HTTP_ERR_PARSE, // url Parse error DUER_HTTP_ERR_DNS, // Could not resolve name DUER_HTTP_ERR_PRTCL, // Protocol error DUER_HTTP_ERR_NOT_FOUND, // HTTP 404 Error DUER_HTTP_ERR_REFUSED, // HTTP 403 Error DUER_HTTP_ERR_TIMEOUT, // Connection timeout DUER_HTTP_ERR_CONNECT, // Connection error DUER_HTTP_CLOSED, // Connection was closed by remote host DUER_HTTP_ERR_NOT_SUPPORT, // not supported feature DUER_HTTP_REDIRECTTION, // take a redirection when http header contains 'Location' DUER_HTTP_TOO_MANY_REDIRECT, // redirect too many times } duer_http_result_t; typedef enum { DUER_HTTP_GET, // Just 'GET' is supported, other methods are reserved DUER_HTTP_POST, // reserved DUER_HTTP_PUT, // reserved DUER_HTTP_DELETE, // reserved DUER_HTTP_HEAD // reserved } duer_http_method_t; typedef struct { duer_handler n_handle; duer_handler(*init)(void *socket_args); int (*open)(duer_handler socket_handle); int (*connect)(duer_handler socket_handle, const char *host, duer_u32_t ip, const int port, duer_u32_t timeout); void (*set_blocking)(duer_handler socket_handle, int blocking); void (*set_timeout)(duer_handler socket_handle, int timeout); int (*recv)(duer_handler socket_handle, void *data, unsigned size); int (*send)(duer_handler socket_handle, const void *data, unsigned size); int (*close)(duer_handler socket_handle); void (*destroy)(duer_handler socket_handle); } duer_http_socket_ops_t; //to tell data output callback user that if the current data block is first block or last block typedef enum { DUER_HTTP_DATA_FIRST = 0x1, DUER_HTTP_DATA_MID = 0x2, DUER_HTTP_DATA_LAST = 0x4 } duer_http_data_pos_t; /** * DESC: * the callback for retrieving http response headers (invoked once for each key/value pair) * * PARAM: * @param[in] p_user_ctx: usr ctx registered by user * @param[in] key: key of the header entry * @param[in] value: value of the header entry */ typedef void (*duer_http_header_cb)(void *p_user_ctx, const char *key, const char *value); /** * * DESC: * the callback to handler the data download by http * * PARAM: * @param[in] p_user_ctx: usr ctx registed by user * @param[in] pos: to identify if it is data stream's start, or middle , or end of data stream * @param[in] buf: buffer stored media data * @param[in] len: data length in 'buf' * @param[in] type: data type to identify media or others * * @RETURN: negative number when failed */ typedef int (*duer_http_data_handler)(void *p_user_ctx, duer_http_data_pos_t pos, const char *buf, size_t len, const char *type); /** * DESC: * callback to check whether need to stop getting data * * PARAM: none * * @RETURN 1: to stop; 0: no stop */ typedef int (*duer_http_stop_notify_cb_t)(); /** * DESC: * sometimes other module need to know which url is used to download data. * this callback is used to get the url * * PARAM: * @param[in] p_user_ctx: usr ctx registed by user * @param[in] url: the url used by http to download data * * RETURN: none */ typedef void (*duer_http_get_url_cb_t)(void *p_user_ctx, const char *url); /** * DESC: * Sometimes we want to keep retrying until we notify http to stop * this callback is used to get the keep retry flag * * PARAM: * @param[in] p_user_ctx: usr ctx registed by user * * RETURN: 0 stop retry, nonzero keep retry */ typedef int (*duer_http_keep_retry_cb)(void *p_user_ctx); /** * DESC: * Inform user the connection ip * * PARAM: * @param[in] p_user_ctx: usr ctx registed by user * @param[in] ip: the connection ip * @param[in] dns_type: defined as duer_auto_dns_resolve_type_t * @param[in] result: connect result, 0: success nonzero: failed * * RETURN: none */ typedef void (*duer_http_inform_ip_cb)( void *p_user_ctx, const char *host, const char *ip, int dns_type, int result); typedef struct { const char **pps_custom_headers; size_t sz_headers_count; int n_http_response_code; // http response code duer_http_socket_ops_t ops; // socket operations int scheme; // http or https type,1 is https, 0 is http duer_http_data_handler data_hdlr_cb; // callback for output data void *p_data_hdlr_ctx; // users args for data_hdlr_cb int n_http_content_len; // http content length // http content type char p_http_content_type[DUER_HTTP_CONTENT_TYPE_LEN_MAX]; char *p_location; // http header "Location" // a callback to check that stopping http client getting data or not //duer_http_stop_notify_cb_t check_stop_notify_cb; int stop_flag; // to get the url used to download, the last url will be returned if 302 location happen duer_http_get_url_cb_t get_url_cb; int n_is_chunked; size_t sz_chunk_size; char *p_chunk_buf; size_t recv_size; // size of the data have been dwonload // the count of http continuously try to resume from break-point int resume_retry_count; char *buf; // buf used to receive data duer_http_data_pos_t data_pos; // play position char *last_host; // the lastest connected host unsigned short last_port; // the lastest connected port duer_timer_handler connect_keep_timer; // used to close persistent connect size_t upload_size; // size of the data have been upload size_t timeout_count; // current timeout count // max reconnect retry count size_t max_resume_retry_count; // max retry count when timeout becore reconnecct size_t max_timeout_retry_count; size_t max_connect_retry_count; size_t timeout_ms; // recv timeout in milliseconds size_t connect_timeout_ms; // connect timeout in milliseconds duer_http_keep_retry_cb keep_retry_cb; duer_http_header_cb rsp_header_cb; // callback for response header duer_http_inform_ip_cb inform_ip_cb; // callback for inform the connection ip duer_mutex_t lock; } duer_http_client_t; /** * DESC: * init the http client * * PARAM: * @param[in] p_client: pointer of the http client * * RETURN: DUER_HTTP_OK if success, DUER_HTTP_ERR_FAILED if failed */ duer_http_result_t duer_http_init(duer_http_client_t *p_client); /** * DESC: * destroy the http client * * PARAM: * @param[in] p_client: pointer of the http client * * RETURN: none */ void duer_http_destroy(duer_http_client_t *p_client); /** * DESC: * to init http client socket operations * * PARAM: * @param[in] p_client: pointer of the http client * @param[in] p_ops: socket operations set * @param[in] socket_args: args for ops "get_inst" * * RETURN: DUER_HTTP_OK if success, DUER_HTTP_ERR_FAILED if failed */ duer_http_result_t duer_http_init_socket_ops(duer_http_client_t *p_client, duer_http_socket_ops_t *p_ops, void *socket_args); /** * DESC: * register data output handler callback to handle data block * * @param[in] p_client: pointer of the http client * @param[in] data_hdlr_cb: data output handler callback to be registered * @param[in] p_usr_ctx: user context for data output handler * * @RETURN none */ void duer_http_reg_data_hdlr(duer_http_client_t *p_client, duer_http_data_handler data_hdlr_cb, void *p_usr_ctx); /** * * DESC: * register callback to get the url which is used by http to get data * * PARAM: * @param[in] p_client: pointer point to the duer_http_client_t * @param[in] cb: the callback to be registered * * @RETURN none */ void duer_http_reg_url_get_cb(duer_http_client_t *p_client, duer_http_get_url_cb_t cb); /** * * DESC: * register callback to get the keep retry flag * * PARAM: * @param[in] p_client: pointer point to the duer_http_client_t * @param[in] cb: the callback to be registered * * @RETURN none */ void duer_http_reg_keep_retry_cb(duer_http_client_t *p_client, duer_http_keep_retry_cb cb); /** * * DESC: * register callback to get the response headers * * PARAM: * @param[in] p_client: pointer point to the duer_http_client_t * @param[in] cb: the callback to be registered * * @RETURN none */ void duer_http_reg_rsp_header_cb(duer_http_client_t *p_client, duer_http_header_cb cb); /** * * DESC: * register callback to get the ip * * PARAM: * @param[in] p_client: pointer point to the duer_http_client_t * @param[in] cb: the callback to be registered * * @RETURN none */ void duer_http_reg_inform_ip_cb(duer_http_client_t *p_client, duer_http_inform_ip_cb cb); /** * * DESC: * set max resume retry count * * PARAM: * @param[in] p_client: pointer point to the duer_http_client_t * @param[in] count: max resume retry count * * @RETURN none */ void duer_http_set_max_resume_retry_count(duer_http_client_t *p_client, size_t count); /** * * DESC: * set max retry count when read timeout * * PARAM: * @param[in] p_client: pointer point to the duer_http_client_t * @param[in] count: retry count * * @RETURN none */ void duer_http_set_max_timeout_retry_count(duer_http_client_t *p_client, size_t count); /** * * DESC: * set connect timeout in milliseconds * * PARAM: * @param[in] p_client: pointer point to the duer_http_client_t * @param[in] timeout_ms: timeout in milliseconds * * @RETURN none */ void duer_http_set_connect_timeout_ms(duer_http_client_t *p_client, size_t timeout_ms); /** * * DESC: * set recv timeout in milliseconds * * PARAM: * @param[in] p_client: pointer point to the duer_http_client_t * @param[in] timeout_ms: timeout in milliseconds * * @RETURN none */ void duer_http_set_recv_timeout_ms(duer_http_client_t *p_client, size_t timeout_ms); /** * DESC: * Set custom headers for request. * Pass NULL, 0 to turn off custom headers. * * PARAM: * @param[in] p_client: pointer point to the duer_http_client_t * @param[in] headers: an array (size multiple of two) key-value pairs, * must remain valid during the whole HTTP session * const char * hdrs[] = * { * "Connection", "keep-alive", * "Accept", "text/html", * "User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64)", * "Accept-Encoding", "gzip,deflate,sdch", * "Accept-Language", "en-US,en;q=0.8", * }; * * duer_http_set_cust_headers(hdrs, 5); * @param[in] pairs: number of key-value pairs * * @RETURN none */ void duer_http_set_cust_headers(duer_http_client_t *p_client, const char **headers, size_t pairs); /** * DESC: * get data by http client * * PARAM: * @param[in] p_client: pointer point to the duer_http_client_t * @param[in] url: url resource * @param[in] pos: the position to receive the http data, * sometimes user only want to get part of the data * @param[in] connect_keep_time: how long time the connection should be kept after download finish * * RETURN DUER_HTTP_OK if success, other duer_http_result_t type code if failed */ duer_http_result_t duer_http_get(duer_http_client_t *p_client, const char *url, const size_t pos, const int connect_keep_time); /** * DESC: * get http response code * * PARAM: * @param[in] p_client: pointer point to the duer_http_client_t * * @RETURN none */ int duer_http_get_rsp_code(duer_http_client_t *p_client); /** * DESC: * Notify the http module to stop download. * * @param[in] p_client: pointer of the http client * * @RETURN none */ void duer_http_stop_notify(duer_http_client_t *p_client); /** * DESC: * get http download progress * * PARAM: * @param[in] p_client: pointer point to the duer_http_client_t * @param[out] total_size: pointer point to a varirable to receive the total size to be download, * 0 will be returned if it's chunk transfer * @param[out] recv_size: pointer point to a varirable to receive the data size have been download * * RETURN none */ void duer_http_get_download_progress(duer_http_client_t *p_client, size_t *total_size, size_t *recv_size); /** * DESC: * post data to http server * * PARAM: * @param[in] p_client: pointer point to the duer_http_client_t * @param[in] url: url resource * @param[in] connect_keep_time: how long time the connection should be kept after download finish * @param[in] data: the data post to server * @param[in] len: the length of data * @param[in] content_type: the data type * * RETURN DUER_HTTP_OK if success, other duer_http_result_t type code if failed */ duer_http_result_t duer_http_post(duer_http_client_t *p_client, const char *url, const int connect_keep_time, const char *data, size_t len, const char *content_type); /** * DESC: * do http request with method specified * * PARAM: * @param[in] p_client: pointer point to the duer_http_client_t * @param[in] url: url resource * @param[in] method: http method * @param[in] connect_keep_time: how long time the connection should be kept after download finish * @param[in] data: the data post to server * @param[in] len: the length of data * @param[in] content_type: the data type * * RETURN DUER_HTTP_OK if success, other duer_http_result_t type code if failed */ duer_http_result_t duer_http_perform(duer_http_client_t *p_client, const char *url, duer_http_method_t method, const int connect_keep_time, const char *data, size_t len, const char *content_type); #ifdef __cplusplus } #endif #endif // BAIDU_DUER_LIGHTDUER_HTTP_CLIENT_H