1 // Copyright 2015-2018 Espressif Systems (Shanghai) PTE LTD
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #ifndef _ESP_HTTP_CLIENT_H
16 #define _ESP_HTTP_CLIENT_H
17 
18 #include "freertos/FreeRTOS.h"
19 #include "http_parser.h"
20 #include "sdkconfig.h"
21 #include "esp_err.h"
22 
23 #ifdef __cplusplus
24 extern "C" {
25 #endif
26 
27 #define DEFAULT_HTTP_BUF_SIZE (512)
28 
29 typedef struct esp_http_client *esp_http_client_handle_t;
30 typedef struct esp_http_client_event *esp_http_client_event_handle_t;
31 
32 /**
33  * @brief   HTTP Client events id
34  */
35 typedef enum {
36     HTTP_EVENT_ERROR = 0,       /*!< This event occurs when there are any errors during execution */
37     HTTP_EVENT_ON_CONNECTED,    /*!< Once the HTTP has been connected to the server, no data exchange has been performed */
38     HTTP_EVENT_HEADERS_SENT,     /*!< After sending all the headers to the server */
39     HTTP_EVENT_HEADER_SENT = HTTP_EVENT_HEADERS_SENT, /*!< This header has been kept for backward compatability
40                                                            and will be deprecated in future versions esp-idf */
41     HTTP_EVENT_ON_HEADER,       /*!< Occurs when receiving each header sent from the server */
42     HTTP_EVENT_ON_DATA,         /*!< Occurs when receiving data from the server, possibly multiple portions of the packet */
43     HTTP_EVENT_ON_FINISH,       /*!< Occurs when finish a HTTP session */
44     HTTP_EVENT_DISCONNECTED,    /*!< The connection has been disconnected */
45 } esp_http_client_event_id_t;
46 
47 /**
48  * @brief      HTTP Client events data
49  */
50 typedef struct esp_http_client_event {
51     esp_http_client_event_id_t event_id;    /*!< event_id, to know the cause of the event */
52     esp_http_client_handle_t client;        /*!< esp_http_client_handle_t context */
53     void *data;                             /*!< data of the event */
54     int data_len;                           /*!< data length of data */
55     void *user_data;                        /*!< user_data context, from esp_http_client_config_t user_data */
56     char *header_key;                       /*!< For HTTP_EVENT_ON_HEADER event_id, it's store current http header key */
57     char *header_value;                     /*!< For HTTP_EVENT_ON_HEADER event_id, it's store current http header value */
58 } esp_http_client_event_t;
59 
60 
61 /**
62  * @brief      HTTP Client transport
63  */
64 typedef enum {
65     HTTP_TRANSPORT_UNKNOWN = 0x0,   /*!< Unknown */
66     HTTP_TRANSPORT_OVER_TCP,        /*!< Transport over tcp */
67     HTTP_TRANSPORT_OVER_SSL,        /*!< Transport over ssl */
68 } esp_http_client_transport_t;
69 
70 typedef esp_err_t (*http_event_handle_cb)(esp_http_client_event_t *evt);
71 
72 /**
73  * @brief HTTP method
74  */
75 typedef enum {
76     HTTP_METHOD_GET = 0,    /*!< HTTP GET Method */
77     HTTP_METHOD_POST,       /*!< HTTP POST Method */
78     HTTP_METHOD_PUT,        /*!< HTTP PUT Method */
79     HTTP_METHOD_PATCH,      /*!< HTTP PATCH Method */
80     HTTP_METHOD_DELETE,     /*!< HTTP DELETE Method */
81     HTTP_METHOD_HEAD,       /*!< HTTP HEAD Method */
82     HTTP_METHOD_NOTIFY,     /*!< HTTP NOTIFY Method */
83     HTTP_METHOD_SUBSCRIBE,  /*!< HTTP SUBSCRIBE Method */
84     HTTP_METHOD_UNSUBSCRIBE,/*!< HTTP UNSUBSCRIBE Method */
85     HTTP_METHOD_OPTIONS,    /*!< HTTP OPTIONS Method */
86     HTTP_METHOD_COPY,       /*!< HTTP COPY Method */
87     HTTP_METHOD_MOVE,       /*!< HTTP MOVE Method */
88     HTTP_METHOD_LOCK,       /*!< HTTP LOCK Method */
89     HTTP_METHOD_UNLOCK,     /*!< HTTP UNLOCK Method */
90     HTTP_METHOD_PROPFIND,   /*!< HTTP PROPFIND Method */
91     HTTP_METHOD_PROPPATCH,  /*!< HTTP PROPPATCH Method */
92     HTTP_METHOD_MKCOL,      /*!< HTTP MKCOL Method */
93     HTTP_METHOD_MAX,
94 } esp_http_client_method_t;
95 
96 /**
97  * @brief HTTP Authentication type
98  */
99 typedef enum {
100     HTTP_AUTH_TYPE_NONE = 0,    /*!< No authention */
101     HTTP_AUTH_TYPE_BASIC,       /*!< HTTP Basic authentication */
102     HTTP_AUTH_TYPE_DIGEST,      /*!< HTTP Disgest authentication */
103 } esp_http_client_auth_type_t;
104 
105 /**
106  * @brief HTTP configuration
107  */
108 typedef struct {
109     const char                  *url;                /*!< HTTP URL, the information on the URL is most important, it overrides the other fields below, if any */
110     const char                  *host;               /*!< Domain or IP as string */
111     int                         port;                /*!< Port to connect, default depend on esp_http_client_transport_t (80 or 443) */
112     const char                  *username;           /*!< Using for Http authentication */
113     const char                  *password;           /*!< Using for Http authentication */
114     esp_http_client_auth_type_t auth_type;           /*!< Http authentication type, see `esp_http_client_auth_type_t` */
115     const char                  *path;               /*!< HTTP Path, if not set, default is `/` */
116     const char                  *query;              /*!< HTTP query */
117     const char                  *cert_pem;           /*!< SSL server certification, PEM format as string, if the client requires to verify server */
118     const char                  *client_cert_pem;    /*!< SSL client certification, PEM format as string, if the server requires to verify client */
119     const char                  *client_key_pem;     /*!< SSL client key, PEM format as string, if the server requires to verify client */
120     const char                  *user_agent;         /*!< The User Agent string to send with HTTP requests */
121     esp_http_client_method_t    method;                   /*!< HTTP Method */
122     int                         timeout_ms;               /*!< Network timeout in milliseconds */
123     bool                        disable_auto_redirect;    /*!< Disable HTTP automatic redirects */
124     int                         max_redirection_count;    /*!< Max number of redirections on receiving HTTP redirect status code, using default value if zero*/
125     int                         max_authorization_retries;    /*!< Max connection retries on receiving HTTP unauthorized status code, using default value if zero. Disables authorization retry if -1*/
126     http_event_handle_cb        event_handler;             /*!< HTTP Event Handle */
127     esp_http_client_transport_t transport_type;           /*!< HTTP transport type, see `esp_http_client_transport_t` */
128     int                         buffer_size;              /*!< HTTP receive buffer size */
129     int                         buffer_size_tx;           /*!< HTTP transmit buffer size */
130     void                        *user_data;               /*!< HTTP user_data context */
131     bool                        is_async;                 /*!< Set asynchronous mode, only supported with HTTPS for now */
132     bool                        use_global_ca_store;      /*!< Use a global ca_store for all the connections in which this bool is set. */
133     bool                        skip_cert_common_name_check;    /*!< Skip any validation of server certificate CN field */
134     bool                        keep_alive_enable;   /*!< Enable keep-alive timeout */
135     int                         keep_alive_idle;     /*!< Keep-alive idle time. Default is 5 (second) */
136     int                         keep_alive_interval; /*!< Keep-alive interval time. Default is 5 (second) */
137     int                         keep_alive_count;    /*!< Keep-alive packet retry send count. Default is 3 counts */
138 } esp_http_client_config_t;
139 
140 /**
141  * Enum for the HTTP status codes.
142  */
143 typedef enum {
144     /* 2xx - Success */
145     HttpStatus_Ok                = 200,
146 
147     /* 3xx - Redirection */
148     HttpStatus_MultipleChoices   = 300,
149     HttpStatus_MovedPermanently  = 301,
150     HttpStatus_Found             = 302,
151     HttpStatus_TemporaryRedirect = 307,
152 
153     /* 4xx - Client Error */
154     HttpStatus_Unauthorized      = 401,
155     HttpStatus_Forbidden         = 403,
156     HttpStatus_NotFound          = 404,
157 
158     /* 5xx - Server Error */
159     HttpStatus_InternalError     = 500
160 } HttpStatus_Code;
161 
162 #define ESP_ERR_HTTP_BASE               (0x7000)                    /*!< Starting number of HTTP error codes */
163 #define ESP_ERR_HTTP_MAX_REDIRECT       (ESP_ERR_HTTP_BASE + 1)     /*!< The error exceeds the number of HTTP redirects */
164 #define ESP_ERR_HTTP_CONNECT            (ESP_ERR_HTTP_BASE + 2)     /*!< Error open the HTTP connection */
165 #define ESP_ERR_HTTP_WRITE_DATA         (ESP_ERR_HTTP_BASE + 3)     /*!< Error write HTTP data */
166 #define ESP_ERR_HTTP_FETCH_HEADER       (ESP_ERR_HTTP_BASE + 4)     /*!< Error read HTTP header from server */
167 #define ESP_ERR_HTTP_INVALID_TRANSPORT  (ESP_ERR_HTTP_BASE + 5)     /*!< There are no transport support for the input scheme */
168 #define ESP_ERR_HTTP_CONNECTING         (ESP_ERR_HTTP_BASE + 6)     /*!< HTTP connection hasn't been established yet */
169 #define ESP_ERR_HTTP_EAGAIN             (ESP_ERR_HTTP_BASE + 7)     /*!< Mapping of errno EAGAIN to esp_err_t */
170 
171 /**
172  * @brief      Start a HTTP session
173  *             This function must be the first function to call,
174  *             and it returns a esp_http_client_handle_t that you must use as input to other functions in the interface.
175  *             This call MUST have a corresponding call to esp_http_client_cleanup when the operation is complete.
176  *
177  * @param[in]  config   The configurations, see `http_client_config_t`
178  *
179  * @return
180  *     - `esp_http_client_handle_t`
181  *     - NULL if any errors
182  */
183 esp_http_client_handle_t esp_http_client_init(const esp_http_client_config_t *config);
184 
185 /**
186  * @brief      Invoke this function after `esp_http_client_init` and all the options calls are made, and will perform the
187  *             transfer as described in the options. It must be called with the same esp_http_client_handle_t as input as the esp_http_client_init call returned.
188  *             esp_http_client_perform performs the entire request in either blocking or non-blocking manner. By default, the API performs request in a blocking manner and returns when done,
189  *             or if it failed, and in non-blocking manner, it returns if EAGAIN/EWOULDBLOCK or EINPROGRESS is encountered, or if it failed. And in case of non-blocking request,
190  *             the user may call this API multiple times unless request & response is complete or there is a failure. To enable non-blocking esp_http_client_perform(), `is_async` member of esp_http_client_config_t
191  *             must be set while making a call to esp_http_client_init() API.
192  *             You can do any amount of calls to esp_http_client_perform while using the same esp_http_client_handle_t. The underlying connection may be kept open if the server allows it.
193  *             If you intend to transfer more than one file, you are even encouraged to do so.
194  *             esp_http_client will then attempt to re-use the same connection for the following transfers, thus making the operations faster, less CPU intense and using less network resources.
195  *             Just note that you will have to use `esp_http_client_set_**` between the invokes to set options for the following esp_http_client_perform.
196  *
197  * @note       You must never call this function simultaneously from two places using the same client handle.
198  *             Let the function return first before invoking it another time.
199  *             If you want parallel transfers, you must use several esp_http_client_handle_t.
200  *             This function include `esp_http_client_open` -> `esp_http_client_write` -> `esp_http_client_fetch_headers` -> `esp_http_client_read` (and option) `esp_http_client_close`.
201  *
202  * @param      client  The esp_http_client handle
203  *
204  * @return
205  *  - ESP_OK on successful
206  *  - ESP_FAIL on error
207  */
208 esp_err_t esp_http_client_perform(esp_http_client_handle_t client);
209 
210 /**
211  * @brief      Set URL for client, when performing this behavior, the options in the URL will replace the old ones
212  *
213  * @param[in]  client  The esp_http_client handle
214  * @param[in]  url     The url
215  *
216  * @return
217  *  - ESP_OK
218  *  - ESP_FAIL
219  */
220 esp_err_t esp_http_client_set_url(esp_http_client_handle_t client, const char *url);
221 
222 /**
223  * @brief      Set post data, this function must be called before `esp_http_client_perform`.
224  *             Note: The data parameter passed to this function is a pointer and this function will not copy the data
225  *
226  * @param[in]  client  The esp_http_client handle
227  * @param[in]  data    post data pointer
228  * @param[in]  len     post length
229  *
230  * @return
231  *  - ESP_OK
232  *  - ESP_FAIL
233  */
234 esp_err_t esp_http_client_set_post_field(esp_http_client_handle_t client, const char *data, int len);
235 
236 /**
237  * @brief      Get current post field information
238  *
239  * @param[in]  client  The client
240  * @param[out] data    Point to post data pointer
241  *
242  * @return     Size of post data
243  */
244 int esp_http_client_get_post_field(esp_http_client_handle_t client, char **data);
245 
246 /**
247  * @brief      Set http request header, this function must be called after esp_http_client_init and before any
248  *             perform function
249  *
250  * @param[in]  client  The esp_http_client handle
251  * @param[in]  key     The header key
252  * @param[in]  value   The header value
253  *
254  * @return
255  *  - ESP_OK
256  *  - ESP_FAIL
257  */
258 esp_err_t esp_http_client_set_header(esp_http_client_handle_t client, const char *key, const char *value);
259 
260 /**
261  * @brief      Get http request header.
262  *             The value parameter will be set to NULL if there is no header which is same as
263  *             the key specified, otherwise the address of header value will be assigned to value parameter.
264  *             This function must be called after `esp_http_client_init`.
265  *
266  * @param[in]  client  The esp_http_client handle
267  * @param[in]  key     The header key
268  * @param[out] value   The header value
269  *
270  * @return
271  *     - ESP_OK
272  *     - ESP_FAIL
273  */
274 esp_err_t esp_http_client_get_header(esp_http_client_handle_t client, const char *key, char **value);
275 
276 /**
277  * @brief      Get http request username.
278  *             The address of username buffer will be assigned to value parameter.
279  *             This function must be called after `esp_http_client_init`.
280  *
281  * @param[in]  client  The esp_http_client handle
282  * @param[out] value   The username value
283  *
284  * @return
285  *     - ESP_OK
286  *     - ESP_ERR_INVALID_ARG
287  */
288 esp_err_t esp_http_client_get_username(esp_http_client_handle_t client, char **value);
289 
290 /**
291  * @brief      Set http request username.
292  *             The value of username parameter will be assigned to username buffer.
293  *             If the username parameter is NULL then username buffer will be freed.
294  *
295  * @param[in]  client    The esp_http_client handle
296  * @param[in]  username  The username value
297  *
298  * @return
299  *     - ESP_OK
300  *     - ESP_ERR_INVALID_ARG
301  */
302 esp_err_t esp_http_client_set_username(esp_http_client_handle_t client, const char *username);
303 
304 /**
305  * @brief      Get http request password.
306  *             The address of password buffer will be assigned to value parameter.
307  *             This function must be called after `esp_http_client_init`.
308  *
309  * @param[in]  client  The esp_http_client handle
310  * @param[out] value   The password value
311  *
312  * @return
313  *     - ESP_OK
314  *     - ESP_ERR_INVALID_ARG
315  */
316 esp_err_t esp_http_client_get_password(esp_http_client_handle_t client, char **value);
317 
318 /**
319  * @brief      Set http request password.
320  *             The value of password parameter will be assigned to password buffer.
321  *             If the password parameter is NULL then password buffer will be freed.
322  *
323  * @param[in]  client    The esp_http_client handle
324  * @param[in]  password  The password value
325  *
326  * @return
327  *     - ESP_OK
328  *     - ESP_ERR_INVALID_ARG
329  */
330 esp_err_t esp_http_client_set_password(esp_http_client_handle_t client, char *password);
331 
332 /**
333  * @brief      Set http request auth_type.
334  *
335  * @param[in]  client    The esp_http_client handle
336  * @param[in]  auth_type The esp_http_client auth type
337  *
338  * @return
339  *     - ESP_OK
340  *     - ESP_ERR_INVALID_ARG
341  */
342 esp_err_t esp_http_client_set_authtype(esp_http_client_handle_t client, esp_http_client_auth_type_t auth_type);
343 
344 /**
345  * @brief      Set http request method
346  *
347  * @param[in]  client  The esp_http_client handle
348  * @param[in]  method  The method
349  *
350  * @return
351  *     - ESP_OK
352  *     - ESP_ERR_INVALID_ARG
353  */
354 esp_err_t esp_http_client_set_method(esp_http_client_handle_t client, esp_http_client_method_t method);
355 
356 /**
357  * @brief      Delete http request header
358  *
359  * @param[in]  client  The esp_http_client handle
360  * @param[in]  key     The key
361  *
362  * @return
363  *  - ESP_OK
364  *  - ESP_FAIL
365  */
366 esp_err_t esp_http_client_delete_header(esp_http_client_handle_t client, const char *key);
367 
368 /**
369  * @brief      This function will be open the connection, write all header strings and return
370  *
371  * @param[in]  client     The esp_http_client handle
372  * @param[in]  write_len  HTTP Content length need to write to the server
373  *
374  * @return
375  *  - ESP_OK
376  *  - ESP_FAIL
377  */
378 esp_err_t esp_http_client_open(esp_http_client_handle_t client, int write_len);
379 
380 /**
381  * @brief     This function will write data to the HTTP connection previously opened by esp_http_client_open()
382  *
383  * @param[in]  client  The esp_http_client handle
384  * @param      buffer  The buffer
385  * @param[in]  len     This value must not be larger than the write_len parameter provided to esp_http_client_open()
386  *
387  * @return
388  *     - (-1) if any errors
389  *     - Length of data written
390  */
391 int esp_http_client_write(esp_http_client_handle_t client, const char *buffer, int len);
392 
393 /**
394  * @brief      This function need to call after esp_http_client_open, it will read from http stream, process all receive headers
395  *
396  * @param[in]  client  The esp_http_client handle
397  *
398  * @return
399  *     - (0) if stream doesn't contain content-length header, or chunked encoding (checked by `esp_http_client_is_chunked` response)
400  *     - (-1: ESP_FAIL) if any errors
401  *     - Download data length defined by content-length header
402  */
403 int esp_http_client_fetch_headers(esp_http_client_handle_t client);
404 
405 
406 /**
407  * @brief      Check response data is chunked
408  *
409  * @param[in]  client  The esp_http_client handle
410  *
411  * @return     true or false
412  */
413 bool esp_http_client_is_chunked_response(esp_http_client_handle_t client);
414 
415 /**
416  * @brief      Read data from http stream
417  *
418  * @param[in]  client  The esp_http_client handle
419  * @param      buffer  The buffer
420  * @param[in]  len     The length
421  *
422  * @return
423  *     - (-1) if any errors
424  *     - Length of data was read
425  */
426 int esp_http_client_read(esp_http_client_handle_t client, char *buffer, int len);
427 
428 
429 /**
430  * @brief      Get http response status code, the valid value if this function invoke after `esp_http_client_perform`
431  *
432  * @param[in]  client  The esp_http_client handle
433  *
434  * @return     Status code
435  */
436 int esp_http_client_get_status_code(esp_http_client_handle_t client);
437 
438 /**
439  * @brief      Get http response content length (from header Content-Length)
440  *             the valid value if this function invoke after `esp_http_client_perform`
441  *
442  * @param[in]  client  The esp_http_client handle
443  *
444  * @return
445  *     - (-1) Chunked transfer
446  *     - Content-Length value as bytes
447  */
448 int esp_http_client_get_content_length(esp_http_client_handle_t client);
449 
450 /**
451  * @brief      Close http connection, still kept all http request resources
452  *
453  * @param[in]  client  The esp_http_client handle
454  *
455  * @return
456  *     - ESP_OK
457  *     - ESP_FAIL
458  */
459 esp_err_t esp_http_client_close(esp_http_client_handle_t client);
460 
461 /**
462  * @brief      This function must be the last function to call for an session.
463  *             It is the opposite of the esp_http_client_init function and must be called with the same handle as input that a esp_http_client_init call returned.
464  *             This might close all connections this handle has used and possibly has kept open until now.
465  *             Don't call this function if you intend to transfer more files, re-using handles is a key to good performance with esp_http_client.
466  *
467  * @param[in]  client  The esp_http_client handle
468  *
469  * @return
470  *     - ESP_OK
471  *     - ESP_FAIL
472  */
473 esp_err_t esp_http_client_cleanup(esp_http_client_handle_t client);
474 
475 /**
476  * @brief      Get transport type
477  *
478  * @param[in]  client   The esp_http_client handle
479  *
480  * @return
481  *     - HTTP_TRANSPORT_UNKNOWN
482  *     - HTTP_TRANSPORT_OVER_TCP
483  *     - HTTP_TRANSPORT_OVER_SSL
484  */
485 esp_http_client_transport_t esp_http_client_get_transport_type(esp_http_client_handle_t client);
486 
487 /**
488  * @brief      Set redirection URL.
489  *             When received the 30x code from the server, the client stores the redirect URL provided by the server.
490  *             This function will set the current URL to redirect to enable client to execute the redirection request.
491  *
492  * @param[in]  client  The esp_http_client handle
493  *
494  * @return
495  *     - ESP_OK
496  *     - ESP_FAIL
497  */
498 esp_err_t esp_http_client_set_redirection(esp_http_client_handle_t client);
499 
500 /**
501  * @brief      On receiving HTTP Status code 401, this API can be invoked to add authorization
502  *             information.
503  *
504  * @note       There is a possibility of receiving body message with redirection status codes, thus make sure
505  *             to flush off body data after calling this API.
506  *
507  * @param[in]  client   The esp_http_client handle
508  */
509 void esp_http_client_add_auth(esp_http_client_handle_t client);
510 
511 /**
512  * @brief      Checks if entire data in the response has been read without any error.
513  *
514  * @param[in]  client   The esp_http_client handle
515  *
516  * @return
517  *     - true
518  *     - false
519  */
520 bool esp_http_client_is_complete_data_received(esp_http_client_handle_t client);
521 
522 /**
523  * @brief      Helper API to read larger data chunks
524  *             This is a helper API which internally calls `esp_http_client_read` multiple times till the end of data is reached or till the buffer gets full.
525  *
526  * @param[in]  client   The esp_http_client handle
527  * @param      buffer   The buffer
528  * @param[in]  len      The buffer length
529  *
530  * @return
531  *     - Length of data was read
532  */
533 
534 int esp_http_client_read_response(esp_http_client_handle_t client, char *buffer, int len);
535 
536 /**
537  * @brief       Process all remaining response data
538  *              This uses an internal buffer to repeatedly receive, parse, and discard response data until complete data is processed.
539  *              As no additional user-supplied buffer is required, this may be preferrable to `esp_http_client_read_response` in situations where the content of the response may be ignored.
540  *
541  * @param[in]  client  The esp_http_client handle
542  * @param      len     Length of data discarded
543  *
544  * @return
545  *     - ESP_OK                 If successful, len will have discarded length
546  *     - ESP_FAIL               If failed to read response
547  *     - ESP_ERR_INVALID_ARG    If the client is NULL
548  */
549 esp_err_t esp_http_client_flush_response(esp_http_client_handle_t client, int *len);
550 
551 /**
552  * @brief          Get URL from client
553  *
554  * @param[in]      client   The esp_http_client handle
555  * @param[inout]   url      The buffer to store URL
556  * @param[in]      len      The buffer length
557  *
558  * @return
559  *     - ESP_OK
560  *     - ESP_FAIL
561  */
562 
563 esp_err_t esp_http_client_get_url(esp_http_client_handle_t client, char *url, const int len);
564 
565 /**
566  * @brief          Get Chunk-Length from client
567  *
568  * @param[in]      client   The esp_http_client handle
569  * @param[out]     len      Variable to store length
570  *
571  * @return
572  *     - ESP_OK                 If successful, len will have length of current chunk
573  *     - ESP_FAIL               If the server is not a chunked server
574  *     - ESP_ERR_INVALID_ARG    If the client or len are NULL
575  */
576 esp_err_t esp_http_client_get_chunk_length(esp_http_client_handle_t client, int *len);
577 
578 #ifdef __cplusplus
579 }
580 #endif
581 
582 
583 #endif
584